Refactor nsIFrame::PeekOfset to use iteration instead of recursion, and some related refactoring. bug=300131 r+sr=roc

This commit is contained in:
uriber%gmail.com 2006-09-11 06:39:56 +00:00
Родитель 3768f6338f
Коммит 95b377fc13
11 изменённых файлов: 611 добавлений и 642 удалений

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

@ -511,7 +511,7 @@ PRInt32 nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell, nsIFr
kIsJumpLinesOk,
kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi,
wordMovementType);
nsresult rv = aFromFrame->PeekOffset(aPresShell->GetPresContext(), &pos);
nsresult rv = aFromFrame->PeekOffset(&pos);
PRInt32 resultOffset = pos.mContentOffset;
nsIContent *resultContent = nsnull;

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

@ -719,7 +719,7 @@ nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode,
{
nsPeekOffsetStruct pos;
pos.SetData(eSelectBeginLine, eDirPrevious, 0, 0, PR_FALSE, PR_TRUE, PR_FALSE, PR_TRUE);
if (NS_SUCCEEDED(frameAfter->PeekOffset(presContext, &pos))) {
if (NS_SUCCEEDED(frameAfter->PeekOffset(&pos))) {
theFrame = pos.mResultFrame;
theFrameOffset = pos.mContentOffset;
}
@ -751,7 +751,7 @@ nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode,
{
nsPeekOffsetStruct pos;
pos.SetData(eSelectEndLine, eDirNext, 0, 0, PR_FALSE, PR_TRUE, PR_FALSE, PR_TRUE);
if (NS_SUCCEEDED(frameBefore->PeekOffset(presContext, &pos))) {
if (NS_SUCCEEDED(frameBefore->PeekOffset(&pos))) {
theFrame = pos.mResultFrame;
theFrameOffset = pos.mContentOffset;
}

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

@ -66,8 +66,10 @@ public:
virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
NS_IMETHOD PeekOffset(nsPresContext* aPresContext,
nsPeekOffsetStruct *aPos);
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset);
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType);
NS_IMETHOD Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -207,42 +209,35 @@ nsIFrame::ContentOffsets BRFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoin
return offsets;
}
NS_IMETHODIMP BRFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
PRBool
BRFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset)
{
if (!aPos)
return NS_ERROR_NULL_POINTER;
//BR is also a whitespace, but sometimes GetNextWord() can't handle this
//See bug 304891
nsTextTransformer::Initialize();
if (aPos->mWordMovementType != eDefaultBehavior) {
// aPos->mWordMovementType possible values:
// eEndWord: eat the space if we're moving backwards
// eStartWord: eat the space if we're moving forwards
if ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious)) {
aPos->mEatingWS = PR_TRUE;
}
}
else if (aPos->mDirection == eDirNext && nsTextTransformer::GetWordSelectEatSpaceAfter()) {
// Use the hidden preference which is based on operating system behavior.
// This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
// When going backwards, the start of the word is always used, on every operating system.
aPos->mEatingWS = PR_TRUE;
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
PRInt32 startOffset = *aOffset;
// If we hit the end of a BR going backwards, go to its beginning and stay there.
if (!aForward && startOffset != 0) {
*aOffset = 0;
return PR_TRUE;
}
// Otherwise, stop if we hit the beginning, continue (forward) if we hit the end.
return (startOffset == 0);
}
//offset of this content in its parents child list. base 0
PRInt32 offsetBegin = mContent->GetParent()->IndexOf(mContent);
PRBool
BRFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
{
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
// Keep going. The actual line jumping will stop us.
return PR_FALSE;
}
if (aPos->mAmount != eSelectLine && aPos->mAmount != eSelectBeginLine
&& aPos->mAmount != eSelectEndLine) //then we must do the adjustment to make sure we leave this frame
{
if (aPos->mDirection == eDirNext)
aPos->mStartOffset = offsetBegin +1;//go to end to make sure we jump to next node.
else
aPos->mStartOffset = offsetBegin; //we start at beginning to make sure we leave this frame.
}
return nsFrame::PeekOffset(aPresContext, aPos);//now we let the default take over.
PRBool
BRFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType)
{
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
// Keep going. The actual line jumping will stop us.
return PR_FALSE;
}
#ifdef ACCESSIBILITY

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

@ -2010,7 +2010,7 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
PR_TRUE, //limit on scrolled views
PR_FALSE,
PR_FALSE);
rv = PeekOffset(aPresContext, &startpos);
rv = PeekOffset(&startpos);
if (NS_FAILED(rv))
return rv;
nsPeekOffsetStruct endpos;
@ -2022,7 +2022,7 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
PR_TRUE, //limit on scrolled views
PR_FALSE,
PR_FALSE);
rv = PeekOffset(aPresContext, &endpos);
rv = PeekOffset(&endpos);
if (NS_FAILED(rv))
return rv;
@ -3767,7 +3767,9 @@ nsFrame::GetPointFromOffset(nsPresContext* inPresContext, nsIRenderingContext* i
if (newContent){
PRInt32 newOffset = newContent->IndexOf(mContent);
if (inOffset > newOffset)
PRBool isRTL = (NS_GET_EMBEDDING_LEVEL(this) & 1) == 1;
if (!isRTL && inOffset > newOffset ||
isRTL && inOffset <= newOffset)
bottomLeft.x = GetRect().width;
}
}
@ -4056,11 +4058,10 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
//we need to jump to new block frame.
aPos->mAmount = eSelectLine;
aPos->mStartOffset = 0;
aPos->mEatingWS = PR_FALSE;
aPos->mAttachForward = !(aPos->mDirection == eDirNext);
if (aPos->mDirection == eDirPrevious)
aPos->mStartOffset = -1;//start from end
return aBlockFrame->PeekOffset(aPresContext, aPos);
return aBlockFrame->PeekOffset(aPos);
}
}
return NS_OK;
@ -4140,8 +4141,7 @@ FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
}
nsresult
nsFrame::PeekOffsetParagraph(nsPresContext* aPresContext,
nsPeekOffsetStruct *aPos)
nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
{
nsIFrame* frame = this;
nsBlockFrame* bf; // used only for QI
@ -4208,62 +4208,137 @@ nsFrame::PeekOffsetParagraph(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
// Determine movement direction relative to frame
static PRBool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, PRBool aVisual)
{
PRBool isReverseDirection = aVisual ?
(NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : PR_FALSE;
return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
}
nsresult
nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
{
if (!aPos)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_ERROR_FAILURE;
switch (aPos->mAmount){
case eSelectCharacter : case eSelectWord:
if (mState & NS_FRAME_IS_DIRTY)
return NS_ERROR_UNEXPECTED;
// Translate content offset to be relative to frame
FrameContentRange range = GetRangeForFrame(this);
PRInt32 offset = aPos->mStartOffset - range.start;
nsIFrame* current = this;
switch (aPos->mAmount) {
case eSelectCharacter:
{
if (mContent)
{
nsIContent* newContent = mContent->GetParent();
if (newContent){
aPos->mResultContent = newContent;
PRBool eatingNonRenderableWS = PR_FALSE;
PRBool done = PR_FALSE;
while (!done) {
PRBool movingInFrameDirection =
IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
PRInt32 newOffset = newContent->IndexOf(mContent);
if (aPos->mDirection == eDirNext)
aPos->mContentOffset = newOffset + 1;
else
aPos->mContentOffset = newOffset;//to beginning of frame
nsTextTransformer::Initialize();
if (nsTextTransformer::GetWordSelectEatSpaceAfter() &&
aPos->mDirection == eDirNext && aPos->mEatingWS)
{
//If we want to stop at beginning of the next word
//GetFrameFromDirection should not return NS_ERROR_FAILURE
//at end of line
aPos->mEatingWS = PR_FALSE;
result = GetFrameFromDirection(aPresContext, aPos);
aPos->mEatingWS = PR_TRUE;
}
else
result = GetFrameFromDirection(aPresContext, aPos);
if (eatingNonRenderableWS)
done = current->PeekOffsetNoAmount(movingInFrameDirection, &offset);
else
done = current->PeekOffsetCharacter(movingInFrameDirection, &offset);
if (!done) {
PRBool jumpedLine;
result =
current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
aPos->mJumpLines, aPos->mScrollViewStop,
&current, &offset, &jumpedLine);
if (NS_FAILED(result))
return result;
PRBool selectable = PR_FALSE;
if (aPos->mResultFrame)
aPos->mResultFrame->IsSelectable(&selectable, nsnull);
if (NS_FAILED(result) || !aPos->mResultFrame || !selectable)
{
return result?result:NS_ERROR_FAILURE;
}
return aPos->mResultFrame->PeekOffset(aPresContext, aPos);
// If we jumped lines, it's as if we found a character, but we still need
// to eat non-renderable content on the new line.
if (jumpedLine)
eatingNonRenderableWS = PR_TRUE;
}
}
// Set outputs
range = GetRangeForFrame(current);
aPos->mResultFrame = current;
aPos->mResultContent = range.content;
// Output offset is relative to content, not frame
aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
break;
}
case eSelectNoAmount:
case eSelectWord:
{
FrameContentRange range = GetRangeForFrame(this);
// wordSelectEatSpace means "are we looking for a boundary between whitespace
// and non-whitespace (in the direction we're moving in)".
// It is true when moving forward and looking for a beginning of a word, or
// when moving backwards and looking for an end of a word.
PRBool wordSelectEatSpace;
if (aPos->mWordMovementType != eDefaultBehavior) {
// aPos->mWordMovementType possible values:
// eEndWord: eat the space if we're moving backwards
// eStartWord: eat the space if we're moving forwards
wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
}
else {
// Use the hidden preference which is based on operating system behavior.
// This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
// When going backwards, the start of the word is always used, on every operating system.
nsTextTransformer::Initialize();
wordSelectEatSpace = aPos->mDirection == eDirNext && nsTextTransformer::GetWordSelectEatSpaceAfter();
}
// sawBeforeType means "we already saw characters of the type
// before the boundary we're looking for". Examples:
// 1. If we're moving forward, looking for a word beginning (i.e. a boundary
// between whitespace and non-whitespace), then eatingWS==PR_TRUE means
// "we already saw some whitespace".
// 2. If we're moving backward, looking for a word beginning (i.e. a boundary
// between non-whitespace and whitespace), then eatingWS==PR_TRUE means
// "we already saw some non-whitespace".
PRBool sawBeforeType = PR_FALSE;
PRBool done = PR_FALSE;
while (!done) {
PRBool movingInFrameDirection =
IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace, aPos->mIsKeyboardSelect,
&offset, &sawBeforeType);
if (!done) {
nsIFrame* nextFrame;
PRInt32 nextFrameOffset;
PRBool jumpedLine;
result =
current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
aPos->mJumpLines, aPos->mScrollViewStop,
&nextFrame, &nextFrameOffset, &jumpedLine);
// We can't jump lines if we're looking for whitespace following
// non-whitespace, and we already encountered non-whitespace.
if (NS_FAILED(result) ||
jumpedLine && !wordSelectEatSpace && sawBeforeType) {
done = PR_TRUE;
} else {
current = nextFrame;
offset = nextFrameOffset;
// Jumping a line is equivalent to encountering whitespace
if (wordSelectEatSpace && jumpedLine)
sawBeforeType = PR_TRUE;
}
}
}
// Set outputs
range = GetRangeForFrame(current);
aPos->mResultFrame = current;
aPos->mResultContent = range.content;
aPos->mContentOffset = range.start;
result = range.content ? NS_OK : NS_ERROR_FAILURE;
// Output offset is relative to content, not frame
aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
break;
}
case eSelectLine :
@ -4272,23 +4347,24 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
nsIFrame *blockFrame = this;
while (NS_FAILED(result)){
PRInt32 thisLine = GetLineNumber(blockFrame, &blockFrame);
PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, &blockFrame);
if (thisLine < 0)
return NS_ERROR_FAILURE;
result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(iter));
NS_ASSERTION(NS_SUCCEEDED(result) && iter, "GetLineNumber() succeeded but no block frame?");
int edgeCase = 0;//no edge case. this should look at thisLine
PRBool doneLooping = PR_FALSE;//tells us when no more block frames hit.
//this part will find a frame or a block frame. if it's a block frame
//it will "drill down" to find a viable frame or it will return an error.
nsIFrame *lastFrame = this;
do {
result = GetNextPrevLineFromeBlockFrame(aPresContext,
aPos,
blockFrame,
thisLine,
edgeCase //start from thisLine
result = nsFrame::GetNextPrevLineFromeBlockFrame(GetPresContext(),
aPos,
blockFrame,
thisLine,
edgeCase //start from thisLine
);
if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
{
@ -4353,11 +4429,11 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
}
} while (!doneLooping);
}
break;
return result;
}
case eSelectParagraph:
return PeekOffsetParagraph(aPresContext, aPos);
return PeekOffsetParagraph(aPos);
case eSelectBeginLine:
case eSelectEndLine:
@ -4365,7 +4441,7 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
nsCOMPtr<nsILineIteratorNavigator> it;
// Adjusted so that the caret can't get confused when content changes
nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
PRInt32 thisLine = GetLineNumber(blockFrame, &blockFrame);
PRInt32 thisLine = nsFrame::GetLineNumber(blockFrame, &blockFrame);
if (thisLine < 0)
return NS_ERROR_FAILURE;
result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
@ -4379,7 +4455,7 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
PRBool endOfLine = (eSelectEndLine == aPos->mAmount);
#ifdef IBMBIDI
if (aPos->mVisual && aPresContext->BidiEnabled()) {
if (aPos->mVisual && GetPresContext()->BidiEnabled()) {
PRBool lineIsRTL;
it->GetDirection(&lineIsRTL);
PRBool isReordered;
@ -4419,17 +4495,61 @@ nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
return NS_ERROR_FAILURE;
return NS_OK;
}
break;
default:
{
if (NS_SUCCEEDED(result))
result = aPos->mResultFrame->PeekOffset(aPresContext, aPos);
NS_ASSERTION(PR_FALSE, "Invalid amount");
return NS_ERROR_FAILURE;
}
}
return result;
}
return NS_OK;
}
PRBool
nsFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset)
{
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
// Sure, we can stop right here.
return PR_TRUE;
}
PRBool
nsFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
{
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
PRInt32 startOffset = *aOffset;
// A negative offset means "end of frame", which in our case means offset 1.
if (startOffset < 0)
startOffset = 1;
if (aForward == (startOffset == 0)) {
// We're before the frame and moving forward, or after it and moving backwards:
// skip to the other side and we're done.
*aOffset = 1 - startOffset;
return PR_TRUE;
}
return PR_FALSE;
}
PRBool
nsFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType)
{
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
PRInt32 startOffset = *aOffset;
if (startOffset < 0)
startOffset = 1;
if (aForward == (startOffset == 0)) {
// We're before the frame and moving forward, or after it and moving backwards.
// If we're looking for non-whitespace, we found it (without skipping this frame).
if (aWordSelectEatSpace && *aSawBeforeType)
return PR_TRUE;
// Otherwise skip to the other side and note that we encountered non-whitespace.
*aOffset = 1 - startOffset;
if (!aWordSelectEatSpace)
*aSawBeforeType = PR_TRUE;
}
return PR_FALSE;
}
NS_IMETHODIMP
nsFrame::CheckVisibility(nsPresContext* , PRInt32 , PRInt32 , PRBool , PRBool *, PRBool *)
@ -4476,8 +4596,18 @@ nsFrame::GetLineNumber(nsIFrame *aFrame, nsIFrame** aContainingBlock)
}
nsresult
nsIFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
{
nsIFrame::GetFrameFromDirection(nsDirection aDirection, PRBool aVisual,
PRBool aJumpLines, PRBool aScrollViewStop,
nsIFrame** aOutFrame, PRInt32* aOutOffset, PRBool* aOutJumpedLine)
{
if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
return NS_ERROR_NULL_POINTER;
nsPresContext* presContext = GetPresContext();
*aOutFrame = nsnull;
*aOutOffset = 0;
*aOutJumpedLine = PR_FALSE;
// Find the prev/next selectable frame
PRBool selectable = PR_FALSE;
nsIFrame *traversedFrame = this;
@ -4495,19 +4625,19 @@ nsIFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct
nsIFrame *firstFrame;
nsIFrame *lastFrame;
#ifdef IBMBIDI
if (aPos->mVisual && aPresContext->BidiEnabled()) {
if (aVisual && presContext->BidiEnabled()) {
PRBool lineIsRTL;
it->GetDirection(&lineIsRTL);
PRBool isReordered;
result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
nsIFrame** framePtr = aPos->mDirection == eDirPrevious ? &firstFrame : &lastFrame;
nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
if (*framePtr) {
nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
if (((embeddingLevel & 1) && lineIsRTL || !(embeddingLevel & 1) && !lineIsRTL) ==
(aPos->mDirection == eDirPrevious)) {
nsFrame::GetFirstLeaf(aPresContext, framePtr);
(aDirection == eDirPrevious)) {
nsFrame::GetFirstLeaf(presContext, framePtr);
} else {
nsFrame::GetLastLeaf(aPresContext, framePtr);
nsFrame::GetLastLeaf(presContext, framePtr);
}
atLineEdge = *framePtr == traversedFrame;
} else {
@ -4524,8 +4654,8 @@ nsIFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct
if (NS_FAILED(result))
return result;
if (aPos->mDirection == eDirPrevious) {
nsFrame::GetFirstLeaf(aPresContext, &firstFrame);
if (aDirection == eDirPrevious) {
nsFrame::GetFirstLeaf(presContext, &firstFrame);
atLineEdge = firstFrame == traversedFrame;
} else { // eDirNext
lastFrame = firstFrame;
@ -4536,43 +4666,36 @@ nsIFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct
return NS_ERROR_FAILURE;
}
}
nsFrame::GetLastLeaf(aPresContext, &lastFrame);
nsFrame::GetLastLeaf(presContext, &lastFrame);
atLineEdge = lastFrame == traversedFrame;
}
}
if (atLineEdge)
{
if (aPos->mJumpLines != PR_TRUE)
return NS_ERROR_FAILURE;//we are done. cannot jump lines
if (aPos->mAmount != eSelectWord)
{
aPos->mAmount = eSelectNoAmount;
}
else{
if (aPos->mEatingWS)//done finding what we wanted
return NS_ERROR_FAILURE;
}
if (atLineEdge) {
*aOutJumpedLine = PR_TRUE;
if (!aJumpLines)
return NS_ERROR_FAILURE; //we are done. cannot jump lines
}
nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
aPresContext, traversedFrame,
presContext, traversedFrame,
eLeaf,
aPos->mVisual && aPresContext->BidiEnabled(),
aPos->mScrollViewStop,
aVisual && presContext->BidiEnabled(),
aScrollViewStop,
PR_TRUE // aFollowOOFs
);
if (NS_FAILED(result))
return result;
nsISupports *isupports = nsnull;
if (aPos->mDirection == eDirNext)
if (aDirection == eDirNext)
result = frameTraversal->Next();
else
else
result = frameTraversal->Prev();
if (NS_FAILED(result))
return result;
nsISupports *isupports = nsnull;
result = frameTraversal->CurrentItem(&isupports);
if (NS_FAILED(result))
return result;
@ -4583,20 +4706,18 @@ nsIFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct
traversedFrame = (nsIFrame *)isupports;
traversedFrame->IsSelectable(&selectable, nsnull);
} // while (!selectable)
if (aPos->mDirection == eDirNext)
aPos->mStartOffset = 0;
else
aPos->mStartOffset = -1;
*aOutOffset = (aDirection == eDirNext) ? 0 : -1;
#ifdef IBMBIDI
if (aPos->mVisual) {
if (aVisual) {
PRUint8 newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
PRUint8 newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
aPos->mStartOffset = -1 - aPos->mStartOffset;
*aOutOffset = -1 - *aOutOffset;
}
#endif
aPos->mResultFrame = traversedFrame;
*aOutFrame = traversedFrame;
return NS_OK;
}

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

@ -250,11 +250,14 @@ public:
NS_IMETHOD IsSelectable(PRBool* aIsSelectable, PRUint8* aSelectStyle) const;
NS_IMETHOD GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon);
NS_IMETHOD PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos) ;
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset);
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType);
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
NS_IMETHOD PeekOffsetParagraph(nsPresContext* aPresContext,
nsPeekOffsetStruct *aPos);
NS_IMETHOD GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const;
NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild);

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

