Bug 1310912 - Part 4. RangeUpdater should be called on DoTransaction. r?masayuki
Although PlaceholderTransaction will use the selection on Merge, it is too late to use UpdateRange. Because RangeUpdater will be used after DoTransaction is finished. So we should update selection on DoTransaction.
Also, part 1 fix doesn't update selection correctly via RangeUpdater when IME composition is multiple node.
MozReview-Commit-ID: 9so9tR8uQ6t
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CompositionTransaction.h"
#include "mozilla/EditorBase.h" // mEditorBase
+#include "mozilla/SelectionState.h" // RangeUpdater
#include "mozilla/dom/Selection.h" // local var
#include "mozilla/dom/Text.h" // mTextNode
#include "nsAString.h" // params
#include "nsDebug.h" // for NS_ASSERTION, etc
#include "nsError.h" // for NS_SUCCEEDED, NS_FAILED, etc
#include "nsIPresShell.h" // nsISelectionController constants
#include "nsRange.h" // local var
#include "nsQueryObject.h" // for do_QueryObject
@@ -20,23 +21,25 @@ namespace mozilla {
using namespace dom;
CompositionTransaction::CompositionTransaction(
Text& aTextNode,
uint32_t aOffset,
uint32_t aReplaceLength,
TextRangeArray* aTextRangeArray,
const nsAString& aStringToInsert,
- EditorBase& aEditorBase)
+ EditorBase& aEditorBase,
+ RangeUpdater* aRangeUpdater)
: mTextNode(&aTextNode)
, mOffset(aOffset)
, mReplaceLength(aReplaceLength)
, mRanges(aTextRangeArray)
, mStringToInsert(aStringToInsert)
, mEditorBase(aEditorBase)
+ , mRangeUpdater(aRangeUpdater)
, mFixed(false)
{
MOZ_ASSERT(mTextNode->TextLength() >= mOffset);
}
CompositionTransaction::~CompositionTransaction()
{
}
@@ -63,34 +66,38 @@ CompositionTransaction::DoTransaction()
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
// Advance caret: This requires the presentation shell to get the selection.
if (mReplaceLength == 0) {
nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+ mRangeUpdater->SelAdjInsertText(*mTextNode, mOffset, mStringToInsert);
} else {
uint32_t replaceableLength = mTextNode->TextLength() - mOffset;
nsresult rv =
mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+ mRangeUpdater->SelAdjDeleteText(mTextNode, mOffset, mReplaceLength);
+ mRangeUpdater->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->IsNodeOfType(nsINode::eTEXT) &&
remainLength > 0) {
Text* text = static_cast<Text*>(node.get());
uint32_t textLength = text->TextLength();
text->DeleteData(0, remainLength);
+ mRangeUpdater->SelAdjDeleteText(text, 0, remainLength);
remainLength -= textLength;
node = node->GetNextSibling();
}
}
}
nsresult rv = SetSelectionForRanges();
NS_ENSURE_SUCCESS(rv, rv);
--- a/editor/libeditor/CompositionTransaction.h
+++ b/editor/libeditor/CompositionTransaction.h
@@ -13,16 +13,17 @@
#define NS_IMETEXTTXN_IID \
{ 0xb391355d, 0x346c, 0x43d1, \
{ 0x85, 0xed, 0x9e, 0x65, 0xbe, 0xe7, 0x7e, 0x48 } }
namespace mozilla {
class EditorBase;
class TextRangeArray;
+class RangeUpdater;
namespace dom {
class Text;
} // namespace dom
/**
* CompositionTransaction stores all edit for a composition, i.e.,
* from compositionstart event to compositionend event. E.g., inserting a
@@ -38,22 +39,24 @@ public:
* @param aTextNode The start node of text content.
* @param aOffset The location in aTextNode to do the insertion.
* @param aReplaceLength The length of text to replace. 0 means not
* replacing existing text.
* @param aTextRangeArray Clauses and/or caret information. This may be
* null.
* @param aString The new text to insert.
* @param aEditorBase Used to get and set the selection.
+ * @param aRangeUpdater The range updater
*/
CompositionTransaction(dom::Text& aTextNode,
uint32_t aOffset, uint32_t aReplaceLength,
TextRangeArray* aTextRangeArray,
const nsAString& aString,
- EditorBase& aEditorBase);
+ EditorBase& aEditorBase,
+ RangeUpdater* aRangeUpdater);
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CompositionTransaction,
EditTransactionBase)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_EDITTRANSACTIONBASE
@@ -84,16 +87,18 @@ private:
RefPtr<TextRangeArray> mRanges;
// The text to insert into mTextNode at mOffset.
nsString mStringToInsert;
// The editor, which is used to get the selection controller.
EditorBase& mEditorBase;
+ RangeUpdater* mRangeUpdater;
+
bool mFixed;
};
NS_DEFINE_STATIC_IID_ACCESSOR(CompositionTransaction, NS_IMETEXTTXN_IID)
} // namespace mozilla
#endif // #ifndef CompositionTransaction_h
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -2434,17 +2434,16 @@ nsresult
EditorBase::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
Text& aTextNode,
int32_t aOffset,
bool aSuppressIME)
{
RefPtr<EditTransactionBase> transaction;
bool isIMETransaction = false;
int32_t replacedOffset = 0;
- int32_t replacedLength = 0;
// aSuppressIME is used when editor must insert text, yet this text is not
// part of the current IME operation. Example: adjusting whitespace around an
// IME insertion.
if (ShouldHandleIMEComposition() && !aSuppressIME) {
if (!mIMETextNode) {
mIMETextNode = &aTextNode;
mIMETextOffset = aOffset;
}
@@ -2465,17 +2464,16 @@ EditorBase::InsertTextIntoTextNodeImpl(c
}
transaction = CreateTxnForComposition(aStringToInsert);
isIMETransaction = true;
// All characters of the composition string will be replaced with
// aStringToInsert. So, we need to emulate to remove the composition
// string.
replacedOffset = mIMETextOffset;
- replacedLength = mIMETextLength;
mIMETextLength = aStringToInsert.Length();
} else {
transaction = CreateTxnForInsertText(aStringToInsert, aTextNode, aOffset);
}
// Let listeners know what's up
for (auto& listener : mActionListeners) {
listener->WillInsertText(
@@ -2484,23 +2482,16 @@ EditorBase::InsertTextIntoTextNodeImpl(c
}
// XXX We may not need these view batches anymore. This is handled at a
// higher level now I believe.
BeginUpdateViewBatch();
nsresult rv = DoTransaction(transaction);
EndUpdateViewBatch();
- if (replacedLength) {
- mRangeUpdater.SelAdjDeleteText(
- static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()),
- replacedOffset, replacedLength);
- }
- mRangeUpdater.SelAdjInsertText(aTextNode, aOffset, aStringToInsert);
-
// let listeners know what happened
for (auto& listener : mActionListeners) {
listener->DidInsertText(
static_cast<nsIDOMCharacterData*>(aTextNode.AsDOMNode()),
aOffset, aStringToInsert, rv);
}
// Added some cruft here for bug 43366. Layout was crashing because we left
@@ -2612,17 +2603,18 @@ EditorBase::NotifyDocumentListeners(
}
already_AddRefed<InsertTextTransaction>
EditorBase::CreateTxnForInsertText(const nsAString& aStringToInsert,
Text& aTextNode,
int32_t aOffset)
{
RefPtr<InsertTextTransaction> transaction =
- new InsertTextTransaction(aTextNode, aOffset, aStringToInsert, *this);
+ new InsertTextTransaction(aTextNode, aOffset, aStringToInsert, *this,
+ &mRangeUpdater);
return transaction.forget();
}
nsresult
EditorBase::DeleteText(nsGenericDOMDataNode& aCharData,
uint32_t aOffset,
uint32_t aLength)
{
@@ -4242,17 +4234,17 @@ EditorBase::CreateTxnForComposition(cons
{
MOZ_ASSERT(mIMETextNode);
// During handling IME composition, mComposition must have been initialized.
// TODO: We can simplify CompositionTransaction::Init() with TextComposition
// class.
RefPtr<CompositionTransaction> transaction =
new CompositionTransaction(*mIMETextNode, mIMETextOffset, mIMETextLength,
mComposition->GetRanges(), aStringToInsert,
- *this);
+ *this, &mRangeUpdater);
return transaction.forget();
}
NS_IMETHODIMP
EditorBase::CreateTxnForAddStyleSheet(StyleSheet* aSheet,
AddStyleSheetTransaction** aTransaction)
{
RefPtr<AddStyleSheetTransaction> transaction = new AddStyleSheetTransaction();
--- a/editor/libeditor/InsertTextTransaction.cpp
+++ b/editor/libeditor/InsertTextTransaction.cpp
@@ -1,35 +1,38 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InsertTextTransaction.h"
#include "mozilla/EditorBase.h" // mEditorBase
+#include "mozilla/SelectionState.h" // RangeUpdater
#include "mozilla/dom/Selection.h" // Selection local var
#include "mozilla/dom/Text.h" // mTextNode
#include "nsAString.h" // nsAString parameter
#include "nsDebug.h" // for NS_ASSERTION, etc.
#include "nsError.h" // for NS_OK, etc.
#include "nsQueryObject.h" // for do_QueryObject
namespace mozilla {
using namespace dom;
InsertTextTransaction::InsertTextTransaction(Text& aTextNode,
uint32_t aOffset,
const nsAString& aStringToInsert,
- EditorBase& aEditorBase)
+ EditorBase& aEditorBase,
+ RangeUpdater* aRangeUpdater)
: mTextNode(&aTextNode)
, mOffset(aOffset)
, mStringToInsert(aStringToInsert)
, mEditorBase(aEditorBase)
+ , mRangeUpdater(aRangeUpdater)
{
}
InsertTextTransaction::~InsertTextTransaction()
{
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase,
@@ -56,16 +59,17 @@ InsertTextTransaction::DoTransaction()
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
DebugOnly<nsresult> rv =
selection->Collapse(mTextNode, mOffset + mStringToInsert.Length());
NS_ASSERTION(NS_SUCCEEDED(rv),
"Selection could not be collapsed after insert");
} else {
// Do nothing - DOM Range gravity will adjust selection
}
+ mRangeUpdater->SelAdjInsertText(*mTextNode, mOffset, mStringToInsert);
return NS_OK;
}
NS_IMETHODIMP
InsertTextTransaction::UndoTransaction()
{
return mTextNode->DeleteData(mOffset, mStringToInsert.Length());
--- a/editor/libeditor/InsertTextTransaction.h
+++ b/editor/libeditor/InsertTextTransaction.h
@@ -17,16 +17,18 @@ class nsITransaction;
#define NS_INSERTTEXTTXN_IID \
{ 0x8c9ad77f, 0x22a7, 0x4d01, \
{ 0xb1, 0x59, 0x8a, 0x0f, 0xdb, 0x1d, 0x08, 0xe9 } }
namespace mozilla {
class EditorBase;
+class RangeUpdater;
+
namespace dom {
class Text;
} // namespace dom
/**
* A transaction that inserts text into a content node.
*/
class InsertTextTransaction final : public EditTransactionBase
@@ -34,19 +36,21 @@ class InsertTextTransaction final : publ
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INSERTTEXTTXN_IID)
/**
* @param aElement The text content node.
* @param aOffset The location in aElement to do the insertion.
* @param aString The new text to insert.
* @param aPresShell Used to get and set the selection.
+ * @param aRangeUpdater The range updater
*/
InsertTextTransaction(dom::Text& aTextNode, uint32_t aOffset,
- const nsAString& aString, EditorBase& aEditorBase);
+ const nsAString& aString, EditorBase& aEditorBase,
+ RangeUpdater* aRangeUpdater);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(InsertTextTransaction,
EditTransactionBase)
NS_DECL_EDITTRANSACTIONBASE
NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
@@ -68,15 +72,17 @@ private:
// The offset into mTextNode where the insertion is to take place.
uint32_t mOffset;
// The text to insert into mTextNode at mOffset.
nsString mStringToInsert;
// The editor, which we'll need to get the selection.
EditorBase& mEditorBase;
+
+ RangeUpdater* mRangeUpdater;
};
NS_DEFINE_STATIC_IID_ACCESSOR(InsertTextTransaction, NS_INSERTTEXTTXN_IID)
} // namespace mozilla
#endif // #ifndef InsertTextTransaction_h