Bug 1678553 - part 11: Make `ContentCache` store its `Caret` with `Maybe` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 27 Nov 2020 14:47:50 +0000
changeset 558603 a4cd97ff70a9db2550000efc69a4358c4db062b3
parent 558602 08cd8d747c33ab8d092ea6de2aac565e79093b3e
child 558604 f7c2ac8767d534c32b487fa73ff2922f1525a3ac
push id131676
push usermasayuki@d-toybox.com
push dateSat, 28 Nov 2020 00:26:32 +0000
treeherderautoland@a4cd97ff70a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1678553
milestone85.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 1678553 - part 11: Make `ContentCache` store its `Caret` with `Maybe` r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D97980
widget/ContentCache.cpp
widget/ContentCache.h
widget/nsGUIEventIPC.h
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -102,17 +102,17 @@ LazyLogModule sContentCacheLog("ContentC
 void ContentCacheInChild::Clear() {
   MOZ_LOG(sContentCacheLog, LogLevel::Info, ("0x%p Clear()", this));
 
   mCompositionStart.reset();
   mLastCommit.reset();
   mText.Truncate();
   mSelection.reset();
   mFirstCharRect.SetEmpty();
-  mCaret.Clear();
+  mCaret.reset();
   mTextRectArray.Clear();
   mLastCommitStringTextRectArray.Clear();
   mEditorRect.SetEmpty();
 }
 
 void ContentCacheInChild::OnCompositionEvent(
     const WidgetCompositionEvent& aCompositionEvent) {
   if (aCompositionEvent.CausesDOMCompositionEndEvent()) {
@@ -167,17 +167,17 @@ bool ContentCacheInChild::CacheAll(nsIWi
 }
 
 bool ContentCacheInChild::CacheSelection(nsIWidget* aWidget,
                                          const IMENotification* aNotification) {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
           ("0x%p CacheSelection(aWidget=0x%p, aNotification=%s)", this, aWidget,
            GetNotificationName(aNotification)));
 
-  mCaret.Clear();
+  mCaret.reset();
   mSelection.reset();
 
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetQueryContentEvent selection(true, eQuerySelectedText, aWidget);
   aWidget->DispatchEvent(&selection, status);
   if (NS_WARN_IF(!selection.mSucceeded)) {
     MOZ_LOG(sContentCacheLog, LogLevel::Error,
             ("0x%p CacheSelection(), FAILED, "
@@ -201,43 +201,41 @@ bool ContentCacheInChild::CacheSelection
 }
 
 bool ContentCacheInChild::CacheCaret(nsIWidget* aWidget,
                                      const IMENotification* aNotification) {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
           ("0x%p CacheCaret(aWidget=0x%p, aNotification=%s)", this, aWidget,
            GetNotificationName(aNotification)));
 
-  mCaret.Clear();
+  mCaret.reset();
 
   if (NS_WARN_IF(mSelection.isNothing())) {
     return false;
   }
 
   // XXX Should be mSelection.mFocus?
-  mCaret.mOffset = mSelection->StartOffset();
+  uint32_t offset = mSelection->StartOffset();
 
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetQueryContentEvent caretRect(true, eQueryCaretRect, aWidget);
-  caretRect.InitForQueryCaretRect(mCaret.mOffset);
+  caretRect.InitForQueryCaretRect(offset);
   aWidget->DispatchEvent(&caretRect, status);
   if (NS_WARN_IF(!caretRect.mSucceeded)) {
     MOZ_LOG(sContentCacheLog, LogLevel::Error,
             ("0x%p CacheCaret(), FAILED, "
              "couldn't retrieve the caret rect at offset=%u",
-             this, mCaret.mOffset));
-    mCaret.Clear();
+             this, offset));
     return false;
   }
-  mCaret.mRect = caretRect.mReply.mRect;
+  mCaret.emplace(offset, caretRect.mReply.mRect);
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
           ("0x%p CacheCaret(), Succeeded, "
-           "mSelection=%s, mCaret={ mOffset=%u, mRect=%s }",
-           this, ToString(mSelection).c_str(), mCaret.mOffset,
-           GetRectText(mCaret.mRect).get()));
+           "mSelection=%s, mCaret=%s",
+           this, ToString(mSelection).c_str(), ToString(mCaret).c_str()));
   return true;
 }
 
 bool ContentCacheInChild::CacheEditorRect(
     nsIWidget* aWidget, const IMENotification* aNotification) {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
           ("0x%p CacheEditorRect(aWidget=0x%p, aNotification=%s)", this,
            aWidget, GetNotificationName(aNotification)));
@@ -336,21 +334,20 @@ bool ContentCacheInChild::QueryCharRectA
     return false;
   }
   aCharRectArray = std::move(textRects.mReply.mRectArray);
   return true;
 }
 
 bool ContentCacheInChild::CacheTextRects(nsIWidget* aWidget,
                                          const IMENotification* aNotification) {
-  MOZ_LOG(sContentCacheLog, LogLevel::Info,
-          ("0x%p CacheTextRects(aWidget=0x%p, aNotification=%s), "
-           "mCaret={ mOffset=%u, IsValid()=%s }",
-           this, aWidget, GetNotificationName(aNotification), mCaret.mOffset,
-           GetBoolName(mCaret.IsValid())));
+  MOZ_LOG(
+      sContentCacheLog, LogLevel::Info,
+      ("0x%p CacheTextRects(aWidget=0x%p, aNotification=%s), mCaret=%s", this,
+       aWidget, GetNotificationName(aNotification), ToString(mCaret).c_str()));
 
   mCompositionStart.reset();
   mTextRectArray.Clear();
   mLastCommitStringTextRectArray.Clear();
   mFirstCharRect.SetEmpty();
 
   if (NS_WARN_IF(mSelection.isNothing())) {
     return false;
@@ -605,33 +602,31 @@ void ContentCacheInParent::AssignContent
       }
     } else if (mCompositionStart.isSome() && mSelection.isSome() &&
                mCompositionStart.value() != mSelection->StartOffset()) {
       mCompositionStart = Some(mSelection->StartOffset());
       mPendingCommitLength = 0;
     }
   }
 
-  MOZ_LOG(
-      sContentCacheLog, LogLevel::Info,
-      ("0x%p AssignContent(aNotification=%s), "
-       "Succeeded, mText.Length()=%u, mSelection=%s, mFirstCharRect=%s, "
-       "mCaret={ mOffset=%u, mRect=%s }, mTextRectArray={ mStart=%u, "
-       "mRects.Length()=%zu }, mWidgetHasComposition=%s, "
-       "mPendingCompositionCount=%u, mCompositionStart=%u, "
-       "mPendingCommitLength=%u, mEditorRect=%s, "
-       "mLastCommitStringTextRectArray={ mStart=%u, mRects.Length()=%zu }",
-       this, GetNotificationName(aNotification), mText.Length(),
-       ToString(mSelection).c_str(), GetRectText(mFirstCharRect).get(),
-       mCaret.mOffset, GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
-       mTextRectArray.mRects.Length(), GetBoolName(mWidgetHasComposition),
-       mPendingCompositionCount, mCompositionStart.valueOr(UINT32_MAX),
-       mPendingCommitLength, GetRectText(mEditorRect).get(),
-       mLastCommitStringTextRectArray.mStart,
-       mLastCommitStringTextRectArray.mRects.Length()));
+  MOZ_LOG(sContentCacheLog, LogLevel::Info,
+          ("0x%p AssignContent(aNotification=%s), "
+           "Succeeded, mText.Length()=%u, mSelection=%s, mFirstCharRect=%s, "
+           "mCaret=%s, mTextRectArray={ mStart=%u, mRects.Length()=%zu }, "
+           "mWidgetHasComposition=%s, mPendingCompositionCount=%u, "
+           "mCompositionStart=%u, mPendingCommitLength=%u, mEditorRect=%s, "
+           "mLastCommitStringTextRectArray={ mStart=%u, mRects.Length()=%zu }",
+           this, GetNotificationName(aNotification), mText.Length(),
+           ToString(mSelection).c_str(), GetRectText(mFirstCharRect).get(),
+           ToString(mCaret).c_str(), mTextRectArray.mStart,
+           mTextRectArray.mRects.Length(), GetBoolName(mWidgetHasComposition),
+           mPendingCompositionCount, mCompositionStart.valueOr(UINT32_MAX),
+           mPendingCommitLength, GetRectText(mEditorRect).get(),
+           mLastCommitStringTextRectArray.mStart,
+           mLastCommitStringTextRectArray.mRects.Length()));
 }
 
 bool ContentCacheInParent::HandleQueryContentEvent(
     WidgetQueryContentEvent& aEvent, nsIWidget* aWidget) const {
   MOZ_ASSERT(aWidget);
 
   aEvent.mSucceeded = false;
   aEvent.mReply.mFocusedWidget = aWidget;
@@ -1128,27 +1123,26 @@ bool ContentCacheInParent::GetUnionTextR
 
   return !aUnionTextRect.IsEmpty();
 }
 
 bool ContentCacheInParent::GetCaretRect(uint32_t aOffset,
                                         bool aRoundToExistingOffset,
                                         LayoutDeviceIntRect& aCaretRect) const {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
-          ("0x%p GetCaretRect(aOffset=%u, "
-           "aRoundToExistingOffset=%s), "
-           "mCaret={ mOffset=%u, mRect=%s, IsValid()=%s }, mTextRectArray={ "
-           "mStart=%u, mRects.Length()=%zu }, mSelection=%s, mFirstCharRect=%s",
-           this, aOffset, GetBoolName(aRoundToExistingOffset), mCaret.mOffset,
-           GetRectText(mCaret.mRect).get(), GetBoolName(mCaret.IsValid()),
-           mTextRectArray.mStart, mTextRectArray.mRects.Length(),
-           ToString(mSelection).c_str(), GetRectText(mFirstCharRect).get()));
+          ("0x%p GetCaretRect(aOffset=%u, aRoundToExistingOffset=%s), "
+           "mCaret=%s, mTextRectArray={ mStart=%u, mRects.Length()=%zu }, "
+           "mSelection=%s, mFirstCharRect=%s",
+           this, aOffset, GetBoolName(aRoundToExistingOffset),
+           ToString(mCaret).c_str(), mTextRectArray.mStart,
+           mTextRectArray.mRects.Length(), ToString(mSelection).c_str(),
+           GetRectText(mFirstCharRect).get()));
 
