Bug 1540037 - part 4: Move `EditorBase::SplitNodeDeepWithTransaction()` to `HTMLEditor` r=m_kato

It's only used by `HTMLEditor` so that we can move it.

Differential Revision: https://phabricator.services.mozilla.com/D72826
This commit is contained in:
Masayuki Nakano 2020-04-30 07:29:27 +00:00
Родитель f7fe0d0066
Коммит 94a85cde62
8 изменённых файлов: 139 добавлений и 143 удалений

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

@ -4015,89 +4015,6 @@ bool EditorBase::IsPreformatted(nsINode* aNode) {
return styleText->WhiteSpaceIsSignificant();
}
SplitNodeResult EditorBase::SplitNodeDeepWithTransaction(
nsIContent& aMostAncestorToSplit,
const EditorDOMPoint& aStartOfDeepestRightNode,
SplitAtEdges aSplitAtEdges) {
MOZ_ASSERT(aStartOfDeepestRightNode.IsSetAndValid());
MOZ_ASSERT(
aStartOfDeepestRightNode.GetContainer() == &aMostAncestorToSplit ||
EditorUtils::IsDescendantOf(*aStartOfDeepestRightNode.GetContainer(),
aMostAncestorToSplit));
if (NS_WARN_IF(!aStartOfDeepestRightNode.IsSet())) {
return SplitNodeResult(NS_ERROR_INVALID_ARG);
}
nsCOMPtr<nsIContent> newLeftNodeOfMostAncestor;
EditorDOMPoint atStartOfRightNode(aStartOfDeepestRightNode);
while (true) {
// Need to insert rules code call here to do things like not split a list
// if you are after the last <li> or before the first, etc. For now we
// just have some smarts about unneccessarily splitting text nodes, which
// should be universal enough to put straight in this EditorBase routine.
if (NS_WARN_IF(!atStartOfRightNode.GetContainerAsContent())) {
return SplitNodeResult(NS_ERROR_FAILURE);
}
// If we meet an orphan node before meeting aMostAncestorToSplit, we need
// to stop splitting. This is a bug of the caller.
if (NS_WARN_IF(atStartOfRightNode.GetContainer() != &aMostAncestorToSplit &&
!atStartOfRightNode.GetContainerParentAsContent())) {
return SplitNodeResult(NS_ERROR_FAILURE);
}
nsIContent* currentRightNode = atStartOfRightNode.GetContainerAsContent();
// If the split point is middle of the node or the node is not a text node
// and we're allowed to create empty element node, split it.
if ((aSplitAtEdges == SplitAtEdges::eAllowToCreateEmptyContainer &&
!atStartOfRightNode.GetContainerAsText()) ||
(!atStartOfRightNode.IsStartOfContainer() &&
!atStartOfRightNode.IsEndOfContainer())) {
ErrorResult error;
nsCOMPtr<nsIContent> newLeftNode =
SplitNodeWithTransaction(atStartOfRightNode, error);
if (error.Failed()) {
NS_WARNING("EditorBase::SplitNodeWithTransaction() failed");
return SplitNodeResult(error.StealNSResult());
}
if (currentRightNode == &aMostAncestorToSplit) {
// Actually, we split aMostAncestorToSplit.
return SplitNodeResult(newLeftNode, &aMostAncestorToSplit);
}
// Then, try to split its parent before current node.
atStartOfRightNode.Set(currentRightNode);
}
// If the split point is end of the node and it is a text node or we're not
// allowed to create empty container node, try to split its parent after it.
else if (!atStartOfRightNode.IsStartOfContainer()) {
if (currentRightNode == &aMostAncestorToSplit) {
return SplitNodeResult(&aMostAncestorToSplit, nullptr);
}
// Try to split its parent after current node.
atStartOfRightNode.Set(currentRightNode);
DebugOnly<bool> advanced = atStartOfRightNode.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after current node");
}
// If the split point is start of the node and it is a text node or we're
// not allowed to create empty container node, try to split its parent.
else {
if (currentRightNode == &aMostAncestorToSplit) {
return SplitNodeResult(nullptr, &aMostAncestorToSplit);
}
// Try to split its parent before current node.
atStartOfRightNode.Set(currentRightNode);
}
}
return SplitNodeResult(NS_ERROR_FAILURE);
}
nsresult EditorBase::EnsureNoPaddingBRElementForEmptyEditor() {
MOZ_ASSERT(IsEditActionDataAvailable());

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

@ -113,22 +113,6 @@ namespace widget {
struct IMEState;
} // namespace widget
/**
* SplitAtEdges is for EditorBase::SplitNodeDeepWithTransaction(),
* HTMLEditor::InsertNodeAtPoint()
*/
enum class SplitAtEdges {
// EditorBase::SplitNodeDeepWithTransaction() won't split container element
// nodes at their edges. I.e., when split point is start or end of
// container, it won't be split.
eDoNotCreateEmptyContainer,
// EditorBase::SplitNodeDeepWithTransaction() always splits containers even
// if the split point is at edge of a container. E.g., if split point is
// start of an inline element, empty inline element is created as a new left
// node.
eAllowToCreateEmptyContainer,
};
/**
* Implementation of an editor object. it will be the controller/focal point
* for the main editor services. i.e. the GUIManager, publishing, transaction
@ -1712,28 +1696,6 @@ class EditorBase : public nsIEditor,
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToJoin);
/**
* SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
*
* @param aMostAncestorToSplit The most ancestor node which should be
* split.
* @param aStartOfDeepestRightNode The start point of deepest right node.
* This point must be descendant of
* aMostAncestorToSplit.
* @param aSplitAtEdges Whether the caller allows this to
* create empty container element when
* split point is start or end of an
* element.
* @return SplitPoint() returns split point in
* aMostAncestorToSplit. The point must
* be good to insert something if the
* caller want to do it.
*/
MOZ_CAN_RUN_SCRIPT SplitNodeResult
SplitNodeDeepWithTransaction(nsIContent& aMostAncestorToSplit,
const EditorDOMPoint& aDeepestStartOfRightNode,
SplitAtEdges aSplitAtEdges);
/**
* EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
* for empty editor if there is.

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

@ -383,7 +383,7 @@ inline MoveNodeResult MoveNodeHandled(
/***************************************************************************
* SplitNodeResult is a simple class for
* EditorBase::SplitNodeDeepWithTransaction().
* HTMLEditor::SplitNodeDeepWithTransaction().
* This makes the callers' code easier to read.
*/
class MOZ_STACK_CLASS SplitNodeResult final {

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

@ -2063,7 +2063,7 @@ nsresult HTMLEditor::InsertBRElement(const EditorDOMPoint& aPointToBreak) {
}
if (splitLinkNodeResult.Failed()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) failed");
return splitLinkNodeResult.Rv();
}
@ -2197,7 +2197,7 @@ EditActionResult HTMLEditor::SplitMailCiteElements(
}
if (splitCiteNodeResult.Failed()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) failed");
return EditActionIgnored(splitCiteNodeResult.Rv());
}
@ -5143,7 +5143,7 @@ nsresult HTMLEditor::FormatBlockContainerWithTransaction(nsAtom& blockType) {
return NS_ERROR_EDITOR_DESTROYED;
}
if (splitNodeResult.Failed()) {
NS_WARNING("EditorBase::SplitNodeDeepWithTransaction() failed");
NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed");
return splitNodeResult.Rv();
}
EditorDOMPoint pointToInsertBRNode(splitNodeResult.SplitPoint());
@ -6475,7 +6475,7 @@ SplitRangeOffFromNodeResult HTMLEditor::SplitRangeOffFromBlock(
return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(splitAtStartResult.Succeeded(),
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) failed");
// Split at after the end
@ -6488,7 +6488,7 @@ SplitRangeOffFromNodeResult HTMLEditor::SplitRangeOffFromBlock(
return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(splitAtEndResult.Succeeded(),
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) failed");
return SplitRangeOffFromNodeResult(splitAtStartResult, splitAtEndResult);
@ -6648,7 +6648,7 @@ nsresult HTMLEditor::CreateStyleForInsertText(AbstractRange& aAbstractRange) {
}
if (splitTextNodeResult.Failed()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eAllowToCreateEmptyContainer) failed");
return splitTextNodeResult.Rv();
}
@ -8480,14 +8480,14 @@ nsresult HTMLEditor::SplitParentInlineElementsAtRangeEdges(
}
if (splitEndInlineResult.Failed()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) failed");
return splitEndInlineResult.Rv();
}
EditorRawDOMPoint splitPointAtEnd(splitEndInlineResult.SplitPoint());
if (!splitPointAtEnd.IsSet()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) didn't return split point");
return NS_ERROR_FAILURE;
}
@ -8508,7 +8508,7 @@ nsresult HTMLEditor::SplitParentInlineElementsAtRangeEdges(
}
if (splitStartInlineResult.Failed()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) failed");
return splitStartInlineResult.Rv();
}
@ -8518,7 +8518,7 @@ nsresult HTMLEditor::SplitParentInlineElementsAtRangeEdges(
EditorRawDOMPoint splitPointAtStart(splitStartInlineResult.SplitPoint());
if (!splitPointAtStart.IsSet()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eDoNotCreateEmptyContainer) didn't return split point");
return NS_ERROR_FAILURE;
}
@ -8558,7 +8558,7 @@ nsresult HTMLEditor::SplitElementsAtEveryBRElement(
return NS_ERROR_EDITOR_DESTROYED;
}
if (splitNodeResult.Failed()) {
NS_WARNING("EditorBase::SplitNodeDeepWithTransaction() failed");
NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed");
return splitNodeResult.Rv();
}
@ -8703,7 +8703,7 @@ nsresult HTMLEditor::HandleInsertParagraphInHeadingElement(Element& aHeader,
}
NS_WARNING_ASSERTION(
splitHeaderResult.Succeeded(),
"EditorBase::SplitNodeDeepWithTransaction() failed, but ignored");
"HTMLEditor::SplitNodeDeepWithTransaction() failed, but ignored");
// If the previous heading of split point is empty, put a padding <br>
// element for empty last line into it.
@ -9010,12 +9010,12 @@ nsresult HTMLEditor::SplitParagraph(
return NS_ERROR_EDITOR_DESTROYED;
}
if (splitDivOrPResult.Failed()) {
NS_WARNING("EditorBase::SplitNodeDeepWithTransaction() failed");
NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed");
return splitDivOrPResult.Rv();
}
if (!splitDivOrPResult.DidSplit()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction() didn't split any nodes");
"HTMLEditor::SplitNodeDeepWithTransaction() didn't split any nodes");
return NS_ERROR_FAILURE;
}
@ -9211,7 +9211,7 @@ nsresult HTMLEditor::HandleInsertParagraphInListItemElement(Element& aListItem,
}
NS_WARNING_ASSERTION(
splitListItemResult.Succeeded(),
"EditorBase::SplitNodeDeepWithTransaction() failed, but ignored");
"HTMLEditor::SplitNodeDeepWithTransaction() failed, but ignored");
// Hack: until I can change the damaged doc range code back to being
// extra-inclusive, I have to manually detect certain list items that may be
@ -9866,7 +9866,7 @@ SplitNodeResult HTMLEditor::MaybeSplitAncestorsForInsertWithTransaction(
return SplitNodeResult(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
"EditorBase::SplitNodeDeepWithTransaction(SplitAtEdges::"
"HTMLEditor::SplitNodeDeepWithTransaction(SplitAtEdges::"
"eAllowToCreateEmptyContainer) failed");
return splitNodeResult;
}

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

