Bug 1166436 part.9 PuppetWidget should have mozilla::ContentCache and send it to TabParent r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 05 Jun 2015 18:28:20 +0900
changeset 247324 f30faf72451ee9afbd08bae7b19824b80ff5f76b
parent 247323 7acbb10cf6d63d2ab600f360f5055462b89c1373
child 247325 d813014e797c44abbf39b10e11dbbb632ef1ae27
push id60677
push usermasayuki@d-toybox.com
push dateFri, 05 Jun 2015 09:28:37 +0000
treeherdermozilla-inbound@cbaeacbb9700 [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.9 PuppetWidget should have mozilla::ContentCache and send it to TabParent r=m_kato
dom/ipc/PBrowser.ipdl
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/ContentCache.cpp
widget/ContentCache.h
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -36,16 +36,17 @@ using struct mozilla::void_t from "ipc/I
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using nscolor from "nsColor.h";
 using class mozilla::WidgetCompositionEvent from "ipc/nsGUIEventIPC.h";
 using struct mozilla::widget::IMENotification from "nsIWidget.h";
 using struct nsIMEUpdatePreference from "nsIWidget.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
 using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h";
 using mozilla::gfx::IntRect from "mozilla/gfx/Rect.h";
+using class mozilla::ContentCache from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetKeyboardEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetMouseEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetWheelEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetDragEvent from "ipc/nsGUIEventIPC.h";
 using struct nsRect from "nsRect.h";
 using class mozilla::WidgetSelectionEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetTouchEvent from "ipc/nsGUIEventIPC.h";
 using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h";
@@ -166,96 +167,86 @@ parent:
       returns (OwningSerializedStructuredCloneBuffer[] retval);
 
     /**
      * Notifies chrome that there is a focus change involving an editable
      * object (input, textarea, document, contentEditable. etc.)
      *
      *  focus        PR_TRUE if editable object is receiving focus
      *               PR_FALSE if losing focus
+     *  contentCache Cache of content
      *  preference   Native widget preference for IME updates
      */
-    prio(urgent) sync NotifyIMEFocus(bool focus)
+    prio(urgent) sync NotifyIMEFocus(bool focus, ContentCache contentCache)
       returns (nsIMEUpdatePreference preference);
 
     /**
      * 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
      *  offset       Starting offset of the change
      *  end          Ending offset of the range deleted
      *  newEnd       New ending offset after insertion
      *  causedByComposition true if the change is caused by composition
      *
      *  for insertion, offset == end
      *  for deletion, offset == newEnd
      */
-    prio(urgent) async NotifyIMETextChange(uint32_t offset, uint32_t end,
+    prio(urgent) async NotifyIMETextChange(ContentCache contentCache,
+                                           uint32_t offset, uint32_t end,
                                            uint32_t newEnd,
                                            bool causedByComposition);
 
     /**
      * Notifies chrome that there is a IME compostion rect updated
      *
-     *  offset       The starting offset of this rect
-     *  rect         The rect of first character of selected IME composition
-     *  caretOffset  The offset of caret position
-     *  caretRect    The rect of IME caret
+     *  contentCache Cache of content
      */
-    prio(urgent) async NotifyIMESelectedCompositionRect(uint32_t offset,
-                                                        LayoutDeviceIntRect[] rect,
-                                                        uint32_t caretOffset,
-                                                        LayoutDeviceIntRect caretRect);
+    prio(urgent) async NotifyIMESelectedCompositionRect(ContentCache contentCache);
 
     /**
      * Notifies chrome that there has been a change in selection
      * Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
      *
-     *  anchor       Offset where the selection started
-     *  focus        Offset where the caret is
-     *  writingMode  CSS writing-mode in effect at the focus
+     *  contentCache Cache of content
      *  causedByComposition true if the change is caused by composition
      */
-    prio(urgent) async NotifyIMESelection(uint32_t anchor,
-                                          uint32_t focus,
-                                          WritingMode writingMode,
+    prio(urgent) async NotifyIMESelection(ContentCache contentCache,
                                           bool causedByComposition);
 
     /**
      * Notifies chrome to refresh its text cache 
      *
-     *  text         The entire content of the text field
+     *  contentCache Cache of content
      */
-    prio(urgent) async NotifyIMETextHint(nsString text);
+    prio(urgent) async NotifyIMETextHint(ContentCache contentCache);
 
     /**
      * Notifies IME of mouse button event on a character in focused editor.
      *
      * Returns true if the mouse button event is consumd by IME.
      */
     prio(urgent) sync NotifyIMEMouseButtonEvent(IMENotification notification)
       returns (bool consumedByIME);
 
     /**
      * Notifies chrome to currect editor rect
      *
-     *  rect         Rect of current focused editor
+     *  contentCache Cache of content
      */
-    prio(urgent) async NotifyIMEEditorRect(LayoutDeviceIntRect rect);
+    prio(urgent) async NotifyIMEEditorRect(ContentCache contentCache);
 
     /**
      * Notifies chrome to position change
      *
-     *  editorRect   Rect of current focused editor
-     *  compositionRects     Rects of current composition string
+     *  contentCache Cache of content
      */
-    prio(urgent) async NotifyIMEPositionChange(LayoutDeviceIntRect editorRect,
-                                               LayoutDeviceIntRect[] compositionRects,
-                                               LayoutDeviceIntRect caretRect);
+    prio(urgent) async NotifyIMEPositionChange(ContentCache contentCache);
 
     /**
      * Instructs chrome to end any pending composition
      *
      *  cancel       true if composition should be cancelled
      *  noCompositionEvent   true if no composition event is fired by commit or
      *                       cancel
      *  composition  Text to commit before ending the composition
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1876,39 +1876,39 @@ TabParent::RecvHideTooltip()
   }
 
   xulBrowserWindow->HideTooltip();
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMEFocus(const bool& aFocus,
+                              const ContentCache& aContentCache,
                               nsIMEUpdatePreference* aPreference)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aPreference = nsIMEUpdatePreference();
     return true;
   }
 
   mIMETabParent = aFocus ? this : nullptr;
-  mContentCache.SetSelection(0, mContentCache.SelectionWritingMode());
+  mContentCache.AssignContent(aContentCache);
   widget->NotifyIME(IMENotification(aFocus ? NOTIFY_IME_OF_FOCUS :
                                              NOTIFY_IME_OF_BLUR));
 
   if (aFocus) {
     *aPreference = widget->GetIMEUpdatePreference();
-  } else {
-    mContentCache.Clear();
   }
   return true;
 }
 
 bool
-TabParent::RecvNotifyIMETextChange(const uint32_t& aStart,
+TabParent::RecvNotifyIMETextChange(const ContentCache& aContentCache,
+                                   const uint32_t& aStart,
                                    const uint32_t& aEnd,
                                    const uint32_t& aNewEnd,
                                    const bool& aCausedByComposition)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return true;
 
@@ -1916,80 +1916,75 @@ 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;
   widget->NotifyIME(notification);
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMESelectedCompositionRect(
-  const uint32_t& aOffset,
-  InfallibleTArray<LayoutDeviceIntRect>&& aRects,
-  const uint32_t& aCaretOffset,
-  const LayoutDeviceIntRect& aCaretRect)
+             const ContentCache& aContentCache)
 {
-  if (!mContentCache.InitTextRectArray(aOffset, aRects)) {
-    NS_WARNING("Failed to set text rect array");
-  }
-  if (!mContentCache.InitCaretRect(aCaretOffset, aCaretRect)) {
-    NS_WARNING("Failed to set caret rect");
-  }
-
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
+
+  mContentCache.AssignContent(aContentCache);
+
   widget->NotifyIME(IMENotification(NOTIFY_IME_OF_COMPOSITION_UPDATE));
   return true;
 }
 
 bool
-TabParent::RecvNotifyIMESelection(const uint32_t& aAnchor,
-                                  const uint32_t& aFocus,
-                                  const mozilla::WritingMode& aWritingMode,
+TabParent::RecvNotifyIMESelection(const ContentCache& aContentCache,
                                   const bool& aCausedByComposition)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return true;
 
-  mContentCache.SetSelection(aAnchor, aFocus, aWritingMode);
+  mContentCache.AssignContent(aContentCache);
+
   const nsIMEUpdatePreference updatePreference =
     widget->GetIMEUpdatePreference();
   if (updatePreference.WantSelectionChange() &&
       (updatePreference.WantChangesCausedByComposition() ||
        !aCausedByComposition)) {
     IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
     notification.mSelectionChangeData.mOffset = mContentCache.SelectionStart();
     notification.mSelectionChangeData.mLength = mContentCache.SelectionLength();
     notification.mSelectionChangeData.mReversed =
       mContentCache.SelectionReversed();
-    notification.mSelectionChangeData.SetWritingMode(aWritingMode);
+    notification.mSelectionChangeData.SetWritingMode(
+      mContentCache.SelectionWritingMode());
     notification.mSelectionChangeData.mCausedByComposition =
       aCausedByComposition;
     widget->NotifyIME(notification);
   }
   return true;
 }
 
 bool
-TabParent::RecvNotifyIMETextHint(const nsString& aText)
+TabParent::RecvNotifyIMETextHint(const ContentCache& aContentCache)
 {
-  mContentCache.SetText(aText);
+  mContentCache.AssignContent(aContentCache);
   return true;
 }
 
 bool
 TabParent::RecvNotifyIMEMouseButtonEvent(
              const IMENotification& aIMENotification,
              bool* aConsumedByIME)
 {
@@ -2000,37 +1995,32 @@ TabParent::RecvNotifyIMEMouseButtonEvent
     return true;
   }
   nsresult rv = widget->NotifyIME(aIMENotification);
   *aConsumedByIME = rv == NS_SUCCESS_EVENT_CONSUMED;
   return true;
 }
 
 bool
-TabParent::RecvNotifyIMEEditorRect(const LayoutDeviceIntRect& aRect)
+TabParent::RecvNotifyIMEEditorRect(const ContentCache& aContentCache)
 {
-  mContentCache.SetEditorRect(aRect);
+  mContentCache.AssignContent(aContentCache);
   return true;
 }
 
 bool
-TabParent::RecvNotifyIMEPositionChange(
-             const LayoutDeviceIntRect& aEditorRect,
-             InfallibleTArray<LayoutDeviceIntRect>&& aCompositionRects,
-             const LayoutDeviceIntRect& aCaretRect)
+TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache)
 {
-  mContentCache.SetEditorRect(aEditorRect);
-  mContentCache.UpdateTextRectArray(aCompositionRects);
-  mContentCache.UpdateCaretRect(aCaretRect);
-
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
+  mContentCache.AssignContent(aContentCache);
+
   const nsIMEUpdatePreference updatePreference =
     widget->GetIMEUpdatePreference();
   if (updatePreference.WantPositionChanged()) {
     widget->NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE));
   }
   return true;
 }
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -156,39 +156,32 @@ public:
                                 InfallibleTArray<CpowEntry>&& aCpows,
                                 const IPC::Principal& aPrincipal,
                                 nsTArray<OwningSerializedStructuredCloneBuffer>* aRetVal) override;
     virtual bool RecvAsyncMessage(const nsString& aMessage,
                                   const ClonedMessageData& aData,
                                   InfallibleTArray<CpowEntry>&& aCpows,
                                   const IPC::Principal& aPrincipal) override;
     virtual bool RecvNotifyIMEFocus(const bool& aFocus,
+                                    const ContentCache& aContentCache,
                                     nsIMEUpdatePreference* aPreference)
                                       override;
-    virtual bool RecvNotifyIMETextChange(const uint32_t& aStart,
+    virtual bool RecvNotifyIMETextChange(const ContentCache& aContentCache,
+                                         const uint32_t& aStart,
                                          const uint32_t& aEnd,
                                          const uint32_t& aNewEnd,
                                          const bool& aCausedByComposition) override;
-    virtual bool RecvNotifyIMESelectedCompositionRect(
-                   const uint32_t& aOffset,
-                   InfallibleTArray<LayoutDeviceIntRect>&& aRects,
-                   const uint32_t& aCaretOffset,
-                   const LayoutDeviceIntRect& aCaretRect) override;
-    virtual bool RecvNotifyIMESelection(const uint32_t& aAnchor,
-                                        const uint32_t& aFocus,
-                                        const mozilla::WritingMode& aWritingMode,
+    virtual bool RecvNotifyIMESelectedCompositionRect(const ContentCache& aContentCache) override;
+    virtual bool RecvNotifyIMESelection(const ContentCache& aContentCache,
                                         const bool& aCausedByComposition) override;
-    virtual bool RecvNotifyIMETextHint(const nsString& aText) override;
+    virtual bool RecvNotifyIMETextHint(const ContentCache& aContentCache) override;
     virtual bool RecvNotifyIMEMouseButtonEvent(const widget::IMENotification& aEventMessage,
                                                bool* aConsumedByIME) override;
-    virtual bool RecvNotifyIMEEditorRect(const LayoutDeviceIntRect& aRect) override;
-    virtual bool RecvNotifyIMEPositionChange(
-                   const LayoutDeviceIntRect& aEditorRect,
-                   InfallibleTArray<LayoutDeviceIntRect>&& aCompositionRects,
-                   const LayoutDeviceIntRect& aCaretRect) override;
+    virtual bool RecvNotifyIMEEditorRect(const ContentCache& aContentCache) override;
+    virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache) override;
     virtual bool RecvEndIMEComposition(const bool& aCancel,
                                        bool* aNoCompositionEvent,
                                        nsString* aComposition) override;
     virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
                                     const int32_t& aPanelX,
                                     const int32_t& aPanelY,
                                     nsString* aCommitted) override;
     virtual bool RecvSetPluginFocused(const bool& aFocused) override;
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -1,18 +1,21 @@
 /* -*- 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/IMEStateManager.h"
+#include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "nsIWidget.h"
+#include "nsRefPtr.h"
 
 namespace mozilla {
 
 using namespace widget;
 
 /*****************************************************************************
  * mozilla::ContentCache
  *****************************************************************************/
@@ -100,23 +103,151 @@ ContentCache::HandleQueryContentEvent(Wi
     case NS_QUERY_EDITOR_RECT:
       aEvent.mReply.mRect = mEditorRect;
       break;
   }
   aEvent.mSucceeded = true;
   return true;
 }
 
+bool
+ContentCache::CacheAll(nsIWidget* aWidget)
+{
+  if (NS_WARN_IF(!CacheText(aWidget)) ||
+      NS_WARN_IF(!CacheSelection(aWidget)) ||
+      NS_WARN_IF(!CacheTextRects(aWidget)) ||
+      NS_WARN_IF(!CacheEditorRect(aWidget))) {
+    return false;
+  }
+  return true;
+}
+
+bool
+ContentCache::CacheSelection(nsIWidget* aWidget)
+{
+  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)) {
+    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;
+    mSelection.mFocus =
+      selection.mReply.mOffset + selection.mReply.mString.Length();
+  }
+  mSelection.mWritingMode = selection.GetWritingMode();
+
+  nsRefPtr<TextComposition> textComposition =
+    IMEStateManager::GetTextCompositionFor(aWidget);
+  if (textComposition) {
+    mCaret.mOffset = textComposition->OffsetOfTargetClause();
+  } else {
+    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)) {
+    mCaret.Clear();
+    return false;
+  }
+  mCaret.mRect = caretRect.mReply.mRect;
+  return true;
+}
+
+bool
+ContentCache::CacheEditorRect(nsIWidget* aWidget)
+{
+  nsEventStatus status = nsEventStatus_eIgnore;
+  WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, aWidget);
+  aWidget->DispatchEvent(&editorRectEvent, status);
+  if (NS_WARN_IF(!editorRectEvent.mSucceeded)) {
+    return false;
+  }
+  mEditorRect = editorRectEvent.mReply.mRect;
+  return true;
+}
+
+bool
+ContentCache::CacheText(nsIWidget* aWidget)
+{
+  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)) {
+    SetText(EmptyString());
+    return false;
+  }
+  SetText(queryText.mReply.mString);
+  return true;
+}
+
+bool
+ContentCache::CacheTextRects(nsIWidget* aWidget)
+{
+  mTextRectArray.Clear();
+
+  nsRefPtr<TextComposition> textComposition =
+    IMEStateManager::GetTextCompositionFor(aWidget);
+  if (NS_WARN_IF(!textComposition)) {
+    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)) {
+      mTextRectArray.Clear();
+      return false;
+    }
+    mTextRectArray.mRects.AppendElement(textRect.mReply.mRect);
+  }
+  return true;
+}
+
 void
 ContentCache::SetText(const nsAString& aText)
 {
   mText = aText;
 }
 
 void
