Bug 1670541 - Return the parent line end offset if an embedded character contains a line break, r=Jamie

If the offset for an embedded character is queried, and it is an inline element, such as a link, and it contains a line break, return the full parent line.

Likewise, if querying character offsets before that embedded character, include its line break in the end offset.

Differential Revision: https://phabricator.services.mozilla.com/D94024
This commit is contained in:
Marco Zehe 2020-10-23 04:57:17 +00:00
Родитель 555178bed2
Коммит 92ae4518de
2 изменённых файлов: 87 добавлений и 3 удалений

Просмотреть файл

@ -745,9 +745,51 @@ uint32_t HyperTextAccessible::FindLineBoundary(
// Move to begin of the next line if any (arrow down and home keys),
// otherwise end of the current line (arrow down only).
uint32_t tmpOffset = FindOffset(aOffset, eDirNext, eSelectLine);
if (tmpOffset == CharacterCount()) return tmpOffset;
uint32_t characterCount = CharacterCount();
if (tmpOffset == characterCount) {
return tmpOffset;
}
return FindOffset(tmpOffset, eDirPrevious, eSelectBeginLine);
// Now, simulate the Home key on the next line to get its real offset.
uint32_t nextLineBeginOffset =
FindOffset(tmpOffset, eDirPrevious, eSelectBeginLine);
// Sometimes, there are line breaks inside embedded characters. If this
// is the case, the cursor is after the line break, but the offset will
// be that of the embedded character, which points to before the line
// break. We definitely want the line break included.
if (IsCharAt(nextLineBeginOffset, kEmbeddedObjectChar)) {
// We can determine if there is a line break by pressing End from
// the queried offset. If there is a line break, the offset will be 1
// greater, since this line ends with the embed. If there is not, the
// value will be different even if a line break follows right after the
// embed.
uint32_t thisLineEndOffset =
FindOffset(aOffset, eDirNext, eSelectEndLine);
if (thisLineEndOffset == nextLineBeginOffset + 1) {
// If we're querying the offset of the embedded character, we want
// the end offset of the parent line instead. Press End
// once more from the current position, which is after the embed.
if (nextLineBeginOffset == aOffset) {
uint32_t thisLineEndOffset2 =
FindOffset(thisLineEndOffset, eDirNext, eSelectEndLine);
// The above returns an offset exclusive the final line break, so we
// need to add 1 to it to return an inclusive end offset. Make sure
// we don't overshoot if we've started from another embedded
// character that has a line break, or landed on another embedded
// character, or if the result is the very end.
return (thisLineEndOffset2 == characterCount ||
(IsCharAt(thisLineEndOffset, kEmbeddedObjectChar) &&
thisLineEndOffset2 == thisLineEndOffset + 1) ||
IsCharAt(thisLineEndOffset2, kEmbeddedObjectChar))
? thisLineEndOffset2
: thisLineEndOffset2 + 1;
}
return thisLineEndOffset;
}
}
return nextLineBeginOffset;
}
case eNextLineEnd: {

Просмотреть файл

@ -171,6 +171,41 @@
[ [ 0, 0, kEmbedChar, 0, 1 ],
[ 1, 1, kEmbedChar, 1, 2 ] ]);
// Embedded char containing a line break breaks line offsets in parent.
testTextAtOffset([ "brInEmbed" ], BOUNDARY_LINE_START,
[ [0, 1, "a " + kEmbedChar, 0, 3],
[2, 2, "a " + kEmbedChar + " d", 0, 5],
[3, 5, kEmbedChar + " d", 2, 5] ]);
testTextAtOffset([ "brInEmbedAndBefore" ], BOUNDARY_LINE_START,
[ [0, 1, "a\n", 0, 2],
[2, 3, "b " + kEmbedChar, 2, 5],
[4, 4, "b " + kEmbedChar + " e", 2, 7],
[5, 7, kEmbedChar + " e", 4, 7] ]);
testTextAtOffset([ "brInEmbedAndAfter" ], BOUNDARY_LINE_START,
[ [0, 1, "a " + kEmbedChar, 0, 3],
[2, 2, "a " + kEmbedChar + " d\n", 0, 6],
[3, 5, kEmbedChar + " d\n", 2, 6],
[6, 7, "e", 6, 7] ]);
testTextAtOffset([ "brInEmbedAndBlockElementAfter" ], BOUNDARY_LINE_START,
[ [0, 2, "a " + kEmbedChar, 0, 3],
[3, 4, kEmbedChar, 3, 4] ]);
testTextAtOffset([ "brInEmbedThenTextThenBlockElement" ], BOUNDARY_LINE_START,
[ [0, 1, "a " + kEmbedChar, 0, 3],
[2, 2, "a " + kEmbedChar + " d", 0, 5],
[3, 4, kEmbedChar + " d", 2, 5],
[5, 6, kEmbedChar, 5, 6] ]);
testTextAtOffset([ "noBrInEmbedButOneBefore" ], BOUNDARY_LINE_START,
[ [0, 1, "a\n", 0, 2],
[2, 7, "b " + kEmbedChar + " d", 2, 7] ]);
testTextAtOffset([ "noBrInEmbedButOneAfter" ], BOUNDARY_LINE_START,
[ [0, 3, "a " + kEmbedChar + "\n", 0, 4],
[4, 5, "c", 4, 5] ]);
testTextAtOffset([ "twoEmbedsWithBRs" ], BOUNDARY_LINE_START,
[ [0, 1, "a " + kEmbedChar, 0, 3],
[2, 2, "a " + kEmbedChar + kEmbedChar, 0, 4],
[3, 3, kEmbedChar + kEmbedChar + " f", 2, 6],
[4, 6, kEmbedChar + " f", 3, 6] ]);
SimpleTest.finish();
}
@ -270,6 +305,13 @@ two words
<p>Block</p>
<ul><li>Li</li></ul>
</div>
</body>
<div id="brInEmbed" contenteditable>a <a href="https://mozilla.org/">b<br>c</a> d</div>
<div id="brInEmbedAndBefore">a<br>b <a href="https://mozilla.org/">c<br>d</a> e</div>
<div id="brInEmbedAndAfter">a <a href="https://mozilla.org/">b<br>c</a> d<br>e</div>
<div id="brInEmbedAndBlockElementAfter">a <a href="https://mozilla.org/">b<br>c</a><p>d</p></div>
<div id="brInEmbedThenTextThenBlockElement">a <a href="https://mozilla.org/">b<br>c</a> d<p>e</p></div>
<div id="noBrInEmbedButOneBefore">a<br>b <a href="https://mozilla.org/">c</a> d</div>
<div id="noBrInEmbedButOneAfter">a <a href="https://mozilla.org/">b</a><br>c</div>
<div id="twoEmbedsWithBRs">a <a href="https://mozilla.org">b<br>c</a><a href="https://mozilla.org">d<br>e</a> f</div>
</body>
</html>