Bug 1166436 part.12 Log the behavior of mozilla::ContentCache r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 05 Jun 2015 18:28:20 +0900
changeset 278135 6ee382b70183f82318b2fd5d3966f87e2fc09ee4
parent 278134 c8afeac76c0e0a82e709d9ef0672a37396b74341
child 278136 d5f5a8d204d1a69415f6bdaca43342966b475f4d
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [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.12 Log the behavior of mozilla::ContentCache r=m_kato
dom/ipc/TabParent.cpp
widget/ContentCache.cpp
widget/ContentCache.h
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1886,19 +1886,20 @@ TabParent::RecvNotifyIMEFocus(const bool
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aPreference = nsIMEUpdatePreference();
     return true;
   }
 
   mIMETabParent = aFocus ? this : nullptr;
-  mContentCache.AssignContent(aContentCache);
-  widget->NotifyIME(IMENotification(aFocus ? NOTIFY_IME_OF_FOCUS :
-                                             NOTIFY_IME_OF_BLUR));
+  IMENotification notification(aFocus ? NOTIFY_IME_OF_FOCUS :
+                                        NOTIFY_IME_OF_BLUR);
+  mContentCache.AssignContent(aContentCache, &notification);
+  widget->NotifyIME(notification);
 
   if (aFocus) {
     *aPreference = widget->GetIMEUpdatePreference();
   }
   return true;
 }
 
 bool
@@ -1916,58 +1917,63 @@ TabParent::RecvNotifyIMETextChange(const
   nsIMEUpdatePreference updatePreference = widget->GetIMEUpdatePreference();
   NS_ASSERTION(updatePreference.WantTextChange(),
                "Don't call Send/RecvNotifyIMETextChange without NOTIFY_TEXT_CHANGE");
   MOZ_ASSERT(!aCausedByComposition ||
                updatePreference.WantChangesCausedByComposition(),
     "The widget doesn't want text change notification caused by composition");
 #endif
 
-  mContentCache.AssignContent(aContentCache);
-
   IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
   notification.mTextChangeData.mStartOffset = aStart;
   notification.mTextChangeData.mOldEndOffset = aEnd;
   notification.mTextChangeData.mNewEndOffset = aNewEnd;
   notification.mTextChangeData.mCausedByComposition = aCausedByComposition;
+
+  mContentCache.AssignContent(aContentCache, &notification);
   widget->NotifyIME(notification);
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMESelectedCompositionRect(
              const ContentCache& aContentCache)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
-  mContentCache.AssignContent(aContentCache);
-
-  widget->NotifyIME(IMENotification(NOTIFY_IME_OF_COMPOSITION_UPDATE));
+  IMENotification notification(NOTIFY_IME_OF_COMPOSITION_UPDATE);
+  mContentCache.AssignContent(aContentCache, &notification);
+
+  widget->NotifyIME(notification);
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMESelection(const ContentCache& aContentCache,
                                   const bool& aCausedByComposition)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return true;
 
-  mContentCache.AssignContent(aContentCache);
+  IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
+  mContentCache.AssignContent(aContentCache, &notification);
 
   const nsIMEUpdatePreference updatePreference =
     widget->GetIMEUpdatePreference();
   if (updatePreference.WantSelectionChange() &&
       (updatePreference.WantChangesCausedByComposition() ||
        !aCausedByComposition)) {
-    mContentCache.NotifyIMEOfSelectionChange(widget, aCausedByComposition);
+    mContentCache.InitNotification(notification);
+    notification.mSelectionChangeData.mCausedByComposition =
+      aCausedByComposition;
+    widget->NotifyIME(notification);
   }
   return true;
 }
 
 bool
 TabParent::RecvUpdateContentCache(const ContentCache& aContentCache)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
@@ -1998,22 +2004,23 @@ TabParent::RecvNotifyIMEMouseButtonEvent
 bool
 TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
-  mContentCache.AssignContent(aContentCache);
+  IMENotification notification(NOTIFY_IME_OF_POSITION_CHANGE);
+  mContentCache.AssignContent(aContentCache, &notification);
 
   const nsIMEUpdatePreference updatePreference =
     widget->GetIMEUpdatePreference();
   if (updatePreference.WantPositionChanged()) {
-    widget->NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE));
+    widget->NotifyIME(notification);
   }
   return true;
 }
 
 bool
 TabParent::RecvRequestFocus(const bool& aCanRaise)
 {
   nsCOMPtr<nsIFocusManager> fm = nsFocusManager::GetFocusManager();
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -2,41 +2,166 @@
  * 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/IMEStateManager.h"
+#include "mozilla/Logging.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "nsIWidget.h"
 #include "nsRefPtr.h"
 
 namespace mozilla {
 
 using namespace widget;
 
+static const char*
+GetBoolName(bool aBool)
+{
+  return aBool ? "true" : "false";
+}
+
+static const char*
+GetEventMessageName(uint32_t aMessage)
+{
+  switch (aMessage) {
+    case NS_COMPOSITION_START:
+      return "NS_COMPOSITION_START";
+    case NS_COMPOSITION_END:
+      return "NS_COMPOSITION_END";
+    case NS_COMPOSITION_UPDATE:
+      return "NS_COMPOSITION_UPDATE";
+    case NS_COMPOSITION_CHANGE:
+      return "NS_COMPOSITION_CHANGE";
+    case NS_COMPOSITION_COMMIT_AS_IS:
+      return "NS_COMPOSITION_COMMIT_AS_IS";
+    case NS_COMPOSITION_COMMIT:
+      return "NS_COMPOSITION_COMMIT";
+    default:
+      return "unacceptable event message";
+  }
+}
+
+static const char*
+GetNotificationName(const IMENotification* aNotification)
+{
+  if (!aNotification) {
+    return "Not notification";
+  }
+  switch (aNotification->mMessage) {
+    case NOTIFY_IME_OF_FOCUS:
+      return "NOTIFY_IME_OF_FOCUS";
+    case NOTIFY_IME_OF_BLUR:
+      return "NOTIFY_IME_OF_BLUR";
+    case NOTIFY_IME_OF_SELECTION_CHANGE:
+      return "NOTIFY_IME_OF_SELECTION_CHANGE";
+    case NOTIFY_IME_OF_TEXT_CHANGE:
+      return "NOTIFY_IME_OF_TEXT_CHANGE";
+    case NOTIFY_IME_OF_COMPOSITION_UPDATE:
+      return "NOTIFY_IME_OF_COMPOSITION_UPDATE";
+    case NOTIFY_IME_OF_POSITION_CHANGE:
+      return "NOTIFY_IME_OF_POSITION_CHANGE";
+    case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
+      return "NOTIFY_IME_OF_MOUSE_BUTTON_EVENT";
+    case REQUEST_TO_COMMIT_COMPOSITION:
+      return "REQUEST_TO_COMMIT_COMPOSITION";
+    case REQUEST_TO_CANCEL_COMPOSITION:
+      return "REQUEST_TO_CANCEL_COMPOSITION";
+    default:
+      return "Unsupported notification";
+  }
+}
+
+class GetRectText : public nsAutoCString
+{
+public:
+  explicit GetRectText(const LayoutDeviceIntRect& aRect)
+  {
+    Assign("{ x=");
+    AppendInt(aRect.x);
+    Append(", y=");
+    AppendInt(aRect.y);
+    Append(", width=");
+    AppendInt(aRect.width);
+    Append(", height=");
+    AppendInt(aRect.height);
+    Append(" }");
+  }
+  virtual ~GetRectText() {}
+};
+
+class GetWritingModeName : public nsAutoCString
+{
+public:
+  explicit GetWritingModeName(const WritingMode& aWritingMode)
+  {
+    if (!aWritingMode.IsVertical()) {
+      Assign("Horizontal");
+      return;
+    }
+    if (aWritingMode.IsVerticalLR()) {
+      Assign("Vertical (LTR)");
+      return;
+    }
+    Assign("Vertical (RTL)");
+  }
+  virtual ~GetWritingModeName() {}
+};
+
 /*****************************************************************************
  * mozilla::ContentCache
  *****************************************************************************/
 
+PRLogModuleInfo* sContentCacheLog = nullptr;
+
 ContentCache::ContentCache()
   : mCompositionStart(UINT32_MAX)
   , mCompositionEventsDuringRequest(0)
   , mIsComposing(false)
   , mRequestedToCommitOrCancelComposition(false)
   , mIsChrome(XRE_GetProcessType() == GeckoProcessType_Default)
 {
+  if (!sContentCacheLog) {
+    sContentCacheLog = PR_NewLogModule("ContentCacheWidgets");
+  }
+}
+
+void
+ContentCache::AssignContent(const ContentCache& aOther,
+                            const IMENotification* aNotification)
+{
+  mText = aOther.mText;
+  mSelection = aOther.mSelection;
+  mCaret = aOther.mCaret;
+  mTextRectArray = aOther.mTextRectArray;
+  mEditorRect = aOther.mEditorRect;
+
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) AssignContent(aNotification=%s), "
+     "Succeeded, mText.Length()=%u, mSelection={ mAnchor=%u, mFocus=%u, "
+     " mWritingMode=%s }, mCaret={ mOffset=%u, mRect=%s }, "
+     "mTextRectArray={ mStart=%u, mRects.Length()=%u }, mEditorRect=%s",
+     this, GetBoolName(mIsChrome), GetNotificationName(aNotification),
+     mText.Length(), mSelection.mAnchor, mSelection.mFocus,
+     GetWritingModeName(mSelection.mWritingMode).get(), mCaret.mOffset,
+     GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
+     mTextRectArray.mRects.Length(), GetRectText(mEditorRect).get()));
 }
 
 void
 ContentCache::Clear()
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) Clear()",
+     this, GetBoolName(mIsChrome)));
+
   mText.Truncate();
   mSelection.Clear();
   mCaret.Clear();
   mTextRectArray.Clear();
   mEditorRect.SetEmpty();
 }
 
 bool