+ContentCache::SetSelection(uint32_t aStartOffset,
+                           uint32_t aLength,
+                           bool aReversed,
+                           const WritingMode& aWritingMode)
+{
+  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)
 {
   mSelection.mAnchor = aAnchorOffset;
   mSelection.mFocus = aFocusOffset;
   mSelection.mWritingMode = aWritingMode;
 }
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -69,16 +69,26 @@ public:
    *
    * For NS_QUERY_CARET_RECT, fail if cached offset isn't equals to input
    *
    * 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 CacheAll(nsIWidget* aWidget);
+
   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.
    */
@@ -100,16 +110,20 @@ public:
   uint32_t RequestToCommitComposition(nsIWidget* aWidget,
                                       bool aCancel,
                                       nsAString& aLastString);
 
   void SetSelection(uint32_t aCaretOffset, const WritingMode& aWritingMode)
   {
     SetSelection(aCaretOffset, aCaretOffset, aWritingMode);
   }
+  void SetSelection(uint32_t aStartOffset,
+                    uint32_t aLength,
+                    bool aReversed,
+                    const WritingMode& aWritingMode);
   void SetSelection(uint32_t aAnchorOffset,
                     uint32_t aFocusOffset,
                     const WritingMode& aWritingMode);
   bool SelectionCollapsed() const { return mSelection.Collapsed(); }
   bool SelectionReversed() const { return mSelection.Reversed(); }
   bool SelectionEndIsGraterThanTextLength() const
   {
     return SelectionEnd() > TextLength();
@@ -170,16 +184,22 @@ private:
     WritingMode mWritingMode;
 
     Selection()
       : mAnchor(0)
       , mFocus(0)
     {
     }
 
+    void Clear()
+    {
+      mAnchor = mFocus = 0;
+      mWritingMode = WritingMode();
+    }
+
     bool Collapsed() const { return mFocus == mAnchor; }
     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;
     }
