Bug 316281. Rework GetContentAndOffsetsFromPoint. r=uriber,sr=roc,patch by Eli Friedman

This commit is contained in:
roc+%cs.cmu.edu 2005-12-07 23:08:39 +00:00
parent 5473753429
commit a710fcd15d
10 changed files with 489 additions and 814 deletions

View File

@ -56,9 +56,8 @@ class nsIPresShell;
// IID for the nsIFrameSelection interface
#define NS_IFRAMESELECTION_IID \
{ 0x18477ed4, 0x01ff, 0x4319, \
{ 0x95, 0xc0, 0x63, 0x9e, 0xe4, 0x33, 0xbe, 0x92 } }
{ 0xe5d9fe4f, 0xf430, 0x41ab, \
{ 0x95, 0xab, 0x1e, 0x7c, 0x86, 0x80, 0x2d, 0xd7 } }
//----------------------------------------------------------------------
@ -289,18 +288,6 @@ public:
*/
NS_IMETHOD GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset)=0;
/** AdjustOffsetsFromStyle. Called after detecting that a click or drag will
* select the frame, this function looks for user-select style on that frame or a parent
* frame, and adjust the content and offsets accordingly.
* @param aFrame the frame that was clicked
* @param outContent content node to be selected
* @param outStartOffset selection start offset
* @param outEndOffset selection end offset
*/
NS_IMETHOD AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset)=0;
NS_IMETHOD GetHint(HINT *aHint)=0;
NS_IMETHOD SetHint(HINT aHint)=0;

View File

@ -597,8 +597,6 @@ public:
NS_IMETHOD GetLimiter(nsIContent **aLimiterContent);
NS_IMETHOD GetTableCellSelection(PRBool *aState);
NS_IMETHOD GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset);
NS_IMETHOD AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset);
NS_IMETHOD GetHint(nsIFrameSelection::HINT *aHint);
NS_IMETHOD SetHint(nsIFrameSelection::HINT aHint);
NS_IMETHOD SetScrollableView(nsIScrollableView *aScrollableView);
@ -1148,13 +1146,6 @@ nsTextInputSelectionImpl::GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffs
return mFrameSelection->GetFrameForNodeOffset(aNode, aOffset, aHint,aReturnFrame,aReturnOffset);
}
NS_IMETHODIMP
nsTextInputSelectionImpl::AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset)
{
return mFrameSelection->AdjustOffsetsFromStyle(aFrame, changeSelection, outContent, outStartOffset, outEndOffset);
}
NS_IMETHODIMP nsTextInputSelectionImpl::GetHint(nsIFrameSelection::HINT *aHint)
{
return mFrameSelection->GetHint(aHint);

View File

@ -61,12 +61,11 @@ public:
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags = 0);
#endif
NS_IMETHOD GetContentAndOffsetsFromPoint(nsPresContext* aCX,
const nsPoint& aPoint,
nsIContent** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd,
PRBool& aBeginFrameContent);
NS_IMETHOD GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD PeekOffset(nsPresContext* aPresContext,
nsPeekOffsetStruct *aPos);
@ -210,22 +209,21 @@ BRFrame::GetType() const
return nsLayoutAtoms::brFrame;
}
NS_IMETHODIMP BRFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX,
const nsPoint& aPoint,
nsIContent ** aContent,
PRInt32& aOffsetBegin,
PRInt32& aOffsetEnd,
PRBool& aBeginFrameContent)
NS_IMETHODIMP BRFrame::GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
if (!mContent)
return NS_ERROR_NULL_POINTER;
NS_IF_ADDREF(*aContent = mContent->GetParent());
NS_IF_ADDREF(*aNewContent = mContent->GetParent());
if (*aContent)
aOffsetBegin = (*aContent)->IndexOf(mContent);
aOffsetEnd = aOffsetBegin;
aBeginFrameContent = PR_TRUE;
return NS_OK;
if (*aNewContent) {
aContentOffset = (*aNewContent)->IndexOf(mContent);
aContentOffsetEnd = aContentOffset;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BRFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)

View File

@ -6484,203 +6484,6 @@ nsBlockFrame::PaintChildren(nsPresContext* aPresContext,
#endif
}
// XXXldb Does this handle all overlap cases correctly? (How?)
nsresult
nsBlockFrame::GetClosestLine(nsILineIterator *aLI,
const nsPoint &aPoint,
PRInt32 &aClosestLine)
{
if (!aLI)
return NS_ERROR_NULL_POINTER;
nsRect rect;
PRInt32 numLines;
PRInt32 lineFrameCount;
nsIFrame *firstFrame;
PRUint32 flags;
nsresult result = aLI->GetNumLines(&numLines);
if (NS_FAILED(result) || numLines < 0)
return NS_OK;//do not handle
PRInt32 shifted = numLines;
PRInt32 start = 0, midpoint = 0;
PRInt32 y = 0;
while(shifted > 0)
{
// Cut the number of lines to look at in half and
// calculate the midpoint of the region we are looking at.
shifted >>= 1; //divide by 2
midpoint = start + shifted;
// Get the dimensions of the line that is at the half
// point of the region we are looking at.
result = aLI->GetLine(midpoint, &firstFrame, &lineFrameCount,rect,&flags);
if (NS_FAILED(result))
break;//do not handle
// Check to see if our point lies with the line's Y bounds.
y = aPoint.y - rect.y;
if (y >=0 && (aPoint.y < (rect.y+rect.height)))
{
aClosestLine = midpoint; //spot on!
return NS_OK;
}
if (y > 0)
{
// If we get here, no match was found above, so aPoint.y must
// be greater than the Y bounds of the current line rect. Move
// our starting point just beyond the midpoint of the current region.
start = midpoint;
if (numLines > 1 && start < (numLines - 1))
++start;
else
shifted = 0;
}
}
// Make sure we don't go off the edge in either direction!
NS_ASSERTION(start >=0 && start <= numLines, "Invalid start calculated.");
if (start < 0)
start = 0;
else if (start >= numLines)
start = numLines - 1;
aClosestLine = start; //close as we could come
return NS_OK;
}
NS_IMETHODIMP
nsBlockFrame::HandleEvent(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
nsresult result;
nsIPresShell *shell = nsnull;
if (aEvent->message == NS_MOUSE_MOVE) {
shell = aPresContext->GetPresShell();
if (!shell)
return NS_OK;
nsCOMPtr<nsIFrameSelection> frameSelection;
PRBool mouseDown = PR_FALSE;
//check to see if we need to ask the selection controller..
if (mState & NS_FRAME_INDEPENDENT_SELECTION)
{
nsCOMPtr<nsISelectionController> selCon;
result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
if (NS_FAILED(result) || !selCon)
return result?result:NS_ERROR_FAILURE;
frameSelection = do_QueryInterface(selCon);
}
else
frameSelection = shell->FrameSelection();
if (!frameSelection || NS_FAILED(frameSelection->GetMouseDownState(&mouseDown)) || !mouseDown)
return NS_OK;//do not handle
}
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN || aEvent->message == NS_MOUSE_MOVE ||
aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK ) {
nsMouseEvent *me = (nsMouseEvent *)aEvent;
nsIFrame *resultFrame = nsnull;//this will be passed the handle event when we
//can tell who to pass it to
nsIFrame *mainframe = this;
shell = aPresContext->GetPresShell();
if (!shell)
return NS_OK;
nsCOMPtr<nsILineIterator> it( do_QueryInterface(mainframe, &result) );
nsPeekOffsetStruct pos;
while(NS_OK == result)
{ //we are starting aloop to allow us to "drill down to the one we want"
PRInt32 closestLine;
nsPoint pt =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, mainframe);
if (NS_FAILED(result = GetClosestLine(it, pt, closestLine)))
return result;
// XXX mDesiredX needs to be in GetOffsetFromView coords
nsPoint offset;
nsIView* view;
mainframe->GetOffsetFromView(offset, &view);
//we will now ask where to go. if we cant find what we want"aka another block frame"
//we drill down again
pos.mShell = shell;
pos.mDirection = eDirNext;
pos.mDesiredX = pt.x + offset.x;
pos.mScrollViewStop = PR_FALSE;
pos.mIsKeyboardSelect = PR_FALSE;
result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext,
&pos,
mainframe,
closestLine-1,
0
);
if (NS_SUCCEEDED(result) && pos.mResultFrame){
if (result == NS_OK)
it = do_QueryInterface(pos.mResultFrame, &result);//if this fails that's ok
resultFrame = pos.mResultFrame;
mainframe = resultFrame;
}
else
break;//time to go nothing was found
}
//end while loop. if nssucceeded resutl then keep going that means
//we have successfully hit another block frame and we should keep going.
if (resultFrame)
{
if (NS_POSITION_BEFORE_TABLE == result)
{
nsCOMPtr<nsISelectionController> selCon;
result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
//get the selection controller
if (NS_SUCCEEDED(result) && selCon)
{
PRInt16 displayresult;
selCon->GetDisplaySelection(&displayresult);
if (displayresult == nsISelectionController::SELECTION_OFF)
return NS_OK;//nothing to do we cannot affect selection from here
}
PRBool mouseDown = aEvent->message == NS_MOUSE_MOVE;
result = shell->FrameSelection()->HandleClick(pos.mResultContent,
pos.mContentOffset,
pos.mContentOffsetEnd,
mouseDown || me->isShift,
PR_FALSE,
pos.mPreferLeft);
}
else
result = resultFrame->HandleEvent(aPresContext, aEvent, aEventStatus);//else let the frame/container do what it needs
/* Note that the above call to HandleEvent may capture the
mouse. If so, don't try to capture again. */
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext))
CaptureMouse(aPresContext, PR_TRUE);
return result;
}
else
{
return NS_OK; //just stop it
}
}
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
}
#ifdef ACCESSIBILITY
NS_IMETHODIMP nsBlockFrame::GetAccessible(nsIAccessible** aAccessible)
{

View File

@ -206,9 +206,6 @@ public:
PRBool aConsiderSelf);
virtual nsIFrame* GetFrameForPoint(const nsPoint& aPoint,
nsFramePaintLayer aWhichLayer);
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild);
NS_IMETHOD IsVisibleForPainting(nsPresContext * aPresContext,
@ -229,21 +226,6 @@ public:
nsIAtom* aAttribute,
PRInt32 aModType);
#ifdef DO_SELECTION
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus);
nsIFrame * FindHitFrame(nsBlockFrame * aBlockFrame,
const nscoord aX, const nscoord aY,
const nsPoint & aPoint);
#endif
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
nsIFrame* aNextInFlow);
@ -312,16 +294,6 @@ protected:
nscoord aAscent,
nscoord aSize);
/**
* GetClosestLine will return the line that VERTICALLY owns the point closest to aPoint.y
* aPoint is the point to search for, relative to the origin of the frame that aLI
* iterates over.
* aClosestLine is the result.
*/
nsresult GetClosestLine(nsILineIterator *aLI,
const nsPoint &aPoint,
PRInt32 &aClosestLine);
void TryAllLines(nsLineList::iterator* aIterator,
nsLineList::iterator* aEndIterator,
PRBool* aInOverflowLines);

View File

