Bug 1349255 - Make PBrowser.NotifyIMEFocus async to avoid UI jank. draft
authorHenry Chang <hchang@mozilla.com>
Mon, 08 May 2017 19:07:56 +0800
changeset 585642 69cb2845a0782bf7ab65040e70d492b5efa59aa1
parent 584687 55e5723b1e62190a38c00927eda796e2ad14778f
child 630764 a783a80ad552f9610fb871ec1d9df999a7a9e4e7
push id61157
push userhchang@mozilla.com
push dateSat, 27 May 2017 14:53:00 +0000
bugs1349255
milestone55.0a1
Bug 1349255 - Make PBrowser.NotifyIMEFocus async to avoid UI jank. MozReview-Commit-ID: 15eUwMJ2Q7H
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
ipc/ipdl/sync-messages.ini
widget/IMEData.h
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -206,19 +206,17 @@ parent:
     /**
      * Notifies chrome that there is a focus change involving an editable
      * object (input, textarea, document, contentEditable. etc.)
      *
      *  contentCache Cache of content
      *  notification Whole data of the notification
      *  requests     Requests of notification for IME of the native widget
      */
-    nested(inside_cpow) sync NotifyIMEFocus(ContentCache contentCache,
-                                            IMENotification notification)
-      returns (IMENotificationRequests requests);
+    async NotifyIMEFocus(ContentCache contentCache, IMENotification notification);
 
     /**
      * Notifies chrome that there has been a change in text content
      * One call can encompass both a delete and an insert operation
      * Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
      *
      *  contentCache Cache of content
      *  notification Whole data of the notification
@@ -546,17 +544,16 @@ parent:
 
     async AccessKeyNotHandled(WidgetKeyboardEvent event);
 
     async SetHasBeforeUnload(bool aHasBeforeUnload);
 
 child:
     async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
 
-
 parent:
 
     /**
      * Child informs the parent that the graphics objects are ready for
      * compositing.  This is sent when all pending changes have been
      * sent to the compositor and are ready to be shown on the next composite.
      * @see PCompositor
      * @see RequestNotifyAfterRemotePaint
@@ -619,16 +616,18 @@ child:
      * content processes always render to a virtual <0, 0> top-left
      * point.
      */
     async Show(ScreenIntSize size,
                ShowInfo info,
                bool parentIsActive,
                nsSizeMode sizeMode);
 
+    async ReplyIMENotificationRequests(IMENotificationRequests requests);
+
     async InitRendering(TextureFactoryIdentifier textureFactoryIdentifier,
                         uint64_t layersId,
                         CompositorOptions compositorOptions,
                         bool layersConnected,
                         nullable PRenderFrame renderFrame);
 
     async LoadURL(nsCString uri, ShowInfo info);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2164,16 +2164,27 @@ TabChild::RecvAsyncMessage(const nsStrin
   RefPtr<nsFrameMessageManager> mm =
     static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
   mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal), nullptr,
                      aMessage, false, &data, &cpows, aPrincipal, nullptr);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+TabChild::RecvReplyIMENotificationRequests(const IMENotificationRequests& aRequests)
+{
+  if (NS_WARN_IF(!mPuppetWidget)) {
+    return IPC_OK();
+  }
+
+  mPuppetWidget->HandleReplyIMENotificationRequests(aRequests);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
 {
   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
   if (NS_WARN_IF(!ourDocShell)) {
     return IPC_OK();
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow();
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -433,16 +433,18 @@ public:
 
   virtual mozilla::ipc::IPCResult RecvLoadRemoteScript(const nsString& aURL,
                                                        const bool& aRunInGlobalScope) override;
 
   virtual mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMessage,
                                                    InfallibleTArray<CpowEntry>&& aCpows,
                                                    const IPC::Principal& aPrincipal,
                                                    const ClonedMessageData& aData) override;
+  virtual mozilla::ipc::IPCResult
+  RecvReplyIMENotificationRequests(const IMENotificationRequests& aRequests) override;
 
   virtual mozilla::ipc::IPCResult
   RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext) override;
 
   virtual PDocAccessibleChild*
   AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&,
                            const uint32_t&, const IAccessibleHolder&) override;
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1684,31 +1684,42 @@ TabParent::RecvHideTooltip()
   }
 
   xulBrowserWindow->HideTooltip();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMEFocus(const ContentCache& aContentCache,
-                              const IMENotification& aIMENotification,
-                              IMENotificationRequests* aRequests)
+                              const IMENotification& aIMENotification)
 {
+  if (mIsDestroyed) {
+    return IPC_OK();
+  }
+
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
-    *aRequests = IMENotificationRequests();
+    if (!SendReplyIMENotificationRequests(IMENotificationRequests())) {
+      NS_WARNING("Failed to SendReplyIMENotificationRequests.");
+    }
     return IPC_OK();
   }
 
   mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
   IMEStateManager::NotifyIME(aIMENotification, widget, true);
 
