Bug 1203871 - Part 2. Implement eQueryTextRectArray. r=masayuki
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Thu, 23 Jun 2016 10:40:04 +0100
changeset 302984 eeadf50643feb4def0137e1c38ad55422856cb2e
parent 302983 a1b865bc98fbd23770988d3ddbd0770630407713
child 302985 894a2784d498725b319fef5bdb613582e8ffa088
push id78947
push userm_kato@ga2.so-net.ne.jp
push dateWed, 29 Jun 2016 06:23:15 +0000
treeherdermozilla-inbound@99635fa90e92 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1203871
milestone50.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 1203871 - Part 2. Implement eQueryTextRectArray. r=masayuki It will use on ContentCache. Also, SetRangeFromFlatTextOffset issue will hanle on another bug. MozReview-Commit-ID: 9Yu8bLlcZS5
dom/events/ContentEventHandler.cpp
dom/events/ContentEventHandler.h
dom/events/EventStateManager.cpp
widget/EventMessageList.h
widget/TextEvents.h
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1194,16 +1194,18 @@ ContentEventHandler::HandleQueryContentE
     case eQuerySelectedText:
       return OnQuerySelectedText(aEvent);
     case eQueryTextContent:
       return OnQueryTextContent(aEvent);
     case eQueryCaretRect:
       return OnQueryCaretRect(aEvent);
     case eQueryTextRect:
       return OnQueryTextRect(aEvent);
+    case eQueryTextRectArray:
+      return OnQueryTextRectArray(aEvent);
     case eQueryEditorRect:
       return OnQueryEditorRect(aEvent);
     case eQueryContentState:
       return OnQueryContentState(aEvent);
     case eQuerySelectionAsTransferable:
       return OnQuerySelectionAsTransferable(aEvent);
     case eQueryCharacterAtPoint:
       return OnQueryCharacterAtPoint(aEvent);
@@ -1388,16 +1390,95 @@ static nsINode* AdjustTextRectNode(nsINo
       node = aNode->GetChildAt(childCount - 1);
       aNodeOffset = node->IsNodeOfType(nsINode::eTEXT) ?
         static_cast<int32_t>(static_cast<nsIContent*>(node)->TextLength()) : 1;
     }
   }
   return node;
 }
 
+static
+nsIFrame*
+GetFirstFrameInRange(nsRange* aRange)
+{
+  // used to iterate over all contents and their frames
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  iter->Init(aRange);
+
+  // get the starting frame
+  int32_t nodeOffset = aRange->StartOffset();
+  nsINode* node = iter->GetCurrentNode();
+  if (!node) {
+    node = AdjustTextRectNode(aRange->GetStartParent(), nodeOffset);
+  }
+  nsIFrame* firstFrame = nullptr;
+  GetFrameForTextRect(node, nodeOffset, true, &firstFrame);
+  return firstFrame;
+}
+
+nsresult
+ContentEventHandler::OnQueryTextRectArray(WidgetQueryContentEvent* aEvent)
+{
+  nsresult rv = Init(aEvent);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  LineBreakType lineBreakType = GetLineBreakType(aEvent);
+  RefPtr<nsRange> range = new nsRange(mRootContent);
+  uint32_t offset = aEvent->mInput.mOffset;
+
+  LayoutDeviceIntRect rect;
+  WritingMode writingMode;
+  while (aEvent->mInput.mLength > aEvent->mReply.mRectArray.Length()) {
+    rv = SetRangeFromFlatTextOffset(range, offset, 1, lineBreakType, true,
+                                    nullptr);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // get the starting frame
+    nsIFrame* firstFrame = GetFirstFrameInRange(range);
+    if (NS_WARN_IF(!firstFrame)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    // get the starting frame rect
+    nsRect frameRect(nsPoint(0, 0), firstFrame->GetRect().Size());
+    rv = ConvertToRootRelativeOffset(firstFrame, frameRect);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    int32_t nodeOffset = range->StartOffset();
+    AutoTArray<nsRect, 16> charRects;
+    rv = firstFrame->GetCharacterRectsInRange(
+           nodeOffset,
+           aEvent->mInput.mLength - aEvent->mReply.mRectArray.Length(),
+           charRects);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    for (size_t i = 0; i < charRects.Length(); i++) {
+      nsRect charRect = charRects[i];
+      charRect.x += frameRect.x;
+      charRect.y += frameRect.y;
+
+      rect = LayoutDeviceIntRect::FromUnknownRect(
+               charRect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()));
+
+      aEvent->mReply.mRectArray.AppendElement(rect);
+    }
+    offset += charRects.Length();
+  }
+  aEvent->mSucceeded = true;
+  return NS_OK;
+}
+
 nsresult
 ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
 {
   nsresult rv = Init(aEvent);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
--- a/dom/events/ContentEventHandler.h
+++ b/dom/events/ContentEventHandler.h
@@ -48,16 +48,18 @@ public:
   // eQuerySelectedText event handler
   nsresult OnQuerySelectedText(WidgetQueryContentEvent* aEvent);
   // eQueryTextContent event handler
   nsresult OnQueryTextContent(WidgetQueryContentEvent* aEvent);
   // eQueryCaretRect event handler
   nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent);
   // eQueryTextRect event handler
   nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent);
+  // eQueryTextRectArray event handler
+  nsresult OnQueryTextRectArray(WidgetQueryContentEvent* aEvent);
   // eQueryEditorRect event handler
   nsresult OnQueryEditorRect(WidgetQueryContentEvent* aEvent);
   // eQueryContentState event handler
   nsresult OnQueryContentState(WidgetQueryContentEvent* aEvent);
   // eQuerySelectionAsTransferable event handler
   nsresult OnQuerySelectionAsTransferable(WidgetQueryContentEvent* aEvent);
   // eQueryCharacterAtPoint event handler
   nsresult OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent);
@@ -294,13 +296,16 @@ protected:
                                int32_t aBaseOffset,
                                int32_t aXPStartOffset,
                                int32_t aXPEndOffset,
                                LineBreakType aLineBreakType);
   nsresult GenerateFlatFontRanges(nsRange* aRange,
                                   FontRangeArray& aFontRanges,
                                   uint32_t& aLength,
                                   LineBreakType aLineBreakType);
+  nsresult QueryTextRectByRange(nsRange* aRange,
+                                LayoutDeviceIntRect& aRect,
+                                WritingMode& aWritingMode);
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ContentEventHandler_h_
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -855,16 +855,17 @@ EventStateManager::HandleQueryContentEve
       // Will not be handled locally, remote the event
       GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
       return;
     // Following events have not been supported in e10s mode yet.
     case eQueryContentState:
     case eQuerySelectionAsTransferable:
     case eQueryCharacterAtPoint:
     case eQueryDOMWidgetHittest:
+    case eQueryTextRectArray:
       break;
     default:
       return;
   }
 
   // If there is an IMEContentObserver, we need to handle QueryContentEvent
   // with it.
   if (mIMEContentObserver) {
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -236,16 +236,19 @@ NS_EVENT_MESSAGE(eQuerySelectedText)
 NS_EVENT_MESSAGE(eQueryTextContent)
 // Query for the caret rect of nth insertion point. The offset of the result is
 // relative position from the top level widget.
 NS_EVENT_MESSAGE(eQueryCaretRect)
 // Query for the bounding rect of a range of characters. This works on any
 // valid character range given offset and length. Result is relative to top
 // level widget coordinates
 NS_EVENT_MESSAGE(eQueryTextRect)
+// Query for the bounding rect array of a range of characters.
+// Thiis similar event of eQueryTextRect.
+NS_EVENT_MESSAGE(eQueryTextRectArray)
 // Query for the bounding rect of the current focused frame. Result is relative
 // to top level widget coordinates
 NS_EVENT_MESSAGE(eQueryEditorRect)
 // Query for the current state of the content. The particular members of
 // mReply that are set for each query content event will be valid on success.
 NS_EVENT_MESSAGE(eQueryContentState)
 // Query for the selection in the form of a nsITransferable.
 NS_EVENT_MESSAGE(eQuerySelectionAsTransferable)
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -707,16 +707,26 @@ public:
 
   void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint)
   {
     NS_ASSERTION(mMessage == eQueryDOMWidgetHittest,
                  "wrong initializer is called");
     mRefPoint = aPoint;
   }
 
+  void InitForQueryTextRectArray(uint32_t aOffset, uint32_t aLength,
+                                 const Options& aOptions = Options())
+  {
+    NS_ASSERTION(mMessage == eQueryTextRectArray,
+                 "wrong initializer is called");
+    mInput.mOffset = aOffset;
+    mInput.mLength = aLength;
+    Init(aOptions);
+  }
+
   void RequestFontRanges()
   {
     NS_ASSERTION(mMessage == eQueryTextContent,
                  "not querying text content");
     mWithFontRanges = true;
   }
 
   uint32_t GetSelectionStart(void) const
@@ -828,16 +838,18 @@ public:
     // The return widget has the caret. This is set at all query events.
     nsIWidget* mFocusedWidget;
     // mozilla::WritingMode value at the end (focus) of the selection
     mozilla::WritingMode mWritingMode;
     // Used by eQuerySelectionAsTransferable
     nsCOMPtr<nsITransferable> mTransferable;
     // Used by eQueryTextContent with font ranges requested
     AutoTArray<mozilla::FontRange, 1> mFontRanges;
+    // Used by eQueryTextRectArray
+    nsTArray<mozilla::LayoutDeviceIntRect> mRectArray;
     // true if selection is reversed (end < start)
     bool mReversed;
     // true if the selection exists
     bool mHasSelection;
     // true if DOM element under mouse belongs to widget
     bool mWidgetIsHit;
 
     Reply()