@@ -190,16 +210,22 @@ private:
     uint32_t mOffset;
     LayoutDeviceIntRect mRect;
 
     Caret()
       : mOffset(UINT32_MAX)
     {
     }
 
+    void Clear()
+    {
+      mOffset = UINT32_MAX;
+      mRect.SetEmpty();
+    }
+
     uint32_t Offset() const
     {
       NS_WARN_IF(mOffset == UINT32_MAX);
       return mOffset;
     }
   } mCaret;
 
   struct TextRectArray final
@@ -207,16 +233,22 @@ private:
     uint32_t mStart;
     RectArray mRects;
 
     TextRectArray()
       : mStart(UINT32_MAX)
     {
     }
 
+    void Clear()
+    {
+      mStart = UINT32_MAX;
+      mRects.Clear();
+    }
+
     uint32_t StartOffset() const
     {
       NS_WARN_IF(mStart == UINT32_MAX);
       return mStart;
     }
     uint32_t EndOffset() const
     {
       if (NS_WARN_IF(mStart == UINT32_MAX) ||
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -132,17 +132,19 @@ PuppetWidget::Create(nsIWidget        *a
   return NS_OK;
 }
 
 void
 PuppetWidget::InitIMEState()
 {
   MOZ_ASSERT(mTabChild);
   if (mNeedIMEStateInit) {
-    mTabChild->SendNotifyIMEFocus(false, &mIMEPreferenceOfParent);
+    mContentCache.Clear();
+    mTabChild->SendNotifyIMEFocus(false, mContentCache,
+                                  &mIMEPreferenceOfParent);
     mNeedIMEStateInit = false;
   }
 }
 
 already_AddRefed<nsIWidget>
 PuppetWidget::CreateChild(const nsIntRect  &aRect,
                           nsWidgetInitData *aInitData,
                           bool             aForceUseIWidgetParent)
@@ -667,33 +669,31 @@ PuppetWidget::NotifyIMEOfFocusChange(boo
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
     return NS_ERROR_FAILURE;
 
   if (aFocus) {
-    nsEventStatus status;
-    WidgetQueryContentEvent queryEvent(true, NS_QUERY_TEXT_CONTENT, this);
-    InitEvent(queryEvent, nullptr);
-    // Query entire content
-    queryEvent.InitForQueryTextContent(0, UINT32_MAX);
-    DispatchEvent(&queryEvent, status);
-
-    if (queryEvent.mSucceeded) {
-      mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString);
+    if (NS_WARN_IF(!mContentCache.CacheText(this))) {
+      return NS_ERROR_FAILURE;
     }
+    mTabChild->SendNotifyIMETextHint(mContentCache);
+  } else {
+    mContentCache.Clear();
   }
 
   mIMEPreferenceOfParent = nsIMEUpdatePreference();
-  if (!mTabChild->SendNotifyIMEFocus(aFocus, &mIMEPreferenceOfParent)) {
+  if (!mTabChild->SendNotifyIMEFocus(aFocus, mContentCache,
+                                     &mIMEPreferenceOfParent)) {
     return NS_ERROR_FAILURE;
   }
 
+  // TODO: Optimize this later.
   if (aFocus) {
     IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
     notification.mSelectionChangeData.mCausedByComposition = false;
     NotifyIMEOfSelectionChange(notification); // Update selection
     NotifyIMEOfEditorRect();
   }
   return NS_OK;
 }
@@ -702,120 +702,41 @@ nsresult
 PuppetWidget::NotifyIMEOfUpdateComposition()
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   NS_ENSURE_TRUE(mTabChild, NS_ERROR_FAILURE);
 
-  uint32_t startOffset;
-  uint32_t targetCauseOffset;
-  nsAutoTArray<LayoutDeviceIntRect, 16> textRectArray;
-  if (!GetCompositionRects(startOffset,
-                           textRectArray,
-                           targetCauseOffset)) {
+  if (NS_WARN_IF(!mContentCache.CacheTextRects(this)) ||
+      NS_WARN_IF(!mContentCache.CacheSelection(this))) {
     return NS_ERROR_FAILURE;
   }
-  LayoutDeviceIntRect caretRect;
-  GetCaretRect(caretRect, targetCauseOffset);
-
-  mTabChild->SendNotifyIMESelectedCompositionRect(startOffset,
-                                                  textRectArray,
-                                                  targetCauseOffset,
-                                                  caretRect);
+  mTabChild->SendNotifyIMESelectedCompositionRect(mContentCache);
   return NS_OK;
 }
 
-bool
-PuppetWidget::GetCompositionRects(uint32_t& aStartOffset,
-                                  nsTArray<LayoutDeviceIntRect>& aTextRectArray,
-                                  uint32_t& aTargetCauseOffset)
-{
-  nsRefPtr<TextComposition> textComposition =
-    IMEStateManager::GetTextCompositionFor(this);
-  NS_ENSURE_TRUE(textComposition, false);
-
-  nsEventStatus status;
-  aTextRectArray.SetCapacity(textComposition->String().Length());
-  aStartOffset = textComposition->NativeOffsetOfStartComposition();
-  aTargetCauseOffset = textComposition->OffsetOfTargetClause();
-  uint32_t endOffset = textComposition->String().Length() + aStartOffset;
-  for (uint32_t i = aStartOffset; i < endOffset; i++) {
-    WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, this);
-    InitEvent(textRect, nullptr);
-    textRect.InitForQueryTextRect(i, 1);
-    DispatchEvent(&textRect, status);
-    NS_ENSURE_TRUE(textRect.mSucceeded, false);
-
-    aTextRectArray.AppendElement(textRect.mReply.mRect);
-  }
-  return true;
-}
-
-uint32_t
-PuppetWidget::GetCaretOffset()
-{
-  nsEventStatus status;
-  WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, this);
-  InitEvent(selection, nullptr);
-  DispatchEvent(&selection, status);
-  NS_ENSURE_TRUE(selection.mSucceeded, 0);
-
-  return selection.mReply.mOffset;
-}
-
-bool
-PuppetWidget::GetCaretRect(LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset)
-{
-  nsEventStatus status;
-  WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, this);
-  InitEvent(caretRect, nullptr);
-  caretRect.InitForQueryCaretRect(aCaretOffset);
-  DispatchEvent(&caretRect, status);
-  NS_ENSURE_TRUE(caretRect.mSucceeded, false);
-
-  aCaretRect = caretRect.mReply.mRect;
-
-  return true;
-}
-
 nsresult
 PuppetWidget::NotifyIMEOfEditorRect()
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
   if (NS_WARN_IF(!mTabChild)) {
     return NS_ERROR_FAILURE;
   }
 
