зеркало из https://github.com/mozilla/gecko-dev.git
Bug 329031 - home/end/ctrl+home/ctrl+end offset calculation cleanup. r=uriber, sr=roc.
This commit is contained in:
Родитель
718a68e83c
Коммит
96bf85b6ac
|
@ -2607,6 +2607,22 @@ nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
|
|||
return offsets;
|
||||
}
|
||||
|
||||
static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
|
||||
nsIFrame* adjustedFrame = aFrame;
|
||||
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
|
||||
{
|
||||
// These are the conditions that make all children not able to handle
|
||||
// a cursor.
|
||||
if (frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE ||
|
||||
frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL ||
|
||||
frame->IsGeneratedContentFrame()) {
|
||||
adjustedFrame = frame;
|
||||
}
|
||||
}
|
||||
return adjustedFrame;
|
||||
}
|
||||
|
||||
|
||||
nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint)
|
||||
{
|
||||
// This section of code deals with special selection styles. Note that
|
||||
|
@ -2615,23 +2631,11 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint)
|
|||
// The offset is forced not to end up in generated content; content offsets
|
||||
// cannot represent content outside of the document's content tree.
|
||||
|
||||
nsIFrame* adjustedFrame = this;
|
||||
PRBool frameAdjusted = PR_FALSE;
|
||||
for (nsIFrame* frame = this; frame; frame = frame->GetParent())
|
||||
{
|
||||
// These are the conditions that make all children not able to handle
|
||||
// a cursor.
|
||||
if (frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE ||
|
||||
frame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_ALL ||
|
||||
frame->IsGeneratedContentFrame()) {
|
||||
adjustedFrame = frame;
|
||||
frameAdjusted = PR_TRUE;
|
||||
}
|
||||
}
|
||||
nsIFrame* adjustedFrame = AdjustFrameForSelectionStyles(this);
|
||||
|
||||
// -moz-user-select: all needs special handling, because clicking on it
|
||||
// should lead to the whole frame being selected
|
||||
if (adjustedFrame->GetStyleUIReset()->mUserSelect ==
|
||||
if (adjustedFrame && adjustedFrame->GetStyleUIReset()->mUserSelect ==
|
||||
NS_STYLE_USER_SELECT_ALL) {
|
||||
return OffsetsForSingleFrame(adjustedFrame, aPoint +
|
||||
this->GetOffsetTo(adjustedFrame));
|
||||
|
@ -2639,7 +2643,7 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint)
|
|||
|
||||
// For other cases, try to find a closest frame starting from the parent of
|
||||
// the unselectable frame
|
||||
if (frameAdjusted)
|
||||
if (adjustedFrame != this)
|
||||
adjustedFrame = adjustedFrame->GetParent();
|
||||
|
||||
nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
|
||||
|
@ -4038,57 +4042,11 @@ nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(PRBool aStart)
|
|||
{
|
||||
nsPeekOffsetStruct result;
|
||||
|
||||
result.mResultContent = this->GetContent();
|
||||
result.mContentOffset = 0;
|
||||
|
||||
nsIFrame *resultFrame = this;
|
||||
|
||||
if (aStart)
|
||||
nsFrame::GetFirstLeaf(GetPresContext(), &resultFrame);
|
||||
else
|
||||
nsFrame::GetLastLeaf(GetPresContext(), &resultFrame);
|
||||
|
||||
NS_ASSERTION(resultFrame,"result frame for carent positioning is Null!");
|
||||
|
||||
if (!resultFrame)
|
||||
return result;
|
||||
|
||||
// there should be some more validity checks here, or earlier in the code,
|
||||
// in case we get to to some 'dummy' frames at the end of the content
|
||||
|
||||
nsIContent* content = resultFrame->GetContent();
|
||||
|
||||
NS_ASSERTION(resultFrame,"result frame content for carent positioning is Null!");
|
||||
|
||||
if (!content)
|
||||
return result;
|
||||
|
||||
// special case: if this is not a textnode,
|
||||
// position the caret to the offset of its parent instead
|
||||
// (position the caret to non-text element may make the caret missing)
|
||||
|
||||
if (!content->IsContentOfType(nsIContent::eTEXT)) {
|
||||
// special case in effect
|
||||
nsIContent* parent = content->GetParent();
|
||||
NS_ASSERTION(parent,"element has no parent!");
|
||||
if (parent) {
|
||||
result.mResultContent = parent;
|
||||
result.mContentOffset = parent->IndexOf(content);
|
||||
if (!aStart)
|
||||
result.mContentOffset++; // go to end of this frame
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result.mResultContent = content;
|
||||
|
||||
PRInt32 start, end;
|
||||
nsresult rv;
|
||||
rv = resultFrame->GetOffsets(start,end);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
result.mContentOffset = aStart ? start : end;
|
||||
}
|
||||
|
||||
FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart);
|
||||
FrameContentRange range = GetRangeForFrame(targetFrame.frame);
|
||||
result.mResultContent = range.content;
|
||||
result.mContentOffset = aStart ? range.start : range.end;
|
||||
result.mPreferLeft = (result.mContentOffset == range.start);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4219,94 +4177,6 @@ nsFrame::PeekOffsetParagraph(nsPresContext* aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
DrillDownToBeginningOfLine(nsIFrame* aFrame,
|
||||
nsPeekOffsetStruct* aPos)
|
||||
{
|
||||
if (!aFrame)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsIFrame *firstFrame = aFrame;
|
||||
nsFrame::GetFirstLeaf(aFrame->GetPresContext(), &firstFrame);
|
||||
|
||||
// If it isn't a text frame, return the offset to its content from its parent content
|
||||
if (firstFrame->GetType() != nsLayoutAtoms::textFrame)
|
||||
{
|
||||
nsIContent* content = firstFrame->GetContent();
|
||||
aPos->mResultContent = content->GetParent();
|
||||
aPos->mContentOffset = aPos->mResultContent->IndexOf(content);
|
||||
// This actually means "associate the caret with the element at
|
||||
// the offset" (the next element after this position). (BLECH!)
|
||||
// Do this because we're returning the position *before* the element
|
||||
// on the line and we want to stay on this line.
|
||||
aPos->mPreferLeft = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aPos->mResultContent = firstFrame->GetContent();
|
||||
PRInt32 startOffset, endOffset;
|
||||
nsresult rv = firstFrame->GetOffsets(startOffset, endOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
aPos->mContentOffset = startOffset;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// Line and paragraph selection (and probably several other cases)
|
||||
// can get a containing frame from a line iterator, but then need
|
||||
// to "drill down" to get the content and offset corresponding to
|
||||
// the last child subframe. Hence:
|
||||
static nsresult
|
||||
DrillDownToEndOfLine(nsIFrame* aFrame, PRInt32 aLineFrameCount,
|
||||
nsPeekOffsetStruct* aPos)
|
||||
{
|
||||
if (!aFrame)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsIFrame *prevFrame = aFrame;
|
||||
nsIFrame *currentFrame = aFrame;
|
||||
PRInt32 i;
|
||||
|
||||
for (i = 1; i < aLineFrameCount; i++) //already have 1st frame
|
||||
{
|
||||
prevFrame = currentFrame;
|
||||
currentFrame = currentFrame->GetNextSibling();
|
||||
NS_ASSERTION(currentFrame, "lineFrame Count lied to us from nsILineIterator!\n");
|
||||
}
|
||||
if (!currentFrame->GetRect().width) //this can happen with BR frames and or empty placeholder frames.
|
||||
{
|
||||
//if we do hit an empty frame then back up the current frame to the frame before it if there is one.
|
||||
currentFrame = prevFrame;
|
||||
}
|
||||
|
||||
nsFrame::GetLastLeaf(aFrame->GetPresContext(), ¤tFrame);
|
||||
|
||||
// If it isn't a text frame, return the offset to its content from its parent content
|
||||
if (currentFrame->GetType() != nsLayoutAtoms::textFrame)
|
||||
{
|
||||
nsIContent* content = currentFrame->GetContent();
|
||||
aPos->mResultContent = content->GetParent();
|
||||
aPos->mContentOffset = aPos->mResultContent->IndexOf(content);
|
||||
// This actually means "associate the caret with the element at
|
||||
// the offset" (the next element after this position). (BLECH!)
|
||||
// Do this because we're returning the position *before* the element
|
||||
// on the line and we want to stay on this line.
|
||||
aPos->mPreferLeft = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aPos->mResultContent = currentFrame->GetContent();
|
||||
PRInt32 startOffset, endOffset;
|
||||
nsresult rv = currentFrame->GetOffsets(startOffset, endOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
aPos->mContentOffset = endOffset;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
|
||||
{
|
||||
|
@ -4505,46 +4375,54 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
|
|||
case eSelectBeginLine:
|
||||
case eSelectEndLine:
|
||||
{
|
||||
nsCOMPtr<nsILineIteratorNavigator> it;
|
||||
nsIFrame* thisBlock = this;
|
||||
nsIFrame* blockFrame = GetParent();
|
||||
if (!blockFrame) //if at line 0 then nothing to do
|
||||
return NS_OK;
|
||||
result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
|
||||
while (NS_FAILED(result) && blockFrame)
|
||||
{
|
||||
nsCOMPtr<nsILineIteratorNavigator> it;
|
||||
// Adjusted so that the caret can't get confused when content changes
|
||||
nsIFrame* thisBlock;
|
||||
nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
|
||||
do {
|
||||
thisBlock = blockFrame;
|
||||
blockFrame = blockFrame->GetParent();
|
||||
result = NS_OK;
|
||||
if (blockFrame) {
|
||||
result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
|
||||
}
|
||||
}
|
||||
if (NS_FAILED(result) || !it || !blockFrame || !thisBlock)
|
||||
} while (NS_FAILED(result) && blockFrame);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
//this block is now one child down from blockframe
|
||||
//thisBlock is now one child down from blockFrame
|
||||
|
||||
PRInt32 thisLine;
|
||||
PRInt32 thisLine;
|
||||
result = it->FindLineContaining(thisBlock, &thisLine);
|
||||
if (NS_FAILED(result) || thisLine < 0 )
|
||||
return result;
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt32 lineFrameCount;
|
||||
nsIFrame *firstFrame;
|
||||
nsRect usedRect;
|
||||
nsRect usedRect;
|
||||
PRUint32 lineFlags;
|
||||
result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,usedRect,
|
||||
&lineFlags);
|
||||
it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
|
||||
|
||||
if (eSelectBeginLine == aPos->mAmount)
|
||||
{
|
||||
return DrillDownToBeginningOfLine(firstFrame, aPos);
|
||||
PRBool endOfLine = (eSelectEndLine == aPos->mAmount);
|
||||
nsIFrame* baseFrame = nsnull;
|
||||
nsIFrame* frame = firstFrame;
|
||||
for (PRInt32 count = lineFrameCount; count;
|
||||
--count, frame = frame->GetNextSibling()) {
|
||||
if (!frame->IsGeneratedContentFrame()) {
|
||||
baseFrame = frame;
|
||||
if (!endOfLine)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // eSelectEndLine
|
||||
{
|
||||
return DrillDownToEndOfLine(firstFrame, lineFrameCount, aPos);
|
||||
}
|
||||
return result;
|
||||
if (!baseFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
|
||||
endOfLine);
|
||||
FrameContentRange range = GetRangeForFrame(targetFrame.frame);
|
||||
aPos->mResultContent = range.content;
|
||||
aPos->mContentOffset = endOfLine ? range.end : range.start;
|
||||
aPos->mPreferLeft = (aPos->mContentOffset == range.start);
|
||||
if (!range.content)
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -1430,23 +1430,11 @@ nsSelection::MoveCaret(PRUint32 aKeycode, PRBool aContinueSelection, nsSelection
|
|||
return result;
|
||||
theFrame->GetOffsets(frameStart, frameEnd);
|
||||
|
||||
tHint = (HINT)pos.mPreferLeft;
|
||||
switch (aKeycode) {
|
||||
case nsIDOMKeyEvent::DOM_VK_HOME:
|
||||
case nsIDOMKeyEvent::DOM_VK_END:
|
||||
|
||||
// force the offset to the logical beginning (for HOME) or end (for END) of the frame
|
||||
// (if it is an RTL frame it will be at the visual beginning or end, which we don't want in this case)
|
||||
if (frameStart !=0 || frameEnd !=0) // Only do this for text frames
|
||||
{
|
||||
if (nsIDOMKeyEvent::DOM_VK_HOME == aKeycode)
|
||||
pos.mContentOffset = frameStart;
|
||||
else
|
||||
pos.mContentOffset = frameEnd;
|
||||
|
||||
// set the caret Bidi level to the paragraph embedding level
|
||||
mShell->SetCaretBidiLevel(NS_GET_BASE_LEVEL(theFrame));
|
||||
}
|
||||
// set the caret Bidi level to the paragraph embedding level
|
||||
mShell->SetCaretBidiLevel(NS_GET_BASE_LEVEL(theFrame));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
Загрузка…
Ссылка в новой задаче