forked from mirrors/gecko-dev
Bug 1827557 part 2: CachedTextMarker: Differentiate between LeftLine and Line. r=eeejay
Line should return the current line when the start of the line is queried. Otherwise, VoiceOver reports the previous line if you're on the first character of a line and you move by line with down or up arrow. LegacyTextMarker behaves inconsistently when you use Line/LeftLine depending on whether you fetched the marker via index or from a selection range. browser_text_basics.js treated the index behaviour as correct, but it isn't. The tests have been updated accordingly with expected failures for non-cached. Differential Revision: https://phabricator.services.mozilla.com/D176608
This commit is contained in:
parent
a431ef8f27
commit
81d78e645f
8 changed files with 135 additions and 22 deletions
|
|
@ -43,6 +43,8 @@ class CachedTextMarker final {
|
|||
|
||||
CachedTextMarkerRange RightWordRange() const;
|
||||
|
||||
CachedTextMarkerRange LineRange() const;
|
||||
|
||||
CachedTextMarkerRange LeftLineRange() const;
|
||||
|
||||
CachedTextMarkerRange RightLineRange() const;
|
||||
|
|
|
|||
|
|
@ -175,6 +175,19 @@ CachedTextMarkerRange CachedTextMarker::RightWordRange() const {
|
|||
start < end ? end : start);
|
||||
}
|
||||
|
||||
CachedTextMarkerRange CachedTextMarker::LineRange() const {
|
||||
TextLeafPoint start = mPoint.FindBoundary(
|
||||
nsIAccessibleText::BOUNDARY_LINE_START, eDirPrevious,
|
||||
TextLeafPoint::BoundaryFlags::eStopInEditable |
|
||||
TextLeafPoint::BoundaryFlags::eIgnoreListItemMarker |
|
||||
TextLeafPoint::BoundaryFlags::eIncludeOrigin);
|
||||
TextLeafPoint end =
|
||||
start.FindBoundary(nsIAccessibleText::BOUNDARY_LINE_END, eDirNext,
|
||||
TextLeafPoint::BoundaryFlags::eStopInEditable);
|
||||
|
||||
return CachedTextMarkerRange(start, end);
|
||||
}
|
||||
|
||||
CachedTextMarkerRange CachedTextMarker::LeftLineRange() const {
|
||||
TextLeafPoint start = mPoint.FindBoundary(
|
||||
nsIAccessibleText::BOUNDARY_LINE_START, eDirPrevious,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ class GeckoTextMarker {
|
|||
|
||||
GeckoTextMarkerRange RightWordRange() const;
|
||||
|
||||
GeckoTextMarkerRange LineRange() const;
|
||||
|
||||
GeckoTextMarkerRange LeftLineRange() const;
|
||||
|
||||
GeckoTextMarkerRange RightLineRange() const;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,15 @@ GeckoTextMarkerRange GeckoTextMarker::RightWordRange() const {
|
|||
}
|
||||
}
|
||||
|
||||
GeckoTextMarkerRange GeckoTextMarker::LineRange() const {
|
||||
if (mLegacy) {
|
||||
return GeckoTextMarkerRange(
|
||||
mLegacyTextMarker.Range(EWhichRange::eLeftLine));
|
||||
} else {
|
||||
return GeckoTextMarkerRange(mCachedTextMarker.LineRange());
|
||||
}
|
||||
}
|
||||
|
||||
GeckoTextMarkerRange GeckoTextMarker::LeftLineRange() const {
|
||||
if (mLegacy) {
|
||||
return GeckoTextMarkerRange(
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ mozAccessible* GetEditableNativeFromGeckoAccessible(Accessible* aAcc) {
|
|||
return nil;
|
||||
}
|
||||
|
||||
return geckoTextMarker.LeftLineRange().CreateAXTextMarkerRange();
|
||||
return geckoTextMarker.LineRange().CreateAXTextMarkerRange();
|
||||
}
|
||||
|
||||
- (AXTextMarkerRangeRef)moxLeftLineTextMarkerRangeForTextMarker:
|
||||
|
|
|
|||
|
|
@ -84,13 +84,17 @@ function testLines(
|
|||
expectedLeft,
|
||||
expectedRight
|
||||
) {
|
||||
testRangeAtMarker(
|
||||
macDoc,
|
||||
marker,
|
||||
"AXLineTextMarkerRangeForTextMarker",
|
||||
expectedLine,
|
||||
`${msg}: line matches`
|
||||
);
|
||||
if (!isCacheEnabled && expectedLine != expectedLeft) {
|
||||
todo(false, `${msg}: line broken at start with cache disabled`);
|
||||
} else {
|
||||
testRangeAtMarker(
|
||||
macDoc,
|
||||
marker,
|
||||
"AXLineTextMarkerRangeForTextMarker",
|
||||
expectedLine,
|
||||
`${msg}: line matches`
|
||||
);
|
||||
}
|
||||
|
||||
testRangeAtMarker(
|
||||
macDoc,
|
||||
|
|
@ -254,14 +258,14 @@ addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => {
|
|||
// Some changes in expected results when cache is enabled
|
||||
// These are more correct return values (or at least not more incorrect)
|
||||
expectedValues[231].words[1] = "Skip'";
|
||||
expectedValues[248].lines[0] = expectedValues[248].lines[1] = "These ";
|
||||
expectedValues[252].lines[0] = expectedValues[252].lines[1] = "are ";
|
||||
expectedValues[255].lines[0] = expectedValues[255].lines[1] = "my ";
|
||||
expectedValues[248].lines[1] = "These ";
|
||||
expectedValues[252].lines[1] = "are ";
|
||||
expectedValues[255].lines[1] = "my ";
|
||||
expectedValues[261].words[0] = expectedValues[261].words[1] = "awards,";
|
||||
expectedValues[263].lines[0] = expectedValues[263].lines[1] = "awards, ";
|
||||
expectedValues[263].lines[1] = "awards, ";
|
||||
expectedValues[269].words[0] = expectedValues[269].words[1] = "Mother.";
|
||||
expectedValues[271].lines[0] = expectedValues[271].lines[1] = "Mother. ";
|
||||
expectedValues[276].lines[0] = expectedValues[276].lines[1] = "From ";
|
||||
expectedValues[271].lines[1] = "Mother. ";
|
||||
expectedValues[276].lines[1] = "From ";
|
||||
expectedValues[269].paragraph = "These are my awards, Mother. From Army.";
|
||||
expectedValues[283].words[0] = "deceived";
|
||||
expectedValues[295].paragraph = "I deceived you, mom.";
|
||||
|
|
|
|||
|
|
@ -177,6 +177,22 @@ function testSelectionEventLeftChar(event, expectedChar) {
|
|||
is(leftCharString, expectedChar, "Left character is correct");
|
||||
}
|
||||
|
||||
function testSelectionEventLine(event, expectedLine) {
|
||||
const selStart = event.macIface.getParameterizedAttributeValue(
|
||||
"AXStartTextMarkerForTextMarkerRange",
|
||||
event.data.AXSelectedTextMarkerRange
|
||||
);
|
||||
const lineRange = event.macIface.getParameterizedAttributeValue(
|
||||
"AXLineTextMarkerRangeForTextMarker",
|
||||
selStart
|
||||
);
|
||||
const lineString = event.macIface.getParameterizedAttributeValue(
|
||||
"AXStringForTextMarkerRange",
|
||||
lineRange
|
||||
);
|
||||
is(lineString, expectedLine, "Line is correct");
|
||||
}
|
||||
|
||||
async function synthKeyAndTestValueChanged(
|
||||
synthKey,
|
||||
synthEvent,
|
||||
|
|
@ -523,3 +539,70 @@ addAccessibleTask(
|
|||
},
|
||||
{ chrome: true, topLevel: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* Test that the caret returns the correct line when the caret is at the start
|
||||
* of the line.
|
||||
*/
|
||||
addAccessibleTask(
|
||||
`
|
||||
<textarea id="hard">ab
|
||||
cd
|
||||
ef</textarea>
|
||||
<div id="wrapped" contenteditable style="width: 1ch;">a b c</div>
|
||||
`,
|
||||
async function(browser, docAcc) {
|
||||
await focusIntoInput(docAcc, "hard");
|
||||
let event = await synthKeyAndTestSelectionChanged(
|
||||
"KEY_ArrowDown",
|
||||
null,
|
||||
"hard",
|
||||
"",
|
||||
{
|
||||
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
|
||||
AXTextSelectionDirection: AXTextSelectionDirectionNext,
|
||||
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
|
||||
}
|
||||
);
|
||||
testSelectionEventLine(event, "cd");
|
||||
event = await synthKeyAndTestSelectionChanged(
|
||||
"KEY_ArrowDown",
|
||||
null,
|
||||
"hard",
|
||||
"",
|
||||
{
|
||||
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
|
||||
AXTextSelectionDirection: AXTextSelectionDirectionNext,
|
||||
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
|
||||
}
|
||||
);
|
||||
testSelectionEventLine(event, "ef");
|
||||
|
||||
await focusIntoInput(docAcc, "wrapped");
|
||||
event = await synthKeyAndTestSelectionChanged(
|
||||
"KEY_ArrowDown",
|
||||
null,
|
||||
"wrapped",
|
||||
"",
|
||||
{
|
||||
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
|
||||
AXTextSelectionDirection: AXTextSelectionDirectionNext,
|
||||
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
|
||||
}
|
||||
);
|
||||
testSelectionEventLine(event, "b ");
|
||||
event = await synthKeyAndTestSelectionChanged(
|
||||
"KEY_ArrowDown",
|
||||
null,
|
||||
"wrapped",
|
||||
"",
|
||||
{
|
||||
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
|
||||
AXTextSelectionDirection: AXTextSelectionDirectionNext,
|
||||
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
|
||||
}
|
||||
);
|
||||
testSelectionEventLine(event, "c");
|
||||
},
|
||||
{ chrome: true, topLevel: true }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@
|
|||
"Bob Loblaw Lobs Law Bomb"] },
|
||||
{ style: "Bob Loblaw Lobs Law Bomb",
|
||||
paragraph: "I love all of my children equally",
|
||||
lines: ["Bob Loblaw Lobs Law Bomb",
|
||||
lines: ["I love all of my children equally",
|
||||
"Bob Loblaw Lobs Law Bomb",
|
||||
"I love all of my children equally"],
|
||||
words: ["Bomb", ""],
|
||||
|
|
@ -470,7 +470,7 @@
|
|||
element: ["AXStaticText", " equally", " equally"] },
|
||||
{ style: " equally",
|
||||
paragraph: "This is the best free scrapbooking class I have ever taken",
|
||||
lines: ["I love all of my children equally",
|
||||
lines: ["This is the best free scrapbooking class I have ever taken",
|
||||
"I love all of my children equally",
|
||||
"This is the best free scrapbooking class I have ever taken"],
|
||||
words: ["equally", ""],
|
||||
|
|
@ -928,7 +928,7 @@
|
|||
"ing class I have ever taken"] },
|
||||
{ style: "ing class I have ever taken",
|
||||
paragraph: "\u2022 Fried cheese with club sauce",
|
||||
lines: ["This is the best free scrapbooking class I have ever taken",
|
||||
lines: ["\u2022 Fried cheese with club sauce",
|
||||
"This is the best free scrapbooking class I have ever taken",
|
||||
"\u2022 Fried cheese with club sauce"],
|
||||
words: ["taken", ""],
|
||||
|
|
@ -1180,7 +1180,7 @@
|
|||
"\u2022 Fried cheese with club sauce"] },
|
||||
{ style: "\u2022 Fried cheese with club sauce",
|
||||
paragraph: "\u2022 Popcorn shrimp with club sauce",
|
||||
lines: ["\u2022 Fried cheese with club sauce",
|
||||
lines: ["\u2022 Popcorn shrimp with club sauce",
|
||||
"\u2022 Fried cheese with club sauce",
|
||||
"\u2022 Popcorn shrimp with club sauce"],
|
||||
words: ["sauce", ""],
|
||||
|
|
@ -1450,7 +1450,7 @@
|
|||
"\u2022 Popcorn shrimp with club sauce"] },
|
||||
{ style: "\u2022 Popcorn shrimp with club sauce",
|
||||
paragraph: "\u2022 Chicken fingers with spicy club sauce",
|
||||
lines: ["\u2022 Popcorn shrimp with club sauce",
|
||||
lines: ["\u2022 Chicken fingers with spicy club sauce",
|
||||
"\u2022 Popcorn shrimp with club sauce",
|
||||
"\u2022 Chicken fingers with spicy club sauce"],
|
||||
words: ["sauce", ""],
|
||||
|
|
@ -1753,7 +1753,7 @@
|
|||
element: ["AXStaticText", " club sauce", " club sauce"] },
|
||||
{ style: " club sauce",
|
||||
paragraph: "Do not order the Skip's Scramble",
|
||||
lines: ["\u2022 Chicken fingers with spicy club sauce",
|
||||
lines: ["Do not order the Skip's Scramble",
|
||||
"\u2022 Chicken fingers with spicy club sauce",
|
||||
"Do not order the Skip's Scramble"],
|
||||
words: ["sauce", ""],
|
||||
|
|
@ -2039,7 +2039,7 @@
|
|||
"Do not order the Skip's Scramble"] },
|
||||
{ style: "Do not order the Skip's Scramble",
|
||||
paragraph: "These are my awards, Mother. From Army.",
|
||||
lines: ["Do not order the Skip's Scramble",
|
||||
lines: ["These ",
|
||||
"Do not order the Skip's Scramble",
|
||||
"These "],
|
||||
words: ["Scramble", ""],
|
||||
|
|
@ -2314,7 +2314,7 @@
|
|||
"These are my awards, Mother. From Army."] },
|
||||
{ style: "These are my awards, Mother. From Army.",
|
||||
paragraph: "I deceived you, mom.",
|
||||
lines: ["Army.", "Army.", "I deceived you, mom."],
|
||||
lines: ["I deceived you, mom.", "Army.", "I deceived you, mom."],
|
||||
words: ["Army.", ""],
|
||||
element: ["AXStaticText",
|
||||
"These are my awards, Mother. From Army.",
|
||||
|
|
|
|||
Loading…
Reference in a new issue