+  IMENotificationRequests requests;
   if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
-    *aRequests = widget->IMENotificationRequestsRef();
+    requests = widget->IMENotificationRequestsRef();
   }
+
+  if (!SendReplyIMENotificationRequests(requests)) {
+    NS_WARNING("Failed to SendReplyIMENotificationRequests.");
+  }
+
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMETextChange(const ContentCache& aContentCache,
                                    const IMENotification& aIMENotification)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -198,20 +198,19 @@ public:
                  const IPC::Principal& aPrincipal,
                  nsTArray<ipc::StructuredCloneData>* aRetVal) override;
 
   virtual mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMessage,
                                                    InfallibleTArray<CpowEntry>&& aCpows,
                                                    const IPC::Principal& aPrincipal,
                                                    const ClonedMessageData& aData) override;
 
-  virtual mozilla::ipc::IPCResult
+virtual mozilla::ipc::IPCResult
   RecvNotifyIMEFocus(const ContentCache& aContentCache,
-                     const widget::IMENotification& aEventMessage,
-                     widget::IMENotificationRequests* aRequests) override;
+                     const widget::IMENotification& aEventMessage) override;
 
   virtual mozilla::ipc::IPCResult
   RecvNotifyIMETextChange(const ContentCache& aContentCache,
                           const widget::IMENotification& aEventMessage) override;
 
   virtual mozilla::ipc::IPCResult
   RecvNotifyIMECompositionUpdate(const ContentCache& aContentCache,
                                  const widget::IMENotification& aEventMessage) override;
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -816,18 +816,16 @@ description =
 [PBrowser::SyncMessage]
 description =
 [PBrowser::PPluginWidget]
 description =
 [PBrowser::GetWidgetNativeData]
 description =
 [PBrowser::DispatchFocusToTopLevelWindow]
 description =
-[PBrowser::NotifyIMEFocus]
-description =
 [PBrowser::NotifyIMEMouseButtonEvent]
 description =
 [PBrowser::RequestIMEToCommitComposition]
 description =
 [PBrowser::StartPluginIME]
 description =
 [PBrowser::GetInputContext]
 description =
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -46,17 +46,21 @@ struct IMENotificationRequests final
     // NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR is used when mouse button is pressed
     // or released on a character in the focused editor.  The notification is
     // notified to IME as a mouse event.  If it's consumed by IME, NotifyIME()
     // returns NS_SUCCESS_EVENT_CONSUMED.  Otherwise, it returns NS_OK if it's
     // handled without any error.
     NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR    = 1 << 3,
     // NOTE: NOTIFY_DURING_DEACTIVE isn't supported in environments where two
     //       or more compositions are possible.  E.g., Mac and Linux (GTK).
-    NOTIFY_DURING_DEACTIVE               = 1 << 7
+    NOTIFY_DURING_DEACTIVE               = 1 << 7,
+
+    NOTIFY_ALL = NOTIFY_TEXT_CHANGE |
+                 NOTIFY_POSITION_CHANGE |
+                 NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR,
   };
 
   IMENotificationRequests()
     : mWantUpdates(NOTIFY_NOTHING)
   {
   }
 
   explicit IMENotificationRequests(Notifications aWantUpdates)
