зеркало из https://github.com/mozilla/gecko-dev.git
Refactor nsIFrame::PeekOfset to use iteration instead of recursion, and some related refactoring. bug=300131 r+sr=roc
This commit is contained in:
Родитель
3768f6338f
Коммит
95b377fc13
|
@ -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,
|
||||
¤t, &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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче