NS_IMETHODIMP CompositionTransaction::DoTransaction() { if (NS_WARN_IF(!mEditorBase)) { return NS_ERROR_NOT_INITIALIZED; } // Fail before making any changes if there's no selection controller nsCOMPtr<nsISelectionController> selCon; mEditorBase->GetSelectionController(getter_AddRefs(selCon)); NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED); // Advance caret: This requires the presentation shell to get the selection. if (mReplaceLength == 0) { ErrorResult rv; mTextNode->InsertData(mOffset, mStringToInsert, rv); if (NS_WARN_IF(rv.Failed())) { return rv.StealNSResult(); } mEditorBase->RangeUpdaterRef().SelAdjInsertText(*mTextNode, mOffset, mStringToInsert); } else { uint32_t replaceableLength = mTextNode->TextLength() - mOffset; ErrorResult rv; mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert, rv); if (NS_WARN_IF(rv.Failed())) { return rv.StealNSResult(); } mEditorBase->RangeUpdaterRef().SelAdjDeleteText(mTextNode, mOffset, mReplaceLength); mEditorBase->RangeUpdaterRef().SelAdjInsertText(*mTextNode, mOffset, mStringToInsert); // If IME text node is multiple node, ReplaceData doesn't remove all IME // text. So we need remove remained text into other text node. if (replaceableLength < mReplaceLength) { int32_t remainLength = mReplaceLength - replaceableLength; nsCOMPtr<nsINode> node = mTextNode->GetNextSibling(); while (node && node->IsText() && remainLength > 0) { Text* text = static_cast<Text*>(node.get()); uint32_t textLength = text->TextLength(); text->DeleteData(0, remainLength, IgnoreErrors()); mEditorBase->RangeUpdaterRef().SelAdjDeleteText(text, 0, remainLength); remainLength -= textLength; node = node->GetNextSibling(); } } } nsresult rv = SetSelectionForRanges(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }