Bug 1166436 part.7 mozilla::ContentCache should handle WidgetQueryContentEvent r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 05 Jun 2015 18:28:19 +0900
changeset 279715 73f252ed199632ba8d3e8557b6baaed6be18db42
parent 279714 cc5d3ee81d5132225e66dc35f0efa800f050ad33
child 279716 7acbb10cf6d63d2ab600f360f5055462b89c1373
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [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.7 mozilla::ContentCache should handle WidgetQueryContentEvent r=m_kato
dom/ipc/TabParent.cpp
widget/ContentCache.cpp
widget/ContentCache.h
widget/TextEvents.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2174,125 +2174,35 @@ TabParent::RecvDispatchAfterKeyboardEven
       localEvent.message != NS_KEY_PRESS) {
     presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
                                           aEvent.mFlags.mDefaultPrevented);
   }
 
   return true;
 }
 
-/**
- * Try to answer query event using cached text.
- *
- * 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.)
- *
- * For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with
- *  the queried range. Note the difference from above. We use
- *  this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to
- *  have out-of-bounds offsets, so that widget can request content without
- *  knowing the exact length of text. It's up to widget to handle cases when
- *  the returned offset/length are different from the queried offset/length.
- *
- * For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input.
- *   Cocoa widget always queries selected offset, so it works on it.
- *
- * For NS_QUERY_CARET_RECT, fail if cached offset isn't equals to input
- *
- * For NS_QUERY_EDITOR_RECT, always success
- */
 bool
 TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
 {
-  aEvent.mSucceeded = false;
-  aEvent.mWasAsync = false;
-  aEvent.mReply.mFocusedWidget = nsCOMPtr<nsIWidget>(GetWidget()).get();
-
-  switch (aEvent.message)
-  {
-  case NS_QUERY_SELECTED_TEXT:
-    {
-      aEvent.mReply.mOffset = mContentCache.SelectionStart();
-      if (mContentCache.SelectionCollapsed()) {
-        aEvent.mReply.mString.Truncate(0);
-      } else {
-        if (NS_WARN_IF(mContentCache.SelectionEndIsGraterThanTextLength())) {
-          break;
-        }
-        aEvent.mReply.mString = Substring(mContentCache.Text(),
-                                          aEvent.mReply.mOffset,
-                                          mContentCache.SelectionLength());
-      }
-      aEvent.mReply.mReversed = mContentCache.SelectionReversed();
-      aEvent.mReply.mHasSelection = true;
-      aEvent.mReply.mWritingMode = mContentCache.SelectionWritingMode();
-      aEvent.mSucceeded = true;
-    }
-    break;
-  case NS_QUERY_TEXT_CONTENT:
-    {
-      uint32_t inputOffset = aEvent.mInput.mOffset,
-               inputEnd = inputOffset + aEvent.mInput.mLength;
-
-      if (inputEnd > mContentCache.TextLength()) {
-        inputEnd = mContentCache.TextLength();
-      }
-      if (inputEnd < inputOffset) {
-        break;
-      }
-      aEvent.mReply.mOffset = inputOffset;
-      aEvent.mReply.mString = Substring(mContentCache.Text(),
-                                        inputOffset,
-                                        inputEnd - inputOffset);
-      aEvent.mSucceeded = true;
-    }
-    break;
-  case NS_QUERY_TEXT_RECT:
-    {
-      if (!mContentCache.GetUnionTextRects(aEvent.mInput.mOffset,
-                                           aEvent.mInput.mLength,
-                                           aEvent.mReply.mRect)) {
-        // XXX We don't have cache for this request.
-        break;
-      }
-      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;
+  nsCOMPtr<nsIWidget> widget = GetWidget();
+  if (!widget) {
+    return true;
+  }
+  if (NS_WARN_IF(!mContentCache.HandleQueryContentEvent(aEvent, widget)) ||
+      NS_WARN_IF(!aEvent.mSucceeded)) {
+    return true;
+  }
+  switch (aEvent.message) {
+    case NS_QUERY_TEXT_RECT:
+    case NS_QUERY_CARET_RECT:
+    case NS_QUERY_EDITOR_RECT:
       aEvent.mReply.mRect -= GetChildProcessOffset();
-      // XXX This may be wrong if storing range isn't in the selection range.
-      aEvent.mReply.mWritingMode = mContentCache.SelectionWritingMode();
-      aEvent.mSucceeded = true;
-    }
-    break;
-  case NS_QUERY_CARET_RECT:
-    {
-      if (!mContentCache.GetCaretRect(aEvent.mInput.mOffset,
-                                      aEvent.mReply.mRect)) {
-        break;
-      }
-
-      aEvent.mReply.mOffset = aEvent.mInput.mOffset;
-      aEvent.mReply.mRect -= GetChildProcessOffset();
-      aEvent.mSucceeded = true;
-    }
-    break;
-  case NS_QUERY_EDITOR_RECT:
-    {
-      aEvent.mReply.mRect =
-        mContentCache.GetEditorRect() - GetChildProcessOffset();
-      aEvent.mSucceeded = true;
-    }
-    break;
+      break;
+    default:
+      break;
   }
   return true;
 }
 
 bool
 TabParent::SendCompositionEvent(WidgetCompositionEvent& event)
 {
   if (mIsDestroyed) {
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -26,16 +26,90 @@ ContentCache::ContentCache()
 }
 
 void
 ContentCache::Clear()
 {
   mText.Truncate();
 }
 
+bool
+ContentCache::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
+                                      nsIWidget* aWidget) const
+{
+  MOZ_ASSERT(aWidget);
+
+  aEvent.mSucceeded = false;
+  aEvent.mWasAsync = false;
+  aEvent.mReply.mFocusedWidget = aWidget;
+
+  switch (aEvent.message) {
+    case NS_QUERY_SELECTED_TEXT:
+      aEvent.mReply.mOffset = mSelection.StartOffset();
+      if (mSelection.Collapsed()) {
+        aEvent.mReply.mString.Truncate(0);
+      } else {
+        if (NS_WARN_IF(SelectionEndIsGraterThanTextLength())) {
+          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;
+      break;
+    case NS_QUERY_TEXT_CONTENT: {
+      uint32_t inputOffset = aEvent.mInput.mOffset;
+      uint32_t inputEndOffset =
+        std::min(aEvent.mInput.EndOffset(), mText.Length());
+      if (NS_WARN_IF(inputEndOffset < inputOffset)) {
+        return false;
+      }
+      aEvent.mReply.mOffset = inputOffset;
+      aEvent.mReply.mString =
+        Substring(mText, inputOffset, inputEndOffset - inputOffset);
+      break;
+    }
+    case NS_QUERY_TEXT_RECT:
+      if (NS_WARN_IF(!GetUnionTextRects(aEvent.mInput.mOffset,
+                                        aEvent.mInput.mLength,
+                                        aEvent.mReply.mRect))) {
+        // XXX We don't have cache for this request.
+        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;
+      break;
+    case NS_QUERY_CARET_RECT:
+      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.
+        return false;
+      }
+      aEvent.mReply.mOffset = aEvent.mInput.mOffset;
+      break;
+    case NS_QUERY_EDITOR_RECT:
+      aEvent.mReply.mRect = mEditorRect;
+      break;
+  }
+  aEvent.mSucceeded = true;
+  return true;
+}
+
 void
 ContentCache::SetText(const nsAString& aText)
 {
   mText = aText;
 }
 
 void
 ContentCache::SetSelection(uint32_t aAnchorOffset,
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -31,16 +31,40 @@ class ContentCache final
 {
 public:
   typedef InfallibleTArray<LayoutDeviceIntRect> RectArray;
 
   ContentCache();
 
   void Clear();
 
+  /**
+   * 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.)
+   *
+   * For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with
+   *  the queried range. Note the difference from above. We use
+   *  this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to
+   *  have out-of-bounds offsets, so that widget can request content without
+   *  knowing the exact length of text. It's up to widget to handle cases when
+   *  the returned offset/length are different from the queried offset/length.
+   *
+   * For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input.
+   *   Cocoa widget always queries selected offset, so it works on it.
+   *
+   * 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;
+
   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.
    */
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -538,16 +538,19 @@ public:
   bool mSucceeded;
   bool mWasAsync;
   bool mUseNativeLineBreak;
   bool mWithFontRanges;
   struct
   {
     uint32_t EndOffset() const
     {
+      if (NS_WARN_IF(static_cast<uint64_t>(mOffset) + mLength > UINT32_MAX)) {
+        return UINT32_MAX;
+      }
       return mOffset + mLength;
     }
 
     uint32_t mOffset;
     uint32_t mLength;
   } mInput;
 
   struct Reply