blob: 565ccbc59fb611271430f643656798bbc70f5e30 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_safearray.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/accessibility_content_browsertest.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_com_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/test/accessibility_notification_waiter.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/hit_test_region_observer.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
using Microsoft::WRL::ComPtr;
namespace content {
#define EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(safearray, expected_property_values) \
{ \
EXPECT_EQ(sizeof(V_R8(LPVARIANT(NULL))), \
::SafeArrayGetElemsize(safearray)); \
ASSERT_EQ(1u, SafeArrayGetDim(safearray)); \
LONG array_lower_bound; \
ASSERT_HRESULT_SUCCEEDED( \
SafeArrayGetLBound(safearray, 1, &array_lower_bound)); \
LONG array_upper_bound; \
ASSERT_HRESULT_SUCCEEDED( \
SafeArrayGetUBound(safearray, 1, &array_upper_bound)); \
double* array_data; \
ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData( \
safearray, reinterpret_cast<void**>(&array_data))); \
size_t count = array_upper_bound - array_lower_bound + 1; \
ASSERT_EQ(expected_property_values.size(), count); \
for (size_t i = 0; i < count; ++i) { \
EXPECT_EQ(array_data[i], expected_property_values[i]); \
} \
ASSERT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(safearray)); \
}
#define EXPECT_UIA_TEXTRANGE_EQ(provider, expected_content) \
{ \
base::win::ScopedBstr provider_content; \
ASSERT_HRESULT_SUCCEEDED( \
provider->GetText(-1, provider_content.Receive())); \
EXPECT_STREQ(expected_content, provider_content); \
}
#define EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider, endpoint, unit, \
count, expected_text, expected_count) \
{ \
int result_count; \
EXPECT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( \
endpoint, unit, count, &result_count)); \
EXPECT_EQ(expected_count, result_count); \
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, expected_text); \
}
#define EXPECT_UIA_MOVE(text_range_provider, unit, count, expected_text, \
expected_count) \
{ \
int result_count; \
EXPECT_HRESULT_SUCCEEDED( \
text_range_provider->Move(unit, count, &result_count)); \
EXPECT_EQ(expected_count, result_count); \
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, expected_text); \
}
class AXPlatformNodeTextRangeProviderWinBrowserTest
: public AccessibilityContentBrowserTest {
protected:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
}
RenderWidgetHostImpl* GetWidgetHost() {
return RenderWidgetHostImpl::From(
shell()->web_contents()->GetRenderViewHost()->GetWidget());
}
void SynchronizeThreads() {
MainThreadFrameObserver observer(GetWidgetHost());
observer.Wait();
}
BrowserAccessibilityManager* GetManager() const {
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
return web_contents->GetRootBrowserAccessibilityManager();
}
void GetTextRangeProviderFromTextNode(
const BrowserAccessibility& target_node,
ITextRangeProvider** text_range_provider) {
BrowserAccessibilityComWin* target_node_com =
ToBrowserAccessibilityWin(&target_node)->GetCOM();
ASSERT_NE(nullptr, target_node_com);
ComPtr<ITextProvider> text_provider;
ASSERT_HRESULT_SUCCEEDED(
target_node_com->GetPatternProvider(UIA_TextPatternId, &text_provider));
ASSERT_NE(nullptr, text_provider.Get());
ASSERT_HRESULT_SUCCEEDED(
text_provider->get_DocumentRange(text_range_provider));
}
void GetDocumentRangeForMarkup(const std::string& html_markup,
ITextRangeProvider** text_range_provider) {
LoadInitialAccessibilityTreeFromHtml(html_markup);
GetTextRangeProviderFromTextNode(*GetManager()->GetRoot(),
text_range_provider);
}
// Run through ITextRangeProvider::ScrollIntoView top tests. It's assumed that
// the browser has already loaded an HTML document's accessibility tree.
// Assert the text range generated for an accessibility node is scrolled to be
// flush with the top of the viewport.
// expected_start_role: the expected accessibility role of the text range
// start node under test
// fstart: the function to retrieve the accessibility text
// range start node under test from the root
// accessibility node
// expected_end_role: the expected accessibility role of the text range
// end node under test
// fend: the function to retrieve the accessibility text
// range end node under test from the root
// accessibility node
// align_to_top: true to test top viewport alignment, otherwise test
// bottom viewport alignment
void 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) {
BrowserAccessibility* root_browser_accessibility =
GetRootAndAssertNonNull();
BrowserAccessibility* browser_accessibility_start =
(root_browser_accessibility->*fstart)();
ASSERT_NE(nullptr, browser_accessibility_start);
ASSERT_EQ(expected_start_role, browser_accessibility_start->GetRole());
BrowserAccessibility* browser_accessibility_end =
(root_browser_accessibility->*fend)();
ASSERT_NE(nullptr, browser_accessibility_end);
ASSERT_EQ(expected_end_role, browser_accessibility_end->GetRole());
AssertScrollIntoView(root_browser_accessibility,
browser_accessibility_start, browser_accessibility_end,
align_to_top);
}
// Run through ITextRangeProvider::ScrollIntoView top tests. It's assumed that
// the browser has already loaded an HTML document's accessibility tree.
// Assert the text range generated for an accessibility node is scrolled to be
// flush with the top of the viewport.
// expected_start_role: the expected accessibility role of the text range
// start node under test
// fstart: the function to retrieve the accessibility text
// range start node under test from the root
// accessibility node
// fstart_arg: an index argument for fstart
// expected_end_role: the expected accessibility role of the text range
// end node under test
// fend: the function to retrieve the accessibility text
// range end node under test from the root
// accessibility node
// fend_arg: an index argument for fend
// align_to_top: true to test top viewport alignment, otherwise test
// bottom viewport alignment
void 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) {
BrowserAccessibility* root_browser_accessibility =
GetRootAndAssertNonNull();
BrowserAccessibility* browser_accessibility_start =
(root_browser_accessibility->*fstart)(fstart_arg);
ASSERT_NE(nullptr, browser_accessibility_start);
ASSERT_EQ(expected_start_role, browser_accessibility_start->GetRole());
BrowserAccessibility* browser_accessibility_end =
(root_browser_accessibility->*fend)(fend_arg);
ASSERT_NE(nullptr, browser_accessibility_end);
ASSERT_EQ(expected_end_role, browser_accessibility_end->GetRole());
AssertScrollIntoView(root_browser_accessibility,
browser_accessibility_start, browser_accessibility_end,
align_to_top);
}
void 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) {
BrowserAccessibility* root_browser_accessibility =
GetRootAndAssertNonNull();
BrowserAccessibility* leaf_iframe_browser_accessibility =
root_browser_accessibility->InternalDeepestLastChild();
ASSERT_NE(nullptr, leaf_iframe_browser_accessibility);
ASSERT_EQ(ax::mojom::Role::kIframe,
leaf_iframe_browser_accessibility->GetRole());
AXTreeID iframe_tree_id = AXTreeID::FromString(
leaf_iframe_browser_accessibility->GetStringAttribute(
ax::mojom::StringAttribute::kChildTreeId));
BrowserAccessibilityManager* iframe_browser_accessibility_manager =
BrowserAccessibilityManager::FromID(iframe_tree_id);
ASSERT_NE(nullptr, iframe_browser_accessibility_manager);
BrowserAccessibility* root_iframe_browser_accessibility =
iframe_browser_accessibility_manager->GetRoot();
ASSERT_NE(nullptr, root_iframe_browser_accessibility);
ASSERT_EQ(ax::mojom::Role::kRootWebArea,
root_iframe_browser_accessibility->GetRole());
BrowserAccessibility* browser_accessibility_start =
(root_iframe_browser_accessibility->*fstart)();
ASSERT_NE(nullptr, browser_accessibility_start);
ASSERT_EQ(expected_start_role, browser_accessibility_start->GetRole());
BrowserAccessibility* browser_accessibility_end =
(root_iframe_browser_accessibility->*fend)();
ASSERT_NE(nullptr, browser_accessibility_end);
ASSERT_EQ(expected_end_role, browser_accessibility_end->GetRole());
AssertScrollIntoView(root_iframe_browser_accessibility,
browser_accessibility_start, browser_accessibility_end,
align_to_top);
}
void AssertScrollIntoView(BrowserAccessibility* root_browser_accessibility,
BrowserAccessibility* browser_accessibility_start,
BrowserAccessibility* browser_accessibility_end,
const bool align_to_top) {
ui::AXNodePosition::AXPositionInstance start =
browser_accessibility_start->CreateTextPositionAt(0);
ui::AXNodePosition::AXPositionInstance end =
browser_accessibility_end->CreateTextPositionAt(0)
->CreatePositionAtEndOfAnchor();
BrowserAccessibilityComWin* start_browser_accessibility_com_win =
ToBrowserAccessibilityWin(browser_accessibility_start)->GetCOM();
ASSERT_NE(nullptr, start_browser_accessibility_com_win);
CComPtr<ITextRangeProvider> text_range_provider =
ui::AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
start_browser_accessibility_com_win, std::move(start),
std::move(end));
ASSERT_NE(nullptr, text_range_provider);
gfx::Rect previous_range_bounds =
align_to_top ? browser_accessibility_start->GetBoundsRect(
ui::AXCoordinateSystem::kFrame,
ui::AXClippingBehavior::kUnclipped)
: browser_accessibility_end->GetBoundsRect(
ui::AXCoordinateSystem::kFrame,
ui::AXClippingBehavior::kUnclipped);
AccessibilityNotificationWaiter location_changed_waiter(
GetWebContentsAndAssertNonNull(), ui::kAXModeComplete,
ax::mojom::Event::kLocationChanged);
ASSERT_HRESULT_SUCCEEDED(text_range_provider->ScrollIntoView(align_to_top));
location_changed_waiter.WaitForNotification();
gfx::Rect root_page_bounds = root_browser_accessibility->GetBoundsRect(
ui::AXCoordinateSystem::kFrame, ui::AXClippingBehavior::kUnclipped);
if (align_to_top) {
gfx::Rect range_bounds = browser_accessibility_start->GetBoundsRect(
ui::AXCoordinateSystem::kFrame, ui::AXClippingBehavior::kUnclipped);
ASSERT_NE(previous_range_bounds.y(), range_bounds.y());
ASSERT_NEAR(root_page_bounds.y(), range_bounds.y(), 1);
} else {
gfx::Rect range_bounds = browser_accessibility_end->GetBoundsRect(
ui::AXCoordinateSystem::kFrame, ui::AXClippingBehavior::kUnclipped);
gfx::Size viewport_size =
gfx::Size(root_page_bounds.width(), root_page_bounds.height());
ASSERT_NE(previous_range_bounds.y(), range_bounds.y());
ASSERT_NEAR(root_page_bounds.y() + viewport_size.height(),
range_bounds.y() + range_bounds.height(), 1);
}
}
void ScrollIntoViewTopBrowserTestTemplate(
const ax::mojom::Role expected_role,
BrowserAccessibility* (BrowserAccessibility::*f)() const) {
ScrollIntoViewBrowserTestTemplate(expected_role, f, expected_role, f, true);
}
void ScrollIntoViewTopBrowserTestTemplate(
const ax::mojom::Role expected_role_start,
BrowserAccessibility* (BrowserAccessibility::*fstart)() const,
const ax::mojom::Role expected_role_end,
BrowserAccessibility* (BrowserAccessibility::*fend)() const) {
ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart,
expected_role_end, fend, true);
}
void 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) {
ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart, fstart_arg,
expected_role_end, fend, fend_arg, true);
}
void ScrollIntoViewBottomBrowserTestTemplate(
const ax::mojom::Role expected_role,
BrowserAccessibility* (BrowserAccessibility::*f)() const) {
ScrollIntoViewBrowserTestTemplate(expected_role, f, expected_role, f,
false);
}
void ScrollIntoViewBottomBrowserTestTemplate(
const ax::mojom::Role expected_role_start,
BrowserAccessibility* (BrowserAccessibility::*fstart)() const,
const ax::mojom::Role expected_role_end,
BrowserAccessibility* (BrowserAccessibility::*fend)() const) {
ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart,
expected_role_end, fend, false);
}
void 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) {
ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart, fstart_arg,
expected_role_end, fend, fend_arg, false);
}
void AssertMoveByUnitForMarkup(
const TextUnit& unit,
const std::string& html_markup,
const std::vector<const wchar_t*>& expected_text) {
ComPtr<ITextRangeProvider> text_range;
GetDocumentRangeForMarkup(html_markup, &text_range);
ASSERT_NE(nullptr, text_range.Get());
text_range->ExpandToEnclosingUnit(unit);
size_t index = 0;
int count_moved = 1;
while (count_moved == 1 && index < expected_text.size()) {
EXPECT_UIA_TEXTRANGE_EQ(text_range, expected_text[index++]);
ASSERT_HRESULT_SUCCEEDED(text_range->Move(unit, 1, &count_moved));
}
EXPECT_EQ(expected_text.size(), index);
EXPECT_EQ(0, count_moved);
count_moved = -1;
index = expected_text.size();
while (count_moved == -1 && index > 0) {
EXPECT_UIA_TEXTRANGE_EQ(text_range, expected_text[--index]);
ASSERT_HRESULT_SUCCEEDED(text_range->Move(unit, -1, &count_moved));
}
EXPECT_EQ(0, count_moved);
EXPECT_EQ(0u, index);
}
};
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
GetBoundingRectangles) {
LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
<!DOCTYPE html>
<html>
<head>
<style>
.break_word {
width: 50px;
word-wrap: break-word;
}
</style>
</head>
<body>
<p class="break_word">AsdfAsdfAsdf</p>
</body>
</html>
)HTML"));
auto* node = FindNode(ax::mojom::Role::kStaticText, "AsdfAsdfAsdf");
ASSERT_NE(nullptr, node);
EXPECT_TRUE(node->PlatformIsLeaf());
EXPECT_EQ(0u, node->PlatformChildCount());
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"AsdfAsdfAsdf");
base::win::ScopedSafearray rectangles;
EXPECT_HRESULT_SUCCEEDED(
text_range_provider->GetBoundingRectangles(rectangles.Receive()));
// |view_offset| is necessary to account for differences in the shell
// between platforms (e.g. title bar height) because the results of
// |GetBoundingRectangles| are in screen coordinates.
gfx::Vector2d view_offset =
node->manager()->GetViewBounds().OffsetFromOrigin();
std::vector<double> expected_values = {
8 + view_offset.x(), 16 + view_offset.y(), 49, 17,
8 + view_offset.x(), 34 + view_offset.y(), 44, 17};
EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(rectangles.Get(), expected_values);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopStaticText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/text.html");
ScrollIntoViewTopBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestFirstChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomStaticText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/text.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestFirstChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopEmbeddedText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/embedded-text.html");
ScrollIntoViewTopBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomEmbeddedText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/embedded-text.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopEmbeddedTextCrossNode) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/embedded-text.html");
ScrollIntoViewTopBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestFirstChild,
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomEmbeddedTextCrossNode) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/embedded-text.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestFirstChild,
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopTable) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/table.html");
ScrollIntoViewTopBrowserTestTemplate(
ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0,
ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomTable) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/table.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0,
ax::mojom::Role::kTable, &BrowserAccessibility::PlatformGetChild, 0);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopTableText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/table.html");
ScrollIntoViewTopBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomTableText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/table.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopLinkText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/link.html");
ScrollIntoViewTopBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomLinkText) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/link.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopLinkContainer) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/link.html");
ScrollIntoViewTopBrowserTestTemplate(ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild,
0, ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild,
0);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomLinkContainer) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/link.html");
ScrollIntoViewBottomBrowserTestTemplate(
ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild, 0,
ax::mojom::Role::kGenericContainer,
&BrowserAccessibility::PlatformGetChild, 0);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewTopTextFromIFrame) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/iframe-text.html");
WaitForAccessibilityTreeToContainNodeWithName(
shell()->web_contents(),
"Game theory is \"the study of Mathematical model mathematical models of "
"conflict and cooperation between intelligent rational decision-makers."
"\"");
ScrollIntoViewFromIframeBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestFirstChild,
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild, true);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ScrollIntoViewBottomTextFromIFrame) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/scrolling/iframe-text.html");
WaitForAccessibilityTreeToContainNodeWithName(
shell()->web_contents(),
"Game theory is \"the study of Mathematical model mathematical models of "
"conflict and cooperation between intelligent rational decision-makers."
"\"");
ScrollIntoViewFromIframeBrowserTestTemplate(
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestFirstChild,
ax::mojom::Role::kStaticText,
&BrowserAccessibility::PlatformDeepestLastChild, false);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
MoveEndpointByUnitFormat) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<body>
<div>plain 1</div><div>plain 2</div>
<div style="font-style: italic">italic 1</div>
<div style="font-style: italic">italic 2</div>
<div style="font-weight: bold">bold 1</div>
<div style="font-weight: bold">bold 2</div>
</body>
</html>)HTML");
auto* node = FindNode(ax::mojom::Role::kStaticText, "plain 1");
ASSERT_NE(nullptr, node);
EXPECT_TRUE(node->PlatformIsLeaf());
EXPECT_EQ(0u, node->PlatformChildCount());
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain 1");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1,
/*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1,
/*expected_text*/
L"plain 1\nplain 2\nitalic 1\nitalic 2",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/ L"plain 1\nplain 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1,
/*expected_text*/
L"plain 1\nplain 2\nitalic 1\nitalic 2",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 5,
/*expected_text*/
L"plain 1\nplain 2\nitalic 1\nitalic 2\nbold 1\nbold 2",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -4,
/*expected_text*/ L"",
/*expected_count*/ -3);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1,
/*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ 1);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
MoveEndpointByUnitFormatAllFormats) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<body>
<div>plain 1</div><div>plain 2</div>
<div style="background-color: red">background-color 1</div>
<div style="background-color: red">background-color 2</div>
<div style="color: blue">color 1</div>
<div style="color: blue">color 2</div>
<div style="text-decoration: overline">overline 1</div>
<div style="text-decoration: overline">overline 2</div>
<div style="text-decoration: line-through">line-through 1</div>
<div style="text-decoration: line-through">line-through 2</div>
<div style="vertical-align:super">sup 1</div>
<div style="vertical-align:super">sup 2</div>
<div style="font-weight: bold">bold 1</div>
<div style="font-weight: bold">bold 2</div>
<div style="font-family: sans-serif">font-family 1</div>
<div style="font-family: sans-serif">font-family 2</div>
</body>
</html>)HTML");
auto* node = FindNode(ax::mojom::Role::kStaticText, "plain 1");
ASSERT_NE(nullptr, node);
EXPECT_TRUE(node->PlatformIsLeaf());
EXPECT_EQ(0u, node->PlatformChildCount());
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain 1");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1,
/*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/ L"plain 1\nplain 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through 2",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\nbold 1\nbold 2",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\nbold 1\nbold 2\nfont-family 1\nfont-family 2",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\nbold 1\nbold 2\n",
/*expected_count*/ -1);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
MoveEndpointByUnitParagraph) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<head><style>
div {
width: 100px;
}
code::before {
content: "[";
}
code::after {
content: "]";
}
b::before, i::after {
width: 5px;
height: 5px;
content: "";
display: block;
background: black;
}
</style></head>
<body>
<div>start</div>
<div>
text with <code>:before</code>
and <code>:after</code> content,
then a <b>bold</b> element with a
<code>block</code> before content
then a <i>italic</i> element with
a <code>block</code> after content
</div>
<div>end</div>
</body>
</html>)HTML");
BrowserAccessibility* start_node =
FindNode(ax::mojom::Role::kStaticText, "start");
ASSERT_NE(nullptr, start_node);
BrowserAccessibility* end_node =
FindNode(ax::mojom::Role::kStaticText, "end");
ASSERT_NE(nullptr, end_node);
std::vector<base::string16> paragraphs = {
L"start",
L"text with [:before] and [:after]content, then a",
L"bold element with a [block]before content then a italic",
L"element with a [block] after content",
L"end",
};
// FORWARD NAVIGATION
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ 0);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -2,
/*expected_text*/ L"",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[1].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[2].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[2] + paragraphs[3]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[3].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[3] + L"\n" + paragraphs[4]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[4].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[4].c_str(),
/*expected_count*/ 0);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 2,
/*expected_text*/ L"",
/*expected_count*/ 1);
// REVERSE NAVIGATION
GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[4].c_str(),
/*expected_count*/ 0);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 2,
/*expected_text*/ L"",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[4].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[3] + L"\n" + paragraphs[4]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[3].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[2] + paragraphs[3]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[2].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[1].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ 0);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -2,
/*expected_text*/ L"",
/*expected_count*/ -1);
}
IN_PROC_BROWSER_TEST_F(
AXPlatformNodeTextRangeProviderWinBrowserTest,
MoveEndpointByUnitParagraphCollapseTrailingLineBreakingObjects) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<body>
<div>start</div>
<div>
<div>some text</div>
<div></div>
<br>
<span><br><div><br></div></span>
<div>more text</div>
</div>
<div>end</div>
</body>
</html>)HTML");
BrowserAccessibility* start_node =
FindNode(ax::mojom::Role::kStaticText, "start");
ASSERT_NE(nullptr, start_node);
BrowserAccessibility* end_node =
FindNode(ax::mojom::Role::kStaticText, "end");
ASSERT_NE(nullptr, end_node);
std::vector<base::string16> paragraphs = {
L"start",
L"some text\n\n\n",
L"more text",
L"end",
};
// FORWARD NAVIGATION
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[1].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[2].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[2] + L"\n" + paragraphs[3]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[3].c_str(),
/*expected_count*/ 1);
// REVERSE NAVIGATION
GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[2] + L"\n" + paragraphs[3]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[2].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[1].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[0] + L"\n" + paragraphs[1]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ -1);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
MoveEndpointByUnitParagraphPreservedWhiteSpace) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<body>
<div>start</div>
<span style='white-space: pre'>
First Paragraph
Second Paragraph
</span>
<!--
Intentional nesting to test that ancestor positions can
resolve to the newline at the start of preserved whitespace.
-->
<div>
<div style='white-space: pre-line'>
Third Paragraph
Fourth Paragraph
</div>
</div>
<div style='white-space: pre-wrap; width: 10em;'>
Fifth Paragraph
Sixth Paragraph
</div>
<div style='white-space: break-spaces; width: 10em;'>
Seventh Paragraph
Eighth Paragraph
</div>
<div>end</div>
</body>
</html>)HTML");
BrowserAccessibility* start_node =
FindNode(ax::mojom::Role::kStaticText, "start");
ASSERT_NE(nullptr, start_node);
BrowserAccessibility* end_node =
FindNode(ax::mojom::Role::kStaticText, "end");
ASSERT_NE(nullptr, end_node);
ComPtr<ITextRangeProvider> text_range_provider;
std::vector<base::string16> paragraphs = {
L"start\n",
L" First Paragraph\n",
L" Second Paragraph\n \n",
L"Third Paragraph\n",
L"Fourth Paragraph\n\n ",
L"Fifth Paragraph\n ",
L"Sixth Paragraph\n \n ",
L"Seventh Paragraph\n ",
L"Eighth Paragraph\n ",
L"end",
};
// FORWARD NAVIGATION
GetTextRangeProviderFromTextNode(*start_node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
// The first paragraph extends beyond the end of the "start" node, because
// the preserved whitespace node begins with a line break, so
// move once to capture that.
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[0] + paragraphs[1]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[1].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[2].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[2] + paragraphs[3]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[3].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[3] + paragraphs[4]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[4].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[4] + paragraphs[5]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[5].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[5] + paragraphs[6]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[6].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[6] + paragraphs[7]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[7].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[7] + paragraphs[8]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[8].c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ (paragraphs[8] + paragraphs[9]).c_str(),
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ 1,
/*expected_text*/ paragraphs[9].c_str(),
/*expected_count*/ 1);
// REVERSE NAVIGATION
GetTextRangeProviderFromTextNode(*end_node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[8] + paragraphs[9]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[8].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[7] + paragraphs[8]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[7].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[6] + paragraphs[7]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[6].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[5] + paragraphs[6]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[5].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[4] + paragraphs[5]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[4].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[3] + paragraphs[4]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[3].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[2] + paragraphs[3]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[2].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[1] + paragraphs[2]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[1].c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ (paragraphs[0] + paragraphs[1]).c_str(),
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph,
/*count*/ -1,
/*expected_text*/ paragraphs[0].c_str(),
/*expected_count*/ -1);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
IFrameTraversal) {
LoadInitialAccessibilityTreeFromUrl(embedded_test_server()->GetURL(
"/accessibility/html/iframe-cross-process.html"));
WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
"Text in iframe");
auto* node = FindNode(ax::mojom::Role::kStaticText, "After frame");
ASSERT_NE(nullptr, node);
EXPECT_TRUE(node->PlatformIsLeaf());
EXPECT_EQ(0u, node->PlatformChildCount());
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"After frame");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
/*count*/ -1,
/*expected_text*/ L"iframe\nAfter frame",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
/*count*/ -2,
/*expected_text*/ L"Text in iframe\nAfter frame",
/*expected_count*/ -2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
TextPatternRangeEndpoint_End, TextUnit_Word,
/*count*/ -3,
/*expected_text*/ L"Text in ",
/*expected_count*/ -3);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
TextPatternRangeEndpoint_End, TextUnit_Word,
/*count*/ 2,
/*expected_text*/ L"Text in iframe\nAfter ",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Line,
/*count*/ 1,
/*expected_text*/ L"Text in iframe\nAfter frame",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Document,
/*count*/ 1,
/*expected_text*/ L"",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
/*count*/ -17,
/*expected_text*/ L"iframe\nAfter frame",
/*expected_count*/ -17);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
TextPatternRangeEndpoint_End, TextUnit_Line,
/*count*/ -1,
/*expected_text*/ L"iframe",
/*expected_count*/ -1);
text_range_provider->ExpandToEnclosingUnit(TextUnit_Line);
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Text in iframe\n");
text_range_provider->ExpandToEnclosingUnit(TextUnit_Document);
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
L"Before frame\nText in iframe\nAfter frame");
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
/*count*/ 2,
/*expected_text*/ L"Text ",
/*expected_count*/ 2);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
/*count*/ -1,
/*expected_text*/ L"frame\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
/*count*/ 1,
/*expected_text*/ L"frame\nT",
/*expected_count*/ 1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
/*count*/ 6,
/*expected_text*/ L"e",
/*expected_count*/ 6);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
/*count*/ 19,
/*expected_text*/ L"f",
/*expected_count*/ 19);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Character,
/*count*/ -7,
/*expected_text*/ L"e",
/*expected_count*/ -7);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Line,
/*count*/ 1,
/*expected_text*/ L"After frame",
/*expected_count*/ 1);
text_range_provider->ExpandToEnclosingUnit(TextUnit_Document);
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider,
L"Before frame\nText in iframe\nAfter frame");
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
OutOfProcessIFrameTraversal) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/accessibility/html/iframe-cross-process.html"));
LoadInitialAccessibilityTreeFromUrl(main_url);
WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
"Text in iframe");
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetFrameTree()
->root();
ASSERT_EQ(1U, root->child_count());
// Navigate oopif to URL.
FrameTreeNode* iframe_node = root->child_at(0);
GURL iframe_url(embedded_test_server()->GetURL(
"b.com", "/accessibility/html/frame/static_text.html"));
WebContentsImpl* iframe_web_contents =
WebContentsImpl::FromFrameTreeNode(iframe_node);
DCHECK(iframe_web_contents);
{
AccessibilityNotificationWaiter waiter(iframe_web_contents,
ui::kAXModeComplete,
ax::mojom::Event::kLoadComplete);
NavigateFrameToURL(iframe_node, iframe_url);
waiter.WaitForNotification();
}
SynchronizeThreads();
WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
"Text in iframe");
WaitForHitTestData(iframe_node->current_frame_host());
FrameTreeVisualizer visualizer;
ASSERT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
visualizer.DepictFrameTree(root));
auto* node = FindNode(ax::mojom::Role::kStaticText, "After frame");
ASSERT_NE(nullptr, node);
EXPECT_TRUE(node->PlatformIsLeaf());
EXPECT_EQ(0u, node->PlatformChildCount());
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"After frame");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
/*count*/ -1,
/*expected_text*/ L"iframe\nAfter frame",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
/*count*/ -2,
/*expected_text*/ L"Text in iframe\nAfter frame",
/*expected_count*/ -2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
TextPatternRangeEndpoint_End, TextUnit_Word,
/*count*/ -3,
/*expected_text*/ L"Text in ",
/*expected_count*/ -3);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
TextPatternRangeEndpoint_End, TextUnit_Word,
/*count*/ 2,
/*expected_text*/ L"Text in iframe\nAfter ",
/*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Line,
/*count*/ 1,
/*expected_text*/ L"Text in iframe\nAfter frame",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Document,
/*count*/ 1,
/*expected_text*/ L"",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
/*count*/ -17,
/*expected_text*/ L"iframe\nAfter frame",
/*expected_count*/ -17);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
TextPatternRangeEndpoint_End, TextUnit_Line,
/*count*/ -1,
/*expected_text*/ L"iframe",
/*expected_count*/ -1);
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
ExpandToEnclosingFormat) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<body>
<div>plain</div>
<div>text</div>
<div style="font-style: italic">italic<div>
<div style="font-style: italic">text<div>
</body>
</html>)HTML");
auto* node = FindNode(ax::mojom::Role::kStaticText, "plain");
ASSERT_NE(nullptr, node);
EXPECT_TRUE(node->PlatformIsLeaf());
EXPECT_EQ(0u, node->PlatformChildCount());
ComPtr<ITextRangeProvider> text_range_provider;
GetTextRangeProviderFromTextNode(*node, &text_range_provider);
ASSERT_NE(nullptr, text_range_provider.Get());
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
/*count*/ 3,
/*expected_text*/ L"in",
/*expected_count*/ 3);
ASSERT_HRESULT_SUCCEEDED(
text_range_provider->ExpandToEnclosingUnit(TextUnit_Format));
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain\ntext\n");
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
/*count*/ 3,
/*expected_text*/ L"plain\ntext\nita",
/*expected_count*/ 3);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Character,
/*count*/ 10,
/*expected_text*/ L"ta",
/*expected_count*/ 10);
ASSERT_HRESULT_SUCCEEDED(
text_range_provider->ExpandToEnclosingUnit(TextUnit_Format));
EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"italic\ntext");
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
EntireMarkupSuccessiveMoveByWord) {
AssertMoveByUnitForMarkup(TextUnit_Word, "this is a test.",
{L"this ", L"is ", L"a ", L"test."});
AssertMoveByUnitForMarkup(TextUnit_Word,
" this is a test. ",
{L"this ", L"is ", L"a ", L"test."});
AssertMoveByUnitForMarkup(
TextUnit_Word, "It said: to be continued...",
{L"It ", L"said: ", L"to ", L"be ", L"continued..."});
AssertMoveByUnitForMarkup(TextUnit_Word,
"a <a>link with multiple words</a> and text after.",
{L"a ", L"link ", L"with ", L"multiple ", L"words ",
L"and ", L"text ", L"after."});
// AssertMoveByUnitForMarkup(
// TextUnit_Word, "<ul><li>item one</li><li>item two</li></ul>",
// {L"* ", L"item ", L"one\n", L"* ", L"item ", L"two"});
}
IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
EntireMarkupSuccessiveMoveByFormat) {
AssertMoveByUnitForMarkup(
TextUnit_Format,
"plain text <b>bold text <i>bold and italic text</i></b><i><b> more bold "
"and italic text</b> italic text</i> plain text",
{L"plain text ", L"bold text ",
L"bold and italic text more bold and italic text", L" italic text",
L" plain text"});
AssertMoveByUnitForMarkup(TextUnit_Format, "before <img src='test'> after",
{L"before ", L" after"});
AssertMoveByUnitForMarkup(TextUnit_Format,
"before <a href='test'>link</a> after",
{L"before ", L"link", L" after"});
AssertMoveByUnitForMarkup(TextUnit_Format,
"before <a href='test'><b>link </b></a> after",
{L"before ", L"link ", L"after"});
AssertMoveByUnitForMarkup(TextUnit_Format,
"before <b><a href='test'>link </a></b> after",
{L"before ", L"link ", L"after"});
AssertMoveByUnitForMarkup(
TextUnit_Format, "before <a href='test'>link </a> after <b>bold</b>",
{L"before ", L"link ", L"after ", L"bold"});
AssertMoveByUnitForMarkup(
TextUnit_Format,
"before <a style='font-weight:bold' href='test'>link </a> after",
{L"before ", L"link ", L"after"});
AssertMoveByUnitForMarkup(
TextUnit_Format,
"before <a style='font-weight:bold' href='test'>link 1</a><a "
"style='font-weight:bold' href='test'>link 2</a> after",
{L"before ", L"link 1link 2", L" after"});
AssertMoveByUnitForMarkup(
TextUnit_Format,
"before <span style='font-weight:bold'>text </span> after",
{L"before ", L"text ", L"after"});
AssertMoveByUnitForMarkup(
TextUnit_Format,
"before <span style='font-weight:bold'>text 1</span><span "
"style='font-weight:bold'>text 2</span> after",
{L"before ", L"text 1text 2", L" after"});
AssertMoveByUnitForMarkup(
TextUnit_Format,
"before <span style='font-weight:bold'>bold text</span><span "
"style='font-style: italic'>italic text</span> after",
{L"before ", L"bold text", L"italic text", L" after"});
}
} // namespace content