@ -91,7 +91,6 @@ struct nsPeekOffsetStruct
mIsKeyboardSelect = aIsKeyboardSelect;
mVisual = aVisual;
mWordMovementType = aWordMovementType;
mEatingWS = PR_FALSE;
}
// Note: Most arguments (input and output) are only used with certain values
@ -105,6 +104,14 @@ struct nsPeekOffsetStruct
nsSelectionAmount mAmount;
// mDirection: eDirPrevious or eDirNext.
// * Note for visual bidi movement:
// eDirPrevious means 'left-then-up' if the containing block is LTR,
// 'right-then-up' if it is RTL.
// eDirNext means 'right-then-down' if the containing block is LTR,
// 'left-then-down' if it is RTL.
// Between paragraphs, eDirPrevious means "go to the visual end of the
// previous paragraph", and eDirNext means "go to the visual beginning
// of the next paragraph".
// Used with: eSelectCharacter, eSelectWord, eSelectLine, eSelectParagraph.
nsDirection mDirection;
@ -156,14 +163,6 @@ struct nsPeekOffsetStruct
// PR_TRUE means "the beginning of the frame logically after the caret".
// Used with: eSelectLine, eSelectBeginLine, eSelectEndLine.
PRBool mAttachForward;
/*** Arguments only used internally ***/
// mEatingWS: Used only internally, for recursive calls into PeekOffset.
// Shold be PR_FALSE upon initial call to PeekOffset.
// Used with: eSelectWord.
PRBool mEatingWS;
};
struct nsPrevNextBidiLevels

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

