Bug 1166436 part.4 mozilla::ContentCache should store text rects and caret rect and TabParent should use them r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 05 Jun 2015 18:28:19 +0900
changeset 278127 d64ef3cb7f7408d71728c869c0fd71fec3bdcc50
parent 278126 a4b5f272f88aa00d8a10c2a959bed1de99eba29d
child 278128 a33f46c01ae80a8d3182919a4c6d25403f76880e
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.4 mozilla::ContentCache should store text rects and caret rect and TabParent should use them r=m_kato
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/ContentCache.cpp
widget/ContentCache.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -257,17 +257,16 @@ NS_IMPL_ISUPPORTS(TabParent,
 
 TabParent::TabParent(nsIContentParent* aManager,
                      const TabId& aTabId,
                      const TabContext& aContext,
                      uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mWritingMode()
-  , mIMECompositionRectOffset(0)
   , mRect(0, 0, 0, 0)
   , mDimensions(0, 0)
   , mOrientation(0)
   , mDPI(0)
   , mDefaultScale(0)
   , mUpdatedDimensions(false)
   , mManager(aManager)
   , mMarkedDestroying(false)
@@ -1934,21 +1933,22 @@ TabParent::RecvNotifyIMETextChange(const
 
 bool
 TabParent::RecvNotifyIMESelectedCompositionRect(
   const uint32_t& aOffset,
   InfallibleTArray<LayoutDeviceIntRect>&& aRects,
   const uint32_t& aCaretOffset,
   const LayoutDeviceIntRect& aCaretRect)
 {
-  // add rect to cache for another query
-  mIMECompositionRectOffset = aOffset;
-  mIMECompositionRects = aRects;
-  mIMECaretOffset = aCaretOffset;
-  mIMECaretRect = aCaretRect;
+  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;
   }
   widget->NotifyIME(IMENotification(NOTIFY_IME_OF_COMPOSITION_UPDATE));
   return true;
 }
@@ -2015,18 +2015,18 @@ TabParent::RecvNotifyIMEEditorRect(const
 
 bool
 TabParent::RecvNotifyIMEPositionChange(
              const LayoutDeviceIntRect& aEditorRect,
              InfallibleTArray<LayoutDeviceIntRect>&& aCompositionRects,
              const LayoutDeviceIntRect& aCaretRect)
 {
   mIMEEditorRect = aEditorRect;
-  mIMECompositionRects = aCompositionRects;
-  mIMECaretRect = aCaretRect;
+  mContentCache.UpdateTextRectArray(aCompositionRects);
+  mContentCache.UpdateCaretRect(aCaretRect);
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
 
   const nsIMEUpdatePreference updatePreference =
     widget->GetIMEUpdatePreference();
@@ -2245,53 +2245,45 @@ TabParent::HandleQueryContentEvent(Widge
       aEvent.mReply.mString = Substring(mContentCache.Text(),
                                         inputOffset,
                                         inputEnd - inputOffset);
       aEvent.mSucceeded = true;
     }
     break;
   case NS_QUERY_TEXT_RECT:
     {
-      if (aEvent.mInput.mOffset < mIMECompositionRectOffset ||
-          (aEvent.mInput.mOffset + aEvent.mInput.mLength >
-            mIMECompositionRectOffset + mIMECompositionRects.Length())) {
-        // XXX
-        // we doesn't have cache for this request.
+      if (!mContentCache.GetUnionTextRects(aEvent.mInput.mOffset,
+                                           aEvent.mInput.mLength,
+                                           aEvent.mReply.mRect)) {
+        // XXX We don't have cache for this request.
         break;
       }
-
-      uint32_t baseOffset = aEvent.mInput.mOffset - mIMECompositionRectOffset;
-      uint32_t endOffset = baseOffset + aEvent.mInput.mLength;
-      aEvent.mReply.mRect.SetEmpty();
-      for (uint32_t i = baseOffset; i < endOffset; i++) {
-        aEvent.mReply.mRect =
-          aEvent.mReply.mRect.Union(mIMECompositionRects[i]);
-      }
       if (aEvent.mInput.mOffset < mContentCache.TextLength()) {
         aEvent.mReply.mString =
           Substring(mContentCache.Text(), aEvent.mInput.mOffset,
                     mContentCache.TextLength() >= aEvent.mInput.EndOffset() ?
                       aEvent.mInput.mLength : UINT32_MAX);
       } else {
         aEvent.mReply.mString.Truncate();
       }
       aEvent.mReply.mOffset = aEvent.mInput.mOffset;
-      aEvent.mReply.mRect = aEvent.mReply.mRect - GetChildProcessOffset();
+      aEvent.mReply.mRect -= GetChildProcessOffset();
       aEvent.mReply.mWritingMode = mWritingMode;
       aEvent.mSucceeded = true;
     }
     break;
   case NS_QUERY_CARET_RECT:
     {
-      if (aEvent.mInput.mOffset != mIMECaretOffset) {
+      if (!mContentCache.GetCaretRect(aEvent.mInput.mOffset,
+                                      aEvent.mReply.mRect)) {
         break;
       }
 
-      aEvent.mReply.mOffset = mIMECaretOffset;
-      aEvent.mReply.mRect = mIMECaretRect - GetChildProcessOffset();
+      aEvent.mReply.mOffset = aEvent.mInput.mOffset;
+      aEvent.mReply.mRect -= GetChildProcessOffset();
       aEvent.mSucceeded = true;
     }
     break;
   case NS_QUERY_EDITOR_RECT:
     {
       aEvent.mReply.mRect = mIMEEditorRect - GetChildProcessOffset();
       aEvent.mSucceeded = true;
     }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -475,20 +475,16 @@ protected:
 
     void SetHasContentOpener(bool aHasContentOpener);
 
     // IME
     static TabParent *mIMETabParent;
     ContentCache mContentCache;
     mozilla::WritingMode mWritingMode;
 
-    uint32_t mIMECompositionRectOffset;
-    InfallibleTArray<LayoutDeviceIntRect> mIMECompositionRects;
-    uint32_t mIMECaretOffset;
-    LayoutDeviceIntRect mIMECaretRect;
     LayoutDeviceIntRect mIMEEditorRect;
 
     nsIntRect mRect;
     ScreenIntSize mDimensions;
     ScreenOrientation mOrientation;
     float mDPI;
     CSSToLayoutDeviceScale mDefaultScale;
     bool mUpdatedDimensions;
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -8,16 +8,20 @@
 #include "mozilla/ContentCache.h"
 #include "mozilla/TextEvents.h"
 #include "nsIWidget.h"
 
 namespace mozilla {
 
 using namespace widget;
 
+/*****************************************************************************
+ * mozilla::ContentCache
+ *****************************************************************************/
+
 ContentCache::ContentCache()
   : mCompositionStart(UINT32_MAX)
   , mCompositionEventsDuringRequest(0)
   , mIsComposing(false)
   , mRequestedToCommitOrCancelComposition(false)
 {
 }
 
@@ -36,16 +40,78 @@ ContentCache::SetText(const nsAString& a
 void
 ContentCache::SetSelection(uint32_t aAnchorOffset, uint32_t aFocusOffset)
 {
   mSelection.mAnchor = aAnchorOffset;
   mSelection.mFocus = aFocusOffset;
 }
 
 bool
+ContentCache::InitTextRectArray(uint32_t aOffset,
+                                const RectArray& aTextRectArray)
+{
+  if (NS_WARN_IF(aOffset >= TextLength()) ||
+      NS_WARN_IF(aOffset + aTextRectArray.Length() > TextLength())) {
+    return false;
+  }
+  mTextRectArray.mStart = aOffset;
+  mTextRectArray.mRects = aTextRectArray;
+  return true;
+}
+
+bool
+ContentCache::GetTextRect(uint32_t aOffset,
+                          LayoutDeviceIntRect& aTextRect) const
+{
+  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
+{
+  if (NS_WARN_IF(!mTextRectArray.InRange(aOffset, aLength))) {
+    aUnionTextRect.SetEmpty();
+    return false;
+  }
+  aUnionTextRect = mTextRectArray.GetUnionRect(aOffset, aLength);
+  return true;
+}
+
+bool
+ContentCache::InitCaretRect(uint32_t aOffset,
+                            const LayoutDeviceIntRect& aCaretRect)
+{
+  if (NS_WARN_IF(aOffset > TextLength())) {
+    return false;
+  }
+  mCaret.mOffset = aOffset;
+  mCaret.mRect = aCaretRect;
+  return true;
+}
+
+bool
+ContentCache::GetCaretRect(uint32_t aOffset,
+                           LayoutDeviceIntRect& aCaretRect) const
+{
+  if (mCaret.mOffset != aOffset) {
+    aCaretRect.SetEmpty();
+    return false;
+  }
+  aCaretRect = mCaret.mRect;
+  return true;
+}
+
+bool
 ContentCache::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
 {
   if (!aEvent.CausesDOMTextEvent()) {
     MOZ_ASSERT(aEvent.message == NS_COMPOSITION_START);
     mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
     mCompositionStart = SelectionStart();
     // XXX What's this case??
     if (mRequestedToCommitOrCancelComposition) {
@@ -96,9 +162,37 @@ ContentCache::RequestToCommitComposition
                                                REQUEST_TO_COMMIT_COMPOSITION));
 
   mRequestedToCommitOrCancelComposition = false;
   aLastString = mCommitStringByRequest;
   mCommitStringByRequest.Truncate(0);
   return mCompositionEventsDuringRequest;
 }
 
+/*****************************************************************************
+ * mozilla::ContentCache::TextRectArray
+ *****************************************************************************/
+
+LayoutDeviceIntRect
+ContentCache::TextRectArray::GetRect(uint32_t aOffset) const
+{
+  LayoutDeviceIntRect rect;
+  if (InRange(aOffset)) {
+    rect = mRects[aOffset - mStart];
+  }
+  return rect;
+}
+
+LayoutDeviceIntRect
+ContentCache::TextRectArray::GetUnionRect(uint32_t aOffset,
+                                          uint32_t aLength) const
+{
+  LayoutDeviceIntRect rect;
+  if (!InRange(aOffset, aLength)) {
+    return rect;
+  }
+  for (uint32_t i = 0; i < aLength; i++) {
+    rect = rect.Union(mRects[aOffset - mStart + i]);
+  }
+  return rect;
+}
+
 } // namespace mozilla
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -8,30 +8,34 @@
 #ifndef mozilla_ContentCache_h
 #define mozilla_ContentCache_h
 
 #include <stdint.h>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/EventForwards.h"
 #include "nsString.h"
+#include "nsTArray.h"
+#include "Units.h"
 
 class nsIWidget;
 
 namespace mozilla {
 
 /**
  * ContentCache stores various information of the child content.  This hides
  * raw information but you can access more useful information with a lot of
  * methods.
  */
 
 class ContentCache final
 {
 public:
+  typedef InfallibleTArray<LayoutDeviceIntRect> RectArray;
+
   ContentCache();
 
   void Clear();
 
   void SetText(const nsAString& aText);
   const nsString& Text() const { return mText; }
   uint32_t TextLength() const { return mText.Length(); }
 
@@ -70,16 +74,35 @@ public:
     return SelectionEnd() > TextLength();
   }
   uint32_t SelectionAnchor() const { return mSelection.mAnchor; }
   uint32_t SelectionFocus() const { return mSelection.mFocus; }
   uint32_t SelectionStart() const { return mSelection.StartOffset(); }
   uint32_t SelectionEnd() const { return mSelection.EndOffset(); }
   uint32_t SelectionLength() const { return mSelection.Length(); }
 
+  bool UpdateTextRectArray(const RectArray& aTextRectArray)
+  {
+    return InitTextRectArray(mTextRectArray.mStart, aTextRectArray);
+  }
+  bool InitTextRectArray(uint32_t aOffset, const RectArray& aTextRectArray);
+  bool GetTextRect(uint32_t aOffset,
+                   LayoutDeviceIntRect& aTextRect) const;
+  bool GetUnionTextRects(uint32_t aOffset,
+                         uint32_t aLength,
+                         LayoutDeviceIntRect& aUnionTextRect) const;
+
+  bool UpdateCaretRect(const LayoutDeviceIntRect& aCaretRect)
+  {
+    return InitCaretRect(mCaret.mOffset, aCaretRect);
+  }
+  bool InitCaretRect(uint32_t aOffset, const LayoutDeviceIntRect& aCaretRect);
+  uint32_t CaretOffset() const { return mCaret.mOffset; }
+  bool GetCaretRect(uint32_t aOffset, LayoutDeviceIntRect& aCaretRect) const;
+
 private:
   // Whole text in the target
   nsString mText;
   // This is commit string which is caused by our request.
   nsString mCommitStringByRequest;
   // Start offset of the composition string.
   uint32_t mCompositionStart;
   // Count of composition events during requesting commit or cancel the
@@ -103,15 +126,72 @@ private:
     uint32_t StartOffset() const { return Reversed() ? mFocus : mAnchor; }
     uint32_t EndOffset() const { return Reversed() ? mAnchor : mFocus; }
     uint32_t Length() const
     {
       return Reversed() ? mAnchor - mFocus : mFocus - mAnchor;
     }
   } mSelection;
 
+  struct Caret final
+  {
+    uint32_t mOffset;
+    LayoutDeviceIntRect mRect;
+
+    Caret()
+      : mOffset(UINT32_MAX)
+    {
+    }
+
+    uint32_t Offset() const
+    {
+      NS_WARN_IF(mOffset == UINT32_MAX);
+      return mOffset;
+    }
+  } mCaret;
+
+  struct TextRectArray final
+  {
+    uint32_t mStart;
+    RectArray mRects;
+
+    TextRectArray()
+      : mStart(UINT32_MAX)
+    {
+    }
+
+    uint32_t StartOffset() const
+    {
+      NS_WARN_IF(mStart == UINT32_MAX);
+      return mStart;
+    }
+    uint32_t EndOffset() const
+    {
+      if (NS_WARN_IF(mStart == UINT32_MAX) ||
+          NS_WARN_IF(static_cast<uint64_t>(mStart) + mRects.Length() >
+                       UINT32_MAX)) {
+        return UINT32_MAX;
+      }
+      return mStart + mRects.Length();
+    }
+    bool InRange(uint32_t aOffset) const
+    {
+      return mStart != UINT32_MAX &&
+             StartOffset() <= aOffset && aOffset < EndOffset();
+    }
+    bool InRange(uint32_t aOffset, uint32_t aLength) const
+    {
+      if (NS_WARN_IF(static_cast<uint64_t>(aOffset) + aLength > UINT32_MAX)) {
+        return false;
+      }
+      return InRange(aOffset) && aOffset + aLength <= EndOffset();
+    }
+    LayoutDeviceIntRect GetRect(uint32_t aOffset) const;
+    LayoutDeviceIntRect GetUnionRect(uint32_t aOffset, uint32_t aLength) const;
+  } mTextRectArray;
+
   bool mIsComposing;
   bool mRequestedToCommitOrCancelComposition;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ContentCache_h