diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index b671360bb14b..0a5c3d68bfa8 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -3239,47 +3239,13 @@ PresShell::CompleteMove(PRBool aForward, PRBool aExtend) if (!frame) return NS_ERROR_FAILURE; //could not find an area frame. - PRInt8 outsideLimit = -1;//search from beginning - nsPeekOffsetStruct pos; - pos.mAmount = eSelectLine; - pos.mShell = this; - pos.mContentOffset = 0; - pos.mContentOffsetEnd = 0; - pos.mScrollViewStop = PR_FALSE;//dont stop on scrolled views. - pos.mIsKeyboardSelect = PR_TRUE; - if (aForward) - { - outsideLimit = 1;//search from end - pos.mDesiredX = frame->GetRect().width * 2;//search way off to right of line - pos.mDirection = eDirPrevious; //seach backwards from the end - } - else - { - pos.mDesiredX = -1; //start before line - pos.mDirection = eDirNext; //search forwards from before beginning - } + nsPeekOffsetStruct pos = frame->GetExtremeCaretPosition(!aForward); + + // we 'prefer left' (i.e. prefer the beginning of the next line) + // iff we're moving to the end of the content + pos.mPreferLeft = aForward; - do - { - result = nsFrame::GetNextPrevLineFromeBlockFrame(mPresContext, - &pos, - frame, - 0, //irrelavent since we set outsidelimit - outsideLimit - ); - if (NS_POSITION_BEFORE_TABLE == result) //NS_POSITION_BEFORE_TABLE should ALSO break - break; - if (NS_FAILED (result) || !pos.mResultFrame ) - return result?result:NS_ERROR_FAILURE; - nsCOMPtr newIt; - //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines - result = pos.mResultFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(newIt)); - if (NS_SUCCEEDED(result) && newIt) - frame = pos.mResultFrame; - } - while (NS_SUCCEEDED(result));//end 'do' - - mSelection->HandleClick(pos.mResultContent ,pos.mContentOffset ,pos.mContentOffsetEnd ,aExtend, PR_FALSE, pos.mPreferLeft); + mSelection->HandleClick(pos.mResultContent ,pos.mContentOffset ,pos.mContentOffset/*End*/ ,aExtend, PR_FALSE, pos.mPreferLeft); return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE); } diff --git a/layout/base/public/nsIFrame.h b/layout/base/public/nsIFrame.h index 053fc56f612a..56586a6b6ca7 100644 --- a/layout/base/public/nsIFrame.h +++ b/layout/base/public/nsIFrame.h @@ -1423,6 +1423,19 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel)) // The above methods have been migrated from nsIBox and are in the process of // being refactored. DO NOT USE OUTSIDE OF XUL. + /** + * gets the first or last possible caret position within the frame + * + * @param [in] aStart + * true for getting the first possible caret position + * false for getting the last possible caret position + * @return The caret position in an nsPeekOffsetStruct (the + * fields set are mResultContent and mContentOffset; + * the returned value is a 'best effort' in case errors + * are encountered rummaging through the frame. + */ + nsPeekOffsetStruct GetExtremeCaretPosition(PRBool aStart); + protected: // Members nsRect mRect; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index e361aea361fc..9113475b7b62 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -3381,6 +3381,63 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, return NS_OK; } +nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(PRBool aStart) +{ + nsPeekOffsetStruct result; + + result.mResultContent = this->GetContent(); + result.mContentOffset = 0; + + nsIFrame *resultFrame = this; + + if (aStart) + nsFrame::GetFirstLeaf(GetPresContext(), &resultFrame); + else + nsFrame::GetLastLeaf(GetPresContext(), &resultFrame); + + NS_ASSERTION(resultFrame,"result frame for carent positioning is Null!"); + + if (!resultFrame) + return result; + + // there should be some more validity checks here, or earlier in the code, + // in case we get to to some 'dummy' frames at the end of the content + + nsIContent* content = resultFrame->GetContent(); + + NS_ASSERTION(resultFrame,"result frame content for carent positioning is Null!"); + + if (!content) + return result; + + // special case: if this is a br element, position the caret before it, + // not after it (perhaps the same exception should be made for some + // other elements?) + + nsIAtom* tag = content->Tag(); + if (tag == nsHTMLAtoms::br) { + // special case in effect + nsIContent* parent = content->GetParent(); + NS_ASSERTION(parent,"
element has no parent!"); + if (parent) { + result.mResultContent = parent; + result.mContentOffset = parent->IndexOf(content); + return result; + } + } + + result.mResultContent = content; + + PRInt32 start, end; + nsresult rv; + rv = GetOffsets(start,end); + if (NS_SUCCEEDED(rv)) { + result.mContentOffset = aStart ? start : end; + } + + return result; +} + // Get a frame which can contain a line iterator // (which generally means it's a block frame). static nsILineIterator* diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index ff13890bf588..0d6240bd0761 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -493,9 +493,14 @@ protected: //return the line number of the aFrame static PRInt32 GetLineNumber(nsIFrame *aFrame); + +public: //given a frame five me the first/last leaf available + //XXX Robert O'Callahan wants to move these elsewhere static void GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame); static void GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame); + +protected: // Test if we are selecting a table object: // Most table/cell selection requires that Ctrl (Cmd on Mac) key is down diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 053fc56f612a..56586a6b6ca7 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1423,6 +1423,19 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel)) // The above methods have been migrated from nsIBox and are in the process of // being refactored. DO NOT USE OUTSIDE OF XUL. + /** + * gets the first or last possible caret position within the frame + * + * @param [in] aStart + * true for getting the first possible caret position + * false for getting the last possible caret position + * @return The caret position in an nsPeekOffsetStruct (the + * fields set are mResultContent and mContentOffset; + * the returned value is a 'best effort' in case errors + * are encountered rummaging through the frame. + */ + nsPeekOffsetStruct GetExtremeCaretPosition(PRBool aStart); + protected: // Members nsRect mRect; diff --git a/layout/html/base/src/nsFrame.cpp b/layout/html/base/src/nsFrame.cpp index e361aea361fc..9113475b7b62 100644 --- a/layout/html/base/src/nsFrame.cpp +++ b/layout/html/base/src/nsFrame.cpp @@ -3381,6 +3381,63 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, return NS_OK; } +nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(PRBool aStart) +{ + nsPeekOffsetStruct result; + + result.mResultContent = this->GetContent(); + result.mContentOffset = 0; + + nsIFrame *resultFrame = this; + + if (aStart) + nsFrame::GetFirstLeaf(GetPresContext(), &resultFrame); + else + nsFrame::GetLastLeaf(GetPresContext(), &resultFrame); + + NS_ASSERTION(resultFrame,"result frame for carent positioning is Null!"); + + if (!resultFrame) + return result; + + // there should be some more validity checks here, or earlier in the code, + // in case we get to to some 'dummy' frames at the end of the content + + nsIContent* content = resultFrame->GetContent(); + + NS_ASSERTION(resultFrame,"result frame content for carent positioning is Null!"); + + if (!content) + return result; + + // special case: if this is a br element, position the caret before it, + // not after it (perhaps the same exception should be made for some + // other elements?) + + nsIAtom* tag = content->Tag(); + if (tag == nsHTMLAtoms::br) { + // special case in effect + nsIContent* parent = content->GetParent(); + NS_ASSERTION(parent,"
element has no parent!"); + if (parent) { + result.mResultContent = parent; + result.mContentOffset = parent->IndexOf(content); + return result; + } + } + + result.mResultContent = content; + + PRInt32 start, end; + nsresult rv; + rv = GetOffsets(start,end); + if (NS_SUCCEEDED(rv)) { + result.mContentOffset = aStart ? start : end; + } + + return result; +} + // Get a frame which can contain a line iterator // (which generally means it's a block frame). static nsILineIterator* diff --git a/layout/html/base/src/nsFrame.h b/layout/html/base/src/nsFrame.h index ff13890bf588..0d6240bd0761 100644 --- a/layout/html/base/src/nsFrame.h +++ b/layout/html/base/src/nsFrame.h @@ -493,9 +493,14 @@ protected: //return the line number of the aFrame static PRInt32 GetLineNumber(nsIFrame *aFrame); + +public: //given a frame five me the first/last leaf available + //XXX Robert O'Callahan wants to move these elsewhere static void GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame); static void GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame); + +protected: // Test if we are selecting a table object: // Most table/cell selection requires that Ctrl (Cmd on Mac) key is down diff --git a/layout/html/base/src/nsPresShell.cpp b/layout/html/base/src/nsPresShell.cpp index b671360bb14b..0a5c3d68bfa8 100644 --- a/layout/html/base/src/nsPresShell.cpp +++ b/layout/html/base/src/nsPresShell.cpp @@ -3239,47 +3239,13 @@ PresShell::CompleteMove(PRBool aForward, PRBool aExtend) if (!frame) return NS_ERROR_FAILURE; //could not find an area frame. - PRInt8 outsideLimit = -1;//search from beginning - nsPeekOffsetStruct pos; - pos.mAmount = eSelectLine; - pos.mShell = this; - pos.mContentOffset = 0; - pos.mContentOffsetEnd = 0; - pos.mScrollViewStop = PR_FALSE;//dont stop on scrolled views. - pos.mIsKeyboardSelect = PR_TRUE; - if (aForward) - { - outsideLimit = 1;//search from end - pos.mDesiredX = frame->GetRect().width * 2;//search way off to right of line - pos.mDirection = eDirPrevious; //seach backwards from the end - } - else - { - pos.mDesiredX = -1; //start before line - pos.mDirection = eDirNext; //search forwards from before beginning - } + nsPeekOffsetStruct pos = frame->GetExtremeCaretPosition(!aForward); + + // we 'prefer left' (i.e. prefer the beginning of the next line) + // iff we're moving to the end of the content + pos.mPreferLeft = aForward; - do - { - result = nsFrame::GetNextPrevLineFromeBlockFrame(mPresContext, - &pos, - frame, - 0, //irrelavent since we set outsidelimit - outsideLimit - ); - if (NS_POSITION_BEFORE_TABLE == result) //NS_POSITION_BEFORE_TABLE should ALSO break - break; - if (NS_FAILED (result) || !pos.mResultFrame ) - return result?result:NS_ERROR_FAILURE; - nsCOMPtr newIt; - //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines - result = pos.mResultFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(newIt)); - if (NS_SUCCEEDED(result) && newIt) - frame = pos.mResultFrame; - } - while (NS_SUCCEEDED(result));//end 'do' - - mSelection->HandleClick(pos.mResultContent ,pos.mContentOffset ,pos.mContentOffsetEnd ,aExtend, PR_FALSE, pos.mPreferLeft); + mSelection->HandleClick(pos.mResultContent ,pos.mContentOffset ,pos.mContentOffset/*End*/ ,aExtend, PR_FALSE, pos.mPreferLeft); return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE); }