From d38cee3cd4a84aefc6b8129a50a1920972b91709 Mon Sep 17 00:00:00 2001 From: "kin%netscape.com" Date: Thu, 7 Feb 2002 22:39:15 +0000 Subject: [PATCH] Fix for bug 83650 (textarea control has problems with caret positioning at end) and bug 97207 (textarea pastes sometimes misplaced by failing to reposition). - Added new utility method GetOriginToViewOffset(). - Modified nsPresShell::HandleEvent(), nsBoxFrame::GetFrameForPoint(), and nsContainerFrame::GetFrameForPointUsing() to factor in the offset from GetOriginToViewOffset() to insure that the point used is always transformed into the correct coordinate system. Files modified: mozilla/layout/base/public/nsIFrame.h mozilla/layout/html/base/src/nsContainerFrame.cpp mozilla/layout/html/base/src/nsFrame.cpp mozilla/layout/html/base/src/nsFrame.h mozilla/layout/html/base/src/nsPresShell.cpp mozilla/layout/xul/base/src/nsBoxFrame.cpp r=kmcclusk@netscape.com sr=sfraser@netscape.com --- layout/base/nsPresShell.cpp | 22 +++++++-- layout/base/public/nsIFrame.h | 12 +++++ layout/generic/nsContainerFrame.cpp | 10 +++- layout/generic/nsFrame.cpp | 56 +++++++++++++++++++++++ layout/generic/nsFrame.h | 1 + layout/generic/nsIFrame.h | 12 +++++ layout/html/base/src/nsContainerFrame.cpp | 10 +++- layout/html/base/src/nsFrame.cpp | 56 +++++++++++++++++++++++ layout/html/base/src/nsFrame.h | 1 + layout/html/base/src/nsPresShell.cpp | 22 +++++++-- layout/xul/base/src/nsBoxFrame.cpp | 7 ++- 11 files changed, 198 insertions(+), 11 deletions(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 2d4c72c300b2..74cda16ae409 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -5880,13 +5880,27 @@ PresShell::HandleEvent(nsIView *aView, } } else { - // This is because we want to give the point in the same - // coordinates as the frame's own Rect, so mRect.Contains(aPoint) - // works. However, this point is relative to the frame's rect, so - // we need to add on the origin of the rect. + // aEvent->point is relative to aView's upper left corner. We need + // a point that is in the same coordinate system as frame's rect + // so that the frame->mRect.Contains(aPoint) calls in + // GetFrameForPoint() work. The assumption here is that frame->GetView() + // will return aView, and frame's parent view is aView's parent. + nsPoint eventPoint; frame->GetOrigin(eventPoint); eventPoint += aEvent->point; + + nsPoint originOffset; + nsIView *view = nsnull; + frame->GetOriginToViewOffset(mPresContext, originOffset, &view); + +#ifdef DEBUG_kin + NS_ASSERTION(view == aView, "view != aView"); +#endif // DEBUG_kin + + if (view == aView) + eventPoint -= originOffset; + rv = frame->GetFrameForPoint(mPresContext, eventPoint, NS_FRAME_PAINT_LAYER_FOREGROUND, &mCurrentEventFrame); if (rv != NS_OK) { rv = frame->GetFrameForPoint(mPresContext, eventPoint, NS_FRAME_PAINT_LAYER_FLOATERS, &mCurrentEventFrame); diff --git a/layout/base/public/nsIFrame.h b/layout/base/public/nsIFrame.h index aa128ea4cfa2..548fce53cd0d 100644 --- a/layout/base/public/nsIFrame.h +++ b/layout/base/public/nsIFrame.h @@ -961,6 +961,18 @@ public: nsPoint& aOffset, nsIView** aView) const = 0; + /** + * Returns the offset from this frame's upper left corner to the upper + * left corner of the view returned by a call to GetView(). aOffset + * will contain the offset to the view or (0,0) if the frame has no + * view. aView will contain a pointer to the view returned by GetView(). + * aView is optional, that is, you may pass null if you are not interested + * in getting a pointer to the view. + */ + NS_IMETHOD GetOriginToViewOffset(nsIPresContext* aPresContext, + nsPoint& aOffset, + nsIView** aView) const = 0; + /** * Returns the window that contains this frame. If this frame has a * view and the view has a window, then this frames window is diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 7fd91f21fb86..8b10c1f7ae31 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -293,8 +293,16 @@ nsContainerFrame::GetFrameForPointUsing(nsIPresContext* aPresContext, FirstChild(aPresContext, aList, &kid); *aFrame = nsnull; tmp.MoveTo(aPoint.x - mRect.x, aPoint.y - mRect.y); + + nsPoint originOffset; + nsIView *view = nsnull; + nsresult rv = GetOriginToViewOffset(aPresContext, originOffset, &view); + + if (NS_SUCCEEDED(rv) && view) + tmp += originOffset; + while (nsnull != kid) { - nsresult rv = kid->GetFrameForPoint(aPresContext, tmp, aWhichLayer, &hit); + rv = kid->GetFrameForPoint(aPresContext, tmp, aWhichLayer, &hit); if (NS_SUCCEEDED(rv) && hit) { *aFrame = hit; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 6677a70a88ef..a0572104d466 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2042,6 +2042,62 @@ NS_IMETHODIMP nsFrame::GetOffsetFromView(nsIPresContext* aPresContext, return NS_OK; } +// The (x,y) value of the frame's upper left corner is always +// relative to its parentFrame's upper left corner, unless +// its parentFrame has a view associated with it, in which case, it +// will be relative to the upper left corner of the view returned +// by a call to parentFrame->GetView(). +// +// This means that while drilling down the frame hierarchy, from +// parent to child frame, we sometimes need to take into account +// crossing these view boundaries, because the coordinate system +// changes from parent frame coordinate system, to the associated +// view's coordinate system. +// +// GetOriginToViewOffset() is a utility method that returns the +// offset necessary to map a point, relative to the frame's upper +// left corner, into the coordinate system of the view associated +// with the frame. +// +// If there is no view associated with the frame, the offset +// returned will always be (0,0). + +NS_IMETHODIMP nsFrame::GetOriginToViewOffset(nsIPresContext* aPresContext, + nsPoint& aOffset, + nsIView** aView) const +{ + NS_ENSURE_ARG_POINTER(aPresContext); + + aOffset.MoveTo(0,0); + + if (aView) + *aView = nsnull; + + nsIView *view = nsnull; + nsresult rv = GetView(aPresContext, &view); + + if (NS_SUCCEEDED(rv) && view) { + nsIView *parentView = nsnull; + nsPoint offsetToParentView; + rv = GetOffsetFromView(aPresContext, offsetToParentView, &parentView); + + if (NS_SUCCEEDED(rv)) { + nsPoint viewPos; + rv = view->GetPosition(&viewPos.x, &viewPos.y); + + if (NS_SUCCEEDED(rv)) { + aOffset = offsetToParentView - viewPos; + + if (aView) + *aView = view; + } + } + } + + return rv; +} + + NS_IMETHODIMP nsFrame::GetWindow(nsIPresContext* aPresContext, nsIWidget** aWindow) const { diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 95666458d586..f2b52479b2de 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -249,6 +249,7 @@ public: NS_IMETHOD SetView(nsIPresContext* aPresContext, nsIView* aView); NS_IMETHOD GetParentWithView(nsIPresContext* aPresContext, nsIFrame** aParent) const; NS_IMETHOD GetOffsetFromView(nsIPresContext* aPresContext, nsPoint& aOffset, nsIView** aView) const; + NS_IMETHOD GetOriginToViewOffset(nsIPresContext *aPresContext, nsPoint& aOffset, nsIView **aView) const; NS_IMETHOD GetWindow(nsIPresContext* aPresContext, nsIWidget**) const; NS_IMETHOD GetFrameType(nsIAtom** aType) const; NS_IMETHOD IsPercentageBase(PRBool& aBase) const; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index aa128ea4cfa2..548fce53cd0d 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -961,6 +961,18 @@ public: nsPoint& aOffset, nsIView** aView) const = 0; + /** + * Returns the offset from this frame's upper left corner to the upper + * left corner of the view returned by a call to GetView(). aOffset + * will contain the offset to the view or (0,0) if the frame has no + * view. aView will contain a pointer to the view returned by GetView(). + * aView is optional, that is, you may pass null if you are not interested + * in getting a pointer to the view. + */ + NS_IMETHOD GetOriginToViewOffset(nsIPresContext* aPresContext, + nsPoint& aOffset, + nsIView** aView) const = 0; + /** * Returns the window that contains this frame. If this frame has a * view and the view has a window, then this frames window is diff --git a/layout/html/base/src/nsContainerFrame.cpp b/layout/html/base/src/nsContainerFrame.cpp index 7fd91f21fb86..8b10c1f7ae31 100644 --- a/layout/html/base/src/nsContainerFrame.cpp +++ b/layout/html/base/src/nsContainerFrame.cpp @@ -293,8 +293,16 @@ nsContainerFrame::GetFrameForPointUsing(nsIPresContext* aPresContext, FirstChild(aPresContext, aList, &kid); *aFrame = nsnull; tmp.MoveTo(aPoint.x - mRect.x, aPoint.y - mRect.y); + + nsPoint originOffset; + nsIView *view = nsnull; + nsresult rv = GetOriginToViewOffset(aPresContext, originOffset, &view); + + if (NS_SUCCEEDED(rv) && view) + tmp += originOffset; + while (nsnull != kid) { - nsresult rv = kid->GetFrameForPoint(aPresContext, tmp, aWhichLayer, &hit); + rv = kid->GetFrameForPoint(aPresContext, tmp, aWhichLayer, &hit); if (NS_SUCCEEDED(rv) && hit) { *aFrame = hit; diff --git a/layout/html/base/src/nsFrame.cpp b/layout/html/base/src/nsFrame.cpp index 6677a70a88ef..a0572104d466 100644 --- a/layout/html/base/src/nsFrame.cpp +++ b/layout/html/base/src/nsFrame.cpp @@ -2042,6 +2042,62 @@ NS_IMETHODIMP nsFrame::GetOffsetFromView(nsIPresContext* aPresContext, return NS_OK; } +// The (x,y) value of the frame's upper left corner is always +// relative to its parentFrame's upper left corner, unless +// its parentFrame has a view associated with it, in which case, it +// will be relative to the upper left corner of the view returned +// by a call to parentFrame->GetView(). +// +// This means that while drilling down the frame hierarchy, from +// parent to child frame, we sometimes need to take into account +// crossing these view boundaries, because the coordinate system +// changes from parent frame coordinate system, to the associated +// view's coordinate system. +// +// GetOriginToViewOffset() is a utility method that returns the +// offset necessary to map a point, relative to the frame's upper +// left corner, into the coordinate system of the view associated +// with the frame. +// +// If there is no view associated with the frame, the offset +// returned will always be (0,0). + +NS_IMETHODIMP nsFrame::GetOriginToViewOffset(nsIPresContext* aPresContext, + nsPoint& aOffset, + nsIView** aView) const +{ + NS_ENSURE_ARG_POINTER(aPresContext); + + aOffset.MoveTo(0,0); + + if (aView) + *aView = nsnull; + + nsIView *view = nsnull; + nsresult rv = GetView(aPresContext, &view); + + if (NS_SUCCEEDED(rv) && view) { + nsIView *parentView = nsnull; + nsPoint offsetToParentView; + rv = GetOffsetFromView(aPresContext, offsetToParentView, &parentView); + + if (NS_SUCCEEDED(rv)) { + nsPoint viewPos; + rv = view->GetPosition(&viewPos.x, &viewPos.y); + + if (NS_SUCCEEDED(rv)) { + aOffset = offsetToParentView - viewPos; + + if (aView) + *aView = view; + } + } + } + + return rv; +} + + NS_IMETHODIMP nsFrame::GetWindow(nsIPresContext* aPresContext, nsIWidget** aWindow) const { diff --git a/layout/html/base/src/nsFrame.h b/layout/html/base/src/nsFrame.h index 95666458d586..f2b52479b2de 100644 --- a/layout/html/base/src/nsFrame.h +++ b/layout/html/base/src/nsFrame.h @@ -249,6 +249,7 @@ public: NS_IMETHOD SetView(nsIPresContext* aPresContext, nsIView* aView); NS_IMETHOD GetParentWithView(nsIPresContext* aPresContext, nsIFrame** aParent) const; NS_IMETHOD GetOffsetFromView(nsIPresContext* aPresContext, nsPoint& aOffset, nsIView** aView) const; + NS_IMETHOD GetOriginToViewOffset(nsIPresContext *aPresContext, nsPoint& aOffset, nsIView **aView) const; NS_IMETHOD GetWindow(nsIPresContext* aPresContext, nsIWidget**) const; NS_IMETHOD GetFrameType(nsIAtom** aType) const; NS_IMETHOD IsPercentageBase(PRBool& aBase) const; diff --git a/layout/html/base/src/nsPresShell.cpp b/layout/html/base/src/nsPresShell.cpp index 2d4c72c300b2..74cda16ae409 100644 --- a/layout/html/base/src/nsPresShell.cpp +++ b/layout/html/base/src/nsPresShell.cpp @@ -5880,13 +5880,27 @@ PresShell::HandleEvent(nsIView *aView, } } else { - // This is because we want to give the point in the same - // coordinates as the frame's own Rect, so mRect.Contains(aPoint) - // works. However, this point is relative to the frame's rect, so - // we need to add on the origin of the rect. + // aEvent->point is relative to aView's upper left corner. We need + // a point that is in the same coordinate system as frame's rect + // so that the frame->mRect.Contains(aPoint) calls in + // GetFrameForPoint() work. The assumption here is that frame->GetView() + // will return aView, and frame's parent view is aView's parent. + nsPoint eventPoint; frame->GetOrigin(eventPoint); eventPoint += aEvent->point; + + nsPoint originOffset; + nsIView *view = nsnull; + frame->GetOriginToViewOffset(mPresContext, originOffset, &view); + +#ifdef DEBUG_kin + NS_ASSERTION(view == aView, "view != aView"); +#endif // DEBUG_kin + + if (view == aView) + eventPoint -= originOffset; + rv = frame->GetFrameForPoint(mPresContext, eventPoint, NS_FRAME_PAINT_LAYER_FOREGROUND, &mCurrentEventFrame); if (rv != NS_OK) { rv = frame->GetFrameForPoint(mPresContext, eventPoint, NS_FRAME_PAINT_LAYER_FLOATERS, &mCurrentEventFrame); diff --git a/layout/xul/base/src/nsBoxFrame.cpp b/layout/xul/base/src/nsBoxFrame.cpp index 3c45e9abdd53..024810df756c 100644 --- a/layout/xul/base/src/nsBoxFrame.cpp +++ b/layout/xul/base/src/nsBoxFrame.cpp @@ -1977,7 +1977,8 @@ nsBoxFrame::GetFrameForPoint(nsIPresContext* aPresContext, return NS_ERROR_FAILURE; nsIView* view = nsnull; - GetView(aPresContext, &view); + nsPoint originOffset; + GetOriginToViewOffset(aPresContext, originOffset, &view); // get the debug frame. if (view || (mState & NS_STATE_IS_ROOT)) @@ -2002,6 +2003,10 @@ nsBoxFrame::GetFrameForPoint(nsIPresContext* aPresContext, FirstChild(aPresContext, nsnull, &kid); *aFrame = nsnull; tmp.MoveTo(aPoint.x - mRect.x, aPoint.y - mRect.y); + + if (view) + tmp += originOffset; + while (nsnull != kid) { // have we hit a child before PRBool haveKid = (hit != nsnull);