Bug 1310912 - Part 1. CompositionTransaction should support multiple text nodes. r=masayuki
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Tue, 08 Nov 2016 16:14:57 +0900
changeset 322350 f0e042371dfe823300562e92254fb473fae518cf
parent 322349 eb3dd588e1afeda3d261078deabaf40fcc77c982
child 322351 94211fba111d93dcab69527cc729f9932c7ee162
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersmasayuki
bugs1310912
milestone52.0a1
Bug 1310912 - Part 1. CompositionTransaction should support multiple text nodes. r=masayuki Google Keep uses range.insertNode on input event. So, text node will be inserted into current caret position. Microsoft IME's caret is after composition string, but ATOK's caret is before it. So when using ATOK, this issue occurs. By range.insertNode, text nodes that have IME attribute becomes multiple text nodes. But CompositionTransanction doesn't consider that IME range isn't single text node. Although it replaces current composition string with new string on first text node, it doesn't delete composition string on other text node. MozReview-Commit-ID: 9uRx0A9mppx
editor/libeditor/CompositionTransaction.cpp
editor/libeditor/CompositionTransaction.h
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -29,16 +29,17 @@ CompositionTransaction::CompositionTrans
   : mTextNode(&aTextNode)
   , mOffset(aOffset)
   , mReplaceLength(aReplaceLength)
   , mRanges(aTextRangeArray)
   , mStringToInsert(aStringToInsert)
   , mEditorBase(aEditorBase)
   , mFixed(false)
 {
+  MOZ_ASSERT(mTextNode->TextLength() >= mOffset);
 }
 
 CompositionTransaction::~CompositionTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase,
                                    mTextNode)
@@ -63,21 +64,37 @@ CompositionTransaction::DoTransaction()
 
   // 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;
     }
   } else {
+    uint32_t replaceableLength = mTextNode->TextLength() - mOffset;
     nsresult rv =
       mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
+
+    // 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);
+        remainLength -= textLength;
+        node = node->GetNextSibling();
+      }
+    }
   }
 
   nsresult rv = SetSelectionForRanges();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
--- a/editor/libeditor/CompositionTransaction.h
+++ b/editor/libeditor/CompositionTransaction.h
@@ -30,17 +30,17 @@ class Text;
  * ranges and commit or cancel the composition.
  */
 class CompositionTransaction final : public EditTransactionBase
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMETEXTTXN_IID)
 
   /**
-   * @param aTextNode           The text content node.
+   * @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.
    */