First pass implementation of selection auto scrolling.

layout/base/public/nsIFrame.h
        - Added GetContentAndOffsetsFromPoint() method. This
          method will eventually replace GetPosition().

    layout/base/public/nsIFrameSelection.h
        - Added HandleDrag() and Start/StopAutoScrollTimer() methods.

    layout/base/src/nsRangeList.cpp
        - Added implementation for HandleDrag() and
          Start/StopAutoScrollTimer() methods.

    layout/html/base/src/nsBRFrame.cpp
        - Added implementation for GetContentAndOffsetsFromPoint().

    layout/html/base/src/nsFrame.cpp
    layout/html/base/src/nsFrame.h
        - Added implementation for GetContentAndOffsetsFromPoint().
        - Added GetClosestViewForFrame() utility method.
        - Modified HandleEvent() to call HandleRelease() which now
          stops the auto scrolling timers.
        - Modified HandleDrag() to call nsIFrameSelection's HandleDrag()
          and Start/StopAutoScrollTimer() methods.

    layout/html/base/src/nsTextFrame.cpp
        - Added implementation for GetContentAndOffsetsFromPoint().


git-svn-id: svn://10.0.0.236/trunk@49313 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kin%netscape.com 1999-09-29 20:04:05 +00:00
parent cf2257de2a
commit 1806b9519b
13 changed files with 934 additions and 37 deletions

View File

@ -136,6 +136,27 @@ public:
NS_IMETHOD HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, PRUint32 aContentEndOffset ,
PRBool aContinueSelection, PRBool aMultipleSelection) = 0;
/** HandleDrag extends the selection to contain the frame closest to aPoint.
* @param aPresContext is the context to use when figuring out what frame contains the point.
* @param aFrame is the parent of all frames to use when searching for the closest frame to the point.
* @param aPoint is relative to aFrame's parent view.
*/
NS_IMETHOD HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint) = 0;
/** StartAutoScrollTimer is responsible for scrolling the view so that aPoint is always
* visible, and for selecting any frame that contains aPoint. The timer will also reset
* itself to fire again if the view has not scrolled to the end of the document.
* @param aPresContext is the context to use when figuring out what frame contains the point.
* @param aFrame is the parent of all frames to use when searching for the closest frame to the point.
* @param aPoint is relative to aFrame's parent view.
* @param aDelay is the timer's interval.
*/
NS_IMETHOD StartAutoScrollTimer(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, PRUint32 aDelay) = 0;
/** StopAutoScrollTimer stops any active auto scroll timer.
*/
NS_IMETHOD StopAutoScrollTimer() = 0;
/** EnableFrameNotification
* mutch like start batching, except all dirty calls are ignored. no notifications will go
* out until enableNotifications with a PR_TRUE is called

View File

@ -457,6 +457,12 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd) = 0;
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd) = 0;
/**
* Get the cursor for a given frame.

View File

@ -136,6 +136,27 @@ public:
NS_IMETHOD HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, PRUint32 aContentEndOffset ,
PRBool aContinueSelection, PRBool aMultipleSelection) = 0;
/** HandleDrag extends the selection to contain the frame closest to aPoint.
* @param aPresContext is the context to use when figuring out what frame contains the point.
* @param aFrame is the parent of all frames to use when searching for the closest frame to the point.
* @param aPoint is relative to aFrame's parent view.
*/
NS_IMETHOD HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint) = 0;
/** StartAutoScrollTimer is responsible for scrolling the view so that aPoint is always
* visible, and for selecting any frame that contains aPoint. The timer will also reset
* itself to fire again if the view has not scrolled to the end of the document.
* @param aPresContext is the context to use when figuring out what frame contains the point.
* @param aFrame is the parent of all frames to use when searching for the closest frame to the point.
* @param aPoint is relative to aFrame's parent view.
* @param aDelay is the timer's interval.
*/
NS_IMETHOD StartAutoScrollTimer(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, PRUint32 aDelay) = 0;
/** StopAutoScrollTimer stops any active auto scroll timer.
*/
NS_IMETHOD StopAutoScrollTimer() = 0;
/** EnableFrameNotification
* mutch like start batching, except all dirty calls are ignored. no notifications will go
* out until enableNotifications with a PR_TRUE is called

View File

@ -51,6 +51,8 @@
#include "nsIViewManager.h"
#include "nsIScrollableView.h"
#include "nsIDeviceContext.h"
#include "nsITimer.h"
#include "nsITimerCallback.h"
#define STATUS_CHECK_RETURN_MACRO() {if (!mTracker) return NS_ERROR_FAILURE;}
@ -79,6 +81,7 @@ static void printRange(nsIDOMRange *aDomRange);
class nsRangeListIterator;
class nsRangeList;
class nsAutoScrollTimer;
class nsDOMSelection : public nsIDOMSelection , public nsIScriptObjectOwner
{
@ -159,6 +162,10 @@ public:
SelectionDetails **aReturnDetails, SelectionType aType);
NS_IMETHOD Repaint();
nsresult StartAutoScrollTimer(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, PRUint32 aDelay);
nsresult StopAutoScrollTimer();
nsresult DoAutoScroll(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint);
private:
friend class nsRangeListIterator;
@ -182,6 +189,8 @@ private:
// for nsIScriptContextOwner
void* mScriptObject;
nsAutoScrollTimer *mAutoScrollTimer; // timer for autoscrolling.
};
@ -200,6 +209,9 @@ public:
NS_IMETHOD HandleKeyEvent(nsGUIEvent *aGuiEvent);
NS_IMETHOD HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, PRUint32 aContentEndOffset,
PRBool aContinueSelection, PRBool aMultipleSelection);
NS_IMETHOD HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint);
NS_IMETHOD StartAutoScrollTimer(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, PRUint32 aDelay);
NS_IMETHOD StopAutoScrollTimer();
NS_IMETHOD EnableFrameNotification(PRBool aEnable){mNotifyFrames = aEnable; return NS_OK;}
NS_IMETHOD LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset, PRInt32 aContentLength,
SelectionDetails **aReturnDetails);
@ -295,8 +307,108 @@ private:
SelectionType mType;
};
class nsAutoScrollTimer : public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
nsAutoScrollTimer()
: mSelection(0), mTimer(0), mFrame(0), mPresContext(0), mPoint(0,0), mDelay(30)
{
NS_INIT_ISUPPORTS();
}
~nsAutoScrollTimer()
{
if (mTimer)
{
mTimer->Cancel();
NS_RELEASE(mTimer);
}
}
nsresult Start(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint)
{
mFrame = aFrame;
mPresContext = aPresContext;
mPoint = aPoint;
if (!mTimer)
{
nsresult result = NS_NewTimer(&mTimer);
if (NS_FAILED(result))
return result;
}
return mTimer->Init(this, mDelay);
}
nsresult Stop()
{
nsresult result = NS_OK;
if (mTimer)
{
mTimer->Cancel();
NS_RELEASE(mTimer);
mTimer = 0;
}
return result;
}
nsresult Init(nsRangeList *aRangeList, nsDOMSelection *aSelection)
{
mRangeList = aRangeList;
mSelection = aSelection;
return NS_OK;
}
nsresult SetDelay(PRUint32 aDelay)
{
mDelay = aDelay;
return NS_OK;
}
virtual void Notify(nsITimer *timer)
{
if (mSelection && mPresContext && mFrame)
{
mRangeList->HandleDrag(mPresContext, mFrame, mPoint);
mSelection->DoAutoScroll(mPresContext, mFrame, mPoint);
}
}
private:
nsRangeList *mRangeList;
nsDOMSelection *mSelection;
nsITimer *mTimer;
nsIFrame *mFrame;
nsIPresContext *mPresContext;
nsPoint mPoint;
PRUint32 mDelay;
};
NS_IMPL_ADDREF(nsAutoScrollTimer)
NS_IMPL_RELEASE(nsAutoScrollTimer)
NS_IMPL_QUERY_INTERFACE1(nsAutoScrollTimer, nsITimerCallback)
nsresult NS_NewAutoScrollTimer(nsAutoScrollTimer **aResult)
{
if (!aResult)
return NS_ERROR_NULL_POINTER;
*aResult = (nsAutoScrollTimer*) new nsAutoScrollTimer;
if (!aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
nsresult NS_NewRangeList(nsIFrameSelection **aRangeList);
@ -914,6 +1026,44 @@ nsRangeList::HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset,
return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aContinueSelection, aMultipleSelection);
}
NS_IMETHODIMP
nsRangeList::HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint)
{
nsresult result;
nsCOMPtr<nsIPresShell> presShell;
result = aPresContext->GetShell(getter_AddRefs(presShell));
if (NS_FAILED(result))
return result;
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
result = aFrame->GetContentAndOffsetsFromPoint(*aPresContext, aPoint,
getter_AddRefs(newContent),
startPos, contentOffsetEnd);
if (NS_SUCCEEDED(result))
result = HandleClick(newContent, startPos, contentOffsetEnd , PR_TRUE, PR_FALSE);
return result;
}
NS_IMETHODIMP
nsRangeList::StartAutoScrollTimer(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, PRUint32 aDelay)
{
return mDomSelections[SELECTION_NORMAL]->StartAutoScrollTimer(aPresContext, aFrame, aPoint, aDelay);
}
NS_IMETHODIMP
nsRangeList::StopAutoScrollTimer()
{
return mDomSelections[SELECTION_NORMAL]->StopAutoScrollTimer();
}
/**
hard to go from nodes to frames, easy the other way!
*/
@ -1266,6 +1416,7 @@ nsDOMSelection::nsDOMSelection(nsRangeList *aList)
mDirection = eDirNext;
NS_NewISupportsArray(getter_AddRefs(mRangeArray));
mScriptObject = nsnull;
mAutoScrollTimer = nsnull;
NS_INIT_REFCNT();
}
@ -1282,6 +1433,8 @@ nsDOMSelection::~nsDOMSelection()
mRangeArray->RemoveElementAt(0);
}
setAnchorFocusRange(-1);
NS_IF_RELEASE(mAutoScrollTimer);
}
@ -1953,6 +2106,243 @@ nsDOMSelection::Repaint()
return NS_OK;
}
nsresult
nsDOMSelection::StartAutoScrollTimer(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, PRUint32 aDelay)
{
nsresult result;
if (!mAutoScrollTimer)
{
result = NS_NewAutoScrollTimer(&mAutoScrollTimer);
if (NS_FAILED(result))
return result;
if (!mAutoScrollTimer)
return NS_ERROR_OUT_OF_MEMORY;
result = mAutoScrollTimer->Init(mRangeList, this);
if (NS_FAILED(result))
return result;
}
result = mAutoScrollTimer->SetDelay(aDelay);
if (NS_FAILED(result))
return result;
return DoAutoScroll(aPresContext, aFrame, aPoint);
}
nsresult
nsDOMSelection::StopAutoScrollTimer()
{
if (mAutoScrollTimer)
return mAutoScrollTimer->Stop();
return NS_OK;
}
nsresult
nsDOMSelection::DoAutoScroll(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint)
{
nsresult result;
if (!aPresContext || !aFrame)
return NS_ERROR_NULL_POINTER;
if (mAutoScrollTimer)
result = mAutoScrollTimer->Stop();
nsCOMPtr<nsIPresShell> presShell;
result = aPresContext->GetShell(getter_AddRefs(presShell));
//
// Get a hold of the root scrollable view for presShell.
//
nsCOMPtr<nsIViewManager> viewManager;
result = presShell->GetViewManager(getter_AddRefs(viewManager));
if (NS_FAILED(result))
return result;
if (!viewManager)
return NS_ERROR_NULL_POINTER;
nsIScrollableView *scrollableView = 0;
result = viewManager->GetRootScrollableView(&scrollableView);
if (NS_SUCCEEDED(result) && scrollableView)
{
//
// Get a hold of the scrollable view's clip view.
//
const nsIView *cView = 0;
result = scrollableView->GetClipView(&cView);
if (NS_SUCCEEDED(result) && cView)
{
//
// Find out if this frame's view is in the parent hierarchy of the clip view.
// If it is, then we know the drag is happening outside of the clip view,
// so we may need to auto scroll.
//
// Get the frame's parent view.
nsPoint viewOffset(0,0);
nsIView *frameView = 0;
nsIFrame *parentFrame = aFrame;
while (NS_SUCCEEDED(result) && parentFrame && !frameView)
{
result = parentFrame->GetView(&frameView);
if (NS_SUCCEEDED(result) && !frameView)
result = parentFrame->GetParent(&parentFrame);
}
if (NS_SUCCEEDED(result) && frameView)
{
//
// Now make sure that the frame's view is in the
// scrollable view's parent hierarchy.
//
nsIView *view = (nsIView*)cView;
nscoord x, y;
while (view && view != frameView)
{
result = view->GetParent(view);
if (NS_FAILED(result))
view = 0;
else if (view)
{
result = view->GetPosition(&x, &y);
if (NS_FAILED(result))
view = 0;
else
{
//
// Keep track of the view offsets so we can
// translate aPoint into the scrollable view's
// coordinate system.
//
viewOffset.x += x;
viewOffset.y += y;
}
}
}
if (view)
{
//
// See if aPoint is outside the clip view's boundaries.
// If it is, scroll the view till it is inside the visible area!
//
nsRect bounds;
result = cView->GetBounds(bounds);
if (NS_SUCCEEDED(result))
{
//
// Calculate the amount we would have to scroll in
// the vertical and horizontal directions to get the point
// within the clip area.
//
nscoord dx = 0, dy = 0;
nsPoint ePoint = aPoint;
ePoint.x -= viewOffset.x;
ePoint.y -= viewOffset.y;
nscoord x1 = bounds.x;
nscoord x2 = bounds.x + bounds.width;
nscoord y1 = bounds.y;
nscoord y2 = bounds.y + bounds.height;
if (ePoint.x < x1)
dx = ePoint.x - x1;
else if (ePoint.x > x2)
dx = ePoint.x - x2;
if (ePoint.y < y1)
dy = ePoint.y - y1;
else if (ePoint.y > y2)
dy = ePoint.y - y2;
//
// Now clip the scroll amounts so that we don't scroll
// beyond the ends of the document.
//
nscoord scrollX = 0, scrollY = 0;
nscoord docWidth = 0, docHeight = 0;
result = scrollableView->GetScrollPosition(scrollX, scrollY);
if (NS_SUCCEEDED(result))
result = scrollableView->GetContainerSize(&docWidth, &docHeight);
if (NS_SUCCEEDED(result))
{
if (dx < 0 && scrollX == 0)
dx = 0;
else if (dx > 0)
{
x1 = scrollX + dx + bounds.width;
if (x1 > docWidth)
dx -= x1 - docWidth;
}
if (dy < 0 && scrollY == 0)
dy = 0;
else if (dy > 0)
{
y1 = scrollY + dy + bounds.height;
if (y1 > docHeight)
dy -= y1 - docHeight;
}
//
// Now scroll the view if neccessary.
//
if (dx != 0 || dy != 0)
{
result = scrollableView->ScrollTo(scrollX + dx, scrollY + dy, NS_VMREFRESH_NO_SYNC);
if (mAutoScrollTimer)
result = mAutoScrollTimer->Start(aPresContext, aFrame, aPoint);
}
}
}
}
}
}
}
return result;
}
NS_IMETHODIMP
nsDOMSelection::GetEnumerator(nsIEnumerator **aIterator)
{
@ -2965,7 +3355,6 @@ nsDOMSelection::Extend(nsIDOMNode* aParentNode, PRInt32 aOffset)
else if (NS_FAILED(mAnchorFocusRange->SetEnd(endNode,endOffset)))
return NS_ERROR_FAILURE;//???
/*end hack*/
ScrollIntoView();
#ifdef DEBUG_SELECTION
if (aParentNode)
{

View File

@ -45,6 +45,11 @@ public:
nsIContent** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
protected:
virtual ~BRFrame();
@ -170,3 +175,20 @@ NS_IMETHODIMP BRFrame::GetPosition(nsIPresContext& aCX,
aOffsetEnd = aOffsetBegin;//BRFrames should return a collapsed selection before itself
return returnval;
}
NS_IMETHODIMP BRFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aContent,
PRInt32& aOffsetBegin,
PRInt32& aOffsetEnd)
{
nsresult result = nsFrame::GetContentAndOffsetsFromPoint(aCX,aPoint,aContent,aOffsetBegin,aOffsetEnd);
if (NS_SUCCEEDED(result))
{
// BRFrames should return a collapsed selection before itself
aOffsetEnd = aOffsetBegin;
}
return result;
}

View File

@ -793,6 +793,9 @@ nsFrame::HandleEvent(nsIPresContext& aPresContext,
frameselection->SetMouseDownState(PR_TRUE);//not important if it fails here
HandlePress(aPresContext, aEvent, aEventStatus);
}break;
case NS_MOUSE_LEFT_BUTTON_UP:
HandleRelease(aPresContext, aEvent, aEventStatus);
break;
default:
break;
}//end switch
@ -822,7 +825,7 @@ nsFrame::HandlePress(nsIPresContext& aPresContext,
// PRUint32 contentOffset = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
if (NS_SUCCEEDED(GetPosition(aPresContext, aEvent->point.x,
if (NS_SUCCEEDED(GetContentAndOffsetsFromPoint(aPresContext, aEvent->point,
getter_AddRefs(newContent),
startPos, contentOffsetEnd))){
nsCOMPtr<nsIFrameSelection> frameselection;
@ -866,7 +869,7 @@ nsFrame::HandleMultiplePress(nsIPresContext& aPresContext,
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
if (NS_SUCCEEDED(GetPosition(aPresContext, aEvent->point.x,
if (NS_SUCCEEDED(GetContentAndOffsetsFromPoint(aPresContext, aEvent->point,
getter_AddRefs(newContent),
startPos, contentOffsetEnd))) {
// find which word needs to be selected! use peek offset one
@ -929,23 +932,26 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsIPresContext& aPresContext,
if (!DisplaySelection(aPresContext)) {
return NS_OK;
}
// printf("handledrag %x\n",this);
nsCOMPtr<nsIPresShell> shell;
nsresult rv = aPresContext.GetShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell) {
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
if (NS_SUCCEEDED(GetPosition(aPresContext, aEvent->point.x,
getter_AddRefs(newContent),
startPos, contentOffsetEnd))) {
nsCOMPtr<nsIFrameSelection> frameselection;
if (NS_SUCCEEDED(shell->GetFrameSelection(getter_AddRefs(frameselection))) && frameselection){
frameselection->HandleClick(newContent, startPos, contentOffsetEnd , PR_TRUE, PR_FALSE); //TRUE IS THE DIFFERENCE for continue selection
}
//no release
}
nsresult result;
nsCOMPtr<nsIPresShell> presShell;
result = aPresContext.GetShell(getter_AddRefs(presShell));
if (NS_FAILED(result))
return result;
nsCOMPtr<nsIFrameSelection> frameselection;
result = presShell->GetFrameSelection(getter_AddRefs(frameselection));
if (NS_SUCCEEDED(result) && frameselection)
{
frameselection->StopAutoScrollTimer();
frameselection->HandleDrag(&aPresContext, this, aEvent->point);
frameselection->StartAutoScrollTimer(&aPresContext, this, aEvent->point, 30);
}
return NS_OK;
}
@ -953,9 +959,153 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus)
{
if (!DisplaySelection(aPresContext))
return NS_OK;
nsresult result;
nsCOMPtr<nsIPresShell> presShell;
result = aPresContext.GetShell(getter_AddRefs(presShell));
if (NS_SUCCEEDED(result))
{
nsCOMPtr<nsIFrameSelection> frameselection;
result = presShell->GetFrameSelection(getter_AddRefs(frameselection));
if (NS_SUCCEEDED(result) && frameselection)
frameselection->StopAutoScrollTimer();
}
return NS_OK;
}
nsresult nsFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
nsresult result = NS_ERROR_FAILURE;
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
nsIView *view = nsnull;
nsIFrame *kid = nsnull;
nsIFrame *closestFrame = nsnull;
result = GetClosestViewForFrame(this, &view);
if (NS_FAILED(result))
return result;
result = FirstChild(nsnull, &kid);
if (NS_SUCCEEDED(result) && nsnull != 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) {
nsRect rect;
nsPoint offsetPoint(0,0);
nsIView * kidView = nsnull;
kid->GetRect(rect);
kid->GetOffsetFromView(offsetPoint, &kidView);
rect.x = offsetPoint.x;
rect.y = offsetPoint.y;
nscoord y1 = rect.y;
nscoord y2 = rect.y + rect.height;
PRInt32 yDistance = PR_MIN(abs(y1 - aPoint.y),abs(y2 - aPoint.y));
if (yDistance <= closestYDistance && rect.width > 0 && rect.height > 0)
{
if (yDistance < closestYDistance)
closestXDistance = HUGE_DISTANCE;
nscoord x1 = rect.x;
nscoord x2 = rect.x + rect.width;
if (x1 <= aPoint.x && x2 >= aPoint.x && y1 <= aPoint.y && y2 >= aPoint.y)
{
closestFrame = kid;
break;
}
PRInt32 xDistance = PR_MIN(abs(x1 - aPoint.x),abs(x2 - aPoint.x));
if (xDistance < closestXDistance)
{
closestXDistance = xDistance;
closestYDistance = yDistance;
closestFrame = kid;
}
// else if (xDistance > closestXDistance)
// break;//done
}
kid->GetNextSibling(&kid);
}
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;
nsIView *closestView = nsnull;
result = GetClosestViewForFrame(closestFrame, &closestView);
if (NS_FAILED(result))
return result;
if (closestView && view != closestView)
{
nscoord vX = 0, vY = 0;
result = closestView->GetPosition(&vX, &vY);
if (NS_SUCCEEDED(result))
{
newPoint.x -= vX;
newPoint.y -= vY;
}
}
// printf(" 0x%.8x 0x%.8x %4d %4d\n",
// closestFrame, closestView, closestXDistance, closestYDistance);
return closestFrame->GetContentAndOffsetsFromPoint(aCX, newPoint, aNewContent,
aContentOffset, aContentOffsetEnd);
}
}
if (!mContent)
return NS_ERROR_NULL_POINTER;
result = mContent->GetParent(*aNewContent);
if (*aNewContent){
result = (*aNewContent)->IndexOf(mContent, aContentOffset);
if (NS_FAILED(result))
{
return result;
}
aContentOffsetEnd = aContentOffset +1;
}
return result;
}
//--------------------------------------------------------------------------
//-- GetPosition
//--------------------------------------------------------------------------
@ -2310,6 +2460,36 @@ nsFrame::PeekOffset(nsPeekOffsetStruct *aPos)
return result;
}
nsresult nsFrame::GetClosestViewForFrame(nsIFrame *aFrame, nsIView **aView)
{
if (!aView)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_OK;
*aView = 0;
nsIFrame *parent = aFrame;
while (parent && !*aView)
{
result = parent->GetView(aView);
if (NS_FAILED(result))
return result;
if (!*aView)
{
result = parent->GetParent(&parent);
if (NS_FAILED(result))
return result;
}
}
return result;
}
//-----------------------------------------------------------------------------------

View File

@ -274,6 +274,13 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
//--------------------------------------------------
// Additional methods
@ -303,6 +310,8 @@ public:
PRBool IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics);
virtual nsresult GetClosestViewForFrame(nsIFrame *aFrame, nsIView **aView);
#ifdef NS_DEBUG
/**
* Tracing method that writes a method enter/exit routine to the

View File

@ -457,6 +457,12 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd) = 0;
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd) = 0;
/**
* Get the cursor for a given frame.

View File

@ -348,6 +348,12 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetPositionSlowly(nsIPresContext& aCX,
nsIRenderingContext * aRendContext,
nscoord aXCoord,
@ -1829,6 +1835,16 @@ nsTextFrame::GetPosition(nsIPresContext& aCX,
return NS_OK;
}
NS_IMETHODIMP
nsTextFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
return GetPosition(aCX, (aPoint.x < 0) ? 0 : aPoint.x, aNewContent, aContentOffset, aContentOffsetEnd);
}
// [HACK] Foward Declarations
void ForceDrawFrame(nsFrame * aFrame);

View File

@ -45,6 +45,11 @@ public:
nsIContent** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
protected:
virtual ~BRFrame();
@ -170,3 +175,20 @@ NS_IMETHODIMP BRFrame::GetPosition(nsIPresContext& aCX,
aOffsetEnd = aOffsetBegin;//BRFrames should return a collapsed selection before itself
return returnval;
}
NS_IMETHODIMP BRFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aContent,
PRInt32& aOffsetBegin,
PRInt32& aOffsetEnd)
{
nsresult result = nsFrame::GetContentAndOffsetsFromPoint(aCX,aPoint,aContent,aOffsetBegin,aOffsetEnd);
if (NS_SUCCEEDED(result))
{
// BRFrames should return a collapsed selection before itself
aOffsetEnd = aOffsetBegin;
}
return result;
}

View File

@ -793,6 +793,9 @@ nsFrame::HandleEvent(nsIPresContext& aPresContext,
frameselection->SetMouseDownState(PR_TRUE);//not important if it fails here
HandlePress(aPresContext, aEvent, aEventStatus);
}break;
case NS_MOUSE_LEFT_BUTTON_UP:
HandleRelease(aPresContext, aEvent, aEventStatus);
break;
default:
break;
}//end switch
@ -822,7 +825,7 @@ nsFrame::HandlePress(nsIPresContext& aPresContext,
// PRUint32 contentOffset = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
if (NS_SUCCEEDED(GetPosition(aPresContext, aEvent->point.x,
if (NS_SUCCEEDED(GetContentAndOffsetsFromPoint(aPresContext, aEvent->point,
getter_AddRefs(newContent),
startPos, contentOffsetEnd))){
nsCOMPtr<nsIFrameSelection> frameselection;
@ -866,7 +869,7 @@ nsFrame::HandleMultiplePress(nsIPresContext& aPresContext,
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
if (NS_SUCCEEDED(GetPosition(aPresContext, aEvent->point.x,
if (NS_SUCCEEDED(GetContentAndOffsetsFromPoint(aPresContext, aEvent->point,
getter_AddRefs(newContent),
startPos, contentOffsetEnd))) {
// find which word needs to be selected! use peek offset one
@ -929,23 +932,26 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsIPresContext& aPresContext,
if (!DisplaySelection(aPresContext)) {
return NS_OK;
}
// printf("handledrag %x\n",this);
nsCOMPtr<nsIPresShell> shell;
nsresult rv = aPresContext.GetShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell) {
PRInt32 startPos = 0;
PRInt32 contentOffsetEnd = 0;
nsCOMPtr<nsIContent> newContent;
if (NS_SUCCEEDED(GetPosition(aPresContext, aEvent->point.x,
getter_AddRefs(newContent),
startPos, contentOffsetEnd))) {
nsCOMPtr<nsIFrameSelection> frameselection;
if (NS_SUCCEEDED(shell->GetFrameSelection(getter_AddRefs(frameselection))) && frameselection){
frameselection->HandleClick(newContent, startPos, contentOffsetEnd , PR_TRUE, PR_FALSE); //TRUE IS THE DIFFERENCE for continue selection
}
//no release
}
nsresult result;
nsCOMPtr<nsIPresShell> presShell;
result = aPresContext.GetShell(getter_AddRefs(presShell));
if (NS_FAILED(result))
return result;
nsCOMPtr<nsIFrameSelection> frameselection;
result = presShell->GetFrameSelection(getter_AddRefs(frameselection));
if (NS_SUCCEEDED(result) && frameselection)
{
frameselection->StopAutoScrollTimer();
frameselection->HandleDrag(&aPresContext, this, aEvent->point);
frameselection->StartAutoScrollTimer(&aPresContext, this, aEvent->point, 30);
}
return NS_OK;
}
@ -953,9 +959,153 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus)
{
if (!DisplaySelection(aPresContext))
return NS_OK;
nsresult result;
nsCOMPtr<nsIPresShell> presShell;
result = aPresContext.GetShell(getter_AddRefs(presShell));
if (NS_SUCCEEDED(result))
{
nsCOMPtr<nsIFrameSelection> frameselection;
result = presShell->GetFrameSelection(getter_AddRefs(frameselection));
if (NS_SUCCEEDED(result) && frameselection)
frameselection->StopAutoScrollTimer();
}
return NS_OK;
}
nsresult nsFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
nsresult result = NS_ERROR_FAILURE;
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
nsIView *view = nsnull;
nsIFrame *kid = nsnull;
nsIFrame *closestFrame = nsnull;
result = GetClosestViewForFrame(this, &view);
if (NS_FAILED(result))
return result;
result = FirstChild(nsnull, &kid);
if (NS_SUCCEEDED(result) && nsnull != 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) {
nsRect rect;
nsPoint offsetPoint(0,0);
nsIView * kidView = nsnull;
kid->GetRect(rect);
kid->GetOffsetFromView(offsetPoint, &kidView);
rect.x = offsetPoint.x;
rect.y = offsetPoint.y;
nscoord y1 = rect.y;
nscoord y2 = rect.y + rect.height;
PRInt32 yDistance = PR_MIN(abs(y1 - aPoint.y),abs(y2 - aPoint.y));
if (yDistance <= closestYDistance && rect.width > 0 && rect.height > 0)
{
if (yDistance < closestYDistance)
closestXDistance = HUGE_DISTANCE;
nscoord x1 = rect.x;
nscoord x2 = rect.x + rect.width;
if (x1 <= aPoint.x && x2 >= aPoint.x && y1 <= aPoint.y && y2 >= aPoint.y)
{
closestFrame = kid;
break;
}
PRInt32 xDistance = PR_MIN(abs(x1 - aPoint.x),abs(x2 - aPoint.x));
if (xDistance < closestXDistance)
{
closestXDistance = xDistance;
closestYDistance = yDistance;
closestFrame = kid;
}
// else if (xDistance > closestXDistance)
// break;//done
}
kid->GetNextSibling(&kid);
}
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;
nsIView *closestView = nsnull;
result = GetClosestViewForFrame(closestFrame, &closestView);
if (NS_FAILED(result))
return result;
if (closestView && view != closestView)
{
nscoord vX = 0, vY = 0;
result = closestView->GetPosition(&vX, &vY);
if (NS_SUCCEEDED(result))
{
newPoint.x -= vX;
newPoint.y -= vY;
}
}
// printf(" 0x%.8x 0x%.8x %4d %4d\n",
// closestFrame, closestView, closestXDistance, closestYDistance);
return closestFrame->GetContentAndOffsetsFromPoint(aCX, newPoint, aNewContent,
aContentOffset, aContentOffsetEnd);
}
}
if (!mContent)
return NS_ERROR_NULL_POINTER;
result = mContent->GetParent(*aNewContent);
if (*aNewContent){
result = (*aNewContent)->IndexOf(mContent, aContentOffset);
if (NS_FAILED(result))
{
return result;
}
aContentOffsetEnd = aContentOffset +1;
}
return result;
}
//--------------------------------------------------------------------------
//-- GetPosition
//--------------------------------------------------------------------------
@ -2310,6 +2460,36 @@ nsFrame::PeekOffset(nsPeekOffsetStruct *aPos)
return result;
}
nsresult nsFrame::GetClosestViewForFrame(nsIFrame *aFrame, nsIView **aView)
{
if (!aView)
return NS_ERROR_NULL_POINTER;
nsresult result = NS_OK;
*aView = 0;
nsIFrame *parent = aFrame;
while (parent && !*aView)
{
result = parent->GetView(aView);
if (NS_FAILED(result))
return result;
if (!*aView)
{
result = parent->GetParent(&parent);
if (NS_FAILED(result))
return result;
}
}
return result;
}
//-----------------------------------------------------------------------------------

View File

@ -274,6 +274,13 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
//--------------------------------------------------
// Additional methods
@ -303,6 +310,8 @@ public:
PRBool IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics);
virtual nsresult GetClosestViewForFrame(nsIFrame *aFrame, nsIView **aView);
#ifdef NS_DEBUG
/**
* Tracing method that writes a method enter/exit routine to the

View File

@ -348,6 +348,12 @@ public:
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd);
NS_IMETHOD GetPositionSlowly(nsIPresContext& aCX,
nsIRenderingContext * aRendContext,
nscoord aXCoord,
@ -1829,6 +1835,16 @@ nsTextFrame::GetPosition(nsIPresContext& aCX,
return NS_OK;
}
NS_IMETHODIMP
nsTextFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX,
const nsPoint& aPoint,
nsIContent ** aNewContent,
PRInt32& aContentOffset,
PRInt32& aContentOffsetEnd)
{
return GetPosition(aCX, (aPoint.x < 0) ? 0 : aPoint.x, aNewContent, aContentOffset, aContentOffsetEnd);
}
// [HACK] Foward Declarations
void ForceDrawFrame(nsFrame * aFrame);