Bug 1166436 part.3 mozilla::ContentCache should store active composition information and TabParent should use them r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 05 Jun 2015 18:28:19 +0900
changeset 247355 a4b5f272f88aa00d8a10c2a959bed1de99eba29d
parent 247354 c152e396e9c3592c7fac82ceb946188304bb6f01
child 247356 d64ef3cb7f7408d71728c869c0fd71fec3bdcc50
push id28864
push userkwierso@gmail.com
push dateFri, 05 Jun 2015 21:49:37 +0000
treeherdermozilla-central@97a39c939c51 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1166436
milestone41.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 1166436 part.3 mozilla::ContentCache should store active composition information and TabParent should use them r=m_kato
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/ContentCache.cpp
widget/ContentCache.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -257,20 +257,16 @@ NS_IMPL_ISUPPORTS(TabParent,
 
 TabParent::TabParent(nsIContentParent* aManager,
                      const TabId& aTabId,
                      const TabContext& aContext,
                      uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mWritingMode()
-  , mIMEComposing(false)
-  , mIMECompositionEnding(false)
-  , mIMEEventCountAfterEnding(0)
-  , mIMECompositionStart(0)
   , mIMECompositionRectOffset(0)
   , mRect(0, 0, 0, 0)
   , mDimensions(0, 0)
   , mOrientation(0)
   , mDPI(0)
   , mDefaultScale(0)
   , mUpdatedDimensions(false)
   , mManager(aManager)
@@ -2306,57 +2302,22 @@ TabParent::HandleQueryContentEvent(Widge
 
 bool
 TabParent::SendCompositionEvent(WidgetCompositionEvent& event)
 {
   if (mIsDestroyed) {
     return false;
   }
 
-  if (event.CausesDOMTextEvent()) {
-    return SendCompositionChangeEvent(event);
-  }
-
-  mIMEComposing = !event.CausesDOMCompositionEndEvent();
-  mIMECompositionStart = mContentCache.SelectionStart();
-  if (mIMECompositionEnding) {
-    mIMEEventCountAfterEnding++;
+  if (!mContentCache.OnCompositionEvent(event)) {
     return true;
   }
   return PBrowserParent::SendCompositionEvent(event);
 }
 
-/**
- * During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
- * widget usually sends a NS_COMPOSITION_CHANGE event to finalize or
- * clear the composition, respectively
- *
- * Because the event will not reach content in time, we intercept it
- * here and pass the text as the EndIMEComposition return value
- */
-bool
-TabParent::SendCompositionChangeEvent(WidgetCompositionEvent& event)
-{
-  if (mIMECompositionEnding) {
-    mIMECompositionText = event.mData;
-    mIMEEventCountAfterEnding++;
-    return true;
-  }
-
-  // We must be able to simulate the selection because
-  // we might not receive selection updates in time
-  if (!mIMEComposing) {
-    mIMECompositionStart = mContentCache.SelectionStart();
-  }
-  mContentCache.SetSelection(mIMECompositionStart + event.mData.Length());
-  mIMEComposing = !event.CausesDOMCompositionEndEvent();
-
-  return PBrowserParent::SendCompositionEvent(event);
-}
-
 bool
 TabParent::SendSelectionEvent(WidgetSelectionEvent& event)
 {
   if (mIsDestroyed) {
     return false;
   }
   mContentCache.SetSelection(
     event.mOffset + (event.mReversed ? event.mLength : 0),
@@ -2425,29 +2386,21 @@ TabParent::GetRenderFrame()
 }
 
 bool
 TabParent::RecvEndIMEComposition(const bool& aCancel,
                                  bool* aNoCompositionEvent,
                                  nsString* aComposition)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
-  if (!widget)
+  if (!widget) {
     return true;
-
-  mIMECompositionEnding = true;
-  mIMEEventCountAfterEnding = 0;
-
-  widget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
-                                              REQUEST_TO_COMMIT_COMPOSITION));
-
-  mIMECompositionEnding = false;
-  *aNoCompositionEvent = !mIMEEventCountAfterEnding;
-  *aComposition = mIMECompositionText;
-  mIMECompositionText.Truncate(0);  
+  }
+  *aNoCompositionEvent =
+    !mContentCache.RequestToCommitComposition(widget, aCancel, *aComposition);
   return true;
 }
 
 bool
 TabParent::RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
                               const int32_t& aPanelX, const int32_t& aPanelY,
                               nsString* aCommitted)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -465,34 +465,25 @@ protected:
     virtual bool RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
                                         TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                         uint64_t* aLayersId) override;
 
     virtual bool RecvSetDimensions(const uint32_t& aFlags,
                                    const int32_t& aX, const int32_t& aY,
                                    const int32_t& aCx, const int32_t& aCy) override;
 