@@ -102,17 +106,17 @@ struct IMENotificationRequests final
   {
     return !!(mWantUpdates & NOTIFY_DURING_DEACTIVE);
   }
 
   Notifications mWantUpdates;
 };
 
 /**
- * Contains IMEStatus plus information about the current 
+ * Contains IMEStatus plus information about the current
  * input context that the IME can use as hints if desired.
  */
 
 struct IMEState final
 {
   /**
    * IME enabled states, the mEnabled value of
    * SetInputContext()/GetInputContext() should be one value of following
@@ -764,17 +768,17 @@ struct IMENotification final
     }
     uint32_t NewLength() const
     {
       MOZ_ASSERT(IsValid());
       return mAddedEndOffset - mStartOffset;
     }
 
     // Positive if text is added. Negative if text is removed.
-    int64_t Difference() const 
+    int64_t Difference() const
     {
       return mAddedEndOffset - mRemovedEndOffset;
     }
 
     bool IsInInt32Range() const
     {
       MOZ_ASSERT(IsValid());
       return mStartOffset <= INT32_MAX &&
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/TextEvents.h"
 #include "mozilla/Unused.h"
 #include "BasicLayers.h"
 #include "PuppetWidget.h"
 #include "nsContentUtils.h"
 #include "nsIWidgetListener.h"
 #include "imgIContainer.h"
 #include "nsView.h"
+#include "nsPrintfCString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
@@ -512,17 +513,17 @@ PuppetWidget::ClearNativeTouchSequence(n
 {
   AutoObserverNotifier notifier(aObserver, "cleartouch");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendClearNativeTouchSequence(notifier.SaveObserver());
   return NS_OK;
 }
- 
+
 void
 PuppetWidget::SetConfirmedTargetAPZC(
                 uint64_t aInputBlockId,
                 const nsTArray<ScrollableLayerGuid>& aTargets) const
 {
   if (mTabChild) {
     mTabChild->SetTargetAPZC(aInputBlockId, aTargets);
   }
@@ -797,24 +798,32 @@ PuppetWidget::NotifyIMEOfFocusChange(con
         return NS_ERROR_FAILURE;
       }
     }
   } else {
     // When IME loses focus, we don't need to store anything.
     mContentCache.Clear();
   }
 
-  mIMENotificationRequestsOfParent = IMENotificationRequests();
-  if (!mTabChild->SendNotifyIMEFocus(mContentCache, aIMENotification,
-                                     &mIMENotificationRequestsOfParent)) {
+  mIMENotificationRequestsOfParent =
+    IMENotificationRequests(IMENotificationRequests::NOTIFY_ALL);
+  if (!mTabChild->SendNotifyIMEFocus(mContentCache, aIMENotification)) {
     return NS_ERROR_FAILURE;
   }
+
   return NS_OK;
 }
 
+void
+PuppetWidget::HandleReplyIMENotificationRequests(
+                const IMENotificationRequests& aRequests)
+{
+  mIMENotificationRequestsOfParent = aRequests;
+}
+
 nsresult
 PuppetWidget::NotifyIMEOfCompositionUpdate(
                 const IMENotification& aIMENotification)
 {
   if (NS_WARN_IF(!mTabChild)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -872,17 +881,17 @@ PuppetWidget::NotifyIMEOfSelectionChange
   // available.
   if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
     return NS_ERROR_FAILURE;
   }
 
   // Note that selection change must be notified after text change if it occurs.
   // Therefore, we don't need to query text content again here.
   mContentCache.SetSelection(
-    this, 
+    this,
     aIMENotification.mSelectionChangeData.mOffset,
     aIMENotification.mSelectionChangeData.Length(),
     aIMENotification.mSelectionChangeData.mReversed,
     aIMENotification.mSelectionChangeData.GetWritingMode());
 
   mTabChild->SendNotifyIMESelection(mContentCache, aIMENotification);
 
   return NS_OK;
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -284,16 +284,19 @@ public:
                           const FrameMetrics::ViewID& aViewId,
                           const CSSRect& aRect,
                           const uint32_t& aFlags) override;
 
   virtual bool HasPendingInputEvent() override;
 
   void HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
                                      bool aIsConsumed);
+
+  void HandleReplyIMENotificationRequests(const IMENotificationRequests& aRequests);
+
   virtual nsresult OnWindowedPluginKeyEvent(
                      const NativeEventData& aKeyEventData,
                      nsIKeyEventInPluginCallback* aCallback) override;
 
   virtual void LookUpDictionary(
                  const nsAString& aText,
                  const nsTArray<mozilla::FontRange>& aFontRangeArray,
                  const bool aIsVertical,