Bug 1739524 - part 2: Make `RangeUpdater::SelAdjSplitNode()` handle both cases that right/left node is a new node r=m_kato

Currently, it assumes that `aLeftNode` is new node and the other is the original
one.  However, we need the opposite case when we fix bug 1735608.

Unfortunately, we cannot test the new path until we fix bug 1735608.  Therefore,
the new path may contain some bugs.

Differential Revision: https://phabricator.services.mozilla.com/D130427
This commit is contained in:
Masayuki Nakano 2021-11-08 09:49:33 +00:00
Родитель b4cbc8db19
Коммит f3ce4ebc2d
4 изменённых файлов: 56 добавлений и 26 удалений

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

@ -37,6 +37,12 @@ enum class JoinNodesDirection {
LeftNodeIntoRightNode,
RightNodeIntoLeftNode,
};
// SplitNodeDirection is also affected to which one is removed at joining a
// node because a couple of undo/redo.
enum class SplitNodeDirection {
LeftNodeIsNewOne,
RightNodeIsNewOne,
};
/*****************************************************************************
* EditResult returns nsresult and preferred point where selection should be

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

@ -4233,7 +4233,8 @@ already_AddRefed<nsIContent> HTMLEditor::SplitNodeWithTransaction(
// XXX Some other transactions manage range updater by themselves.
// Why doesn't SplitNodeTransaction do it?
DebugOnly<nsresult> rvIgnored = RangeUpdaterRef().SelAdjSplitNode(
*aStartOfRightNode.GetContainerAsContent(), *newLeftContent);
*aStartOfRightNode.GetContainerAsContent(), aStartOfRightNode.Offset(),
*newLeftContent, SplitNodeDirection::LeftNodeIsNewOne);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
"RangeUpdater::SelAdjSplitNode() failed, but ignored");
}

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

@ -6,7 +6,7 @@
#include "SelectionState.h"
#include "EditorUtils.h" // for EditorUtils
#include "HTMLEditHelpers.h" // for JoinNodesDirection
#include "HTMLEditHelpers.h" // for JoinNodesDirection, SplitNodeDirection
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
#include "mozilla/dom/RangeBinding.h"
@ -304,8 +304,10 @@ void RangeUpdater::SelAdjDeleteNode(nsINode& aNodeToDelete) {
}
}
nsresult RangeUpdater::SelAdjSplitNode(nsIContent& aRightNode,
nsIContent& aNewLeftNode) {
nsresult RangeUpdater::SelAdjSplitNode(nsIContent& aOriginalContent,
uint32_t aSplitOffset,
nsIContent& aNewContent,
SplitNodeDirection aSplitNodeDirection) {
if (mLocked) {
// lock set by Will/DidReplaceParent, etc...
return NS_OK;
@ -315,36 +317,40 @@ nsresult RangeUpdater::SelAdjSplitNode(nsIContent& aRightNode,
return NS_OK;
}
EditorRawDOMPoint atLeftNode(&aNewLeftNode);
nsresult rv = SelAdjInsertNode(atLeftNode);
EditorRawDOMPoint atNewNode(&aNewContent);
nsresult rv = SelAdjInsertNode(atNewNode);
if (NS_FAILED(rv)) {
NS_WARNING("RangeUpdater::SelAdjInsertNode() failed");
return rv;
}
// If point in the ranges is in left node, change its container to the left
// node. If point in the ranges is in right node, subtract numbers of
// children moved to left node from the offset.
uint32_t lengthOfLeftNode = aNewLeftNode.Length();
// If point is in the range which are moved from aOriginalContent to
// aNewContent, we need to change its container to aNewContent and may need to
// adjust the offset. If point is in the range which are not moved from
// aOriginalContent, we may need to adjust the offset.
auto AdjustDOMPoint = [&](nsCOMPtr<nsINode>& aContainer,
uint32_t& aOffset) -> void {
if (aContainer != &aOriginalContent) {
return;
}
if (aSplitNodeDirection == SplitNodeDirection::LeftNodeIsNewOne) {
if (aOffset > aSplitOffset) {
aOffset -= aSplitOffset;
} else {
aContainer = &aNewContent;
}
} else if (aOffset >= aSplitOffset) {
aContainer = &aNewContent;
aOffset = aSplitOffset - aOffset;
}
};
for (RefPtr<RangeItem>& rangeItem : mArray) {
if (NS_WARN_IF(!rangeItem)) {
return NS_ERROR_FAILURE;
}
if (rangeItem->mStartContainer == &aRightNode) {
if (rangeItem->mStartOffset > lengthOfLeftNode) {
rangeItem->mStartOffset -= lengthOfLeftNode;
} else {
rangeItem->mStartContainer = &aNewLeftNode;
}
}
if (rangeItem->mEndContainer == &aRightNode) {
if (rangeItem->mEndOffset > lengthOfLeftNode) {
rangeItem->mEndOffset -= lengthOfLeftNode;
} else {
rangeItem->mEndContainer = &aNewLeftNode;
}
}
AdjustDOMPoint(rangeItem->mStartContainer, rangeItem->mStartOffset);
AdjustDOMPoint(rangeItem->mEndContainer, rangeItem->mEndOffset);
}
return NS_OK;
}

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

@ -27,6 +27,7 @@ class Text;
} // namespace dom
enum class JoinNodesDirection; // Declared in HTMLEditHelpers.h
enum class SplitNodeDirection; // Declared in HTMLEditHelpers.h
/**
* A helper struct for saving/setting ranges.
@ -142,7 +143,23 @@ class MOZ_STACK_CLASS RangeUpdater final {
template <typename PT, typename CT>
nsresult SelAdjInsertNode(const EditorDOMPointBase<PT, CT>& aPoint);
void SelAdjDeleteNode(nsINode& aNode);
nsresult SelAdjSplitNode(nsIContent& aRightNode, nsIContent& aNewLeftNode);
/**
* SelAdjSplitNode() is called immediately after spliting aOriginalNode
* and inserted aNewContent into the DOM tree.
*
* @param aOriginalContent The node which was split.
* @param aSplitOffset The old offset in aOriginalContent at splitting
* it.
* @param aNewContent The new content node which was inserted into
* the DOM tree.
* @param aSplitNodeDirection Whether aNewNode was inserted before or after
* aOriginalContent.
*/
nsresult SelAdjSplitNode(nsIContent& aOriginalContent, uint32_t aSplitOffset,
nsIContent& aNewContent,
SplitNodeDirection aSplitNodeDirection);
/**
* SelAdjJoinNodes() is called immediately after joining aRemovedContent and
* the container of aStartOfRightContent.