diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp
index 17120e609854..6e66e48d889f 100644
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -2348,9 +2348,8 @@ EditActionResult HTMLEditRules::WillDeleteSelection(
// First check for table selection mode. If so, hand off to table editor.
ErrorResult error;
- RefPtr cellElement =
- HTMLEditorRef().GetFirstSelectedTableCellElement(error);
- if (cellElement) {
+ if (RefPtr cellElement =
+ HTMLEditorRef().GetFirstSelectedTableCellElement(error)) {
error.SuppressException();
nsresult rv =
MOZ_KnownLive(HTMLEditorRef()).DeleteTableCellContentsWithTransaction();
@@ -2361,18 +2360,26 @@ EditActionResult HTMLEditRules::WillDeleteSelection(
"DeleteTableCellContentsWithTransaction() failed");
return EditActionHandled(rv);
}
- nsresult rv = error.StealNSResult();
- cellElement = nullptr;
- // origCollapsed is used later to determine whether we should join blocks. We
- // don't really care about bCollapsed because it will be modified by
- // ExtendSelectionForDelete later. TryToJoinBlocksWithTransaction() should
- // happen if the original selection is collapsed and the cursor is at the end
- // of a block element, in which case ExtendSelectionForDelete would always
- // make the selection not collapsed.
- bool origCollapsed = SelectionRefPtr()->IsCollapsed();
+ // Only when there is no selection range, GetFirstSelectedTableCellElement()
+ // returns error and in this case, anyway we cannot handle delete selection.
+ // So, let's return error here even though we haven't handled this.
+ if (NS_WARN_IF(error.Failed())) {
+ return EditActionResult(error.StealNSResult());
+ }
- if (origCollapsed) {
+ // selectionWasCollapsed is used later to determine whether we should join
+ // blocks in HandleDeleteNonCollapasedSelection(). We don't really care
+ // about collapsed because it will be modified by ExtendSelectionForDelete()
+ // later. TryToJoinBlocksWithTransaction() should happen if the original
+ // selection is collapsed and the cursor is at the end of a block element,
+ // in which case ExtendSelectionForDelete() would always make the selection
+ // not collapsed.
+ SelectionWasCollapsed selectionWasCollapsed = SelectionRefPtr()->IsCollapsed()
+ ? SelectionWasCollapsed::Yes
+ : SelectionWasCollapsed::No;
+
+ if (selectionWasCollapsed == SelectionWasCollapsed::Yes) {
EditorDOMPoint startPoint(EditorBase::GetStartPoint(*SelectionRefPtr()));
if (NS_WARN_IF(!startPoint.IsSet())) {
return EditActionResult(NS_ERROR_FAILURE);
@@ -2411,7 +2418,8 @@ EditActionResult HTMLEditRules::WillDeleteSelection(
AutoSetTemporaryAncestorLimiter autoSetter(
HTMLEditorRef(), *SelectionRefPtr(), *startPoint.GetContainer());
- rv = HTMLEditorRef().ExtendSelectionForDelete(&aDirectionAndAmount);
+ nsresult rv =
+ HTMLEditorRef().ExtendSelectionForDelete(&aDirectionAndAmount);
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionResult(rv);
}
@@ -2420,541 +2428,564 @@ EditActionResult HTMLEditRules::WillDeleteSelection(
if (aDirectionAndAmount == nsIEditor::eNone) {
return EditActionIgnored();
}
+
+ if (SelectionRefPtr()->IsCollapsed()) {
+ EditActionResult result = HandleDeleteAroundCollapsedSelection(
+ aDirectionAndAmount, aStripWrappers);
+ NS_WARNING_ASSERTION(result.Succeeded(),
+ "HandleDeleteAroundCollapsedSelection() failed");
+ return result;
+ }
}
- if (SelectionRefPtr()->IsCollapsed()) {
- // ExtendSelectionForDelete() won't change the selection.
+ EditActionResult result = HandleDeleteNonCollapsedSelection(
+ aDirectionAndAmount, aStripWrappers, selectionWasCollapsed);
+ NS_WARNING_ASSERTION(result.Succeeded(),
+ "HandleDeleteNonCollapasedSelection() failed");
+ return result;
+}
- EditorDOMPoint startPoint(EditorBase::GetStartPoint(*SelectionRefPtr()));
- if (NS_WARN_IF(!startPoint.IsSet())) {
- return EditActionResult(NS_ERROR_FAILURE);
- }
+EditActionResult HTMLEditRules::HandleDeleteAroundCollapsedSelection(
+ nsIEditor::EDirection aDirectionAndAmount,
+ nsIEditor::EStripWrappers aStripWrappers) {
+ MOZ_ASSERT(IsEditorDataAvailable());
+ MOZ_ASSERT(HTMLEditorRef().IsTopLevelEditSubActionDataAvailable());
+ MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
+ MOZ_ASSERT(aDirectionAndAmount != nsIEditor::eNone);
- // What's in the direction we are deleting?
- WSRunObject wsObj(&HTMLEditorRef(), startPoint);
- nsCOMPtr visibleNode;
- int32_t visibleNodeOffset;
- WSType wsType;
+ EditorDOMPoint startPoint(EditorBase::GetStartPoint(*SelectionRefPtr()));
+ if (NS_WARN_IF(!startPoint.IsSet())) {
+ return EditActionResult(NS_ERROR_FAILURE);
+ }
- // Find next visible node
+ // What's in the direction we are deleting?
+ WSRunObject wsObj(&HTMLEditorRef(), startPoint);
+ nsCOMPtr visibleNode;
+ int32_t visibleNodeOffset;
+ WSType wsType;
+
+ // Find next visible node
+ if (aDirectionAndAmount == nsIEditor::eNext) {
+ wsObj.NextVisibleNode(startPoint, address_of(visibleNode),
+ &visibleNodeOffset, &wsType);
+ } else {
+ wsObj.PriorVisibleNode(startPoint, address_of(visibleNode),
+ &visibleNodeOffset, &wsType);
+ }
+
+ if (!visibleNode) {
+ return EditActionCanceled();
+ }
+
+ if (wsType == WSType::normalWS) {
+ // We found some visible ws to delete. Let ws code handle it.
if (aDirectionAndAmount == nsIEditor::eNext) {
- wsObj.NextVisibleNode(startPoint, address_of(visibleNode),
- &visibleNodeOffset, &wsType);
+ nsresult rv = wsObj.DeleteWSForward();
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionHandled(rv);
+ }
} else {
- wsObj.PriorVisibleNode(startPoint, address_of(visibleNode),
- &visibleNodeOffset, &wsType);
+ nsresult rv = wsObj.DeleteWSBackward();
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionHandled(rv);
+ }
}
+ nsresult rv = MOZ_KnownLive(HTMLEditorRef())
+ .InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
+ EditorBase::GetStartPoint(*SelectionRefPtr()));
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rv),
+ "InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary() failed");
+ return EditActionHandled(rv);
+ }
- if (!visibleNode) {
- // XXX This is the result of GetFirstSelectedTableCellElement().
- // This must be a bug.
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
- "GetFirstSelectedTableCellElement() failed");
- return EditActionCanceled(rv);
- }
-
- if (wsType == WSType::normalWS) {
- // We found some visible ws to delete. Let ws code handle it.
- if (aDirectionAndAmount == nsIEditor::eNext) {
- nsresult rv = wsObj.DeleteWSForward();
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionHandled(rv);
- }
- } else {
- nsresult rv = wsObj.DeleteWSBackward();
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionHandled(rv);
+ if (wsType == WSType::text) {
+ // Found normal text to delete.
+ OwningNonNull visibleTextNode = *visibleNode->GetAsText();
+ int32_t startOffset = visibleNodeOffset;
+ int32_t endOffset = visibleNodeOffset + 1;
+ if (aDirectionAndAmount == nsIEditor::ePrevious) {
+ if (!startOffset) {
+ return EditActionResult(NS_ERROR_UNEXPECTED);
+ }
+ startOffset--;
+ endOffset--;
+ // Bug 1068979: delete both codepoints if surrogate pair
+ if (startOffset > 0) {
+ const nsTextFragment* text = &visibleTextNode->TextFragment();
+ if (text->IsLowSurrogateFollowingHighSurrogateAt(startOffset)) {
+ startOffset--;
}
}
- nsresult rv =
- MOZ_KnownLive(HTMLEditorRef())
- .InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
- EditorBase::GetStartPoint(*SelectionRefPtr()));
- NS_WARNING_ASSERTION(
- NS_SUCCEEDED(rv),
- "InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary() failed");
+ } else {
+ RefPtr range = SelectionRefPtr()->GetRangeAt(0);
+ if (NS_WARN_IF(!range)) {
+ return EditActionResult(NS_ERROR_FAILURE);
+ }
+
+ NS_ASSERTION(range->GetStartContainer() == visibleNode,
+ "selection start not in visibleNode");
+ NS_ASSERTION(range->GetEndContainer() == visibleNode,
+ "selection end not in visibleNode");
+
+ startOffset = range->StartOffset();
+ endOffset = range->EndOffset();
+ }
+ nsresult rv = WSRunObject::PrepareToDeleteRange(
+ MOZ_KnownLive(&HTMLEditorRef()), address_of(visibleNode), &startOffset,
+ address_of(visibleNode), &endOffset);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionResult(rv);
+ }
+ rv = MOZ_KnownLive(HTMLEditorRef())
+ .DeleteTextWithTransaction(visibleTextNode,
+ std::min(startOffset, endOffset),
+ DeprecatedAbs(endOffset - startOffset));
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionHandled(rv);
}
- if (wsType == WSType::text) {
- // Found normal text to delete.
- OwningNonNull visibleTextNode = *visibleNode->GetAsText();
- int32_t startOffset = visibleNodeOffset;
- int32_t endOffset = visibleNodeOffset + 1;
- if (aDirectionAndAmount == nsIEditor::ePrevious) {
- if (!startOffset) {
- return EditActionResult(NS_ERROR_UNEXPECTED);
- }
- startOffset--;
- endOffset--;
- // Bug 1068979: delete both codepoints if surrogate pair
- if (startOffset > 0) {
- const nsTextFragment* text = &visibleTextNode->TextFragment();
- if (text->IsLowSurrogateFollowingHighSurrogateAt(startOffset)) {
- startOffset--;
- }
- }
- } else {
- RefPtr range = SelectionRefPtr()->GetRangeAt(0);
- if (NS_WARN_IF(!range)) {
- return EditActionResult(NS_ERROR_FAILURE);
- }
+ // XXX When Backspace key is pressed, Chromium removes following empty
+ // text nodes when removing the last character of the non-empty text
+ // node. However, Edge never removes empty text nodes even if
+ // selection is in the following empty text node(s). For now, we
+ // should keep our traditional behavior same as Edge for backward
+ // compatibility.
+ // XXX When Delete key is pressed, Edge removes all preceding empty
+ // text nodes when removing the first character of the non-empty
+ // text node. Chromium removes only selected empty text node and
+ // following empty text nodes and the first character of the
+ // non-empty text node. For now, we should keep our traditional
+ // behavior same as Chromium for backward compatibility.
- NS_ASSERTION(range->GetStartContainer() == visibleNode,
- "selection start not in visibleNode");
- NS_ASSERTION(range->GetEndContainer() == visibleNode,
- "selection end not in visibleNode");
+ rv = MOZ_KnownLive(HTMLEditorRef())
+ .DeleteNodeIfInvisibleAndEditableTextNode(visibleTextNode);
+ if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ }
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rv),
+ "DeleteNodeIfInvisibleAndEditableTextNode() failed, but ignored");
- startOffset = range->StartOffset();
- endOffset = range->EndOffset();
- }
- nsresult rv = WSRunObject::PrepareToDeleteRange(
- MOZ_KnownLive(&HTMLEditorRef()), address_of(visibleNode),
- &startOffset, address_of(visibleNode), &endOffset);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionResult(rv);
- }
- rv = MOZ_KnownLive(HTMLEditorRef())
- .DeleteTextWithTransaction(
- visibleTextNode, std::min(startOffset, endOffset),
- DeprecatedAbs(endOffset - startOffset));
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionHandled(rv);
- }
+ rv = MOZ_KnownLive(HTMLEditorRef())
+ .InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
+ EditorBase::GetStartPoint(*SelectionRefPtr()));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionHandled(rv);
+ }
- // XXX When Backspace key is pressed, Chromium removes following empty
- // text nodes when removing the last character of the non-empty text
- // node. However, Edge never removes empty text nodes even if
- // selection is in the following empty text node(s). For now, we
- // should keep our traditional behavior same as Edge for backward
- // compatibility.
- // XXX When Delete key is pressed, Edge removes all preceding empty
- // text nodes when removing the first character of the non-empty
- // text node. Chromium removes only selected empty text node and
- // following empty text nodes and the first character of the
- // non-empty text node. For now, we should keep our traditional
- // behavior same as Chromium for backward compatibility.
+ // Remember that we did a ranged delete for the benefit of
+ // AfterEditInner().
+ HTMLEditorRef().TopLevelEditSubActionDataRef().mDidDeleteNonCollapsedRange =
+ true;
- rv = MOZ_KnownLive(HTMLEditorRef())
- .DeleteNodeIfInvisibleAndEditableTextNode(visibleTextNode);
- if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
- }
- NS_WARNING_ASSERTION(
- NS_SUCCEEDED(rv),
- "DeleteNodeIfInvisibleAndEditableTextNode() failed, but ignored");
-
- rv = MOZ_KnownLive(HTMLEditorRef())
- .InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
- EditorBase::GetStartPoint(*SelectionRefPtr()));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionHandled(rv);
- }
-
- // Remember that we did a ranged delete for the benefit of
- // AfterEditInner().
- HTMLEditorRef()
- .TopLevelEditSubActionDataRef()
- .mDidDeleteNonCollapsedRange = true;
+ return EditActionHandled();
+ }
+ if (wsType == WSType::special || wsType == WSType::br ||
+ visibleNode->IsHTMLElement(nsGkAtoms::hr)) {
+ // If the void element is editing host, we should do nothing.
+ if (visibleNode == wsObj.GetEditingHost()) {
return EditActionHandled();
}
- if (wsType == WSType::special || wsType == WSType::br ||
+ // Short circuit for invisible breaks. delete them and recurse.
+ if (visibleNode->IsHTMLElement(nsGkAtoms::br) &&
+ !HTMLEditorRef().IsVisibleBRElement(visibleNode)) {
+ nsresult rv = MOZ_KnownLive(HTMLEditorRef())
+ .DeleteNodeWithTransaction(*visibleNode);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionResult(rv);
+ }
+ EditActionResult result =
+ WillDeleteSelection(aDirectionAndAmount, aStripWrappers);
+ NS_WARNING_ASSERTION(result.Succeeded(),
+ "Nested WillDeleteSelection() failed");
+ return result;
+ }
+
+ // Special handling for backspace when positioned after
+ if (aDirectionAndAmount == nsIEditor::ePrevious &&
visibleNode->IsHTMLElement(nsGkAtoms::hr)) {
- // If the void element is editing host, we should do nothing.
- if (visibleNode == wsObj.GetEditingHost()) {
- return EditActionHandled();
+ // Only if the caret is positioned at the end-of-hr-line position, we
+ // want to delete the
.
+ //
+ // In other words, we only want to delete, if our selection position
+ // (indicated by startPoint) is the position directly
+ // after the
, on the same line as the
.
+ //
+ // To detect this case we check:
+ // startPoint's container == parentOfVisNode
+ // and
+ // startPoint's offset -1 == visibleNodeOffsetToVisNodeParent
+ // and
+ // interline position is false (left)
+ //
+ // In any other case we set the position to startPoint's container -1
+ // and interlineposition to false, only moving the caret to the
+ // end-of-hr-line position.
+ bool moveOnly = true;
+
+ EditorRawDOMPoint atHRElement(visibleNode);
+
+ ErrorResult err;
+ bool interLineIsRight = SelectionRefPtr()->GetInterlinePosition(err);
+ if (NS_WARN_IF(err.Failed())) {
+ return EditActionResult(err.StealNSResult());
}
- // Short circuit for invisible breaks. delete them and recurse.
- if (visibleNode->IsHTMLElement(nsGkAtoms::br) &&
- !HTMLEditorRef().IsVisibleBRElement(visibleNode)) {
- nsresult rv = MOZ_KnownLive(HTMLEditorRef())
- .DeleteNodeWithTransaction(*visibleNode);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionResult(rv);
- }
- EditActionResult result =
- WillDeleteSelection(aDirectionAndAmount, aStripWrappers);
- NS_WARNING_ASSERTION(result.Succeeded(),
- "Nested WillDeleteSelection() failed");
- return result;
+ if (startPoint.GetContainer() == atHRElement.GetContainer() &&
+ startPoint.Offset() - 1 == atHRElement.Offset() &&
+ !interLineIsRight) {
+ moveOnly = false;
}
- // Special handling for backspace when positioned after
- if (aDirectionAndAmount == nsIEditor::ePrevious &&
- visibleNode->IsHTMLElement(nsGkAtoms::hr)) {
- // Only if the caret is positioned at the end-of-hr-line position, we
- // want to delete the
.
- //
- // In other words, we only want to delete, if our selection position
- // (indicated by startPoint) is the position directly
- // after the
, on the same line as the
.
- //
- // To detect this case we check:
- // startPoint's container == parentOfVisNode
- // and
- // startPoint's offset -1 == visibleNodeOffsetToVisNodeParent
- // and
- // interline position is false (left)
- //
- // In any other case we set the position to startPoint's container -1
- // and interlineposition to false, only moving the caret to the
- // end-of-hr-line position.
- bool moveOnly = true;
+ if (moveOnly) {
+ // Go to the position after the
, but to the end of the
line
+ // by setting the interline position to left.
+ EditorDOMPoint atNextOfHRElement(visibleNode);
+ DebugOnly advanced = atNextOfHRElement.AdvanceOffset();
+ NS_WARNING_ASSERTION(advanced,
+ "Failed to advance offset after
element");
- EditorRawDOMPoint atHRElement(visibleNode);
-
- ErrorResult err;
- bool interLineIsRight = SelectionRefPtr()->GetInterlinePosition(err);
- if (NS_WARN_IF(err.Failed())) {
- return EditActionResult(err.StealNSResult());
- }
-
- if (startPoint.GetContainer() == atHRElement.GetContainer() &&
- startPoint.Offset() - 1 == atHRElement.Offset() &&
- !interLineIsRight) {
- moveOnly = false;
- }
-
- if (moveOnly) {
- // Go to the position after the
, but to the end of the
line
- // by setting the interline position to left.
- EditorDOMPoint atNextOfHRElement(visibleNode);
- DebugOnly advanced = atNextOfHRElement.AdvanceOffset();
- NS_WARNING_ASSERTION(advanced,
- "Failed to advance offset after
element");
-
- {
- AutoEditorDOMPointChildInvalidator lockOffset(atNextOfHRElement);
-
- IgnoredErrorResult ignoredError;
- SelectionRefPtr()->Collapse(atNextOfHRElement, ignoredError);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
- }
- NS_WARNING_ASSERTION(
- !ignoredError.Failed(),
- "Failed to collapse selection at after the
");
- }
+ {
+ AutoEditorDOMPointChildInvalidator lockOffset(atNextOfHRElement);
IgnoredErrorResult ignoredError;
- SelectionRefPtr()->SetInterlinePosition(false, ignoredError);
- NS_WARNING_ASSERTION(!ignoredError.Failed(),
- "Failed to unset interline position");
- HTMLEditorRef()
- .TopLevelEditSubActionDataRef()
- .mDidExplicitlySetInterLine = true;
-
- // There is one exception to the move only case. If the
is
- // followed by a
we want to delete the
.
-
- WSType otherWSType;
- nsCOMPtr otherNode;
-
- wsObj.NextVisibleNode(startPoint, address_of(otherNode), nullptr,
- &otherWSType);
-
- if (otherWSType != WSType::br) {
- return EditActionHandled();
- }
-
- // Delete the
- if (NS_WARN_IF(!otherNode->IsContent())) {
- return EditActionHandled(NS_ERROR_FAILURE);
- }
- nsIContent* otherContent = otherNode->AsContent();
- nsresult rv = WSRunObject::PrepareToDeleteNode(
- MOZ_KnownLive(&HTMLEditorRef()), MOZ_KnownLive(otherContent));
+ SelectionRefPtr()->Collapse(atNextOfHRElement, ignoredError);
if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
}
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionHandled(rv);
- }
- rv = MOZ_KnownLive(HTMLEditorRef())
- .DeleteNodeWithTransaction(MOZ_KnownLive(*otherContent));
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
- }
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
- "DeleteNodeWithTransaction() failed");
- return EditActionHandled(rv);
+ NS_WARNING_ASSERTION(
+ !ignoredError.Failed(),
+ "Failed to collapse selection at after the
");
}
- // Else continue with normal delete code
- }
- if (NS_WARN_IF(!visibleNode->IsContent())) {
- return EditActionResult(NS_ERROR_FAILURE);
- }
- // Found break or image, or hr.
- nsresult rv = WSRunObject::PrepareToDeleteNode(
- MOZ_KnownLive(&HTMLEditorRef()),
- MOZ_KnownLive(visibleNode->AsContent()));
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionResult(rv);
- }
- // Remember sibling to visnode, if any
- nsCOMPtr previousEditableSibling =
- HTMLEditorRef().GetPriorHTMLSibling(visibleNode);
- // Delete the node, and join like nodes if appropriate
- rv = MOZ_KnownLive(HTMLEditorRef())
- .DeleteNodeWithTransaction(*visibleNode);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionResult(rv);
- }
- // Is there a prior node and are they siblings?
- nsCOMPtr nextEditableSibling;
- if (previousEditableSibling) {
- nextEditableSibling =
- HTMLEditorRef().GetNextHTMLSibling(previousEditableSibling);
- }
- // Are they both text nodes? If so, join them!
- if (startPoint.GetContainer() == nextEditableSibling &&
- startPoint.GetContainerAsText() &&
- previousEditableSibling->GetAsText()) {
- EditorDOMPoint atFirstChildOfRightNode;
- nsresult rv =
- MOZ_KnownLive(HTMLEditorRef())
- .JoinNearestEditableNodesWithTransaction(
- *previousEditableSibling,
- MOZ_KnownLive(*startPoint.GetContainerAsContent()),
- &atFirstChildOfRightNode);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionHandled(rv);
- }
- if (NS_WARN_IF(!atFirstChildOfRightNode.IsSet())) {
- return EditActionHandled(NS_ERROR_FAILURE);
- }
- // Fix up selection
- ErrorResult error;
- SelectionRefPtr()->Collapse(atFirstChildOfRightNode, error);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- error.SuppressException();
- return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
- }
- if (NS_WARN_IF(error.Failed())) {
- return EditActionHandled(error.StealNSResult());
- }
- }
- rv = MOZ_KnownLive(HTMLEditorRef())
- .InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
- EditorBase::GetStartPoint(*SelectionRefPtr()));
- NS_WARNING_ASSERTION(
- NS_SUCCEEDED(rv),
- "InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary() failed");
- return EditActionHandled(rv);
- }
+ IgnoredErrorResult ignoredError;
+ SelectionRefPtr()->SetInterlinePosition(false, ignoredError);
+ NS_WARNING_ASSERTION(!ignoredError.Failed(),
+ "Failed to unset interline position");
+ HTMLEditorRef()
+ .TopLevelEditSubActionDataRef()
+ .mDidExplicitlySetInterLine = true;
- if (wsType == WSType::otherBlock) {
- // Make sure it's not a table element. If so, cancel the operation
- // (translation: users cannot backspace or delete across table cells)
- if (HTMLEditUtils::IsTableElement(visibleNode)) {
- return EditActionCanceled();
- }
+ // There is one exception to the move only case. If the
is
+ // followed by a
we want to delete the
.
- // Next to a block. See if we are between a block and a br. If so, we
- // really want to delete the br. Else join content at selection to the
- // block.
- WSType otherWSType;
- nsCOMPtr otherNode;
+ WSType otherWSType;
+ nsCOMPtr otherNode;
- // Find node in other direction
- if (aDirectionAndAmount == nsIEditor::eNext) {
- wsObj.PriorVisibleNode(startPoint, address_of(otherNode), nullptr,
- &otherWSType);
- } else {
wsObj.NextVisibleNode(startPoint, address_of(otherNode), nullptr,
&otherWSType);
- }
- // First find the adjacent node in the block
- nsCOMPtr leafNode;
- nsCOMPtr leftNode, rightNode;
- if (aDirectionAndAmount == nsIEditor::ePrevious) {
- leafNode = HTMLEditorRef().GetLastEditableLeaf(*visibleNode);
- leftNode = leafNode;
- rightNode = startPoint.GetContainer();
- } else {
- leafNode = HTMLEditorRef().GetFirstEditableLeaf(*visibleNode);
- leftNode = startPoint.GetContainer();
- rightNode = leafNode;
- }
-
- bool didBRElementDeleted = false;
- if (otherNode->IsHTMLElement(nsGkAtoms::br)) {
- nsresult rv = MOZ_KnownLive(HTMLEditorRef())
- .DeleteNodeWithTransaction(*otherNode);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ if (otherWSType != WSType::br) {
+ return EditActionHandled();
}
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return EditActionResult(rv);
- }
- didBRElementDeleted = true;
- }
- // Don't cross table boundaries
- if (leftNode && rightNode &&
- HTMLEditor::NodesInDifferentTableElements(*leftNode, *rightNode)) {
- return didBRElementDeleted ? EditActionHandled() : EditActionIgnored();
- }
-
- if (didBRElementDeleted) {
- // Put selection at edge of block and we are done.
- if (NS_WARN_IF(!leafNode)) {
+ // Delete the
+ if (NS_WARN_IF(!otherNode->IsContent())) {
return EditActionHandled(NS_ERROR_FAILURE);
}
- EditorDOMPoint newSel = HTMLEditorRef().GetGoodCaretPointFor(
- *leafNode, aDirectionAndAmount);
- if (NS_WARN_IF(!newSel.IsSet())) {
- return EditActionHandled(NS_ERROR_FAILURE);
- }
- IgnoredErrorResult error;
- SelectionRefPtr()->Collapse(newSel, error);
+ nsIContent* otherContent = otherNode->AsContent();
+ nsresult rv = WSRunObject::PrepareToDeleteNode(
+ MOZ_KnownLive(&HTMLEditorRef()), MOZ_KnownLive(otherContent));
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
- NS_WARNING_ASSERTION(!error.Failed(),
- "Selection::Collapse() failed, but ignored");
- return EditActionHandled();
- }
-
- // Else we are joining content to block
- EditActionResult result(NS_OK);
- EditorDOMPoint pointToPutCaret(startPoint);
- {
- AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
- &pointToPutCaret);
- if (NS_WARN_IF(!leftNode) || NS_WARN_IF(!leftNode->IsContent()) ||
- NS_WARN_IF(!rightNode) || NS_WARN_IF(!rightNode->IsContent())) {
- return EditActionResult(NS_ERROR_FAILURE);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionHandled(rv);
}
- result |= MOZ_KnownLive(HTMLEditorRef())
- .TryToJoinBlocksWithTransaction(
- MOZ_KnownLive(*leftNode->AsContent()),
- MOZ_KnownLive(*rightNode->AsContent()));
- if (NS_WARN_IF(result.Failed())) {
- return result;
- }
- }
-
- // If TryToJoinBlocksWithTransaction() didn't handle it and it's not
- // canceled, user may want to modify the start leaf node or the last leaf
- // node of the block.
- if (!result.Handled() && !result.Canceled() &&
- leafNode != startPoint.GetContainer()) {
- int32_t offset = aDirectionAndAmount == nsIEditor::ePrevious
- ? static_cast(leafNode->Length())
- : 0;
- DebugOnly rv = SelectionRefPtr()->Collapse(leafNode, offset);
+ rv = MOZ_KnownLive(HTMLEditorRef())
+ .DeleteNodeWithTransaction(MOZ_KnownLive(*otherContent));
if (NS_WARN_IF(!CanHandleEditAction())) {
- return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
- "Selection::Collapse() failed, but ignored");
- EditActionResult result =
- WillDeleteSelection(aDirectionAndAmount, aStripWrappers);
- NS_WARNING_ASSERTION(result.Succeeded(),
- "Nested WillDeleteSelection() failed");
+ "DeleteNodeWithTransaction() failed");
+ return EditActionHandled(rv);
+ }
+ // Else continue with normal delete code
+ }
+
+ if (NS_WARN_IF(!visibleNode->IsContent())) {
+ return EditActionResult(NS_ERROR_FAILURE);
+ }
+ // Found break or image, or hr.
+ nsresult rv = WSRunObject::PrepareToDeleteNode(
+ MOZ_KnownLive(&HTMLEditorRef()),
+ MOZ_KnownLive(visibleNode->AsContent()));
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionResult(rv);
+ }
+ // Remember sibling to visnode, if any
+ nsCOMPtr previousEditableSibling =
+ HTMLEditorRef().GetPriorHTMLSibling(visibleNode);
+ // Delete the node, and join like nodes if appropriate
+ rv = MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*visibleNode);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionResult(rv);
+ }
+ // Is there a prior node and are they siblings?
+ nsCOMPtr nextEditableSibling;
+ if (previousEditableSibling) {
+ nextEditableSibling =
+ HTMLEditorRef().GetNextHTMLSibling(previousEditableSibling);
+ }
+ // Are they both text nodes? If so, join them!
+ if (startPoint.GetContainer() == nextEditableSibling &&
+ startPoint.GetContainerAsText() &&
+ previousEditableSibling->GetAsText()) {
+ EditorDOMPoint atFirstChildOfRightNode;
+ nsresult rv = MOZ_KnownLive(HTMLEditorRef())
+ .JoinNearestEditableNodesWithTransaction(
+ *previousEditableSibling,
+ MOZ_KnownLive(*startPoint.GetContainerAsContent()),
+ &atFirstChildOfRightNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionHandled(rv);
+ }
+ if (NS_WARN_IF(!atFirstChildOfRightNode.IsSet())) {
+ return EditActionHandled(NS_ERROR_FAILURE);
+ }
+ // Fix up selection
+ ErrorResult error;
+ SelectionRefPtr()->Collapse(atFirstChildOfRightNode, error);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ error.SuppressException();
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(error.Failed())) {
+ return EditActionHandled(error.StealNSResult());
+ }
+ }
+ rv = MOZ_KnownLive(HTMLEditorRef())
+ .InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
+ EditorBase::GetStartPoint(*SelectionRefPtr()));
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rv),
+ "InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary() failed");
+ return EditActionHandled(rv);
+ }
+
+ if (wsType == WSType::otherBlock) {
+ // Make sure it's not a table element. If so, cancel the operation
+ // (translation: users cannot backspace or delete across table cells)
+ if (HTMLEditUtils::IsTableElement(visibleNode)) {
+ return EditActionCanceled();
+ }
+
+ // Next to a block. See if we are between a block and a br. If so, we
+ // really want to delete the br. Else join content at selection to the
+ // block.
+ WSType otherWSType;
+ nsCOMPtr otherNode;
+
+ // Find node in other direction
+ if (aDirectionAndAmount == nsIEditor::eNext) {
+ wsObj.PriorVisibleNode(startPoint, address_of(otherNode), nullptr,
+ &otherWSType);
+ } else {
+ wsObj.NextVisibleNode(startPoint, address_of(otherNode), nullptr,
+ &otherWSType);
+ }
+
+ // First find the adjacent node in the block
+ nsCOMPtr leafNode;
+ nsCOMPtr leftNode, rightNode;
+ if (aDirectionAndAmount == nsIEditor::ePrevious) {
+ leafNode = HTMLEditorRef().GetLastEditableLeaf(*visibleNode);
+ leftNode = leafNode;
+ rightNode = startPoint.GetContainer();
+ } else {
+ leafNode = HTMLEditorRef().GetFirstEditableLeaf(*visibleNode);
+ leftNode = startPoint.GetContainer();
+ rightNode = leafNode;
+ }
+
+ bool didBRElementDeleted = false;
+ if (otherNode->IsHTMLElement(nsGkAtoms::br)) {
+ nsresult rv =
+ MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*otherNode);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditActionResult(rv);
+ }
+ didBRElementDeleted = true;
+ }
+
+ // Don't cross table boundaries
+ if (leftNode && rightNode &&
+ HTMLEditor::NodesInDifferentTableElements(*leftNode, *rightNode)) {
+ return didBRElementDeleted ? EditActionHandled() : EditActionIgnored();
+ }
+
+ if (didBRElementDeleted) {
+ // Put selection at edge of block and we are done.
+ if (NS_WARN_IF(!leafNode)) {
+ return EditActionHandled(NS_ERROR_FAILURE);
+ }
+ EditorDOMPoint newSel =
+ HTMLEditorRef().GetGoodCaretPointFor(*leafNode, aDirectionAndAmount);
+ if (NS_WARN_IF(!newSel.IsSet())) {
+ return EditActionHandled(NS_ERROR_FAILURE);
+ }
+ IgnoredErrorResult error;
+ SelectionRefPtr()->Collapse(newSel, error);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+ }
+ NS_WARNING_ASSERTION(!error.Failed(),
+ "Selection::Collapse() failed, but ignored");
+ return EditActionHandled();
+ }
+
+ // Else we are joining content to block
+ EditActionResult result(NS_OK);
+ EditorDOMPoint pointToPutCaret(startPoint);
+ {
+ AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
+ &pointToPutCaret);
+ if (NS_WARN_IF(!leftNode) || NS_WARN_IF(!leftNode->IsContent()) ||
+ NS_WARN_IF(!rightNode) || NS_WARN_IF(!rightNode->IsContent())) {
+ return EditActionResult(NS_ERROR_FAILURE);
+ }
+ result |= MOZ_KnownLive(HTMLEditorRef())
+ .TryToJoinBlocksWithTransaction(
+ MOZ_KnownLive(*leftNode->AsContent()),
+ MOZ_KnownLive(*rightNode->AsContent()));
+ if (NS_WARN_IF(result.Failed())) {
return result;
}
+ }
- // Otherwise, we must have deleted the selection as user expected.
- IgnoredErrorResult ignoredError;
- SelectionRefPtr()->Collapse(pointToPutCaret, ignoredError);
+ // If TryToJoinBlocksWithTransaction() didn't handle it and it's not
+ // canceled, user may want to modify the start leaf node or the last leaf
+ // node of the block.
+ if (!result.Handled() && !result.Canceled() &&
+ leafNode != startPoint.GetContainer()) {
+ int32_t offset = aDirectionAndAmount == nsIEditor::ePrevious
+ ? static_cast(leafNode->Length())
+ : 0;
+ DebugOnly rv = SelectionRefPtr()->Collapse(leafNode, offset);
if (NS_WARN_IF(!CanHandleEditAction())) {
return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
}
- NS_WARNING_ASSERTION(!ignoredError.Failed(),
- "Failed to selection at deleted point");
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "Selection::Collapse() failed, but ignored");
+ EditActionResult result =
+ WillDeleteSelection(aDirectionAndAmount, aStripWrappers);
+ NS_WARNING_ASSERTION(result.Succeeded(),
+ "Nested WillDeleteSelection() failed");
return result;
}
- if (wsType == WSType::thisBlock) {
- // At edge of our block. Look beside it and see if we can join to an
- // adjacent block
-
- // Make sure it's not a table element. If so, cancel the operation
- // (translation: users cannot backspace or delete across table cells)
- if (HTMLEditUtils::IsTableElement(visibleNode)) {
- return EditActionCanceled();
- }
-
- // First find the relevant nodes
- nsCOMPtr leftNode, rightNode;
- if (aDirectionAndAmount == nsIEditor::ePrevious) {
- leftNode = HTMLEditorRef().GetPreviousEditableHTMLNode(*visibleNode);
- rightNode = startPoint.GetContainer();
- } else {
- rightNode = HTMLEditorRef().GetNextEditableHTMLNode(*visibleNode);
- leftNode = startPoint.GetContainer();
- }
-
- // Nothing to join
- if (!leftNode || !rightNode) {
- return EditActionCanceled();
- }
-
- // Don't cross table boundaries -- cancel it
- if (HTMLEditor::NodesInDifferentTableElements(*leftNode, *rightNode)) {
- return EditActionCanceled();
- }
-
- EditActionResult result(NS_OK);
- EditorDOMPoint pointToPutCaret(startPoint);
- {
- AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
- &pointToPutCaret);
- if (NS_WARN_IF(!leftNode->IsContent()) ||
- NS_WARN_IF(!rightNode->IsContent())) {
- return EditActionResult(NS_ERROR_FAILURE);
- }
- result |= MOZ_KnownLive(HTMLEditorRef())
- .TryToJoinBlocksWithTransaction(
- MOZ_KnownLive(*leftNode->AsContent()),
- MOZ_KnownLive(*rightNode->AsContent()));
- // This should claim that trying to join the block means that
- // this handles the action because the caller shouldn't do anything
- // anymore in this case.
- result.MarkAsHandled();
- if (NS_WARN_IF(result.Failed())) {
- return result;
- }
- }
- IgnoredErrorResult ignoredError;
- SelectionRefPtr()->Collapse(pointToPutCaret, ignoredError);
- if (NS_WARN_IF(!CanHandleEditAction())) {
- return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
- }
- NS_WARNING_ASSERTION(!ignoredError.Failed(),
- "Failed to collapse selection");
- return result;
+ // Otherwise, we must have deleted the selection as user expected.
+ IgnoredErrorResult ignoredError;
+ SelectionRefPtr()->Collapse(pointToPutCaret, ignoredError);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
}
+ NS_WARNING_ASSERTION(!ignoredError.Failed(),
+ "Failed to selection at deleted point");
+ return result;
}
+ if (wsType == WSType::thisBlock) {
+ // At edge of our block. Look beside it and see if we can join to an
+ // adjacent block
+
+ // Make sure it's not a table element. If so, cancel the operation
+ // (translation: users cannot backspace or delete across table cells)
+ if (HTMLEditUtils::IsTableElement(visibleNode)) {
+ return EditActionCanceled();
+ }
+
+ // First find the relevant nodes
+ nsCOMPtr leftNode, rightNode;
+ if (aDirectionAndAmount == nsIEditor::ePrevious) {
+ leftNode = HTMLEditorRef().GetPreviousEditableHTMLNode(*visibleNode);
+ rightNode = startPoint.GetContainer();
+ } else {
+ rightNode = HTMLEditorRef().GetNextEditableHTMLNode(*visibleNode);
+ leftNode = startPoint.GetContainer();
+ }
+
+ // Nothing to join
+ if (!leftNode || !rightNode) {
+ return EditActionCanceled();
+ }
+
+ // Don't cross table boundaries -- cancel it
+ if (HTMLEditor::NodesInDifferentTableElements(*leftNode, *rightNode)) {
+ return EditActionCanceled();
+ }
+
+ EditActionResult result(NS_OK);
+ EditorDOMPoint pointToPutCaret(startPoint);
+ {
+ AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
+ &pointToPutCaret);
+ if (NS_WARN_IF(!leftNode->IsContent()) ||
+ NS_WARN_IF(!rightNode->IsContent())) {
+ return EditActionResult(NS_ERROR_FAILURE);
+ }
+ result |= MOZ_KnownLive(HTMLEditorRef())
+ .TryToJoinBlocksWithTransaction(
+ MOZ_KnownLive(*leftNode->AsContent()),
+ MOZ_KnownLive(*rightNode->AsContent()));
+ // This should claim that trying to join the block means that
+ // this handles the action because the caller shouldn't do anything
+ // anymore in this case.
+ result.MarkAsHandled();
+ if (NS_WARN_IF(result.Failed())) {
+ return result;
+ }
+ }
+ IgnoredErrorResult ignoredError;
+ SelectionRefPtr()->Collapse(pointToPutCaret, ignoredError);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ NS_WARNING_ASSERTION(!ignoredError.Failed(),
+ "Failed to collapse selection");
+ return result;
+ }
+
+ MOZ_ASSERT_UNREACHABLE("New WSType value hasn't been handled yet");
+ return EditActionIgnored();
+}
+
+EditActionResult HTMLEditRules::HandleDeleteNonCollapsedSelection(
+ nsIEditor::EDirection aDirectionAndAmount,
+ nsIEditor::EStripWrappers aStripWrappers,
+ SelectionWasCollapsed aSelectionWasCollapsed) {
+ MOZ_ASSERT(IsEditorDataAvailable());
+ MOZ_ASSERT(HTMLEditorRef().IsTopLevelEditSubActionDataAvailable());
+ MOZ_ASSERT(!SelectionRefPtr()->IsCollapsed());
+
// Else we have a non-collapsed selection. First adjust the selection.
// XXX Why do we extend selection only when there is only one range?
if (SelectionRefPtr()->RangeCount() == 1) {
@@ -3141,7 +3172,7 @@ EditActionResult HTMLEditRules::WillDeleteSelection(
arrayOfNodes.RemoveElementAt(0);
// If something visible is deleted, no need to join. Visible means
// all nodes except non-visible textnodes and breaks.
- if (join && origCollapsed) {
+ if (join && aSelectionWasCollapsed == SelectionWasCollapsed::Yes) {
if (!node->IsContent()) {
join = false;
continue;
@@ -3278,7 +3309,7 @@ EditActionResult HTMLEditRules::WillDeleteSelection(
return result.SetResult(rv);
}
- rv = SelectionRefPtr()->Collapse(startNode, startOffset);
+ nsresult rv = SelectionRefPtr()->Collapse(startNode, startOffset);
if (NS_WARN_IF(!CanHandleEditAction())) {
return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
}
diff --git a/editor/libeditor/HTMLEditRules.h b/editor/libeditor/HTMLEditRules.h
index c73a05aa0e60..6dfb5f16b862 100644
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -129,6 +129,39 @@ class HTMLEditRules : public TextEditRules {
WillDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers);
+ /**
+ * HandleDeleteAroundCollapsedSelection() handles deletion with collapsed
+ * `Selection`. Callers must guarantee that this is called only when
+ * `Selection` is collapsed.
+ *
+ * @param aDirectionAndAmount Direction of the deletion.
+ * @param aStripWrappers Must be eStrip or eNoStrip.
+ */
+ MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
+ HandleDeleteAroundCollapsedSelection(
+ nsIEditor::EDirection aDirectionAndAmount,
+ nsIEditor::EStripWrappers aStripWrappers);
+
+ /**
+ * HandleDeleteNonCollapsedSelection() handles deletion with non-collapsed
+ * `Selection`. Callers must guarantee that this is called only when
+ * `Selection` is NOT collapsed.
+ *
+ * @param aDirectionAndAmount Direction of the deletion.
+ * @param aStripWrappers Must be eStrip or eNoStrip.
+ * @param aSelectionWasCollpased If the caller extended `Selection`
+ * from collapsed, set this to `Yes`.
+ * Otherwise, i.e., `Selection` is not
+ * collapsed from the beginning, set
+ * this to `No`.
+ */
+ enum class SelectionWasCollapsed { Yes, No };
+ MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
+ HandleDeleteNonCollapsedSelection(
+ nsIEditor::EDirection aDirectionAndAmount,
+ nsIEditor::EStripWrappers aStripWrappers,
+ SelectionWasCollapsed aSelectionWasCollapsed);
+
/**
* Called after deleting selected content.
* This method removes unnecessary empty nodes and/or inserts
if