0

Revert "[a11y] Fixes move by format for CSS spellcheck highlights"

This reverts commit c6bfb8a155.

Reason for revert: This change broke Narrator's move-by-headings
feature. Heading navigation is a critical feature of screen readers that
facilites navigating web pages, like the google/bing results page. It
impacts all headings throughout the web, whereas the original CL was
fixing a scoped problem: spelling errors unannounced when exposed using
CSS highlights. We will also revert this change from 134.

Original change's description:
> [a11y] Fixes move by format for CSS spellcheck highlights
>
> Uses Spelling/Grammar error CSS highlight markers in the
> Accessibility Tree to break format boundaries around those
> errors to help navigate better around these spelling/grammar
> errors.
>
> This CL achieves following:
> 1) Fixes Move by format to accommodate CSS spellcheck highlights.
> 2) Narrator calls out the spelling issues correctly.
>
> Bug: 364795299
> Change-Id: I4842a49449c666100e31f859447f951e9f9eb09e
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6178990
> Auto-Submit: Vinay Singh <vinaysingh@microsoft.com>
> Reviewed-by: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
> Commit-Queue: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
> Cr-Commit-Position: refs/heads/main@{#1415710}

Bug: 402800783, 364795299
Change-Id: I1ee7bd394f18fba21e97e5cc8998de1a03501931
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6349562
Reviewed-by: Jacques Newman <janewman@microsoft.com>
Auto-Submit: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
Commit-Queue: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1431891}
This commit is contained in:
Benjamin Beaudry
2025-03-12 19:50:00 -07:00
committed by Chromium LUCI CQ
parent 03badce254
commit fa24efebcd
5 changed files with 72 additions and 292 deletions

@ -1544,43 +1544,42 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ L"plain 1\nplain 2\n", /*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nplain heading\n", L"plain 1\nplain 2\nplain heading",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\n", L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ L"plain 1\nplain 2\nplain heading\n", /*expected_text*/ L"plain 1\nplain 2\nplain heading",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\n", L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\nheading\n", L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\nheading",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic " L"plain 1\nplain 2\nplain heading\nitalic 1\nitalic 2\nheading\nheading",
L"2\nheading\nheading\n",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1597,7 +1596,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ L"plain 1\nplain 2\n", /*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ 1); /*expected_count*/ 1);
} }
@ -1716,59 +1715,59 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ L"plain 1\nplain 2\n", /*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\n", L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ L"plain 1\nplain 2\n", /*expected_text*/ L"plain 1\nplain 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2, /*count*/ 2,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\n", L"1\ncolor 2",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\n", L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2, /*count*/ 2,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\n", L"1\ncolor 2\noverline 1\noverline 2",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\n", L"1\ncolor 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 2, /*count*/ 2,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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", L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through 2",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor "
L"1\ncolor 2\noverline 1\noverline 2\n", L"1\ncolor 2\noverline 1\noverline 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1776,14 +1775,14 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\n", L"2\nsup 1\nsup 2",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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", L"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1791,7 +1790,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\nbold 1\nbold 2\n", L"2\nsup 1\nsup 2\nbold 1\nbold 2",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1799,7 +1798,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\n", L"2\nsup 1\nsup 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1807,7 +1806,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"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\n", L"2\nsup 1\nsup 2\nbold 1\nbold 2\nfont-family 1\nfont-family 2",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1815,7 +1814,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"1\ncolor 2\noverline 1\noverline 2\nline-through 1\nline-through "
L"2\nsup 1\nsup 2\nbold 1\nbold 2\n", L"2\nsup 1\nsup 2\nbold 1\nbold 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1824,7 +1823,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"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 " L"2\nsup 1\nsup 2\nbold 1\nbold 2\nfont-family 1\nfont-family "
L"2\nspelling 1\nspelling two\n", L"2\nspelling 1\nspelling two",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1832,7 +1831,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
/*expected_text*/ /*expected_text*/
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"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\n", L"2\nsup 1\nsup 2\nbold 1\nbold 2\nfont-family 1\nfont-family 2",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
@ -1850,7 +1849,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
L"plain 1\nplain 2\nbackground-color 1\nbackground-color 2\ncolor " 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"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 " L"2\nsup 1\nsup 2\nbold 1\nbold 2\nfont-family 1\nfont-family "
L"2\nspelling 1\nspelling two\n", L"2\nspelling 1\nspelling two",
/*expected_count*/ -1); /*expected_count*/ -1);
} }
@ -3564,7 +3563,7 @@ IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
"<div><h2>Second Heading</h2><span>\nParagraph Two</span></div>"; "<div><h2>Second Heading</h2><span>\nParagraph Two</span></div>";
const std::vector<const wchar_t*> format_units = { const std::vector<const wchar_t*> format_units = {
L"First Heading", L"\nParagraph One\n", L"Second Heading", L"First Heading", L"\nParagraph One", L"Second Heading",
L"\nParagraph Two"}; L"\nParagraph Two"};
AssertMoveByUnitForMarkup(TextUnit_Format, html_markup, format_units); AssertMoveByUnitForMarkup(TextUnit_Format, html_markup, format_units);
@ -3584,7 +3583,7 @@ IN_PROC_BROWSER_TEST_F(
</html>)HTML"; </html>)HTML";
const std::vector<const wchar_t*> format_units = { const std::vector<const wchar_t*> format_units = {
L"First Heading", L"\nParagraph One\n", L"Second Heading", L"First Heading", L"\nParagraph One", L"Second Heading",
L"\nParagraph Two"}; L"\nParagraph Two"};
AssertMoveByUnitForMarkup(TextUnit_Format, html_markup, format_units); AssertMoveByUnitForMarkup(TextUnit_Format, html_markup, format_units);

