Bug 1785930 - Introduce aStopInEditable argument in TextLeafPoint::FindBoundary. r=Jamie

Differential Revision: https://phabricator.services.mozilla.com/D155030
This commit is contained in:
Eitan Isaacson 2022-08-26 16:26:31 +00:00
parent f6705eb81f
commit c039e2a85b
2 changed files with 56 additions and 28 deletions

View file

@ -123,20 +123,32 @@ static HyperTextAccessible* HyperTextFor(LocalAccessible* aAcc) {
return nullptr; return nullptr;
} }
static Accessible* NextLeaf(Accessible* aOrigin) { static Accessible* NextLeaf(Accessible* aOrigin, bool aIsEditable = false) {
MOZ_ASSERT(aOrigin); MOZ_ASSERT(aOrigin);
Accessible* doc = nsAccUtils::DocumentFor(aOrigin); Accessible* doc = nsAccUtils::DocumentFor(aOrigin);
Pivot pivot(doc); Pivot pivot(doc);
auto rule = LeafRule(); auto rule = LeafRule();
return pivot.Next(aOrigin, rule); Accessible* leaf = pivot.Next(aOrigin, rule);
if (aIsEditable && leaf) {
return leaf->Parent() && (leaf->Parent()->State() & states::EDITABLE)
? leaf
: nullptr;
}
return leaf;
} }
static Accessible* PrevLeaf(Accessible* aOrigin) { static Accessible* PrevLeaf(Accessible* aOrigin, bool aIsEditable = false) {
MOZ_ASSERT(aOrigin); MOZ_ASSERT(aOrigin);
Accessible* doc = nsAccUtils::DocumentFor(aOrigin); Accessible* doc = nsAccUtils::DocumentFor(aOrigin);
Pivot pivot(doc); Pivot pivot(doc);
auto rule = LeafRule(); auto rule = LeafRule();
return pivot.Prev(aOrigin, rule); Accessible* leaf = pivot.Prev(aOrigin, rule);
if (aIsEditable && leaf) {
return leaf->Parent() && (leaf->Parent()->State() & states::EDITABLE)
? leaf
: nullptr;
}
return leaf;
} }
static nsIFrame* GetFrameInBlock(const LocalAccessible* aAcc) { static nsIFrame* GetFrameInBlock(const LocalAccessible* aAcc) {
@ -820,7 +832,8 @@ TextLeafPoint TextLeafPoint::ActualizeCaret(bool aAdjustAtEndOfLine) const {
TextLeafPoint TextLeafPoint::FindBoundary(AccessibleTextBoundary aBoundaryType, TextLeafPoint TextLeafPoint::FindBoundary(AccessibleTextBoundary aBoundaryType,
nsDirection aDirection, nsDirection aDirection,
bool aIncludeOrigin) const { bool aIncludeOrigin,
bool aStopInEditable) const {
if (IsCaret()) { if (IsCaret()) {
if (aBoundaryType == nsIAccessibleText::BOUNDARY_CHAR) { if (aBoundaryType == nsIAccessibleText::BOUNDARY_CHAR) {
if (IsCaretAtEndOfLine()) { if (IsCaretAtEndOfLine()) {
@ -831,11 +844,14 @@ TextLeafPoint TextLeafPoint::FindBoundary(AccessibleTextBoundary aBoundaryType,
return ActualizeCaret().FindBoundary(aBoundaryType, aDirection, return ActualizeCaret().FindBoundary(aBoundaryType, aDirection,
aIncludeOrigin); aIncludeOrigin);
} }
bool inEditableAndStopInIt = aStopInEditable && mAcc->Parent() &&
(mAcc->Parent()->State() & states::EDITABLE);
if (aBoundaryType == nsIAccessibleText::BOUNDARY_LINE_END) { if (aBoundaryType == nsIAccessibleText::BOUNDARY_LINE_END) {
return FindLineEnd(aDirection, aIncludeOrigin); return FindLineEnd(aDirection, aIncludeOrigin, inEditableAndStopInIt);
} }
if (aBoundaryType == nsIAccessibleText::BOUNDARY_WORD_END) { if (aBoundaryType == nsIAccessibleText::BOUNDARY_WORD_END) {
return FindWordEnd(aDirection, aIncludeOrigin); return FindWordEnd(aDirection, aIncludeOrigin, inEditableAndStopInIt);
} }
if ((aBoundaryType == nsIAccessibleText::BOUNDARY_LINE_START || if ((aBoundaryType == nsIAccessibleText::BOUNDARY_LINE_START ||
aBoundaryType == nsIAccessibleText::BOUNDARY_PARAGRAPH) && aBoundaryType == nsIAccessibleText::BOUNDARY_PARAGRAPH) &&
@ -892,8 +908,9 @@ TextLeafPoint TextLeafPoint::FindBoundary(AccessibleTextBoundary aBoundaryType,
return boundary; return boundary;
} }
// We didn't find it in this Accessible, so try the previous/next leaf. // We didn't find it in this Accessible, so try the previous/next leaf.
Accessible* acc = aDirection == eDirPrevious ? PrevLeaf(searchFrom.mAcc) Accessible* acc = aDirection == eDirPrevious
: NextLeaf(searchFrom.mAcc); ? PrevLeaf(searchFrom.mAcc, inEditableAndStopInIt)
: NextLeaf(searchFrom.mAcc, inEditableAndStopInIt);
if (!acc) { if (!acc) {
// No further leaf was found. Use the start/end of the first/last leaf. // No further leaf was found. Use the start/end of the first/last leaf.
return TextLeafPoint( return TextLeafPoint(
@ -917,22 +934,24 @@ TextLeafPoint TextLeafPoint::FindBoundary(AccessibleTextBoundary aBoundaryType,
} }
TextLeafPoint TextLeafPoint::FindLineEnd(nsDirection aDirection, TextLeafPoint TextLeafPoint::FindLineEnd(nsDirection aDirection,
bool aIncludeOrigin) const { bool aIncludeOrigin,
bool aStopInEditable) const {
if (aDirection == eDirPrevious && IsEmptyLastLine()) { if (aDirection == eDirPrevious && IsEmptyLastLine()) {
// If we're at an empty line at the end of an Accessible, we don't want to // If we're at an empty line at the end of an Accessible, we don't want to
// walk into the previous line. For example, this can happen if the caret // walk into the previous line. For example, this can happen if the caret
// is positioned on an empty line at the end of a textarea. // is positioned on an empty line at the end of a textarea.
// Because we want the line end, we must walk back to the line feed // Because we want the line end, we must walk back to the line feed
// character. // character.
return FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious); return FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious, false,
aStopInEditable);
} }
if (aIncludeOrigin && IsLineFeedChar()) { if (aIncludeOrigin && IsLineFeedChar()) {
return *this; return *this;
} }
if (aDirection == eDirPrevious && !aIncludeOrigin) { if (aDirection == eDirPrevious && !aIncludeOrigin) {
// If there is a line feed immediately before us, return that. // If there is a line feed immediately before us, return that.
TextLeafPoint prevChar = TextLeafPoint prevChar = FindBoundary(nsIAccessibleText::BOUNDARY_CHAR,
FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious); eDirPrevious, false, aStopInEditable);
if (prevChar.IsLineFeedChar()) { if (prevChar.IsLineFeedChar()) {
return prevChar; return prevChar;
} }
@ -942,14 +961,16 @@ TextLeafPoint TextLeafPoint::FindLineEnd(nsDirection aDirection,
// If we search for the next line start from a line feed, we'll get the // If we search for the next line start from a line feed, we'll get the
// character immediately following the line feed. We actually want the // character immediately following the line feed. We actually want the
// next line start after that. Skip the line feed. // next line start after that. Skip the line feed.
searchFrom = FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirNext); searchFrom = FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirNext, false,
aStopInEditable);
} }
TextLeafPoint lineStart = searchFrom.FindBoundary( TextLeafPoint lineStart =
nsIAccessibleText::BOUNDARY_LINE_START, aDirection, aIncludeOrigin); searchFrom.FindBoundary(nsIAccessibleText::BOUNDARY_LINE_START,
aDirection, aIncludeOrigin, aStopInEditable);
// If there is a line feed before this line start (at the end of the previous // If there is a line feed before this line start (at the end of the previous
// line), we must return that. // line), we must return that.
TextLeafPoint prevChar = lineStart.FindBoundary( TextLeafPoint prevChar = lineStart.FindBoundary(
nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious, false); nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious, false, aStopInEditable);
if (prevChar && prevChar.IsLineFeedChar()) { if (prevChar && prevChar.IsLineFeedChar()) {
return prevChar; return prevChar;
} }
@ -961,14 +982,15 @@ bool TextLeafPoint::IsSpace() const {
} }
TextLeafPoint TextLeafPoint::FindWordEnd(nsDirection aDirection, TextLeafPoint TextLeafPoint::FindWordEnd(nsDirection aDirection,
bool aIncludeOrigin) const { bool aIncludeOrigin,
bool aStopInEditable) const {
char16_t origChar = GetChar(); char16_t origChar = GetChar();
const bool origIsSpace = GetWordBreakClass(origChar) == eWbcSpace; const bool origIsSpace = GetWordBreakClass(origChar) == eWbcSpace;
bool prevIsSpace = false; bool prevIsSpace = false;
if (aDirection == eDirPrevious || (aIncludeOrigin && origIsSpace) || if (aDirection == eDirPrevious || (aIncludeOrigin && origIsSpace) ||
!origChar) { !origChar) {
TextLeafPoint prev = TextLeafPoint prev = FindBoundary(nsIAccessibleText::BOUNDARY_CHAR,
FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious, false); eDirPrevious, false, aStopInEditable);
if (aDirection == eDirPrevious && prev == *this) { if (aDirection == eDirPrevious && prev == *this) {
return *this; // Can't go any further. return *this; // Can't go any further.
} }
@ -984,13 +1006,13 @@ TextLeafPoint TextLeafPoint::FindWordEnd(nsDirection aDirection,
// If there isn't space immediately before us, first find the start of the // If there isn't space immediately before us, first find the start of the
// previous word. // previous word.
boundary = FindBoundary(nsIAccessibleText::BOUNDARY_WORD_START, boundary = FindBoundary(nsIAccessibleText::BOUNDARY_WORD_START,
eDirPrevious, aIncludeOrigin); eDirPrevious, aIncludeOrigin, aStopInEditable);
} else if (aDirection == eDirNext && } else if (aDirection == eDirNext &&
(origIsSpace || (!origChar && prevIsSpace))) { (origIsSpace || (!origChar && prevIsSpace))) {
// We're within the space at the end of the word. Skip over the space. We // We're within the space at the end of the word. Skip over the space. We
// can do that by searching for the next word start. // can do that by searching for the next word start.
boundary = boundary = FindBoundary(nsIAccessibleText::BOUNDARY_WORD_START, eDirNext,
FindBoundary(nsIAccessibleText::BOUNDARY_WORD_START, eDirNext, false); false, aStopInEditable);
if (boundary.IsSpace()) { if (boundary.IsSpace()) {
// The next word starts with a space. This can happen if there is a space // The next word starts with a space. This can happen if there is a space
// after or at the start of a block element. // after or at the start of a block element.
@ -999,14 +1021,15 @@ TextLeafPoint TextLeafPoint::FindWordEnd(nsDirection aDirection,
} }
if (aDirection == eDirNext) { if (aDirection == eDirNext) {
boundary = boundary.FindBoundary(nsIAccessibleText::BOUNDARY_WORD_START, boundary = boundary.FindBoundary(nsIAccessibleText::BOUNDARY_WORD_START,
eDirNext, aIncludeOrigin); eDirNext, aIncludeOrigin, aStopInEditable);
} }
// At this point, boundary is either the start of a word or at a space. A // At this point, boundary is either the start of a word or at a space. A
// word ends at the beginning of consecutive space. Therefore, skip back to // word ends at the beginning of consecutive space. Therefore, skip back to
// the start of any space before us. // the start of any space before us.
TextLeafPoint prev = boundary; TextLeafPoint prev = boundary;
for (;;) { for (;;) {
prev = prev.FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious); prev = prev.FindBoundary(nsIAccessibleText::BOUNDARY_CHAR, eDirPrevious,
false, aStopInEditable);
if (prev == boundary) { if (prev == boundary) {
break; // Can't go any further. break; // Can't go any further.
} }

View file

@ -95,10 +95,13 @@ class TextLeafPoint final {
* (depending on the direction). * (depending on the direction).
* If aIncludeorigin is true and this is at a boundary, this will be * If aIncludeorigin is true and this is at a boundary, this will be
* returned unchanged. * returned unchanged.
* If aStopInEditable is true the boundary returned will be within the
* current editable (if this point is in an editable).
*/ */
TextLeafPoint FindBoundary(AccessibleTextBoundary aBoundaryType, TextLeafPoint FindBoundary(AccessibleTextBoundary aBoundaryType,
nsDirection aDirection, nsDirection aDirection,
bool aIncludeOrigin = false) const; bool aIncludeOrigin = false,
bool aStopInEditable = false) const;
/** /**
* These two functions find a line start boundary within the same * These two functions find a line start boundary within the same
@ -196,8 +199,10 @@ class TextLeafPoint final {
TextLeafPoint FindLineStartSameAcc(nsDirection aDirection, TextLeafPoint FindLineStartSameAcc(nsDirection aDirection,
bool aIncludeOrigin) const; bool aIncludeOrigin) const;
TextLeafPoint FindLineEnd(nsDirection aDirection, bool aIncludeOrigin) const; TextLeafPoint FindLineEnd(nsDirection aDirection, bool aIncludeOrigin,
TextLeafPoint FindWordEnd(nsDirection aDirection, bool aIncludeOrigin) const; bool aStopInEditable) const;
TextLeafPoint FindWordEnd(nsDirection aDirection, bool aIncludeOrigin,
bool aStopInEditable) const;
TextLeafPoint FindParagraphSameAcc(nsDirection aDirection, TextLeafPoint FindParagraphSameAcc(nsDirection aDirection,
bool aIncludeOrigin) const; bool aIncludeOrigin) const;