@ -1798,7 +1798,7 @@ EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
SplitNodeDeepWithTransaction(MOZ_KnownLive(*pointToInsert.GetChild()),
aPointToInsert, aSplitAtEdges);
if (splitNodeResult.Failed()) {
NS_WARNING("EditorBase::SplitNodeDeepWithTransaction() failed");
NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed");
return EditorDOMPoint();
}
pointToInsert = splitNodeResult.SplitPoint();
@ -3985,6 +3985,89 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
return rv;
}
SplitNodeResult HTMLEditor::SplitNodeDeepWithTransaction(
nsIContent& aMostAncestorToSplit,
const EditorDOMPoint& aStartOfDeepestRightNode,
SplitAtEdges aSplitAtEdges) {
MOZ_ASSERT(aStartOfDeepestRightNode.IsSetAndValid());
MOZ_ASSERT(
aStartOfDeepestRightNode.GetContainer() == &aMostAncestorToSplit ||
EditorUtils::IsDescendantOf(*aStartOfDeepestRightNode.GetContainer(),
aMostAncestorToSplit));
if (NS_WARN_IF(!aStartOfDeepestRightNode.IsSet())) {
return SplitNodeResult(NS_ERROR_INVALID_ARG);
}
nsCOMPtr<nsIContent> newLeftNodeOfMostAncestor;
EditorDOMPoint atStartOfRightNode(aStartOfDeepestRightNode);
while (true) {
// Need to insert rules code call here to do things like not split a list
// if you are after the last <li> or before the first, etc. For now we
// just have some smarts about unneccessarily splitting text nodes, which
// should be universal enough to put straight in this EditorBase routine.
if (NS_WARN_IF(!atStartOfRightNode.GetContainerAsContent())) {
return SplitNodeResult(NS_ERROR_FAILURE);
}
// If we meet an orphan node before meeting aMostAncestorToSplit, we need
// to stop splitting. This is a bug of the caller.
if (NS_WARN_IF(atStartOfRightNode.GetContainer() != &aMostAncestorToSplit &&
!atStartOfRightNode.GetContainerParentAsContent())) {
return SplitNodeResult(NS_ERROR_FAILURE);
}
nsIContent* currentRightNode = atStartOfRightNode.GetContainerAsContent();
// If the split point is middle of the node or the node is not a text node
// and we're allowed to create empty element node, split it.
if ((aSplitAtEdges == SplitAtEdges::eAllowToCreateEmptyContainer &&
!atStartOfRightNode.GetContainerAsText()) ||
(!atStartOfRightNode.IsStartOfContainer() &&
!atStartOfRightNode.IsEndOfContainer())) {
ErrorResult error;
nsCOMPtr<nsIContent> newLeftNode =
SplitNodeWithTransaction(atStartOfRightNode, error);
if (error.Failed()) {
NS_WARNING("EditorBase::SplitNodeWithTransaction() failed");
return SplitNodeResult(error.StealNSResult());
}
if (currentRightNode == &aMostAncestorToSplit) {
// Actually, we split aMostAncestorToSplit.
return SplitNodeResult(newLeftNode, &aMostAncestorToSplit);
}
// Then, try to split its parent before current node.
atStartOfRightNode.Set(currentRightNode);
}
// If the split point is end of the node and it is a text node or we're not
// allowed to create empty container node, try to split its parent after it.
else if (!atStartOfRightNode.IsStartOfContainer()) {
if (currentRightNode == &aMostAncestorToSplit) {
return SplitNodeResult(&aMostAncestorToSplit, nullptr);
}
// Try to split its parent after current node.
atStartOfRightNode.Set(currentRightNode);
DebugOnly<bool> advanced = atStartOfRightNode.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after current node");
}
// If the split point is start of the node and it is a text node or we're
// not allowed to create empty container node, try to split its parent.
else {
if (currentRightNode == &aMostAncestorToSplit) {
return SplitNodeResult(nullptr, &aMostAncestorToSplit);
}
// Try to split its parent before current node.
atStartOfRightNode.Set(currentRightNode);
}
}
return SplitNodeResult(NS_ERROR_FAILURE);
}
nsIContent* HTMLEditor::GetPriorHTMLSibling(nsINode* aNode,
SkipWhitespace aSkipWS) const {
MOZ_ASSERT(aNode);

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

@ -2158,6 +2158,40 @@ class HTMLEditor final : public TextEditor,
const EditorDOMPoint& aPointToInsert,
MoveToEndOfContainer aMoveToEndOfContainer = MoveToEndOfContainer::No);
enum class SplitAtEdges {
// SplitNodeDeepWithTransaction() won't split container element
// nodes at their edges. I.e., when split point is start or end of
// container, it won't be split.
eDoNotCreateEmptyContainer,
// SplitNodeDeepWithTransaction() always splits containers even
// if the split point is at edge of a container. E.g., if split point is
// start of an inline element, empty inline element is created as a new left
// node.
eAllowToCreateEmptyContainer,
};
/**
* SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
*
* @param aMostAncestorToSplit The most ancestor node which should be
* split.
* @param aStartOfDeepestRightNode The start point of deepest right node.
* This point must be descendant of
* aMostAncestorToSplit.
* @param aSplitAtEdges Whether the caller allows this to
* create empty container element when
* split point is start or end of an
* element.
* @return SplitPoint() returns split point in
* aMostAncestorToSplit. The point must
* be good to insert something if the
* caller want to do it.
*/
MOZ_CAN_RUN_SCRIPT SplitNodeResult
SplitNodeDeepWithTransaction(nsIContent& aMostAncestorToSplit,
const EditorDOMPoint& aDeepestStartOfRightNode,
SplitAtEdges aSplitAtEdges);
/**
* JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
* First, they are joined simply, then, new right node is assumed as the

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

@ -420,13 +420,13 @@ nsresult HTMLEditor::DoInsertHTMLWithContext(
MOZ_KnownLive(*pointToInsert.GetContainerAsContent()), pointToInsert,
SplitAtEdges::eAllowToCreateEmptyContainer);
if (splitNodeResult.Failed()) {
NS_WARNING("EditorBase::SplitNodeDeepWithTransaction() failed");
NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed");
return splitNodeResult.Rv();
}
pointToInsert = splitNodeResult.SplitPoint();
if (!pointToInsert.IsSet()) {
NS_WARNING(
"EditorBase::SplitNodeDeepWithTransaction() didn't return split "
"HTMLEditor::SplitNodeDeepWithTransaction() didn't return split "
"point");
return NS_ERROR_FAILURE;
}
@ -760,7 +760,7 @@ nsresult HTMLEditor::DoInsertHTMLWithContext(
*linkElement, pointToPutCaret, SplitAtEdges::eDoNotCreateEmptyContainer);
NS_WARNING_ASSERTION(
splitLinkResult.Succeeded(),
"EditorBase::SplitNodeDeepWithTransaction() failed, but ignored");
"HTMLEditor::SplitNodeDeepWithTransaction() failed, but ignored");
if (splitLinkResult.GetPreviousNode()) {
EditorRawDOMPoint afterLeftLink(splitLinkResult.GetPreviousNode());
if (afterLeftLink.AdvanceOffset()) {

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

@ -809,7 +809,7 @@ SplitNodeResult HTMLEditor::SplitAncestorStyledInlineElementsAt(
MOZ_KnownLive(content), result.SplitPoint(),
SplitAtEdges::eAllowToCreateEmptyContainer);
if (splitNodeResult.Failed()) {
NS_WARNING("EditorBase::SplitNodeDeepWithTransaction() failed");
NS_WARNING("HTMLEditor::SplitNodeDeepWithTransaction() failed");
return splitNodeResult;
}
MOZ_ASSERT(splitNodeResult.Handled());