@@ -46,110 +171,203 @@ ContentCache::HandleQueryContentEvent(Wi
   MOZ_ASSERT(aWidget);
 
   aEvent.mSucceeded = false;
   aEvent.mWasAsync = false;
   aEvent.mReply.mFocusedWidget = aWidget;
 
   switch (aEvent.message) {
     case NS_QUERY_SELECTED_TEXT:
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
+         "aEvent={ message=NS_QUERY_SELECTED_TEXT }, aWidget=0x%p)",
+         this, GetBoolName(mIsChrome), aWidget));
       aEvent.mReply.mOffset = mSelection.StartOffset();
       if (mSelection.Collapsed()) {
         aEvent.mReply.mString.Truncate(0);
       } else {
         if (NS_WARN_IF(mSelection.EndOffset() > mText.Length())) {
+          MOZ_LOG(sContentCacheLog, LogLevel::Error,
+            ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+             "FAILED because mSelection.EndOffset()=%u is larger than "
+             "mText.Length()=%u",
+             this, GetBoolName(mIsChrome), mSelection.EndOffset(),
+             mText.Length()));
           return false;
         }
         aEvent.mReply.mString =
           Substring(mText, aEvent.mReply.mOffset, mSelection.Length());
       }
       aEvent.mReply.mReversed = mSelection.Reversed();
       aEvent.mReply.mHasSelection = true;
       aEvent.mReply.mWritingMode = mSelection.mWritingMode;
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+         "Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
+         "mReversed=%s, mHasSelection=%s, mWritingMode=%s } }",
+         this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
+         NS_ConvertUTF16toUTF8(aEvent.mReply.mString).get(),
+         GetBoolName(aEvent.mReply.mReversed),
+         GetBoolName(aEvent.mReply.mHasSelection),
+         GetWritingModeName(aEvent.mReply.mWritingMode).get()));
       break;
     case NS_QUERY_TEXT_CONTENT: {
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
+         "aEvent={ message=NS_QUERY_TEXT_CONTENT, mInput={ mOffset=%u, "
+         "mLength=%u } }, aWidget=0x%p), mText.Length()=%u",
+         this, GetBoolName(mIsChrome), aEvent.mInput.mOffset,
+         aEvent.mInput.mLength, aWidget, mText.Length()));
       uint32_t inputOffset = aEvent.mInput.mOffset;
       uint32_t inputEndOffset =
         std::min(aEvent.mInput.EndOffset(), mText.Length());
       if (NS_WARN_IF(inputEndOffset < inputOffset)) {
+        MOZ_LOG(sContentCacheLog, LogLevel::Error,
+          ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+           "FAILED because inputOffset=%u is larger than inputEndOffset=%u",
+           this, GetBoolName(mIsChrome), inputOffset, inputEndOffset));
         return false;
       }
       aEvent.mReply.mOffset = inputOffset;
       aEvent.mReply.mString =
         Substring(mText, inputOffset, inputEndOffset - inputOffset);
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+         "Succeeded, aEvent={ mReply={ mOffset=%u, mString.Length()=%u } }",
+         this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
+         aEvent.mReply.mString.Length()));
       break;
     }
     case NS_QUERY_TEXT_RECT:
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
+         "aEvent={ message=NS_QUERY_TEXT_RECT, mInput={ mOffset=%u, "
+         "mLength=%u } }, aWidget=0x%p), mText.Length()=%u",
+         this, GetBoolName(mIsChrome), aEvent.mInput.mOffset,
+         aEvent.mInput.mLength, aWidget, mText.Length()));
       if (NS_WARN_IF(!GetUnionTextRects(aEvent.mInput.mOffset,
                                         aEvent.mInput.mLength,
                                         aEvent.mReply.mRect))) {
         // XXX We don't have cache for this request.
+        MOZ_LOG(sContentCacheLog, LogLevel::Error,
+          ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+           "FAILED to get union rect",
+           this, GetBoolName(mIsChrome)));
         return false;
       }
       if (aEvent.mInput.mOffset < mText.Length()) {
         aEvent.mReply.mString =
           Substring(mText, aEvent.mInput.mOffset,
                     mText.Length() >= aEvent.mInput.EndOffset() ?
                       aEvent.mInput.mLength : UINT32_MAX);
       } else {
         aEvent.mReply.mString.Truncate(0);
       }
       aEvent.mReply.mOffset = aEvent.mInput.mOffset;
       // XXX This may be wrong if storing range isn't in the selection range.
       aEvent.mReply.mWritingMode = mSelection.mWritingMode;
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+         "Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
+         "mWritingMode=%s, mRect=%s } }",
+         this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
+         NS_ConvertUTF16toUTF8(aEvent.mReply.mString).get(),
+         GetWritingModeName(aEvent.mReply.mWritingMode).get(),
+         GetRectText(aEvent.mReply.mRect).get()));
       break;
     case NS_QUERY_CARET_RECT:
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
+         "aEvent={ message=NS_QUERY_CARET_RECT, mInput={ mOffset=%u } }, "
+         "aWidget=0x%p), mText.Length()=%u",
+         this, GetBoolName(mIsChrome), aEvent.mInput.mOffset, aWidget,
+         mText.Length()));
       if (NS_WARN_IF(!GetCaretRect(aEvent.mInput.mOffset,
                                    aEvent.mReply.mRect))) {
         // XXX If the input offset is in the range of cached text rects,
         //     we can guess the caret rect.
+        MOZ_LOG(sContentCacheLog, LogLevel::Error,
+          ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+           "FAILED to get caret rect",
+           this, GetBoolName(mIsChrome)));
         return false;
       }
       aEvent.mReply.mOffset = aEvent.mInput.mOffset;
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+         "Succeeded, aEvent={ mReply={ mOffset=%u, mRect=%s } }",
+         this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
+         GetRectText(aEvent.mReply.mRect).get()));
       break;
     case NS_QUERY_EDITOR_RECT:
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
+         "aEvent={ message=NS_QUERY_EDITOR_RECT }, aWidget=0x%p)",
+         this, GetBoolName(mIsChrome), aWidget));
       aEvent.mReply.mRect = mEditorRect;