-    bool SendCompositionChangeEvent(mozilla::WidgetCompositionEvent& event);
-
     bool InitBrowserConfiguration(const nsCString& aURI,
                                   BrowserConfiguration& aConfiguration);
 
     void SetHasContentOpener(bool aHasContentOpener);
 
     // IME
     static TabParent *mIMETabParent;
     ContentCache mContentCache;
     mozilla::WritingMode mWritingMode;
-    bool mIMEComposing;
-    bool mIMECompositionEnding;
-    uint32_t mIMEEventCountAfterEnding;
-    // Buffer to store composition text during ResetInputState
-    // Compositions in almost all cases are small enough for nsAutoString
-    nsAutoString mIMECompositionText;
-    uint32_t mIMECompositionStart;
 
     uint32_t mIMECompositionRectOffset;
     InfallibleTArray<LayoutDeviceIntRect> mIMECompositionRects;
     uint32_t mIMECaretOffset;
     LayoutDeviceIntRect mIMECaretRect;
     LayoutDeviceIntRect mIMEEditorRect;
 
     nsIntRect mRect;
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -1,19 +1,31 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=8 et :
  */
 /* 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 "mozilla/ContentCache.h"
+#include "mozilla/TextEvents.h"
+#include "nsIWidget.h"
 
 namespace mozilla {
 
+using namespace widget;
+
+ContentCache::ContentCache()
+  : mCompositionStart(UINT32_MAX)
+  , mCompositionEventsDuringRequest(0)
+  , mIsComposing(false)
+  , mRequestedToCommitOrCancelComposition(false)
+{
+}
+
 void
 ContentCache::Clear()
 {
   mText.Truncate();
 }
 
 void
 ContentCache::SetText(const nsAString& aText)
@@ -23,9 +35,70 @@ ContentCache::SetText(const nsAString& a
 
 void
 ContentCache::SetSelection(uint32_t aAnchorOffset, uint32_t aFocusOffset)
 {
   mSelection.mAnchor = aAnchorOffset;
   mSelection.mFocus = aFocusOffset;
 }
 
+bool
+ContentCache::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
+{
+  if (!aEvent.CausesDOMTextEvent()) {
+    MOZ_ASSERT(aEvent.message == NS_COMPOSITION_START);
+    mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
+    mCompositionStart = SelectionStart();
+    // XXX What's this case??
+    if (mRequestedToCommitOrCancelComposition) {
+      mCommitStringByRequest = aEvent.mData;
+      mCompositionEventsDuringRequest++;
+      return false;
+    }
+    return true;
+  }
+
+  // XXX Why do we ignore following composition events here?
+  //     TextComposition must handle following events correctly!
+
+  // During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
+  // widget usually sends a NS_COMPOSITION_CHANGE event to finalize or
+  // clear the composition, respectively.
+  // Because the event will not reach content in time, we intercept it
+  // here and pass the text as the DidRequestToCommitOrCancelComposition()
+  // return value.
+  if (mRequestedToCommitOrCancelComposition) {
+    mCommitStringByRequest = aEvent.mData;
+    mCompositionEventsDuringRequest++;
+    return false;
+  }
+
+  // We must be able to simulate the selection because
+  // we might not receive selection updates in time
+  if (!mIsComposing) {
+    mCompositionStart = SelectionStart();
+  }
+  // XXX This causes different behavior from non-e10s mode.
+  //     Selection range should represent caret position in the composition
+  //     string but this means selection range is all of the composition string.
+  SetSelection(mCompositionStart + aEvent.mData.Length());
+  mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
+  return true;
+}
+
+uint32_t
+ContentCache::RequestToCommitComposition(nsIWidget* aWidget,
+                                         bool aCancel,
+                                         nsAString& aLastString)
+{
+  mRequestedToCommitOrCancelComposition = true;
+  mCompositionEventsDuringRequest = 0;
+
+  aWidget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
+                                               REQUEST_TO_COMMIT_COMPOSITION));
+
+  mRequestedToCommitOrCancelComposition = false;
+  aLastString = mCommitStringByRequest;
+  mCommitStringByRequest.Truncate(0);
+  return mCompositionEventsDuringRequest;
+}
+
 } // namespace mozilla
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -5,35 +5,64 @@
  * 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/. */
 
 #ifndef mozilla_ContentCache_h
 #define mozilla_ContentCache_h
 
 #include <stdint.h>
 
