зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
72f541b831
Коммит
0f764ef889
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче