Bug 1990586 - Make WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt track given caret point a=pascalc

It's used as the result in some cases.  However, it's not tracked in
some cases when touching the DOM.

This modifies the API of `AutoTrackDOMPoint` to flush the tracking point
but can keep tracking.  We should use the new API in every place later.

(This manually merges `WhiteSpaceVisibilityKeeper.cpp` because ESR140
still has the pref to take the legacy mode back and that blocks applying
the patch cleanly.)

Differential Revision: https://phabricator.services.mozilla.com/D270643
This commit is contained in:
Masayuki Nakano
2025-10-30 08:51:11 +00:00
committed by pchevrel@mozilla.com
parent 3c22b4c56f
commit 0c6404cf72
4 changed files with 48 additions and 9 deletions

View File

@@ -46,6 +46,7 @@ enum class EditorCommandParamType : uint16_t; // mozilla/EditorCommands.h
enum class EditSubAction : int32_t; // mozilla/EditAction.h
enum class ParagraphSeparator; // mozilla/HTMLEditor.h
enum class SpecifiedStyle : uint8_t; // mozilla/PendingStyles.h
enum class StopTracking : bool; // mozilla/SelectionState.h
enum class SuggestCaret; // EditorUtils.h
enum class WithTransaction; // HTMLEditHelpers.h

View File

@@ -284,6 +284,8 @@ class MOZ_STACK_CLASS RangeUpdater final {
bool mLocked;
};
enum class StopTracking : bool { No, Yes };
/**
* Helper class for using SelectionState. Stack based class for doing
* preservation of dom points across editor actions.
@@ -331,11 +333,13 @@ class MOZ_STACK_CLASS AutoTrackDOMPoint final {
~AutoTrackDOMPoint() { FlushAndStopTracking(); }
void FlushAndStopTracking() {
void Flush(StopTracking aStopTracking) {
if (!mIsTracking) {
return;
}
mIsTracking = false;
if (static_cast<bool>(aStopTracking)) {
mIsTracking = false;
}
if (mPoint.isSome()) {
mRangeUpdater.DropRangeItem(mRangeItem);
// Setting `mPoint` with invalid DOM point causes hitting `NS_ASSERTION()`
@@ -378,6 +382,8 @@ class MOZ_STACK_CLASS AutoTrackDOMPoint final {
}
}
void FlushAndStopTracking() { Flush(StopTracking::Yes); }
void StopTracking() { mIsTracking = false; }
private:

View File

@@ -3450,6 +3450,11 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
MOZ_ASSERT(
StaticPrefs::editor_white_space_normalization_blink_compatible());
Maybe<AutoTrackDOMPoint> trackPointToPutCaret;
if (aCaretPoint.IsSet()) {
trackPointToPutCaret.emplace(aHTMLEditor.RangeUpdaterRef(),
&pointToPutCaret);
}
// If we're removing a block, it may be surrounded by invisible
// white-spaces. We should remove them to avoid to make them accidentally
// visible.
@@ -3459,8 +3464,6 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
AutoTrackDOMPoint trackAtContent(aHTMLEditor.RangeUpdaterRef(),
&atContent);
{
AutoTrackDOMPoint trackPointToPutCaret(aHTMLEditor.RangeUpdaterRef(),
&pointToPutCaret);
nsresult rv =
WhiteSpaceVisibilityKeeper::EnsureNoInvisibleWhiteSpacesBefore(
aHTMLEditor, EditorDOMPoint(aContentToDelete.AsElement()));
@@ -3484,6 +3487,9 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
if (NS_WARN_IF(!aContentToDelete.IsInComposedDoc())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
if (trackPointToPutCaret.isSome()) {
trackPointToPutCaret->Flush(StopTracking::No);
}
}
if (pointToPutCaret.IsInContentNode()) {
// Additionally, we may put caret into the preceding block (this is the
@@ -3558,7 +3564,7 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
}
}
}
trackAtContent.FlushAndStopTracking();
trackAtContent.Flush(StopTracking::Yes);
if (NS_WARN_IF(!atContent.IsInContentNodeAndValidInComposedDoc())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
@@ -3584,7 +3590,7 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
"failed");
return afterLastVisibleThingOrError.propagateErr();
}
trackAtContent.FlushAndStopTracking();
trackAtContent.Flush(StopTracking::Yes);
if (NS_WARN_IF(!atContent.IsInContentNodeAndValidInComposedDoc())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
@@ -3604,7 +3610,7 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
"WhiteSpaceVisibilityKeeper::NormalizeWhiteSpacesBefore() failed");
return atFirstVisibleThingOrError.propagateErr();
}
trackAtContent.FlushAndStopTracking();
trackAtContent.Flush(StopTracking::Yes);
if (NS_WARN_IF(!atContent.IsInContentNodeAndValidInComposedDoc())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
@@ -3616,13 +3622,22 @@ WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
aContentToDelete, {WalkTreeOption::IgnoreNonEditableNode});
// Delete the node, and join like nodes if appropriate
{
AutoTrackDOMPoint trackPointToPutCaret(aHTMLEditor.RangeUpdaterRef(),
&pointToPutCaret);
Maybe<AutoTrackDOMPoint> trackPointToPutCaret;
if (pointToPutCaret.IsSet()) {
trackPointToPutCaret.emplace(aHTMLEditor.RangeUpdaterRef(),
&pointToPutCaret);
}
nsresult rv = aHTMLEditor.DeleteNodeWithTransaction(aContentToDelete);
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::DeleteNodeWithTransaction() failed");
return Err(rv);
}
if (trackPointToPutCaret.isSome()) {
trackPointToPutCaret->Flush(StopTracking::Yes);
if (NS_WARN_IF(!pointToPutCaret.IsInContentNode())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
}
}
// Are they both text nodes? If so, join them!