Bug 1655392 - part 4: Give independent mode and handler for the next block of AutoBlockElementsJoiner::HandleDeleteNonCollapsedRanges() r=m_kato

And now, `HTMLEditor::JoinNodesDeepWithTransaction()` is used only by
`AutoBlockElementsJoiner`.  Therefore, this patch moves it to the
stack only class.

Differential Revision: https://phabricator.services.mozilla.com/D86789
This commit is contained in:
Masayuki Nakano 2020-08-16 04:20:38 +00:00
parent aa3497a28e
commit 9d1482c813
2 changed files with 102 additions and 61 deletions

View File

@ -3440,6 +3440,23 @@ bool HTMLEditor::AutoBlockElementsJoiner::PrepareToDeleteNonCollapsedRanges(
mMode = Mode::DeleteContentInRanges;
return true;
}
// If left block and right block are adjuscent siblings and they are same
// type of elements, we can merge them after deleting the selected contents.
// MOOSE: this could conceivably screw up a table.. fix me.
if (mLeftContent->GetParentNode() == mRightContent->GetParentNode() &&
HTMLEditUtils::CanContentsBeJoined(
*mLeftContent, *mRightContent,
aHTMLEditor.IsCSSEnabled() ? StyleDifference::CompareIfSpanElements
: StyleDifference::Ignore) &&
// XXX What's special about these three types of block?
(mLeftContent->IsHTMLElement(nsGkAtoms::p) ||
HTMLEditUtils::IsListItem(mLeftContent) ||
HTMLEditUtils::IsHeader(*mLeftContent))) {
mMode = Mode::JoinBlocksInSameParent;
return true;
}
mMode = Mode::DeleteNonCollapsedRanges;
return true;
}
@ -3490,6 +3507,48 @@ EditActionResult HTMLEditor::AutoBlockElementsJoiner::DeleteContentInRanges(
return EditActionHandled(rv);
}
EditActionResult
HTMLEditor::AutoBlockElementsJoiner::JoinBlockElementsInSameParent(
HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers, AutoRangeArray& aRangesToDelete) {
MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable());
MOZ_ASSERT(!aRangesToDelete.IsCollapsed());
MOZ_ASSERT(mMode == Mode::JoinBlocksInSameParent);
MOZ_ASSERT(mLeftContent);
MOZ_ASSERT(mLeftContent->IsElement());
MOZ_ASSERT(aRangesToDelete.FirstRangeRef()
->GetStartContainer()
->IsInclusiveDescendantOf(mLeftContent));
MOZ_ASSERT(mRightContent);
MOZ_ASSERT(mRightContent->IsElement());
MOZ_ASSERT(aRangesToDelete.FirstRangeRef()
->GetEndContainer()
->IsInclusiveDescendantOf(mRightContent));
MOZ_ASSERT(mLeftContent->GetParentNode() == mRightContent->GetParentNode());
nsresult rv = aHTMLEditor.DeleteRangesWithTransaction(
aDirectionAndAmount, aStripWrappers, aRangesToDelete);
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::DeleteRangesWithTransaction() failed");
return EditActionHandled(rv);
}
Result<EditorDOMPoint, nsresult> atFirstChildOfTheLastRightNodeOrError =
JoinNodesDeepWithTransaction(aHTMLEditor, MOZ_KnownLive(*mLeftContent),
MOZ_KnownLive(*mRightContent));
if (atFirstChildOfTheLastRightNodeOrError.isErr()) {
NS_WARNING("HTMLEditor::JoinNodesDeepWithTransaction() failed");
return EditActionHandled(atFirstChildOfTheLastRightNodeOrError.unwrapErr());
}
MOZ_ASSERT(atFirstChildOfTheLastRightNodeOrError.inspect().IsSet());
rv = aHTMLEditor.CollapseSelectionTo(
atFirstChildOfTheLastRightNodeOrError.inspect());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::CollapseSelectionTo() failed");
return EditActionHandled(rv);
}
EditActionResult
HTMLEditor::AutoBlockElementsJoiner::HandleDeleteNonCollapsedRanges(
HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount,
@ -3508,43 +3567,6 @@ HTMLEditor::AutoBlockElementsJoiner::HandleDeleteNonCollapsedRanges(
->GetEndContainer()
->IsInclusiveDescendantOf(mRightContent));
// If left block and right block are adjuscent siblings and they are same
// type of elements, we can merge them after deleting the selected contents.
// MOOSE: this could conceivably screw up a table.. fix me.
if (mLeftContent->GetParentNode() == mRightContent->GetParentNode() &&
HTMLEditUtils::CanContentsBeJoined(
*mLeftContent, *mRightContent,
aHTMLEditor.IsCSSEnabled() ? StyleDifference::CompareIfSpanElements
: StyleDifference::Ignore) &&
// XXX What's special about these three types of block?
(mLeftContent->IsHTMLElement(nsGkAtoms::p) ||
HTMLEditUtils::IsListItem(mLeftContent) ||
HTMLEditUtils::IsHeader(*mLeftContent))) {
// First delete the selection
nsresult rv = aHTMLEditor.DeleteRangesWithTransaction(
aDirectionAndAmount, aStripWrappers, aRangesToDelete);
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::DeleteRangesWithTransaction() failed");
return EditActionHandled(rv);
}
// Join blocks
Result<EditorDOMPoint, nsresult> atFirstChildOfTheLastRightNodeOrError =
aHTMLEditor.JoinNodesDeepWithTransaction(MOZ_KnownLive(*mLeftContent),
MOZ_KnownLive(*mRightContent));
if (atFirstChildOfTheLastRightNodeOrError.isErr()) {
NS_WARNING("HTMLEditor::JoinNodesDeepWithTransaction() failed");
return EditActionHandled(
atFirstChildOfTheLastRightNodeOrError.unwrapErr());
}
MOZ_ASSERT(atFirstChildOfTheLastRightNodeOrError.inspect().IsSet());
// Fix up selection
rv = aHTMLEditor.CollapseSelectionTo(
atFirstChildOfTheLastRightNodeOrError.inspect());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::CollapseSelectionTo() failed");
return EditActionHandled(rv);
}
// Otherwise, delete every nodes in all ranges, then, clean up something.
EditActionResult result(NS_OK);
result.MarkAsHandled();
@ -4464,8 +4486,10 @@ EditorDOMPoint HTMLEditor::GetGoodCaretPointFor(
return EditorDOMPoint(&aContent);
}
Result<EditorDOMPoint, nsresult> HTMLEditor::JoinNodesDeepWithTransaction(
nsIContent& aLeftContent, nsIContent& aRightContent) {
Result<EditorDOMPoint, nsresult>
HTMLEditor::AutoBlockElementsJoiner::JoinNodesDeepWithTransaction(
HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
nsIContent& aRightContent) {
// While the rightmost children and their descendants of the left node match
// the leftmost children and their descendants of the right node, join them
// up.
@ -4476,17 +4500,17 @@ Result<EditorDOMPoint, nsresult> HTMLEditor::JoinNodesDeepWithTransaction(
EditorDOMPoint ret;
const HTMLEditUtils::StyleDifference kCompareStyle =
IsCSSEnabled() ? StyleDifference::CompareIfSpanElements
: StyleDifference::Ignore;
aHTMLEditor.IsCSSEnabled() ? StyleDifference::CompareIfSpanElements
: StyleDifference::Ignore;
while (leftContentToJoin && rightContentToJoin && parentNode &&
HTMLEditUtils::CanContentsBeJoined(
*leftContentToJoin, *rightContentToJoin, kCompareStyle)) {
uint32_t length = leftContentToJoin->Length();
// Do the join
nsresult rv =
JoinNodesWithTransaction(*leftContentToJoin, *rightContentToJoin);
if (NS_WARN_IF(Destroyed())) {
nsresult rv = aHTMLEditor.JoinNodesWithTransaction(*leftContentToJoin,
*rightContentToJoin);
if (NS_WARN_IF(aHTMLEditor.Destroyed())) {
return Err(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_FAILED(rv)) {

View File

@ -2363,23 +2363,6 @@ class HTMLEditor final : public TextEditor,
const EditorDOMPoint& aDeepestStartOfRightNode,
SplitAtEdges aSplitAtEdges);
/**
* JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
* First, they are joined simply, then, new right node is assumed as the
* child at length of the left node before joined and new left node is
* assumed as its previous sibling. Then, they will be joined again.
* And then, these steps are repeated.
*
* @param aLeftContent The node which will be removed form the tree.
* @param aRightContent The node which will be inserted the contents of
* aRightContent.
* @return The point of the first child of the last right node.
* The result is always set if this succeeded.
*/
MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
JoinNodesDeepWithTransaction(nsIContent& aLeftContent,
nsIContent& aRightContent);
/**
* TryToJoinBlocksWithTransaction() tries to join two block elements. The
* right element is always joined to the left element. If the elements are
@ -2815,6 +2798,7 @@ class HTMLEditor final : public TextEditor,
"AutoBlockElementsJoiner::DeleteBRElement() failed");
return result;
}
case Mode::JoinBlocksInSameParent:
case Mode::DeleteContentInRanges:
case Mode::DeleteNonCollapsedRanges:
MOZ_ASSERT_UNREACHABLE(
@ -2851,6 +2835,15 @@ class HTMLEditor final : public TextEditor,
MOZ_ASSERT_UNREACHABLE(
"This mode should be handled in the other Run()");
return EditActionResult(NS_ERROR_UNEXPECTED);
case Mode::JoinBlocksInSameParent: {
EditActionResult result =
JoinBlockElementsInSameParent(aHTMLEditor, aDirectionAndAmount,
aStripWrappers, aRangesToDelete);
NS_WARNING_ASSERTION(result.Succeeded(),
"AutoBlockElementsJoiner::"
"JoinBlockElementsInSameParent() failed");
return result;
}
case Mode::DeleteContentInRanges: {
EditActionResult result =
DeleteContentInRanges(aHTMLEditor, aDirectionAndAmount,
@ -2892,6 +2885,11 @@ class HTMLEditor final : public TextEditor,
[[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
HTMLEditor& aHTMLEditor, const EditorDOMPoint& aCaretPoint);
[[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
JoinBlockElementsInSameParent(HTMLEditor& aHTMLEditor,
nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers,
AutoRangeArray& aRangesToDelete);
[[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult DeleteBRElement(
HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount,
const EditorDOMPoint& aCaretPoint);
@ -2906,10 +2904,29 @@ class HTMLEditor final : public TextEditor,
AutoRangeArray& aRangesToDelete,
HTMLEditor::SelectionWasCollapsed aSelectionWasCollapsed);
/**
* JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
* First, they are joined simply, then, new right node is assumed as the
* child at length of the left node before joined and new left node is
* assumed as its previous sibling. Then, they will be joined again.
* And then, these steps are repeated.
*
* @param aLeftContent The node which will be removed form the tree.
* @param aRightContent The node which will be inserted the contents of
* aRightContent.
* @return The point of the first child of the last right
* node. The result is always set if this succeeded.
*/
MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
JoinNodesDeepWithTransaction(HTMLEditor& aHTMLEditor,
nsIContent& aLeftContent,
nsIContent& aRightContent);
enum class Mode {
NotInitialized,
JoinCurrentBlock,
JoinOtherBlock,
JoinBlocksInSameParent,
DeleteBRElement,
DeleteContentInRanges,
DeleteNonCollapsedRanges,