Bug 1203871 - Part 2. Implement eQueryTextRectArray. r=masayuki draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Thu, 23 Jun 2016 10:40:04 +0100
changeset 380802 20cd5777d0088a8c5eb22f4f5c74111af05125c2
parent 380801 ea0cad756e4a26ec2f2f5a1cfa0a36bd132c9675
child 380803 6b6cfbba6777d267b0e884444be41079be06dba8
push id21331
push userm_kato@ga2.so-net.ne.jp
push dateThu, 23 Jun 2016 12:36:21 +0000
reviewersmasayuki
bugs1203871
milestone50.0a1
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()