1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h"
6
7 #include "base/win/scoped_bstr.h"
8 #include "base/win/scoped_safearray.h"
9 #include "base/win/scoped_variant.h"
10 #include "content/browser/accessibility/accessibility_content_browsertest.h"
11 #include "content/browser/accessibility/browser_accessibility.h"
12 #include "content/browser/accessibility/browser_accessibility_com_win.h"
13 #include "content/browser/accessibility/browser_accessibility_manager.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/public/test/accessibility_notification_waiter.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "content/public/test/hit_test_region_observer.h"
18 #include "content/shell/browser/shell.h"
19 #include "content/test/content_browser_test_utils_internal.h"
20 #include "net/dns/mock_host_resolver.h"
21
22 using Microsoft::WRL::ComPtr;
23
24 namespace content {
25
26 #define EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(safearray, expected_property_values) \
27 { \
28 EXPECT_EQ(sizeof(V_R8(LPVARIANT(NULL))), \
29 ::SafeArrayGetElemsize(safearray)); \
30 ASSERT_EQ(1u, SafeArrayGetDim(safearray)); \
31 LONG array_lower_bound; \
32 ASSERT_HRESULT_SUCCEEDED( \
33 SafeArrayGetLBound(safearray, 1, &array_lower_bound)); \
34 LONG array_upper_bound; \
35 ASSERT_HRESULT_SUCCEEDED( \
36 SafeArrayGetUBound(safearray, 1, &array_upper_bound)); \
37 double* array_data; \
38 ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData( \
39 safearray, reinterpret_cast<void**>(&array_data))); \
40 size_t count = array_upper_bound - array_lower_bound + 1; \
41 ASSERT_EQ(expected_property_values.size(), count); \
42 for (size_t i = 0; i < count; ++i) { \
43 EXPECT_EQ(array_data[i], expected_property_values[i]); \
44 } \
45 ASSERT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(safearray)); \
46 }
47
48 #define EXPECT_UIA_TEXTRANGE_EQ(provider, expected_content) \
49 { \
50 base::win::ScopedBstr provider_content; \
51 ASSERT_HRESULT_SUCCEEDED( \
52 provider->GetText(-1, provider_content.Receive())); \
53 EXPECT_STREQ(expected_content, provider_content.Get()); \
54 }
55
56 #define EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider, endpoint, unit, \
57 count, expected_text, expected_count) \
58 { \
59 int result_count; \
60 EXPECT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( \
61 endpoint, unit, count, &result_count)); \
62 EXPECT_EQ(expected_count, result_count); \
63 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, expected_text); \
64 }
65
66 #define EXPECT_UIA_MOVE(text_range_provider, unit, count, expected_text, \
67 expected_count) \
68 { \
69 int result_count; \
70 EXPECT_HRESULT_SUCCEEDED( \
71 text_range_provider->Move(unit, count, &result_count)); \
72 EXPECT_EQ(expected_count, result_count); \
73 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, expected_text); \
74 }
75
76 class AXPlatformNodeTextRangeProviderWinBrowserTest
77 : public AccessibilityContentBrowserTest {
78 protected:
79 const base::string16 kEmbeddedCharacterAsString = {
80 ui::AXPlatformNodeBase::kEmbeddedCharacter};
81
SetUpOnMainThread()82 void SetUpOnMainThread() override {
83 host_resolver()->AddRule("*", "127.0.0.1");
84 SetupCrossSiteRedirector(embedded_test_server());
85 ASSERT_TRUE(embedded_test_server()->Start());
86 }
87
GetWidgetHost()88 RenderWidgetHostImpl* GetWidgetHost() {
89 return RenderWidgetHostImpl::From(
90 shell()->web_contents()->GetRenderViewHost()->GetWidget());
91 }
92
SynchronizeThreads()93 void SynchronizeThreads() {
94 MainThreadFrameObserver observer(GetWidgetHost());
95 observer.Wait();
96 }
97
GetManager() const98 BrowserAccessibilityManager* GetManager() const {
99 WebContentsImpl* web_contents =
100 static_cast<WebContentsImpl*>(shell()->web_contents());
101 return web_contents->GetRootBrowserAccessibilityManager();
102 }
103
GetTextRangeProviderFromTextNode(const BrowserAccessibility & target_node,ITextRangeProvider ** text_range_provider)104 void GetTextRangeProviderFromTextNode(
105 const BrowserAccessibility& target_node,
106 ITextRangeProvider** text_range_provider) {
107 BrowserAccessibilityComWin* target_node_com =
108 ToBrowserAccessibilityWin(&target_node)->GetCOM();
109 ASSERT_NE(nullptr, target_node_com);
110
111 ComPtr<ITextProvider> text_provider;
112 ASSERT_HRESULT_SUCCEEDED(
113 target_node_com->GetPatternProvider(UIA_TextPatternId, &text_provider));
114 ASSERT_NE(nullptr, text_provider.Get());
115
116 ASSERT_HRESULT_SUCCEEDED(
117 text_provider->get_DocumentRange(text_range_provider));
118 }
119
GetDocumentRangeForMarkup(const std::string & html_markup,ITextRangeProvider ** text_range_provider)120 void GetDocumentRangeForMarkup(const std::string& html_markup,
121 ITextRangeProvider** text_range_provider) {
122 LoadInitialAccessibilityTreeFromHtml(html_markup);
123 GetTextRangeProviderFromTextNode(*GetManager()->GetRoot(),
124 text_range_provider);
125 }
126
127 // Run through ITextRangeProvider::ScrollIntoView top tests. It's assumed that
128 // the browser has already loaded an HTML document's accessibility tree.
129 // Assert the text range generated for an accessibility node is scrolled to be
130 // flush with the top of the viewport.
131 // expected_start_role: the expected accessibility role of the text range
132 // start node under test
133 // fstart: the function to retrieve the accessibility text
134 // range start node under test from the root
135 // accessibility node
136 // expected_end_role: the expected accessibility role of the text range
137 // end node under test
138 // fend: the function to retrieve the accessibility text
139 // range end node under test from the root
140 // accessibility node
141 // align_to_top: true to test top viewport alignment, otherwise test
142 // bottom viewport alignment
ScrollIntoViewBrowserTestTemplate(const ax::mojom::Role expected_start_role,BrowserAccessibility * (BrowserAccessibility::* fstart)()const,const ax::mojom::Role expected_end_role,BrowserAccessibility * (BrowserAccessibility::* fend)()const,const bool align_to_top)143 void ScrollIntoViewBrowserTestTemplate(
144 const ax::mojom::Role expected_start_role,
145 BrowserAccessibility* (BrowserAccessibility::*fstart)() const,
146 const ax::mojom::Role expected_end_role,
147 BrowserAccessibility* (BrowserAccessibility::*fend)() const,
148 const bool align_to_top) {
149 BrowserAccessibility* root_browser_accessibility =
150 GetRootAndAssertNonNull();
151
152 BrowserAccessibility* browser_accessibility_start =
153 (root_browser_accessibility->*fstart)();
154 ASSERT_NE(nullptr, browser_accessibility_start);
155 ASSERT_EQ(expected_start_role, browser_accessibility_start->GetRole());
156
157 BrowserAccessibility* browser_accessibility_end =
158 (root_browser_accessibility->*fend)();
159 ASSERT_NE(nullptr, browser_accessibility_end);
160 ASSERT_EQ(expected_end_role, browser_accessibility_end->GetRole());
161
162 AssertScrollIntoView(root_browser_accessibility,
163 browser_accessibility_start, browser_accessibility_end,
164 align_to_top);
165 }
166
167 // Run through ITextRangeProvider::ScrollIntoView top tests. It's assumed that
168 // the browser has already loaded an HTML document's accessibility tree.
169 // Assert the text range generated for an accessibility node is scrolled to be
170 // flush with the top of the viewport.
171 // expected_start_role: the expected accessibility role of the text range
172 // start node under test
173 // fstart: the function to retrieve the accessibility text
174 // range start node under test from the root
175 // accessibility node
176 // fstart_arg: an index argument for fstart
177 // expected_end_role: the expected accessibility role of the text range
178 // end node under test
179 // fend: the function to retrieve the accessibility text
180 // range end node under test from the root
181 // accessibility node
182 // fend_arg: an index argument for fend
183 // align_to_top: true to test top viewport alignment, otherwise test
184 // bottom viewport alignment
ScrollIntoViewBrowserTestTemplate(const ax::mojom::Role expected_start_role,BrowserAccessibility * (BrowserAccessibility::* fstart)(uint32_t)const,const uint32_t fstart_arg,const ax::mojom::Role expected_end_role,BrowserAccessibility * (BrowserAccessibility::* fend)(uint32_t)const,const uint32_t fend_arg,const bool align_to_top)185 void ScrollIntoViewBrowserTestTemplate(
186 const ax::mojom::Role expected_start_role,
187 BrowserAccessibility* (BrowserAccessibility::*fstart)(uint32_t) const,
188 const uint32_t fstart_arg,
189 const ax::mojom::Role expected_end_role,
190 BrowserAccessibility* (BrowserAccessibility::*fend)(uint32_t) const,
191 const uint32_t fend_arg,
192 const bool align_to_top) {
193 BrowserAccessibility* root_browser_accessibility =
194 GetRootAndAssertNonNull();
195
196 BrowserAccessibility* browser_accessibility_start =
197 (root_browser_accessibility->*fstart)(fstart_arg);
198 ASSERT_NE(nullptr, browser_accessibility_start);
199 ASSERT_EQ(expected_start_role, browser_accessibility_start->GetRole());
200
201 BrowserAccessibility* browser_accessibility_end =
202 (root_browser_accessibility->*fend)(fend_arg);
203 ASSERT_NE(nullptr, browser_accessibility_end);
204 ASSERT_EQ(expected_end_role, browser_accessibility_end->GetRole());
205
206 AssertScrollIntoView(root_browser_accessibility,
207 browser_accessibility_start, browser_accessibility_end,
208 align_to_top);
209 }
210
ScrollIntoViewFromIframeBrowserTestTemplate(const ax::mojom::Role expected_start_role,BrowserAccessibility * (BrowserAccessibility::* fstart)()const,const ax::mojom::Role expected_end_role,BrowserAccessibility * (BrowserAccessibility::* fend)()const,const bool align_to_top)211 void ScrollIntoViewFromIframeBrowserTestTemplate(
212 const ax::mojom::Role expected_start_role,
213 BrowserAccessibility* (BrowserAccessibility::*fstart)() const,
214 const ax::mojom::Role expected_end_role,
215 BrowserAccessibility* (BrowserAccessibility::*fend)() const,
216 const bool align_to_top) {
217 BrowserAccessibility* root_browser_accessibility =
218 GetRootAndAssertNonNull();
219 BrowserAccessibility* leaf_iframe_browser_accessibility =
220 root_browser_accessibility->InternalDeepestLastChild();
221 ASSERT_NE(nullptr, leaf_iframe_browser_accessibility);
222 ASSERT_EQ(ax::mojom::Role::kIframe,
223 leaf_iframe_browser_accessibility->GetRole());
224
225 AXTreeID iframe_tree_id = AXTreeID::FromString(
226 leaf_iframe_browser_accessibility->GetStringAttribute(
227 ax::mojom::StringAttribute::kChildTreeId));
228 BrowserAccessibilityManager* iframe_browser_accessibility_manager =
229 BrowserAccessibilityManager::FromID(iframe_tree_id);
230 ASSERT_NE(nullptr, iframe_browser_accessibility_manager);
231 BrowserAccessibility* root_iframe_browser_accessibility =
232 iframe_browser_accessibility_manager->GetRoot();
233 ASSERT_NE(nullptr, root_iframe_browser_accessibility);
234 ASSERT_EQ(ax::mojom::Role::kRootWebArea,
235 root_iframe_browser_accessibility->GetRole());
236
237 BrowserAccessibility* browser_accessibility_start =
238 (root_iframe_browser_accessibility->*fstart)();
239 ASSERT_NE(nullptr, browser_accessibility_start);
240 ASSERT_EQ(expected_start_role, browser_accessibility_start->GetRole());
241
242 BrowserAccessibility* browser_accessibility_end =
243 (root_iframe_browser_accessibility->*fend)();
244 ASSERT_NE(nullptr, browser_accessibility_end);
245 ASSERT_EQ(expected_end_role, browser_accessibility_end->GetRole());
246
247 AssertScrollIntoView(root_iframe_browser_accessibility,
248 browser_accessibility_start, browser_accessibility_end,
249 align_to_top);
250 }
251
AssertScrollIntoView(BrowserAccessibility * root_browser_accessibility,BrowserAccessibility * browser_accessibility_start,BrowserAccessibility * browser_accessibility_end,const bool align_to_top)252 void AssertScrollIntoView(BrowserAccessibility* root_browser_accessibility,
253 BrowserAccessibility* browser_accessibility_start,
254 BrowserAccessibility* browser_accessibility_end,
255 const bool align_to_top) {
256 ui::AXNodePosition::AXPositionInstance start =
257 browser_accessibility_start->CreateTextPositionAt(0);
258 ui::AXNodePosition::AXPositionInstance end =
259 browser_accessibility_end->CreateTextPositionAt(0)
260 ->CreatePositionAtEndOfAnchor();
261
262 BrowserAccessibilityComWin* start_browser_accessibility_com_win =
263 ToBrowserAccessibilityWin(browser_accessibility_start)->GetCOM();
264 ASSERT_NE(nullptr, start_browser_accessibility_com_win);
265
266 ComPtr<ITextRangeProvider> text_range_provider =
267 ui::AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
268 start_browser_accessibility_com_win, std::move(start),
269 std::move(end));
270 ASSERT_NE(nullptr, text_range_provider);
271
272 gfx::Rect previous_range_bounds =
273 align_to_top ? browser_accessibility_start->GetBoundsRect(
274 ui::AXCoordinateSystem::kFrame,
275 ui::AXClippingBehavior::kUnclipped)
276 : browser_accessibility_end->GetBoundsRect(
277 ui::AXCoordinateSystem::kFrame,
278 ui::AXClippingBehavior::kUnclipped);
279
280 AccessibilityNotificationWaiter location_changed_waiter(
281 GetWebContentsAndAssertNonNull(), ui::kAXModeComplete,
282 ax::mojom::Event::kLocationChanged);
283 ASSERT_HRESULT_SUCCEEDED(text_range_provider->ScrollIntoView(align_to_top));
284 location_changed_waiter.WaitForNotification();
285
286 gfx::Rect root_page_bounds = root_browser_accessibility->GetBoundsRect(
287 ui::AXCoordinateSystem::kFrame, ui::AXClippingBehavior::kUnclipped);
288 if (align_to_top) {
289 gfx::Rect range_bounds = browser_accessibility_start->GetBoundsRect(
290 ui::AXCoordinateSystem::kFrame, ui::AXClippingBehavior::kUnclipped);
291 ASSERT_NE(previous_range_bounds.y(), range_bounds.y());
292 ASSERT_NEAR(root_page_bounds.y(), range_bounds.y(), 1);
293 } else {
294 gfx::Rect range_bounds = browser_accessibility_end->GetBoundsRect(
295 ui::AXCoordinateSystem::kFrame, ui::AXClippingBehavior::kUnclipped);
296 gfx::Size viewport_size =
297 gfx::Size(root_page_bounds.width(), root_page_bounds.height());
298 ASSERT_NE(previous_range_bounds.y(), range_bounds.y());
299 ASSERT_NEAR(root_page_bounds.y() + viewport_size.height(),
300 range_bounds.y() + range_bounds.height(), 1);
301 }
302 }
303
ScrollIntoViewTopBrowserTestTemplate(const ax::mojom::Role expected_role,BrowserAccessibility * (BrowserAccessibility::* f)()const)304 void ScrollIntoViewTopBrowserTestTemplate(
305 const ax::mojom::Role expected_role,
306 BrowserAccessibility* (BrowserAccessibility::*f)() const) {
307 ScrollIntoViewBrowserTestTemplate(expected_role, f, expected_role, f, true);
308 }
309
ScrollIntoViewTopBrowserTestTemplate(const ax::mojom::Role expected_role_start,BrowserAccessibility * (BrowserAccessibility::* fstart)()const,const ax::mojom::Role expected_role_end,BrowserAccessibility * (BrowserAccessibility::* fend)()const)310 void ScrollIntoViewTopBrowserTestTemplate(
311 const ax::mojom::Role expected_role_start,
312 BrowserAccessibility* (BrowserAccessibility::*fstart)() const,
313 const ax::mojom::Role expected_role_end,
314 BrowserAccessibility* (BrowserAccessibility::*fend)() const) {
315 ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart,
316 expected_role_end, fend, true);
317 }
318
ScrollIntoViewTopBrowserTestTemplate(const ax::mojom::Role expected_role_start,BrowserAccessibility * (BrowserAccessibility::* fstart)(uint32_t)const,const uint32_t fstart_arg,const ax::mojom::Role expected_role_end,BrowserAccessibility * (BrowserAccessibility::* fend)(uint32_t)const,const uint32_t fend_arg)319 void ScrollIntoViewTopBrowserTestTemplate(
320 const ax::mojom::Role expected_role_start,
321 BrowserAccessibility* (BrowserAccessibility::*fstart)(uint32_t) const,
322 const uint32_t fstart_arg,
323 const ax::mojom::Role expected_role_end,
324 BrowserAccessibility* (BrowserAccessibility::*fend)(uint32_t) const,
325 const uint32_t fend_arg) {
326 ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart, fstart_arg,
327 expected_role_end, fend, fend_arg, true);
328 }
329
ScrollIntoViewBottomBrowserTestTemplate(const ax::mojom::Role expected_role,BrowserAccessibility * (BrowserAccessibility::* f)()const)330 void ScrollIntoViewBottomBrowserTestTemplate(
331 const ax::mojom::Role expected_role,
332 BrowserAccessibility* (BrowserAccessibility::*f)() const) {
333 ScrollIntoViewBrowserTestTemplate(expected_role, f, expected_role, f,
334 false);
335 }
336
ScrollIntoViewBottomBrowserTestTemplate(const ax::mojom::Role expected_role_start,BrowserAccessibility * (BrowserAccessibility::* fstart)()const,const ax::mojom::Role expected_role_end,BrowserAccessibility * (BrowserAccessibility::* fend)()const)337 void ScrollIntoViewBottomBrowserTestTemplate(
338 const ax::mojom::Role expected_role_start,
339 BrowserAccessibility* (BrowserAccessibility::*fstart)() const,
340 const ax::mojom::Role expected_role_end,
341 BrowserAccessibility* (BrowserAccessibility::*fend)() const) {
342 ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart,
343 expected_role_end, fend, false);
344 }
345
ScrollIntoViewBottomBrowserTestTemplate(const ax::mojom::Role expected_role_start,BrowserAccessibility * (BrowserAccessibility::* fstart)(uint32_t)const,const uint32_t fstart_arg,const ax::mojom::Role expected_role_end,BrowserAccessibility * (BrowserAccessibility::* fend)(uint32_t)const,const uint32_t fend_arg)346 void ScrollIntoViewBottomBrowserTestTemplate(
347 const ax::mojom::Role expected_role_start,
348 BrowserAccessibility* (BrowserAccessibility::*fstart)(uint32_t) const,
349 const uint32_t fstart_arg,
350 const ax::mojom::Role expected_role_end,
351 BrowserAccessibility* (BrowserAccessibility::*fend)(uint32_t) const,
352 const uint32_t fend_arg) {
353 ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart, fstart_arg,
354 expected_role_end, fend, fend_arg, false);
355 }
356
AssertMoveByUnitForMarkup(const TextUnit & unit,const std::string & html_markup,const std::vector<const wchar_t * > & expected_text)357 void AssertMoveByUnitForMarkup(
358 const TextUnit& unit,
359 const std::string& html_markup,
360 const std::vector<const wchar_t*>& expected_text) {
361 ComPtr<ITextRangeProvider> text_range;
362
363 GetDocumentRangeForMarkup(html_markup, &text_range);
364 ASSERT_NE(nullptr, text_range.Get());
365 text_range->ExpandToEnclosingUnit(unit);
366
367 size_t index = 0;
368 int count_moved = 1;
369 while (count_moved == 1 && index < expected_text.size()) {
370 EXPECT_UIA_TEXTRANGE_EQ(text_range, expected_text[index++]);
371 ASSERT_HRESULT_SUCCEEDED(text_range->Move(unit, 1, &count_moved));
372 }
373 EXPECT_EQ(expected_text.size(), index);
374 EXPECT_EQ(0, count_moved);
375
376 count_moved = -1;
377 index = expected_text.size();
378 while (count_moved == -1 && index > 0) {
379 EXPECT_UIA_TEXTRANGE_EQ(text_range, expected_text[--index]);
380 ASSERT_HRESULT_SUCCEEDED(text_range->Move(unit, -1, &count_moved));
381 }
382 EXPECT_EQ(0, count_moved);
383 EXPECT_EQ(0u, index);
384 }
385 };
386
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,GetAttributeValue)387 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
388 GetAttributeValue) {
389 LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
390 <!DOCTYPE html>
391 <html>
392 <body>
393 <div style="font-size: 16pt">
394 <span style="font-size: 12pt">Text1</span>
395 Text2
396 </div>
397 </body>
398 </html>
399 )HTML"));
400
401 ComPtr<IUnknown> mix_attribute_value;
402 EXPECT_HRESULT_SUCCEEDED(
403 UiaGetReservedMixedAttributeValue(&mix_attribute_value));
404
405 auto* node = FindNode(ax::mojom::Role::kStaticText, "Text1");
406 ASSERT_NE(nullptr, node);
407 EXPECT_TRUE(node->PlatformIsLeaf());
408 EXPECT_EQ(0u, node->PlatformChildCount());
409
410 ComPtr<ITextRangeProvider> text_range_provider;
411 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
412 ASSERT_NE(nullptr, text_range_provider.Get());
413 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Text1");
414
415 base::win::ScopedVariant value;
416 EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue(
417 UIA_FontSizeAttributeId, value.Receive()));
418 EXPECT_EQ(value.type(), VT_R8);
419 EXPECT_EQ(V_R8(value.ptr()), 12.0);
420
421 EXPECT_HRESULT_SUCCEEDED(
422 text_range_provider->ExpandToEnclosingUnit(TextUnit_Paragraph));
423 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Text1 Text2");
424
425 EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue(
426 UIA_FontSizeAttributeId, value.Receive()));
427 EXPECT_EQ(value.type(), VT_UNKNOWN);
428 EXPECT_EQ(V_UNKNOWN(value.ptr()), mix_attribute_value.Get())
429 << "expected 'mixed attribute value' interface pointer";
430 }
431
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,GetAttributeValueIsReadonlyEmptyTextInputs)432 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
433 GetAttributeValueIsReadonlyEmptyTextInputs) {
434 LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
435 <!DOCTYPE html>
436 <html>
437 <body>
438 <input type='text' aria-label='input_text'>
439 <input type='search' aria-label='input_search'>
440 </body>
441 </html>
442 )HTML"));
443
444 auto* input_text_node = FindNode(ax::mojom::Role::kTextField, "input_text");
445 ASSERT_NE(nullptr, input_text_node);
446 EXPECT_TRUE(input_text_node->PlatformIsLeaf());
447 EXPECT_EQ(0u, input_text_node->PlatformChildCount());
448
449 ComPtr<ITextRangeProvider> text_range_provider;
450 GetTextRangeProviderFromTextNode(*input_text_node, &text_range_provider);
451 ASSERT_NE(nullptr, text_range_provider.Get());
452 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
453 kEmbeddedCharacterAsString.c_str());
454
455 base::win::ScopedVariant value;
456 EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue(
457 UIA_IsReadOnlyAttributeId, value.Receive()));
458 EXPECT_EQ(value.type(), VT_BOOL);
459 EXPECT_EQ(V_BOOL(value.ptr()), VARIANT_FALSE);
460 text_range_provider.Reset();
461 value.Reset();
462
463 auto* input_search_node =
464 FindNode(ax::mojom::Role::kSearchBox, "input_search");
465 ASSERT_NE(nullptr, input_search_node);
466 EXPECT_TRUE(input_search_node->PlatformIsLeaf());
467 EXPECT_EQ(0u, input_search_node->PlatformChildCount());
468
469 GetTextRangeProviderFromTextNode(*input_search_node, &text_range_provider);
470 ASSERT_NE(nullptr, text_range_provider.Get());
471 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
472 kEmbeddedCharacterAsString.c_str());
473
474 EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue(
475 UIA_IsReadOnlyAttributeId, value.Receive()));
476 EXPECT_EQ(value.type(), VT_BOOL);
477 EXPECT_EQ(V_BOOL(value.ptr()), VARIANT_FALSE);
478 text_range_provider.Reset();
479 value.Reset();
480 }
481
482 // With a rich text field, the read-only attribute should be determined based on
483 // the editable root node's editable state.
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,GetAttributeValueIsReadonlyRichTextField)484 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
485 GetAttributeValueIsReadonlyRichTextField) {
486 LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
487 <!DOCTYPE html>
488 <html>
489 <style>
490 .myDiv::before {
491 content: attr(data-placeholder);
492 pointer-events: none;
493 }
494 </style>
495 <body>
496 <div contenteditable="true" data-placeholder="@mention or comment"
497 role="textbox" aria-readonly="false" aria-label="text_field"
498 class="myDiv"><p>3.14</p></div>
499 </body>
500 </html>
501 )HTML"));
502
503 auto* text_field_node = FindNode(ax::mojom::Role::kTextField, "text_field");
504 ASSERT_NE(nullptr, text_field_node);
505 ComPtr<ITextRangeProvider> text_range_provider;
506 GetTextRangeProviderFromTextNode(*text_field_node, &text_range_provider);
507 ASSERT_NE(nullptr, text_range_provider.Get());
508
509 base::win::ScopedVariant value;
510 EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue(
511 UIA_IsReadOnlyAttributeId, value.Receive()));
512 EXPECT_EQ(value.type(), VT_BOOL);
513 EXPECT_EQ(V_BOOL(value.ptr()), VARIANT_FALSE);
514 text_range_provider.Reset();
515 value.Reset();
516 }
517
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,DoNotNormalizeRangeWithVisibleCaretOrSelection)518 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
519 DoNotNormalizeRangeWithVisibleCaretOrSelection) {
520 LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
521 <!DOCTYPE html>
522 <html>
523 <body>
524 <div aria-value="wrapper">
525 <input type='text' aria-label='input_text'><span
526 style="font-size: 12pt">Text1</span>
527 </div>
528 </body>
529 </html>
530 )HTML"));
531
532 // In order for the test harness to effectively simulate typing in a text
533 // input, first change the value of the text input and then focus it. Only
534 // editing the value won't show the cursor and only focusing will put the
535 // cursor at the beginning of the text input, so both steps are necessary.
536 auto* input_text_node = FindNode(ax::mojom::Role::kTextField, "input_text");
537 ASSERT_NE(nullptr, input_text_node);
538 EXPECT_TRUE(input_text_node->PlatformIsLeaf());
539 EXPECT_EQ(0u, input_text_node->PlatformChildCount());
540
541 AccessibilityNotificationWaiter edit_waiter(shell()->web_contents(),
542 ui::kAXModeComplete,
543 ax::mojom::Event::kValueChanged);
544 ui::AXActionData edit_data;
545 edit_data.target_node_id = input_text_node->GetId();
546 edit_data.action = ax::mojom::Action::kSetValue;
547 edit_data.value = "test";
548 input_text_node->AccessibilityPerformAction(edit_data);
549 edit_waiter.WaitForNotification();
550
551 AccessibilityNotificationWaiter focus_waiter(
552 shell()->web_contents(), ui::kAXModeComplete, ax::mojom::Event::kFocus);
553 ui::AXActionData focus_data;
554 focus_data.target_node_id = input_text_node->GetId();
555 focus_data.action = ax::mojom::Action::kFocus;
556 input_text_node->AccessibilityPerformAction(focus_data);
557 focus_waiter.WaitForNotification();
558
559 ComPtr<ITextRangeProvider> text_range_provider;
560 GetTextRangeProviderFromTextNode(*input_text_node, &text_range_provider);
561 ASSERT_NE(nullptr, text_range_provider.Get());
562 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"test");
563
564 // Move the first position so that both endpoints are at the end of the text
565 // input. This is where calls to NormalizeTextRange can be problematic.
566 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
567 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
568 /*count*/ 4,
569 /*expected_text*/ L"",
570 /*expected_count*/ 4);
571
572 // Clone the original text range so we can keep track if NormalizeEndpoints
573 // causes a change in position.
574 ComPtr<ITextRangeProvider> text_range_provider_clone;
575 text_range_provider->Clone(&text_range_provider_clone);
576
577 // Since both ranges are identical, the result of CompareEndpoints should be
578 // 0.
579 int result = 0;
580 EXPECT_HRESULT_SUCCEEDED(text_range_provider->CompareEndpoints(
581 TextPatternRangeEndpoint_End, text_range_provider_clone.Get(),
582 TextPatternRangeEndpoint_Start, &result));
583 ASSERT_EQ(0, result);
584
585 // Calling GetAttributeValue will call NormalizeTextRange, which shouldn't
586 // change the result of CompareEndpoints below.
587 base::win::ScopedVariant value;
588 EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue(
589 UIA_IsReadOnlyAttributeId, value.Receive()));
590 EXPECT_EQ(value.type(), VT_BOOL);
591 EXPECT_EQ(V_BOOL(value.ptr()), VARIANT_FALSE);
592 value.Reset();
593
594 EXPECT_HRESULT_SUCCEEDED(text_range_provider_clone->GetAttributeValue(
595 UIA_IsReadOnlyAttributeId, value.Receive()));
596 EXPECT_EQ(value.type(), VT_BOOL);
597 EXPECT_EQ(V_BOOL(value.ptr()), VARIANT_FALSE);
598 value.Reset();
599
600 EXPECT_HRESULT_SUCCEEDED(text_range_provider->CompareEndpoints(
601 TextPatternRangeEndpoint_End, text_range_provider_clone.Get(),
602 TextPatternRangeEndpoint_Start, &result));
603 ASSERT_EQ(0, result);
604 }
605
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,GetBoundingRectangles)606 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
607 GetBoundingRectangles) {
608 LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
609 <!DOCTYPE html>
610 <html>
611 <head>
612 <style>
613 .break_word {
614 width: 50px;
615 word-wrap: break-word;
616 }
617 </style>
618 </head>
619 <body>
620 <p class="break_word">AsdfAsdfAsdf</p>
621 </body>
622 </html>
623 )HTML"));
624
625 auto* node = FindNode(ax::mojom::Role::kStaticText, "AsdfAsdfAsdf");
626 ASSERT_NE(nullptr, node);
627 EXPECT_TRUE(node->PlatformIsLeaf());
628 EXPECT_EQ(0u, node->PlatformChildCount());
629
630 ComPtr<ITextRangeProvider> text_range_provider;
631 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
632 ASSERT_NE(nullptr, text_range_provider.Get());
633 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"AsdfAsdfAsdf");
634
635 base::win::ScopedSafearray rectangles;
636 EXPECT_HRESULT_SUCCEEDED(
637 text_range_provider->GetBoundingRectangles(rectangles.Receive()));
638
639 // |view_offset| is necessary to account for differences in the shell
640 // between platforms (e.g. title bar height) because the results of
641 // |GetBoundingRectangles| are in screen coordinates.
642 gfx::Vector2d view_offset =
643 node->manager()->GetViewBoundsInScreenCoordinates().OffsetFromOrigin();
644 std::vector<double> expected_values = {
645 8 + view_offset.x(), 16 + view_offset.y(), 49, 17,
646 8 + view_offset.x(), 34 + view_offset.y(), 44, 17};
647 EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(rectangles.Get(), expected_values);
648 }
649
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopStaticText)650 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
651 ScrollIntoViewTopStaticText) {
652 LoadInitialAccessibilityTreeFromHtmlFilePath(
653 "/accessibility/scrolling/text.html");
654 ScrollIntoViewTopBrowserTestTemplate(
655 ax::mojom::Role::kStaticText,
656 &BrowserAccessibility::PlatformDeepestFirstChild);
657 }
658
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomStaticText)659 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
660 ScrollIntoViewBottomStaticText) {
661 LoadInitialAccessibilityTreeFromHtmlFilePath(
662 "/accessibility/scrolling/text.html");
663 ScrollIntoViewBottomBrowserTestTemplate(
664 ax::mojom::Role::kStaticText,
665 &BrowserAccessibility::PlatformDeepestFirstChild);
666 }
667
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopEmbeddedText)668 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
669 ScrollIntoViewTopEmbeddedText) {
670 LoadInitialAccessibilityTreeFromHtmlFilePath(
671 "/accessibility/scrolling/embedded-text.html");
672 ScrollIntoViewTopBrowserTestTemplate(
673 ax::mojom::Role::kStaticText,
674 &BrowserAccessibility::PlatformDeepestLastChild);
675 }
676
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomEmbeddedText)677 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
678 ScrollIntoViewBottomEmbeddedText) {
679 LoadInitialAccessibilityTreeFromHtmlFilePath(
680 "/accessibility/scrolling/embedded-text.html");
681 ScrollIntoViewBottomBrowserTestTemplate(
682 ax::mojom::Role::kStaticText,
683 &BrowserAccessibility::PlatformDeepestLastChild);
684 }
685
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopEmbeddedTextCrossNode)686 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
687 ScrollIntoViewTopEmbeddedTextCrossNode) {
688 LoadInitialAccessibilityTreeFromHtmlFilePath(
689 "/accessibility/scrolling/embedded-text.html");
690 ScrollIntoViewTopBrowserTestTemplate(
691 ax::mojom::Role::kStaticText,
692 &BrowserAccessibility::PlatformDeepestFirstChild,
693 ax::mojom::Role::kStaticText,
694 &BrowserAccessibility::PlatformDeepestLastChild);
695 }
696
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomEmbeddedTextCrossNode)697 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
698 ScrollIntoViewBottomEmbeddedTextCrossNode) {
699 LoadInitialAccessibilityTreeFromHtmlFilePath(
700 "/accessibility/scrolling/embedded-text.html");
701 ScrollIntoViewBottomBrowserTestTemplate(
702 ax::mojom::Role::kStaticText,
703 &BrowserAccessibility::PlatformDeepestFirstChild,
704 ax::mojom::Role::kStaticText,
705 &BrowserAccessibility::PlatformDeepestLastChild);
706 }
707
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopTable)708 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
709 ScrollIntoViewTopTable) {
710 LoadInitialAccessibilityTreeFromHtmlFilePath(
711 "/accessibility/scrolling/table.html");
712 ScrollIntoViewTopBrowserTestTemplate(
713 ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0,
714 ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0);
715 }
716
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomTable)717 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
718 ScrollIntoViewBottomTable) {
719 LoadInitialAccessibilityTreeFromHtmlFilePath(
720 "/accessibility/scrolling/table.html");
721 ScrollIntoViewBottomBrowserTestTemplate(
722 ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0,
723 ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0);
724 }
725
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopTableText)726 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
727 ScrollIntoViewTopTableText) {
728 LoadInitialAccessibilityTreeFromHtmlFilePath(
729 "/accessibility/scrolling/table.html");
730 ScrollIntoViewTopBrowserTestTemplate(
731 ax::mojom::Role::kStaticText,
732 &BrowserAccessibility::PlatformDeepestLastChild);
733 }
734
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomTableText)735 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
736 ScrollIntoViewBottomTableText) {
737 LoadInitialAccessibilityTreeFromHtmlFilePath(
738 "/accessibility/scrolling/table.html");
739 ScrollIntoViewBottomBrowserTestTemplate(
740 ax::mojom::Role::kStaticText,
741 &BrowserAccessibility::PlatformDeepestLastChild);
742 }
743
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopLinkText)744 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
745 ScrollIntoViewTopLinkText) {
746 LoadInitialAccessibilityTreeFromHtmlFilePath(
747 "/accessibility/scrolling/link.html");
748 ScrollIntoViewTopBrowserTestTemplate(
749 ax::mojom::Role::kStaticText,
750 &BrowserAccessibility::PlatformDeepestLastChild);
751 }
752
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomLinkText)753 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
754 ScrollIntoViewBottomLinkText) {
755 LoadInitialAccessibilityTreeFromHtmlFilePath(
756 "/accessibility/scrolling/link.html");
757 ScrollIntoViewBottomBrowserTestTemplate(
758 ax::mojom::Role::kStaticText,
759 &BrowserAccessibility::PlatformDeepestLastChild);
760 }
761
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopLinkContainer)762 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
763 ScrollIntoViewTopLinkContainer) {
764 LoadInitialAccessibilityTreeFromHtmlFilePath(
765 "/accessibility/scrolling/link.html");
766 ScrollIntoViewTopBrowserTestTemplate(ax::mojom::Role::kGenericContainer,
767 &BrowserAccessibility::PlatformGetChild,
768 0, ax::mojom::Role::kGenericContainer,
769 &BrowserAccessibility::PlatformGetChild,
770 0);
771 }
772
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomLinkContainer)773 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
774 ScrollIntoViewBottomLinkContainer) {
775 LoadInitialAccessibilityTreeFromHtmlFilePath(
776 "/accessibility/scrolling/link.html");
777 ScrollIntoViewBottomBrowserTestTemplate(
778 ax::mojom::Role::kGenericContainer,
779 &BrowserAccessibility::PlatformGetChild, 0,
780 ax::mojom::Role::kGenericContainer,
781 &BrowserAccessibility::PlatformGetChild, 0);
782 }
783
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewTopTextFromIFrame)784 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
785 ScrollIntoViewTopTextFromIFrame) {
786 LoadInitialAccessibilityTreeFromHtmlFilePath(
787 "/accessibility/scrolling/iframe-text.html");
788 WaitForAccessibilityTreeToContainNodeWithName(
789 shell()->web_contents(),
790 "Game theory is \"the study of Mathematical model mathematical models of "
791 "conflict and cooperation between intelligent rational decision-makers."
792 "\"");
793 ScrollIntoViewFromIframeBrowserTestTemplate(
794 ax::mojom::Role::kStaticText,
795 &BrowserAccessibility::PlatformDeepestFirstChild,
796 ax::mojom::Role::kStaticText,
797 &BrowserAccessibility::PlatformDeepestLastChild, true);
798 }
799
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ScrollIntoViewBottomTextFromIFrame)800 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
801 ScrollIntoViewBottomTextFromIFrame) {
802 LoadInitialAccessibilityTreeFromHtmlFilePath(
803 "/accessibility/scrolling/iframe-text.html");
804 WaitForAccessibilityTreeToContainNodeWithName(
805 shell()->web_contents(),
806 "Game theory is \"the study of Mathematical model mathematical models of "
807 "conflict and cooperation between intelligent rational decision-makers."
808 "\"");
809 ScrollIntoViewFromIframeBrowserTestTemplate(
810 ax::mojom::Role::kStaticText,
811 &BrowserAccessibility::PlatformDeepestFirstChild,
812 ax::mojom::Role::kStaticText,
813 &BrowserAccessibility::PlatformDeepestLastChild, false);
814 }
815
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitFormat)816 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
817 MoveEndpointByUnitFormat) {
818 LoadInitialAccessibilityTreeFromHtml(
819 R"HTML(<!DOCTYPE html>
820 <html>
821 <body>
822 <div>plain 1</div><div>plain 2</div>
823 <div role="heading">plain heading</div>
824 <div role="article" style="font-style: italic">italic 1</div>
825 <div style="font-style: italic">italic 2</div>
826 <h1>heading</h1>
827 <h1>heading</h1>
828 <div style="font-weight: bold">bold 1</div>
829 <div style="font-weight: bold">bold 2</div>
830 </body>
831 </html>)HTML");
832 auto* node = FindNode(ax::mojom::Role::kStaticText, "plain 1");
833 ASSERT_NE(nullptr, node);
834 EXPECT_TRUE(node->PlatformIsLeaf());
835 EXPECT_EQ(0u, node->PlatformChildCount());
836
837 ComPtr<ITextRangeProvider> text_range_provider;
838 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
839 ASSERT_NE(nullptr, text_range_provider.Get());
840 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain 1");
841
842 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
843 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
844 /*count*/ 1,
845 /*expected_text*/ L"plain 1\nplain 2",
846 /*expected_count*/ 1);
847 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
848 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
849 /*count*/ 1,
850 /*expected_text*/
851 L"plain 1\nplain 2\nplain heading",
852 /*expected_count*/ 1);
853 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
854 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
855 /*count*/ 1,
856 /*expected_text*/
857 L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2",
858 /*expected_count*/ 1);
859 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
860 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
861 /*count*/ -1,
862 /*expected_text*/ L"plain 1\nplain 2\nplain heading\n",
863 /*expected_count*/ -1);
864 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
865 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
866 /*count*/ 1,
867 /*expected_text*/
868 L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2",
869 /*expected_count*/ 1);
870 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
871 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
872 /*count*/ 1,
873 /*expected_text*/
874 L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\nheading",
875 /*expected_count*/ 1);
876 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
877 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
878 /*count*/ 1,
879 /*expected_text*/
880 L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\nheading\nheading",
881 /*expected_count*/ 1);
882 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
883 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
884 /*count*/ 5,
885 /*expected_text*/
886 L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2"
887 L"\nheading\nheading\nbold 1\nbold 2",
888 /*expected_count*/ 1);
889 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
890 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
891 /*count*/ -8,
892 /*expected_text*/ L"",
893 /*expected_count*/ -6);
894 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
895 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
896 /*count*/ 1,
897 /*expected_text*/ L"plain 1\nplain 2",
898 /*expected_count*/ 1);
899 }
900
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitFormatAllFormats)901 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
902 MoveEndpointByUnitFormatAllFormats) {
903 LoadInitialAccessibilityTreeFromHtml(
904 R"HTML(<!DOCTYPE html>
905 <html>
906 <body>
907 <div>plain 1</div><div>plain 2</div>
908 <div style="background-color: red">background-color 1</div>
909 <div style="background-color: red">background-color 2</div>
910 <div style="color: blue">color 1</div>
911 <div style="color: blue">color 2</div>
912 <div style="text-decoration: overline">overline 1</div>
913 <div style="text-decoration: overline">overline 2</div>
914 <div style="text-decoration: line-through">line-through 1</div>
915 <div style="text-decoration: line-through">line-through 2</div>
916 <div style="vertical-align:super">sup 1</div>
917 <div style="vertical-align:super">sup 2</div>
918 <div style="font-weight: bold">bold 1</div>
919 <div style="font-weight: bold">bold 2</div>
920 <div style="font-family: sans-serif">font-family 1</div>
921 <div style="font-family: sans-serif">font-family 2</div>
922 </body>
923 </html>)HTML");
924 auto* node = FindNode(ax::mojom::Role::kStaticText, "plain 1");
925 ASSERT_NE(nullptr, node);
926 EXPECT_TRUE(node->PlatformIsLeaf());
927 EXPECT_EQ(0u, node->PlatformChildCount());
928
929 ComPtr<ITextRangeProvider> text_range_provider;
930 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
931 ASSERT_NE(nullptr, text_range_provider.Get());
932 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain 1");
933
934 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
935 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
936 /*count*/ 1,
937 /*expected_text*/ L"plain 1\nplain 2",
938 /*expected_count*/ 1);
939 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
940 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
941 /*count*/ 1,
942 /*expected_text*/
943 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2",
944 /*expected_count*/ 1);
945 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
946 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
947 /*count*/ -1,
948 /*expected_text*/ L"plain 1\nplain 2\n",
949 /*expected_count*/ -1);
950 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
951 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
952 /*count*/ 2,
953 /*expected_text*/
954 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
955 L"1\ncolor 2",
956 /*expected_count*/ 2);
957 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
958 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
959 /*count*/ -1,
960 /*expected_text*/
961 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\n",
962 /*expected_count*/ -1);
963 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
964 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
965 /*count*/ 2,
966 /*expected_text*/
967 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
968 L"1\ncolor 2\noverline 1\noverline 2",
969 /*expected_count*/ 2);
970 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
971 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
972 /*count*/ -1,
973 /*expected_text*/
974 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
975 L"1\ncolor 2\n",
976 /*expected_count*/ -1);
977 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
978 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
979 /*count*/ 2,
980 /*expected_text*/
981 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
982 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through 2",
983 /*expected_count*/ 2);
984 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
985 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
986 /*count*/ -1,
987 /*expected_text*/
988 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
989 L"1\ncolor 2\noverline 1\noverline 2\n",
990 /*expected_count*/ -1);
991 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
992 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
993 /*count*/ 2,
994 /*expected_text*/
995 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
996 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
997 L"2\nsup 1\nsup 2",
998 /*expected_count*/ 2);
999 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1000 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
1001 /*count*/ -1,
1002 /*expected_text*/
1003 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
1004 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through 2\n",
1005 /*expected_count*/ -1);
1006 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1007 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
1008 /*count*/ 2,
1009 /*expected_text*/
1010 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
1011 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
1012 L"2\nsup 1\nsup 2\nbold 1\nbold 2",
1013 /*expected_count*/ 2);
1014 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1015 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
1016 /*count*/ -1,
1017 /*expected_text*/
1018 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
1019 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
1020 L"2\nsup 1\nsup 2\n",
1021 /*expected_count*/ -1);
1022 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1023 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
1024 /*count*/ 2,
1025 /*expected_text*/
1026 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
1027 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
1028 L"2\nsup 1\nsup 2\nbold 1\nbold 2\nfont-family 1\nfont-family 2",
1029 /*expected_count*/ 2);
1030 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1031 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
1032 /*count*/ -1,
1033 /*expected_text*/
1034 L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
1035 L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
1036 L"2\nsup 1\nsup 2\nbold 1\nbold 2\n",
1037 /*expected_count*/ -1);
1038 }
1039
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitParagraph)1040 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
1041 MoveEndpointByUnitParagraph) {
1042 LoadInitialAccessibilityTreeFromHtml(
1043 R"HTML(<!DOCTYPE html>
1044 <html>
1045 <head><style>
1046 div {
1047 width: 100px;
1048 }
1049 code::before {
1050 content: "[";
1051 }
1052 code::after {
1053 content: "]";
1054 }
1055 b::before, i::after {
1056 width: 5px;
1057 height: 5px;
1058 content: "";
1059 display: block;
1060 background: black;
1061 }
1062 </style></head>
1063 <body>
1064 <div>start</div>
1065 <div>
1066 text with <code>:before</code>
1067 and <code>:after</code> content,
1068 then a <b>bold</b> element with a
1069 <code>block</code> before content
1070 then a <i>italic</i> element with
1071 a <code>block</code> after content
1072 </div>
1073 <div>end</div>
1074 </body>
1075 </html>)HTML");
1076 BrowserAccessibility* start_node =
1077 FindNode(ax::mojom::Role::kStaticText, "start");
1078 ASSERT_NE(nullptr, start_node);
1079 BrowserAccessibility* end_node =
1080 FindNode(ax::mojom::Role::kStaticText, "end");
1081 ASSERT_NE(nullptr, end_node);
1082
1083 std::vector<base::string16> paragraphs = {
1084 L"start",
1085 L"text with [:before] and [:after]content, then a",
1086 L"bold element with a [block]before content then a italic",
1087 L"element with a [block] after content",
1088 L"end",
1089 };
1090
1091 // FORWARD NAVIGATION
1092 ComPtr<ITextRangeProvider> text_range_provider;
1093 GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
1094 ASSERT_NE(nullptr, text_range_provider.Get());
1095 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
1096
1097 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1098 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1099 /*count*/ -1,
1100 /*expected_text*/ paragraphs[0].c_str(),
1101 /*expected_count*/ 0);
1102 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1103 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1104 /*count*/ -2,
1105 /*expected_text*/ L"",
1106 /*expected_count*/ -1);
1107 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1108 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1109 /*count*/ 1,
1110 /*expected_text*/ paragraphs[0].c_str(),
1111 /*expected_count*/ 1);
1112 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1113 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1114 /*count*/ 1,
1115 /*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
1116 /*expected_count*/ 1);
1117 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1118 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1119 /*count*/ 1,
1120 /*expected_text*/ paragraphs[1].c_str(),
1121 /*expected_count*/ 1);
1122 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1123 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1124 /*count*/ 1,
1125 /*expected_text*/ (paragraphs[1] + L"\n" + paragraphs[2]).c_str(),
1126 /*expected_count*/ 1);
1127 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1128 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1129 /*count*/ 1,
1130 /*expected_text*/ paragraphs[2].c_str(),
1131 /*expected_count*/ 1);
1132 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1133 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1134 /*count*/ 1,
1135 /*expected_text*/ (paragraphs[2] + L"\n" + paragraphs[3]).c_str(),
1136 /*expected_count*/ 1);
1137 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1138 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1139 /*count*/ 1,
1140 /*expected_text*/ paragraphs[3].c_str(),
1141 /*expected_count*/ 1);
1142 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1143 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1144 /*count*/ 1,
1145 /*expected_text*/ (paragraphs[3] + L"\n" + paragraphs[4]).c_str(),
1146 /*expected_count*/ 1);
1147 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1148 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1149 /*count*/ 1,
1150 /*expected_text*/ paragraphs[4].c_str(),
1151 /*expected_count*/ 1);
1152 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1153 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1154 /*count*/ 1,
1155 /*expected_text*/ paragraphs[4].c_str(),
1156 /*expected_count*/ 0);
1157 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1158 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1159 /*count*/ 2,
1160 /*expected_text*/ L"",
1161 /*expected_count*/ 1);
1162
1163 // REVERSE NAVIGATION
1164 GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
1165 ASSERT_NE(nullptr, text_range_provider.Get());
1166 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
1167
1168 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1169 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1170 /*count*/ 1,
1171 /*expected_text*/ paragraphs[4].c_str(),
1172 /*expected_count*/ 0);
1173 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1174 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1175 /*count*/ 2,
1176 /*expected_text*/ L"",
1177 /*expected_count*/ 1);
1178 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1179 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1180 /*count*/ -1,
1181 /*expected_text*/ paragraphs[4].c_str(),
1182 /*expected_count*/ -1);
1183 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1184 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1185 /*count*/ -1,
1186 /*expected_text*/ (paragraphs[3] + L"\n" + paragraphs[4]).c_str(),
1187 /*expected_count*/ -1);
1188 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1189 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1190 /*count*/ -1,
1191 /*expected_text*/ paragraphs[3].c_str(),
1192 /*expected_count*/ -1);
1193 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1194 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1195 /*count*/ -1,
1196 /*expected_text*/ (paragraphs[2] + L"\n" + paragraphs[3]).c_str(),
1197 /*expected_count*/ -1);
1198 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1199 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1200 /*count*/ -1,
1201 /*expected_text*/ paragraphs[2].c_str(),
1202 /*expected_count*/ -1);
1203 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1204 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1205 /*count*/ -1,
1206 /*expected_text*/ (paragraphs[1] + L"\n" + paragraphs[2]).c_str(),
1207 /*expected_count*/ -1);
1208 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1209 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1210 /*count*/ -1,
1211 /*expected_text*/ paragraphs[1].c_str(),
1212 /*expected_count*/ -1);
1213 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1214 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1215 /*count*/ -1,
1216 /*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
1217 /*expected_count*/ -1);
1218 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1219 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1220 /*count*/ -1,
1221 /*expected_text*/ paragraphs[0].c_str(),
1222 /*expected_count*/ -1);
1223 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1224 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1225 /*count*/ -1,
1226 /*expected_text*/ paragraphs[0].c_str(),
1227 /*expected_count*/ 0);
1228 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1229 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1230 /*count*/ -2,
1231 /*expected_text*/ L"",
1232 /*expected_count*/ -1);
1233 }
1234
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitParagraphCollapseTrailingLineBreakingObjects)1235 IN_PROC_BROWSER_TEST_F(
1236 AXPlatformNodeTextRangeProviderWinBrowserTest,
1237 MoveEndpointByUnitParagraphCollapseTrailingLineBreakingObjects) {
1238 LoadInitialAccessibilityTreeFromHtml(
1239 R"HTML(<!DOCTYPE html>
1240 <html>
1241 <body>
1242 <div>start</div>
1243 <div>
1244 <div>some text</div>
1245 <div></div>
1246 <br>
1247 <span><br><div><br></div></span>
1248 <div>more text</div>
1249 </div>
1250 <div>end</div>
1251 </body>
1252 </html>)HTML");
1253 BrowserAccessibility* start_node =
1254 FindNode(ax::mojom::Role::kStaticText, "start");
1255 ASSERT_NE(nullptr, start_node);
1256 BrowserAccessibility* end_node =
1257 FindNode(ax::mojom::Role::kStaticText, "end");
1258 ASSERT_NE(nullptr, end_node);
1259
1260 std::vector<base::string16> paragraphs = {
1261 L"start",
1262 L"some text\n\n\n",
1263 L"more text",
1264 L"end",
1265 };
1266
1267 // FORWARD NAVIGATION
1268 ComPtr<ITextRangeProvider> text_range_provider;
1269 GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
1270 ASSERT_NE(nullptr, text_range_provider.Get());
1271 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
1272
1273 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1274 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1275 /*count*/ 1,
1276 /*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
1277 /*expected_count*/ 1);
1278 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1279 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1280 /*count*/ 1,
1281 /*expected_text*/ paragraphs[1].c_str(),
1282 /*expected_count*/ 1);
1283 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1284 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1285 /*count*/ 1,
1286 /*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
1287 /*expected_count*/ 1);
1288 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1289 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1290 /*count*/ 1,
1291 /*expected_text*/ paragraphs[2].c_str(),
1292 /*expected_count*/ 1);
1293 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1294 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1295 /*count*/ 1,
1296 /*expected_text*/ (paragraphs[2] + L"\n" + paragraphs[3]).c_str(),
1297 /*expected_count*/ 1);
1298 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1299 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1300 /*count*/ 1,
1301 /*expected_text*/ paragraphs[3].c_str(),
1302 /*expected_count*/ 1);
1303
1304 // REVERSE NAVIGATION
1305 GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
1306 ASSERT_NE(nullptr, text_range_provider.Get());
1307 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
1308
1309 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1310 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1311 /*count*/ -1,
1312 /*expected_text*/ (paragraphs[2] + L"\n" + paragraphs[3]).c_str(),
1313 /*expected_count*/ -1);
1314 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1315 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1316 /*count*/ -1,
1317 /*expected_text*/ paragraphs[2].c_str(),
1318 /*expected_count*/ -1);
1319 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1320 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1321 /*count*/ -1,
1322 /*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
1323 /*expected_count*/ -1);
1324 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1325 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1326 /*count*/ -1,
1327 /*expected_text*/ paragraphs[1].c_str(),
1328 /*expected_count*/ -1);
1329 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1330 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1331 /*count*/ -1,
1332 /*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
1333 /*expected_count*/ -1);
1334 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1335 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1336 /*count*/ -1,
1337 /*expected_text*/ paragraphs[0].c_str(),
1338 /*expected_count*/ -1);
1339 }
1340
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitParagraphCollapseConsecutiveParentChildLineBreakingObjects)1341 IN_PROC_BROWSER_TEST_F(
1342 AXPlatformNodeTextRangeProviderWinBrowserTest,
1343 MoveEndpointByUnitParagraphCollapseConsecutiveParentChildLineBreakingObjects) {
1344 LoadInitialAccessibilityTreeFromHtml(
1345 R"HTML(<!DOCTYPE html>
1346 <html>
1347 <head>
1348 <style>
1349 div {
1350 width: 100px;
1351 }
1352
1353 code::before {
1354 content: "[";
1355 }
1356
1357 code::after {
1358 content: "]";
1359 }
1360
1361 /* This will create an empty anonymous layout block before the <b>
1362 element. */
1363 b::before {
1364 content: "";
1365 display: block;
1366 }
1367 </style>
1368 </head>
1369
1370 <body>
1371 <div>start</div>
1372 <div>
1373 text with <code>:before</code>
1374 and <code>:after</code> content,
1375 then a
1376 <div>
1377 <b>bold</b> element
1378 </div>
1379 </div>
1380 </body>
1381 </html>)HTML");
1382 BrowserAccessibility* start_node =
1383 FindNode(ax::mojom::Role::kStaticText, "start");
1384 ASSERT_NE(nullptr, start_node);
1385
1386 std::vector<base::string16> paragraphs = {
1387 L"start",
1388 L"text with [:before] and [:after]content, then a",
1389 L"bold element",
1390 };
1391
1392 // Forward navigation.
1393 ComPtr<ITextRangeProvider> text_range_provider;
1394 GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
1395 ASSERT_NE(nullptr, text_range_provider.Get());
1396 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
1397
1398 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1399 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1400 /*count*/ 1,
1401 /*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
1402 /*expected_count*/ 1);
1403 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1404 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1405 /*count*/ 1,
1406 /*expected_text*/
1407 (paragraphs[0] + L"\n" + paragraphs[1] + L"\n" + paragraphs[2]).c_str(),
1408 /*expected_count*/ 1);
1409
1410 // Reverse navigation.
1411 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1412 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1413 /*count*/ -1,
1414 /*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
1415 /*expected_count*/ -1);
1416
1417 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1418 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1419 /*count*/ -1,
1420 /*expected_text*/ paragraphs[0].c_str(),
1421 /*expected_count*/ -1);
1422 }
1423
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitParagraphPreservedWhiteSpace)1424 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
1425 MoveEndpointByUnitParagraphPreservedWhiteSpace) {
1426 LoadInitialAccessibilityTreeFromHtml(
1427 R"HTML(<!DOCTYPE html>
1428 <html>
1429 <body>
1430 <div>start</div>
1431 <span style='white-space: pre'>
1432 First Paragraph
1433 Second Paragraph
1434 </span>
1435 <!--
1436 Intentional nesting to test that ancestor positions can
1437 resolve to the newline at the start of preserved whitespace.
1438 -->
1439 <div>
1440 <div style='white-space: pre-line'>
1441 Third Paragraph
1442 Fourth Paragraph
1443 </div>
1444 </div>
1445 <div style='white-space: pre-wrap; width: 10em;'>
1446 Fifth Paragraph
1447 Sixth Paragraph
1448 </div>
1449 <div style='white-space: break-spaces; width: 10em;'>
1450 Seventh Paragraph
1451 Eighth Paragraph
1452 </div>
1453 <div>end</div>
1454 </body>
1455 </html>)HTML");
1456 BrowserAccessibility* start_node =
1457 FindNode(ax::mojom::Role::kStaticText, "start");
1458 ASSERT_NE(nullptr, start_node);
1459 BrowserAccessibility* end_node =
1460 FindNode(ax::mojom::Role::kStaticText, "end");
1461 ASSERT_NE(nullptr, end_node);
1462
1463 ComPtr<ITextRangeProvider> text_range_provider;
1464
1465 std::vector<base::string16> paragraphs = {
1466 L"start\n",
1467 L" First Paragraph\n",
1468 L" Second Paragraph\n \n",
1469 L"Third Paragraph\n",
1470 L"Fourth Paragraph\n\n ",
1471 L"Fifth Paragraph\n ",
1472 L"Sixth Paragraph\n \n ",
1473 L"Seventh Paragraph\n ",
1474 L"Eighth Paragraph\n ",
1475 L"end",
1476 };
1477
1478 // FORWARD NAVIGATION
1479 GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
1480 ASSERT_NE(nullptr, text_range_provider.Get());
1481 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
1482
1483 // The first paragraph extends beyond the end of the "start" node, because
1484 // the preserved whitespace node begins with a line break, so
1485 // move once to capture that.
1486 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1487 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1488 /*count*/ 1,
1489 /*expected_text*/ paragraphs[0].c_str(),
1490 /*expected_count*/ 1);
1491 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1492 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1493 /*count*/ 1,
1494 /*expected_text*/ (paragraphs[0] + paragraphs[1]).c_str(),
1495 /*expected_count*/ 1);
1496 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1497 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1498 /*count*/ 1,
1499 /*expected_text*/ paragraphs[1].c_str(),
1500 /*expected_count*/ 1);
1501 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1502 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1503 /*count*/ 1,
1504 /*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
1505 /*expected_count*/ 1);
1506 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1507 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1508 /*count*/ 1,
1509 /*expected_text*/ paragraphs[2].c_str(),
1510 /*expected_count*/ 1);
1511 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1512 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1513 /*count*/ 1,
1514 /*expected_text*/ (paragraphs[2] + paragraphs[3]).c_str(),
1515 /*expected_count*/ 1);
1516 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1517 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1518 /*count*/ 1,
1519 /*expected_text*/ paragraphs[3].c_str(),
1520 /*expected_count*/ 1);
1521 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1522 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1523 /*count*/ 1,
1524 /*expected_text*/ (paragraphs[3] + paragraphs[4]).c_str(),
1525 /*expected_count*/ 1);
1526 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1527 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1528 /*count*/ 1,
1529 /*expected_text*/ paragraphs[4].c_str(),
1530 /*expected_count*/ 1);
1531 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1532 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1533 /*count*/ 1,
1534 /*expected_text*/ (paragraphs[4] + paragraphs[5]).c_str(),
1535 /*expected_count*/ 1);
1536 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1537 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1538 /*count*/ 1,
1539 /*expected_text*/ paragraphs[5].c_str(),
1540 /*expected_count*/ 1);
1541 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1542 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1543 /*count*/ 1,
1544 /*expected_text*/ (paragraphs[5] + paragraphs[6]).c_str(),
1545 /*expected_count*/ 1);
1546 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1547 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1548 /*count*/ 1,
1549 /*expected_text*/ paragraphs[6].c_str(),
1550 /*expected_count*/ 1);
1551 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1552 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1553 /*count*/ 1,
1554 /*expected_text*/ (paragraphs[6] + paragraphs[7]).c_str(),
1555 /*expected_count*/ 1);
1556 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1557 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1558 /*count*/ 1,
1559 /*expected_text*/ paragraphs[7].c_str(),
1560 /*expected_count*/ 1);
1561 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1562 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1563 /*count*/ 1,
1564 /*expected_text*/ (paragraphs[7] + paragraphs[8]).c_str(),
1565 /*expected_count*/ 1);
1566 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1567 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1568 /*count*/ 1,
1569 /*expected_text*/ paragraphs[8].c_str(),
1570 /*expected_count*/ 1);
1571 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1572 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1573 /*count*/ 1,
1574 /*expected_text*/ (paragraphs[8] + paragraphs[9]).c_str(),
1575 /*expected_count*/ 1);
1576 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1577 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1578 /*count*/ 1,
1579 /*expected_text*/ paragraphs[9].c_str(),
1580 /*expected_count*/ 1);
1581
1582 // REVERSE NAVIGATION
1583 GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
1584 ASSERT_NE(nullptr, text_range_provider.Get());
1585 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
1586
1587 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1588 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1589 /*count*/ -1,
1590 /*expected_text*/ (paragraphs[8] + paragraphs[9]).c_str(),
1591 /*expected_count*/ -1);
1592 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1593 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1594 /*count*/ -1,
1595 /*expected_text*/ paragraphs[8].c_str(),
1596 /*expected_count*/ -1);
1597 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1598 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1599 /*count*/ -1,
1600 /*expected_text*/ (paragraphs[7] + paragraphs[8]).c_str(),
1601 /*expected_count*/ -1);
1602 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1603 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1604 /*count*/ -1,
1605 /*expected_text*/ paragraphs[7].c_str(),
1606 /*expected_count*/ -1);
1607 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1608 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1609 /*count*/ -1,
1610 /*expected_text*/ (paragraphs[6] + paragraphs[7]).c_str(),
1611 /*expected_count*/ -1);
1612 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1613 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1614 /*count*/ -1,
1615 /*expected_text*/ paragraphs[6].c_str(),
1616 /*expected_count*/ -1);
1617 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1618 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1619 /*count*/ -1,
1620 /*expected_text*/ (paragraphs[5] + paragraphs[6]).c_str(),
1621 /*expected_count*/ -1);
1622 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1623 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1624 /*count*/ -1,
1625 /*expected_text*/ paragraphs[5].c_str(),
1626 /*expected_count*/ -1);
1627 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1628 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1629 /*count*/ -1,
1630 /*expected_text*/ (paragraphs[4] + paragraphs[5]).c_str(),
1631 /*expected_count*/ -1);
1632 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1633 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1634 /*count*/ -1,
1635 /*expected_text*/ paragraphs[4].c_str(),
1636 /*expected_count*/ -1);
1637 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1638 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1639 /*count*/ -1,
1640 /*expected_text*/ (paragraphs[3] + paragraphs[4]).c_str(),
1641 /*expected_count*/ -1);
1642 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1643 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1644 /*count*/ -1,
1645 /*expected_text*/ paragraphs[3].c_str(),
1646 /*expected_count*/ -1);
1647 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1648 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1649 /*count*/ -1,
1650 /*expected_text*/ (paragraphs[2] + paragraphs[3]).c_str(),
1651 /*expected_count*/ -1);
1652 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1653 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1654 /*count*/ -1,
1655 /*expected_text*/ paragraphs[2].c_str(),
1656 /*expected_count*/ -1);
1657 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1658 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1659 /*count*/ -1,
1660 /*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
1661 /*expected_count*/ -1);
1662 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1663 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1664 /*count*/ -1,
1665 /*expected_text*/ paragraphs[1].c_str(),
1666 /*expected_count*/ -1);
1667 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1668 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1669 /*count*/ -1,
1670 /*expected_text*/ (paragraphs[0] + paragraphs[1]).c_str(),
1671 /*expected_count*/ -1);
1672 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1673 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1674 /*count*/ -1,
1675 /*expected_text*/ paragraphs[0].c_str(),
1676 /*expected_count*/ -1);
1677 }
1678
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveByUnitParagraphWithAriaHiddenNodes)1679 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
1680 MoveByUnitParagraphWithAriaHiddenNodes) {
1681 const std::string html_markup = R"HTML(<!DOCTYPE html>
1682 <html>
1683 <body>
1684 <div>start</div>
1685 <div>
1686 1. Paragraph with hidden <span aria-hidden="true">
1687 [IGNORED]
1688 </span> inline in between
1689 </div>
1690 <div>
1691 <span>2. Paragraph parts wrapped by</span> <span aria-hidden="true">
1692 [IGNORED]
1693 </span> <span>span with hidden inline in between</span>
1694 </div>
1695 <div>
1696 <span>3. Paragraph before hidden block</span><div aria-hidden="true">
1697 [IGNORED]
1698 </div><span>4. Paragraph after hidden block</span>
1699 </div>
1700 <div>
1701 <span aria-hidden="true">[IGNORED]</span><span>5. Paragraph with leading
1702 and trailing hidden span</span><span aria-hidden="true">[IGNORED]</span>
1703 </div>
1704 <div>
1705 <div aria-hidden="true">[IGNORED]</div><span>6. Paragraph with leading
1706 and trailing hidden block</span><div aria-hidden="true">[IGNORED]</div>
1707 </div>
1708 <div>end</div>
1709 </body>
1710 </html>)HTML";
1711
1712 const std::vector<const wchar_t*> paragraphs = {
1713 L"start",
1714 L"1. Paragraph with hidden inline in between",
1715 L"2. Paragraph parts wrapped by span with hidden inline in between",
1716 L"3. Paragraph before hidden block",
1717 L"4. Paragraph after hidden block",
1718 L"5. Paragraph with leading and trailing hidden span",
1719 L"6. Paragraph with leading and trailing hidden block",
1720 L"end",
1721 };
1722
1723 AssertMoveByUnitForMarkup(TextUnit_Paragraph, html_markup, paragraphs);
1724 }
1725
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveEndpointByUnitParagraphWithEmbeddedObject)1726 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
1727 MoveEndpointByUnitParagraphWithEmbeddedObject) {
1728 LoadInitialAccessibilityTreeFromHtml(
1729 R"HTML(<!DOCTYPE html>
1730 <html>
1731 <head></head>
1732 <body>
1733 <span>start</span>
1734 <svg></svg>
1735 <span>end</span>
1736 </body>
1737 </html>)HTML");
1738 BrowserAccessibility* start_node =
1739 FindNode(ax::mojom::Role::kStaticText, "start");
1740 ASSERT_NE(nullptr, start_node);
1741 BrowserAccessibility* end_node =
1742 FindNode(ax::mojom::Role::kStaticText, "end");
1743 ASSERT_NE(nullptr, end_node);
1744
1745 std::vector<base::string16> paragraphs = {
1746 L"start",
1747 kEmbeddedCharacterAsString,
1748 L"end",
1749 };
1750
1751 // FORWARD NAVIGATION
1752 ComPtr<ITextRangeProvider> text_range_provider;
1753 GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
1754 ASSERT_NE(nullptr, text_range_provider.Get());
1755 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
1756
1757 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1758 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1759 /*count*/ -1,
1760 /*expected_text*/ paragraphs[0].c_str(),
1761 /*expected_count*/ 0);
1762 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1763 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1764 /*count*/ -2,
1765 /*expected_text*/ L"",
1766 /*expected_count*/ -1);
1767 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1768 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1769 /*count*/ 1,
1770 /*expected_text*/ paragraphs[0].c_str(),
1771 /*expected_count*/ 1);
1772 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1773 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1774 /*count*/ 1,
1775 /*expected_text*/ (paragraphs[0] + paragraphs[1]).c_str(),
1776 /*expected_count*/ 1);
1777 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1778 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1779 /*count*/ 1,
1780 /*expected_text*/ paragraphs[1].c_str(),
1781 /*expected_count*/ 1);
1782 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1783 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1784 /*count*/ 1,
1785 /*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
1786 /*expected_count*/ 1);
1787 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1788 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1789 /*count*/ 1,
1790 /*expected_text*/ paragraphs[2].c_str(),
1791 /*expected_count*/ 1);
1792 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1793 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1794 /*count*/ 1,
1795 /*expected_text*/ paragraphs[2].c_str(),
1796 /*expected_count*/ 0);
1797 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1798 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1799 /*count*/ 2,
1800 /*expected_text*/ L"",
1801 /*expected_count*/ 1);
1802
1803 // REVERSE NAVIGATION
1804 GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
1805 ASSERT_NE(nullptr, text_range_provider.Get());
1806 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
1807
1808 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1809 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1810 /*count*/ 1,
1811 /*expected_text*/ paragraphs[2].c_str(),
1812 /*expected_count*/ 0);
1813 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1814 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1815 /*count*/ 2,
1816 /*expected_text*/ L"",
1817 /*expected_count*/ 1);
1818 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1819 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1820 /*count*/ -1,
1821 /*expected_text*/ paragraphs[2].c_str(),
1822 /*expected_count*/ -1);
1823 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1824 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1825 /*count*/ -1,
1826 /*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
1827 /*expected_count*/ -1);
1828 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1829 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1830 /*count*/ -1,
1831 /*expected_text*/ paragraphs[1].c_str(),
1832 /*expected_count*/ -1);
1833 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1834 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1835 /*count*/ -1,
1836 /*expected_text*/ (paragraphs[0] + paragraphs[1]).c_str(),
1837 /*expected_count*/ -1);
1838 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1839 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1840 /*count*/ -1,
1841 /*expected_text*/ paragraphs[0].c_str(),
1842 /*expected_count*/ -1);
1843 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1844 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
1845 /*count*/ -1,
1846 /*expected_text*/ paragraphs[0].c_str(),
1847 /*expected_count*/ 0);
1848 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1849 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
1850 /*count*/ -2,
1851 /*expected_text*/ L"",
1852 /*expected_count*/ -1);
1853 }
1854
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,IFrameTraversal)1855 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
1856 IFrameTraversal) {
1857 LoadInitialAccessibilityTreeFromUrl(embedded_test_server()->GetURL(
1858 "/accessibility/html/iframe-cross-process.html"));
1859
1860 WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
1861 "Text in iframe");
1862
1863 auto* node = FindNode(ax::mojom::Role::kStaticText, "After frame");
1864 ASSERT_NE(nullptr, node);
1865 EXPECT_TRUE(node->PlatformIsLeaf());
1866 EXPECT_EQ(0u, node->PlatformChildCount());
1867
1868 ComPtr<ITextRangeProvider> text_range_provider;
1869 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
1870 ASSERT_NE(nullptr, text_range_provider.Get());
1871 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"After frame");
1872
1873 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1874 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
1875 /*count*/ -1,
1876 /*expected_text*/ L"iframe\nAfter frame",
1877 /*expected_count*/ -1);
1878 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1879 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
1880 /*count*/ -2,
1881 /*expected_text*/ L"Text in iframe\nAfter frame",
1882 /*expected_count*/ -2);
1883 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
1884 TextPatternRangeEndpoint_End, TextUnit_Word,
1885 /*count*/ -3,
1886 /*expected_text*/ L"Text in ",
1887 /*expected_count*/ -3);
1888 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
1889 TextPatternRangeEndpoint_End, TextUnit_Word,
1890 /*count*/ 2,
1891 /*expected_text*/ L"Text in iframe\nAfter ",
1892 /*expected_count*/ 2);
1893 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1894 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Line,
1895 /*count*/ 1,
1896 /*expected_text*/ L"Text in iframe\nAfter frame",
1897 /*expected_count*/ 1);
1898 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1899 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Document,
1900 /*count*/ 1,
1901 /*expected_text*/ L"",
1902 /*expected_count*/ 1);
1903 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1904 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
1905 /*count*/ -17,
1906 /*expected_text*/ L"iframe\nAfter frame",
1907 /*expected_count*/ -17);
1908 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
1909 TextPatternRangeEndpoint_End, TextUnit_Line,
1910 /*count*/ -1,
1911 /*expected_text*/ L"iframe",
1912 /*expected_count*/ -1);
1913
1914 text_range_provider->ExpandToEnclosingUnit(TextUnit_Line);
1915 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Text in iframe");
1916
1917 text_range_provider->ExpandToEnclosingUnit(TextUnit_Document);
1918 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
1919 L"Before frame\nText in iframe\nAfter frame");
1920
1921 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
1922 /*count*/ 2,
1923 /*expected_text*/ L"Text ",
1924 /*expected_count*/ 2);
1925 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
1926 /*count*/ -1,
1927 /*expected_text*/ L"frame",
1928 /*expected_count*/ -1);
1929 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
1930 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
1931 /*count*/ 1,
1932 /*expected_text*/ L"frame\nT",
1933 /*expected_count*/ 1);
1934 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
1935 /*count*/ 6,
1936 /*expected_text*/ L"e",
1937 /*expected_count*/ 6);
1938 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
1939 /*count*/ 19,
1940 /*expected_text*/ L"f",
1941 /*expected_count*/ 19);
1942 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
1943 /*count*/ -7,
1944 /*expected_text*/ L"e",
1945 /*expected_count*/ -7);
1946 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Line,
1947 /*count*/ 1,
1948 /*expected_text*/ L"After frame",
1949 /*expected_count*/ 1);
1950
1951 text_range_provider->ExpandToEnclosingUnit(TextUnit_Document);
1952 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
1953 L"Before frame\nText in iframe\nAfter frame");
1954 }
1955
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,OutOfProcessIFrameTraversal)1956 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
1957 OutOfProcessIFrameTraversal) {
1958 GURL main_url(embedded_test_server()->GetURL(
1959 "a.com", "/accessibility/html/iframe-cross-process.html"));
1960 LoadInitialAccessibilityTreeFromUrl(main_url);
1961
1962 WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
1963 "Text in iframe");
1964
1965 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1966 ->GetFrameTree()
1967 ->root();
1968 ASSERT_EQ(1U, root->child_count());
1969
1970 // Navigate oopif to URL.
1971 FrameTreeNode* iframe_node = root->child_at(0);
1972 GURL iframe_url(embedded_test_server()->GetURL(
1973 "b.com", "/accessibility/html/frame/static_text.html"));
1974 WebContentsImpl* iframe_web_contents =
1975 WebContentsImpl::FromFrameTreeNode(iframe_node);
1976 DCHECK(iframe_web_contents);
1977 {
1978 AccessibilityNotificationWaiter waiter(iframe_web_contents,
1979 ui::kAXModeComplete,
1980 ax::mojom::Event::kLoadComplete);
1981 NavigateFrameToURL(iframe_node, iframe_url);
1982 waiter.WaitForNotification();
1983 }
1984
1985 SynchronizeThreads();
1986 WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
1987 "Text in iframe");
1988
1989 WaitForHitTestData(iframe_node->current_frame_host());
1990 FrameTreeVisualizer visualizer;
1991 ASSERT_EQ(
1992 " Site A ------------ proxies for B\n"
1993 " +--Site B ------- proxies for A\n"
1994 "Where A = http://a.com/\n"
1995 " B = http://b.com/",
1996 visualizer.DepictFrameTree(root));
1997
1998 auto* node = FindNode(ax::mojom::Role::kStaticText, "After frame");
1999 ASSERT_NE(nullptr, node);
2000 EXPECT_TRUE(node->PlatformIsLeaf());
2001 EXPECT_EQ(0u, node->PlatformChildCount());
2002
2003 ComPtr<ITextRangeProvider> text_range_provider;
2004 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
2005 ASSERT_NE(nullptr, text_range_provider.Get());
2006 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"After frame");
2007
2008 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2009 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
2010 /*count*/ -1,
2011 /*expected_text*/ L"iframe\nAfter frame",
2012 /*expected_count*/ -1);
2013 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2014 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
2015 /*count*/ -2,
2016 /*expected_text*/ L"Text in iframe\nAfter frame",
2017 /*expected_count*/ -2);
2018 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
2019 TextPatternRangeEndpoint_End, TextUnit_Word,
2020 /*count*/ -3,
2021 /*expected_text*/ L"Text in ",
2022 /*expected_count*/ -3);
2023 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
2024 TextPatternRangeEndpoint_End, TextUnit_Word,
2025 /*count*/ 2,
2026 /*expected_text*/ L"Text in iframe\nAfter ",
2027 /*expected_count*/ 2);
2028 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2029 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Line,
2030 /*count*/ 1,
2031 /*expected_text*/ L"Text in iframe\nAfter frame",
2032 /*expected_count*/ 1);
2033 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2034 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Document,
2035 /*count*/ 1,
2036 /*expected_text*/ L"",
2037 /*expected_count*/ 1);
2038 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2039 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
2040 /*count*/ -17,
2041 /*expected_text*/ L"iframe\nAfter frame",
2042 /*expected_count*/ -17);
2043 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
2044 TextPatternRangeEndpoint_End, TextUnit_Line,
2045 /*count*/ -1,
2046 /*expected_text*/ L"iframe",
2047 /*expected_count*/ -1);
2048 }
2049
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,ExpandToEnclosingFormat)2050 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2051 ExpandToEnclosingFormat) {
2052 LoadInitialAccessibilityTreeFromHtml(
2053 R"HTML(<!DOCTYPE html>
2054 <html>
2055 <body>
2056 <div>plain</div>
2057 <div>text</div>
2058 <div style="font-style: italic">italic<div>
2059 <div style="font-style: italic">text<div>
2060 </body>
2061 </html>)HTML");
2062
2063 auto* node = FindNode(ax::mojom::Role::kStaticText, "plain");
2064 ASSERT_NE(nullptr, node);
2065 EXPECT_TRUE(node->PlatformIsLeaf());
2066 EXPECT_EQ(0u, node->PlatformChildCount());
2067
2068 ComPtr<ITextRangeProvider> text_range_provider;
2069 GetTextRangeProviderFromTextNode(*node, &text_range_provider);
2070 ASSERT_NE(nullptr, text_range_provider.Get());
2071 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain");
2072
2073 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2074 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
2075 /*count*/ 3,
2076 /*expected_text*/ L"in",
2077 /*expected_count*/ 3);
2078
2079 ASSERT_HRESULT_SUCCEEDED(
2080 text_range_provider->ExpandToEnclosingUnit(TextUnit_Format));
2081 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain\ntext");
2082
2083 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2084 text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
2085 /*count*/ 3,
2086 /*expected_text*/ L"plain\ntext\nita",
2087 /*expected_count*/ 3);
2088
2089 EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
2090 text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
2091 /*count*/ 10,
2092 /*expected_text*/ L"ta",
2093 /*expected_count*/ 10);
2094
2095 ASSERT_HRESULT_SUCCEEDED(
2096 text_range_provider->ExpandToEnclosingUnit(TextUnit_Format));
2097 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"italic\ntext");
2098 }
2099
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,EntireMarkupSuccessiveMoveByCharacter)2100 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2101 EntireMarkupSuccessiveMoveByCharacter) {
2102 AssertMoveByUnitForMarkup(
2103 TextUnit_Character, "Test ing.",
2104 {L"T", L"e", L"s", L"t", L" ", L"i", L"n", L"g", L"."});
2105
2106 // The text consists of an e acute, and two emoticons.
2107 const std::string html = R"HTML(<!DOCTYPE html>
2108 <html>
2109 <body>
2110 <input type="text" value="">
2111 <script>
2112 document.querySelector('input').value = 'e\u0301' +
2113 '\uD83D\uDC69\u200D\u2764\uFE0F\u200D\uD83D\uDC69' +
2114 '\uD83D\uDC36';
2115 </script>
2116 </body>
2117 </html>)HTML";
2118 AssertMoveByUnitForMarkup(
2119 TextUnit_Character, html,
2120 {L"e\x0301", L"\xD83D\xDC69\x200D\x2764\xFE0F\x200D\xD83D\xDC69",
2121 L"\xD83D\xDC36"});
2122 }
2123
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,EntireMarkupSuccessiveMoveByWord)2124 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2125 EntireMarkupSuccessiveMoveByWord) {
2126 AssertMoveByUnitForMarkup(TextUnit_Word, "this is a test.",
2127 {L"this ", L"is ", L"a ", L"test."});
2128
2129 AssertMoveByUnitForMarkup(TextUnit_Word,
2130 " this is a test. ",
2131 {L"this ", L"is ", L"a ", L"test."});
2132
2133 AssertMoveByUnitForMarkup(
2134 TextUnit_Word, "It said: to be continued...",
2135 {L"It ", L"said: ", L"to ", L"be ", L"continued..."});
2136
2137 AssertMoveByUnitForMarkup(TextUnit_Word,
2138 "a <a>link with multiple words</a> and text after.",
2139 {L"a ", L"link ", L"with ", L"multiple ", L"words",
2140 L"and ", L"text ", L"after."});
2141
2142 AssertMoveByUnitForMarkup(TextUnit_Word,
2143 "a <span aria-hidden='true'>span with ignored "
2144 "text</span> and text after.",
2145 {L"a ", L"and ", L"text ", L"after."});
2146
2147 AssertMoveByUnitForMarkup(
2148 TextUnit_Word, "<ol><li>item one</li><li>item two</li></ol>",
2149 {L"1. ", L"item ", L"one", L"2. ", L"item ", L"two"});
2150
2151 AssertMoveByUnitForMarkup(TextUnit_Word,
2152 "<ul><li>item one</li><li>item two</li></ul>",
2153 {L"• ", L"item ", L"one", L"• ", L"item ", L"two"});
2154 }
2155
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,EntireMarkupSuccessiveMoveByFormat)2156 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2157 EntireMarkupSuccessiveMoveByFormat) {
2158 AssertMoveByUnitForMarkup(
2159 TextUnit_Format,
2160 "plain text <b>bold text <i>bold and italic text</i></b><i><b> more bold "
2161 "and italic text</b> italic text</i> plain text",
2162 {L"plain text ", L"bold text ",
2163 L"bold and italic text more bold and italic text", L" italic text",
2164 L" plain text"});
2165
2166 AssertMoveByUnitForMarkup(
2167 TextUnit_Format, "before <img src='test'> after",
2168 {L"before ", kEmbeddedCharacterAsString.c_str(), L" after"});
2169
2170 AssertMoveByUnitForMarkup(TextUnit_Format,
2171 "before <a href='test'>link</a> after",
2172 {L"before ", L"link", L" after"});
2173
2174 AssertMoveByUnitForMarkup(TextUnit_Format,
2175 "before <a href='test'><b>link </b></a> after",
2176 {L"before ", L"link ", L"after"});
2177
2178 AssertMoveByUnitForMarkup(TextUnit_Format,
2179 "before <b><a href='test'>link </a></b> after",
2180 {L"before ", L"link ", L"after"});
2181
2182 AssertMoveByUnitForMarkup(
2183 TextUnit_Format, "before <a href='test'>link </a> after <b>bold</b>",
2184 {L"before ", L"link ", L"after ", L"bold"});
2185
2186 AssertMoveByUnitForMarkup(
2187 TextUnit_Format,
2188 "before <a style='font-weight:bold' href='test'>link </a> after",
2189 {L"before ", L"link ", L"after"});
2190
2191 AssertMoveByUnitForMarkup(
2192 TextUnit_Format,
2193 "before <a style='font-weight:bold' href='test'>link 1</a><a "
2194 "style='font-weight:bold' href='test'>link 2</a> after",
2195 {L"before ", L"link 1link 2", L" after"});
2196
2197 AssertMoveByUnitForMarkup(
2198 TextUnit_Format,
2199 "before <span style='font-weight:bold'>text </span> after",
2200 {L"before ", L"text ", L"after"});
2201
2202 AssertMoveByUnitForMarkup(
2203 TextUnit_Format,
2204 "before <span style='font-weight:bold'>text 1</span><span "
2205 "style='font-weight:bold'>text 2</span> after",
2206 {L"before ", L"text 1text 2", L" after"});
2207
2208 AssertMoveByUnitForMarkup(
2209 TextUnit_Format,
2210 "before <span style='font-weight:bold'>bold text</span><span "
2211 "style='font-style: italic'>italic text</span> after",
2212 {L"before ", L"bold text", L"italic text", L" after"});
2213 }
2214
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,EntireMarkupSuccessiveMoveByLine)2215 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2216 EntireMarkupSuccessiveMoveByLine) {
2217 AssertMoveByUnitForMarkup(TextUnit_Line, "<div style='width:0'>one two</div>",
2218 {L"one ", L"two"});
2219
2220 AssertMoveByUnitForMarkup(TextUnit_Line, "line one<br>line two",
2221 {L"line one", L"line two"});
2222
2223 AssertMoveByUnitForMarkup(TextUnit_Line,
2224 "<div>line one</div><div><div>line two</div></div>",
2225 {L"line one", L"line two"});
2226
2227 AssertMoveByUnitForMarkup(
2228 TextUnit_Line, "<div style='display:inline-block'>a</div>", {L"a"});
2229
2230 // This tests a weird edge-case; TextUnit_Line breaks at the beginning of an
2231 // inline-block, but not at the end.
2232 AssertMoveByUnitForMarkup(TextUnit_Line,
2233 "a<div style='display:inline-block'>b</div>c",
2234 {L"a", L"b\nc"});
2235
2236 AssertMoveByUnitForMarkup(
2237 TextUnit_Line,
2238 "<h1>line one</h1><ul><li>line two</li><li>line three</li></ul>",
2239 {L"line one", L"• line two", L"• line three"});
2240 }
2241
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveByCharacterWithEmbeddedObject)2242 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2243 MoveByCharacterWithEmbeddedObject) {
2244 const std::string html_markup = R"HTML(<!DOCTYPE html>
2245 <html>
2246 <body>
2247 <div>
2248 <label for="input1">Some text</label>
2249 <input id="input1">
2250 <p>after</p>
2251 </div>
2252 </body>
2253 </html>)HTML";
2254
2255 const std::vector<const wchar_t*> characters = {
2256 L"S", L"o", L"m", L"e", L" ",
2257 L"t", L"e", L"x", L"t", kEmbeddedCharacterAsString.c_str(),
2258 L"a", L"f", L"t", L"e", L"r"};
2259
2260 AssertMoveByUnitForMarkup(TextUnit_Character, html_markup, characters);
2261 }
2262
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveByWordWithEmbeddedObject)2263 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2264 MoveByWordWithEmbeddedObject) {
2265 const std::string html_markup = R"HTML(<!DOCTYPE html>
2266 <html>
2267 <body>
2268 <div>
2269 <label for="input1">Some text </label>
2270 <input id="input1">
2271 <p> after input</p>
2272 <button><div></div></button>
2273 </div>
2274 </body>
2275 </html>)HTML";
2276
2277 const std::vector<const wchar_t*> words = {
2278 L"Some ", L"text ", kEmbeddedCharacterAsString.c_str(),
2279 L"after ", L"input", kEmbeddedCharacterAsString.c_str()};
2280
2281 AssertMoveByUnitForMarkup(TextUnit_Word, html_markup, words);
2282 }
2283
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,BoundingRectangleOfWordBeforeListItemMarker)2284 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2285 BoundingRectangleOfWordBeforeListItemMarker) {
2286 LoadInitialAccessibilityTreeFromHtml(
2287 R"HTML(<!DOCTYPE html>
2288 <html>
2289 <body>
2290 <p>Text before list</p>
2291 <ul>
2292 <li>First list item</li>
2293 <li>Second list item</li>
2294 </ul>
2295 </body>
2296 </html>)HTML");
2297
2298 BrowserAccessibility* text_before_list =
2299 FindNode(ax::mojom::Role::kStaticText, "Text before list");
2300 ASSERT_NE(nullptr, text_before_list);
2301
2302 ComPtr<ITextRangeProvider> text_range_provider;
2303 GetTextRangeProviderFromTextNode(*text_before_list, &text_range_provider);
2304 ASSERT_NE(nullptr, text_range_provider.Get());
2305
2306 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
2307 /*count*/ 12,
2308 /*expected_text*/ L"l",
2309 /*expected_count*/ 12);
2310 text_range_provider->ExpandToEnclosingUnit(TextUnit_Word);
2311 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"list");
2312
2313 base::win::ScopedSafearray rectangles;
2314 ASSERT_HRESULT_SUCCEEDED(
2315 text_range_provider->GetBoundingRectangles(rectangles.Receive()));
2316
2317 gfx::Vector2d view_offset = text_before_list->manager()
2318 ->GetViewBoundsInScreenCoordinates()
2319 .OffsetFromOrigin();
2320 std::vector<double> expected_values = {85 + view_offset.x(),
2321 16 + view_offset.y(), 20, 17};
2322 EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(rectangles.Get(), expected_values);
2323
2324 EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
2325 /*count*/ 19,
2326 /*expected_text*/ L"e",
2327 /*expected_count*/ 19);
2328 text_range_provider->ExpandToEnclosingUnit(TextUnit_Word);
2329 EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"item");
2330
2331 ASSERT_HRESULT_SUCCEEDED(
2332 text_range_provider->GetBoundingRectangles(rectangles.Receive()));
2333 expected_values = {105 + view_offset.x(), 50 + view_offset.y(), 28, 17};
2334 EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(rectangles.Get(), expected_values);
2335 }
2336
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,MoveByFormatWithGeneratedContentTableAndSpans)2337 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
2338 MoveByFormatWithGeneratedContentTableAndSpans) {
2339 const std::string html_markup =
2340 "<!DOCTYPE html>"
2341 "<style>"
2342 "h2:before, h2:after { content: \" \"; display: table; }"
2343 "span {white-space: pre; }"
2344 "</style>"
2345 "<div><h2>First Heading</h2><span>\nParagraph One</span></div>"
2346 "<div><h2>Second Heading</h2><span>\nParagraph Two</span></div>";
2347
2348 const std::vector<const wchar_t*> format_units = {
2349 L" \nFirst Heading ", L"\nParagraph One", L" \nSecond Heading ",
2350 L"\nParagraph Two"};
2351
2352 AssertMoveByUnitForMarkup(TextUnit_Format, html_markup, format_units);
2353 }
2354
2355 // https://crbug.com/1036397
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,DISABLED_MoveByFormatWithGeneratedContentTableAndParagraphs)2356 IN_PROC_BROWSER_TEST_F(
2357 AXPlatformNodeTextRangeProviderWinBrowserTest,
2358 DISABLED_MoveByFormatWithGeneratedContentTableAndParagraphs) {
2359 const std::string html_markup = R"HTML(<!DOCTYPE html>
2360 <html>
2361 <style>
2362 h2:before, h2:after { content: " "; display: table; }
2363 </style>
2364 <div><h2>First Heading</h2><p>Paragraph One</p></div>
2365 <div><h2>Second Heading</h2><p>Paragraph Two</p></div>
2366 </html>)HTML";
2367
2368 const std::vector<const wchar_t*> format_units = {
2369 L" \nFirst Heading ", L"\nParagraph One", L" \nSecond Heading ",
2370 L"\nParagraph Two"};
2371
2372 AssertMoveByUnitForMarkup(TextUnit_Format, html_markup, format_units);
2373 }
2374
2375 } // namespace content
2376