Bug 1286464 part.3 Make static methods, AdjustTextRectNode() and GetFirstFrameInRange(), members of ContentEventHandler r=smaug

This patch makes the static methods members of ContentEventHandler because ContentEventHandler::NodePosition is useful for them.

* nsINode* AdjustTextRectNode(nsINode*, int32_t&) -> NodePosition GetNodeHavingFlatText(nsINode* int32_t)
* nsIFrame* GetFirstFrameInRange(nsRange*, int32_t&) -> FrameAndNodeOffset GetFirstFrameHavingFlatTextInRange(nsRange*)

So, this patch avoids unclear in/out arguments of them.

MozReview-Commit-ID: 7yWeIkRdGj

--HG--
extra : rebase_source : 635cec95ee9f3d73f619186925464ae17010e929
This commit is contained in:
Masayuki Nakano 2016-08-05 12:43:40 +09:00
parent 24e9e4a700
commit 92692b4cb4
2 changed files with 115 additions and 43 deletions

View File

@ -1375,43 +1375,70 @@ ContentEventHandler::OnQueryTextContent(WidgetQueryContentEvent* aEvent)
return NS_OK;
}
// Adjust to use a child node if possible
// to make the returned rect more accurate
static nsINode* AdjustTextRectNode(nsINode* aNode,
int32_t& aNodeOffset)
ContentEventHandler::NodePosition
ContentEventHandler::GetNodePositionHavingFlatText(
const NodePosition& aNodePosition)
{
int32_t childCount = int32_t(aNode->GetChildCount());
nsINode* node = aNode;
if (childCount) {
if (aNodeOffset < childCount) {
node = aNode->GetChildAt(aNodeOffset);
aNodeOffset = 0;
} else if (aNodeOffset == childCount) {
node = aNode->GetChildAt(childCount - 1);
aNodeOffset = node->IsNodeOfType(nsINode::eTEXT) ?
static_cast<int32_t>(static_cast<nsIContent*>(node)->TextLength()) : 1;
}
}
return node;
return GetNodePositionHavingFlatText(aNodePosition.mNode,
aNodePosition.mOffset);
}
static
nsIFrame*
GetFirstFrameInRange(nsRange* aRange, int32_t& aNodeOffset)
ContentEventHandler::NodePosition
ContentEventHandler::GetNodePositionHavingFlatText(nsINode* aNode,
int32_t aNodeOffset)
{
if (aNode->IsNodeOfType(nsINode::eTEXT)) {
return NodePosition(aNode, aNodeOffset);
}
int32_t childCount = static_cast<int32_t>(aNode->GetChildCount());
// If it's a empty element node, returns itself.
if (!childCount) {
MOZ_ASSERT(!aNodeOffset || aNodeOffset == 1);
return NodePosition(aNode, aNodeOffset);
}
// If there is a node at given position, return the start of it.
if (aNodeOffset < childCount) {
return NodePosition(aNode->GetChildAt(aNodeOffset), 0);
}
// If the offset represents "after" the node, we need to return the last
// child of it. For example, if a range is |<p>[<br>]</p>|, then, the
// end point is {<p>, 1}. In such case, callers need the <br> node.
if (aNodeOffset == childCount) {
NodePosition result;
result.mNode = aNode->GetChildAt(childCount - 1);
result.mOffset = result.mNode->IsNodeOfType(nsINode::eTEXT) ?
static_cast<int32_t>(result.mNode->AsContent()->TextLength()) : 1;
}
NS_WARNING("aNodeOffset is invalid value");
return NodePosition();
}
ContentEventHandler::FrameAndNodeOffset
ContentEventHandler::GetFirstFrameHavingFlatTextInRange(nsRange* aRange)
{
// used to iterate over all contents and their frames
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
iter->Init(aRange);
// get the starting frame
aNodeOffset = aRange->StartOffset();
nsINode* node = iter->GetCurrentNode();
if (!node) {
node = AdjustTextRectNode(aRange->GetStartParent(), aNodeOffset);
NodePosition nodePosition(iter->GetCurrentNode(), aRange->StartOffset());
if (!nodePosition.mNode) {
nodePosition =
GetNodePositionHavingFlatText(aRange->GetStartParent(),
nodePosition.mOffset);
if (NS_WARN_IF(!nodePosition.IsValid())) {
return FrameAndNodeOffset();
}
}
nsIFrame* firstFrame = nullptr;
GetFrameForTextRect(node, aNodeOffset, true, &firstFrame);
return firstFrame;
GetFrameForTextRect(nodePosition.mNode, nodePosition.mOffset,
true, &firstFrame);
return FrameAndNodeOffset(firstFrame, nodePosition.mOffset);
}
nsresult
@ -1436,9 +1463,8 @@ ContentEventHandler::OnQueryTextRectArray(WidgetQueryContentEvent* aEvent)
}
// get the starting frame
int32_t nodeOffset = -1;
nsIFrame* firstFrame = GetFirstFrameInRange(range, nodeOffset);
if (NS_WARN_IF(!firstFrame)) {
FrameAndNodeOffset firstFrame = GetFirstFrameHavingFlatTextInRange(range);
if (NS_WARN_IF(!firstFrame.IsValid())) {
return NS_ERROR_FAILURE;
}
@ -1450,8 +1476,8 @@ ContentEventHandler::OnQueryTextRectArray(WidgetQueryContentEvent* aEvent)
}
AutoTArray<nsRect, 16> charRects;
rv = firstFrame->GetCharacterRectsInRange(nodeOffset, kEndOffset - offset,
charRects);
rv = firstFrame->GetCharacterRectsInRange(firstFrame.mStartOffsetInNode,
kEndOffset - offset, charRects);
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(charRects.IsEmpty())) {
return rv;
}
@ -1498,13 +1524,18 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
iter->Init(range);
// get the starting frame
int32_t nodeOffset = range->StartOffset();
nsINode* node = iter->GetCurrentNode();
if (!node) {
node = AdjustTextRectNode(range->GetStartParent(), nodeOffset);
NodePosition startNodePosition(iter->GetCurrentNode(), range->StartOffset());
if (!startNodePosition.mNode) {
startNodePosition =
GetNodePositionHavingFlatText(range->GetStartParent(),
startNodePosition.mOffset);
if (NS_WARN_IF(!startNodePosition.IsValid())) {
return NS_ERROR_FAILURE;
}
}
nsIFrame* firstFrame = nullptr;
rv = GetFrameForTextRect(node, nodeOffset, true, &firstFrame);
rv = GetFrameForTextRect(startNodePosition.mNode, startNodePosition.mOffset,
true, &firstFrame);
NS_ENSURE_SUCCESS(rv, rv);
// get the starting frame rect
@ -1513,7 +1544,7 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
NS_ENSURE_SUCCESS(rv, rv);
nsRect frameRect = rect;
nsPoint ptOffset;
firstFrame->GetPointFromOffset(nodeOffset, &ptOffset);
firstFrame->GetPointFromOffset(startNodePosition.mOffset, &ptOffset);
// minus 1 to avoid creating an empty rect
if (firstFrame->GetWritingMode().IsVertical()) {
rect.y += ptOffset.y - 1;
@ -1524,10 +1555,14 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
}
// get the ending frame
nodeOffset = range->EndOffset();
node = AdjustTextRectNode(range->GetEndParent(), nodeOffset);
NodePosition endNodePosition =
GetNodePositionHavingFlatText(range->GetEndParent(), range->EndOffset());
if (NS_WARN_IF(!endNodePosition.IsValid())) {
return NS_ERROR_FAILURE;
}
nsIFrame* lastFrame = nullptr;
rv = GetFrameForTextRect(node, nodeOffset, range->Collapsed(), &lastFrame);
rv = GetFrameForTextRect(endNodePosition.mNode, endNodePosition.mOffset,
range->Collapsed(), &lastFrame);
NS_ENSURE_SUCCESS(rv, rv);
// iterate over all covered frames
@ -1536,14 +1571,14 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
if (!frame) {
do {
iter->Next();
node = iter->GetCurrentNode();
nsINode* node = iter->GetCurrentNode();
if (!node) {
break;
}
if (!node->IsNodeOfType(nsINode::eCONTENT)) {
continue;
}
frame = static_cast<nsIContent*>(node)->GetPrimaryFrame();
frame = node->AsContent()->GetPrimaryFrame();
} while (!frame && !iter->IsDone());
if (!frame) {
// this can happen when the end offset of the range is 0.
@ -1560,7 +1595,7 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
}
// get the ending frame rect
lastFrame->GetPointFromOffset(nodeOffset, &ptOffset);
lastFrame->GetPointFromOffset(endNodePosition.mOffset, &ptOffset);
// minus 1 to avoid creating an empty rect
if (lastFrame->GetWritingMode().IsVertical()) {
frameRect.height -= lastFrame->GetRect().height - ptOffset.y - 1;

View File

@ -304,6 +304,43 @@ protected:
nsresult QueryTextRectByRange(nsRange* aRange,
LayoutDeviceIntRect& aRect,
WritingMode& aWritingMode);
// Returns a node and position in the node for computing text rect.
NodePosition GetNodePositionHavingFlatText(const NodePosition& aNodePosition);
NodePosition GetNodePositionHavingFlatText(nsINode* aNode,
int32_t aNodeOffset);
struct MOZ_STACK_CLASS FrameAndNodeOffset final
{
// mFrame is safe since this can live in only stack class and
// ContentEventHandler doesn't modify layout after
// ContentEventHandler::Init() flushes pending layout. In other words,
// this struct shouldn't be used before calling
// ContentEventHandler::Init().
nsIFrame* mFrame;
// Start offset in the node of mFrame
int32_t mStartOffsetInNode;
FrameAndNodeOffset()
: mFrame(nullptr)
, mStartOffsetInNode(-1)
{
}
FrameAndNodeOffset(nsIFrame* aFrame, int32_t aStartOffsetInNode)
: mFrame(aFrame)
, mStartOffsetInNode(aStartOffsetInNode)
{
}
nsIFrame* operator->() { return mFrame; }
const nsIFrame* operator->() const { return mFrame; }
operator nsIFrame*() { return mFrame; }
operator const nsIFrame*() const { return mFrame; }
bool IsValid() const { return mFrame && mStartOffsetInNode >= 0; }
};
// Get first frame in the given range for computing text rect.
FrameAndNodeOffset GetFirstFrameHavingFlatTextInRange(nsRange* aRange);
};
} // namespace mozilla