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