mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1815383 - part 3: Make ReplaceTextTransaction::DoTransaction
stop updating Selection
directly r=m_kato
And also this changes `HTMLEditor::ReplaceTextWithTransaction` which is the only user of `ReplaceTextTransaction`. Depends on D169745 Differential Revision: https://phabricator.services.mozilla.com/D169746
This commit is contained in:
parent
7fe7780038
commit
6daaabe189
@ -269,11 +269,17 @@ class MOZ_STACK_CLASS InsertTextResult final : public CaretPoint {
|
||||
explicit InsertTextResult(EditorDOMPointInText&& aEndOfInsertedText)
|
||||
: CaretPoint(EditorDOMPoint()),
|
||||
mEndOfInsertedText(std::move(aEndOfInsertedText)) {}
|
||||
template <typename EditorDOMPointType>
|
||||
template <typename PT, typename CT>
|
||||
InsertTextResult(EditorDOMPointInText&& aEndOfInsertedText,
|
||||
const EditorDOMPointType& aCaretPoint)
|
||||
const EditorDOMPointBase<PT, CT>& aCaretPoint)
|
||||
: CaretPoint(aCaretPoint.template To<EditorDOMPoint>()),
|
||||
mEndOfInsertedText(std::move(aEndOfInsertedText)) {}
|
||||
InsertTextResult(EditorDOMPointInText&& aEndOfInsertedText,
|
||||
CaretPoint&& aCaretPoint)
|
||||
: CaretPoint(std::move(aCaretPoint)),
|
||||
mEndOfInsertedText(std::move(aEndOfInsertedText)) {
|
||||
UnmarkAsHandledCaretPoint();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Handled() const { return mEndOfInsertedText.IsSet(); }
|
||||
const EditorDOMPointInText& EndOfInsertedTextRef() const {
|
||||
|
@ -519,6 +519,13 @@ nsresult HTMLEditor::OnEndHandlingTopLevelEditSubActionInternal() {
|
||||
case EditSubAction::eInsertParagraphSeparator:
|
||||
case EditSubAction::ePasteHTMLContent:
|
||||
case EditSubAction::eInsertHTMLSource: {
|
||||
// Due to the replacement of white-spaces in
|
||||
// WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(),
|
||||
// selection ranges may be changed since DOM ranges track the DOM
|
||||
// mutation by themselves. However, we want to keep selection as-is.
|
||||
// Therefore, we should restore `Selection` after replacing
|
||||
// white-spaces.
|
||||
AutoSelectionRestorer restoreSelection(*this);
|
||||
// TODO: Temporarily, WhiteSpaceVisibilityKeeper replaces ASCII
|
||||
// white-spaces with NPSPs and then, we'll replace them with ASCII
|
||||
// white-spaces here. We should avoid this overwriting things as
|
||||
@ -2906,7 +2913,7 @@ void HTMLEditor::ExtendRangeToDeleteWithNormalizingWhiteSpaces(
|
||||
}
|
||||
}
|
||||
|
||||
Result<EditorDOMPoint, nsresult>
|
||||
Result<CaretPoint, nsresult>
|
||||
HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
const EditorDOMPointInText& aStartToDelete,
|
||||
const EditorDOMPointInText& aEndToDelete,
|
||||
@ -2932,7 +2939,7 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
// normalize white-space sequence, but there is no white-spaces which need to
|
||||
// be replaced, we need to do nothing here.
|
||||
if (startToDelete == endToDelete) {
|
||||
return aStartToDelete.To<EditorDOMPoint>();
|
||||
return CaretPoint(aStartToDelete.To<EditorDOMPoint>());
|
||||
}
|
||||
|
||||
// Note that the container text node of startToDelete may be removed from
|
||||
@ -2964,14 +2971,17 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
? trackingEndToDelete.Offset() - startToDelete.Offset()
|
||||
: startToDelete.ContainerAs<Text>()->TextLength() -
|
||||
startToDelete.Offset();
|
||||
nsresult rv = ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*startToDelete.ContainerAs<Text>()),
|
||||
startToDelete.Offset(), lengthToReplaceInFirstTextNode,
|
||||
normalizedWhiteSpacesInFirstNode);
|
||||
if (NS_FAILED(rv)) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*startToDelete.ContainerAs<Text>()),
|
||||
startToDelete.Offset(), lengthToReplaceInFirstTextNode,
|
||||
normalizedWhiteSpacesInFirstNode);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return Err(rv);
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// We'll return computed caret point, newCaretPosition, below.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
if (startToDelete.ContainerAs<Text>() ==
|
||||
trackingEndToDelete.ContainerAs<Text>()) {
|
||||
MOZ_ASSERT(normalizedWhiteSpacesInLastNode.IsEmpty());
|
||||
@ -3038,22 +3048,23 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
MOZ_ASSERT(!normalizedWhiteSpacesInLastNode.IsEmpty());
|
||||
MOZ_ASSERT(startToDelete.ContainerAs<Text>() ==
|
||||
endToDelete.ContainerAs<Text>());
|
||||
nsresult rv = ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*startToDelete.ContainerAs<Text>()),
|
||||
startToDelete.Offset(), endToDelete.Offset() - startToDelete.Offset(),
|
||||
normalizedWhiteSpacesInLastNode);
|
||||
if (NS_FAILED(rv)) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*startToDelete.ContainerAs<Text>()),
|
||||
startToDelete.Offset(),
|
||||
endToDelete.Offset() - startToDelete.Offset(),
|
||||
normalizedWhiteSpacesInLastNode);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return Err(rv);
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// We'll return computed caret point, newCaretPosition, below.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newCaretPosition.IsSetAndValid() ||
|
||||
!newCaretPosition.GetContainer()->IsInComposedDoc()) {
|
||||
NS_WARNING(
|
||||
"HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces() got lost "
|
||||
"the modifying line");
|
||||
if (NS_WARN_IF(!newCaretPosition.IsSetAndValid()) ||
|
||||
NS_WARN_IF(!newCaretPosition.GetContainer()->IsInComposedDoc())) {
|
||||
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
|
||||
}
|
||||
|
||||
@ -3121,7 +3132,7 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
NS_WARNING("Inserting <br> element caused unexpected DOM tree");
|
||||
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
|
||||
}
|
||||
return newCaretPosition;
|
||||
return CaretPoint(std::move(newCaretPosition));
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
|
||||
|
@ -3830,7 +3830,7 @@ Result<CaretPoint, nsresult> HTMLEditor::DeleteTextWithTransaction(
|
||||
return caretPointOrError;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
Result<InsertTextResult, nsresult> HTMLEditor::ReplaceTextWithTransaction(
|
||||
Text& aTextNode, uint32_t aOffset, uint32_t aLength,
|
||||
const nsAString& aStringToInsert) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
@ -3843,48 +3843,25 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
NS_WARNING("HTMLEditor::DeleteTextWithTransaction() failed");
|
||||
return caretPointOrError.propagateErr();
|
||||
}
|
||||
nsresult rv = caretPointOrError.inspect().SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CaretPoint::SuggestCaretPointTo() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CaretPoint::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
return InsertTextResult(EditorDOMPointInText(&aTextNode, aOffset),
|
||||
caretPointOrError.unwrap());
|
||||
}
|
||||
|
||||
if (!aLength) {
|
||||
RefPtr<Document> document = GetDocument();
|
||||
if (NS_WARN_IF(!document)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
return Err(NS_ERROR_NOT_INITIALIZED);
|
||||
}
|
||||
Result<InsertTextResult, nsresult> insertTextResult =
|
||||
InsertTextWithTransaction(*document, aStringToInsert,
|
||||
EditorDOMPoint(&aTextNode, aOffset));
|
||||
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::InsertTextWithTransaction() failed");
|
||||
return insertTextResult.unwrapErr();
|
||||
}
|
||||
nsresult rv = insertTextResult.unwrap().SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CaretPoint::SuggestCaretPointTo() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CaretPoint::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
NS_WARNING_ASSERTION(insertTextResult.isOk(),
|
||||
"HTMLEditor::InsertTextWithTransaction() failed");
|
||||
return insertTextResult;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(aTextNode))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// This should emulates inserting text for better undo/redo behavior.
|
||||
@ -3892,7 +3869,7 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||
*this, EditSubAction::eInsertText, nsIEditor::eNext, ignoredError);
|
||||
if (NS_WARN_IF(ignoredError.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
return EditorBase::ToGenericNSResult(ignoredError.StealNSResult());
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
!ignoredError.Failed(),
|
||||
@ -3902,30 +3879,6 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
// the point may become invalid offset after that.
|
||||
EditorDOMPointInText pointToInsert(&aTextNode, aOffset);
|
||||
|
||||
// `ReplaceTextTransaction()` removes the replaced text first, then,
|
||||
// insert new text. Therefore, if selection is in the text node, the
|
||||
// range is moved to start of the range and deletion and never adjusted
|
||||
// for the inserting text since the change occurs after the range.
|
||||
// Therefore, we might need to save/restore selection here.
|
||||
Maybe<AutoSelectionRestorer> restoreSelection;
|
||||
if (!AllowsTransactionsToChangeSelection() && !ArePreservingSelection()) {
|
||||
const uint32_t rangeCount = SelectionRef().RangeCount();
|
||||
for (const uint32_t i : IntegerRange(rangeCount)) {
|
||||
MOZ_ASSERT(SelectionRef().RangeCount() == rangeCount);
|
||||
const nsRange* range = SelectionRef().GetRangeAt(i);
|
||||
if (MOZ_UNLIKELY(!range)) {
|
||||
continue;
|
||||
}
|
||||
if ((range->GetStartContainer() == &aTextNode &&
|
||||
range->StartOffset() >= aOffset) ||
|
||||
(range->GetEndContainer() == &aTextNode &&
|
||||
range->EndOffset() >= aOffset)) {
|
||||
restoreSelection.emplace(*this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<ReplaceTextTransaction> transaction = ReplaceTextTransaction::Create(
|
||||
*this, aStringToInsert, aTextNode, aOffset, aLength);
|
||||
MOZ_ASSERT(transaction);
|
||||
@ -3944,6 +3897,12 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::DoTransactionInternal() failed");
|
||||
|
||||
// Don't check whether we've been destroyed here because we need to notify
|
||||
// listeners and observers below even if we've already destroyed.
|
||||
|
||||
EditorDOMPointInText endOfInsertedText(&aTextNode,
|
||||
aOffset + aStringToInsert.Length());
|
||||
|
||||
if (pointToInsert.IsSet()) {
|
||||
auto [begin, end] = ComputeInsertedRange(pointToInsert, aStringToInsert);
|
||||
if (begin.IsSet() && end.IsSet()) {
|
||||
@ -3952,11 +3911,9 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
TopLevelEditSubActionDataRef().DidInsertText(
|
||||
*this, begin.To<EditorRawDOMPoint>(), end.To<EditorRawDOMPoint>());
|
||||
}
|
||||
}
|
||||
|
||||
// Now, restores selection for allowing the following listeners to modify
|
||||
// selection.
|
||||
restoreSelection.reset();
|
||||
// XXX Should we update endOfInsertedText here?
|
||||
}
|
||||
|
||||
if (!mActionListeners.IsEmpty()) {
|
||||
for (auto& listener : mActionListeners.Clone()) {
|
||||
@ -3968,7 +3925,13 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
|
||||
}
|
||||
}
|
||||
|
||||
return NS_WARN_IF(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : rv;
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
|
||||
return InsertTextResult(
|
||||
std::move(endOfInsertedText),
|
||||
transaction->SuggestPointToPutCaret<EditorDOMPoint>());
|
||||
}
|
||||
|
||||
Result<InsertTextResult, nsresult> HTMLEditor::InsertTextWithTransaction(
|
||||
|
@ -744,12 +744,16 @@ class HTMLEditor final : public EditorBase,
|
||||
uint32_t aLength);
|
||||
|
||||
/**
|
||||
* ReplaceTextWithTransaction() replaces text in the range with
|
||||
* aStringToInsert.
|
||||
* Replace text in the range with aStringToInsert. If there is a DOM range
|
||||
* exactly same as the replacing range, it'll be collapsed to
|
||||
* {aTextNode, aOffset} because of the order of deletion and insertion.
|
||||
* Therefore, the callers may need to handle `Selection` even when callers
|
||||
* do not want to update `Selection`.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReplaceTextWithTransaction(
|
||||
dom::Text& aTextNode, uint32_t aOffset, uint32_t aLength,
|
||||
const nsAString& aStringToInsert);
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<InsertTextResult, nsresult>
|
||||
ReplaceTextWithTransaction(dom::Text& aTextNode, uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const nsAString& aStringToInsert);
|
||||
|
||||
/**
|
||||
* Insert aStringToInsert to aPointToInsert. If the point is not editable,
|
||||
@ -2002,7 +2006,7 @@ class HTMLEditor final : public EditorBase,
|
||||
Forward,
|
||||
Backward,
|
||||
};
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
|
||||
DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
const EditorDOMPointInText& aStartToDelete,
|
||||
const EditorDOMPointInText& aEndToDelete,
|
||||
|
@ -2083,8 +2083,7 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteTextAroundCollapsedRanges(
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
Result<EditorDOMPoint, nsresult> result =
|
||||
Result<CaretPoint, nsresult> caretPointOrError =
|
||||
aHTMLEditor.DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
rangeToDelete.StartRef().AsInText(),
|
||||
rangeToDelete.EndRef().AsInText(),
|
||||
@ -2092,20 +2091,20 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteTextAroundCollapsedRanges(
|
||||
aDirectionAndAmount == nsIEditor::eNext ? DeleteDirection::Forward
|
||||
: DeleteDirection::Backward);
|
||||
aHTMLEditor.TopLevelEditSubActionDataRef().mDidNormalizeWhitespaces = true;
|
||||
if (MOZ_UNLIKELY(result.isErr())) {
|
||||
if (MOZ_UNLIKELY(caretPointOrError.isErr())) {
|
||||
NS_WARNING(
|
||||
"HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces() failed");
|
||||
return result.propagateErr();
|
||||
return caretPointOrError.propagateErr();
|
||||
}
|
||||
const EditorDOMPoint& newCaretPosition = result.inspect();
|
||||
MOZ_ASSERT(newCaretPosition.IsSetAndValid());
|
||||
|
||||
rv = aHTMLEditor.CollapseSelectionTo(newCaretPosition);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
rv = caretPointOrError.unwrap().SuggestCaretPointTo(
|
||||
aHTMLEditor,
|
||||
{SuggestCaret::OnlyIfHasSuggestion, SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CaretPoint::SuggestCaretPointTo() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
NS_WARNING_ASSERTION(rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CaretPoint::SuggestCaretPointTo() failed, but ignored");
|
||||
return EditActionResult::HandledResult();
|
||||
}
|
||||
|
||||
|
@ -63,22 +63,6 @@ NS_IMETHODIMP ReplaceTextTransaction::DoTransaction() {
|
||||
editorBase->RangeUpdaterRef().SelAdjReplaceText(textNode, mOffset,
|
||||
mStringToBeReplaced.Length(),
|
||||
mStringToInsert.Length());
|
||||
|
||||
if (!editorBase->AllowsTransactionsToChangeSelection()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX Should we stop setting selection when mutation event listener
|
||||
// modifies the text node?
|
||||
editorBase->CollapseSelectionTo(
|
||||
EditorRawDOMPoint(textNode, mOffset + mStringToInsert.Length()), error);
|
||||
if (MOZ_UNLIKELY(error.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_ASSERTION(!error.Failed(),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -187,8 +171,8 @@ NS_IMETHODIMP ReplaceTextTransaction::RedoTransaction() {
|
||||
|
||||
// XXX Should we stop setting selection when mutation event listener
|
||||
// modifies the text node?
|
||||
editorBase->CollapseSelectionTo(
|
||||
EditorRawDOMPoint(textNode, mOffset + mStringToInsert.Length()), error);
|
||||
editorBase->CollapseSelectionTo(SuggestPointToPutCaret<EditorRawDOMPoint>(),
|
||||
error);
|
||||
if (MOZ_UNLIKELY(error.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
|
@ -69,6 +69,14 @@ class ReplaceTextTransaction final : public EditTransactionBase {
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() final;
|
||||
|
||||
template <typename EditorDOMPointType>
|
||||
EditorDOMPointType SuggestPointToPutCaret() const {
|
||||
if (NS_WARN_IF(!mTextNode)) {
|
||||
return EditorDOMPointType();
|
||||
}
|
||||
return EditorDOMPointType(mTextNode, mOffset + mStringToInsert.Length());
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& aStream,
|
||||
const ReplaceTextTransaction& aTransaction);
|
||||
|
||||
|
@ -63,8 +63,6 @@ template EditorRawDOMPoint WSRunScanner::GetFirstVisiblePoint(
|
||||
|
||||
template nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
HTMLEditor& aHTMLEditor, const EditorDOMPoint& aScanStartPoint);
|
||||
template nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
HTMLEditor& aHTMLEditor, const EditorRawDOMPoint& aScanStartPoint);
|
||||
template nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
HTMLEditor& aHTMLEditor, const EditorDOMPointInText& aScanStartPoint);
|
||||
|
||||
@ -938,15 +936,18 @@ WhiteSpaceVisibilityKeeper::InsertBRElement(
|
||||
atNBSPReplacedWithASCIIWhiteSpace.IsCharNBSP()) {
|
||||
AutoTrackDOMPoint trackPointToInsert(aHTMLEditor.RangeUpdaterRef(),
|
||||
&pointToInsert);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
nsresult rv = aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
|
||||
if (NS_FAILED(rv)) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed failed");
|
||||
return Err(rv);
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// Ignore caret suggestion because there was
|
||||
// AutoTransactionsConserveSelection.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
// Don't refer the following variables anymore unless tracking the
|
||||
// change.
|
||||
atNBSPReplaceableWithSP.Clear();
|
||||
@ -1099,15 +1100,18 @@ Result<InsertTextResult, nsresult> WhiteSpaceVisibilityKeeper::ReplaceText(
|
||||
AutoTrackDOMRange trackInvisibleTrailingWhiteSpaceRange(
|
||||
aHTMLEditor.RangeUpdaterRef(),
|
||||
&invisibleTrailingWhiteSpaceRangeAtEnd);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
nsresult rv = aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return Err(rv);
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// Ignore caret suggestion because there was
|
||||
// AutoTransactionsConserveSelection.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1152,15 +1156,18 @@ Result<InsertTextResult, nsresult> WhiteSpaceVisibilityKeeper::ReplaceText(
|
||||
AutoTrackDOMRange trackInvisibleTrailingWhiteSpaceRange(
|
||||
aHTMLEditor.RangeUpdaterRef(),
|
||||
&invisibleTrailingWhiteSpaceRangeAtEnd);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
nsresult rv = aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed failed");
|
||||
return Err(rv);
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// Ignore caret suggestion because there was
|
||||
// AutoTransactionsConserveSelection.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
// Don't refer the following variables anymore unless tracking the
|
||||
// change.
|
||||
atNBSPReplaceableWithSP.Clear();
|
||||
@ -3038,26 +3045,30 @@ nsresult WhiteSpaceVisibilityKeeper::ReplaceTextAndRemoveEmptyTextNodes(
|
||||
MOZ_ASSERT(aRangeToReplace.EndRef().IsSetAndValid());
|
||||
MOZ_ASSERT(aRangeToReplace.StartRef().IsBefore(aRangeToReplace.EndRef()));
|
||||
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
nsresult rv = aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*aRangeToReplace.StartRef().ContainerAs<Text>()),
|
||||
aRangeToReplace.StartRef().Offset(),
|
||||
aRangeToReplace.InSameContainer()
|
||||
? aRangeToReplace.EndRef().Offset() -
|
||||
aRangeToReplace.StartRef().Offset()
|
||||
: aRangeToReplace.StartRef().ContainerAs<Text>()->TextLength() -
|
||||
aRangeToReplace.StartRef().Offset(),
|
||||
aReplaceString);
|
||||
if (NS_FAILED(rv)) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*aRangeToReplace.StartRef().ContainerAs<Text>()),
|
||||
aRangeToReplace.StartRef().Offset(),
|
||||
aRangeToReplace.InSameContainer()
|
||||
? aRangeToReplace.EndRef().Offset() -
|
||||
aRangeToReplace.StartRef().Offset()
|
||||
: aRangeToReplace.StartRef().ContainerAs<Text>()->TextLength() -
|
||||
aRangeToReplace.StartRef().Offset(),
|
||||
aReplaceString);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return rv;
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// Ignore caret suggestion because there was
|
||||
// AutoTransactionsConserveSelection.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
|
||||
if (aRangeToReplace.InSameContainer()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = aHTMLEditor.DeleteTextAndTextNodesWithTransaction(
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
nsresult rv = aHTMLEditor.DeleteTextAndTextNodesWithTransaction(
|
||||
EditorDOMPointInText::AtEndOf(
|
||||
*aRangeToReplace.StartRef().ContainerAs<Text>()),
|
||||
aRangeToReplace.EndRef(),
|
||||
@ -3114,7 +3125,7 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
atEndOfVisibleWhiteSpaces);
|
||||
if (!atPreviousCharOfEndOfVisibleWhiteSpaces.IsSet() ||
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.IsEndOfContainer() ||
|
||||
// If the NBSP is never replaced from an ASCII white-space, we cannod
|
||||
// If the NBSP is never replaced from an ASCII white-space, we cannot
|
||||
// replace it with an ASCII white-space.
|
||||
!atPreviousCharOfEndOfVisibleWhiteSpaces.IsCharCollapsibleNBSP()) {
|
||||
return NS_OK;
|
||||
@ -3201,27 +3212,17 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
if (MOZ_UNLIKELY(insertBRElementResult.isErr())) {
|
||||
NS_WARNING(
|
||||
"HTMLEditor::InsertBRElement(WithTransaction::Yes) failed");
|
||||
return insertBRElementResult.unwrapErr();
|
||||
return insertBRElementResult.propagateErr();
|
||||
}
|
||||
// XXX Is this intentional selection change?
|
||||
nsresult rv = insertBRElementResult.inspect().SuggestCaretPointTo(
|
||||
aHTMLEditor, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateElementResult::SuggestCaretPointTo() failed");
|
||||
return rv;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateElementResult::SuggestCaretPointTo() failed, but ignored");
|
||||
MOZ_ASSERT(insertBRElementResult.inspect().GetNewNode());
|
||||
// Ignore caret suggestion because the caller must want to restore
|
||||
// `Selection` due to the purpose of this method.
|
||||
insertBRElementResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces =
|
||||
textFragmentData.GetPreviousEditableCharPoint(
|
||||
atEndOfVisibleWhiteSpaces);
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(
|
||||
!atPreviousCharOfEndOfVisibleWhiteSpaces.IsSet()))) {
|
||||
if (NS_WARN_IF(!atPreviousCharOfEndOfVisibleWhiteSpaces.IsSet())) {
|
||||
return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
|
||||
}
|
||||
atPreviousCharOfPreviousCharOfEndOfVisibleWhiteSpaces =
|
||||
@ -3256,14 +3257,19 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
(followedByVisibleContent || followedByBRElement) &&
|
||||
!visibleWhiteSpaces.StartsFromPreformattedLineBreak()) {
|
||||
MOZ_ASSERT(!followedByPreformattedLineBreak);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
nsresult rv = aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(
|
||||
*atPreviousCharOfEndOfVisibleWhiteSpaces.ContainerAs<Text>()),
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.Offset(), 1, u" "_ns);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return rv;
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*atPreviousCharOfEndOfVisibleWhiteSpaces
|
||||
.ContainerAs<Text>()),
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.Offset(), 1, u" "_ns);
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// Ignore caret suggestion because the caller must want to restore
|
||||
// `Selection` due to the purpose of this method.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// If the text node is not preformatted, and the NBSP is followed by a <br>
|
||||
@ -3290,7 +3296,6 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
textFragmentData.GetFirstASCIIWhiteSpacePointCollapsedTo(
|
||||
atPreviousCharOfPreviousCharOfEndOfVisibleWhiteSpaces,
|
||||
nsIEditor::eNone);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
uint32_t numberOfASCIIWhiteSpacesInStartNode =
|
||||
atFirstASCIIWhiteSpace.ContainerAs<Text>() ==
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.ContainerAs<Text>()
|
||||
@ -3305,18 +3310,23 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.ContainerAs<Text>()
|
||||
? 1
|
||||
: 0);
|
||||
nsresult rv = aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*atFirstASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atFirstASCIIWhiteSpace.Offset(), replaceLengthInStartNode,
|
||||
textFragmentData.StartsFromPreformattedLineBreak() &&
|
||||
textFragmentData.EndsByPreformattedLineBreak()
|
||||
? u"\x00A0\x00A0"_ns
|
||||
: (textFragmentData.EndsByPreformattedLineBreak() ? u" \x00A0"_ns
|
||||
: u"\x00A0 "_ns));
|
||||
if (NS_FAILED(rv)) {
|
||||
Result<InsertTextResult, nsresult> replaceTextResult =
|
||||
aHTMLEditor.ReplaceTextWithTransaction(
|
||||
MOZ_KnownLive(*atFirstASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atFirstASCIIWhiteSpace.Offset(), replaceLengthInStartNode,
|
||||
textFragmentData.StartsFromPreformattedLineBreak() &&
|
||||
textFragmentData.EndsByPreformattedLineBreak()
|
||||
? u"\x00A0\x00A0"_ns
|
||||
: (textFragmentData.EndsByPreformattedLineBreak()
|
||||
? u" \x00A0"_ns
|
||||
: u"\x00A0 "_ns));
|
||||
if (MOZ_UNLIKELY(replaceTextResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
|
||||
return rv;
|
||||
return replaceTextResult.propagateErr();
|
||||
}
|
||||
// Ignore caret suggestion because the caller must want to restore
|
||||
// `Selection` due to the purpose of this method.
|
||||
replaceTextResult.unwrap().IgnoreCaretPointSuggestion();
|
||||
|
||||
if (atFirstASCIIWhiteSpace.GetContainer() ==
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.GetContainer()) {
|
||||
@ -3326,7 +3336,7 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
// We need to remove the following unnecessary ASCII white-spaces and
|
||||
// NBSP at atPreviousCharOfEndOfVisibleWhiteSpaces because we collapsed them
|
||||
// into the start node.
|
||||
rv = aHTMLEditor.DeleteTextAndTextNodesWithTransaction(
|
||||
nsresult rv = aHTMLEditor.DeleteTextAndTextNodesWithTransaction(
|
||||
EditorDOMPointInText::AtEndOf(
|
||||
*atFirstASCIIWhiteSpace.ContainerAs<Text>()),
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.NextPoint(),
|
||||
@ -3387,16 +3397,20 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
|
||||
atPreviousCharOfEndOfVisibleWhiteSpaces.NextPoint();
|
||||
}
|
||||
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(aHTMLEditor);
|
||||
Result<EditorDOMPoint, nsresult> result =
|
||||
Result<CaretPoint, nsresult> caretPointOrError =
|
||||
aHTMLEditor.DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
||||
startToDelete, endToDelete,
|
||||
HTMLEditor::TreatEmptyTextNodes::KeepIfContainerOfRangeBoundaries,
|
||||
HTMLEditor::DeleteDirection::Forward);
|
||||
NS_WARNING_ASSERTION(
|
||||
!result.isOk(),
|
||||
"HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces() failed");
|
||||
return result.isErr() ? result.unwrapErr() : NS_OK;
|
||||
if (MOZ_UNLIKELY(caretPointOrError.isErr())) {
|
||||
NS_WARNING(
|
||||
"HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpace() failed");
|
||||
return caretPointOrError.unwrapErr();
|
||||
}
|
||||
// Ignore caret suggestion because the caller must want to restore
|
||||
// `Selection` due to the purpose of this method.
|
||||
caretPointOrError.unwrap().IgnoreCaretPointSuggestion();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EditorDOMPointInText WSRunScanner::TextFragmentData::
|
||||
|
@ -1533,8 +1533,10 @@ class WhiteSpaceVisibilityKeeper final {
|
||||
const EditorDOMPoint& aCaretPoint);
|
||||
|
||||
/**
|
||||
* NormalizeVisibleWhiteSpacesAt() tries to normalize visible white-space
|
||||
* sequence around aPoint.
|
||||
* Try to normalize visible white-space sequence around aPoint.
|
||||
* This may collapse `Selection` after replaced text. Therefore, the callers
|
||||
* of this need to restore `Selection` by themselves (this does not do it for
|
||||
* performance reason of multiple calls).
|
||||
*/
|
||||
template <typename EditorDOMPointType>
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsresult
|
||||
|
Loading…
Reference in New Issue
Block a user