diff --git a/editor/libeditor/HTMLEditSubActionHandler.cpp b/editor/libeditor/HTMLEditSubActionHandler.cpp
index f9662665065f..150095519350 100644
--- a/editor/libeditor/HTMLEditSubActionHandler.cpp
+++ b/editor/libeditor/HTMLEditSubActionHandler.cpp
@@ -2678,8 +2678,7 @@ EditActionResult HTMLEditor::HandleDeleteAroundCollapsedRanges(
}
if (aScanFromCaretPointResult.ReachedSpecialContent() ||
- aScanFromCaretPointResult.ReachedBRElement() ||
- aScanFromCaretPointResult.ReachedHRElement()) {
+ aScanFromCaretPointResult.ReachedBRElement()) {
if (aScanFromCaretPointResult.GetContent() ==
aWSRunScannerAtCaret.GetEditingHost()) {
return EditActionHandled();
@@ -2694,6 +2693,21 @@ EditActionResult HTMLEditor::HandleDeleteAroundCollapsedRanges(
return result;
}
+ if (aScanFromCaretPointResult.ReachedHRElement()) {
+ if (aScanFromCaretPointResult.GetContent() ==
+ aWSRunScannerAtCaret.GetEditingHost()) {
+ return EditActionHandled();
+ }
+ EditActionResult result = HandleDeleteCollapsedSelectionAtHRElement(
+ aDirectionAndAmount, aStripWrappers,
+ MOZ_KnownLive(*aScanFromCaretPointResult.ElementPtr()),
+ aWSRunScannerAtCaret.ScanStartRef(), aWSRunScannerAtCaret);
+ NS_WARNING_ASSERTION(
+ result.Succeeded(),
+ "HTMLEditor::HandleDeleteCollapsedSelectionAtHRElement() failed");
+ return result;
+ }
+
if (aScanFromCaretPointResult.ReachedOtherBlockElement()) {
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
return EditActionResult(NS_ERROR_FAILURE);
@@ -2978,6 +2992,107 @@ EditActionResult HTMLEditor::HandleDeleteCollapsedSelectionAtVisibleChar(
return EditActionHandled();
}
+EditActionResult HTMLEditor::HandleDeleteCollapsedSelectionAtHRElement(
+ nsIEditor::EDirection aDirectionAndAmount,
+ nsIEditor::EStripWrappers aStripWrappers, Element& aHRElement,
+ const EditorDOMPoint& aCaretPoint,
+ const WSRunScanner& aWSRunScannerAtCaret) {
+ MOZ_ASSERT(IsEditActionDataAvailable());
+ MOZ_ASSERT(aHRElement.IsHTMLElement(nsGkAtoms::hr));
+ MOZ_ASSERT(&aHRElement != aWSRunScannerAtCaret.GetEditingHost());
+
+ if (aDirectionAndAmount != nsIEditor::ePrevious) {
+ EditActionResult result = HandleDeleteCollapsedSelectionAtAtomicContent(
+ aDirectionAndAmount, aStripWrappers, aHRElement, aCaretPoint,
+ aWSRunScannerAtCaret);
+ NS_WARNING_ASSERTION(
+ result.Succeeded(),
+ "HTMLEditor::HandleDeleteCollapsedSelectionAtAtomicContent() failed");
+ return result;
+ }
+
+ // 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 aCaretPoint) is the position directly
+ // after the , on the same line as the .
+ //
+ // To detect this case we check:
+ // aCaretPoint's container == parent of `` element
+ // and
+ // aCaretPoint's offset -1 == `` element offset
+ // and
+ // interline position is false (left)
+ //
+ // In any other case we set the position to aCaretPoint's container -1
+ // and interlineposition to false, only moving the caret to the
+ // end-of-hr-line position.
+ EditorRawDOMPoint atHRElement(&aHRElement);
+
+ ErrorResult error;
+ bool interLineIsRight = SelectionRefPtr()->GetInterlinePosition(error);
+ if (error.Failed()) {
+ NS_WARNING("Selection::GetInterlinePosition() failed");
+ return EditActionResult(error.StealNSResult());
+ }
+
+ if (aCaretPoint.GetContainer() == atHRElement.GetContainer() &&
+ aCaretPoint.Offset() - 1 == atHRElement.Offset() && !interLineIsRight) {
+ EditActionResult result = HandleDeleteCollapsedSelectionAtAtomicContent(
+ aDirectionAndAmount, aStripWrappers, aHRElement, aCaretPoint,
+ aWSRunScannerAtCaret);
+ NS_WARNING_ASSERTION(
+ result.Succeeded(),
+ "HTMLEditor::HandleDeleteCollapsedSelectionAtAtomicContent() failed");
+ return result;
+ }
+
+ // Go to the position after the , but to the end of the line
+ // by setting the interline position to left.
+ EditorDOMPoint atNextOfHRElement(EditorDOMPoint::After(aHRElement));
+ NS_WARNING_ASSERTION(atNextOfHRElement.IsSet(),
+ "Failed to set after element");
+
+ {
+ AutoEditorDOMPointChildInvalidator lockOffset(atNextOfHRElement);
+
+ nsresult rv = CollapseSelectionTo(atNextOfHRElement);
+ if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+ return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+ }
+ NS_WARNING_ASSERTION(
+ NS_SUCCEEDED(rv),
+ "HTMLEditor::CollapseSelectionTo() failed, but ignored");
+ }
+
+ IgnoredErrorResult ignoredError;
+ SelectionRefPtr()->SetInterlinePosition(false, ignoredError);
+ NS_WARNING_ASSERTION(
+ !ignoredError.Failed(),
+ "Selection::SetInterlinePosition(false) failed, but ignored");
+ TopLevelEditSubActionDataRef().mDidExplicitlySetInterLine = true;
+
+ // There is one exception to the move only case. If the is
+ // followed by a we want to delete the .
+
+ WSScanResult forwardScanFromCaretResult =
+ aWSRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(aCaretPoint);
+ if (!forwardScanFromCaretResult.ReachedBRElement()) {
+ return EditActionHandled();
+ }
+
+ // Delete the
+ nsresult rv =
+ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
+ *this, MOZ_KnownLive(*forwardScanFromCaretResult.BRElementPtr()),
+ aCaretPoint);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "WhiteSpaceVisibilityKeeper::"
+ "DeleteContentNodeAndJoinTextNodesAroundIt() failed");
+ return EditActionHandled(rv);
+}
+
EditActionResult HTMLEditor::HandleDeleteCollapsedSelectionAtAtomicContent(
nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers, nsIContent& aAtomicContent,
@@ -2988,92 +3103,6 @@ EditActionResult HTMLEditor::HandleDeleteCollapsedSelectionAtAtomicContent(
IsVisibleBRElement(&aAtomicContent));
MOZ_ASSERT(&aAtomicContent != aWSRunScannerAtCaret.GetEditingHost());
- // Special handling for backspace when positioned after
- if (aDirectionAndAmount == nsIEditor::ePrevious &&
- aAtomicContent.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 aCaretPoint) is the position directly
- // after the , on the same line as the .
- //
- // To detect this case we check:
- // aCaretPoint's container == parent of `` element
- // and
- // aCaretPoint's offset -1 == `` element offset
- // and
- // interline position is false (left)
- //
- // In any other case we set the position to aCaretPoint's container -1
- // and interlineposition to false, only moving the caret to the
- // end-of-hr-line position.
- bool moveOnly = true;
-
- EditorRawDOMPoint atHRElement(&aAtomicContent);
-
- ErrorResult error;
- bool interLineIsRight = SelectionRefPtr()->GetInterlinePosition(error);
- if (error.Failed()) {
- NS_WARNING("Selection::GetInterlinePosition() failed");
- return EditActionResult(error.StealNSResult());
- }
-
- if (aCaretPoint.GetContainer() == atHRElement.GetContainer() &&
- aCaretPoint.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(EditorDOMPoint::After(aAtomicContent));
- NS_WARNING_ASSERTION(atNextOfHRElement.IsSet(),
- "Failed to set after element");
-
- {
- AutoEditorDOMPointChildInvalidator lockOffset(atNextOfHRElement);
-
- nsresult rv = CollapseSelectionTo(atNextOfHRElement);
- if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
- return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
- }
- NS_WARNING_ASSERTION(
- NS_SUCCEEDED(rv),
- "HTMLEditor::CollapseSelectionTo() failed, but ignored");
- }
-
- IgnoredErrorResult ignoredError;
- SelectionRefPtr()->SetInterlinePosition(false, ignoredError);
- NS_WARNING_ASSERTION(
- !ignoredError.Failed(),
- "Selection::SetInterlinePosition(false) failed, but ignored");
- TopLevelEditSubActionDataRef().mDidExplicitlySetInterLine = true;
-
- // There is one exception to the move only case. If the is
- // followed by a we want to delete the .
-
- WSScanResult forwardScanFromCaretResult =
- aWSRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
- aCaretPoint);
- if (!forwardScanFromCaretResult.ReachedBRElement()) {
- return EditActionHandled();
- }
-
- // Delete the
- nsresult rv =
- WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
- *this, MOZ_KnownLive(*forwardScanFromCaretResult.BRElementPtr()),
- aCaretPoint);
- NS_WARNING_ASSERTION(
- NS_SUCCEEDED(rv),
- "WhiteSpaceVisibilityKeeper::"
- "DeleteContentNodeAndJoinTextNodesAroundIt() failed");
- return EditActionHandled(rv);
- }
- // Else continue with normal delete code
- }
-
nsresult rv =
WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
*this, aAtomicContent, aCaretPoint);
diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h
index f47481f03fd8..7e44a8697051 100644
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -2603,8 +2603,9 @@ class HTMLEditor final : public TextEditor,
* HandleDeleteCollapsedSelectionAtAtomicContent() handles deletion of
* atomic elements like ` `, ``, ``, ``, etc and
* data nodes except text node (e.g., comment node).
- * If aAtomicContent is a invisible ` ` element, this will call
- * `HandleDeleteSelectionInternal()` recursively after deleting it.
+ * Note that don't call this directly with `` element. Instead, call
+ * `HandleDeleteCollapsedSelectionAtHRElement()`.
+ * Note that don't call this for invisible ` ` element.
*
* @param aDirectionAndAmount Direction of the deletion.
* @param aStripWrappers Must be eStrip or eNoStrip.
@@ -2621,6 +2622,31 @@ class HTMLEditor final : public TextEditor,
const EditorDOMPoint& aCaretPoint,
const WSRunScanner& aWSRunScannerAtCaret);
+ /**
+ * HandleDeleteCollapsedSelectionAtHRElement() handles deletion around
+ * `` element. If aDirectionAndAmount is nsIEditor::ePrevious,
+ * aHTElement is removed only when caret is at next sibling of the ``
+ * element and inter line position is "left". Otherwise, caret is moved
+ * and does not remove the `` elemnent.
+ * XXX Perhaps, we can get rid of this special handling because the other
+ * browsers don't do this, and our `` element handling is really
+ * odd.
+ *
+ * @param aDirectionAndAmount Direction of the deletion.
+ * @param aStripWrappers Must be eStrip or eNoStrip.
+ * @param aHRElement The `` element to be removed.
+ * @param aCaretPoint The caret point (i.e., selection start or
+ * end).
+ * @param aWSRunScannerAtCaret WSRunScanner instance which was initialized
+ * with the caret point.
+ */
+ [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
+ HandleDeleteCollapsedSelectionAtHRElement(
+ nsIEditor::EDirection aDirectionAndAmount,
+ nsIEditor::EStripWrappers aStripWrappers, Element& aHRElement,
+ const EditorDOMPoint& aCaretPoint,
+ const WSRunScanner& aWSRunScannerAtCaret);
+
class MOZ_STACK_CLASS AutoEmptyBlockAncestorDeleter final {
public:
/**