-  if (mCaret.IsValid() && mCaret.mOffset == aOffset) {
-    aCaretRect = mCaret.mRect;
+  if (mCaret.isSome() && mCaret->mOffset == aOffset) {
+    aCaretRect = mCaret->mRect;
     return true;
   }
 
   // Guess caret rect from the text rect if it's stored.
   if (!GetTextRect(aOffset, aRoundToExistingOffset, aCaretRect)) {
     // There might be previous character rect in the cache.  If so, we can
     // guess the caret rect with it.
     if (!aOffset ||
@@ -1164,19 +1158,19 @@ bool ContentCacheInParent::GetCaretRect(
       aCaretRect.MoveToX(aCaretRect.XMost());
     }
   }
 
   // XXX This is not bidi aware because we don't cache each character's
   //     direction.  However, this is usually used by IME, so, assuming the
   //     character is in LRT context must not cause any problem.
   if (mSelection.isSome() && mSelection->mWritingMode.IsVertical()) {
-    aCaretRect.SetHeight(mCaret.IsValid() ? mCaret.mRect.Height() : 1);
+    aCaretRect.SetHeight(mCaret.isSome() ? mCaret->mRect.Height() : 1);
   } else {
-    aCaretRect.SetWidth(mCaret.IsValid() ? mCaret.mRect.Width() : 1);
+    aCaretRect.SetWidth(mCaret.isSome() ? mCaret->mRect.Width() : 1);
   }
   return true;
 }
 
 bool ContentCacheInParent::OnCompositionEvent(
     const WidgetCompositionEvent& aEvent) {
   MOZ_LOG(
       sContentCacheLog, LogLevel::Info,
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -159,30 +159,38 @@ class ContentCache {
   // Stores first char rect because Yosemite's Japanese IME sometimes tries
   // to query it.  If there is no text, this is caret rect.
   LayoutDeviceIntRect mFirstCharRect;
 
   struct Caret final {
     uint32_t mOffset;
     LayoutDeviceIntRect mRect;
 
-    Caret() : mOffset(UINT32_MAX) {}
+    explicit Caret(uint32_t aOffset, LayoutDeviceIntRect aCaretRect)
+        : mOffset(aOffset), mRect(aCaretRect) {}
+
+    uint32_t Offset() const { return mOffset; }
+    bool HasRect() const { return !mRect.IsEmpty(); }
 
-    void Clear() {
-      mOffset = UINT32_MAX;
-      mRect.SetEmpty();
+    friend std::ostream& operator<<(std::ostream& aStream,
+                                    const Caret& aCaret) {
+      aStream << "{ mOffset=" << aCaret.mOffset;
+      if (aCaret.HasRect()) {
+        aStream << ", mRect=" << aCaret.mRect;
+      }
+      return aStream << " }";
     }
 
-    bool IsValid() const { return mOffset != UINT32_MAX; }
+   private:
+    Caret() = default;
 
-    uint32_t Offset() const {
-      NS_ASSERTION(IsValid(), "The caller should check if the caret is valid");
-      return mOffset;
-    }
-  } mCaret;
+    friend struct IPC::ParamTraits<ContentCache::Caret>;
+    friend struct IPC::ParamTraits<Maybe<ContentCache::Caret>>;
+  };
+  Maybe<Caret> mCaret;
 
   struct TextRectArray final {
     uint32_t mStart;
     RectArray mRects;
 
     TextRectArray() : mStart(UINT32_MAX) {}
 
     void Clear() {
@@ -238,16 +246,17 @@ class ContentCache {
   TextRectArray mTextRectArray;
   TextRectArray mLastCommitStringTextRectArray;
 
   LayoutDeviceIntRect mEditorRect;
 
   friend class ContentCacheInParent;
   friend struct IPC::ParamTraits<ContentCache>;
   friend struct IPC::ParamTraits<ContentCache::Selection>;
+  friend struct IPC::ParamTraits<ContentCache::Caret>;
   friend std::ostream& operator<<(
       std::ostream& aStream,
       const Selection& aSelection);  // For e(Prev|Next)CharRect
 };
 
 class ContentCacheInChild final : public ContentCache {
  public:
   ContentCacheInChild() = default;
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -1055,41 +1055,55 @@ struct ParamTraits<mozilla::ContentCache
            ReadParam(aMsg, aIter, &aResult->mAnchorCharRects[1]) &&
            ReadParam(aMsg, aIter, &aResult->mFocusCharRects[0]) &&
            ReadParam(aMsg, aIter, &aResult->mFocusCharRects[1]) &&
            ReadParam(aMsg, aIter, &aResult->mRect);
   }
 };
 
 template <>
+struct ParamTraits<mozilla::ContentCache::Caret> {
+  typedef mozilla::ContentCache::Caret paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam) {
+    WriteParam(aMsg, aParam.mOffset);
+    WriteParam(aMsg, aParam.mRect);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter,
+                   paramType* aResult) {
+    return ReadParam(aMsg, aIter, &aResult->mOffset) &&
+           ReadParam(aMsg, aIter, &aResult->mRect);
+  }
+};
+
+template <>
 struct ParamTraits<mozilla::ContentCache> {
   typedef mozilla::ContentCache paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mCompositionStart);
     WriteParam(aMsg, aParam.mText);
     WriteParam(aMsg, aParam.mSelection);
     WriteParam(aMsg, aParam.mFirstCharRect);
-    WriteParam(aMsg, aParam.mCaret.mOffset);
-    WriteParam(aMsg, aParam.mCaret.mRect);
+    WriteParam(aMsg, aParam.mCaret);
     WriteParam(aMsg, aParam.mTextRectArray.mStart);
     WriteParam(aMsg, aParam.mTextRectArray.mRects);
     WriteParam(aMsg, aParam.mLastCommitStringTextRectArray.mStart);
     WriteParam(aMsg, aParam.mLastCommitStringTextRectArray.mRects);
     WriteParam(aMsg, aParam.mEditorRect);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
     return ReadParam(aMsg, aIter, &aResult->mCompositionStart) &&
            ReadParam(aMsg, aIter, &aResult->mText) &&
            ReadParam(aMsg, aIter, &aResult->mSelection) &&
            ReadParam(aMsg, aIter, &aResult->mFirstCharRect) &&
-           ReadParam(aMsg, aIter, &aResult->mCaret.mOffset) &&
-           ReadParam(aMsg, aIter, &aResult->mCaret.mRect) &&
+           ReadParam(aMsg, aIter, &aResult->mCaret) &&
            ReadParam(aMsg, aIter, &aResult->mTextRectArray.mStart) &&
            ReadParam(aMsg, aIter, &aResult->mTextRectArray.mRects) &&
            ReadParam(aMsg, aIter,
                      &aResult->mLastCommitStringTextRectArray.mStart) &&
            ReadParam(aMsg, aIter,
                      &aResult->mLastCommitStringTextRectArray.mRects) &&
            ReadParam(aMsg, aIter, &aResult->mEditorRect);
   }