From f53f98f7f3c1d2184d2e86378644e1bea70f6f31 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Wed, 3 Nov 2004 16:16:57 +0000 Subject: [PATCH] Create an api for easily converting between the coordinate systems of two frames or two views. Use this to fix the auto-positioning of abs pos boxes to work no matter how their containing block and the block their placeholder lives in are related, and convert various other callers to the new API. Bug 266968, r+sr=roc git-svn-id: svn://10.0.0.236/trunk@164857 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/accessible/src/base/nsAccessible.cpp | 14 +-- mozilla/content/base/src/nsSelection.cpp | 85 ++----------------- mozilla/layout/base/nsCSSFrameConstructor.cpp | 75 +++++----------- mozilla/layout/base/nsCSSRendering.cpp | 15 +--- mozilla/layout/base/public/nsIFrame.h | 20 ++++- mozilla/layout/forms/nsListControlFrame.cpp | 22 +---- mozilla/layout/forms/nsListControlFrame.h | 1 - mozilla/layout/generic/nsContainerFrame.cpp | 18 +--- mozilla/layout/generic/nsFrame.cpp | 80 +++++++++-------- mozilla/layout/generic/nsGfxScrollFrame.cpp | 18 +--- mozilla/layout/generic/nsHTMLReflowState.cpp | 50 ++--------- mozilla/layout/generic/nsIFrame.h | 20 ++++- mozilla/layout/generic/nsSelection.cpp | 85 ++----------------- .../layout/html/base/src/nsContainerFrame.cpp | 18 +--- mozilla/layout/html/base/src/nsFrame.cpp | 80 +++++++++-------- .../layout/html/base/src/nsGfxScrollFrame.cpp | 18 +--- .../html/base/src/nsHTMLReflowState.cpp | 50 ++--------- .../html/forms/src/nsListControlFrame.cpp | 22 +---- .../html/forms/src/nsListControlFrame.h | 1 - .../html/style/src/nsCSSFrameConstructor.cpp | 75 +++++----------- .../layout/html/style/src/nsCSSRendering.cpp | 15 +--- mozilla/view/public/nsIView.h | 15 ++++ mozilla/view/src/nsView.cpp | 21 +++++ 23 files changed, 249 insertions(+), 569 deletions(-) diff --git a/mozilla/accessible/src/base/nsAccessible.cpp b/mozilla/accessible/src/base/nsAccessible.cpp index d7ae7390c95..dba0998de44 100644 --- a/mozilla/accessible/src/base/nsAccessible.cpp +++ b/mozilla/accessible/src/base/nsAccessible.cpp @@ -709,19 +709,11 @@ void nsAccessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame // Look only at frames below this depth, or at this depth (if we're still on the content node we started with) while (iterContent == firstContent || depth > 0) { // Coordinates will come back relative to parent frame - nsIFrame *parentFrame = iterFrame; nsRect currFrameBounds = iterFrame->GetRect(); - - // We just want the width and height - only get relative coordinates if we're not already - // at the bounding frame - currFrameBounds.x = currFrameBounds.y = 0; - + // Make this frame's bounds relative to common parent frame - while (parentFrame && parentFrame != *aBoundingFrame) { - // Add this frame's bounds to our total rectangle - currFrameBounds += parentFrame->GetPosition(); - parentFrame = parentFrame->GetParent(); - } + currFrameBounds += + iterFrame->GetParent()->GetOffsetToExternal(*aBoundingFrame); // Add this frame's bounds to total aTotalBounds.UnionRect(aTotalBounds, currFrameBounds); diff --git a/mozilla/content/base/src/nsSelection.cpp b/mozilla/content/base/src/nsSelection.cpp index 3aa80800d40..718776ff880 100644 --- a/mozilla/content/base/src/nsSelection.cpp +++ b/mozilla/content/base/src/nsSelection.cpp @@ -442,7 +442,6 @@ private: void SetDesiredX(nscoord aX); //set the mDesiredX nsresult GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent); - nsresult GetGlobalViewOffsetsFromFrame(nsPresContext *aPresContext, nsIFrame *aFrame, nscoord *offsetX, nscoord *offsetY); nsresult ConstrainFrameAndPointToAnchorSubtree(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint); PRUint32 GetBatching(){return mBatching;} @@ -1047,47 +1046,6 @@ nsSelection::GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent return NS_OK; } -nsresult -nsSelection::GetGlobalViewOffsetsFromFrame(nsPresContext *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; - - nsIFrame *frame = aFrame; - while (frame) - { - frame = frame->GetAncestorWithView(); - - if (frame) { - nsIView *view = frame->GetView(); - - if (view) - { - nsPoint pt = view->GetPosition(); - *offsetX += pt.x; - *offsetY += pt.y; - } - } - } - - return NS_OK; -} - nsresult nsSelection::ConstrainFrameAndPointToAnchorSubtree(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint) { @@ -1197,20 +1155,7 @@ nsSelection::ConstrainFrameAndPointToAnchorSubtree(nsPresContext *aPresContext, // 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; + aRetPoint = aPoint + aFrame->GetOffsetTo(*aRetFrame); return NS_OK; } @@ -2958,13 +2903,7 @@ nsSelection::CommonPageMove(PRBool aForward, if (caretView) { - while (caretView != scrolledView) - { - caretPos += caretView->GetPosition(); - caretView = caretView->GetParent(); - if (!caretView) //how did we miss the scrolled view. something is very wrong - return NS_ERROR_FAILURE; - } + caretPos += caretView->GetOffsetTo(scrolledView); } // get a content at desired location @@ -5223,16 +5162,10 @@ nsTypedSelection::GetViewAncestorOffset(nsIView *aView, nsIView *aAncestorView, if (!aView || !aXOffset || !aYOffset) return NS_ERROR_FAILURE; - *aXOffset = 0; - *aYOffset = 0; + nsPoint offset = aView->GetOffsetTo(aAncestorView); - for (nsIView* view = aView; view && view != aAncestorView; - view = view->GetParent()) - { - nsPoint pt = view->GetPosition(); - *aXOffset += pt.x; - *aYOffset += pt.y; - } + *aXOffset = offset.x; + *aYOffset = offset.y; return NS_OK; } @@ -6740,13 +6673,7 @@ nsTypedSelection::GetFrameToScrolledViewOffsets(nsIScrollableView *aScrollableVi // XXX Deal with the case where there is a scrolled element, e.g., a // DIV in the middle... - while (closestView && closestView != scrolledView) { - // Update the offset - offset += closestView->GetPosition(); - - // Get its parent view - closestView = closestView->GetParent(); - } + offset += closestView->GetOffsetTo(scrolledView); *aX = offset.x; *aY = offset.y; diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 7ee55b16768..6a34d0b2d2f 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -1353,47 +1353,27 @@ GetRealFrame(nsIFrame* aFrame) /** * Utility method, called from MoveChildrenTo(), that recursively - * descends down the frame hierarchy looking for out-of-flow frames that + * descends down the frame hierarchy looking for floating frames that * need parent pointer adjustments to account for the containment block * changes that could occur as the result of the reparenting done in * MoveChildrenTo(). */ static void -AdjustOutOfFlowFrameParentPtrs(nsPresContext* aPresContext, - nsIFrame* aFrame, - nsFrameConstructorState* aState) +AdjustFloatParentPtrs(nsIFrame* aFrame, + nsFrameConstructorState& aState) { nsIFrame *outOfFlowFrame = GetRealFrame(aFrame); if (outOfFlowFrame && outOfFlowFrame != aFrame) { // Get the display data for the outOfFlowFrame so we can - // figure out if it is a float or absolutely positioned element. + // figure out if it is a float. - const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay(); - - // Update the parent pointer for outOfFlowFrame if it's - // containing block has changed as the result of reparenting, - // XXXbz Why is this needed? The reflow code can just be tweaked to do - // better coordinate system conversion, and then this case will work. - - if (NS_STYLE_POSITION_ABSOLUTE == display->mPosition) { - // XXX_kin: I think we'll need to add code here to handle the - // XXX_kin: reparenting that can happen in ConstructInline()? - // XXX_kin: - // XXX_kin: The case I'm thinking about here is when the inline being - // XXX_kin: constructed has a style="position: relative;" property - // XXX_kin: on it, and ConstructInline() moves/reparents all child block - // XXX_kin: frames and any inlines (including placeholders) that happen - // XXX_kin: to be between these blocks, under the new inline-block it created. - // XXX_kin: I think right now this case generates an assertion during - // XXX_kin: reflow, and as a result things fail to render since I believe - // XXX_kin: the placeholder is parented to the inline-block, and the - // XXX_kin: outOfFlowFrame is in the original inline frame's absolute list, - // XXX_kin: and is also parented to it. - } - else if (NS_STYLE_FLOAT_NONE != display->mFloats) { - nsIFrame *parent = aState->mFloatedItems.containingBlock; + if (outOfFlowFrame->GetStyleDisplay()->IsFloating()) { + // Update the parent pointer for outOfFlowFrame if it's + // containing block has changed as the result of reparenting, + + nsIFrame *parent = aState.mFloatedItems.containingBlock; outOfFlowFrame->SetParent(parent); if (outOfFlowFrame->GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) { @@ -1404,25 +1384,17 @@ AdjustOutOfFlowFrameParentPtrs(nsPresContext* aPresContext, } } - // XXX_kin: We'll need to remove the return below when we support - // XXX_kin: descending into out-of-flow frames. Here are some notes - // XXX_kin: from waterson: - // XXX_kin: - // XXX_kin: We'd want to continue to descend into placeholders - // XXX_kin: until we found an out-of-flow frame that established - // XXX_kin: a new containing block for absolutely positioned - // XXX_kin: elements. At that point, we could terminate the descent, - // XXX_kin: because any absolutely positioned frames below that frame - // XXX_kin: would be properly parented. - + // All out-of-flows are automatically float containing blocks, so we're + // done here return; } - // XXX_kin: Since we're only handling floats at the moment, - // XXX_kin: we don't need to cross block boundaries. - - if (IsBlockFrame(aPresContext, aFrame)) + // XXXbz we really want IsFloatContainingBlock() here! + if (IsBlockFrame(aState.mPresContext, aFrame)) { + // No need to recurse further; floats whose placeholders are + // inside a block already have the right parent. return; + } // Dive down into children to see if any of their // placeholders need adjusting. @@ -1431,14 +1403,9 @@ AdjustOutOfFlowFrameParentPtrs(nsPresContext* aPresContext, while (childFrame) { - // XXX_kin: Once we add support for adjusting absolutely positioned - // XXX_kin: frames, we will be crossing block boundaries, we/ll need - // XXX_kin: to update aState's containingBlock info to avoid incorrectly - // XXX_kin: reparenting floats, etc. - // XXX_kin: // XXX_kin: Do we need to prevent descent into anonymous content here? - AdjustOutOfFlowFrameParentPtrs(aPresContext, childFrame, aState); + AdjustFloatParentPtrs(childFrame, aState); childFrame = childFrame->GetNextSibling(); } } @@ -1467,11 +1434,11 @@ MoveChildrenTo(nsPresContext* aPresContext, aFrameList->SetParent(aNewParent); - // If aState is not null, the caller expects us to make adjustments - // so that placeholder out of flow frames point to the correct parent. - + // If aState is not null, the caller expects us to make adjustments so that + // floats whose placeholders are descendants of frames in aFrameList point + // to the correct parent. if (aState) - AdjustOutOfFlowFrameParentPtrs(aPresContext, aFrameList, aState); + AdjustFloatParentPtrs(aFrameList, *aState); #if 0 // XXX When this is used with {ib} frame hierarchies, it seems diff --git a/mozilla/layout/base/nsCSSRendering.cpp b/mozilla/layout/base/nsCSSRendering.cpp index a35f079235f..fb41bb45b50 100644 --- a/mozilla/layout/base/nsCSSRendering.cpp +++ b/mozilla/layout/base/nsCSSRendering.cpp @@ -3015,18 +3015,11 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext, ComputeBackgroundAnchorPoint(aColor, viewportArea, viewportArea, tileWidth, tileHeight, anchor); // Convert the anchor point to aForFrame's coordinate space - nsIView* view = aForFrame->GetView(); - if (!view) { - nsPoint offset; - aForFrame->GetOffsetFromView(aPresContext, offset, &view); - anchor -= offset; - } + nsPoint offset(0, 0); + nsIView* view = aForFrame->GetClosestView(&offset); + anchor -= offset; NS_ASSERTION(view, "expected a view"); - while (view && (view != viewportView)) { - anchor -= view->GetPosition(); - // Get the parent view until we reach the viewport view - view = view->GetParent(); - } + anchor -= view->GetOffsetTo(viewportView); } else { if (frameType == nsLayoutAtoms::canvasFrame) { // If the frame is the canvas, the image is placed relative to diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h index 3d9e3535365..a353cc15728 100644 --- a/mozilla/layout/base/public/nsIFrame.h +++ b/mozilla/layout/base/public/nsIFrame.h @@ -972,8 +972,10 @@ public: /** * Find the closest view (on |this| or an ancestor). + * If aOffset is non-null, it will be set to the offset of |this| + * from the returned view. */ - nsIView* GetClosestView() const; + nsIView* GetClosestView(nsPoint* aOffset = nsnull) const; /** * Find the closest ancestor (excluding |this| !) that has a view @@ -981,6 +983,22 @@ public: nsIFrame* GetAncestorWithView() const; virtual nsIFrame* GetAncestorWithViewExternal() const; + /** + * Get the offset between the coordinate systems of |this| and aOther. + * Adding the return value to a point in the coordinate system of |this| + * will transform the point to the coordinate system of aOther. + * + * aOther must be non-null. + * + * This function is fastest when aOther is an ancestor of |this|. + * + * NOTE: this actually returns the offset from aOther to |this|, but + * that offset is added to transform _coordinates_ from |this| to + * aOther. + */ + nsPoint GetOffsetTo(const nsIFrame* aOther) const; + virtual nsPoint GetOffsetToExternal(const nsIFrame* aOther) const; + /** * Returns the offset from this frame to the closest geometric parent that * has a view. Also returns the containing view or null in case of error diff --git a/mozilla/layout/forms/nsListControlFrame.cpp b/mozilla/layout/forms/nsListControlFrame.cpp index c77030fe8ca..12b5ccc6914 100644 --- a/mozilla/layout/forms/nsListControlFrame.cpp +++ b/mozilla/layout/forms/nsListControlFrame.cpp @@ -505,12 +505,7 @@ void nsListControlFrame::PaintFocus(nsIRenderingContext& aRC, nsFramePaintLayer nsRect fRect = childframe->GetRect(); // get it into the coordinates of containerFrame - for (nsIFrame* ancestor = childframe->GetParent(); - ancestor && ancestor != containerFrame; - ancestor = ancestor->GetParent()) { - fRect += ancestor->GetPosition(); - } - + fRect.MoveBy(childframe->GetParent()->GetOffsetTo(containerFrame)); PRBool lastItemIsSelected = PR_FALSE; if (focusedIndex != kNothingSelected) { nsCOMPtr node; @@ -2242,21 +2237,6 @@ nsListControlFrame::GetProperty(nsIAtom* aName, nsAString& aValue) return NS_OK; } -//--------------------------------------------------------- -void -nsListControlFrame::GetViewOffset(nsIViewManager* aManager, nsIView* aView, - nsPoint& aPoint) -{ - aPoint.x = 0; - aPoint.y = 0; - - for (nsIView* parent = aView; - parent && parent->GetViewManager() == aManager; - parent = parent->GetParent()) { - aPoint += parent->GetPosition(); - } -} - //--------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::SyncViewWithFrame(nsPresContext* aPresContext) diff --git a/mozilla/layout/forms/nsListControlFrame.h b/mozilla/layout/forms/nsListControlFrame.h index e9df1685456..f4b92f5fbe6 100644 --- a/mozilla/layout/forms/nsListControlFrame.h +++ b/mozilla/layout/forms/nsListControlFrame.h @@ -237,7 +237,6 @@ protected: nsIContent* GetOptionContent(PRInt32 aIndex); PRBool IsContentSelected(nsIContent* aContent); PRBool IsContentSelectedByIndex(PRInt32 aIndex); - void GetViewOffset(nsIViewManager* aManager, nsIView* aView, nsPoint& aPoint); PRBool IsOptionElement(nsIContent* aContent); PRBool CheckIfAllFramesHere(); PRInt32 GetIndexFromContent(nsIContent *aContent); diff --git a/mozilla/layout/generic/nsContainerFrame.cpp b/mozilla/layout/generic/nsContainerFrame.cpp index 7551fb20bf2..866e37a3c36 100644 --- a/mozilla/layout/generic/nsContainerFrame.cpp +++ b/mozilla/layout/generic/nsContainerFrame.cpp @@ -433,17 +433,6 @@ nsContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) ///////////////////////////////////////////////////////////////////////////// // Helper member functions -static PRBool -TranslatePointTo(nsPoint& aPoint, nsIView* aChildView, nsIView* aParentView) -{ - do { - aPoint += aChildView->GetPosition(); - aChildView = aChildView->GetParent(); - } while (aChildView && (aChildView != aParentView)); - - return aChildView == aParentView; -} - /** * Position the view associated with |aKidFrame|, if there is one. A * container frame should call this method after positioning a frame, @@ -498,12 +487,7 @@ nsContainerFrame::PositionFrameView(nsPresContext* aPresContext, // We have the origin in the coordinate space of the containing view, // but we need it in the coordinate space of the parent view so do a // view translation -#ifdef DEBUG - PRBool ok = -#endif - TranslatePointTo(origin, containingView, parentView); - - NS_ASSERTION(ok, "translation failed"); + origin += containingView->GetOffsetTo(parentView); } } diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 6015ad76c6e..8f52648d6ea 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -1213,23 +1213,7 @@ ContentContainsPoint(nsPresContext *aPresContext, // that our point is in the same view space our content frame's // rects are in. - nsPoint point(*aPoint); - - if (frameView != aRelativeView) { - // Views are different, just assume frameView is an ancestor - // of aRelativeView and walk up the view hierarchy calculating what - // the actual point is, relative to frameView. - - while (aRelativeView && aRelativeView != frameView) { - point += aRelativeView->GetPosition(); - aRelativeView = aRelativeView->GetParent(); - } - - // At this point the point should be in the correct - // view coordinate space. If not, just bail! - - if (aRelativeView != frameView) return PR_FALSE; - } + 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. @@ -1242,10 +1226,7 @@ ContentContainsPoint(nsPresContext *aPresContext, frameRect.x = offsetPoint.x; frameRect.y = offsetPoint.y; - if (frameRect.x <= point.x && - frameRect.XMost() >= point.x && - frameRect.y <= point.y && - frameRect.YMost() >= point.y) { + if (frameRect.Contains(point)) { // point is within this frame's rect! return PR_TRUE; } @@ -1759,19 +1740,7 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, nsPoint dummyPoint; nsIView* eventView; GetOffsetFromView(aPresContext, dummyPoint, &eventView); - nsPoint pt = aEvent->point; - nsIView* view = eventView; - while (view && view != captureView) { - pt += view->GetPosition(); - view = view->GetParent(); - } - if (!view) { - // Hmm. Maybe captureView is a child of eventView? Recover by - // subtracting the global offset of eventView. - for (view = eventView; view; view = view->GetParent()) { - pt -= view->GetPosition(); - } - } + nsPoint pt = aEvent->point + eventView->GetOffsetTo(captureView); frameselection->StartAutoScrollTimer(aPresContext, captureView, pt, 30); } @@ -2298,6 +2267,35 @@ nsIFrame* nsIFrame::GetAncestorWithView() const return nsnull; } +// virtual +nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const +{ + return GetOffsetTo(aOther); +} + +nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const +{ + NS_PRECONDITION(aOther, + "Must have frame for destination coordinate system!"); + // Note that if we hit a view while walking up the frame tree we need to stop + // and switch to traversing the view tree so that we will deal with scroll + // views properly. + nsPoint offset(0, 0); + const nsIFrame* f; + for (f = this; !f->HasView() && f != aOther; f = f->GetParent()) { + offset += f->GetPosition(); + } + + if (f != aOther) { + // We found a view. Switch to the view tree + nsPoint toViewOffset(0, 0); + nsIView* otherView = aOther->GetClosestView(&toViewOffset); + offset += f->GetView()->GetOffsetTo(otherView) - toViewOffset; + } + + return offset; +} + // Returns the offset from this frame to the closest geometric parent that // has a view. Also returns the containing view or null in case of error NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPresContext* aPresContext, @@ -2369,6 +2367,7 @@ NS_IMETHODIMP nsFrame::GetOriginToViewOffset(nsPresContext* aPresContext, nsIView *tmpView = pview->GetParent(); if (tmpView && vVM != tmpView->GetViewManager()) { // Don't cross ViewManager boundaries! + // XXXbz why not? break; } pview = tmpView; @@ -4145,12 +4144,19 @@ nsFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct * return NS_OK; } -nsIView* nsIFrame::GetClosestView() const +nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const { - for (const nsIFrame *f = this; f; f = f->GetParent()) - if (f->HasView()) + nsPoint offset(0,0); + for (const nsIFrame *f = this; f; f = f->GetParent()) { + if (f->HasView()) { + if (aOffset) + *aOffset = offset; return f->GetView(); + } + offset += f->GetPosition(); + } + NS_NOTREACHED("No view on any parent? How did that happen?"); return nsnull; } diff --git a/mozilla/layout/generic/nsGfxScrollFrame.cpp b/mozilla/layout/generic/nsGfxScrollFrame.cpp index f64615eab01..e12df9ffb1a 100644 --- a/mozilla/layout/generic/nsGfxScrollFrame.cpp +++ b/mozilla/layout/generic/nsGfxScrollFrame.cpp @@ -281,18 +281,13 @@ nsHTMLScrollFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX, PRInt32& aContentOffsetEnd, PRBool& aBeginFrameContent) { - nsPoint point(aPoint); //we need to translate the coordinates to the inner nsIView *view = GetClosestView(); if (!view) return NS_ERROR_FAILURE; - nsIView *innerView = GetClosestView(); - while (view != innerView && innerView) - { - point -= innerView->GetPosition(); - innerView = innerView->GetParent(); - } + nsIView *innerView = mInner.mScrollAreaBox->GetClosestView(); + nsPoint point = aPoint - innerView->GetOffsetTo(view); return mInner.mScrollAreaBox->GetContentAndOffsetsFromPoint(aCX, point, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent); } @@ -809,18 +804,13 @@ nsXULScrollFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX, PRInt32& aContentOffsetEnd, PRBool& aBeginFrameContent) { - nsPoint point(aPoint); //we need to translate the coordinates to the inner nsIView *view = GetClosestView(); if (!view) return NS_ERROR_FAILURE; - nsIView *innerView = GetClosestView(); - while (view != innerView && innerView) - { - point -= innerView->GetPosition(); - innerView = innerView->GetParent(); - } + nsIView *innerView = mInner.mScrollAreaBox->GetClosestView(); + nsPoint point = aPoint - innerView->GetOffsetTo(view); return mInner.mScrollAreaBox->GetContentAndOffsetsFromPoint(aCX, point, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent); } diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index 8614c17dee4..eb6aaf1662b 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -685,22 +685,6 @@ nsHTMLReflowState::CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWid margin.left + margin.right; } -static void -GetPlaceholderOffset(nsIFrame* aPlaceholderFrame, - nsIFrame* aBlockFrame, - nsPoint& aOffset) -{ - aOffset = aPlaceholderFrame->GetPosition(); - - // Convert the placeholder position to the coordinate space of the block - // frame that contains it - nsIFrame* parent = aPlaceholderFrame->GetParent(); - while (parent && (parent != aBlockFrame)) { - aOffset += parent->GetPosition(); - parent = parent->GetParent(); - } -} - static nsIFrame* FindImmediateChildOf(nsIFrame* aParent, nsIFrame* aDescendantFrame) { @@ -794,8 +778,7 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, // space of the block frame that contains it // XXXbz the placeholder is not fully reflown yet if our containing block is // relatively positioned... - nsPoint placeholderOffset; - GetPlaceholderOffset(aPlaceholderFrame, aBlockFrame, placeholderOffset); + nsPoint placeholderOffset = aPlaceholderFrame->GetOffsetTo(aBlockFrame); // First, determine the hypothetical box's mTop if (aBlockFrame) { @@ -895,32 +878,11 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, // The current coordinate space is that of the nearest block to the placeholder. // Convert to the coordinate space of the absolute containing block - nsIFrame* absoluteContainingBlock = cbrs->frame; - if (aBlockFrame != absoluteContainingBlock) { - nsIFrame* parent; - nsIFrame* stop; - if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { - // The absolute containing block is an inline frame... so it will be a - // descendant of aBlockFrame - parent = absoluteContainingBlock; - stop = aBlockFrame; - } else { - // aBlockFrame may be a descendant of absoluteContainingBlock - parent = aBlockFrame; - stop = absoluteContainingBlock; - } - do { - nsPoint origin = parent->GetPosition(); - - aHypotheticalBox.mLeft += origin.x; - aHypotheticalBox.mRight += origin.x; - aHypotheticalBox.mTop += origin.y; - - // Move up the tree one level - parent = parent->GetParent(); - } while (parent && parent != stop); - } - + nsPoint cbOffset = aBlockFrame->GetOffsetTo(cbrs->frame); + aHypotheticalBox.mLeft += cbOffset.x; + aHypotheticalBox.mTop += cbOffset.y; + aHypotheticalBox.mRight += cbOffset.x; + // The specified offsets are relative to the absolute containing block's // padding edge or content edge, and our current values are relative to the // border edge, so translate. diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index 3d9e3535365..a353cc15728 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -972,8 +972,10 @@ public: /** * Find the closest view (on |this| or an ancestor). + * If aOffset is non-null, it will be set to the offset of |this| + * from the returned view. */ - nsIView* GetClosestView() const; + nsIView* GetClosestView(nsPoint* aOffset = nsnull) const; /** * Find the closest ancestor (excluding |this| !) that has a view @@ -981,6 +983,22 @@ public: nsIFrame* GetAncestorWithView() const; virtual nsIFrame* GetAncestorWithViewExternal() const; + /** + * Get the offset between the coordinate systems of |this| and aOther. + * Adding the return value to a point in the coordinate system of |this| + * will transform the point to the coordinate system of aOther. + * + * aOther must be non-null. + * + * This function is fastest when aOther is an ancestor of |this|. + * + * NOTE: this actually returns the offset from aOther to |this|, but + * that offset is added to transform _coordinates_ from |this| to + * aOther. + */ + nsPoint GetOffsetTo(const nsIFrame* aOther) const; + virtual nsPoint GetOffsetToExternal(const nsIFrame* aOther) const; + /** * Returns the offset from this frame to the closest geometric parent that * has a view. Also returns the containing view or null in case of error diff --git a/mozilla/layout/generic/nsSelection.cpp b/mozilla/layout/generic/nsSelection.cpp index 3aa80800d40..718776ff880 100644 --- a/mozilla/layout/generic/nsSelection.cpp +++ b/mozilla/layout/generic/nsSelection.cpp @@ -442,7 +442,6 @@ private: void SetDesiredX(nscoord aX); //set the mDesiredX nsresult GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent); - nsresult GetGlobalViewOffsetsFromFrame(nsPresContext *aPresContext, nsIFrame *aFrame, nscoord *offsetX, nscoord *offsetY); nsresult ConstrainFrameAndPointToAnchorSubtree(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint); PRUint32 GetBatching(){return mBatching;} @@ -1047,47 +1046,6 @@ nsSelection::GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent return NS_OK; } -nsresult -nsSelection::GetGlobalViewOffsetsFromFrame(nsPresContext *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; - - nsIFrame *frame = aFrame; - while (frame) - { - frame = frame->GetAncestorWithView(); - - if (frame) { - nsIView *view = frame->GetView(); - - if (view) - { - nsPoint pt = view->GetPosition(); - *offsetX += pt.x; - *offsetY += pt.y; - } - } - } - - return NS_OK; -} - nsresult nsSelection::ConstrainFrameAndPointToAnchorSubtree(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint) { @@ -1197,20 +1155,7 @@ nsSelection::ConstrainFrameAndPointToAnchorSubtree(nsPresContext *aPresContext, // 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; + aRetPoint = aPoint + aFrame->GetOffsetTo(*aRetFrame); return NS_OK; } @@ -2958,13 +2903,7 @@ nsSelection::CommonPageMove(PRBool aForward, if (caretView) { - while (caretView != scrolledView) - { - caretPos += caretView->GetPosition(); - caretView = caretView->GetParent(); - if (!caretView) //how did we miss the scrolled view. something is very wrong - return NS_ERROR_FAILURE; - } + caretPos += caretView->GetOffsetTo(scrolledView); } // get a content at desired location @@ -5223,16 +5162,10 @@ nsTypedSelection::GetViewAncestorOffset(nsIView *aView, nsIView *aAncestorView, if (!aView || !aXOffset || !aYOffset) return NS_ERROR_FAILURE; - *aXOffset = 0; - *aYOffset = 0; + nsPoint offset = aView->GetOffsetTo(aAncestorView); - for (nsIView* view = aView; view && view != aAncestorView; - view = view->GetParent()) - { - nsPoint pt = view->GetPosition(); - *aXOffset += pt.x; - *aYOffset += pt.y; - } + *aXOffset = offset.x; + *aYOffset = offset.y; return NS_OK; } @@ -6740,13 +6673,7 @@ nsTypedSelection::GetFrameToScrolledViewOffsets(nsIScrollableView *aScrollableVi // XXX Deal with the case where there is a scrolled element, e.g., a // DIV in the middle... - while (closestView && closestView != scrolledView) { - // Update the offset - offset += closestView->GetPosition(); - - // Get its parent view - closestView = closestView->GetParent(); - } + offset += closestView->GetOffsetTo(scrolledView); *aX = offset.x; *aY = offset.y; diff --git a/mozilla/layout/html/base/src/nsContainerFrame.cpp b/mozilla/layout/html/base/src/nsContainerFrame.cpp index 7551fb20bf2..866e37a3c36 100644 --- a/mozilla/layout/html/base/src/nsContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsContainerFrame.cpp @@ -433,17 +433,6 @@ nsContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) ///////////////////////////////////////////////////////////////////////////// // Helper member functions -static PRBool -TranslatePointTo(nsPoint& aPoint, nsIView* aChildView, nsIView* aParentView) -{ - do { - aPoint += aChildView->GetPosition(); - aChildView = aChildView->GetParent(); - } while (aChildView && (aChildView != aParentView)); - - return aChildView == aParentView; -} - /** * Position the view associated with |aKidFrame|, if there is one. A * container frame should call this method after positioning a frame, @@ -498,12 +487,7 @@ nsContainerFrame::PositionFrameView(nsPresContext* aPresContext, // We have the origin in the coordinate space of the containing view, // but we need it in the coordinate space of the parent view so do a // view translation -#ifdef DEBUG - PRBool ok = -#endif - TranslatePointTo(origin, containingView, parentView); - - NS_ASSERTION(ok, "translation failed"); + origin += containingView->GetOffsetTo(parentView); } } diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 6015ad76c6e..8f52648d6ea 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -1213,23 +1213,7 @@ ContentContainsPoint(nsPresContext *aPresContext, // that our point is in the same view space our content frame's // rects are in. - nsPoint point(*aPoint); - - if (frameView != aRelativeView) { - // Views are different, just assume frameView is an ancestor - // of aRelativeView and walk up the view hierarchy calculating what - // the actual point is, relative to frameView. - - while (aRelativeView && aRelativeView != frameView) { - point += aRelativeView->GetPosition(); - aRelativeView = aRelativeView->GetParent(); - } - - // At this point the point should be in the correct - // view coordinate space. If not, just bail! - - if (aRelativeView != frameView) return PR_FALSE; - } + 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. @@ -1242,10 +1226,7 @@ ContentContainsPoint(nsPresContext *aPresContext, frameRect.x = offsetPoint.x; frameRect.y = offsetPoint.y; - if (frameRect.x <= point.x && - frameRect.XMost() >= point.x && - frameRect.y <= point.y && - frameRect.YMost() >= point.y) { + if (frameRect.Contains(point)) { // point is within this frame's rect! return PR_TRUE; } @@ -1759,19 +1740,7 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, nsPoint dummyPoint; nsIView* eventView; GetOffsetFromView(aPresContext, dummyPoint, &eventView); - nsPoint pt = aEvent->point; - nsIView* view = eventView; - while (view && view != captureView) { - pt += view->GetPosition(); - view = view->GetParent(); - } - if (!view) { - // Hmm. Maybe captureView is a child of eventView? Recover by - // subtracting the global offset of eventView. - for (view = eventView; view; view = view->GetParent()) { - pt -= view->GetPosition(); - } - } + nsPoint pt = aEvent->point + eventView->GetOffsetTo(captureView); frameselection->StartAutoScrollTimer(aPresContext, captureView, pt, 30); } @@ -2298,6 +2267,35 @@ nsIFrame* nsIFrame::GetAncestorWithView() const return nsnull; } +// virtual +nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const +{ + return GetOffsetTo(aOther); +} + +nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const +{ + NS_PRECONDITION(aOther, + "Must have frame for destination coordinate system!"); + // Note that if we hit a view while walking up the frame tree we need to stop + // and switch to traversing the view tree so that we will deal with scroll + // views properly. + nsPoint offset(0, 0); + const nsIFrame* f; + for (f = this; !f->HasView() && f != aOther; f = f->GetParent()) { + offset += f->GetPosition(); + } + + if (f != aOther) { + // We found a view. Switch to the view tree + nsPoint toViewOffset(0, 0); + nsIView* otherView = aOther->GetClosestView(&toViewOffset); + offset += f->GetView()->GetOffsetTo(otherView) - toViewOffset; + } + + return offset; +} + // Returns the offset from this frame to the closest geometric parent that // has a view. Also returns the containing view or null in case of error NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPresContext* aPresContext, @@ -2369,6 +2367,7 @@ NS_IMETHODIMP nsFrame::GetOriginToViewOffset(nsPresContext* aPresContext, nsIView *tmpView = pview->GetParent(); if (tmpView && vVM != tmpView->GetViewManager()) { // Don't cross ViewManager boundaries! + // XXXbz why not? break; } pview = tmpView; @@ -4145,12 +4144,19 @@ nsFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct * return NS_OK; } -nsIView* nsIFrame::GetClosestView() const +nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const { - for (const nsIFrame *f = this; f; f = f->GetParent()) - if (f->HasView()) + nsPoint offset(0,0); + for (const nsIFrame *f = this; f; f = f->GetParent()) { + if (f->HasView()) { + if (aOffset) + *aOffset = offset; return f->GetView(); + } + offset += f->GetPosition(); + } + NS_NOTREACHED("No view on any parent? How did that happen?"); return nsnull; } diff --git a/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp b/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp index f64615eab01..e12df9ffb1a 100644 --- a/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp +++ b/mozilla/layout/html/base/src/nsGfxScrollFrame.cpp @@ -281,18 +281,13 @@ nsHTMLScrollFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX, PRInt32& aContentOffsetEnd, PRBool& aBeginFrameContent) { - nsPoint point(aPoint); //we need to translate the coordinates to the inner nsIView *view = GetClosestView(); if (!view) return NS_ERROR_FAILURE; - nsIView *innerView = GetClosestView(); - while (view != innerView && innerView) - { - point -= innerView->GetPosition(); - innerView = innerView->GetParent(); - } + nsIView *innerView = mInner.mScrollAreaBox->GetClosestView(); + nsPoint point = aPoint - innerView->GetOffsetTo(view); return mInner.mScrollAreaBox->GetContentAndOffsetsFromPoint(aCX, point, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent); } @@ -809,18 +804,13 @@ nsXULScrollFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX, PRInt32& aContentOffsetEnd, PRBool& aBeginFrameContent) { - nsPoint point(aPoint); //we need to translate the coordinates to the inner nsIView *view = GetClosestView(); if (!view) return NS_ERROR_FAILURE; - nsIView *innerView = GetClosestView(); - while (view != innerView && innerView) - { - point -= innerView->GetPosition(); - innerView = innerView->GetParent(); - } + nsIView *innerView = mInner.mScrollAreaBox->GetClosestView(); + nsPoint point = aPoint - innerView->GetOffsetTo(view); return mInner.mScrollAreaBox->GetContentAndOffsetsFromPoint(aCX, point, aNewContent, aContentOffset, aContentOffsetEnd, aBeginFrameContent); } diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp index 8614c17dee4..eb6aaf1662b 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp @@ -685,22 +685,6 @@ nsHTMLReflowState::CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWid margin.left + margin.right; } -static void -GetPlaceholderOffset(nsIFrame* aPlaceholderFrame, - nsIFrame* aBlockFrame, - nsPoint& aOffset) -{ - aOffset = aPlaceholderFrame->GetPosition(); - - // Convert the placeholder position to the coordinate space of the block - // frame that contains it - nsIFrame* parent = aPlaceholderFrame->GetParent(); - while (parent && (parent != aBlockFrame)) { - aOffset += parent->GetPosition(); - parent = parent->GetParent(); - } -} - static nsIFrame* FindImmediateChildOf(nsIFrame* aParent, nsIFrame* aDescendantFrame) { @@ -794,8 +778,7 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, // space of the block frame that contains it // XXXbz the placeholder is not fully reflown yet if our containing block is // relatively positioned... - nsPoint placeholderOffset; - GetPlaceholderOffset(aPlaceholderFrame, aBlockFrame, placeholderOffset); + nsPoint placeholderOffset = aPlaceholderFrame->GetOffsetTo(aBlockFrame); // First, determine the hypothetical box's mTop if (aBlockFrame) { @@ -895,32 +878,11 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, // The current coordinate space is that of the nearest block to the placeholder. // Convert to the coordinate space of the absolute containing block - nsIFrame* absoluteContainingBlock = cbrs->frame; - if (aBlockFrame != absoluteContainingBlock) { - nsIFrame* parent; - nsIFrame* stop; - if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { - // The absolute containing block is an inline frame... so it will be a - // descendant of aBlockFrame - parent = absoluteContainingBlock; - stop = aBlockFrame; - } else { - // aBlockFrame may be a descendant of absoluteContainingBlock - parent = aBlockFrame; - stop = absoluteContainingBlock; - } - do { - nsPoint origin = parent->GetPosition(); - - aHypotheticalBox.mLeft += origin.x; - aHypotheticalBox.mRight += origin.x; - aHypotheticalBox.mTop += origin.y; - - // Move up the tree one level - parent = parent->GetParent(); - } while (parent && parent != stop); - } - + nsPoint cbOffset = aBlockFrame->GetOffsetTo(cbrs->frame); + aHypotheticalBox.mLeft += cbOffset.x; + aHypotheticalBox.mTop += cbOffset.y; + aHypotheticalBox.mRight += cbOffset.x; + // The specified offsets are relative to the absolute containing block's // padding edge or content edge, and our current values are relative to the // border edge, so translate. diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.cpp b/mozilla/layout/html/forms/src/nsListControlFrame.cpp index c77030fe8ca..12b5ccc6914 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsListControlFrame.cpp @@ -505,12 +505,7 @@ void nsListControlFrame::PaintFocus(nsIRenderingContext& aRC, nsFramePaintLayer nsRect fRect = childframe->GetRect(); // get it into the coordinates of containerFrame - for (nsIFrame* ancestor = childframe->GetParent(); - ancestor && ancestor != containerFrame; - ancestor = ancestor->GetParent()) { - fRect += ancestor->GetPosition(); - } - + fRect.MoveBy(childframe->GetParent()->GetOffsetTo(containerFrame)); PRBool lastItemIsSelected = PR_FALSE; if (focusedIndex != kNothingSelected) { nsCOMPtr node; @@ -2242,21 +2237,6 @@ nsListControlFrame::GetProperty(nsIAtom* aName, nsAString& aValue) return NS_OK; } -//--------------------------------------------------------- -void -nsListControlFrame::GetViewOffset(nsIViewManager* aManager, nsIView* aView, - nsPoint& aPoint) -{ - aPoint.x = 0; - aPoint.y = 0; - - for (nsIView* parent = aView; - parent && parent->GetViewManager() == aManager; - parent = parent->GetParent()) { - aPoint += parent->GetPosition(); - } -} - //--------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::SyncViewWithFrame(nsPresContext* aPresContext) diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.h b/mozilla/layout/html/forms/src/nsListControlFrame.h index e9df1685456..f4b92f5fbe6 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.h +++ b/mozilla/layout/html/forms/src/nsListControlFrame.h @@ -237,7 +237,6 @@ protected: nsIContent* GetOptionContent(PRInt32 aIndex); PRBool IsContentSelected(nsIContent* aContent); PRBool IsContentSelectedByIndex(PRInt32 aIndex); - void GetViewOffset(nsIViewManager* aManager, nsIView* aView, nsPoint& aPoint); PRBool IsOptionElement(nsIContent* aContent); PRBool CheckIfAllFramesHere(); PRInt32 GetIndexFromContent(nsIContent *aContent); diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index 7ee55b16768..6a34d0b2d2f 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -1353,47 +1353,27 @@ GetRealFrame(nsIFrame* aFrame) /** * Utility method, called from MoveChildrenTo(), that recursively - * descends down the frame hierarchy looking for out-of-flow frames that + * descends down the frame hierarchy looking for floating frames that * need parent pointer adjustments to account for the containment block * changes that could occur as the result of the reparenting done in * MoveChildrenTo(). */ static void -AdjustOutOfFlowFrameParentPtrs(nsPresContext* aPresContext, - nsIFrame* aFrame, - nsFrameConstructorState* aState) +AdjustFloatParentPtrs(nsIFrame* aFrame, + nsFrameConstructorState& aState) { nsIFrame *outOfFlowFrame = GetRealFrame(aFrame); if (outOfFlowFrame && outOfFlowFrame != aFrame) { // Get the display data for the outOfFlowFrame so we can - // figure out if it is a float or absolutely positioned element. + // figure out if it is a float. - const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay(); - - // Update the parent pointer for outOfFlowFrame if it's - // containing block has changed as the result of reparenting, - // XXXbz Why is this needed? The reflow code can just be tweaked to do - // better coordinate system conversion, and then this case will work. - - if (NS_STYLE_POSITION_ABSOLUTE == display->mPosition) { - // XXX_kin: I think we'll need to add code here to handle the - // XXX_kin: reparenting that can happen in ConstructInline()? - // XXX_kin: - // XXX_kin: The case I'm thinking about here is when the inline being - // XXX_kin: constructed has a style="position: relative;" property - // XXX_kin: on it, and ConstructInline() moves/reparents all child block - // XXX_kin: frames and any inlines (including placeholders) that happen - // XXX_kin: to be between these blocks, under the new inline-block it created. - // XXX_kin: I think right now this case generates an assertion during - // XXX_kin: reflow, and as a result things fail to render since I believe - // XXX_kin: the placeholder is parented to the inline-block, and the - // XXX_kin: outOfFlowFrame is in the original inline frame's absolute list, - // XXX_kin: and is also parented to it. - } - else if (NS_STYLE_FLOAT_NONE != display->mFloats) { - nsIFrame *parent = aState->mFloatedItems.containingBlock; + if (outOfFlowFrame->GetStyleDisplay()->IsFloating()) { + // Update the parent pointer for outOfFlowFrame if it's + // containing block has changed as the result of reparenting, + + nsIFrame *parent = aState.mFloatedItems.containingBlock; outOfFlowFrame->SetParent(parent); if (outOfFlowFrame->GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) { @@ -1404,25 +1384,17 @@ AdjustOutOfFlowFrameParentPtrs(nsPresContext* aPresContext, } } - // XXX_kin: We'll need to remove the return below when we support - // XXX_kin: descending into out-of-flow frames. Here are some notes - // XXX_kin: from waterson: - // XXX_kin: - // XXX_kin: We'd want to continue to descend into placeholders - // XXX_kin: until we found an out-of-flow frame that established - // XXX_kin: a new containing block for absolutely positioned - // XXX_kin: elements. At that point, we could terminate the descent, - // XXX_kin: because any absolutely positioned frames below that frame - // XXX_kin: would be properly parented. - + // All out-of-flows are automatically float containing blocks, so we're + // done here return; } - // XXX_kin: Since we're only handling floats at the moment, - // XXX_kin: we don't need to cross block boundaries. - - if (IsBlockFrame(aPresContext, aFrame)) + // XXXbz we really want IsFloatContainingBlock() here! + if (IsBlockFrame(aState.mPresContext, aFrame)) { + // No need to recurse further; floats whose placeholders are + // inside a block already have the right parent. return; + } // Dive down into children to see if any of their // placeholders need adjusting. @@ -1431,14 +1403,9 @@ AdjustOutOfFlowFrameParentPtrs(nsPresContext* aPresContext, while (childFrame) { - // XXX_kin: Once we add support for adjusting absolutely positioned - // XXX_kin: frames, we will be crossing block boundaries, we/ll need - // XXX_kin: to update aState's containingBlock info to avoid incorrectly - // XXX_kin: reparenting floats, etc. - // XXX_kin: // XXX_kin: Do we need to prevent descent into anonymous content here? - AdjustOutOfFlowFrameParentPtrs(aPresContext, childFrame, aState); + AdjustFloatParentPtrs(childFrame, aState); childFrame = childFrame->GetNextSibling(); } } @@ -1467,11 +1434,11 @@ MoveChildrenTo(nsPresContext* aPresContext, aFrameList->SetParent(aNewParent); - // If aState is not null, the caller expects us to make adjustments - // so that placeholder out of flow frames point to the correct parent. - + // If aState is not null, the caller expects us to make adjustments so that + // floats whose placeholders are descendants of frames in aFrameList point + // to the correct parent. if (aState) - AdjustOutOfFlowFrameParentPtrs(aPresContext, aFrameList, aState); + AdjustFloatParentPtrs(aFrameList, *aState); #if 0 // XXX When this is used with {ib} frame hierarchies, it seems diff --git a/mozilla/layout/html/style/src/nsCSSRendering.cpp b/mozilla/layout/html/style/src/nsCSSRendering.cpp index a35f079235f..fb41bb45b50 100644 --- a/mozilla/layout/html/style/src/nsCSSRendering.cpp +++ b/mozilla/layout/html/style/src/nsCSSRendering.cpp @@ -3015,18 +3015,11 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext, ComputeBackgroundAnchorPoint(aColor, viewportArea, viewportArea, tileWidth, tileHeight, anchor); // Convert the anchor point to aForFrame's coordinate space - nsIView* view = aForFrame->GetView(); - if (!view) { - nsPoint offset; - aForFrame->GetOffsetFromView(aPresContext, offset, &view); - anchor -= offset; - } + nsPoint offset(0, 0); + nsIView* view = aForFrame->GetClosestView(&offset); + anchor -= offset; NS_ASSERTION(view, "expected a view"); - while (view && (view != viewportView)) { - anchor -= view->GetPosition(); - // Get the parent view until we reach the viewport view - view = view->GetParent(); - } + anchor -= view->GetOffsetTo(viewportView); } else { if (frameType == nsLayoutAtoms::canvasFrame) { // If the frame is the canvas, the image is placed relative to diff --git a/mozilla/view/public/nsIView.h b/mozilla/view/public/nsIView.h index 225d3394859..5ac610a2385 100644 --- a/mozilla/view/public/nsIView.h +++ b/mozilla/view/public/nsIView.h @@ -189,6 +189,21 @@ public: */ nsRect GetBounds() const { return mDimBounds; } + /** + * Get the offset between the coordinate systems of |this| and aOther. + * Adding the return value to a point in the coordinate system of |this| + * will transform the point to the coordinate system of aOther. + * + * If aOther is null, this will return the offset of |this| from the + * root of the viewmanager tree. + * + * This function is fastest when aOther is an ancestor of |this|. + * + * NOTE: this actually returns the offset from aOther to |this|, but + * that offset is added to transform _coordinates_ from |this| to aOther. + */ + nsPoint GetOffsetTo(const nsIView* aOther) const; + /** * Called to query the visibility state of a view. * @result current visibility state diff --git a/mozilla/view/src/nsView.cpp b/mozilla/view/src/nsView.cpp index 309e7bcca53..164ec4720b1 100644 --- a/mozilla/view/src/nsView.cpp +++ b/mozilla/view/src/nsView.cpp @@ -761,6 +761,27 @@ void nsIView::List(FILE* out, PRInt32 aIndent) const } #endif // DEBUG +nsPoint nsIView::GetOffsetTo(const nsIView* aOther) const +{ + nsPoint offset(0, 0); + const nsIView* v; + for (v = this; v != aOther && v; v = v->GetParent()) { + offset += v->GetPosition(); + } + + if (v != aOther) { + // Looks like aOther wasn't an ancestor of |this|. So now we have + // the root-VM-relative position of |this| in |offset|. Convert back + // to the coordinates of aOther + while (aOther) { + offset -= aOther->GetPosition(); + aOther = aOther->GetParent(); + } + } + + return offset; +} + nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) { nsPoint pt(0, 0);