Bug 1168891 Part 1 - Refine two functions related to caret positioning. r=mats

FindFirstNodeWithFrame() and CompareRangeWithContentOffset() share a lot
of code duplication. I refactor and rename the two functions to improve
the readability.

MozReview-Commit-ID: CyetLHOGT23

--HG--
extra : rebase_source : e026acc87347253bcc795538ea06cbbd68634227
This commit is contained in:
Ting-Yu Lin 2016-04-11 17:57:29 +08:00
Родитель 72f541b831
Коммит 0f764ef889
2 изменённых файлов: 86 добавлений и 95 удалений

Просмотреть файл

@ -341,10 +341,12 @@ AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
AC_LOG("%s: selection: %p", __FUNCTION__, GetSelection());
int32_t startOffset = 0;
nsIFrame* startFrame = FindFirstNodeWithFrame(false, &startOffset);
nsIFrame* startFrame =
GetFrameForFirstRangeStartOrLastRangeEnd(eDirNext, &startOffset);
int32_t endOffset = 0;
nsIFrame* endFrame = FindFirstNodeWithFrame(true, &endOffset);
nsIFrame* endFrame =
GetFrameForFirstRangeStartOrLastRangeEnd(eDirPrevious, &endOffset);
if (!CompareTreePosition(startFrame, endFrame)) {
// XXX: Do we really have to hide carets if this condition isn't satisfied?
@ -864,41 +866,51 @@ AccessibleCaretManager::FlushLayout() const
}
nsIFrame*
AccessibleCaretManager::FindFirstNodeWithFrame(bool aBackward,
int32_t* aOutOffset) const
AccessibleCaretManager::GetFrameForFirstRangeStartOrLastRangeEnd(
nsDirection aDirection, int32_t* aOutOffset, nsINode** aOutNode,
int32_t* aOutNodeOffset) const
{
if (!mPresShell) {
return nullptr;
}
MOZ_ASSERT(GetCaretMode() == CaretMode::Selection);
nsRange* range = nullptr;
RefPtr<nsINode> startNode;
RefPtr<nsINode> endNode;
int32_t nodeOffset = 0;
CaretAssociationHint hint;
RefPtr<Selection> selection = GetSelection();
if (!selection) {
return nullptr;
bool findInFirstRangeStart = aDirection == eDirNext;
if (findInFirstRangeStart) {
range = selection->GetRangeAt(0);
startNode = range->GetStartParent();
endNode = range->GetEndParent();
nodeOffset = range->StartOffset();
hint = CARET_ASSOCIATE_AFTER;
} else {
range = selection->GetRangeAt(selection->RangeCount() - 1);
startNode = range->GetEndParent();
endNode = range->GetStartParent();
nodeOffset = range->EndOffset();
hint = CARET_ASSOCIATE_BEFORE;
}
RefPtr<nsFrameSelection> fs = GetFrameSelection();
if (!fs) {
return nullptr;
}
uint32_t rangeCount = selection->RangeCount();
if (rangeCount <= 0) {
return nullptr;
}
nsRange* range = selection->GetRangeAt(aBackward ? rangeCount - 1 : 0);
RefPtr<nsINode> startNode =
aBackward ? range->GetEndParent() : range->GetStartParent();
RefPtr<nsINode> endNode =
aBackward ? range->GetStartParent() : range->GetEndParent();
int32_t offset = aBackward ? range->EndOffset() : range->StartOffset();
nsCOMPtr<nsIContent> startContent = do_QueryInterface(startNode);
CaretAssociationHint hintStart =
aBackward ? CARET_ASSOCIATE_BEFORE : CARET_ASSOCIATE_AFTER;
RefPtr<nsFrameSelection> fs = GetFrameSelection();
nsIFrame* startFrame =
fs->GetFrameForNodeOffset(startContent, offset, hintStart, aOutOffset);
fs->GetFrameForNodeOffset(startContent, nodeOffset, hint, aOutOffset);
if (startFrame) {
if (aOutNode) {
*aOutNode = startNode.get();
}
if (aOutNodeOffset) {
*aOutNodeOffset = nodeOffset;
}
return startFrame;
}
@ -912,7 +924,8 @@ AccessibleCaretManager::FindFirstNodeWithFrame(bool aBackward,
startFrame = startContent ? startContent->GetPrimaryFrame() : nullptr;
while (!startFrame && startNode != endNode) {
startNode = aBackward ? walker->PreviousNode(err) : walker->NextNode(err);
startNode = findInFirstRangeStart ? walker->NextNode(err)
: walker->PreviousNode(err);
if (!startNode) {
break;
@ -925,78 +938,50 @@ AccessibleCaretManager::FindFirstNodeWithFrame(bool aBackward,
}
bool
AccessibleCaretManager::CompareRangeWithContentOffset(nsIFrame::ContentOffsets& aOffsets)
AccessibleCaretManager::RestrictCaretDraggingOffsets(
nsIFrame::ContentOffsets& aOffsets)
{
Selection* selection = GetSelection();
if (!selection) {
if (!mPresShell) {
return false;
}
uint32_t rangeCount = selection->RangeCount();
MOZ_ASSERT(rangeCount > 0);
int32_t rangeIndex = (mActiveCaret == mFirstCaret.get() ? rangeCount - 1 : 0);
RefPtr<nsRange> range = selection->GetRangeAt(rangeIndex);
MOZ_ASSERT(GetCaretMode() == CaretMode::Selection);
nsDirection dir = mActiveCaret == mFirstCaret.get() ? eDirPrevious : eDirNext;
int32_t offset = 0;
nsINode* node = nullptr;
int32_t nodeOffset = 0;
CaretAssociationHint hint;
nsDirection dir;
int32_t contentOffset = 0;
nsIFrame* frame =
GetFrameForFirstRangeStartOrLastRangeEnd(dir, &offset, &node, &contentOffset);
if (mActiveCaret == mFirstCaret.get()) {
// Check previous character of end node offset
node = range->GetEndParent();
nodeOffset = range->EndOffset();
hint = CARET_ASSOCIATE_BEFORE;
dir = eDirPrevious;
} else {
// Check next character of start node offset
node = range->GetStartParent();
nodeOffset = range->StartOffset();
hint = CARET_ASSOCIATE_AFTER;
dir = eDirNext;
if (!frame) {
return false;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
RefPtr<nsFrameSelection> fs = GetFrameSelection();
if (!fs) {
return false;
}
int32_t offset = 0;
nsIFrame* theFrame =
fs->GetFrameForNodeOffset(content, nodeOffset, hint, &offset);
if (!theFrame) {
return false;
}
// Move one character forward/backward from point and get offset
nsPeekOffsetStruct pos(eSelectCluster,
dir,
offset,
nsPoint(0, 0),
true,
true, //limit on scrolled views
false,
false,
false);
nsresult rv = theFrame->PeekOffset(&pos);
// Move one character (in the direction of dir) from the inactive caret's
// position. This is the limit for the active caret's new position.
nsPeekOffsetStruct limit(eSelectCluster, dir, offset, nsPoint(0, 0), true, true,
false, false, false);
nsresult rv = frame->PeekOffset(&limit);
if (NS_FAILED(rv)) {
pos.mResultContent = content;
pos.mContentOffset = nodeOffset;
limit.mResultContent = content;
limit.mContentOffset = contentOffset;
}
// Compare with current point
int32_t result = nsContentUtils::ComparePoints(aOffsets.content,
aOffsets.StartOffset(),
pos.mResultContent,
pos.mContentOffset);
if ((mActiveCaret == mFirstCaret.get() && result == 1) ||
(mActiveCaret == mSecondCaret.get() && result == -1)) {
aOffsets.content = pos.mResultContent;
aOffsets.offset = pos.mContentOffset;
aOffsets.secondaryOffset = pos.mContentOffset;
// Compare the active caret's new position (aOffsets) to the limit.
int32_t cmpToLimit =
nsContentUtils::ComparePoints(aOffsets.content, aOffsets.StartOffset(),
limit.mResultContent, limit.mContentOffset);
if ((mActiveCaret == mFirstCaret.get() && cmpToLimit == 1) ||
(mActiveCaret == mSecondCaret.get() && cmpToLimit == -1)) {
// The active caret's position is past the limit, which we don't allow
// here. So set it to the limit, resulting in one character being
// selected.
aOffsets.content = limit.mResultContent;
aOffsets.offset = limit.mContentOffset;
aOffsets.secondaryOffset = limit.mContentOffset;
}
return true;
@ -1066,7 +1051,7 @@ AccessibleCaretManager::DragCaretInternal(const nsPoint& aPoint)
}
if (GetCaretMode() == CaretMode::Selection &&
!CompareRangeWithContentOffset(offsets)) {
!RestrictCaretDraggingOffsets(offsets)) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -157,10 +157,13 @@ protected:
void SetSelectionDragState(bool aState) const;
void SetSelectionDirection(nsDirection aDir) const;
// If aBackward is false, find the first node from the first range in current
// selection, and return the frame and the offset into that frame. If aBackward
// is true, find the last node from the last range instead.
nsIFrame* FindFirstNodeWithFrame(bool aBackward, int32_t* aOutOffset) const;
// If aDirection is eDirNext, get the frame for the range start in the first
// range from the current selection, and return the offset into that frame as
// well as the range start node and the node offset. Otherwise, get the frame
// and offset for the range end in the last range instead.
nsIFrame* GetFrameForFirstRangeStartOrLastRangeEnd(
nsDirection aDirection, int32_t* aOutOffset, nsINode** aOutNode = nullptr,
int32_t* aOutNodeOffset = nullptr) const;
nsresult DragCaretInternal(const nsPoint& aPoint);
nsPoint AdjustDragBoundary(const nsPoint& aPoint) const;
@ -179,11 +182,14 @@ protected:
// be dragged. Returns the rect relative to aFrame.
nsRect GetAllChildFrameRectsUnion(nsIFrame* aFrame) const;
// If we're dragging the first caret, we do not want to drag it over the
// previous character of the second caret. Same as the second caret. So we
// check if content offset exceeds the previous/next character of second/first
// caret base the active caret.
bool CompareRangeWithContentOffset(nsIFrame::ContentOffsets& aOffsets);
// Suppose the user is dragging the first caret. We do not want it to be
// dragged across the second caret, i.e. we want it to stop at the limit which
// is the previous character of the second caret. Same rule applies when
// dragging the second caret.
// @param aOffsets is the new position of the active caret, and it will be set
// to the limit if it's being dragged past the limit.
// @return true if the aOffsets is suitable for changing the selection.
bool RestrictCaretDraggingOffsets(nsIFrame::ContentOffsets& aOffsets);
// Timeout in milliseconds to hide the AccessibleCaret under cursor mode while
// no one touches it.