Bug 1765018 - part 4: Make EditorBase::InsertTextWithTransaction treat only EditorDOMPoint r=m_kato

In theory, methods which touch the DOM tree should take `EditorDOMPoint` rather
than `EditorRawDOMPoint`.  And now, we can return meaningful value if it
succeeded, with `Result`.

Therefore, this patch makes it return `Result<EditorDOMPoint, nsresult>` instead
of taking an out argument, and take only `EditorDOMPoint` rather than taking any
type of `EditorDOMPointBase` since it's always converted to `EditorDOMPoint`.

Differential Revision: https://phabricator.services.mozilla.com/D143881
This commit is contained in:
Masayuki Nakano
2022-04-20 23:46:19 +00:00
parent 90a36f5bcc
commit c56be53f24
7 changed files with 153 additions and 183 deletions

View File

@@ -2779,33 +2779,28 @@ EditorDOMPointType EditorBase::FindBetterInsertionPoint(
return aPoint;
}
nsresult EditorBase::InsertTextWithTransaction(
Result<EditorDOMPoint, nsresult> EditorBase::InsertTextWithTransaction(
Document& aDocument, const nsAString& aStringToInsert,
const EditorRawDOMPoint& aPointToInsert,
EditorRawDOMPoint* aPointAfterInsertedString) {
const EditorDOMPoint& aPointToInsert) {
MOZ_ASSERT(
ShouldHandleIMEComposition() || !AllowsTransactionsToChangeSelection(),
"caller must have already used AutoTransactionsConserveSelection "
"if this is not for updating composition string");
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return NS_ERROR_INVALID_ARG;
return Err(NS_ERROR_INVALID_ARG);
}
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
if (!ShouldHandleIMEComposition() && aStringToInsert.IsEmpty()) {
if (aPointAfterInsertedString) {
*aPointAfterInsertedString = aPointToInsert;
}
return NS_OK;
return aPointToInsert;
}
// In some cases, the node may be the anonymous div element or a padding
// <br> element for empty last line. Let's try to look for better insertion
// point in the nearest text node if there is.
EditorDOMPoint pointToInsert =
FindBetterInsertionPoint(aPointToInsert.To<EditorDOMPoint>());
EditorDOMPoint pointToInsert = FindBetterInsertionPoint(aPointToInsert);
// If a neighboring text node already exists, use that
if (!pointToInsert.IsInTextNode()) {
@@ -2825,84 +2820,83 @@ nsresult EditorBase::InsertTextWithTransaction(
if (!pointToInsert.IsInTextNode()) {
// create a text node
RefPtr<nsTextNode> newNode = CreateTextNode(u""_ns);
if (NS_WARN_IF(!newNode)) {
return NS_ERROR_FAILURE;
if (MOZ_UNLIKELY(NS_WARN_IF(!newNode))) {
return Err(NS_ERROR_FAILURE);
}
// then we insert it into the dom tree
nsresult rv = InsertNodeWithTransaction(*newNode, pointToInsert);
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
return rv;
if (MOZ_UNLIKELY(NS_WARN_IF(Destroyed()))) {
return Err(NS_ERROR_EDITOR_DESTROYED);
}
pointToInsert.Set(newNode, 0);
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
return Err(rv);
}
pointToInsert.Set(newNode, 0u);
newOffset = aStringToInsert.Length();
} else {
newOffset = aStringToInsert.Length();
newOffset += pointToInsert.Offset();
if (NS_WARN_IF(!newOffset.isValid())) {
return NS_ERROR_FAILURE;
if (MOZ_UNLIKELY(NS_WARN_IF(!newOffset.isValid()))) {
return Err(NS_ERROR_FAILURE);
}
}
nsresult rv = InsertTextIntoTextNodeWithTransaction(
aStringToInsert, EditorDOMPointInText(pointToInsert.ContainerAsText(),
pointToInsert.Offset()));
if (NS_FAILED(rv)) {
aStringToInsert, pointToInsert.AsInText());
if (MOZ_UNLIKELY(Destroyed())) {
NS_WARNING(
"EditorBase::InsertTextIntoTextNodeWithTransaction() caused "
"destroying the editor");
return Err(NS_ERROR_EDITOR_DESTROYED);
}
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
NS_WARNING("EditorBase::InsertTextIntoTextNodeWithTransaction() failed");
return rv;
return Err(rv);
}
if (aPointAfterInsertedString) {
aPointAfterInsertedString->Set(pointToInsert.GetContainer(),
newOffset.value());
NS_WARNING_ASSERTION(
aPointAfterInsertedString->IsSetAndValid(),
"Failed to set aPointAfterInsertedString, but ignored");
}
return NS_OK;
return EditorDOMPoint(pointToInsert.GetContainer(), newOffset.value());
}
if (pointToInsert.IsInTextNode()) {
CheckedUint32 newOffset = aStringToInsert.Length();
newOffset += pointToInsert.Offset();
if (NS_WARN_IF(!newOffset.isValid())) {
return NS_ERROR_FAILURE;
if (MOZ_UNLIKELY(NS_WARN_IF(!newOffset.isValid()))) {
return Err(NS_ERROR_FAILURE);
}
// we are inserting text into an existing text node.
nsresult rv = InsertTextIntoTextNodeWithTransaction(
aStringToInsert, EditorDOMPointInText(pointToInsert.ContainerAsText(),
pointToInsert.Offset()));
if (NS_FAILED(rv)) {
if (MOZ_UNLIKELY(Destroyed())) {
NS_WARNING(
"EditorBase::InsertTextIntoTextNodeWithTransaction() caused "
"destroying the editor");
return Err(NS_ERROR_EDITOR_DESTROYED);
}
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
NS_WARNING("EditorBase::InsertTextIntoTextNodeWithTransaction() failed");
return rv;
return Err(rv);
}
if (aPointAfterInsertedString) {
aPointAfterInsertedString->Set(pointToInsert.GetContainer(),
newOffset.value());
NS_WARNING_ASSERTION(
aPointAfterInsertedString->IsSetAndValid(),
"Failed to set aPointAfterInsertedString, but ignored");
}
return NS_OK;
return EditorDOMPoint(pointToInsert.GetContainer(), newOffset.value());
}
// we are inserting text into a non-text node. first we have to create a
// textnode (this also populates it with the text)
RefPtr<nsTextNode> newNode = CreateTextNode(aStringToInsert);
if (NS_WARN_IF(!newNode)) {
return NS_ERROR_FAILURE;
if (MOZ_UNLIKELY(NS_WARN_IF(!newNode))) {
return Err(NS_ERROR_FAILURE);
}
// then we insert it into the dom tree
nsresult rv = InsertNodeWithTransaction(*newNode, pointToInsert);
if (NS_FAILED(rv)) {
if (MOZ_UNLIKELY(Destroyed())) {
NS_WARNING(
"EditorBase::InsertNodeWithTransaction() caused destroying the editor");
return Err(NS_ERROR_EDITOR_DESTROYED);
}
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
return rv;
return Err(rv);
}
if (aPointAfterInsertedString) {
aPointAfterInsertedString->Set(newNode, aStringToInsert.Length());
NS_WARNING_ASSERTION(
aPointAfterInsertedString->IsSetAndValid(),
"Failed to set aPointAfterInsertedString, but ignored");
}
return NS_OK;
return EditorDOMPoint(newNode, aStringToInsert.Length());
}
static bool TextFragmentBeginsWithStringAtOffset(

View File

@@ -1642,21 +1642,17 @@ class EditorBase : public nsIEditor,
*
* @param aDocument The document of this editor.
* @param aStringToInsert The string to insert.
* @param aPointToInser The point to insert aStringToInsert.
* @param aPointToInsert The point to insert aStringToInsert.
* Must be valid DOM point.
* @param aPointAfterInsertedString
* The point after inserted aStringToInsert.
* So, when this method actually inserts string,
* this is set to a point in the text node.
* Otherwise, this may be set to aPointToInsert.
* @return When this succeeds to insert the string or
* does nothing during composition, returns NS_OK.
* Otherwise, an error code.
* @return If succeeded, returns the point after inserted
* aStringToInsert. So, when this method actually
* inserts string, returns a point in the text node.
* Otherwise, returns aPointToInsert.
*/
MOZ_CAN_RUN_SCRIPT virtual nsresult InsertTextWithTransaction(
Document& aDocument, const nsAString& aStringToInsert,
const EditorRawDOMPoint& aPointToInsert,
EditorRawDOMPoint* aPointAfterInsertedString = nullptr);
[[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual Result<EditorDOMPoint, nsresult>
InsertTextWithTransaction(Document& aDocument,
const nsAString& aStringToInsert,
const EditorDOMPoint& aPointToInsert);
/**
* InsertTextIntoTextNodeWithTransaction() inserts aStringToInsert into

View File

@@ -1132,26 +1132,26 @@ EditActionResult HTMLEditor::HandleInsertText(
if (aEditSubAction == EditSubAction::eInsertTextComingFromIME) {
auto compositionStartPoint =
GetFirstIMESelectionStartPoint<EditorRawDOMPoint>();
GetFirstIMESelectionStartPoint<EditorDOMPoint>();
if (!compositionStartPoint.IsSet()) {
compositionStartPoint = pointToInsert.To<EditorRawDOMPoint>();
compositionStartPoint = pointToInsert;
}
if (aInsertionString.IsEmpty()) {
// Right now the WhiteSpaceVisibilityKeeper code bails on empty strings,
// but IME needs the InsertTextWithTransaction() call to still happen
// since empty strings are meaningful there.
nsresult rv = InsertTextWithTransaction(*document, aInsertionString,
compositionStartPoint);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, aInsertionString,
compositionStartPoint);
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("HTMLEditor::InsertTextWithTransaction() failed");
return EditActionResult(insertTextResult.unwrapErr());
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::InsertTextWithTransaction() failed");
return EditActionHandled(rv);
return EditActionHandled();
}
auto compositionEndPoint = GetLastIMESelectionEndPoint<EditorRawDOMPoint>();
auto compositionEndPoint = GetLastIMESelectionEndPoint<EditorDOMPoint>();
if (!compositionEndPoint.IsSet()) {
compositionEndPoint = compositionStartPoint;
}
@@ -1163,8 +1163,8 @@ EditActionResult HTMLEditor::HandleInsertText(
return EditActionHandled(rv);
}
compositionStartPoint = GetFirstIMESelectionStartPoint<EditorRawDOMPoint>();
compositionEndPoint = GetLastIMESelectionEndPoint<EditorRawDOMPoint>();
compositionStartPoint = GetFirstIMESelectionStartPoint<EditorDOMPoint>();
compositionEndPoint = GetLastIMESelectionEndPoint<EditorDOMPoint>();
if (NS_WARN_IF(!compositionStartPoint.IsSet()) ||
NS_WARN_IF(!compositionEndPoint.IsSet())) {
// Mutation event listener has changed the DOM tree...
@@ -1256,19 +1256,14 @@ EditActionResult HTMLEditor::HandleInsertText(
"to different point "
"by mutation observer");
} else {
EditorRawDOMPoint pointAfterInsertedString;
nsresult rv = InsertTextWithTransaction(
*document, subStr, currentPoint.To<EditorRawDOMPoint>(),
&pointAfterInsertedString);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_FAILED(rv)) {
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, subStr, currentPoint);
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("HTMLEditor::InsertTextWithTransaction() failed");
return EditActionHandled(rv);
return EditActionHandled(insertTextResult.unwrapErr());
}
currentPoint = pointAfterInsertedString.To<EditorDOMPoint>();
pointToInsert = pointAfterInsertedString.To<EditorDOMPoint>();
currentPoint = insertTextResult.inspect();
pointToInsert = insertTextResult.unwrap();
}
}
} else {
@@ -2097,13 +2092,13 @@ nsresult HTMLEditor::HandleInsertLinefeed(const EditorDOMPoint& aPointToBreak,
{
AutoTrackDOMPoint trackingInsertingPosition(RangeUpdaterRef(),
&pointToInsert);
nsresult rv = InsertTextWithTransaction(
*document, u"\n"_ns, pointToInsert.To<EditorRawDOMPoint>(),
&caretAfterInsert);
if (NS_FAILED(rv)) {
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, u"\n"_ns, pointToInsert);
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("HTMLEditor::InsertTextWithTransaction() failed");
return rv;
return insertTextResult.unwrapErr();
}
caretAfterInsert = insertTextResult.unwrap().To<EditorRawDOMPoint>();
}
// Insert a padding <br> element at the end of the block element if there is

View File

@@ -3492,14 +3492,14 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
if (NS_WARN_IF(!document)) {
return NS_ERROR_NOT_INITIALIZED;
}
nsresult rv = InsertTextWithTransaction(
*document, aStringToInsert, EditorRawDOMPoint(&aTextNode, aOffset));
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, aStringToInsert,
EditorDOMPoint(&aTextNode, aOffset));
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("HTMLEditor::InsertTextWithTransaction() failed");
return insertTextResult.unwrapErr();
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::InsertTextWithTransaction() failed");
return rv;
return NS_OK;
}
if (NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(aTextNode))) {
@@ -3590,25 +3590,21 @@ nsresult HTMLEditor::ReplaceTextWithTransaction(
return NS_WARN_IF(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : rv;
}
nsresult HTMLEditor::InsertTextWithTransaction(
Result<EditorDOMPoint, nsresult> HTMLEditor::InsertTextWithTransaction(
Document& aDocument, const nsAString& aStringToInsert,
const EditorRawDOMPoint& aPointToInsert,
EditorRawDOMPoint* aPointAfterInsertedString) {
const EditorDOMPoint& aPointToInsert) {
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return NS_ERROR_INVALID_ARG;
return Err(NS_ERROR_INVALID_ARG);
}
// Do nothing if the node is read-only
if (NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(
*aPointToInsert.GetContainer()))) {
return NS_ERROR_FAILURE;
if (MOZ_UNLIKELY(NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(
*aPointToInsert.GetContainer())))) {
return Err(NS_ERROR_FAILURE);
}
nsresult rv = EditorBase::InsertTextWithTransaction(
aDocument, aStringToInsert, aPointToInsert, aPointAfterInsertedString);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::InsertTextWithTransaction() failed");
return rv;
return EditorBase::InsertTextWithTransaction(aDocument, aStringToInsert,
aPointToInsert);
}
Result<EditorDOMPoint, nsresult> HTMLEditor::PrepareToInsertBRElement(

View File

@@ -784,10 +784,10 @@ class HTMLEditor final : public EditorBase,
/**
* InsertTextWithTransaction() inserts aStringToInsert at aPointToInsert.
*/
MOZ_CAN_RUN_SCRIPT nsresult InsertTextWithTransaction(
Document& aDocument, const nsAString& aStringToInsert,
const EditorRawDOMPoint& aPointToInsert,
EditorRawDOMPoint* aPointAfterInsertedString = nullptr) final;
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
InsertTextWithTransaction(Document& aDocument,
const nsAString& aStringToInsert,
const EditorDOMPoint& aPointToInsert) final;
/**
* CopyLastEditableChildStyles() clones inline container elements into

View File

@@ -199,58 +199,50 @@ EditActionResult TextEditor::InsertLineFeedCharacterAtSelection() {
}
}
// get the (collapsed) selection location
const nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return EditActionIgnored(NS_ERROR_FAILURE);
}
EditorRawDOMPoint pointToInsert(firstRange->StartRef());
if (NS_WARN_IF(!pointToInsert.IsSet())) {
return EditActionIgnored(NS_ERROR_FAILURE);
const auto pointToInsert = GetFirstSelectionStartPoint<EditorDOMPoint>();
if (MOZ_UNLIKELY(NS_WARN_IF(!pointToInsert.IsSet()))) {
return EditActionResult(NS_ERROR_FAILURE);
}
MOZ_ASSERT(pointToInsert.IsSetAndValid());
MOZ_ASSERT(!pointToInsert.IsContainerHTMLElement(nsGkAtoms::br));
RefPtr<Document> document = GetDocument();
if (NS_WARN_IF(!document)) {
return EditActionIgnored(NS_ERROR_NOT_INITIALIZED);
if (MOZ_UNLIKELY(NS_WARN_IF(!document))) {
return EditActionResult(NS_ERROR_NOT_INITIALIZED);
}
// Don't change my selection in sub-transactions.
AutoTransactionsConserveSelection dontChangeMySelection(*this);
// Insert a linefeed character.
EditorRawDOMPoint pointAfterInsertedLineFeed;
nsresult rv = InsertTextWithTransaction(*document, u"\n"_ns, pointToInsert,
&pointAfterInsertedLineFeed);
if (!pointAfterInsertedLineFeed.IsSet()) {
NS_WARNING(
"EditorBase::InsertTextWithTransaction(\\n) didn't return position of "
"inserted linefeed");
return EditActionIgnored(NS_ERROR_FAILURE);
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, u"\n"_ns, pointToInsert);
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("TextEditor::InsertTextWithTransaction(\"\\n\") failed");
return EditActionResult(insertTextResult.unwrapErr());
}
if (NS_FAILED(rv)) {
NS_WARNING("TextEditor::InsertTextWithTransaction(\\n) failed");
return EditActionIgnored(rv);
if (MOZ_UNLIKELY(!insertTextResult.inspect().IsSet())) {
NS_WARNING(
"EditorBase::InsertTextWithTransaction(\"\\n\") didn't return position "
"of inserted linefeed");
return EditActionHandled(NS_ERROR_FAILURE);
}
// set the selection to the correct location
MOZ_ASSERT(
!pointAfterInsertedLineFeed.GetChild(),
"After inserting text into a text node, pointAfterInsertedLineFeed."
"GetChild() should be nullptr");
rv = CollapseSelectionTo(pointAfterInsertedLineFeed);
MOZ_ASSERT(insertTextResult.inspect().IsInTextNode(),
"After inserting text into a text node, insertTextResult should "
"return a point in a text node");
nsresult rv = CollapseSelectionTo(insertTextResult.inspect());
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
return EditActionIgnored(rv);
return EditActionHandled(rv);
}
// XXX I don't think we still need this. This must have been required when
// `<textarea>` was implemented with text nodes and `<br>` elements.
// see if we're at the end of the editor range
const auto endPoint = GetFirstSelectionEndPoint<EditorRawDOMPoint>();
if (endPoint == pointAfterInsertedLineFeed) {
if (endPoint == insertTextResult.inspect()) {
// SetInterlinePosition(true) means we want the caret to stick to the
// content on the "right". We want the caret to stick to whatever is
// past the break. This is because the break is on the same line we
@@ -454,13 +446,8 @@ EditActionResult TextEditor::HandleInsertText(
HandleNewLinesInStringForSingleLineEditor(insertionString);
}
// get the (collapsed) selection location
const nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return EditActionHandled(NS_ERROR_FAILURE);
}
EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
if (NS_WARN_IF(!atStartOfSelection.IsSetAndValid())) {
const auto atStartOfSelection = GetFirstSelectionStartPoint<EditorDOMPoint>();
if (MOZ_UNLIKELY(NS_WARN_IF(!atStartOfSelection.IsSetAndValid()))) {
return EditActionHandled(NS_ERROR_FAILURE);
}
MOZ_ASSERT(!atStartOfSelection.IsContainerHTMLElement(nsGkAtoms::br));
@@ -471,22 +458,20 @@ EditActionResult TextEditor::HandleInsertText(
}
if (aEditSubAction == EditSubAction::eInsertTextComingFromIME) {
EditorRawDOMPoint compositionStartPoint =
GetFirstIMESelectionStartPoint<EditorRawDOMPoint>();
EditorDOMPoint compositionStartPoint =
GetFirstIMESelectionStartPoint<EditorDOMPoint>();
if (!compositionStartPoint.IsSet()) {
compositionStartPoint = FindBetterInsertionPoint(atStartOfSelection);
NS_WARNING_ASSERTION(
compositionStartPoint.IsSet(),
"EditorBase::FindBetterInsertionPoint() failed, but ignored");
}
nsresult rv = InsertTextWithTransaction(*document, insertionString,
compositionStartPoint);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_FAILED(rv)) {
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, insertionString,
compositionStartPoint);
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("EditorBase::InsertTextWithTransaction() failed");
return EditActionHandled(rv);
return EditActionResult(insertTextResult.unwrapErr());
}
} else {
MOZ_ASSERT(aEditSubAction == EditSubAction::eInsertText);
@@ -494,32 +479,30 @@ EditActionResult TextEditor::HandleInsertText(
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(*this);
EditorRawDOMPoint pointAfterStringInserted;
nsresult rv = InsertTextWithTransaction(*document, insertionString,
atStartOfSelection,
&pointAfterStringInserted);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_FAILED(rv)) {
Result<EditorDOMPoint, nsresult> insertTextResult =
InsertTextWithTransaction(*document, insertionString,
atStartOfSelection);
if (MOZ_UNLIKELY(insertTextResult.isErr())) {
NS_WARNING("EditorBase::InsertTextWithTransaction() failed");
return EditActionHandled(rv);
return EditActionResult(insertTextResult.unwrapErr());
}
if (pointAfterStringInserted.IsSet()) {
if (insertTextResult.inspect().IsSet()) {
// Make the caret attach to the inserted text, unless this text ends with
// a LF, in which case make the caret attach to the next line.
const bool endsWithLF =
!insertionString.IsEmpty() && insertionString.Last() == nsCRT::LF;
pointAfterStringInserted.SetInterlinePosition(
EditorDOMPoint pointToPutCaret = insertTextResult.unwrap();
pointToPutCaret.SetInterlinePosition(
endsWithLF ? InterlinePosition::StartOfNextLine
: InterlinePosition::EndOfLine);
MOZ_ASSERT(
!pointAfterStringInserted.GetChild(),
"After inserting text into a text node, pointAfterStringInserted."
"GetChild() should be nullptr");
nsresult rv = CollapseSelectionTo(pointAfterStringInserted);
MOZ_ASSERT(pointToPutCaret.IsInTextNode(),
"After inserting text into a text node, insertTextResult "
"should return a point in a text node");
nsresult rv = CollapseSelectionTo(pointToPutCaret);
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
NS_WARNING(
"EditorBase::CollapseSelectionTo() caused destroying the editor");
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(

View File

@@ -1203,13 +1203,19 @@ nsresult WhiteSpaceVisibilityKeeper::ReplaceText(
return NS_ERROR_UNEXPECTED;
}
OwningNonNull<Document> document = *aHTMLEditor.GetDocument();
nsresult rv = aHTMLEditor.InsertTextWithTransaction(
document, theString, pointToInsert.To<EditorRawDOMPoint>(),
aPointAfterInsertedString);
if (NS_WARN_IF(aHTMLEditor.Destroyed())) {
Result<EditorDOMPoint, nsresult> insertTextResult =
aHTMLEditor.InsertTextWithTransaction(document, theString, pointToInsert);
if (MOZ_UNLIKELY(insertTextResult.isErr() && insertTextResult.inspectErr() ==
NS_ERROR_EDITOR_DESTROYED)) {
NS_WARNING(
"HTMLEditor::InsertTextWithTransaction() caused destroying the editor");
return NS_ERROR_EDITOR_DESTROYED;
}
if (NS_SUCCEEDED(rv)) {
if (insertTextResult.isOk()) {
if (aPointAfterInsertedString) {
*aPointAfterInsertedString =
insertTextResult.unwrap().To<EditorRawDOMPoint>();
}
return NS_OK;
}