@ -100,10 +100,10 @@ struct nsMargin;
typedef class nsIFrame nsIBox;
// IID for the nsIFrame interface
// b7f1e31d-0dc8-466f-a46c-76a718a805a3
// 48813f12-5e55-46af-8527-c8f408bac999
#define NS_IFRAME_IID \
{ 0xb7f1e31d, 0x0dc8, 0x466f, \
{ 0xa4, 0x6c, 0x76, 0xa7, 0x18, 0xa8, 0x05, 0xa3 } }
{ 0x48813f12, 0x5e55, 0x46af, \
{ 0x85, 0x27, 0xc8, 0xf4, 0x08, 0xba, 0xc9, 0x99 } }
/**
* Indication of how the frame can be split. This is used when doing runaround
@ -1335,26 +1335,22 @@ public:
* return NS_ERROR_FAILURE
* @param aPOS is defined in nsFrameSelection
*/
NS_IMETHOD PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos) = 0;
nsresult PeekOffset(nsPeekOffsetStruct *aPos);
/**
* called to find the previous/next selectable leaf frame.
* @param aPOS is defined in nsFrameSelection.
* Fields of aPos used as input are:
* mAmount: should be either eSelectWord or eSelectCharacter
* mDirection: eDirPrevious or eDirNext
* mJumpLines: whether to allow jumping across line boundaries
* mScrollViewStop: whether to stop when reaching a scroll view boundary
* mVisual: whether bidi caret behavior is visual (PR_TRUE) or logical (PR_FALSE)
* mEatingWS: indicates whether we're seeking a boundary between
* non-whitespace and whitespace.
* Fields of aPos set as output are:
* mResultFrame: the previous/next selectable leaf frame
* mAmount: might be set to eSelectNone after crossing a line boundary
* mStartOffset: set to 0 or -1 to indicate which edge of the result frame
* is closer to "this" frame.
* @param aDirection [in] the direction to move in (eDirPrevious or eDirNext)
* @param aVisual [in] whether bidi caret behavior is visual (PR_TRUE) or logical (PR_FALSE)
* @param aJumpLines [in] whether to allow jumping across line boundaries
* @param aScrollViewStop [in] whether to stop when reaching a scroll frame boundary
* @param aOutFrame [out] the previous/next selectable leaf frame
* @param aOutOffset [out] 0 indicates that we arrived at the beginning of the output frame;
* -1 indicates that we arrived at its end.
* @param aOutJumpedLine [out] whether this frame and the returned frame are on different lines
*/
nsresult GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos);
nsresult GetFrameFromDirection(nsDirection aDirection, PRBool aVisual,
PRBool aJumpLines, PRBool aScrollViewStop,
nsIFrame** aOutFrame, PRInt32* aOutOffset, PRBool* aOutJumpedLine);
/**
* called to see if the children of the frame are visible from indexstart to index end.
@ -1704,7 +1700,60 @@ protected:
*/
void InvalidateRoot(const nsRect& aDamageRect,
nscoord aOffsetX, nscoord aOffsetY,
PRBool aImmediate);
PRBool aImmediate);
/**
* Can we stop inside this frame when we're skipping non-rendered whitespace?
* @param aForward [in] Are we moving forward (or backward) in content order.
* @param aOffset [in/out] At what offset into the frame to start looking.
* on output - what offset was reached (whether or not we found a place to stop).
* @return PR_TRUE: An appropriate offset was found within this frame,
* and is given by aOffset.
* PR_FALSE: Not found within this frame, need to try the next frame.
*/
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset) = 0;
/**
* Search the frame for the next character
* @param aForward [in] Are we moving forward (or backward) in content order.
* @param aOffset [in/out] At what offset into the frame to start looking.
* on output - what offset was reached (whether or not we found a place to stop).
* @return PR_TRUE: An appropriate offset was found within this frame,
* and is given by aOffset.
* PR_FALSE: Not found within this frame, need to try the next frame.
*/
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset) = 0;
/**
* Search the frame for the next word boundary
* @param aForward [in] Are we moving forward (or backward) in content order.
* @param aWordSelectEatSpace [in] PR_TRUE: look for non-whitespace following
* whitespace (in the direction of movement).
* PR_FALSE: look for whitespace following non-whitespace (in the
* direction of movement).
* @param aIsKeyboardSelect [in] Was the action initiated by a keyboard operation?
* If PR_TRUE, punctuation immediately following a word is considered part
* of that word. Otherwise, a sequence of punctuation is always considered
* as a word on its own.
* @param aOffset [in/out] At what offset into the frame to start looking.
* on output - what offset was reached (whether or not we found a place to stop).
* @param aSawBeforeType [in/out] Did we encounter a character of the pre-boundary type
* (whitespace if aWordSelectEatSpace is true, non-whitespace otherwise).
* @return PR_TRUE: An appropriate offset was found within this frame,
* and is given by aOffset.
* PR_FALSE: Not found within this frame, need to try the next frame.
*/
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType) = 0;
/**
* Search for the first paragraph boundary before or after the given position
* @param aPos See description in nsFrameSelection.h. The following fields are
* used by this method:
* Input: mDirection
* Output: mResultContent, mContentOffset
*/
nsresult PeekOffsetParagraph(nsPeekOffsetStruct *aPos);
private:
NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;

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

@ -175,6 +175,22 @@ nsInlineFrame::IsEmpty()
return PR_TRUE;
}
PRBool
nsInlineFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
{
// Override the implementation in nsFrame, to skip empty inline frames
NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
PRInt32 startOffset = *aOffset;
if (startOffset < 0)
startOffset = 1;
if (aForward == (startOffset == 0)) {
// We're before the frame and moving forward, or after it and moving backwards:
// skip to the other side, but keep going.
*aOffset = 1 - startOffset;
}
return PR_FALSE;
}
NS_IMETHODIMP
nsInlineFrame::AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList)

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

