Bug 1858794 - Make `AutoMoveOneLineHandler` track the new line range while moving content nodes r=m_kato

It moves nodes in a range to new place one by one.  At this time, the moved
position range is not tracked.  Therefore, if the DOM tree is unexpectedly
changed by `HTMLEditor` itself, the range gets broken.  E.g., in this case,
deleting empty inline element causes the range after the source position is
broken.

Differential Revision: https://phabricator.services.mozilla.com/D192180
This commit is contained in:
Masayuki Nakano 2023-11-01 01:32:40 +00:00
Родитель b77d9f1bde
Коммит 197de3d0a2
2 изменённых файлов: 53 добавлений и 1 удалений

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

@ -5399,6 +5399,8 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
for (const OwningNonNull<nsIContent>& content : arrayOfContents) {
{
AutoEditorDOMRangeChildrenInvalidator lockOffsets(movedContentRange);
AutoTrackDOMRange trackMovedContentRange(aHTMLEditor.RangeUpdaterRef(),
&movedContentRange);
// If the content is a block element, move all children of it to the
// new container, and then, remove the (probably) empty block element.
if (HTMLEditUtils::IsBlockElement(
@ -5413,7 +5415,6 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
return moveChildrenResult;
}
moveContentsInLineResult |= moveChildrenResult.inspect();
moveContentsInLineResult.MarkAsHandled();
// MOZ_KnownLive due to bug 1620312
nsresult rv =
aHTMLEditor.DeleteNodeWithTransaction(MOZ_KnownLive(content));
@ -5428,6 +5429,7 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
// If the moving content is a comment node or an empty inline node, we
// don't want it to appear in the dist paragraph.
else if (content->IsComment() ||
(content->IsText() && !content->AsText()->TextDataLength()) ||
HTMLEditUtils::IsEmptyInlineContainer(
content,
{EmptyCheckOption::TreatSingleBRElementAsVisible,
@ -5461,10 +5463,16 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
moveContentsInLineResult |= moveNodeOrChildrenResult.inspect();
}
}
moveContentsInLineResult.MarkAsHandled();
if (NS_WARN_IF(!movedContentRange.IsPositioned())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
// For backward compatibility, we should move contents to end of the
// container if the instance is created without specific insertion point.
if (ForceMoveToEndOfContainer()) {
pointToInsert = NextInsertionPointRef();
MOZ_ASSERT(pointToInsert.IsSet());
MOZ_ASSERT(movedContentRange.StartRef().EqualsOrIsBefore(pointToInsert));
movedContentRange.SetEnd(pointToInsert);
}
// And also if pointToInsert has been made invalid with removing preceding
@ -5482,6 +5490,9 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
pointToInsert = NextInsertionPointRef();
if (!aHTMLEditor.MayHaveMutationEventListeners() ||
movedContentRange.EndRef().IsBefore(pointToInsert)) {
MOZ_ASSERT(pointToInsert.IsSet());
MOZ_ASSERT(
movedContentRange.StartRef().EqualsOrIsBefore(pointToInsert));
movedContentRange.SetEnd(pointToInsert);
}
}

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

@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
mask, li {
float: inline-start;
animation-name: kf0;
}
@keyframes kf0 {}
</style>
<script>
document.addEventListener("DOMContentLoaded", () => {
window.focus();
document.designMode = "on";
document.onpointerlockerror = onPointerLockErrorOrAnimationStart;
const mask = document.querySelector("mask");
mask.requestPointerLock();
mask.prepend(document.querySelector("table"));
});
function onPointerLockErrorOrAnimationStart() {
document.execCommand("underline");
document.execCommand("delete");
onanimationstart = onPointerLockErrorOrAnimationStart;
try {
getSelection().setBaseAndExtent(
document.querySelector("li"), 0,
document.querySelector("thead"), 0
);
} catch (e) {}
}
</script>
<body><svg>
<mask>
<clipPath>
</clipPath></mask></svg><sup>
AA
<li>
<br></li></sup><table>
<thead>
</thead></table>