@ -917,9 +917,8 @@ class AXPosition {
AXBoundaryType GetFormatStartBoundaryType() const { AXBoundaryType GetFormatStartBoundaryType() const {
// Since formats are stored on text anchors, the start of a format boundary // Since formats are stored on text anchors, the start of a format boundary
// must be at the start of an anchor. // must be at the start of an anchor.
if (IsNullPosition() || !AtStartOfAnchor()) { if (IsNullPosition() || !AtStartOfAnchor())
return AXBoundaryType::kNone; return AXBoundaryType::kNone;
}
// Treat the first iterable node as a format boundary. // Treat the first iterable node as a format boundary.
if (CreatePreviousLeafTreePosition( if (CreatePreviousLeafTreePosition(
@ -929,9 +928,8 @@ class AXPosition {
} }
// Ignored positions cannot be format boundaries. // Ignored positions cannot be format boundaries.
if (IsIgnored()) { if (IsIgnored())
return AXBoundaryType::kNone; return AXBoundaryType::kNone;
}
// Iterate over anchors until a format boundary is found. This will return a // Iterate over anchors until a format boundary is found. This will return a
// null position upon crossing a boundary. Make sure the previous position // null position upon crossing a boundary. Make sure the previous position
@ -949,31 +947,14 @@ class AXPosition {
} }
bool AtStartOfFormat() const { bool AtStartOfFormat() const {
AXPositionInstance text_position = AsLeafTextPosition(); return GetFormatStartBoundaryType() != AXBoundaryType::kNone;
switch (text_position->kind_) {
case AXPositionKind::NULL_POSITION:
return false;
case AXPositionKind::TREE_POSITION:
NOTREACHED();
case AXPositionKind::TEXT_POSITION: {
const std::vector<int32_t>& format_starts =
text_position->GetFormatStartOffsets();
if (format_starts.size() <= 1) {
return GetFormatStartBoundaryType() != AXBoundaryType::kNone;
}
return base::Contains(format_starts,
int32_t{text_position->text_offset_});
}
}
} }
AXBoundaryType GetFormatEndBoundaryType() const { AXBoundaryType GetFormatEndBoundaryType() const {
// Since formats are stored on text anchors, the end of a format break must // Since formats are stored on text anchors, the end of a format break must
// be at the end of an anchor. // be at the end of an anchor.
if (IsNullPosition() || !AtEndOfAnchor()) { if (IsNullPosition() || !AtEndOfAnchor())
return AXBoundaryType::kNone; return AXBoundaryType::kNone;
}
// Treat the last iterable node as a format boundary // Treat the last iterable node as a format boundary
if (CreateNextLeafTreePosition( if (CreateNextLeafTreePosition(
@ -982,9 +963,8 @@ class AXPosition {
return AXBoundaryType::kContentEnd; return AXBoundaryType::kContentEnd;
// Ignored positions cannot be format boundaries. // Ignored positions cannot be format boundaries.
if (IsIgnored()) { if (IsIgnored())
return AXBoundaryType::kNone; return AXBoundaryType::kNone;
}
// Iterate over anchors until a format boundary is found. This will return a // Iterate over anchors until a format boundary is found. This will return a
// null position upon crossing a boundary. Make sure the next position is // null position upon crossing a boundary. Make sure the next position is
@ -1002,23 +982,7 @@ class AXPosition {
} }
bool AtEndOfFormat() const { bool AtEndOfFormat() const {
AXPositionInstance text_position = AsLeafTextPosition(); return GetFormatEndBoundaryType() != AXBoundaryType::kNone;
switch (text_position->kind_) {
case AXPositionKind::NULL_POSITION:
return false;
case AXPositionKind::TREE_POSITION:
NOTREACHED();
case AXPositionKind::TEXT_POSITION: {
const std::vector<int32_t>& format_ends =
text_position->GetFormatEndOffsets();
if (format_ends.size() <= 1) {
return GetFormatEndBoundaryType() != AXBoundaryType::kNone;
}
return base::Contains(format_ends,
int32_t{text_position->text_offset_});
}
}
} }
bool AtStartOfSentence() const { bool AtStartOfSentence() const {
@ -3285,8 +3249,7 @@ class AXPosition {
return CreateBoundaryStartPosition( return CreateBoundaryStartPosition(
options, ax::mojom::MoveDirection::kForward, options, ax::mojom::MoveDirection::kForward,
base::BindRepeating(&AtStartOfFormatPredicate), base::BindRepeating(&AtStartOfFormatPredicate),
base::BindRepeating(&AtEndOfFormatPredicate), base::BindRepeating(&AtEndOfFormatPredicate));
base::BindRepeating(&GetFormatStartOffsetsFunc));
} }
AXPositionInstance CreatePreviousFormatStartPosition( AXPositionInstance CreatePreviousFormatStartPosition(
@ -3294,8 +3257,7 @@ class AXPosition {
return CreateBoundaryStartPosition( return CreateBoundaryStartPosition(
options, ax::mojom::MoveDirection::kBackward, options, ax::mojom::MoveDirection::kBackward,
base::BindRepeating(&AtStartOfFormatPredicate), base::BindRepeating(&AtStartOfFormatPredicate),
base::BindRepeating(&AtEndOfFormatPredicate), base::BindRepeating(&AtEndOfFormatPredicate));
base::BindRepeating(&GetFormatStartOffsetsFunc));
} }
AXPositionInstance CreateNextFormatEndPosition( AXPositionInstance CreateNextFormatEndPosition(
@ -3303,8 +3265,7 @@ class AXPosition {
return CreateBoundaryEndPosition( return CreateBoundaryEndPosition(
options, ax::mojom::MoveDirection::kForward, options, ax::mojom::MoveDirection::kForward,
base::BindRepeating(&AtStartOfFormatPredicate), base::BindRepeating(&AtStartOfFormatPredicate),
base::BindRepeating(&AtEndOfFormatPredicate), base::BindRepeating(&AtEndOfFormatPredicate));
base::BindRepeating(&GetFormatEndOffsetsFunc));
} }
AXPositionInstance CreatePreviousFormatEndPosition( AXPositionInstance CreatePreviousFormatEndPosition(
@ -3312,8 +3273,7 @@ class AXPosition {
return CreateBoundaryEndPosition( return CreateBoundaryEndPosition(
options, ax::mojom::MoveDirection::kBackward, options, ax::mojom::MoveDirection::kBackward,
base::BindRepeating(&AtStartOfFormatPredicate), base::BindRepeating(&AtStartOfFormatPredicate),
base::BindRepeating(&AtEndOfFormatPredicate), base::BindRepeating(&AtEndOfFormatPredicate));
base::BindRepeating(&GetFormatEndOffsetsFunc));
} }
AXPositionInstance CreateNextSentenceStartPosition( AXPositionInstance CreateNextSentenceStartPosition(
@ -4914,143 +4874,6 @@ class AXPosition {
ax::mojom::IntListAttribute::kWordEnds); ax::mojom::IntListAttribute::kWordEnds);
} }
const std::vector<int32_t>& GetFormatStartOffsets() const {
if (IsNullPosition()) {
static const base::NoDestructor<std::vector<int32_t>> empty_format_starts;
return *empty_format_starts;
}
DCHECK(GetAnchor());
std::vector<int32_t> format_starts;
format_starts.push_back(0);
// Format is almost always consistent throughout any node -- the only
// exception are inline text boxes with CSS highlights. Therefore, unless
// the node is an inline text box with CSS highlights, we can assume the
// node's format starts only at index 0.
if (GetAnchor()->GetRole() != ax::mojom::Role::kInlineTextBox) {
static const base::NoDestructor<std::vector<int32_t>> format_starts_copy(
std::move(format_starts));
return *format_starts_copy;
}
AXNode* parent = GetAnchor()->GetUnignoredParent();
const std::vector<int32_t>& marker_types =
parent->GetIntListAttribute(ax::mojom::IntListAttribute::kMarkerTypes);
const std::vector<int32_t>& highlight_types = parent->GetIntListAttribute(
ax::mojom::IntListAttribute::kHighlightTypes);
// Since, there are no highlights, there is no possibility of any spelling
// or grammar highlights.
if (highlight_types.empty()) {
static const base::NoDestructor<std::vector<int32_t>> format_starts_copy(
std::move(format_starts));
return *format_starts_copy;
}
CHECK_EQ(marker_types.size(), highlight_types.size());
const std::vector<int>& marker_starts =
parent->GetIntListAttribute(ax::mojom::IntListAttribute::kMarkerStarts);
const std::vector<int>& marker_ends =
parent->GetIntListAttribute(ax::mojom::IntListAttribute::kMarkerEnds);
CHECK_EQ(marker_types.size(), marker_starts.size());
CHECK_EQ(marker_types.size(), marker_ends.size());
int text_length = GetAnchor()->GetTextContentLengthUTF16();
for (size_t i = 0; i < marker_types.size(); ++i) {
if (HasSpellingOrGrammarErrorHighlight(
static_cast<ax::mojom::MarkerType>(marker_types[i]),
static_cast<ax::mojom::HighlightType>(highlight_types[i]))) {
if (marker_starts[i] != 0) { // 0 is already added
format_starts.push_back(marker_starts[i]);
}
if (marker_ends[i] < text_length - 1) {
format_starts.push_back(marker_ends[i]);
}
}
}
static const base::NoDestructor<std::vector<int32_t>> format_starts_copy(
std::move(format_starts));
return *format_starts_copy;
}
const std::vector<int32_t>& GetFormatEndOffsets() const {
if (IsNullPosition()) {
static const base::NoDestructor<std::vector<int32_t>> empty_format_ends;
return *empty_format_ends;
}
DCHECK(GetAnchor());
int text_length = GetAnchor()->GetTextContentLengthUTF16();
std::vector<int32_t> format_ends;
format_ends.push_back(text_length);
// Format is almost always consistent throughout any node -- the only
// exception are inline text boxes with CSS highlights. Therefore, unless
// the node is an inline text box with CSS highlights, we can assume the
// node's format ends only at the text length.
if (GetAnchor()->GetRole() != ax::mojom::Role::kInlineTextBox) {
static const base::NoDestructor<std::vector<int32_t>> format_ends_copy(
std::move(format_ends));
return *format_ends_copy;
}
AXNode* parent = GetAnchor()->GetUnignoredParent();
const std::vector<int32_t>& marker_types =
parent->GetIntListAttribute(ax::mojom::IntListAttribute::kMarkerTypes);
const std::vector<int32_t>& highlight_types = parent->GetIntListAttribute(
ax::mojom::IntListAttribute::kHighlightTypes);
// Since, there are no highlights, there is no possibility of any spelling
// or grammar highlights.
if (highlight_types.empty()) {
static const base::NoDestructor<std::vector<int32_t>> format_ends_copy(
std::move(format_ends));
return *format_ends_copy;
}
CHECK_EQ(marker_types.size(), highlight_types.size());
const std::vector<int>& marker_starts =
parent->GetIntListAttribute(ax::mojom::IntListAttribute::kMarkerStarts);
const std::vector<int>& marker_ends =
parent->GetIntListAttribute(ax::mojom::IntListAttribute::kMarkerEnds);
CHECK_EQ(marker_types.size(), marker_starts.size());
CHECK_EQ(marker_types.size(), marker_ends.size());
format_ends.clear();
for (size_t i = 0; i < marker_types.size(); ++i) {
if (HasSpellingOrGrammarErrorHighlight(
static_cast<ax::mojom::MarkerType>(marker_types[i]),
static_cast<ax::mojom::HighlightType>(highlight_types[i]))) {
if (marker_starts[i] > 0) {
format_ends.push_back(marker_starts[i]);
}
format_ends.push_back(marker_ends[i]);
}
}
if (format_ends.empty() || format_ends.back() != text_length) {
format_ends.push_back(text_length);
}
static const base::NoDestructor<std::vector<int32_t>> format_ends_copy(
std::move(format_ends));
return *format_ends_copy;
}
static bool HasSpellingOrGrammarErrorHighlight(
ax::mojom::MarkerType marker_type,
ax::mojom::HighlightType highlight_type) {
return marker_type == ax::mojom::MarkerType::kHighlight &&
(highlight_type == ax::mojom::HighlightType::kSpellingError ||
highlight_type == ax::mojom::HighlightType::kGrammarError);
}
AXNodeID GetNextOnLineID() const { AXNodeID GetNextOnLineID() const {
if (IsNullPosition()) if (IsNullPosition())
return kInvalidAXNodeID; return kInvalidAXNodeID;
@ -5706,16 +5529,6 @@ class AXPosition {
return position->GetWordEndOffsets(); return position->GetWordEndOffsets();
} }
static const std::vector<int32_t>& GetFormatStartOffsetsFunc(
const AXPositionInstance& position) {
return position->GetFormatStartOffsets();
}
static const std::vector<int32_t>& GetFormatEndOffsetsFunc(
const AXPositionInstance& position) {
return position->GetFormatEndOffsets();
}
// Creates an ancestor equivalent position at the root node of this position's // Creates an ancestor equivalent position at the root node of this position's
// accessibility tree, e.g. at the root of the current iframe (out-of-process // accessibility tree, e.g. at the root of the current iframe (out-of-process
// or not), PDF plugin, Views tree, dialog (native, ARIA or HTML), window, or // or not), PDF plugin, Views tree, dialog (native, ARIA or HTML), window, or

@ -884,7 +884,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitImpl(
MoveEndpointByCharacter(position_to_move, count, units_moved); MoveEndpointByCharacter(position_to_move, count, units_moved);
break; break;
case TextUnit_Format: case TextUnit_Format:
new_position = MoveEndpointByFormat(position_to_move, count, units_moved); new_position = MoveEndpointByFormat(position_to_move, is_start_endpoint,
count, units_moved);
break; break;
case TextUnit_Word: case TextUnit_Word:
new_position = MoveEndpointByWord(position_to_move, count, units_moved); new_position = MoveEndpointByWord(position_to_move, count, units_moved);
@ -1362,11 +1363,14 @@ AXPlatformNodeTextRangeProviderWin::MoveEndpointByLine(
AXPlatformNodeTextRangeProviderWin::AXPositionInstance AXPlatformNodeTextRangeProviderWin::AXPositionInstance
AXPlatformNodeTextRangeProviderWin::MoveEndpointByFormat( AXPlatformNodeTextRangeProviderWin::MoveEndpointByFormat(
const AXPositionInstance& endpoint, const AXPositionInstance& endpoint,
const bool is_start_endpoint,
const int count, const int count,
int* units_moved) { int* units_moved) {
return MoveEndpointByUnitHelper(std::move(endpoint), return MoveEndpointByUnitHelper(std::move(endpoint),
ax::mojom::TextBoundary::kFormatStart, count, is_start_endpoint
units_moved); ? ax::mojom::TextBoundary::kFormatStart
: ax::mojom::TextBoundary::kFormatEnd,
count, units_moved);
} }
AXPlatformNodeTextRangeProviderWin::AXPositionInstance AXPlatformNodeTextRangeProviderWin::AXPositionInstance

@ -163,6 +163,7 @@ class COMPONENT_EXPORT(AX_PLATFORM) __declspec(uuid(
const int count, const int count,
int* units_moved); int* units_moved);
AXPositionInstance MoveEndpointByFormat(const AXPositionInstance& endpoint, AXPositionInstance MoveEndpointByFormat(const AXPositionInstance& endpoint,
const bool is_start_endpoint,
const int count, const int count,
int* units_moved); int* units_moved);
AXPositionInstance MoveEndpointByDocument(const AXPositionInstance& endpoint, AXPositionInstance MoveEndpointByDocument(const AXPositionInstance& endpoint,

@ -804,19 +804,8 @@ class AXPlatformNodeTextRangeProviderTest : public AXPlatformNodeWinTest {
AXNodeData paragraph4_text_data; AXNodeData paragraph4_text_data;
paragraph4_text_data.id = 17; paragraph4_text_data.id = 17;
paragraph4_text_data.role = ax::mojom::Role::kInlineTextBox; paragraph4_text_data.role = ax::mojom::Role::kStaticText;
paragraph4_text_data.SetName("Paraaagraph 4"); paragraph4_text_data.SetName("Paragraph 4");
// Marking `Paraaagraph` as a misspelled word modeled as a CSS highlight.
paragraph4_data.AddIntListAttribute(
ax::mojom::IntListAttribute::kMarkerTypes,
{(int)ax::mojom::MarkerType::kHighlight});
paragraph4_data.AddIntListAttribute(
ax::mojom::IntListAttribute::kHighlightTypes,
{(int)ax::mojom::HighlightType::kSpellingError});
paragraph4_data.AddIntListAttribute(
ax::mojom::IntListAttribute::kMarkerStarts, {0});
paragraph4_data.AddIntListAttribute(
ax::mojom::IntListAttribute::kMarkerEnds, {11});
paragraph4_data.child_ids = {paragraph4_text_data.id}; paragraph4_data.child_ids = {paragraph4_text_data.id};
AXNodeData root_data; AXNodeData root_data;
@ -1497,7 +1486,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ( EXPECT_UIA_TEXTRANGE_EQ(
text_range_provider, text_range_provider,
L"Text with formatting\nStandalone line with no formatting\nbold " L"Text with formatting\nStandalone line with no formatting\nbold "
L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParaaagraph 4"); L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4");
// https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-expandtoenclosingunit // https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-expandtoenclosingunit
// Consider two consecutive text units A and B. // Consider two consecutive text units A and B.
@ -2089,7 +2078,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
/*count*/ 0, /*count*/ 0,
/*expected_text*/ /*expected_text*/
L"Text with formatting\nStandalone line with no formatting\nbold " L"Text with formatting\nStandalone line with no formatting\nbold "
L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParaaagraph 4", L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4",
/*expected_count*/ 0); /*expected_count*/ 0);
// Move forward. // Move forward.
@ -2099,32 +2088,28 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 2, /*count*/ 2,
/*expected_text*/ L"Paragraph 1\n", /*expected_text*/ L"Paragraph 1",
/*expected_count*/ 2); /*expected_count*/ 2);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ L"Paragraph 2\nParagraph 3\n", /*expected_text*/ L"Paragraph 2\nParagraph 3",
/*expected_count*/ 1); /*expected_count*/ 1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ L"Paraaagraph", /*expected_text*/ L"Paragraph 4",
/*expected_count*/ 1);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1,
/*expected_text*/ L" 4",
/*expected_count*/ 1); /*expected_count*/ 1);
// Trying to move past the last format should have no effect. // Trying to move past the last format should have no effect.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
/*expected_text*/ L" 4", /*expected_text*/ L"Paragraph 4",
/*expected_count*/ 0); /*expected_count*/ 0);
// Move backward. // Move backward.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ -4, /*count*/ -3,
/*expected_text*/ L"bold text\n", /*expected_text*/ L"bold text",
/*expected_count*/ -4); /*expected_count*/ -3);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ L"\nStandalone line with no formatting\n", /*expected_text*/ L"\nStandalone line with no formatting\n",
@ -2157,12 +2142,8 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
// Test degenerate range creation at the end of the document. // Test degenerate range creation at the end of the document.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 5, /*count*/ 5,
/*expected_text*/ L"Paraaagraph", /*expected_text*/ L"Paragraph 4",
/*expected_count*/ 5); /*expected_count*/ 5);
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 1,
/*expected_text*/ L" 4",
/*expected_count*/ 1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format,
/*count*/ 1, /*count*/ 1,
@ -2171,7 +2152,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ L" 4", /*expected_text*/ L"Paragraph 4",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format,
@ -2181,14 +2162,14 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ L" 4", /*expected_text*/ L"Paragraph 4",
/*expected_count*/ -1); /*expected_count*/ -1);
// Degenerate range moves. // Degenerate range moves.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ -6, /*count*/ -5,
/*expected_text*/ L"Text with formatting", /*expected_text*/ L"Text with formatting",
/*expected_count*/ -6); /*expected_count*/ -5);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
@ -2201,7 +2182,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
/*count*/ 70, /*count*/ 70,
/*expected_text*/ L"", /*expected_text*/ L"",
/*expected_count*/ 4); /*expected_count*/ 3);
// Trying to move past the last format should have no effect. // Trying to move past the last format should have no effect.
EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format, EXPECT_UIA_MOVE(text_range_provider, TextUnit_Format,
@ -3251,38 +3232,20 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_TEXTRANGE_EQ( EXPECT_UIA_TEXTRANGE_EQ(
text_range_provider, text_range_provider,
L"Text with formatting\nStandalone line with no formatting\nbold " L"Text with formatting\nStandalone line with no formatting\nbold "
L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParaaagraph 4"); L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4");
// `Paraaagraph 4` should be broken into two separate `format` units based on
// the spelling error (modeled as CSS highlight) in corresponding AXNode.
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -2,
/*expected_text*/ /*expected_text*/
L"Text with formatting\nStandalone line with no formatting\nbold " L"Text with formatting\nStandalone line with no formatting\nbold "
L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParaaagraph", L"text\nParagraph 1",
/*expected_count*/ -1); /*expected_count*/ -2);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"Text with formatting\nStandalone line with no formatting\nbold "
L"text\nParagraph 1\nParagraph 2\nParagraph 3\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1, /*count*/ -1,
/*expected_text*/ /*expected_text*/
L"Text with formatting\nStandalone line with no formatting\nbold " L"Text with formatting\nStandalone line with no formatting\nbold text",
L"text\nParagraph 1\n",
/*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -1,
/*expected_text*/
L"Text with formatting\nStandalone line with no formatting\nbold text\n",
/*expected_count*/ -1); /*expected_count*/ -1);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
@ -3306,17 +3269,17 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ 8, /*count*/ 7,
/*expected_text*/ /*expected_text*/
L"Text with formatting\nStandalone line with no formatting\nbold " L"Text with formatting\nStandalone line with no formatting\nbold "
L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParaaagraph 4", L"text\nParagraph 1\nParagraph 2\nParagraph 3\nParagraph 4",
/*expected_count*/ 7); /*expected_count*/ 6);
EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format, text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Format,
/*count*/ -8, /*count*/ -8,
/*expected_text*/ L"", /*expected_text*/ L"",
/*expected_count*/ -7); /*expected_count*/ -6);
} }
TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderCompare) { TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderCompare) {