diff --git a/mozilla/layout/base/src/nsRangeList.cpp b/mozilla/layout/base/src/nsRangeList.cpp index 76e01bf17c7..9078e269655 100644 --- a/mozilla/layout/base/src/nsRangeList.cpp +++ b/mozilla/layout/base/src/nsRangeList.cpp @@ -255,7 +255,10 @@ private: void InvalidateDesiredX(); //do not listen to mDesiredX you must get another. void SetDesiredX(nscoord aX); //set the mDesiredX - + nsresult GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent); + nsresult GetGlobalViewOffsetsFromFrame(nsIPresContext *aPresContext, nsIFrame *aFrame, nscoord *offsetX, nscoord *offsetY); + nsresult ConstrainFrameAndPointToAnchorSubtree(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint); + PRUint32 GetBatching(){return mBatching;} PRBool GetNotifyFrames(){return mNotifyFrames;} void SetDirty(PRBool aDirty=PR_TRUE){if (mBatching) mChangesDuringBatching = aDirty;} @@ -744,6 +747,256 @@ nsRangeList::SetDesiredX(nscoord aX) //set the mDesiredX mDesiredXSet = PR_TRUE; } +nsresult +nsRangeList::GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent) +{ + // This method returns the root of the sub-tree containing aContent. + // We do this by searching up through the parent hierarchy, and stopping + // when there are no more parents, or we hit a situation where the + // parent/child relationship becomes invalid. + // + // An example of an invalid parent/child relationship is anonymous content. + // Anonymous content has a pointer to it's parent, but it is not listed + // as a child of it's parent. In this case, the anonymous content would + // be considered the root of the subtree. + + nsresult result; + + if (!aContent || !aParent) + return NS_ERROR_NULL_POINTER; + + *aParent = 0; + + nsCOMPtr parent = do_QueryInterface(aContent); + nsCOMPtr child = parent; + + while (child) + { + result = child->GetParent(*getter_AddRefs(parent)); + + if (NS_FAILED(result)) + return result; + + if (!parent) + break; + + PRInt32 childIndex = 0; + PRInt32 childCount = 0; + + result = parent->ChildCount(childCount); + + if (NS_FAILED(result)) + return result; + + if (childCount < 1) + break; + + result = parent->IndexOf(child, childIndex); + + if (NS_FAILED(result)) + return result; + + if (childIndex < 0 || childIndex >= childCount) + break; + + child = parent; + } + + *aParent = child; + + NS_IF_ADDREF(*aParent); + + return result; +} + +nsresult +nsRangeList::GetGlobalViewOffsetsFromFrame(nsIPresContext *aPresContext, nsIFrame *aFrame, nscoord *offsetX, nscoord *offsetY) +{ + // + // The idea here is to figure out what the offset of aFrame's view + // is within the global space. Where I define the global space to + // be the coordinate system that exists above all views. + // + // The offsets are calculated by walking up the view parent hierarchy, + // adding up all the view positions, until there are no more views. + // + // A point in a view's coordinate space can be converted to the global + // coordinate space by simply adding the offsets returned by this method + // to the point itself. + // + + if (!aPresContext || !aFrame || !offsetX || !offsetY) + return NS_ERROR_NULL_POINTER; + + *offsetX = *offsetY = 0; + + nsresult result; + nsIFrame *frame = aFrame; + nsIView *view; + + while (frame) + { + result = frame->GetParentWithView(aPresContext, &frame); + + if (NS_FAILED(result)) + return result; + + if (frame) { + view = 0; + + result = frame->GetView(aPresContext, &view); + + if (NS_FAILED(result)) + return result; + + if (view) + { + nscoord vX = 0, vY = 0; + + result = view->GetPosition(&vX, &vY); + + if (NS_FAILED(result)) + return result; + + *offsetX += vX; + *offsetY += vY; + } + } + + } + + return NS_OK; +} + +nsresult +nsRangeList::ConstrainFrameAndPointToAnchorSubtree(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint) +{ + // + // The whole point of this method is to return a frame and point that + // that lie within the same valid subtree as the anchor node's frame, + // for use with the method GetContentAndOffsetsFromPoint(). + // + // A valid subtree is defined to be one where all the content nodes in + // the tree have a valid parent-child relationship. + // + // If the anchor frame and aFrame are in the same subtree, aFrame will + // be returned in aRetFrame. If they are in different subtrees, we + // return the frame for the root of the subtree. + // + + if (!aFrame || !aRetFrame) + return NS_ERROR_NULL_POINTER; + + *aRetFrame = aFrame; + aRetPoint = aPoint; + + // + // Get the frame and content for the selection's anchor point! + // + + nsresult result; + nsCOMPtr anchorNode; + PRInt32 anchorOffset = 0; + + if (! mDomSelections[SELECTION_NORMAL]) + return NS_ERROR_NULL_POINTER; + + result = mDomSelections[SELECTION_NORMAL]->GetAnchorNode(getter_AddRefs(anchorNode)); + + if (NS_FAILED(result)) + return result; + + if (!anchorNode) + return NS_OK; + + result = mDomSelections[SELECTION_NORMAL]->GetAnchorOffset(&anchorOffset); + + if (NS_FAILED(result)) + return result; + + nsIFrame *anchorFrame = 0; + nsCOMPtr anchorContent = do_QueryInterface(anchorNode); + + if (!anchorContent) + return NS_ERROR_FAILURE; + + result = GetFrameForNodeOffset(anchorContent, anchorOffset, &anchorFrame); + + // + // Now find the root of the subtree containing the anchor's content. + // + + nsCOMPtr anchorRoot; + result = GetRootForContentSubtree(anchorContent, getter_AddRefs(anchorRoot)); + + if (NS_FAILED(result)) + return result; + + // + // Now find the root of the subtree containing aFrame's content. + // + + nsCOMPtr content; + + result = aFrame->GetContent(getter_AddRefs(content)); + + if (NS_FAILED(result)) + return result; + + if (content) + { + nsCOMPtr contentRoot; + + result = GetRootForContentSubtree(content, getter_AddRefs(contentRoot)); + + if (anchorRoot == contentRoot) + { + // + // The anchor and AFrame's root are the same. There + // is no need to constrain, simply return aFrame. + // + *aRetFrame = aFrame; + return NS_OK; + } + } + + // + // aFrame's root does not match the anchor's root, or there is no + // content associated with aFrame. Just return the primary frame + // for the anchor's root. We'll let GetContentAndOffsetsFromPoint() + // find the closest frame aPoint. + // + + result = mTracker->GetPrimaryFrameFor(anchorRoot, aRetFrame); + + if (NS_FAILED(result)) + return result; + + if (! *aRetFrame) + return NS_ERROR_FAILURE; + + // + // Now make sure that aRetPoint is converted to the same coordinate + // system used by aRetFrame. + // + + nsPoint frameOffset; + nsPoint retFrameOffset; + + result = GetGlobalViewOffsetsFromFrame(aPresContext, aFrame, &frameOffset.x, &frameOffset.y); + + if (NS_FAILED(result)) + return result; + + result = GetGlobalViewOffsetsFromFrame(aPresContext, *aRetFrame, &retFrameOffset.x, &retFrameOffset.y); + + if (NS_FAILED(result)) + return result; + + aRetPoint = aPoint + frameOffset - retFrameOffset; + + return NS_OK; +} #ifdef XP_MAC #pragma mark - @@ -1050,7 +1303,20 @@ nsRangeList::HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, NS_IMETHODIMP nsRangeList::HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint) { + if (!aPresContext || !aFrame) + return NS_ERROR_NULL_POINTER; + nsresult result; + nsIFrame *newFrame = 0; + nsPoint newPoint; + + result = ConstrainFrameAndPointToAnchorSubtree(aPresContext, aFrame, aPoint, &newFrame, newPoint); + + if (NS_FAILED(result)) + return result; + + if (!newFrame) + return NS_ERROR_FAILURE; nsCOMPtr presShell; @@ -1064,9 +1330,9 @@ nsRangeList::HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint& PRBool beginOfContent; nsCOMPtr newContent; - result = aFrame->GetContentAndOffsetsFromPoint(*aPresContext, aPoint, - getter_AddRefs(newContent), - startPos, contentOffsetEnd,beginOfContent); + result = newFrame->GetContentAndOffsetsFromPoint(*aPresContext, newPoint, + getter_AddRefs(newContent), + startPos, contentOffsetEnd,beginOfContent); if (NS_SUCCEEDED(result)) result = HandleClick(newContent, startPos, contentOffsetEnd , PR_TRUE, PR_FALSE,beginOfContent); diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 44c144d5334..5ef77927479 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -1035,6 +1035,64 @@ nsresult nsFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX, 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 = PR_FALSE; + nsFrameState frameState; + result = kid->GetFrameState(&frameState); + + if (NS_FAILED(result)) + return result; + + if (frameState & NS_FRAME_GENERATED_CONTENT) { + // It's generated content, so skip it! + skipThisKid = PR_TRUE; + } + else { + // The frame's content is not generated. Now check + // if it is anonymous content! + + nsCOMPtr kidContent; + + result = kid->GetContent(getter_AddRefs(kidContent)); + + if (NS_SUCCEEDED(result) && kidContent) { + nsCOMPtr content; + + result = kidContent->GetParent(*getter_AddRefs(content)); + + if (NS_SUCCEEDED(result) && content) { + PRInt32 kidCount = 0; + + result = content->ChildCount(kidCount); + if (NS_SUCCEEDED(result)) { + + PRInt32 kidIndex = 0; + result = content->IndexOf(kidContent, kidIndex); + + // IndexOf() should return -1 for the index if it doesn't + // find kidContent in it's child list. + + if (NS_SUCCEEDED(result) && (kidIndex < 0 || kidIndex >= kidCount)) { + // Must be anonymous content! So skip it! + skipThisKid = PR_TRUE; + } + } + } + } + } + + if (skipThisKid) { + kid->GetNextSibling(&kid); + 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; nsPoint offsetPoint(0,0); nsIView * kidView = nsnull; @@ -1066,7 +1124,7 @@ nsresult nsFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX, PRInt32 xDistance = PR_MIN(abs(xa - aPoint.x),abs(xb - aPoint.x)); - if (xDistance < closestXDistance) + if (xDistance < closestXDistance || (xDistance == closestXDistance && rect.x <= aPoint.x)) { closestXDistance = xDistance; closestYDistance = yDistance; diff --git a/mozilla/layout/generic/nsGfxScrollFrame.cpp b/mozilla/layout/generic/nsGfxScrollFrame.cpp index 1e358fe5c9e..63526f3bfeb 100644 --- a/mozilla/layout/generic/nsGfxScrollFrame.cpp +++ b/mozilla/layout/generic/nsGfxScrollFrame.cpp @@ -602,6 +602,19 @@ nsGfxScrollFrame::Paint(nsIPresContext& aPresContext, aWhichLayer); } +NS_IMETHODIMP +nsGfxScrollFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX, + const nsPoint& aPoint, + nsIContent ** aNewContent, + PRInt32& aContentOffset, + PRInt32& aContentOffsetEnd, + PRBool& aBeginFrameContent) +{ + if (! mInner) + return NS_ERROR_NULL_POINTER; + + return mInner->mScrollAreaFrame->GetContentAndOffsetsFromPoint(aCX, aPoint, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent); +} PRIntn nsGfxScrollFrame::GetSkipSides() const diff --git a/mozilla/layout/generic/nsGfxScrollFrame.h b/mozilla/layout/generic/nsGfxScrollFrame.h index 2ed9367d0af..e36bb4529f7 100644 --- a/mozilla/layout/generic/nsGfxScrollFrame.h +++ b/mozilla/layout/generic/nsGfxScrollFrame.h @@ -93,6 +93,13 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); + NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX, + const nsPoint& aPoint, + nsIContent ** aNewContent, + PRInt32& aContentOffset, + PRInt32& aContentOffsetEnd, + PRBool& aBeginFrameContent); + // nsIAnonymousContentCreator NS_IMETHOD CreateAnonymousContent(nsISupportsArray& aAnonymousItems); diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 44c144d5334..5ef77927479 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -1035,6 +1035,64 @@ nsresult nsFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX, 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 = PR_FALSE; + nsFrameState frameState; + result = kid->GetFrameState(&frameState); + + if (NS_FAILED(result)) + return result; + + if (frameState & NS_FRAME_GENERATED_CONTENT) { + // It's generated content, so skip it! + skipThisKid = PR_TRUE; + } + else { + // The frame's content is not generated. Now check + // if it is anonymous content! + + nsCOMPtr kidContent; + + result = kid->GetContent(getter_AddRefs(kidContent)); + + if (NS_SUCCEEDED(result) && kidContent) { + nsCOMPtr content; + + result = kidContent->GetParent(*getter_AddRefs(content)); + + if (NS_SUCCEEDED(result) && content) { + PRInt32 kidCount = 0; + + result = content->ChildCount(kidCount); + if (NS_SUCCEEDED(result)) { + + PRInt32 kidIndex = 0; + result = content->IndexOf(kidContent, kidIndex); + + // IndexOf() should return -1 for the index if it doesn't + // find kidContent in it's child list. + + if (NS_SUCCEEDED(result) && (kidIndex < 0 || kidIndex >= kidCount)) { + // Must be anonymous content! So skip it! + skipThisKid = PR_TRUE; + } + } + } + } + } + + if (skipThisKid) { + kid->GetNextSibling(&kid); + 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; nsPoint offsetPoint(0,0); nsIView * kidView = nsnull; @@ -1066,7 +1124,7 @@ nsresult nsFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX, PRInt32 xDistance = PR_MIN(abs(xa - aPoint.x),abs(xb - aPoint.x)); - if (xDistance < closestXDistance) + if (xDistance < closestXDistance || (xDistance == closestXDistance && rect.x <= aPoint.x)) { closestXDistance = xDistance; closestYDistance = yDistance; diff --git a/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp b/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp index 1e358fe5c9e..63526f3bfeb 100644 --- a/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp +++ b/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp @@ -602,6 +602,19 @@ nsGfxScrollFrame::Paint(nsIPresContext& aPresContext, aWhichLayer); } +NS_IMETHODIMP +nsGfxScrollFrame::GetContentAndOffsetsFromPoint(nsIPresContext& aCX, + const nsPoint& aPoint, + nsIContent ** aNewContent, + PRInt32& aContentOffset, + PRInt32& aContentOffsetEnd, + PRBool& aBeginFrameContent) +{ + if (! mInner) + return NS_ERROR_NULL_POINTER; + + return mInner->mScrollAreaFrame->GetContentAndOffsetsFromPoint(aCX, aPoint, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent); +} PRIntn nsGfxScrollFrame::GetSkipSides() const diff --git a/mozilla/layout/html/base/src/nsGfxScrollFrame.h b/mozilla/layout/html/base/src/nsGfxScrollFrame.h index 2ed9367d0af..e36bb4529f7 100644 --- a/mozilla/layout/html/base/src/nsGfxScrollFrame.h +++ b/mozilla/layout/html/base/src/nsGfxScrollFrame.h @@ -93,6 +93,13 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); + NS_IMETHOD GetContentAndOffsetsFromPoint(nsIPresContext& aCX, + const nsPoint& aPoint, + nsIContent ** aNewContent, + PRInt32& aContentOffset, + PRInt32& aContentOffsetEnd, + PRBool& aBeginFrameContent); + // nsIAnonymousContentCreator NS_IMETHOD CreateAnonymousContent(nsISupportsArray& aAnonymousItems); diff --git a/mozilla/view/src/nsScrollPortView.cpp b/mozilla/view/src/nsScrollPortView.cpp index ae23e5fc0c2..4d359029d08 100644 --- a/mozilla/view/src/nsScrollPortView.cpp +++ b/mozilla/view/src/nsScrollPortView.cpp @@ -1230,9 +1230,23 @@ NS_IMETHODIMP nsScrollPortView::ComputeScrollOffsets(PRBool aAdjustWidgets) NS_IMETHODIMP nsScrollPortView::GetContainerSize(nscoord *aWidth, nscoord *aHeight) const { - GetDimensions(aWidth, aHeight); + if (!aWidth || !aHeight) + return NS_ERROR_NULL_POINTER; - return NS_OK; + *aWidth = 0; + *aHeight = 0; + + nsIView *scrolledView = 0; + + nsresult result = GetScrolledView(scrolledView); + + if (NS_FAILED(result)) + return result; + + if (!scrolledView) + return NS_ERROR_FAILURE; + + return scrolledView->GetDimensions(aWidth, aHeight); } NS_IMETHODIMP nsScrollPortView::ShowQuality(PRBool aShow)