Enable PeekOffset to find the visual beginning/end of a line, and use use it for bidi caret positioning. bug=302051 r=smontagu sr=roc

This commit is contained in:
uriber%gmail.com 2006-08-03 06:24:11 +00:00
parent 5defba927b
commit cee7609648
4 changed files with 46 additions and 35 deletions

View File

@ -731,19 +731,15 @@ nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode,
// if there is no frameBefore, we must be at the beginning of the line
// so we stay with the current frame.
// Exception: when the first frame on the line has a different Bidi level from the paragraph level, there is no
// real frame for the caret to be in. We have to find the first frame whose level is the same as the
// paragraph level, and put the caret at the end of the frame before that.
// real frame for the caret to be in. We have to find the visually first frame on the line.
PRUint8 baseLevel = NS_GET_BASE_LEVEL(frameAfter);
if (baseLevel != levelAfter)
{
if (NS_SUCCEEDED(frameSelection->GetFrameFromLevel(frameAfter, eDirNext, baseLevel, &theFrame)))
{
theFrame->GetOffsets(start, end);
levelAfter = NS_GET_EMBEDDING_LEVEL(theFrame);
if (baseLevel & 1) // RTL paragraph: caret to the right of the rightmost character
theFrameOffset = (levelAfter & 1) ? start : end;
else // LTR paragraph: caret to the left of the leftmost character
theFrameOffset = (levelAfter & 1) ? end : start;
nsPeekOffsetStruct pos;
pos.SetData(eSelectBeginLine, eDirPrevious, 0, 0, PR_FALSE, PR_TRUE, PR_FALSE, PR_TRUE);
if (NS_SUCCEEDED(frameAfter->PeekOffset(presContext, &pos))) {
theFrame = pos.mResultFrame;
theFrameOffset = pos.mContentOffset;
}
}
}
@ -766,22 +762,16 @@ nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode,
{
// if there is no frameAfter, we must be at the end of the line
// so we stay with the current frame.
//
// Exception: when the last frame on the line has a different Bidi level from the paragraph level, there is no
// real frame for the caret to be in. We have to find the last frame whose level is the same as the
// paragraph level, and put the caret at the end of the frame after that.
// real frame for the caret to be in. We have to find the visually last frame on the line.
PRUint8 baseLevel = NS_GET_BASE_LEVEL(frameBefore);
if (baseLevel != levelBefore)
{
if (NS_SUCCEEDED(frameSelection->GetFrameFromLevel(frameBefore, eDirPrevious, baseLevel, &theFrame)))
{
theFrame->GetOffsets(start, end);
levelBefore = NS_GET_EMBEDDING_LEVEL(theFrame);
if (baseLevel & 1) // RTL paragraph: caret to the left of the leftmost character
theFrameOffset = (levelBefore & 1) ? end : start;
else // RTL paragraph: caret to the right of the rightmost character
theFrameOffset = (levelBefore & 1) ? start : end;
nsPeekOffsetStruct pos;
pos.SetData(eSelectEndLine, eDirNext, 0, 0, PR_FALSE, PR_TRUE, PR_FALSE, PR_TRUE);
if (NS_SUCCEEDED(frameBefore->PeekOffset(presContext, &pos))) {
theFrame = pos.mResultFrame;
theFrameOffset = pos.mContentOffset;
}
}
}

View File

@ -4364,17 +4364,35 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
nsIFrame *firstFrame;
nsRect usedRect;
PRUint32 lineFlags;
it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
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;
PRBool endOfLine = (eSelectEndLine == aPos->mAmount);
#ifdef IBMBIDI
if (aPos->mVisual && aPresContext->BidiEnabled()) {
PRBool lineIsRTL;
it->GetDirection(&lineIsRTL);
PRBool isReordered;
nsIFrame *lastFrame;
result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
baseFrame = endOfLine ? lastFrame : firstFrame;
nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
// If the direction of the frame on the edge is opposite to that of the line,
// we'll need to drill down to its opposite end, so reverse endOfLine.
if ((embeddingLevel & 1) == !lineIsRTL)
endOfLine = !endOfLine;
} else
#endif
{
it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect, &lineFlags);
nsIFrame* frame = firstFrame;
for (PRInt32 count = lineFrameCount; count;
--count, frame = frame->GetNextSibling()) {
if (!frame->IsGeneratedContentFrame()) {
baseFrame = frame;
if (!endOfLine)
break;
}
}
}
if (!baseFrame)
@ -4384,6 +4402,7 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
FrameContentRange range = GetRangeForFrame(targetFrame.frame);
aPos->mResultContent = range.content;
aPos->mContentOffset = endOfLine ? range.end : range.start;
aPos->mResultFrame = targetFrame.frame;
aPos->mAttachForward = (aPos->mContentOffset == range.start);
if (!range.content)
return NS_ERROR_FAILURE;

View File

@ -125,7 +125,7 @@ struct nsPeekOffsetStruct
PRBool mIsKeyboardSelect;
// mVisual: Whether bidi caret behavior is visual (PR_TRUE) or logical (PR_FALSE).
// Used with: eSelectCharacter, eSelectWord.
// Used with: eSelectCharacter, eSelectWord, eSelectBeginLine, eSelectEndLine.
PRBool mVisual;
// mWordMovementType: An enum that determines whether to prefer the start or end of a word

View File

@ -1264,8 +1264,10 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
PRBool visualMovement =
(aKeycode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE ||
aKeycode == nsIDOMKeyEvent::DOM_VK_DELETE) ?
PR_FALSE : // Delete operations are always logical
aKeycode == nsIDOMKeyEvent::DOM_VK_DELETE ||
aKeycode == nsIDOMKeyEvent::DOM_VK_HOME ||
aKeycode == nsIDOMKeyEvent::DOM_VK_END) ?
PR_FALSE : // Delete operations and home/end are always logical
mCaretMovementStyle == 1 || (mCaretMovementStyle == 2 && !aContinueSelection);
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking