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