@ -48,7 +48,7 @@
class nsAnonymousBlockFrame;
#define NS_INLINE_FRAME_CID \
{ 0xa6cf90e0, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
{ 0x88b298af, 0x8b0e, 0x4592,{0x9e, 0xc6, 0xea, 0x4c, 0x4b, 0x3f, 0xf7, 0xa4}}
#define nsInlineFrameSuper nsHTMLContainerFrame
@ -113,6 +113,8 @@ public:
virtual PRBool IsEmpty();
virtual PRBool IsSelfEmpty();
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
// nsIHTMLReflow overrides
NS_IMETHOD Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,

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

@ -1287,9 +1287,6 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
}
}
offsetused = mDomSelections[index]->FetchFocusOffset();
weakNodeUsed = mDomSelections[index]->FetchFocusNode();
PRBool visualMovement =
(aKeycode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE ||
aKeycode == nsIDOMKeyEvent::DOM_VK_DELETE ||
@ -1349,7 +1346,7 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
default :return NS_ERROR_FAILURE;
}
PostReason(nsISelectionListener::KEYPRESS_REASON);
if (NS_SUCCEEDED(result = frame->PeekOffset(context, &pos)) && pos.mResultContent)
if (NS_SUCCEEDED(result = frame->PeekOffset(&pos)) && pos.mResultContent)
{
nsIFrame *theFrame;
PRInt32 currentOffset, frameStart, frameEnd;
@ -1416,6 +1413,8 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
result = TakeFocus(pos.mResultContent, pos.mContentOffset, pos.mContentOffset, aContinueSelection, PR_FALSE);
} else if (aKeycode == nsIDOMKeyEvent::DOM_VK_RIGHT && !aContinueSelection) {
// Collapse selection if PeekOffset failed because we bumped into the BRFrame, bug 207623.
weakNodeUsed = mDomSelections[index]->FetchFocusNode();
offsetused = mDomSelections[index]->FetchFocusOffset();
mDomSelections[index]->Collapse(weakNodeUsed, offsetused);
tHint = mHint; // make the line below restore the original hint
result = NS_OK;
@ -1548,10 +1547,8 @@ nsFrameSelection::VisualSequence(nsIFrame* aSelectFrame,
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsresult result = nsnull;
nsPresContext* presContext = mShell->GetPresContext();
PRUint8 currentLevel = NS_GET_EMBEDDING_LEVEL(aCurrentFrame);
result = aSelectFrame->PeekOffset(presContext, aPos);
result = aSelectFrame->PeekOffset(aPos);
while (aCurrentFrame != (aSelectFrame = aPos->mResultFrame))
{
if (NS_FAILED(result))
@ -1584,7 +1581,7 @@ nsFrameSelection::VisualSequence(nsIFrame* aSelectFrame,
aPos->mAmount = eSelectDir; // reset this because PeekOffset will have changed it to eSelectNoAmount
aPos->mContentOffset = 0;
result = aSelectFrame->PeekOffset(presContext, aPos);
result = aSelectFrame->PeekOffset(aPos);
}
return NS_OK;
@ -1654,19 +1651,17 @@ nsFrameSelection::SelectLines(nsDirection aSelectionDirection,
endOffset = aAnchorOffset;
}
nsPresContext* presContext = mShell->GetPresContext();
aPos.mStartOffset = startOffset;
aPos.mDirection = eDirNext;
aPos.mAmount = eSelectLine;
result = startFrame->PeekOffset(presContext, &aPos);
result = startFrame->PeekOffset(&aPos);
if (NS_FAILED(result))
return result;
startFrame = aPos.mResultFrame;
aPos.mStartOffset = aPos.mContentOffset;
aPos.mAmount = eSelectBeginLine;
result = startFrame->PeekOffset(presContext, &aPos);
result = startFrame->PeekOffset(&aPos);
if (NS_FAILED(result))
return result;
@ -1690,14 +1685,14 @@ nsFrameSelection::SelectLines(nsDirection aSelectionDirection,
aPos.mStartOffset = endOffset;
aPos.mDirection = eDirPrevious;
aPos.mAmount = eSelectLine;
result = endFrame->PeekOffset(presContext, &aPos);
result = endFrame->PeekOffset(&aPos);
if (NS_FAILED(result))
return result;
endFrame = aPos.mResultFrame;
aPos.mStartOffset = aPos.mContentOffset;
aPos.mAmount = eSelectEndLine;
result = endFrame->PeekOffset(presContext, &aPos);
result = endFrame->PeekOffset(&aPos);
if (NS_FAILED(result))
return result;
@ -1741,8 +1736,6 @@ nsFrameSelection::VisualSelectFrames(nsIFrame* aCurrentFrame,
nsDirection selectionDirection;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsPresContext* presContext = mShell->GetPresContext();
result = mDomSelections[index]->GetOriginalAnchorPoint(getter_AddRefs(anchorNode), &anchorOffset);
if (NS_FAILED(result))
return result;
@ -1818,7 +1811,7 @@ nsFrameSelection::VisualSelectFrames(nsIFrame* aCurrentFrame,
aPos.mStartOffset = anchorOffset;
aPos.mDirection = selectionDirection;
result = anchorFrame->PeekOffset(presContext, &aPos);
result = anchorFrame->PeekOffset(&aPos);
if (NS_FAILED(result))
return result;
@ -1970,20 +1963,14 @@ nsFrameSelection::GetPrevNextBidiLevels(nsIContent *aNode,
return levels;
}
nsPeekOffsetStruct pos;
pos.SetData(eSelectCharacter,
direction,
currentOffset,
0,
aJumpLines,
PR_TRUE, // aScrollViewStop
PR_FALSE, // aIsKeyboardSelect
PR_FALSE); // aVisual
nsresult rv = currentFrame->GetFrameFromDirection(mShell->GetPresContext(), &pos);
nsIFrame *newFrame = nsnull;
if (NS_SUCCEEDED(rv))
newFrame = pos.mResultFrame;
nsIFrame *newFrame;
PRInt32 offset;
PRBool jumpedLine;
nsresult rv = currentFrame->GetFrameFromDirection(direction, PR_FALSE,
aJumpLines, PR_TRUE,
&newFrame, &offset, &jumpedLine);
if (NS_FAILED(rv))
newFrame = nsnull;
PRUint8 baseLevel = NS_GET_BASE_LEVEL(currentFrame);
PRUint8 currentLevel = NS_GET_EMBEDDING_LEVEL(currentFrame);
@ -2299,7 +2286,7 @@ nsFrameSelection::HandleDrag(nsIFrame *aFrame, nsPoint aPoint)
pos.SetData(amount, direction, offset, 0,
PR_FALSE, mLimiter != nsnull, PR_FALSE, PR_FALSE);
if (frame && NS_SUCCEEDED(frame->PeekOffset(mShell->GetPresContext(), &pos)) && pos.mResultContent) {
if (frame && NS_SUCCEEDED(frame->PeekOffset(&pos)) && pos.mResultContent) {
offsets.content = pos.mResultContent;
offsets.offset = pos.mContentOffset;
}

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

@ -345,7 +345,11 @@ public:
PRBool aSelected,
nsSpread aSpread);
NS_IMETHOD PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos);
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset);
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType);
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const;
@ -4463,480 +4467,273 @@ nsTextFrame::GetChildFrameContainingOffset(PRInt32 inContentOffset,
return NS_OK;
}
NS_IMETHODIMP
nsTextFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
PRBool
nsTextFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset)
{
DEBUG_VERIFY_NOT_DIRTY(mState);
if (mState & NS_FRAME_IS_DIRTY)
return NS_ERROR_UNEXPECTED;
#ifdef IBMBIDI
// XXX TODO: - this explanation may not be accurate
// - need to better explain for what happens when you move
// from the end of a line to the beginning of the next
// despite not making a move logically within the text.
//
// When you move your caret by in some visual direction, and you find the
// new position is at the edge of a line (beginning or end), you usually
// want to stay on the current line rather than move to the next or the
// previous one; however, if you want to get to the edge of the next or
// the previous word (i.e. you're 'eating white space' when moving
// between words), and you couldn't find the word in the current line,
// you do _not_ want to stay on the current line - you want to get to that
// word.
//
// When your frames are ordered the same way logically as they are
// visually (e.g. when they're frames of LTR text displayed in
// left-then-down order), this translates to terms of 'prefer left' or
// 'prefer right', i.e. if you move to the left and hit the beginning of
// the line you have to choose between the frame "on the left" - the last
// frame on the previous line - and the frame "on the right" - the
// first frame of the current line.
//
// When the frames are displayed in right-then-down order (i.e. frames
// within an RTL line), the last sentence remains correct, but now
// the directions are reversed - if you're moving left, you hit the end
// of a line; the frame closer to your original position is the one
// "on the right" - the last frame on the current line - rather than the
// one "on the left" - the first frame on the next
// line.
//
// Note (for visual caret movement):
// eDirPrevious means 'left-then-up' if the containing block is LTR,
// 'right-then-up' if it is RTL.
// eDirNext means 'right-then-down' if the containing block is LTR,
// 'left-then-down' if it is RTL.
// Between paragraphs, eDirPrevious means "go to the visual end of the
// previous paragraph", and eDirNext means "go to the visual beginning of
// the next paragraph"
PRBool isReverseDirection = aPos->mVisual ?
(NS_GET_EMBEDDING_LEVEL(this) & 1) != (NS_GET_BASE_LEVEL(this) & 1) : PR_FALSE;
PRBool movementIsInFrameDirection =
((aPos->mDirection == eDirNext) && !isReverseDirection) ||
((aPos->mDirection == eDirPrevious) && isReverseDirection);
#endif
if (!aPos || !mContent)
return NS_ERROR_NULL_POINTER;
// XXX TODO: explain this policy; why the assymetry between
// too high and too low start offsets?
//
// There are 4 possible ranges of aPos->mStartOffset:
//
// 0 mContentOffset mContentOffset+mContentLength
// | | |
// range #1 | range #2 | range #3 | range #4
// ***************
// our frame's part
// of the content
//
// Range Policy
// ------------------------------------------------------------------------
// #1 Assume the start position is at the end of the content of 'this'
// #2 Round up the position to the beginning of our frame
// #3 No change necessary
// #4 Delegate the PeekOffset() to the next frame (according
// to the direction, either to our left or our right)
//
// Note: the diagram above is drawn left-to-right, but advancing
// in the content may sometimes mean going right-to-left
if (aPos->mStartOffset < 0 )
aPos->mStartOffset = mContentLength + mContentOffset;
if (aPos->mStartOffset < mContentOffset){
aPos->mStartOffset = mContentOffset;
}
if (aPos->mStartOffset > (mContentOffset + mContentLength)){
nsIFrame *nextContinuation = GetNextContinuation();
if (!nextContinuation){
NS_ASSERTION(PR_FALSE,"nsTextFrame::PeekOffset no more continuation\n");
return NS_ERROR_INVALID_ARG;
}
return nextContinuation->PeekOffset(aPresContext, aPos);
}
// XXX TODO: explain the following:
// - if this frame is the first of the last in the line according
// to the content indices, why not handle the cases of
// eSelectBeginLine/eSelectEndLine
// - why can't we make the hand-off to the parent class' method
// before correcting aPos->mStartOffset?
if (aPos->mAmount == eSelectLine || aPos->mAmount == eSelectBeginLine
|| aPos->mAmount == eSelectEndLine || aPos->mAmount == eSelectParagraph)
{
return nsFrame::PeekOffset(aPresContext, aPos);
}
NS_ASSERTION (aOffset && *aOffset <= mContentLength, "aOffset out of range");
nsAutoTextBuffer paintBuffer;
nsAutoIndexBuffer indexBuffer;
nsresult rv = indexBuffer.GrowTo(mContentLength + 1);
if (NS_FAILED(rv)) {
return rv;
}
return PR_FALSE;
}
PRInt32 textLength;
nsTextTransformer tx(GetPresContext());
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
return (textLength > 0);
}
PRBool
nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
{
NS_ASSERTION (aOffset && *aOffset <= mContentLength, "aOffset out of range");
PRInt32 startOffset = *aOffset;
// A negative offset means "end of frame".
if (startOffset < 0)
startOffset = mContentLength;
nsPresContext* presContext = GetPresContext();
// Transform text from content into renderable form
nsAutoTextBuffer paintBuffer;
nsAutoIndexBuffer indexBuffer;
nsresult rv = indexBuffer.GrowTo(mContentLength + 1);
if (NS_FAILED(rv)) {
return PR_FALSE;
}
PRInt32 textLength;
nsTextTransformer tx(presContext);
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
PRInt32* ip = indexBuffer.mBuffer;
PRInt32 textLength;
nsresult result(NS_ERROR_FAILURE);
aPos->mResultContent = mContent;//do this right off
switch (aPos->mAmount){
case eSelectNoAmount:
{
if (!IsEmpty()) //if no renderable length, you can't park here.
PRBool found = PR_TRUE;
PRBool selectable;
PRUint8 selectStyle;
IsSelectable(&selectable, &selectStyle);
if (selectStyle == NS_STYLE_USER_SELECT_ALL)
return PR_FALSE;
if (!aForward) {
*aOffset = 0;
PRInt32 i;
nsAutoPRUint8Buffer clusterBuffer;
rv = FillClusterBuffer(presContext, paintBuffer.mBuffer,
(PRUint32)textLength, clusterBuffer);
NS_ENSURE_SUCCESS(rv, rv);
for (i = startOffset-1; i >= 0; i--){
if ((ip[i] < ip[startOffset]) &&
(clusterBuffer.mBuffer[ip[i] - mContentOffset]) &&
(! IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i]-mContentOffset])))
{
aPos->mContentOffset = aPos->mStartOffset;
result = NS_OK;
}
else
{
result = GetFrameFromDirection(aPresContext, aPos);
if (NS_SUCCEEDED(result) && aPos->mResultFrame && aPos->mResultFrame!= this)
return aPos->mResultFrame->PeekOffset(aPresContext, aPos);
else if (NS_FAILED(result))
return result;
*aOffset = i;
break;
}
}
break;
case eSelectCharacter:
{
// Transform text from content into renderable form
nsIDocument* doc = mContent->GetDocument();
if (!doc) {
return NS_OK;
}
nsTextTransformer tx(aPresContext);
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
PRBool found = PR_TRUE;
PRBool selectable;
PRUint8 selectStyle;
IsSelectable(&selectable, &selectStyle);
if ( selectStyle == NS_STYLE_USER_SELECT_ALL )
found = PR_FALSE;
else
{
#ifdef IBMBIDI
if (!movementIsInFrameDirection){
#else
if (aPos->mDirection == eDirPrevious){
#endif
aPos->mContentOffset = 0;
PRInt32 i;
nsAutoPRUint8Buffer clusterBuffer;
rv = FillClusterBuffer(aPresContext, paintBuffer.mBuffer,
(PRUint32)textLength, clusterBuffer);
NS_ENSURE_SUCCESS(rv, rv);
for (i = aPos->mStartOffset -1 - mContentOffset; i >=0; i--){
if ((ip[i] < ip[aPos->mStartOffset - mContentOffset]) &&
(clusterBuffer.mBuffer[ip[i] - mContentOffset]) &&
(! IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i]-mContentOffset])))
{
aPos->mContentOffset = i + mContentOffset;
break;
}
}
#ifdef SUNCTL
static NS_DEFINE_CID(kLECID, NS_ULE_CID);
nsCOMPtr<nsILE> ctlObj;
ctlObj = do_CreateInstance(kLECID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Cell based cursor movement will not be supported\n");
ctlObj = nsnull;
}
else {
PRBool needsCTL = PR_FALSE;
PRInt32 previousOffset;
ctlObj->NeedsCTLFix(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
aPos->mStartOffset, -1, &needsCTL);
if (needsCTL) {
ctlObj->PrevCluster(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
textLength,aPos->mStartOffset,
&previousOffset);
aPos->mContentOffset = i = previousOffset;
}
}
#endif /* SUNCTL */
if (i <0){
found = PR_FALSE;
aPos->mContentOffset = mContentOffset;//in case next call fails we stop at this offset
}
}
#ifdef IBMBIDI
else if (movementIsInFrameDirection){
#else
else if (aPos->mDirection == eDirNext){
#endif
PRInt32 i;
aPos->mContentOffset = mContentLength;
nsAutoPRUint8Buffer clusterBuffer;
rv = FillClusterBuffer(aPresContext, paintBuffer.mBuffer,
(PRUint32)textLength, clusterBuffer);
NS_ENSURE_SUCCESS(rv, rv);
for (i = aPos->mStartOffset - mContentOffset; i <= mContentLength; i++) {
if ((ip[i] > ip[aPos->mStartOffset - mContentOffset]) &&
((i == mContentLength) ||
(!IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i] - mContentOffset])) &&
(clusterBuffer.mBuffer[ip[i] - mContentOffset]))) {
aPos->mContentOffset = i + mContentOffset;
break;
}
}
#ifdef SUNCTL
static NS_DEFINE_CID(kLECID, NS_ULE_CID);
nsCOMPtr<nsILE> ctlObj;
ctlObj = do_CreateInstance(kLECID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Cell based cursor movement will not be supported\n");
ctlObj = nsnull;
}
else {
PRBool needsCTL = PR_FALSE;
PRInt32 nextOffset;
ctlObj->NeedsCTLFix(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
aPos->mStartOffset, 0, &needsCTL);
if (needsCTL) {
ctlObj->NextCluster(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
textLength, aPos->mStartOffset,
&nextOffset);
aPos->mContentOffset = i = nextOffset;
}
}
#endif /* SUNCTL */
/* if (aStartOffset == 0 && (mState & TEXT_SKIP_LEADING_WS))
i--; //back up because we just skipped over some white space. why skip over the char also?
*/
if (i > mContentLength){
found = PR_FALSE;
aPos->mContentOffset = mContentOffset + mContentLength;//in case next call fails we stop at this offset
}
}
}
if (!found)
{
result = GetFrameFromDirection(aPresContext, aPos);
if (NS_SUCCEEDED(result) && aPos->mResultFrame && aPos->mResultFrame!= this)
{
return aPos->mResultFrame->PeekOffset(aPresContext, aPos);
}
}
else
aPos->mResultContent = mContent;
#ifdef SUNCTL
static NS_DEFINE_CID(kLECID, NS_ULE_CID);
nsCOMPtr<nsILE> ctlObj;
ctlObj = do_CreateInstance(kLECID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Cell based cursor movement will not be supported\n");
ctlObj = nsnull;
}
break;
case eSelectWord:
{
// Transform text from content into renderable form
nsIDocument* doc = mContent->GetDocument();
if (!doc) {
return result;
}
nsTextTransformer tx(aPresContext);
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
PRBool keepSearching; //if you run out of chars before you hit the end of word, maybe next frame has more text to select?
PRBool found = PR_FALSE;
PRBool isWhitespace, wasTransformed;
PRInt32 wordLen, contentLen;
PRBool wordSelectEatSpace;
if (aPos->mWordMovementType != eDefaultBehavior) {
// aPos->mWordMovementType possible values:
// eEndWord: eat the space if we're moving backwards
// eStartWord: eat the space if we're moving forwards
wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
}
else {
// Use the hidden preference which is based on operating system behavior.
// This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
// When going backwards, the start of the word is always used, on every operating system.
wordSelectEatSpace = aPos->mDirection == eDirNext && nsTextTransformer::GetWordSelectEatSpaceAfter();
}
else {
PRBool needsCTL = PR_FALSE;
PRInt32 previousOffset;
PRBool selectable;
PRUint8 selectStyle;
IsSelectable(&selectable, &selectStyle);
if ( selectStyle == NS_STYLE_USER_SELECT_ALL )
found = PR_FALSE;
else
{
ctlObj->NeedsCTLFix(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
mContentOffset + startOffset, -1, &needsCTL);
if (needsCTL) {
ctlObj->PrevCluster(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
textLength, mContentOffset + startOffset,
&previousOffset);
*aOffset = i = previousOffset - mContentOffset;
}
}
#endif /* SUNCTL */
if (i < 0)
found = PR_FALSE;
}
else // aForward
{
PRInt32 i;
*aOffset = mContentLength;
nsAutoPRUint8Buffer clusterBuffer;
rv = FillClusterBuffer(presContext, paintBuffer.mBuffer,
(PRUint32)textLength, clusterBuffer);
NS_ENSURE_SUCCESS(rv, rv);
for (i = startOffset; i <= mContentLength; i++) {
if ((ip[i] > ip[startOffset]) &&
((i == mContentLength) ||
(!IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i] - mContentOffset])) &&
(clusterBuffer.mBuffer[ip[i] - mContentOffset]))) {
*aOffset = i;
break;
}
}
#ifdef SUNCTL
static NS_DEFINE_CID(kLECID, NS_ULE_CID);
nsCOMPtr<nsILE> ctlObj;
ctlObj = do_CreateInstance(kLECID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Cell based cursor movement will not be supported\n");
ctlObj = nsnull;
}
else {
PRBool needsCTL = PR_FALSE;
PRInt32 nextOffset;
ctlObj->NeedsCTLFix(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
mContentOffset + startOffset, 0, &needsCTL);
if (needsCTL) {
ctlObj->NextCluster(NS_REINTERPRET_CAST(const PRUnichar*,
paintBuffer.mBuffer),
textLength, mContentOffset + startOffset,
&nextOffset);
*aOffset = i = nextOffset - mContentOffset;
}
}
#endif /* SUNCTL */
if (i > mContentLength)
found = PR_FALSE;
}
return found;
}
PRBool
nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
PRInt32* aOffset, PRBool* aSawBeforeType)
{
NS_ASSERTION (aOffset && *aOffset <= mContentLength, "aOffset out of range");
PRInt32 startOffset = *aOffset;
if (startOffset < 0)
startOffset = mContentLength;
nsTextTransformer tx(GetPresContext());
PRBool keepSearching = PR_TRUE; //if you run out of chars before you hit the end of word, maybe next frame has more text to select?
PRBool found = PR_FALSE;
PRBool isWhitespace, wasTransformed;
PRInt32 wordLen, contentLen;
PRBool selectable;
PRUint8 selectStyle;
IsSelectable(&selectable, &selectStyle);
if (selectStyle == NS_STYLE_USER_SELECT_ALL)
found = PR_FALSE;
else
{
tx.Init(this, mContent, mContentOffset + startOffset);
if (!aForward) {
*aOffset = 0; //initialize
#ifdef IBMBIDI
if (!movementIsInFrameDirection){
#else
if (aPos->mDirection == eDirPrevious){
#endif
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
#endif // IBMBIDI
if (tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace,
PR_FALSE, aIsKeyboardSelect) &&
contentLen <= startOffset) {
if ((aWordSelectEatSpace ? isWhitespace : !isWhitespace) || !*aSawBeforeType){
*aOffset = startOffset - contentLen;
keepSearching = PR_TRUE;
tx.Init(this, mContent, aPos->mStartOffset);
aPos->mContentOffset = mContentOffset;//initialize
if (aWordSelectEatSpace ? isWhitespace : !isWhitespace)
*aSawBeforeType = PR_TRUE;
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
#endif // IBMBIDI
if (tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace,
PR_FALSE, aPos->mIsKeyboardSelect) &&
(aPos->mStartOffset - contentLen >= mContentOffset) ){
if ((wordSelectEatSpace ? isWhitespace : !isWhitespace) || !aPos->mEatingWS){
aPos->mContentOffset = aPos->mStartOffset - contentLen;
keepSearching = PR_TRUE;
if (wordSelectEatSpace ? isWhitespace : !isWhitespace)
aPos->mEatingWS = PR_TRUE;
while (tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen,
&isWhitespace, PR_FALSE,
aIsKeyboardSelect)){
if (aWordSelectEatSpace ? !isWhitespace : *aSawBeforeType)
break;
if (contentLen >= startOffset)
goto TryNextFrame;
*aOffset -= contentLen;
if (aWordSelectEatSpace ? isWhitespace : !isWhitespace)
*aSawBeforeType = PR_TRUE;
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
#endif // IBMBIDI
while (tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen,
&isWhitespace, PR_FALSE,
aPos->mIsKeyboardSelect)){
if (wordSelectEatSpace ? !isWhitespace : aPos->mEatingWS)
break;
if (aPos->mStartOffset - contentLen <= mContentOffset)
goto TryNextFrame;
aPos->mContentOffset -= contentLen;
if (wordSelectEatSpace ? isWhitespace : !isWhitespace)
aPos->mEatingWS = PR_TRUE;
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
#endif // IBMBIDI
}
keepSearching = aPos->mContentOffset <= mContentOffset;
if (!keepSearching)
found = PR_TRUE;
}
else {
aPos->mContentOffset = mContentLength + mContentOffset;
found = PR_TRUE;
}
}
keepSearching = *aOffset <= 0;
if (!keepSearching)
found = PR_TRUE;
}
else {
*aOffset = mContentLength;
found = PR_TRUE;
}
}
}
else { // aForward
*aOffset = mContentLength; //initialize
#ifdef IBMBIDI
else if (movementIsInFrameDirection){
#else
else if (aPos->mDirection == eDirNext) {
#endif
tx.Init(this, mContent, aPos->mStartOffset );
aPos->mContentOffset = mContentOffset + mContentLength;//initialize
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
if (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aIsKeyboardSelect) &&
(startOffset + contentLen <= mContentLength)) {
if ((aWordSelectEatSpace ? isWhitespace : !isWhitespace) || !*aSawBeforeType) {
*aOffset = startOffset + contentLen;
keepSearching = PR_TRUE;
if (aWordSelectEatSpace ? isWhitespace : !isWhitespace)
*aSawBeforeType = PR_TRUE;
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
if (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect) &&
(aPos->mStartOffset + contentLen <= (mContentLength + mContentOffset))){
// On some platforms (mac, unix), we want the selection to end
// at the end of the word (not the beginning of the next one).
if ((wordSelectEatSpace ? isWhitespace : !isWhitespace) || !aPos->mEatingWS) {
aPos->mContentOffset = aPos->mStartOffset + contentLen;
keepSearching = PR_TRUE;
if (wordSelectEatSpace ? isWhitespace : !isWhitespace)
aPos->mEatingWS = PR_TRUE;
while (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aIsKeyboardSelect))
{
if (aWordSelectEatSpace ? !isWhitespace : *aSawBeforeType)
break;
if (startOffset + contentLen >= mContentLength)
goto TryNextFrame;
if (aWordSelectEatSpace ? isWhitespace : !isWhitespace)
*aSawBeforeType = PR_TRUE;
*aOffset += contentLen;
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI)
? mContentOffset + mContentLength : -1;
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
while (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect))
{
if (wordSelectEatSpace ? !isWhitespace : aPos->mEatingWS)
break;
if (aPos->mStartOffset + contentLen >= (mContentLength + mContentOffset))
goto TryNextFrame;
if (wordSelectEatSpace ? isWhitespace : !isWhitespace)
aPos->mEatingWS = PR_TRUE;
aPos->mContentOffset += contentLen;
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI)
? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
}
keepSearching = (mContentOffset + mContentLength) <= aPos->mContentOffset;
if (!keepSearching)
found = PR_TRUE;
}
else
{
aPos->mContentOffset = mContentOffset;
found = PR_TRUE;
}
}
}
}
TryNextFrame:
if (!found ||
(aPos->mContentOffset > (mContentOffset + mContentLength)) ||
(aPos->mContentOffset < mContentOffset))
{
aPos->mContentOffset = PR_MIN(aPos->mContentOffset, mContentOffset + mContentLength);
aPos->mContentOffset = PR_MAX(aPos->mContentOffset, mContentOffset);
if (wordSelectEatSpace && aPos->mEatingWS) {
//If we want to stop at beginning of the next word
//GetFrameFromDirction should not return NS_ERROR_FAILURE at end of line
aPos->mEatingWS = PR_FALSE;
result = GetFrameFromDirection(aPresContext, aPos);
aPos->mEatingWS = PR_TRUE;
}
keepSearching = *aOffset >= mContentLength;
if (!keepSearching)
found = PR_TRUE;
}
else
result = GetFrameFromDirection(aPresContext, aPos);
if (NS_SUCCEEDED(result) && aPos->mResultFrame && aPos->mResultFrame!= this)
{
if (NS_SUCCEEDED(result = aPos->mResultFrame->PeekOffset(aPresContext, aPos)))
return NS_OK;//else fall through
#ifdef IBMBIDI
else if (movementIsInFrameDirection)
#else
else if (aPos->mDirection == eDirNext)
#endif
aPos->mContentOffset = mContentOffset + mContentLength;
else
aPos->mContentOffset = mContentOffset;
*aOffset = 0;
found = PR_TRUE;
}
else
aPos->mResultContent = mContent;
}
else
{
aPos->mResultContent = mContent;
}
}
}
break;
default:
result = NS_ERROR_FAILURE; break;
}
if (NS_FAILED(result)){
aPos->mResultContent = mContent;
//aPos->mContentOffset = aPos->mStartOffset;
result = NS_OK;
TryNextFrame:
if (!found ||
*aOffset > mContentLength ||
*aOffset < 0)
{
found = PR_FALSE;
*aOffset = PR_MIN(*aOffset, mContentLength);
*aOffset = PR_MAX(*aOffset, 0);
}
aPos->mResultFrame = this;
return result;
}
return found;
}
NS_IMETHODIMP
nsTextFrame::CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval)