Bug 917322 part.3 Pending composition string data should be cleared immediately before flushing a pending composition string r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 28 Jan 2015 15:27:31 +0900
changeset 226209 a3c0661108138058c16363814ac44855b5fb7d14
parent 226208 d7c660bbe955ffd01892590b4e38da9106a2ebc4
child 226210 7b196aeab6de7296dee5896f6557cb85cde0a962
push id28187
push usercbook@mozilla.com
push dateWed, 28 Jan 2015 13:20:48 +0000
treeherdermozilla-central@fc21937ca612 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs917322
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 917322 part.3 Pending composition string data should be cleared immediately before flushing a pending composition string r=smaug
widget/TextEventDispatcher.cpp
widget/TextEventDispatcher.h
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -57,28 +57,36 @@ TextEventDispatcher::OnDestroyWidget()
 }
 
 /******************************************************************************
  * TextEventDispatcher::PendingComposition
  *****************************************************************************/
 
 TextEventDispatcher::PendingComposition::PendingComposition()
 {
-  mClauses = new TextRangeArray();
   Clear();
 }
 
 void
 TextEventDispatcher::PendingComposition::Clear()
 {
   mString.Truncate();
-  mClauses->Clear();
+  mClauses = nullptr;
   mCaret.mRangeType = 0;
 }
 
+void
+TextEventDispatcher::PendingComposition::EnsureClauseArray()
+{
+  if (mClauses) {
+    return;
+  }
+  mClauses = new TextRangeArray();
+}
+
 nsresult
 TextEventDispatcher::PendingComposition::SetString(const nsAString& aString)
 {
   mString = aString;
   return NS_OK;
 }
 
 nsresult
@@ -89,16 +97,17 @@ TextEventDispatcher::PendingComposition:
     return NS_ERROR_INVALID_ARG;
   }
 
   switch (aAttribute) {
     case NS_TEXTRANGE_RAWINPUT:
     case NS_TEXTRANGE_SELECTEDRAWTEXT:
     case NS_TEXTRANGE_CONVERTEDTEXT:
     case NS_TEXTRANGE_SELECTEDCONVERTEDTEXT: {
+      EnsureClauseArray();
       TextRange textRange;
       textRange.mStartOffset =
         mClauses->IsEmpty() ? 0 : mClauses->LastElement().mEndOffset;
       textRange.mEndOffset = textRange.mStartOffset + aLength;
       textRange.mRangeType = aAttribute;
       mClauses->AppendElement(textRange);
       return NS_OK;
     }
@@ -128,43 +137,49 @@ TextEventDispatcher::PendingComposition:
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   nsCOMPtr<nsIWidget> widget(aDispatcher->mWidget);
   if (NS_WARN_IF(!widget || widget->Destroyed())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  if (!mClauses->IsEmpty() &&
+  if (mClauses && !mClauses->IsEmpty() &&
       mClauses->LastElement().mEndOffset != mString.Length()) {
     NS_WARNING("Sum of length of the all clauses must be same as the string "
                "length");
     Clear();
     return NS_ERROR_ILLEGAL_VALUE;
   }
   if (mCaret.mRangeType == NS_TEXTRANGE_CARETPOSITION) {
     if (mCaret.mEndOffset > mString.Length()) {
       NS_WARNING("Caret position is out of the composition string");
       Clear();
       return NS_ERROR_ILLEGAL_VALUE;
     }
+    EnsureClauseArray();
     mClauses->AppendElement(mCaret);
   }
 
   WidgetCompositionEvent compChangeEvent(true, NS_COMPOSITION_CHANGE, widget);
   compChangeEvent.time = PR_IntervalNow();
   compChangeEvent.mData = mString;
-  if (!mClauses->IsEmpty()) {
+  if (mClauses) {
+    MOZ_ASSERT(!mClauses->IsEmpty(),
+               "mClauses must be non-empty array when it's not nullptr");
     compChangeEvent.mRanges = mClauses;
   }
 
   compChangeEvent.mFlags.mIsSynthesizedForTests = aDispatcher->mForTests;
 
+  // While this method dispatches a composition event, some other event handler
+  // cause more clauses to be added.  So, we should clear pending composition
+  // before dispatching the event.
+  Clear();
   nsresult rv = widget->DispatchEvent(&compChangeEvent, aStatus);
-  Clear();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 } // namespace widget
--- a/widget/TextEventDispatcher.h
+++ b/widget/TextEventDispatcher.h
@@ -130,16 +130,18 @@ private:
     nsresult Flush(const TextEventDispatcher* aDispatcher,
                    nsEventStatus& aStatus);
     void Clear();
 
   private:
     nsAutoString mString;
     nsRefPtr<TextRangeArray> mClauses;
     TextRange mCaret;
+
+    void EnsureClauseArray();
   };
   PendingComposition mPendingComposition;
 
   bool mInitialized;
   bool mForTests;
 };
 
 } // namespace widget