+#include "mozilla/Assertions.h"
+#include "mozilla/EventForwards.h"
 #include "nsString.h"
 
+class nsIWidget;
+
 namespace mozilla {
 
 /**
  * ContentCache stores various information of the child content.  This hides
  * raw information but you can access more useful information with a lot of
  * methods.
  */
 
 class ContentCache final
 {
 public:
+  ContentCache();
+
   void Clear();
 
   void SetText(const nsAString& aText);
   const nsString& Text() const { return mText; }
   uint32_t TextLength() const { return mText.Length(); }
 
+  /**
+   * OnCompositionEvent() should be called before sending composition string.
+   * This returns true if the event should be sent.  Otherwise, false.
+   */
+  bool OnCompositionEvent(const WidgetCompositionEvent& aCompositionEvent);
+  /**
+   * RequestToCommitComposition() requests to commit or cancel composition to
+   * the widget.  If it's handled synchronously, this returns the number of
+   * composition events after that.
+   *
+   * @param aWidget     The widget to be requested to commit or cancel
+   *                    the composition.
+   * @param aCancel     When the caller tries to cancel the composition, true.
+   *                    Otherwise, i.e., tries to commit the composition, false.
+   * @param aLastString The last composition string before requesting to
+   *                    commit or cancel composition.
+   * @return            The count of composition events ignored after a call of
+   *                    WillRequestToCommitOrCancelComposition().
+   */
+  uint32_t RequestToCommitComposition(nsIWidget* aWidget,
+                                      bool aCancel,
+                                      nsAString& aLastString);
+
   void SetSelection(uint32_t aCaretOffset)
   {
     SetSelection(aCaretOffset, aCaretOffset);
   }
   void SetSelection(uint32_t aAnchorOffset, uint32_t aFocusOffset);
   bool SelectionCollapsed() const { return mSelection.Collapsed(); }
   bool SelectionReversed() const { return mSelection.Reversed(); }
   bool SelectionEndIsGraterThanTextLength() const
@@ -44,16 +73,23 @@ public:
   uint32_t SelectionFocus() const { return mSelection.mFocus; }
   uint32_t SelectionStart() const { return mSelection.StartOffset(); }
   uint32_t SelectionEnd() const { return mSelection.EndOffset(); }
   uint32_t SelectionLength() const { return mSelection.Length(); }
 
 private:
   // Whole text in the target
   nsString mText;
+  // This is commit string which is caused by our request.
+  nsString mCommitStringByRequest;
+  // Start offset of the composition string.
+  uint32_t mCompositionStart;
+  // Count of composition events during requesting commit or cancel the
+  // composition.
+  uint32_t mCompositionEventsDuringRequest;
 
   struct Selection final
   {
     // Following values are offset in "flat text".
     uint32_t mAnchor;
     uint32_t mFocus;
 
     Selection()
@@ -66,13 +102,16 @@ private:
     bool Reversed() const { return mFocus < mAnchor; }
     uint32_t StartOffset() const { return Reversed() ? mFocus : mAnchor; }
     uint32_t EndOffset() const { return Reversed() ? mAnchor : mFocus; }
     uint32_t Length() const
     {
       return Reversed() ? mAnchor - mFocus : mFocus - mAnchor;
     }
   } mSelection;
+
+  bool mIsComposing;
+  bool mRequestedToCommitOrCancelComposition;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ContentCache_h