+      MOZ_LOG(sContentCacheLog, LogLevel::Info,
+        ("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
+         "Succeeded, aEvent={ mReply={ mRect=%s } }",
+         this, GetBoolName(mIsChrome), GetRectText(aEvent.mReply.mRect).get()));
       break;
   }
   aEvent.mSucceeded = true;
   return true;
 }
 
 bool
-ContentCache::CacheAll(nsIWidget* aWidget)
+ContentCache::CacheAll(nsIWidget* aWidget,
+                       const IMENotification* aNotification)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheAll(aWidget=0x%p, "
+     "aNotification=%s)",
+     this, GetBoolName(mIsChrome), aWidget,
+     GetNotificationName(aNotification)));
+
   // CacheAll() must be called in content process.
   if (NS_WARN_IF(mIsChrome)) {
     return false;
   }
 
-  if (NS_WARN_IF(!CacheText(aWidget)) ||
-      NS_WARN_IF(!CacheSelection(aWidget)) ||
-      NS_WARN_IF(!CacheTextRects(aWidget)) ||
-      NS_WARN_IF(!CacheEditorRect(aWidget))) {
+  if (NS_WARN_IF(!CacheText(aWidget, aNotification)) ||
+      NS_WARN_IF(!CacheSelection(aWidget, aNotification)) ||
+      NS_WARN_IF(!CacheTextRects(aWidget, aNotification)) ||
+      NS_WARN_IF(!CacheEditorRect(aWidget, aNotification))) {
     return false;
   }
   return true;
 }
 
 bool
-ContentCache::CacheSelection(nsIWidget* aWidget)
+ContentCache::CacheSelection(nsIWidget* aWidget,
+                             const IMENotification* aNotification)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheSelection(aWidget=0x%p, "
+     "aNotification=%s)",
+     this, GetBoolName(mIsChrome), aWidget,
+     GetNotificationName(aNotification)));
+
   // CacheSelection() must be called in content process.
   if (NS_WARN_IF(mIsChrome)) {
     return false;
   }
 
   mCaret.Clear();
   mSelection.Clear();
 
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, aWidget);
   aWidget->DispatchEvent(&selection, status);
   if (NS_WARN_IF(!selection.mSucceeded)) {
+    MOZ_LOG(sContentCacheLog, LogLevel::Error,
+      ("ContentCache: 0x%p (mIsChrome=%s) CacheSelection(), FAILED, "
+       "couldn't retrieve the selected text",
+       this, GetBoolName(mIsChrome)));
     return false;
   }
   if (selection.mReply.mReversed) {
     mSelection.mAnchor =
       selection.mReply.mOffset + selection.mReply.mString.Length();
     mSelection.mFocus = selection.mReply.mOffset;
   } else {
     mSelection.mAnchor = selection.mReply.mOffset;
@@ -166,161 +384,262 @@ ContentCache::CacheSelection(nsIWidget* 
     mCaret.mOffset = selection.mReply.mOffset;
   }
 
   status = nsEventStatus_eIgnore;
   WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, aWidget);
   caretRect.InitForQueryCaretRect(mCaret.mOffset);
   aWidget->DispatchEvent(&caretRect, status);
   if (NS_WARN_IF(!caretRect.mSucceeded)) {
+    MOZ_LOG(sContentCacheLog, LogLevel::Error,
+      ("ContentCache: 0x%p (mIsChrome=%s) CacheSelection(), FAILED, "
+       "couldn't retrieve the caret rect at offset=%u",
+       this, GetBoolName(mIsChrome), mCaret.mOffset));
     mCaret.Clear();
     return false;
   }
   mCaret.mRect = caretRect.mReply.mRect;
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheSelection(), Succeeded, "
+     "mSelection={ mAnchor=%u, mFocus=%u, mWritingMode=%s }, "
+     "mCaret={ mOffset=%u, mRect=%s }",
+     this, GetBoolName(mIsChrome), mSelection.mAnchor, mSelection.mFocus,
+     GetWritingModeName(mSelection.mWritingMode).get(), mCaret.mOffset,
+     GetRectText(mCaret.mRect).get()));
   return true;
 }
 
 bool
-ContentCache::CacheEditorRect(nsIWidget* aWidget)
+ContentCache::CacheEditorRect(nsIWidget* aWidget,
+                              const IMENotification* aNotification)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheEditorRect(aWidget=0x%p, "
+     "aNotification=%s)",
+     this, GetBoolName(mIsChrome), aWidget,
+     GetNotificationName(aNotification)));
+
   // CacheEditorRect() must be called in content process.
   if (NS_WARN_IF(mIsChrome)) {
     return false;
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, aWidget);
   aWidget->DispatchEvent(&editorRectEvent, status);
   if (NS_WARN_IF(!editorRectEvent.mSucceeded)) {
+    MOZ_LOG(sContentCacheLog, LogLevel::Error,
+      ("ContentCache: 0x%p (mIsChrome=%s) CacheEditorRect(), FAILED, "
+       "couldn't retrieve the editor rect",
+       this, GetBoolName(mIsChrome)));
     return false;
   }
   mEditorRect = editorRectEvent.mReply.mRect;
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheEditorRect(), Succeeded, "
+     "mEditorRect=%s",
+     this, GetBoolName(mIsChrome), GetRectText(mEditorRect).get()));
   return true;
 }
 
 bool
