Bug 1304620 part.2 ContentCacheInParent should manage if there is pending composition in the remote process r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 12 Oct 2016 17:09:02 +0900
changeset 424549 bca04593e3e430b6405806cf354ef285a1604fe3
parent 424548 3f976110079107362629adf7fb91985818678e1b
child 424550 eb8c87848c25769165b0dbace32626752f648c78
push id32189
push usermasayuki@d-toybox.com
push dateThu, 13 Oct 2016 01:32:14 +0000
reviewersm_kato
bugs1304620
milestone52.0a1
Bug 1304620 part.2 ContentCacheInParent should manage if there is pending composition in the remote process r?m_kato If the remote process is busy or user restarts composition too quickly, there could be 2 or more compositions in ContentCache. For managing such case, ContentCacheInParent should manage the pending composition count which is increased at dispatching eCompositionStart event to the remote process and decreased at receiving eCompositionCommit(AsIs) event from the remote process. MozReview-Commit-ID: KbTsK20NEZD
widget/ContentCache.cpp
widget/ContentCache.h
widget/TextEvents.h
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -505,16 +505,17 @@ ContentCacheInChild::SetSelection(nsIWid
 /*****************************************************************************
  * mozilla::ContentCacheInParent
  *****************************************************************************/
 
 ContentCacheInParent::ContentCacheInParent()
   : ContentCache()
   , mCommitStringByRequest(nullptr)
   , mPendingEventsNeedingAck(0)
+  , mPendingCompositionCount(0)
   , mWidgetHasComposition(false)
 {
 }
 
 void
 ContentCacheInParent::AssignContent(const ContentCache& aOther,
                                     nsIWidget* aWidget,
                                     const IMENotification* aNotification)
@@ -1054,31 +1055,35 @@ ContentCacheInParent::GetCaretRect(uint3
 
 bool
 ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
 {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("0x%p OnCompositionEvent(aEvent={ "
      "mMessage=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), "
      "mPendingEventsNeedingAck=%u, mWidgetHasComposition=%s, "
-     "mCommitStringByRequest=0x%p",
+     "mPendingCompositionCount=%u, mCommitStringByRequest=0x%p",
      this, ToChar(aEvent.mMessage),
      GetEscapedUTF8String(aEvent.mData).get(), aEvent.mData.Length(),
      aEvent.mRanges ? aEvent.mRanges->Length() : 0, mPendingEventsNeedingAck,
-     GetBoolName(mWidgetHasComposition), mCommitStringByRequest));
+     GetBoolName(mWidgetHasComposition), mPendingCompositionCount,
+     mCommitStringByRequest));
 
   // We must be able to simulate the selection because
   // we might not receive selection updates in time
   if (!mWidgetHasComposition) {
     if (aEvent.mWidget && aEvent.mWidget->PluginHasFocus()) {
       // If focus is on plugin, we cannot get selection range
       mCompositionStart = 0;
     } else {
       mCompositionStart = mSelection.StartOffset();
     }
+    MOZ_ASSERT(aEvent.mMessage == eCompositionStart);
+    MOZ_RELEASE_ASSERT(mPendingCompositionCount < UINT8_MAX);
+    mPendingCompositionCount++;
   }
 
   mWidgetHasComposition = !aEvent.CausesDOMCompositionEndEvent();
 
   if (!mWidgetHasComposition) {
     mCompositionStart = UINT32_MAX;
   }
 
@@ -1103,39 +1108,45 @@ ContentCacheInParent::OnCompositionEvent
 void
 ContentCacheInParent::OnSelectionEvent(
                         const WidgetSelectionEvent& aSelectionEvent)
 {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("0x%p OnSelectionEvent(aEvent={ "
      "mMessage=%s, mOffset=%u, mLength=%u, mReversed=%s, "
      "mExpandToClusterBoundary=%s, mUseNativeLineBreak=%s }), "
-     "mPendingEventsNeedingAck=%u, mWidgetHasComposition=%s",
+     "mPendingEventsNeedingAck=%u, mWidgetHasComposition=%s, "
+     "mPendingCompositionCount=%u",
      this, ToChar(aSelectionEvent.mMessage),
      aSelectionEvent.mOffset, aSelectionEvent.mLength,
      GetBoolName(aSelectionEvent.mReversed),
      GetBoolName(aSelectionEvent.mExpandToClusterBoundary),
      GetBoolName(aSelectionEvent.mUseNativeLineBreak), mPendingEventsNeedingAck,
-     GetBoolName(mWidgetHasComposition)));
+     GetBoolName(mWidgetHasComposition), mPendingCompositionCount));
 
   mPendingEventsNeedingAck++;
 }
 
 void
 ContentCacheInParent::OnEventNeedingAckHandled(nsIWidget* aWidget,
                                                 EventMessage aMessage)
 {
   // This is called when the child process receives WidgetCompositionEvent or
   // WidgetSelectionEvent.
 
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("0x%p OnEventNeedingAckHandled(aWidget=0x%p, "
-     "aMessage=%s), mPendingEventsNeedingAck=%u",
+     "aMessage=%s), mPendingEventsNeedingAck=%u, mPendingCompositionCount=%u",
      this, aWidget, ToChar(aMessage), mPendingEventsNeedingAck));
 
+  if (WidgetCompositionEvent::IsFollowedByCompositionEnd(aMessage)) {
+    MOZ_RELEASE_ASSERT(mPendingCompositionCount > 0);
+    mPendingCompositionCount--;
+  }
+
   MOZ_RELEASE_ASSERT(mPendingEventsNeedingAck > 0);
   if (--mPendingEventsNeedingAck) {
     return;
   }
 
   FlushPendingNotifications(aWidget);
 }
 
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -409,17 +409,19 @@ private:
   // This is not nullptr only while the instance is requesting IME to
   // composition.  Then, data value of dispatched composition events should
   // be stored into the instance.
   nsAString* mCommitStringByRequest;
   // mPendingEventsNeedingAck is increased before sending a composition event or
   // a selection event and decreased after they are received in the child
   // process.
   uint32_t mPendingEventsNeedingAck;
-
+  // mPendingCompositionCount is number of compositions which started in widget
+  // but not yet handled in the child process.
+  uint8_t mPendingCompositionCount;
   // mWidgetHasComposition is true when the widget in this process thinks that
   // IME has composition.  So, this is set to true when eCompositionStart is
   // dispatched and set to false when eCompositionCommit(AsIs) is dispatched.
   bool mWidgetHasComposition;
 
   /**
    * When following methods' aRoundToExistingOffset is true, even if specified
    * offset or range is out of bounds, the result is computed with the existing
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -590,18 +590,23 @@ public:
   {
     return mMessage == eCompositionEnd ||
            mMessage == eCompositionCommit ||
            mMessage == eCompositionCommitAsIs;
   }
 
   bool IsFollowedByCompositionEnd() const
   {
-    return mOriginalMessage == eCompositionCommit ||
-           mOriginalMessage == eCompositionCommitAsIs;
+    return IsFollowedByCompositionEnd(mOriginalMessage);
+  }
+
+  static bool IsFollowedByCompositionEnd(EventMessage aEventMessage)
+  {
+    return aEventMessage == eCompositionCommit ||
+           aEventMessage == eCompositionCommitAsIs;
   }
 };
 
 /******************************************************************************
  * mozilla::WidgetQueryContentEvent
  ******************************************************************************/
 
 class WidgetQueryContentEvent : public WidgetGUIEvent