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
--- 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()