-ContentCache::CacheText(nsIWidget* aWidget)
+ContentCache::CacheText(nsIWidget* aWidget,
+                        const IMENotification* aNotification)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheText(aWidget=0x%p, "
+     "aNotification=%s)",
+     this, GetBoolName(mIsChrome), aWidget,
+     GetNotificationName(aNotification)));
+
   // CacheText() must be called in content process.
   if (NS_WARN_IF(mIsChrome)) {
     return false;
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetQueryContentEvent queryText(true, NS_QUERY_TEXT_CONTENT, aWidget);
   queryText.InitForQueryTextContent(0, UINT32_MAX);
   aWidget->DispatchEvent(&queryText, status);
   if (NS_WARN_IF(!queryText.mSucceeded)) {
+    MOZ_LOG(sContentCacheLog, LogLevel::Error,
+      ("ContentCache: 0x%p (mIsChrome=%s) CacheText(), FAILED, "
+       "couldn't retrieve whole text",
+       this, GetBoolName(mIsChrome)));
     mText.Truncate();
     return false;
   }
   mText = queryText.mReply.mString;
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheText(), Succeeded, "
+     "mText.Length()=%u",
+     this, GetBoolName(mIsChrome), mText.Length()));
   return true;
 }
 
 bool
-ContentCache::CacheTextRects(nsIWidget* aWidget)
+ContentCache::CacheTextRects(nsIWidget* aWidget,
+                             const IMENotification* aNotification)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(aWidget=0x%p, "
+     "aNotification=%s)",
+     this, GetBoolName(mIsChrome), aWidget,
+     GetNotificationName(aNotification)));
+
   // CacheTextRects() must be called in content process.
   if (NS_WARN_IF(mIsChrome)) {
     return false;
   }
 
   mTextRectArray.Clear();
 
   nsRefPtr<TextComposition> textComposition =
     IMEStateManager::GetTextCompositionFor(aWidget);
   if (NS_WARN_IF(!textComposition)) {
+    MOZ_LOG(sContentCacheLog, LogLevel::Info,
+      ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), not caching "
+       "text rects because there is no composition string",
+       this, GetBoolName(mIsChrome), aWidget));
     return true;
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
   mTextRectArray.mRects.SetCapacity(textComposition->String().Length());
   mTextRectArray.mStart = textComposition->NativeOffsetOfStartComposition();
   uint32_t endOffset =
     mTextRectArray.mStart + textComposition->String().Length();
   for (uint32_t i = mTextRectArray.mStart; i < endOffset; i++) {
     WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget);
     textRect.InitForQueryTextRect(i, 1);
     aWidget->DispatchEvent(&textRect, status);
     if (NS_WARN_IF(!textRect.mSucceeded)) {
+      MOZ_LOG(sContentCacheLog, LogLevel::Error,
+        ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
+         "couldn't retrieve text rect at offset=%u",
+         this, GetBoolName(mIsChrome), i));
       mTextRectArray.Clear();
       return false;
     }
     mTextRectArray.mRects.AppendElement(textRect.mReply.mRect);
   }
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), Succeeded, "
+     "mTextRectArray={ mStart=%u, mRects.Length()=%u }, mText.Length()=%u",
+     this, GetBoolName(mIsChrome), mTextRectArray.mStart,
+     mTextRectArray.mRects.Length(), mText.Length()));
   return true;
 }
 
 void
 ContentCache::SetSelection(uint32_t aStartOffset,
                            uint32_t aLength,
                            bool aReversed,
                            const WritingMode& aWritingMode)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) SetSelection(aStartOffset=%u, "
+     "aLength=%u, aReversed=%s, aWritingMode=%s), mText.Length()=%u",
+     this, GetBoolName(mIsChrome), aStartOffset, aLength,
+     GetBoolName(aReversed), GetWritingModeName(aWritingMode).get(),
+     mText.Length()));
+
   if (!aReversed) {
     mSelection.mAnchor = aStartOffset;
     mSelection.mFocus = aStartOffset + aLength;
   } else {
     mSelection.mAnchor = aStartOffset + aLength;
     mSelection.mFocus = aStartOffset;
   }
   mSelection.mWritingMode = aWritingMode;
 }
 
 void
 ContentCache::SetSelection(uint32_t aAnchorOffset,
                            uint32_t aFocusOffset,
                            const WritingMode& aWritingMode)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) SetSelection(aAnchorOffset=%u, "
+     "aFocusOffset=%u, aWritingMode=%s), mText.Length()=%u",
+     this, GetBoolName(mIsChrome), aAnchorOffset, aFocusOffset,
+     GetWritingModeName(aWritingMode).get(), mText.Length()));
+
   mSelection.mAnchor = aAnchorOffset;
   mSelection.mFocus = aFocusOffset;
   mSelection.mWritingMode = aWritingMode;
 }
 
 bool
 ContentCache::GetTextRect(uint32_t aOffset,
                           LayoutDeviceIntRect& aTextRect) const
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) GetTextRect(aOffset=%u), "
+     "mTextRectArray={ mStart=%u, mRects.Length()=%u }",
+     this, GetBoolName(mIsChrome), aOffset, mTextRectArray.mStart,
+     mTextRectArray.mRects.Length()));
+
   if (NS_WARN_IF(!mTextRectArray.InRange(aOffset))) {
     aTextRect.SetEmpty();
     return false;
   }
   aTextRect = mTextRectArray.GetRect(aOffset);
   return true;
 }
 
 bool
 ContentCache::GetUnionTextRects(uint32_t aOffset,
                                 uint32_t aLength,
                                 LayoutDeviceIntRect& aUnionTextRect) const
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) GetUnionTextRects(aOffset=%u, "
+     "aLength=%u), mTextRectArray={ mStart=%u, mRects.Length()=%u }",
+     this, GetBoolName(mIsChrome), aOffset, aLength,
+     mTextRectArray.mStart, mTextRectArray.mRects.Length()));
+
   if (NS_WARN_IF(!mTextRectArray.InRange(aOffset, aLength))) {
     aUnionTextRect.SetEmpty();
     return false;
   }
   aUnionTextRect = mTextRectArray.GetUnionRect(aOffset, aLength);
   return true;
 }
 
 bool
 ContentCache::GetCaretRect(uint32_t aOffset,
                            LayoutDeviceIntRect& aCaretRect) const
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) GetCaretRect(aOffset=%u), "
+     "mCaret={ mOffset=%u, mRect=%s }",
+     this, GetBoolName(mIsChrome), aOffset, mCaret.mOffset,
+     GetRectText(mCaret.mRect).get()));
+
   if (mCaret.mOffset != aOffset) {
     aCaretRect.SetEmpty();
     return false;
   }
   aCaretRect = mCaret.mRect;
   return true;
 }
 
 bool
 ContentCache::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) OnCompositionEvent(aEvent={ "
+     "message=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), "
+     "mIsComposing=%s, mRequestedToCommitOrCancelComposition=%s",
+     this, GetBoolName(mIsChrome), GetEventMessageName(aEvent.message),
+     NS_ConvertUTF16toUTF8(aEvent.mData).get(), aEvent.mData.Length(),
+     aEvent.mRanges ? aEvent.mRanges->Length() : 0, GetBoolName(mIsComposing),
+     GetBoolName(mRequestedToCommitOrCancelComposition)));
+
   if (!aEvent.CausesDOMTextEvent()) {
     MOZ_ASSERT(aEvent.message == NS_COMPOSITION_START);
     mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
     mCompositionStart = mSelection.StartOffset();
     // XXX What's this case??
     if (mRequestedToCommitOrCancelComposition) {
       mCommitStringByRequest = aEvent.mData;
       mCompositionEventsDuringRequest++;
@@ -358,40 +677,47 @@ ContentCache::OnCompositionEvent(const W
   return true;
 }
 
 uint32_t
 ContentCache::RequestToCommitComposition(nsIWidget* aWidget,
                                          bool aCancel,
                                          nsAString& aLastString)
 {
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+    ("ContentCache: 0x%p (mIsChrome=%s) RequestToCommitComposition(aWidget=%p, "
+     "aCancel=%s), mIsComposing=%s, mRequestedToCommitOrCancelComposition=%s, "
+     "mCompositionEventsDuringRequest=%u",
+     this, GetBoolName(mIsChrome), aWidget, GetBoolName(aCancel),
+     GetBoolName(mIsComposing),
+     GetBoolName(mRequestedToCommitOrCancelComposition),
+     mCompositionEventsDuringRequest));
+
   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;
 }
 
 void
-ContentCache::NotifyIMEOfSelectionChange(nsIWidget* aWidget,
-                                         bool aCausedByComposition) const
+ContentCache::InitNotification(IMENotification& aNotification) const
 {
-  IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
-  notification.mSelectionChangeData.mOffset = mSelection.StartOffset();
-  notification.mSelectionChangeData.mLength = mSelection.Length();
-  notification.mSelectionChangeData.mReversed = mSelection.Reversed();
-  notification.mSelectionChangeData.SetWritingMode(mSelection.mWritingMode);
-  notification.mSelectionChangeData.mCausedByComposition =
-    aCausedByComposition;
-  aWidget->NotifyIME(notification);
+  if (NS_WARN_IF(aNotification.mMessage != NOTIFY_IME_OF_SELECTION_CHANGE)) {
+    return;
+  }
+  aNotification.mSelectionChangeData.mOffset = mSelection.StartOffset();
+  aNotification.mSelectionChangeData.mLength = mSelection.Length();
+  aNotification.mSelectionChangeData.mReversed = mSelection.Reversed();
+  aNotification.mSelectionChangeData.SetWritingMode(mSelection.mWritingMode);
 }
 
 /*****************************************************************************
  * mozilla::ContentCache::TextRectArray
  *****************************************************************************/
 
 LayoutDeviceIntRect
 ContentCache::TextRectArray::GetRect(uint32_t aOffset) const
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -16,44 +16,43 @@
 #include "nsString.h"
 #include "nsTArray.h"
 #include "Units.h"
 
 class nsIWidget;
 
 namespace mozilla {
 
+namespace widget {
+struct IMENotification;
+}
+
 /**
  * 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:
   typedef InfallibleTArray<LayoutDeviceIntRect> RectArray;
+  typedef widget::IMENotification IMENotification;
 
   ContentCache();
 
   void Clear();
 
   /**
    * AssignContent() is called when TabParent receives ContentCache from
    * the content process.  This doesn't copy composition information because
    * it's managed by TabParent itself.
    */
-  void AssignContent(const ContentCache& aOther)
-  {
-    mText = aOther.mText;
-    mSelection = aOther.mSelection;
-    mCaret = aOther.mCaret;
-    mTextRectArray = aOther.mTextRectArray;
-    mEditorRect = aOther.mEditorRect;
-  }
+  void AssignContent(const ContentCache& aOther,
+                     const IMENotification* aNotification = nullptr);
 
   /**
    * HandleQueryContentEvent() sets content data to aEvent.mReply.
    *
    * For NS_QUERY_SELECTED_TEXT, fail if the cache doesn't contain the whole
    *  selected range. (This shouldn't happen because PuppetWidget should have
    *  already sent the whole selection.)
    *
@@ -72,22 +71,27 @@ public:
    * For NS_QUERY_EDITOR_RECT, always success
    */
   bool HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
                                nsIWidget* aWidget) const;
 
   /**
    * Cache*() retrieves the latest content information and store them.
    */
-  bool CacheEditorRect(nsIWidget* aWidget);
-  bool CacheSelection(nsIWidget* aWidget);
-  bool CacheText(nsIWidget* aWidget);
-  bool CacheTextRects(nsIWidget* aWidget);
+  bool CacheEditorRect(nsIWidget* aWidget,
+                       const IMENotification* aNotification = nullptr);
+  bool CacheSelection(nsIWidget* aWidget,
+                      const IMENotification* aNotification = nullptr);
+  bool CacheText(nsIWidget* aWidget,
+                 const IMENotification* aNotification = nullptr);
+  bool CacheTextRects(nsIWidget* aWidget,
+                      const IMENotification* aNotification = nullptr);
 
-  bool CacheAll(nsIWidget* aWidget);
+  bool CacheAll(nsIWidget* aWidget,
+                const IMENotification* aNotification = nullptr);
 
   /**
    * 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
@@ -103,25 +107,21 @@ public:
    * @return            The count of composition events ignored after a call of
    *                    WillRequestToCommitOrCancelComposition().
    */
   uint32_t RequestToCommitComposition(nsIWidget* aWidget,
                                       bool aCancel,
                                       nsAString& aLastString);
 
   /**
-   * NotifyIMEOfSelectionChange() notifies IME of selection change with
-   * storing selection range.
+   * InitNotification() initializes aNotification with stored data.
    *
-   * @param aWidget                 A widget to notify IME of the notification.
-   * @param aCausedByComposition    true if the change is caused by composition.
-   *                                Otherwise, false.
+   * @param aNotification       Must be NOTIFY_IME_OF_SELECTION_CHANGE.
    */
-  void NotifyIMEOfSelectionChange(nsIWidget* aWidget,
-                                  bool aCausedByComposition) const;
+  void InitNotification(IMENotification& aNotification) const;
 
   void SetSelection(uint32_t aCaretOffset, const WritingMode& aWritingMode)
   {
     SetSelection(aCaretOffset, aCaretOffset, aWritingMode);
   }
   void SetSelection(uint32_t aStartOffset,
                     uint32_t aLength,
                     bool aReversed)
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -578,29 +578,28 @@ nsresult
 PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
 {
   switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
       return IMEEndComposition(false);
     case REQUEST_TO_CANCEL_COMPOSITION:
       return IMEEndComposition(true);
     case NOTIFY_IME_OF_FOCUS:
-      return NotifyIMEOfFocusChange(true);
     case NOTIFY_IME_OF_BLUR:
-      return NotifyIMEOfFocusChange(false);
+      return NotifyIMEOfFocusChange(aIMENotification);
     case NOTIFY_IME_OF_SELECTION_CHANGE:
       return NotifyIMEOfSelectionChange(aIMENotification);
     case NOTIFY_IME_OF_TEXT_CHANGE:
       return NotifyIMEOfTextChange(aIMENotification);
     case NOTIFY_IME_OF_COMPOSITION_UPDATE:
-      return NotifyIMEOfUpdateComposition();
+      return NotifyIMEOfUpdateComposition(aIMENotification);
     case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
       return NotifyIMEOfMouseButtonEvent(aIMENotification);
     case NOTIFY_IME_OF_POSITION_CHANGE:
-      return NotifyIMEOfPositionChange();
+      return NotifyIMEOfPositionChange(aIMENotification);
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 NS_IMETHODIMP
 PuppetWidget::StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
                              int32_t aPanelX, int32_t aPanelY,
@@ -659,54 +658,56 @@ PuppetWidget::GetInputContext()
     context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled);
     context.mIMEState.mOpen = static_cast<IMEState::Open>(open);
     context.mNativeIMEContext = reinterpret_cast<void*>(nativeIMEContext);
   }
   return context;
 }
 
 nsresult