-  LayoutDeviceIntRect rect;
-  if (!GetEditorRect(rect)) {
+  if (NS_WARN_IF(!mContentCache.CacheEditorRect(this))) {
     return NS_ERROR_FAILURE;
   }
-  mTabChild->SendNotifyIMEEditorRect(rect);
+  mTabChild->SendNotifyIMEEditorRect(mContentCache);
   return NS_OK;
 }
 
-bool
-PuppetWidget::GetEditorRect(LayoutDeviceIntRect& aRect)
-{
-  nsEventStatus status;
-  WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, this);
-  InitEvent(editorRectEvent);
-  DispatchEvent(&editorRectEvent, status);
-  if (NS_WARN_IF(!editorRectEvent.mSucceeded)) {
-    return false;
-  }
-  aRect = editorRectEvent.mReply.mRect;
-
-  return true;
-}
-
 nsIMEUpdatePreference
 PuppetWidget::GetIMEUpdatePreference()
 {
 #ifdef MOZ_CROSS_PROCESS_IME
   // e10s requires IME information cache into TabParent
   return nsIMEUpdatePreference(mIMEPreferenceOfParent.mWantUpdates |
                                nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE |
                                nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE |
@@ -834,32 +755,28 @@ PuppetWidget::NotifyIMEOfTextChange(cons
 
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
     return NS_ERROR_FAILURE;
 
-  nsEventStatus status;
-  WidgetQueryContentEvent queryEvent(true, NS_QUERY_TEXT_CONTENT, this);
-  InitEvent(queryEvent, nullptr);
-  queryEvent.InitForQueryTextContent(0, UINT32_MAX);
-  DispatchEvent(&queryEvent, status);
-
-  if (queryEvent.mSucceeded) {
-    mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString);
+  if (NS_WARN_IF(!mContentCache.CacheText(this))) {
+    return NS_ERROR_FAILURE;
   }
+  mTabChild->SendNotifyIMETextHint(mContentCache);
 
   // 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)) {
     mTabChild->SendNotifyIMETextChange(
+      mContentCache,
       aIMENotification.mTextChangeData.mStartOffset,
       aIMENotification.mTextChangeData.mOldEndOffset,
       aIMENotification.mTextChangeData.mNewEndOffset,
       aIMENotification.mTextChangeData.mCausedByComposition);
   }
   return NS_OK;
 }
 
@@ -872,21 +789,24 @@ PuppetWidget::NotifyIMEOfSelectionChange
 
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
     return NS_ERROR_FAILURE;
 
+  mContentCache.SetSelection(
+    aIMENotification.mSelectionChangeData.mOffset,
+    aIMENotification.mSelectionChangeData.mLength,
+    aIMENotification.mSelectionChangeData.mReversed,
+    aIMENotification.mSelectionChangeData.GetWritingMode());
+
   mTabChild->SendNotifyIMESelection(
-    aIMENotification.mSelectionChangeData.StartOffset(),
-    aIMENotification.mSelectionChangeData.EndOffset(),
-    aIMENotification.mSelectionChangeData.GetWritingMode(),
-    aIMENotification.mSelectionChangeData.mCausedByComposition);
+    mContentCache, aIMENotification.mSelectionChangeData.mCausedByComposition);
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfMouseButtonEvent(
                 const IMENotification& aIMENotification)
 {
   if (!mTabChild) {
@@ -907,35 +827,22 @@ PuppetWidget::NotifyIMEOfPositionChange(
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
   if (NS_WARN_IF(!mTabChild)) {
     return NS_ERROR_FAILURE;
   }
 
-  LayoutDeviceIntRect editorRect;
-  if (!GetEditorRect(editorRect)) {
+  if (NS_WARN_IF(!mContentCache.CacheEditorRect(this)) ||
+      NS_WARN_IF(!mContentCache.CacheTextRects(this)) ||
+      NS_WARN_IF(!mContentCache.CacheSelection(this))) {
     return NS_ERROR_FAILURE;
   }
-
-  uint32_t startOffset;
-  uint32_t targetCauseOffset;
-  nsAutoTArray<LayoutDeviceIntRect, 16> textRectArray;
-  if (!GetCompositionRects(startOffset,
-                           textRectArray,
-                           targetCauseOffset)) {
-    // no composition string, get caret offset by NS_QUERY_SELECTED_TEXT
-    targetCauseOffset = GetCaretOffset();
-  }
-
-  LayoutDeviceIntRect caretRect;
-  GetCaretRect(caretRect, targetCauseOffset);
-  if (!mTabChild->SendNotifyIMEPositionChange(editorRect, textRectArray,
-                                              caretRect)) {
+  if (!mTabChild->SendNotifyIMEPositionChange(mContentCache)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PuppetWidget::SetCursor(nsCursor aCursor)
 {
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -17,16 +17,17 @@
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
 #include "nsBaseScreen.h"
 #include "nsBaseWidget.h"
 #include "nsIScreenManager.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/ContentCache.h"
 #include "mozilla/EventForwards.h"
 
 namespace mozilla {
 
 namespace dom {
 class TabChild;
 }
 
@@ -259,20 +260,20 @@ private:
   nsresult NotifyIMEOfFocusChange(bool aFocus);
   nsresult NotifyIMEOfSelectionChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfUpdateComposition();
   nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfMouseButtonEvent(const IMENotification& aIMENotification);
   nsresult NotifyIMEOfEditorRect();
   nsresult NotifyIMEOfPositionChange();
 
-  bool GetEditorRect(mozilla::LayoutDeviceIntRect& aEditorRect);
-  bool GetCompositionRects(uint32_t& aStartOffset,
-                           nsTArray<mozilla::LayoutDeviceIntRect>& aRectArray,
-                           uint32_t& aTargetCauseOffset);
+  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();
 
   class PaintTask : public nsRunnable {
   public:
     NS_DECL_NSIRUNNABLE
     explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {}
     void Revoke() { mWidget = nullptr; }
@@ -305,16 +306,17 @@ private:
   nsIntRegion mDirtyRegion;
   nsRevocableEventPtr<PaintTask> mPaintTask;
   nsRefPtr<MemoryPressureObserver> mMemoryPressureObserver;
   // XXX/cjones: keeping this around until we teach LayerManager to do
   // retained-content-only transactions
   mozilla::RefPtr<DrawTarget> mDrawTarget;
   // IME
   nsIMEUpdatePreference mIMEPreferenceOfParent;
+  ContentCache mContentCache;
   bool mNeedIMEStateInit;
 
   // The DPI of the screen corresponding to this widget
   float mDPI;
   double mDefaultScale;
 
   // Precomputed answers for ExecuteNativeKeyBinding
   bool mNativeKeyCommandsValid;