mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 16:25:38 +00:00
Bug 1655388 - part 5: Split the special handling for <hr>
element off from HTMLEditor::HandleDeleteCollapsedSelectionAtAtomicContent()
r=m_kato
Depends on D87032 Differential Revision: https://phabricator.services.mozilla.com/D87033
This commit is contained in:
parent
416bf2f5ad
commit
c9bee9126b
@ -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 <hr>.
|
||||
//
|
||||
// In other words, we only want to delete, if our selection position
|
||||
// (indicated by aCaretPoint) is the position directly
|
||||
// after the <hr>, on the same line as the <hr>.
|
||||
//
|
||||
// To detect this case we check:
|
||||
// aCaretPoint's container == parent of `<hr>` element
|
||||
// and
|
||||
// aCaretPoint's offset -1 == `<hr>` 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 <hr>, but to the end of the <hr> line
|
||||
// by setting the interline position to left.
|
||||
EditorDOMPoint atNextOfHRElement(EditorDOMPoint::After(aHRElement));
|
||||
NS_WARNING_ASSERTION(atNextOfHRElement.IsSet(),
|
||||
"Failed to set after <hr> 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 <hr> is
|
||||
// followed by a <br> we want to delete the <br>.
|
||||
|
||||
WSScanResult forwardScanFromCaretResult =
|
||||
aWSRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(aCaretPoint);
|
||||
if (!forwardScanFromCaretResult.ReachedBRElement()) {
|
||||
return EditActionHandled();
|
||||
}
|
||||
|
||||
// Delete the <br>
|
||||
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 <hr>
|
||||
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 <hr>.
|
||||
//
|
||||
// In other words, we only want to delete, if our selection position
|
||||
// (indicated by aCaretPoint) is the position directly
|
||||
// after the <hr>, on the same line as the <hr>.
|
||||
//
|
||||
// To detect this case we check:
|
||||
// aCaretPoint's container == parent of `<hr>` element
|
||||
// and
|
||||
// aCaretPoint's offset -1 == `<hr>` 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 <hr>, but to the end of the <hr> line
|
||||
// by setting the interline position to left.
|
||||
EditorDOMPoint atNextOfHRElement(EditorDOMPoint::After(aAtomicContent));
|
||||
NS_WARNING_ASSERTION(atNextOfHRElement.IsSet(),
|
||||
"Failed to set after <hr> 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 <hr> is
|
||||
// followed by a <br> we want to delete the <br>.
|
||||
|
||||
WSScanResult forwardScanFromCaretResult =
|
||||
aWSRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
aCaretPoint);
|
||||
if (!forwardScanFromCaretResult.ReachedBRElement()) {
|
||||
return EditActionHandled();
|
||||
}
|
||||
|
||||
// Delete the <br>
|
||||
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);
|
||||
|
@ -2603,8 +2603,9 @@ class HTMLEditor final : public TextEditor,
|
||||
* HandleDeleteCollapsedSelectionAtAtomicContent() handles deletion of
|
||||
* atomic elements like `<br>`, `<hr>`, `<img>`, `<input>`, etc and
|
||||
* data nodes except text node (e.g., comment node).
|
||||
* If aAtomicContent is a invisible `<br>` element, this will call
|
||||
* `HandleDeleteSelectionInternal()` recursively after deleting it.
|
||||
* Note that don't call this directly with `<hr>` element. Instead, call
|
||||
* `HandleDeleteCollapsedSelectionAtHRElement()`.
|
||||
* Note that don't call this for invisible `<br>` 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
|
||||
* `<hr>` element. If aDirectionAndAmount is nsIEditor::ePrevious,
|
||||
* aHTElement is removed only when caret is at next sibling of the `<hr>`
|
||||
* element and inter line position is "left". Otherwise, caret is moved
|
||||
* and does not remove the `<hr>` elemnent.
|
||||
* XXX Perhaps, we can get rid of this special handling because the other
|
||||
* browsers don't do this, and our `<hr>` element handling is really
|
||||
* odd.
|
||||
*
|
||||
* @param aDirectionAndAmount Direction of the deletion.
|
||||
* @param aStripWrappers Must be eStrip or eNoStrip.
|
||||
* @param aHRElement The `<hr>` 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:
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user