-PuppetWidget::NotifyIMEOfFocusChange(bool aFocus)
+PuppetWidget::NotifyIMEOfFocusChange(const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
     return NS_ERROR_FAILURE;
 
-  if (aFocus) {
+  bool gotFocus = aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS;
+  if (gotFocus) {
     // When IME gets focus, we should initalize all information of the content.
-    if (NS_WARN_IF(!mContentCache.CacheAll(this))) {
+    if (NS_WARN_IF(!mContentCache.CacheAll(this, &aIMENotification))) {
       return NS_ERROR_FAILURE;
     }
   } else {
     // When IME loses focus, we don't need to store anything.
     mContentCache.Clear();
   }
 
   mIMEPreferenceOfParent = nsIMEUpdatePreference();
-  if (!mTabChild->SendNotifyIMEFocus(aFocus, mContentCache,
+  if (!mTabChild->SendNotifyIMEFocus(gotFocus, mContentCache,
                                      &mIMEPreferenceOfParent)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult
-PuppetWidget::NotifyIMEOfUpdateComposition()
+PuppetWidget::NotifyIMEOfUpdateComposition(
+                const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   NS_ENSURE_TRUE(mTabChild, NS_ERROR_FAILURE);
 
-  if (NS_WARN_IF(!mContentCache.CacheTextRects(this)) ||
-      NS_WARN_IF(!mContentCache.CacheSelection(this))) {
+  if (NS_WARN_IF(!mContentCache.CacheTextRects(this, &aIMENotification)) ||
+      NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendNotifyIMESelectedCompositionRect(mContentCache);
   return NS_OK;
 }
 
 nsIMEUpdatePreference
 PuppetWidget::GetIMEUpdatePreference()
@@ -736,19 +737,19 @@ PuppetWidget::NotifyIMEOfTextChange(cons
   if (!mTabChild)
     return NS_ERROR_FAILURE;
 
   // FYI: text change notification is the first notification after
   //      a user operation changes the content.  So, we need to modify
   //      the cache as far as possible here.
 
   // When text is changed, selection and text rects must be changed too.
-  if (NS_WARN_IF(!mContentCache.CacheText(this)) ||
-      NS_WARN_IF(!mContentCache.CacheTextRects(this)) ||
-      NS_WARN_IF(!mContentCache.CacheSelection(this))) {
+  if (NS_WARN_IF(!mContentCache.CacheText(this, &aIMENotification)) ||
+      NS_WARN_IF(!mContentCache.CacheTextRects(this, &aIMENotification)) ||
+      NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
     return NS_ERROR_FAILURE;
   }
 
   // TabParent doesn't this this to cache.  we don't send the notification
   // if parent process doesn't request NOTIFY_TEXT_CHANGE.
   if (mIMEPreferenceOfParent.WantTextChange() &&
       (mIMEPreferenceOfParent.WantChangesCausedByComposition() ||
        !aIMENotification.mTextChangeData.mCausedByComposition)) {
@@ -804,28 +805,28 @@ PuppetWidget::NotifyIMEOfMouseButtonEven
                                                 &consumedByIME)) {
     return NS_ERROR_FAILURE;
   }
 
   return consumedByIME ? NS_SUCCESS_EVENT_CONSUMED : NS_OK;
 }
 
 nsresult
-PuppetWidget::NotifyIMEOfPositionChange()
+PuppetWidget::NotifyIMEOfPositionChange(const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
   if (NS_WARN_IF(!mTabChild)) {
     return NS_ERROR_FAILURE;
   }
 
-  if (NS_WARN_IF(!mContentCache.CacheEditorRect(this)) ||
-      NS_WARN_IF(!mContentCache.CacheTextRects(this)) ||
-      NS_WARN_IF(!mContentCache.CacheSelection(this))) {
+  if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification)) ||
+      NS_WARN_IF(!mContentCache.CacheTextRects(this, &aIMENotification)) ||
+      NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
     return NS_ERROR_FAILURE;
   }
   if (!mTabChild->SendNotifyIMEPositionChange(mContentCache)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -252,22 +252,22 @@ protected:
                      const IMENotification& aIMENotification) override;
 
 private:
   nsresult Paint();
 
   void SetChild(PuppetWidget* aChild);
 
   nsresult IMEEndComposition(bool aCancel);
-  nsresult NotifyIMEOfFocusChange(bool aFocus);
+  nsresult NotifyIMEOfFocusChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfSelectionChange(const IMENotification& aIMENotification);
-  nsresult NotifyIMEOfUpdateComposition();
+  nsresult NotifyIMEOfUpdateComposition(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfMouseButtonEvent(const IMENotification& aIMENotification);
-  nsresult NotifyIMEOfPositionChange();
+  nsresult NotifyIMEOfPositionChange(const IMENotification& aIMENotification);
 
   bool CacheEditorRect();
   bool CacheCompositionRects(uint32_t& aStartOffset,
                              nsTArray<mozilla::LayoutDeviceIntRect>& aRectArray,
                              uint32_t& aTargetCauseOffset);
   bool GetCaretRect(mozilla::LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset);
   uint32_t GetCaretOffset();