@ -23,6 +23,7 @@
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Uri Bernstein <uriber@gmail.com>
* Eli Friedman <sharparrow1@yahoo.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -1112,28 +1113,6 @@ nsFrame::GetDataForTableSelection(nsIFrameSelection *aFrameSelection,
return NS_OK;
}
/*
NS_IMETHODIMP
nsFrame::FrameOrParentHasSpecialSelectionStyle(PRUint8 aSelectionStyle, nsIFrame* *foundFrame)
{
nsIFrame* thisFrame = this;
while (thisFrame)
{
if (thisFrame->GetStyleUserInterface()->mUserSelect == aSelectionStyle)
{
*foundFrame = thisFrame;
return NS_OK;
}
thisFrame = thisFrame->GetParent();
}
*foundFrame = nsnull;
return NS_OK;
}
*/
NS_IMETHODIMP
nsFrame::IsSelectable(PRBool* aSelectable, PRUint8* aSelectStyle) const
{
@ -1199,58 +1178,6 @@ nsFrame::IsSelectable(PRBool* aSelectable, PRUint8* aSelectStyle) const
return NS_OK;
}
PRBool
ContentContainsPoint(nsPresContext *aPresContext,
nsIContent *aContent,
const nsPoint &aPoint,
nsIView *aRelativeView)
{
nsIPresShell *presShell = aPresContext->GetPresShell();
if (!presShell) return PR_FALSE;
nsIFrame *frame = presShell->GetPrimaryFrameFor(aContent);
if (!frame) return PR_FALSE;
nsIView *frameView = nsnull;
nsPoint offsetPoint;
// Get the view that contains the content's frame.
nsresult rv = frame->GetOffsetFromView(offsetPoint, &frameView);
if (NS_FAILED(rv) || !frameView) return PR_FALSE;
// aPoint is relative to aRelativeView's upper left corner! Make sure
// that our point is in the same view space our content frame's
// rects are in.
nsPoint point = aPoint + aRelativeView->GetOffsetTo(frameView);
// Now check to see if the point is within the bounds of the
// content's primary frame, or any of it's continuation frames.
while (frame) {
// Get the frame's rect and make it relative to the
// upper left corner of its parent view.
nsRect frameRect = frame->GetRect();
frameRect.x = offsetPoint.x;
frameRect.y = offsetPoint.y;
if (frameRect.Contains(point)) {
// point is within this frame's rect!
return PR_TRUE;
}
frame = frame->GetNextInFlow();
}
return PR_FALSE;
}
/**
* Handles the Mouse Press Event for the frame
*/
@ -1366,19 +1293,6 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
rv = GetContentAndOffsetsFromPoint(aPresContext, pt, getter_AddRefs(content),
startOffset, endOffset,
beginFrameContent);
// do we have CSS that changes selection behaviour?
PRBool changeSelection = PR_FALSE;
{
nsCOMPtr<nsIContent> selectContent;
PRInt32 newStart, newEnd;
if (NS_SUCCEEDED(frameselection->AdjustOffsetsFromStyle(this, &changeSelection, getter_AddRefs(selectContent), &newStart, &newEnd))
&& changeSelection)
{
content = selectContent;
startOffset = newStart;
endOffset = newEnd;
}
}
if (NS_FAILED(rv))
return rv;
@ -1475,83 +1389,16 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
if (isEditor && !me->isShift && (endOffset - startOffset) == 1)
{
// A single node is selected and we aren't extending an existing
// selection, which means the user clicked directly on an object.
// Check if the user clicked in a -moz-user-select:all subtree,
// image, or hr. If so, we want to give the drag and drop
// code a chance to execute so we need to turn off selection extension
// when processing mouse move/drag events that follow this mouse
// down event.
PRBool disableDragSelect = PR_FALSE;
if (changeSelection)
{
// The click hilited a -moz-user-select:all subtree.
//
// XXX: We really should be able to just do a:
//
// disableDragSelect = PR_TRUE;
//
// but we are working around the fact that in some cases,
// selection selects a -moz-user-select:all subtree even
// when the click was outside of the subtree. An example of
// this case would be when the subtree is at the end of a
// line and the user clicks to the right of it. In this case
// I would expect the caret to be placed next to the root of
// the subtree, but right now the whole subtree gets selected.
// This means that we have to do geometric frame containment
// checks on the point to see if the user truly clicked
// inside the subtree.
nsIView *view = nsnull;
nsPoint dummyPoint;
// aEvent->point is relative to the upper left corner of the
// frame's parent view. Unfortunately, the only way to get
// the parent view is to call GetOffsetFromView().
nsPoint pt = nsLayoutUtils::
GetEventCoordinatesForNearestView(aEvent, this, &view);
GetOffsetFromView(dummyPoint, &view);
// Now check to see if the point is truly within the bounds
// of any of the frames that make up the -moz-user-select:all subtree:
if (view)
disableDragSelect = ContentContainsPoint(aPresContext, content,
pt, view);
}
else
{
// Check if click was in an image.
nsIContent* frameContent = GetContent();
nsCOMPtr<nsIDOMHTMLImageElement> img(do_QueryInterface(frameContent));
disableDragSelect = img != nsnull;
if (!img)
{
// Check if click was in an hr.
nsCOMPtr<nsIDOMHTMLHRElement> hr(do_QueryInterface(frameContent));
disableDragSelect = hr != nsnull;
}
}
if (disableDragSelect)
{
// Click was in one of our draggable objects, so disable
// selection extension during mouse moves.
rv = frameselection->SetMouseDownState( PR_FALSE );
}
// selection, which means the user clicked directly on an object (either
// -moz-user-select: all or a non-text node without children).
// Therefore, disable selection extension during mouse moves.
// XXX This is a bit hacky; shouldn't editor be able to deal with this?
rv = frameselection->SetMouseDownState( PR_FALSE );
}
return rv;
}
/**
* Multiple Mouse Press -- line or paragraph selection -- for the frame.
* Wouldn't it be nice if this didn't have to be hardwired into Frame code?
@ -1575,28 +1422,31 @@ nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
// If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
// Otherwise, triple-click selects line, and quadruple-click selects paragraph
// (on platforms that support quadruple-click).
PRBool selectPara = PR_FALSE;
nsSelectionAmount beginAmount, endAmount;
nsMouseEvent *me = (nsMouseEvent *)aEvent;
if (!me) return NS_OK;
if (me->clickCount == 4)
selectPara = PR_TRUE;
else if (me->clickCount == 3)
{
selectPara =
nsContentUtils::GetBoolPref("browser.triple_click_selects_paragraph");
}
else
if (me->clickCount == 4) {
beginAmount = endAmount = eSelectParagraph;
} else if (me->clickCount == 3) {
if (nsContentUtils::GetBoolPref("browser.triple_click_selects_paragraph")) {
beginAmount = endAmount = eSelectParagraph;
} else {
beginAmount = eSelectBeginLine;
endAmount = eSelectEndLine;
}
} else if (me->clickCount == 2) {
// We only want inline frames; PeekBackwardAndForward dislikes blocks
beginAmount = endAmount = eSelectWord;
} else {
return NS_OK;
}
// Line or paragraph selection:
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
PRBool beginContent = PR_FALSE;
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
rv = GetContentAndOffsetsFromPoint(aPresContext,
pt,
getter_AddRefs(newContent),
@ -1604,13 +1454,19 @@ nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
contentOffsetEnd,
beginContent);
if (NS_FAILED(rv)) return rv;
return PeekBackwardAndForward(selectPara ? eSelectParagraph
: eSelectBeginLine,
selectPara ? eSelectParagraph
: eSelectEndLine,
startPos, aPresContext, PR_TRUE);
nsIFrame* result;
PRInt32 offset;
// Maybe make this a static helper?
rv = GetPresContext()->GetPresShell()->FrameSelection()->
GetFrameForNodeOffset(newContent, startPos,
nsIFrameSelection::HINT(beginContent),
&result, &offset);
NS_ENSURE_SUCCESS(rv, rv);
nsFrame* frame = NS_STATIC_CAST(nsFrame*, result);
return frame->PeekBackwardAndForward(beginAmount, endAmount,
startPos, aPresContext, PR_TRUE);
}
NS_IMETHODIMP
@ -1711,6 +1567,9 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
PRBool selectable;
PRUint8 selectStyle;
IsSelectable(&selectable, &selectStyle);
// XXX Do we really need to exclude non-selectable content here?
// GetContentAndOffsetsFromPoint can handle it just fine, although some
// other stuff might not like it.
if (!selectable)
return NS_OK;
if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
@ -1851,20 +1710,6 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
beginFrameContent);
if (NS_FAILED(result)) return result;
// do we have CSS that changes selection behaviour?
{
PRBool changeSelection;
nsCOMPtr<nsIContent> selectContent;
PRInt32 newStart, newEnd;
if (NS_SUCCEEDED(frameselection->AdjustOffsetsFromStyle(this, &changeSelection, getter_AddRefs(selectContent), &newStart, &newEnd))
&& changeSelection)
{
content = selectContent;
startOffset = newStart;
endOffset = newEnd;
}
}
result = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
if (NS_FAILED(result)) return result;
}
@ -1897,139 +1742,431 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
return NS_OK;
}
struct ContentOffsets {
ContentOffsets(nsIContent* aContent, PRInt32 aStart, PRInt32 aEnd) :
content(aContent), start(aStart), end(aEnd) { }
nsCOMPtr<nsIContent> content;
PRInt32 start;
PRInt32 end;
};
// Retrieve the content offsets of a frame
static ContentOffsets GetOffsetsOfFrame(nsIFrame* aFrame) {
nsCOMPtr<nsIContent> content, parent;
NS_ASSERTION(aFrame->GetContent(), "No content?!");
content = aFrame->GetContent();
if (aFrame->GetType() == nsLayoutAtoms::textFrame) {
PRInt32 offset, offsetEnd;
aFrame->GetOffsets(offset, offsetEnd);
return ContentOffsets(content, offset, offsetEnd);
}
// Loop to deal with anonymous content, which has no index; this loop
// probably won't run more than twice under normal conditions
do {
parent = content->GetParent();
if (parent) {
PRInt32 beginOffset = parent->IndexOf(content);
if (beginOffset >= 0)
return ContentOffsets(parent, beginOffset, beginOffset + 1);
content = parent;
}
} while (parent);
// The root content node must act differently
return ContentOffsets(content, 0, content->GetChildCount());
}
// The FrameTarget represents the closest frame to a point that can be selected
// The frame is the frame represented, frameEdge says whether one end of the
// frame is the result (in which case different handling is needed), and
// afterFrame says which end is repersented if frameEdge is true
struct FrameTarget {
FrameTarget(nsIFrame* aFrame, PRBool aFrameEdge, PRBool aAfterFrame) :
frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame) { }
static FrameTarget Null() {
return FrameTarget(nsnull, PR_FALSE, PR_FALSE);
}
PRBool IsNull() {
return !frame;
}
nsIFrame* frame;
PRPackedBool frameEdge;
PRPackedBool afterFrame;
};
// See function implementation for information
static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint);
static PRBool SelfIsSelectable(nsIFrame* aFrame)
{
return !(aFrame->IsGeneratedContentFrame() ||
aFrame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE);
}
static PRBool SelectionDescendToKids(nsIFrame* aFrame) {
PRUint8 style = aFrame->GetStyleUIReset()->mUserSelect;
nsIFrame* parent = aFrame->GetParent();
// If we are only near (not directly over) then don't traverse
// frames with independent selection (e.g. text and list controls)
// unless we're already inside such a frame (see bug 268497). Note that this
// prevents any of the users of this method from entering form controls.
// XXX We might want some way to allow using the up-arrow to go into a form
// control, but the focus didn't work right anyway; it'd probably be enough
// if the left and right arrows could enter textboxes (which I don't believe
// they can at the moment)
return !aFrame->IsGeneratedContentFrame() &&
style != NS_STYLE_USER_SELECT_ALL &&
style != NS_STYLE_USER_SELECT_NONE &&
((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
!(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
}
static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
nsPoint aPoint)
{
nsIFrame* parent = aChild->GetParent();
if (SelectionDescendToKids(aChild)) {
nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
return GetSelectionClosestFrame(aChild, pt);
}
return FrameTarget(aChild, PR_FALSE, PR_FALSE);
}
// When the cursor needs to be at the beginning of a block, it shouldn't be
// before the first child. A click on a block whose first child is a block
// should put the cursor in the child. The cursor shouldn't be between the
// blocks, because that's not where it's expected.
// Note that this method is guaranteed to succeed.
static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
PRBool aEndFrame) {
if (SelectionDescendToKids(aFrame)) {
nsIFrame* result = nsnull;
nsIFrame *frame = aFrame->GetFirstChild(nsnull);
if (!aEndFrame) {
while (frame && (!SelfIsSelectable(frame) ||
frame->IsEmpty()))
frame = frame->GetNextSibling();
if (frame)
result = frame;
} else {
// Because the frame tree is singly linked, to find the last frame,
// we have to iterate through all the frames
// XXX I have a feeling this could be slow for long blocks, although
// I can't find any slowdowns
while (frame) {
if (!frame->IsEmpty() && SelfIsSelectable(frame))
result = frame;
frame = frame->GetNextSibling();
}
}
if (result)
return DrillDownToSelectionFrame(result, aEndFrame);
}
// If the current frame has no targetable children, target the current frame
return FrameTarget(aFrame, PR_TRUE, aEndFrame);
}
// This method finds the closest valid FrameTarget on a given line; if there is
// no valid FrameTarget on the line, it returns a null FrameTarget
static FrameTarget GetSelectionClosestFrameForLine(
nsBlockFrame* aParent,
nsBlockFrame::line_iterator aLine,
nsPoint aPoint)
{
nsIFrame *frame = aLine->mFirstChild;
// Account for end of lines (any iterator from the block is valid)
if (aLine == aParent->end_lines())
return DrillDownToSelectionFrame(aParent, PR_TRUE);
nsIFrame *closestFromLeft = nsnull, *closestFromRight = nsnull;
nsRect rect = aLine->mBounds;
nscoord closestLeft = rect.x, closestRight = rect.XMost();
for (PRInt32 n = aLine->GetChildCount(); n;
--n, frame = frame->GetNextSibling()) {
if (!SelfIsSelectable(frame) || frame->IsEmpty())
continue;
nsRect frameRect = frame->GetRect();
if (aPoint.x >= frameRect.x) {
if (aPoint.x < frameRect.XMost()) {
return GetSelectionClosestFrameForChild(frame, aPoint);
}
if (frameRect.XMost() >= closestLeft) {
closestFromLeft = frame;
closestLeft = frameRect.XMost();
}
} else {
if (frameRect.x <= closestRight) {
closestFromRight = frame;
closestRight = frameRect.x;
}
}
}
if (!closestFromLeft && !closestFromRight) {
// We should only get here if there are no selectable frames on a line
// XXX Do we need more elaborate handling here?
return FrameTarget::Null();
}
if (closestFromLeft &&
(!closestFromRight ||
(abs(aPoint.x - closestLeft) <= abs(aPoint.x - closestRight)))) {
return GetSelectionClosestFrameForChild(closestFromLeft, aPoint);
}
return GetSelectionClosestFrameForChild(closestFromRight, aPoint);
}
// This method is for the special handling we do for block frames; they're
// special because they represent paragraphs and because they are organized
// into lines, which have bounds that are not stored elsewhere in the
// frame tree. Returns a null FrameTarget for frames which are not
// blocks or blocks with no lines.
static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
nsPoint aPoint)
{
nsresult rv;
nsBlockFrame* bf; // used only for QI
rv = aFrame->QueryInterface(kBlockFrameCID, (void**)&bf);
if (NS_FAILED(rv))
return FrameTarget::Null();
// This code searches for the correct line
nsBlockFrame::line_iterator firstLine = bf->begin_lines();
nsBlockFrame::line_iterator end = bf->end_lines();
if (firstLine == end)
return FrameTarget::Null();
nsBlockFrame::line_iterator curLine = firstLine;
nsBlockFrame::line_iterator closestLine = end;
while (curLine != end) {
// Check to see if our point lies with the line's Y bounds
nscoord y = aPoint.y - curLine->mBounds.y;
nscoord height = curLine->mBounds.height;
if (y >= 0 && y < height) {
closestLine = curLine;
break; // We found the line; stop looking
}
if (y < 0)
break;
++curLine;
}
if (closestLine == end) {
nsBlockFrame::line_iterator prevLine = curLine.prev();
nsBlockFrame::line_iterator nextLine = curLine;
// Avoid empty lines
while (nextLine != end && nextLine->IsEmpty())
++nextLine;
while (prevLine != end && prevLine->IsEmpty())
--prevLine;
// This hidden pref dictates whether a point above or below all lines comes
// up with a line or the beginning or end of the frame; 0 on Windows,
// 1 on other platforms by default at the writing of this code
PRInt32 dragOutOfFrame =
nsContentUtils::GetIntPref("browser.drag_out_of_frame_style");
if (prevLine == end) {
if (dragOutOfFrame == 1 || nextLine == end)
return DrillDownToSelectionFrame(aFrame, PR_FALSE);
closestLine = nextLine;
} else if (nextLine == end) {
if (dragOutOfFrame == 1)
return DrillDownToSelectionFrame(aFrame, PR_TRUE);
closestLine = prevLine;
} else { // Figure out which line is closer
if (aPoint.y - prevLine->mBounds.YMost() < nextLine->mBounds.y - aPoint.y)
closestLine = prevLine;
else
closestLine = nextLine;
}
}
do {
FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
aPoint);
if (!target.IsNull())
return target;
++closestLine;
} while (closestLine != end);
// Fall back to just targeting the last targetable place
return DrillDownToSelectionFrame(aFrame, PR_TRUE);
}
// GetSelectionClosestFrame is the helper function that calculates the closest
// frame to the given point.
// It doesn't completely account for offset styles, so needs to be used in
// restricted environments.
// Cannot handle overlapping frames correctly, so it should recieve the output
// of GetFrameForPoint
// Guaranteed to return a valid FrameTarget
static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint)
{
{
// Handle blocks; if the frame isn't a block, the method fails
FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint);
if (!target.IsNull())
return target;
}
nsIFrame *kid = aFrame->GetFirstChild(nsnull);
if (kid) {
// Go through all the child frames to find the closest one
// Large number to force the comparison to succeed
const nscoord HUGE_DISTANCE = nscoord_MAX;
nscoord closestXDistance = HUGE_DISTANCE;
nscoord closestYDistance = HUGE_DISTANCE;
nsIFrame *closestFrame = nsnull;
do {
if (!SelfIsSelectable(kid) || kid->IsEmpty())
continue;
nsRect rect = kid->GetRect();
nscoord fromLeft = aPoint.x - rect.x;
nscoord fromRight = aPoint.x - rect.XMost();
nscoord xDistance;
if (fromLeft >= 0 && fromRight <= 0) {
xDistance = 0;
} else {
xDistance = PR_MIN(abs(fromLeft), abs(fromRight));
}
if (xDistance <= closestXDistance)
{
if (xDistance < closestXDistance)
closestYDistance = HUGE_DISTANCE;
nscoord fromTop = aPoint.y - rect.y;
nscoord fromBottom = aPoint.y - rect.YMost();
nscoord yDistance;
if (fromTop >= 0 && fromBottom <= 0)
yDistance = 0;
else
yDistance = PR_MIN(abs(fromTop), abs(fromBottom));
if (yDistance < closestYDistance)
{
closestXDistance = xDistance;
closestYDistance = yDistance;
closestFrame = kid;
}
}
} while (kid = kid->GetNextSibling());
if (closestFrame);
return GetSelectionClosestFrameForChild(closestFrame, aPoint);
}
return FrameTarget(aFrame, PR_FALSE, PR_FALSE);
}
nsresult nsFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd,
PRBool& aBeginFrameContent)
PRBool& aKeepWithAbove)
{
if (!aNewContent)
return NS_ERROR_NULL_POINTER;
// Traverse through children and look for the best one to give this
// to if it fails the getposition call, make it yourself also only
// look at primary list
nsIFrame *closestFrame = nsnull;
nsIFrame *kid = GetFirstChild(nsnull);
// This section of code deals with special selection styles. Note that
// -moz-none and -moz-all exist, even though they don't need to be explicitly
// handled.
// The offset is forced not to end up in generated content; content offsets
// cannot represent content outside of the document's content tree.
if (kid) {
#define HUGE_DISTANCE 999999 //some HUGE number that will always fail first comparison
PRInt32 closestXDistance = HUGE_DISTANCE;
PRInt32 closestYDistance = HUGE_DISTANCE;
while (nsnull != kid) {
// Skip over generated content kid frames, or frames
// that don't have a proper parent-child relationship!
PRBool skipThisKid = (kid->GetStateBits() & NS_FRAME_GENERATED_CONTENT) != 0;
if (skipThisKid) {
kid = kid->GetNextSibling();
continue;
}
// Kid frame has content that has a proper parent-child
// relationship. Now see if the aPoint inside it's bounding
// rect or close by.
nsRect rect = kid->GetRect();
nscoord fromTop = aPoint.y - rect.y;
nscoord fromBottom = aPoint.y - rect.y - rect.height;
PRInt32 yDistance;
if (fromTop > 0 && fromBottom < 0)
yDistance = 0;
else
yDistance = PR_MIN(abs(fromTop), abs(fromBottom));
if (yDistance <= closestYDistance && rect.width > 0 && rect.height > 0)
{
if (yDistance < closestYDistance)
closestXDistance = HUGE_DISTANCE;
nscoord fromLeft = aPoint.x - rect.x;
nscoord fromRight = aPoint.x - rect.x - rect.width;
PRInt32 xDistance;
if (fromLeft > 0 && fromRight < 0)
xDistance = 0;
else
xDistance = PR_MIN(abs(fromLeft), abs(fromRight));
if (xDistance == 0 && yDistance == 0)
{
closestFrame = kid;
break;
}
if (xDistance < closestXDistance || (xDistance == closestXDistance && rect.x <= aPoint.x))
{
// If we are only near (not directly over) then don't traverse a frame with independent
// selection (e.g. text and list controls) unless we're already inside such a frame,
// except in "browsewithcaret" mode, bug 268497.
if (!(kid->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
(GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
nsContentUtils::GetBoolPref("accessibility.browsewithcaret")) {
closestXDistance = xDistance;
closestYDistance = yDistance;
closestFrame = kid;
}
}
// else if (xDistance > closestXDistance)
// break;//done
}
kid = kid->GetNextSibling();
}
if (closestFrame) {
// If we cross a view boundary, we need to adjust
// the coordinates because GetPosition() expects
// them to be relative to the closest view.
nsPoint newPoint = aPoint - closestFrame->GetOffsetTo(this);
return closestFrame->GetContentAndOffsetsFromPoint(aCX, newPoint,
aNewContent,
aContentOffset,
aContentOffsetEnd,
aBeginFrameContent);
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;
}
}
if (!mContent)
return NS_ERROR_NULL_POINTER;
// -moz-user-select: all needs special handling, because clicking on it
// should lead to the whole frame being selected
if (adjustedFrame->GetStyleUIReset()->mUserSelect ==
NS_STYLE_USER_SELECT_ALL) {
ContentOffsets selectOffset = GetOffsetsOfFrame(adjustedFrame);
NS_IF_ADDREF(*aNewContent = mContent->GetParent());
if (*aNewContent){
PRInt32 contentOffset(aContentOffset); //temp to hold old value in case of failure
contentOffset = (*aNewContent)->IndexOf(mContent);
if (contentOffset < 0)
{
return NS_ERROR_FAILURE;
NS_IF_ADDREF(*aNewContent = selectOffset.content);
aContentOffset = selectOffset.start;
aContentOffsetEnd = selectOffset.end;
aKeepWithAbove = PR_FALSE;
return NS_OK;
}
// For other cases, try to find a closest frame starting from the parent of
// the unselectable frame
if (frameAdjusted)
adjustedFrame = adjustedFrame->GetParent();
nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
FrameTarget closest = GetSelectionClosestFrame(adjustedFrame, adjustedPoint);
ContentOffsets offset = GetOffsetsOfFrame(closest.frame);
// If the correct offset is at one end of a frame, use offset-based
// calculation method
if (closest.frameEdge) {
NS_ADDREF(*aNewContent = offset.content);
if (closest.afterFrame) {
aContentOffset = offset.end;
aKeepWithAbove = PR_FALSE;
} else {
aContentOffset = offset.start;
aKeepWithAbove = PR_TRUE;
}
aContentOffset = contentOffset; //its clear save the result
aContentOffsetEnd = aContentOffset;
return NS_OK;
}
nsPoint pt = aPoint - closest.frame->GetOffsetTo(this);
nsresult rv = closest.frame->GetPositionHelper(pt, aNewContent,
aContentOffset,
aContentOffsetEnd);
NS_ENSURE_SUCCESS(rv, rv);
aBeginFrameContent = PR_TRUE;
nsRect thisRect(nsPoint(0, 0), GetSize());
if (thisRect.Contains(aPoint))
aContentOffsetEnd = aContentOffset +1;
else
{
//if we are a collapsed frame then dont check to see if we need to skip past this content
//see bug http://bugzilla.mozilla.org/show_bug.cgi?id=103888
if (thisRect.width && thisRect.height && ((thisRect.x + thisRect.width) < aPoint.x || thisRect.y > aPoint.y))
{
aBeginFrameContent = PR_FALSE;
aContentOffset++;
}
aContentOffsetEnd = aContentOffset;
// XXX should I add some kind of offset standardization?
// consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
// x and first z put the cursor in the same logical position in addition
// to the same visual position?
NS_ASSERTION(*aNewContent == offset.content,
"There should only be one possible content base");
aKeepWithAbove = (aContentOffset == offset.start);
return NS_OK;
}
NS_IMETHODIMP nsFrame::GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
ContentOffsets offset = GetOffsetsOfFrame(this);
NS_IF_ADDREF(*aNewContent = offset.content);
// Figure out whether the offsets should be over, after, or before the frame
nsRect rect(nsPoint(0, 0), GetSize());
if (rect.Contains(aPoint)) {
aContentOffset = offset.start;
aContentOffsetEnd = offset.end;
} else {
PRBool isBlock = (GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE);
PRBool isRtl = (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
if ((isBlock && rect.y < aPoint.y) ||
(!isBlock && ((isRtl && rect.x + rect.width < aPoint.x) ||
(!isRtl && rect.x < aPoint.x)))) {
aContentOffset = offset.end;
aContentOffsetEnd = offset.end;
} else {
aContentOffset = offset.start;
aContentOffsetEnd = offset.start;
}
}
return NS_OK;

View File

@ -321,6 +321,11 @@ public:
PRBool aJumpLines);
// Helper for GetContentAndOffsetsFromPoint
NS_IMETHOD GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
// Box layout methods
NS_IMETHOD GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize);
NS_IMETHOD GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize);

View File

@ -760,6 +760,11 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd,
PRBool& aBeginFrameContent) = 0;
// Helper for GetContentAndOffsetsFromPoint
NS_IMETHOD GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd) = 0;
/**
* This structure holds information about a cursor. mContainer represents a

View File

@ -340,9 +340,6 @@ public:
NS_IMETHOD GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset);
NS_IMETHOD CommonPageMove(PRBool aForward, PRBool aExtend, nsIScrollableView *aScrollableView, nsIFrameSelection *aFrameSel);
NS_IMETHOD AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset);
NS_IMETHOD SetHint(HINT aHintRight);
NS_IMETHOD GetHint(HINT *aHintRight);
NS_IMETHOD CharacterMove(PRBool aForward, PRBool aExtend);
@ -462,9 +459,6 @@ private:
nsresult NotifySelectionListeners(SelectionType aType); // add parameters to say collapsed etc?
// utility method to lookup frame style
nsresult FrameOrParentHasSpecialSelectionStyle(nsIFrame* aFrame, PRUint8 aSelectionStyle, nsIFrame* *foundFrame);
nsTypedSelection *mDomSelections[nsISelectionController::NUM_SELECTIONTYPES];
// Table selection support.
@ -2468,21 +2462,6 @@ nsSelection::HandleDrag(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint&
AdjustForMaintainedSelection(newContent, startPos))
return NS_OK;
// do we have CSS that changes selection behaviour?
{
//add scope for nsCOMPtr
PRBool changeSelection;
nsCOMPtr<nsIContent> selectContent;
PRInt32 newStart, newEnd;
if (NS_SUCCEEDED(AdjustOffsetsFromStyle(newFrame, &changeSelection, getter_AddRefs(selectContent), &newStart, &newEnd))
&& changeSelection)
{
newContent = selectContent;
startPos = newStart;
contentOffsetEnd = newEnd;
}
}
if (NS_SUCCEEDED(result))
{
#ifdef VISUALSELECTION
@ -3056,27 +3035,6 @@ nsSelection::NotifySelectionListeners(SelectionType aType)
return NS_ERROR_FAILURE;
}
nsresult
nsSelection::FrameOrParentHasSpecialSelectionStyle(nsIFrame* aFrame, PRUint8 aSelectionStyle, nsIFrame* *foundFrame)
{
nsIFrame* thisFrame = aFrame;
while (thisFrame)
{
if (thisFrame->GetStyleUIReset()->mUserSelect == aSelectionStyle)
{
*foundFrame = thisFrame;
return NS_OK;
}
thisFrame = thisFrame->GetParent();
}
*foundFrame = nsnull;
return NS_OK;
}
// Start of Table Selection methods
static PRBool IsCell(nsIContent *aContent)
@ -4093,59 +4051,6 @@ nsSelection::CreateAndAddRange(nsIDOMNode *aParentNode, PRInt32 aOffset)
// End of Table Selection
NS_IMETHODIMP
nsSelection::AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset)
{
*changeSelection = PR_FALSE;
*outContent = nsnull;
nsresult rv;
nsIFrame* selectAllFrame;
rv = FrameOrParentHasSpecialSelectionStyle(aFrame, NS_STYLE_USER_SELECT_ALL, &selectAllFrame);
if (NS_FAILED(rv)) return rv;
if (!selectAllFrame)
return NS_OK;
nsIContent* selectAllContent = selectAllFrame->GetContent();
if (selectAllContent)
{
nsCOMPtr<nsIContent> parentContent = selectAllContent->GetParent();
if (parentContent)
{
PRInt32 startOffset = parentContent->IndexOf(selectAllContent);
if (startOffset < 0)
{
// hrmm, this is probably anonymous content. Let's go up another level
// do we need to do this if we get the right frameSelection to start with?
nsCOMPtr<nsIContent> superParent = parentContent->GetParent();
if (superParent)
{
PRInt32 superStartOffset = superParent->IndexOf(parentContent);
if (superStartOffset < 0)
return NS_ERROR_FAILURE; // give up
parentContent = superParent;
startOffset = superStartOffset;
}
}
NS_IF_ADDREF(*outContent = parentContent);
*outStartOffset = startOffset;
*outEndOffset = startOffset + 1;
*changeSelection = PR_TRUE;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsSelection::SetHint(HINT aHintRight)
{

View File

@ -294,21 +294,12 @@ public:
NS_IMETHOD_(nsFrameState) GetDebugStateBits() const ;
#endif
NS_IMETHOD GetPosition(nsPresContext* aPresContext,
const nsPoint& aPoint,
NS_IMETHOD GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsPresContext* aPresContext,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd,
PRBool& aBeginFrameContent);
NS_IMETHOD GetPositionSlowly(nsPresContext* aPresContext,
nsIRenderingContext * aRendContext,
NS_IMETHOD GetPositionSlowly(nsIRenderingContext * aRendContext,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aOffset);
@ -322,10 +313,6 @@ public:
NS_IMETHOD PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos);
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const;
virtual void AdjustOffsetsForBidi(PRInt32 start, PRInt32 end);
@ -3065,22 +3052,21 @@ nsTextFrame::PaintUnicodeText(nsPresContext* aPresContext,
//measure Spaced Textvoid
nsresult
nsTextFrame::GetPositionSlowly(nsPresContext* aPresContext,
nsIRenderingContext* aRendContext,
nsTextFrame::GetPositionSlowly(nsIRenderingContext* aRendContext,
const nsPoint& aPoint,
nsIContent** aNewContent,
PRInt32& aOffset)
{
// pre-condition tests
NS_PRECONDITION(aPresContext && aRendContext && aNewContent, "null arg");
if (!aPresContext || !aRendContext || !aNewContent) {
NS_PRECONDITION(aRendContext && aNewContent, "null arg");
if (!aRendContext || !aNewContent) {
return NS_ERROR_NULL_POINTER;
}
// initialize out param
*aNewContent = nsnull;
nsTextStyle ts(aPresContext, *aRendContext, mStyleContext);
nsTextStyle ts(GetPresContext(), *aRendContext, mStyleContext);
if (!ts.mSmallCaps && !ts.mWordSpacing && !ts.mLetterSpacing && !ts.mJustifying) {
return NS_ERROR_INVALID_ARG;
}
@ -3119,7 +3105,7 @@ nsTextFrame::GetPositionSlowly(nsPresContext* aPresContext,
}
// Transform text from content into renderable form
nsTextTransformer tx(aPresContext);
nsTextTransformer tx(GetPresContext());
PRInt32 textLength;
PRIntn numJustifiableCharacter;
@ -3148,29 +3134,6 @@ nsTextFrame::GetPositionSlowly(nsPresContext* aPresContext,
#endif // IBMBIDI
ComputeExtraJustificationSpacing(*aRendContext, ts, paintBuffer.mBuffer, textLength, numJustifiableCharacter);
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
PRInt32 prefInt =
nsContentUtils::GetIntPref("browser.drag_out_of_frame_style");
PRBool outofstylehandled = PR_FALSE;
if (prefInt)
{
if (aPoint.y < 0)//above rectangle
{
aOffset = mContentOffset;
outofstylehandled = PR_TRUE;
}
else if (aPoint.y > mRect.height)
{
aOffset = mContentOffset + mContentLength;
outofstylehandled = PR_TRUE;
}
}
if (!outofstylehandled) //then we drag to closest X point and dont worry about the 'Y'
//END STYLE RULE
{
//the following will first get the index into the PAINTBUFFER then the actual content
nscoord adjustedX = PR_MAX(0,aPoint.x);
@ -4033,16 +3996,15 @@ nsTextFrame::PaintAsciiText(nsPresContext* aPresContext,
// display of selection is based on the compressed text.
//---------------------------------------------------------------------------
NS_IMETHODIMP
nsTextFrame::GetPosition(nsPresContext* aPresContext,
const nsPoint& aPoint,
nsTextFrame::GetPositionHelper(const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
// pre-condition tests
NS_PRECONDITION(aPresContext && aNewContent, "null arg");
if (!aPresContext || !aNewContent) {
NS_PRECONDITION(aNewContent, "null arg");
if (!aNewContent) {
return NS_ERROR_NULL_POINTER;
}
// initialize out param
@ -4052,14 +4014,14 @@ nsTextFrame::GetPosition(nsPresContext* aPresContext,
if (mState & NS_FRAME_IS_DIRTY)
return NS_ERROR_UNEXPECTED;
nsIPresShell *shell = aPresContext->GetPresShell();
nsIPresShell *shell = GetPresContext()->GetPresShell();
if (shell) {
nsCOMPtr<nsIRenderingContext> rendContext;
nsresult rv = shell->CreateRenderingContext(this, getter_AddRefs(rendContext));
if (NS_SUCCEEDED(rv)) {
nsTextStyle ts(aPresContext, *rendContext, mStyleContext);
nsTextStyle ts(GetPresContext(), *rendContext, mStyleContext);
if (ts.mSmallCaps || ts.mWordSpacing || ts.mLetterSpacing || ts.mJustifying) {
nsresult result = GetPositionSlowly(aPresContext, rendContext, aPoint, aNewContent,
nsresult result = GetPositionSlowly(rendContext, aPoint, aNewContent,
aContentOffset);
aContentOffsetEnd = aContentOffset;
return result;
@ -4077,39 +4039,17 @@ nsTextFrame::GetPosition(nsPresContext* aPresContext,
SetFontFromStyle(rendContext, mStyleContext);
// Get the renderable form of the text
nsTextTransformer tx(aPresContext);
nsTextTransformer tx(GetPresContext());
PRInt32 textLength;
// no need to worry about justification, that's always on the slow path
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
PRInt32 prefInt =
nsContentUtils::GetIntPref("browser.drag_out_of_frame_style");
PRBool outofstylehandled = PR_FALSE;
if (prefInt)
{
if (aPoint.y < 0)//above rectangle
{
aContentOffset = mContentOffset;
aContentOffsetEnd = aContentOffset;
outofstylehandled = PR_TRUE;
}
else if (aPoint.y > mRect.height)
{
aContentOffset = mContentOffset + mContentLength;
aContentOffsetEnd = aContentOffset;
outofstylehandled = PR_TRUE;
}
}
if (textLength <= 0) {
aContentOffset = mContentOffset;
aContentOffsetEnd = aContentOffset;
}
else if (!outofstylehandled) //then we need to track based on the X coord only
else
{
//END STYLE IF
PRInt32* ip = indexBuffer.mBuffer;
PRInt32 indx;
@ -4196,42 +4136,6 @@ nsTextFrame::GetPosition(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsTextFrame::GetContentAndOffsetsFromPoint(nsPresContext* aPresContext,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd,
PRBool& aBeginFrameContent)
{
if (!aNewContent)
return NS_ERROR_NULL_POINTER;
*aNewContent = nsnull;//initialize
aContentOffset = 0;
aContentOffsetEnd = 0;
aBeginFrameContent = 0;
DEBUG_VERIFY_NOT_DIRTY(mState);
if (mState & NS_FRAME_IS_DIRTY)
return NS_ERROR_UNEXPECTED;
nsPoint newPoint;
newPoint.y = aPoint.y;
if (aPoint.x < 0)
newPoint.x = 0;
else
newPoint.x = aPoint.x;
nsresult rv = GetPosition(aPresContext, newPoint, aNewContent, aContentOffset, aContentOffsetEnd);
if (NS_FAILED(rv))
return rv;
if (aContentOffset == mContentOffset)
aBeginFrameContent = PR_TRUE;
else
aBeginFrameContent = PR_FALSE;
return rv;
}
// [HACK] Foward Declarations
void ForceDrawFrame(nsFrame * aFrame);
@ -5120,38 +5024,6 @@ nsTextFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
return result;
}
NS_IMETHODIMP
nsTextFrame::HandleMultiplePress(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
{
if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
return NS_OK;
}
nsMouseEvent *me = (nsMouseEvent *)aEvent;
if (!me) return NS_OK;
// Triple- and greater click counts are handled by nsFrame.
if (me->clickCount > 2)
return nsFrame::HandleMultiplePress(aPresContext, aEvent, aEventStatus);
// Double-click: word selection, handled here:
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
nsresult rv = GetPosition(aPresContext, pt,
getter_AddRefs(newContent), startPos,
contentOffsetEnd);
if (NS_FAILED(rv))
return rv;
return PeekBackwardAndForward(eSelectWord, eSelectWord, startPos,
aPresContext, PR_FALSE);
}
NS_IMETHODIMP
nsTextFrame::CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval)
{