From 85ae51a4b3e9d2c57395d90f197e392312813822 Mon Sep 17 00:00:00 2001 From: troy Date: Fri, 26 Jun 1998 18:49:30 +0000 Subject: [PATCH] Changed absolutely positioned elements to have the body as their geometric parent git-svn-id: svn://10.0.0.236/trunk@4586 18797224-902f-48f8-a5cc-f745e15eee43 --- .../layout/html/base/src/nsAbsoluteFrame.cpp | 327 ++------- .../layout/html/base/src/nsAbsoluteFrame.h | 25 +- mozilla/layout/html/base/src/nsBodyFrame.cpp | 663 ++++++++++++++---- mozilla/layout/html/base/src/nsBodyFrame.h | 31 +- mozilla/layout/html/base/src/nsHTMLIIDs.cpp | 2 + mozilla/layout/html/base/src/nsHTMLIIDs.h | 1 + .../layout/html/base/src/nsIAbsoluteItems.h | 51 ++ 7 files changed, 664 insertions(+), 436 deletions(-) create mode 100644 mozilla/layout/html/base/src/nsIAbsoluteItems.h diff --git a/mozilla/layout/html/base/src/nsAbsoluteFrame.cpp b/mozilla/layout/html/base/src/nsAbsoluteFrame.cpp index aab1ba69d67..a397e22b0b3 100644 --- a/mozilla/layout/html/base/src/nsAbsoluteFrame.cpp +++ b/mozilla/layout/html/base/src/nsAbsoluteFrame.cpp @@ -16,20 +16,12 @@ * Reserved. */ #include "nsAbsoluteFrame.h" -#include "nsIContentDelegate.h" -#include "nsIPresContext.h" -#include "nsIPtr.h" -#include "nsIScrollableView.h" -#include "nsIStyleContext.h" -#include "nsIView.h" -#include "nsIViewManager.h" #include "nsBodyFrame.h" +#include "nsIAbsoluteItems.h" +#include "nsIContentDelegate.h" +#include "nsIStyleContext.h" #include "nsStyleConsts.h" -#include "nsViewsCID.h" - -static NS_DEFINE_IID(kIScrollableViewIID, NS_ISCROLLABLEVIEW_IID); - -NS_DEF_PTR(nsIStyleContext); +#include "nsHTMLIIDs.h" nsresult nsAbsoluteFrame::NewFrame(nsIFrame** aInstancePtrResult, @@ -49,7 +41,7 @@ nsAbsoluteFrame::NewFrame(nsIFrame** aInstancePtrResult, } nsAbsoluteFrame::nsAbsoluteFrame(nsIContent* aContent, nsIFrame* aParent) - : nsContainerFrame(aContent, aParent) + : nsFrame(aContent, aParent) { } @@ -57,198 +49,54 @@ nsAbsoluteFrame::~nsAbsoluteFrame() { } -NS_IMETHODIMP -nsAbsoluteFrame::IsSplittable(nsSplittableType& aIsSplittable) const +NS_METHOD nsAbsoluteFrame::Reflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState, + nsReflowStatus& aStatus) { - aIsSplittable = NS_FRAME_NOT_SPLITTABLE; - return NS_OK; -} + // Have we created the absolutely positioned item yet? + if (nsnull == mFrame) { + // If the content object is a container then wrap it in a body pseudo-frame + if (mContent->CanContainChildren()) { + nsBodyFrame::NewFrame(&mFrame, mContent, this); -nsIView* nsAbsoluteFrame::CreateView(nsIView* aContainingView, - const nsRect& aRect, - const nsStylePosition* aPosition, - const nsStyleDisplay* aDisplay) const -{ - nsIView* view; + // Use our style context for the pseudo-frame + mFrame->SetStyleContext(aPresContext, mStyleContext); - static NS_DEFINE_IID(kViewCID, NS_VIEW_CID); - static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); - - nsresult result = NSRepository::CreateInstance(kViewCID, - nsnull, - kIViewIID, - (void **)&view); - if (NS_OK == result) { - nsIViewManager* viewManager = aContainingView->GetViewManager(); - - // Initialize the view - NS_ASSERTION(nsnull != viewManager, "null view manager"); - - // See if the containing view is a scroll view - nsIScrollableView* scrollView = nsnull; - nsresult result; - nsViewClip clip = {0, 0, 0, 0}; - PRUint8 clipType = (aDisplay->mClipFlags & NS_STYLE_CLIP_TYPE_MASK); - nsViewClip* pClip = nsnull; - - // Is there a clip rect specified? - if (NS_STYLE_CLIP_RECT == clipType) { - if ((NS_STYLE_CLIP_LEFT_AUTO & aDisplay->mClipFlags) == 0) { - clip.mLeft = aDisplay->mClip.left; - } - if ((NS_STYLE_CLIP_RIGHT_AUTO & aDisplay->mClipFlags) == 0) { - clip.mRight = aDisplay->mClip.right; - } - if ((NS_STYLE_CLIP_TOP_AUTO & aDisplay->mClipFlags) == 0) { - clip.mTop = aDisplay->mClip.top; - } - if ((NS_STYLE_CLIP_BOTTOM_AUTO & aDisplay->mClipFlags) == 0) { - clip.mBottom = aDisplay->mClip.bottom; - } - pClip = &clip; - } - else if (NS_STYLE_CLIP_INHERIT == clipType) { - // XXX need to handle clip inherit (get from parent style context) - NS_NOTYETIMPLEMENTED("clip inherit"); - } - - PRInt32 zIndex = 0; - if (aPosition->mZIndex.GetUnit() == eStyleUnit_Integer) { - zIndex = aPosition->mZIndex.GetIntValue(); - } else if (aPosition->mZIndex.GetUnit() == eStyleUnit_Auto) { - zIndex = 0; - } else if (aPosition->mZIndex.GetUnit() == eStyleUnit_Inherit) { - // XXX need to handle z-index "inherit" - NS_NOTYETIMPLEMENTED("zIndex: inherit"); - } - - result = aContainingView->QueryInterface(kIScrollableViewIID, (void**)&scrollView); - if (NS_OK == result) { - nsIView* scrolledView = scrollView->GetScrolledView(); - - view->Init(viewManager, aRect, scrolledView, nsnull, nsnull, nsnull, - zIndex, pClip); - viewManager->InsertChild(scrolledView, view, 0); - NS_RELEASE(scrolledView); - NS_RELEASE(scrollView); } else { - view->Init(viewManager, aRect, aContainingView, nsnull, nsnull, nsnull, - zIndex, pClip); - viewManager->InsertChild(aContainingView, view, 0); - } + // Ask the content delegate to create the frame + nsIContentDelegate* delegate = mContent->GetDelegate(aPresContext); - NS_RELEASE(viewManager); + nsresult rv = delegate->CreateFrame(aPresContext, mContent, this, + mStyleContext, mFrame); + NS_RELEASE(delegate); + if (NS_OK != rv) { + return rv; + } + } + + // Get the containing block + nsIFrame* containingBlock = GetContainingBlock(); + NS_ASSERTION(nsnull != containingBlock, "no initial containing block"); + + // Query for its nsIAbsoluteItems interface + nsIAbsoluteItems* absoluteItemContainer; + containingBlock->QueryInterface(kIAbsoluteItemsIID, (void**)&absoluteItemContainer); + + // Notify it that there's a new absolutely positioned frame, passing it the + // anchor frame + NS_ASSERTION(nsnull != absoluteItemContainer, "no nsIAbsoluteItems support"); + absoluteItemContainer->AddAbsoluteItem(this); } - return view; -} - -// Returns the offset from this frame to aFrameTo -void nsAbsoluteFrame::GetOffsetFromFrame(nsIFrame* aFrameTo, nsPoint& aOffset) const -{ - nsIFrame* frame = (nsIFrame*)this; - - aOffset.MoveTo(0, 0); - do { - nsPoint origin; - - frame->GetOrigin(origin); - aOffset += origin; - frame->GetGeometricParent(frame); - } while ((nsnull != frame) && (frame != aFrameTo)); -} - -void nsAbsoluteFrame::ComputeViewBounds(nsIFrame* aContainingBlock, - const nsStylePosition* aPosition, - nsRect& aRect) const -{ - nsRect containingRect; - - // XXX We should be using the inner rect, and not just the bounding rect. - // Because of the way the frame sizing protocol works (it's top-down, and - // the size of a container is set after reflowing its children), get the - // rect from the containing block's view - nsIView* containingView; - aContainingBlock->GetView(containingView); - containingView->GetBounds(containingRect); - NS_RELEASE(containingView); - containingRect.x = containingRect.y = 0; - - // Compute the offset and size of the view based on the position properties - // and the inner rect of the containing block - const nsStylePosition* position = (const nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); - - // If either the left or top are 'auto' then get the offset of our frame from - // the containing block - nsPoint offset; // offset from containing block - if ((eStyleUnit_Auto == position->mLeftOffset.GetUnit()) || - (eStyleUnit_Auto == position->mTopOffset.GetUnit())) { - GetOffsetFromFrame(aContainingBlock, offset); - } - - // x-offset - if (eStyleUnit_Auto == position->mLeftOffset.GetUnit()) { - // Use the current x-offset of our frame translated into the coordinate space - // of the containing block - aRect.x = offset.x; - } else if (eStyleUnit_Coord == position->mLeftOffset.GetUnit()) { - aRect.x = position->mLeftOffset.GetCoordValue(); - } else { - NS_ASSERTION(eStyleUnit_Percent == position->mLeftOffset.GetUnit(), - "unexpected offset type"); - // Percentage values refer to the width of the containing block - aRect.x = containingRect.x + - (nscoord)((float)containingRect.width * - position->mLeftOffset.GetPercentValue()); - } - - // y-offset - if (eStyleUnit_Auto == position->mTopOffset.GetUnit()) { - // Use the current y-offset of our frame translated into the coordinate space - // of the containing block - aRect.y = offset.y; - } else if (eStyleUnit_Coord == position->mTopOffset.GetUnit()) { - aRect.y = position->mTopOffset.GetCoordValue(); - } else { - NS_ASSERTION(eStyleUnit_Percent == position->mTopOffset.GetUnit(), - "unexpected offset type"); - // Percentage values refer to the height of the containing block - aRect.y = containingRect.y + - (nscoord)((float)containingRect.height * - position->mTopOffset.GetPercentValue()); - } - - // width - if (eStyleUnit_Auto == position->mWidth.GetUnit()) { - // Use the right-edge of the containing block - aRect.width = containingRect.width - aRect.x; - } else if (eStyleUnit_Coord == position->mWidth.GetUnit()) { - aRect.width = position->mWidth.GetCoordValue(); - } else { - NS_ASSERTION(eStyleUnit_Percent == position->mWidth.GetUnit(), - "unexpected width type"); - aRect.width = (nscoord)((float)containingRect.width * - position->mWidth.GetPercentValue()); - } - - // height - if (eStyleUnit_Auto == position->mHeight.GetUnit()) { - // Allow it to be as high as it wants - aRect.height = NS_UNCONSTRAINEDSIZE; - } else if (eStyleUnit_Coord == position->mHeight.GetUnit()) { - aRect.height = position->mHeight.GetCoordValue(); - } else { - NS_ASSERTION(eStyleUnit_Percent == position->mHeight.GetUnit(), - "unexpected height type"); - aRect.height = (nscoord)((float)containingRect.height * - position->mHeight.GetPercentValue()); - } + // Return our desired size as (0, 0) + return nsFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); } nsIFrame* nsAbsoluteFrame::GetContainingBlock() const { // Look for a containing frame that is absolutely positioned. If we don't - // find one then use the initial containg block which is the root frame + // find one then use the initial containg block which is the BODY nsIFrame* lastFrame = (nsIFrame*)this; nsIFrame* result; @@ -269,91 +117,24 @@ nsIFrame* nsAbsoluteFrame::GetContainingBlock() const } if (nsnull == result) { - result = lastFrame; + // Walk back down the tree until we find a frame that supports nsIAnchoredItems + // XXX This is pretty yucky, but there isn't currently a better way to do + // this... + lastFrame->FirstChild(result); + + while (nsnull != result) { + nsIAbsoluteItems* interface; + if (NS_OK == result->QueryInterface(kIAbsoluteItemsIID, (void**)&interface)) { + break; + } + + result->FirstChild(result); + } } return result; } -NS_METHOD nsAbsoluteFrame::Reflow(nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - // Have we created the absolutely positioned item yet? - if (nsnull == mFirstChild) { - // If the content object is a container then wrap it in a body pseudo-frame - if (mContent->CanContainChildren()) { - nsBodyFrame::NewFrame(&mFirstChild, mContent, this); - - // Use our style context for the pseudo-frame - mFirstChild->SetStyleContext(aPresContext, mStyleContext); - - } else { - // Create the absolutely positioned item as a pseudo-frame child. We'll - // also create a view - nsIContentDelegate* delegate = mContent->GetDelegate(aPresContext); - - nsresult rv = delegate->CreateFrame(aPresContext, mContent, this, - mStyleContext, mFirstChild); - NS_RELEASE(delegate); - if (NS_OK != rv) { - return rv; - } - } - - // Get the containing block, and its associated view - nsIFrame* containingBlock = GetContainingBlock(); - - // Use the position properties to determine the offset and size - const nsStylePosition* position = (const nsStylePosition*)mStyleContext->GetStyleData(eStyleStruct_Position); - nsRect rect; - - ComputeViewBounds(containingBlock, position, rect); - - // Create a view for the frame - const nsStyleDisplay* display = (const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display); - nsIView* containingView; - containingBlock->GetView(containingView); - nsIView* view = CreateView(containingView, rect, position, display); - NS_RELEASE(containingView); - - mFirstChild->SetView(view); - NS_RELEASE(view); - - // Resize reflow the absolutely positioned element - nsSize availSize(rect.width, rect.height); - - if (NS_STYLE_OVERFLOW_VISIBLE == display->mOverflow) { - // Don't constrain the height since the container should be enlarged to - // contain overflowing frames - availSize.height = NS_UNCONSTRAINEDSIZE; - } - - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(mFirstChild, aReflowState, availSize, eReflowReason_Initial); - mFirstChild->WillReflow(*aPresContext); - mFirstChild->Reflow(aPresContext, desiredSize, reflowState, aStatus); - - // Figure out what size to actually use. If the position style is 'auto' or - // the container should be enlarged to contain overflowing frames then use - // the desired size - if ((eStyleUnit_Auto == position->mWidth.GetUnit()) || - ((desiredSize.width > availSize.width) && - (NS_STYLE_OVERFLOW_VISIBLE == display->mOverflow))) { - rect.width = desiredSize.width; - } - if (eStyleUnit_Auto == position->mHeight.GetUnit()) { - rect.height = desiredSize.height; - } - mFirstChild->SetRect(rect); - mFirstChild->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); - } - - // Return our desired size as (0, 0) - return nsFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); -} - NS_METHOD nsAbsoluteFrame::ListTag(FILE* out) const { fputs("*absolute", out); diff --git a/mozilla/layout/html/base/src/nsAbsoluteFrame.h b/mozilla/layout/html/base/src/nsAbsoluteFrame.h index 90df6631947..ce4eb5ba17b 100644 --- a/mozilla/layout/html/base/src/nsAbsoluteFrame.h +++ b/mozilla/layout/html/base/src/nsAbsoluteFrame.h @@ -18,23 +18,26 @@ #ifndef nsAbsoluteFrame_h___ #define nsAbsoluteFrame_h___ -#include "nsContainerFrame.h" -struct nsStylePosition; -struct nsStyleDisplay; +#include "nsFrame.h" // Implementation of a frame that's used as a placeholder for an absolutely // positioned frame -class nsAbsoluteFrame : public nsContainerFrame { +class nsAbsoluteFrame : public nsFrame { public: /** - * Create a new absolutely positioned frame + * Create a placeholder for an absolutely positioned frame. Also creates + * the absolutely positioned frame itself + * + * @see #GetAbsoluteFrame() */ static nsresult NewFrame(nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent); + // Returns the associated anchored item + nsIFrame* GetAbsoluteFrame() const {return mFrame;} + // nsIFrame overrides - NS_IMETHOD IsSplittable(nsSplittableType& aIsSplittable) const; NS_IMETHOD Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, @@ -42,21 +45,15 @@ public: NS_IMETHOD ListTag(FILE* out = stdout) const; protected: + nsIFrame* mFrame; // the absolutely positioned frame + // Constructor. Takes as arguments the content object, the index in parent, // and the Frame for the content parent nsAbsoluteFrame(nsIContent* aContent, nsIFrame* aParent); virtual ~nsAbsoluteFrame(); - nsIView* CreateView(nsIView* aContainingView, - const nsRect& aRect, - const nsStylePosition* aPosition, - const nsStyleDisplay* aDisplay) const; nsIFrame* GetContainingBlock() const; - void ComputeViewBounds(nsIFrame* aContainingBlock, - const nsStylePosition* aPosition, - nsRect& aRect) const; - void GetOffsetFromFrame(nsIFrame* aFrameTo, nsPoint& aOffset) const; }; #endif /* nsAbsoluteFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsBodyFrame.cpp b/mozilla/layout/html/base/src/nsBodyFrame.cpp index 8161464c03e..79ef0aa9b37 100644 --- a/mozilla/layout/html/base/src/nsBodyFrame.cpp +++ b/mozilla/layout/html/base/src/nsBodyFrame.cpp @@ -28,6 +28,9 @@ #include "nsIRunaround.h" #include "nsSpaceManager.h" #include "nsHTMLAtoms.h" +#include "nsIView.h" +#include "nsViewsCID.h" +#include "nsAbsoluteFrame.h" #include "nsHTMLIIDs.h" #include "nsCSSBlockFrame.h" @@ -60,6 +63,9 @@ nsBodyFrame::~nsBodyFrame() NS_RELEASE(mSpaceManager); } +///////////////////////////////////////////////////////////////////////////// +// nsIUnknown + nsresult nsBodyFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) { @@ -71,63 +77,15 @@ nsBodyFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) *aInstancePtr = (void*) ((nsIAnchoredItems*) this); return NS_OK; } + if (aIID.Equals(kIAbsoluteItemsIID)) { + *aInstancePtr = (void*) ((nsIAbsoluteItems*) this); + return NS_OK; + } return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); } -void nsBodyFrame::CreateColumnFrame(nsIPresContext* aPresContext) -{ - nsIStyleContext* styleContext = - aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo, this); - - // Do we have a prev-in-flow? - if (nsnull == mPrevInFlow) { - // No, create a column pseudo frame - NS_NewCSSBlockFrame(&mFirstChild, mContent, this); - mChildCount = 1; - mFirstChild->SetStyleContext(aPresContext,styleContext); - } else { - // Create a continuing column - nsBodyFrame* prevBody = (nsBodyFrame*)mPrevInFlow; - nsIFrame* prevColumn = prevBody->mFirstChild; - NS_ASSERTION(prevBody->ChildIsPseudoFrame(prevColumn), - "bad previous column"); - - prevColumn->CreateContinuingFrame(aPresContext, this, styleContext, - mFirstChild); - mChildCount = 1; - } - - NS_RELEASE(styleContext); -} - -nsSize nsBodyFrame::GetColumnAvailSpace(nsIPresContext* aPresContext, - const nsMargin& aBorderPadding, - const nsSize& aMaxSize) -{ - nsSize result(aMaxSize); - - // If we're not being used as a pseudo frame then make adjustments - // for border/padding and a vertical scrollbar - if (!mIsPseudoFrame) { - // If our width is constrained then subtract for the border/padding - if (aMaxSize.width != NS_UNCONSTRAINEDSIZE) { - result.width -= aBorderPadding.left + - aBorderPadding.right; - if (! aPresContext->IsPaginated()) { - nsIDeviceContext* dc = aPresContext->GetDeviceContext(); - result.width -= NS_TO_INT_ROUND(dc->GetScrollBarWidth()); - NS_RELEASE(dc); - } - } - // If our height is constrained then subtract for the border/padding - if (aMaxSize.height != NS_UNCONSTRAINEDSIZE) { - result.height -= aBorderPadding.top + - aBorderPadding.bottom; - } - } - - return result; -} +///////////////////////////////////////////////////////////////////////////// +// nsIFrame NS_METHOD nsBodyFrame::Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, @@ -249,6 +207,9 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext* aPresContext, mLastContentIsComplete = blockPseudoFrame->GetLastContentIsComplete(); #endif + // Reflow any absolutely positioned frames that need reflowing + ReflowAbsoluteItems(aPresContext, aReflowState); + // Return our desired size ComputeDesiredSize(desiredRect, aReflowState.maxSize, borderPadding, aDesiredSize); } @@ -269,6 +230,508 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext* aPresContext, return NS_OK; } +NS_METHOD nsBodyFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + NS_ASSERTION(mContent == aContainer, "bad content-appended target"); + + // Pass along the notification to our pseudo frame. It will generate a + // reflow command + return mFirstChild->ContentAppended(aShell, aPresContext, aContainer); +} + +NS_METHOD nsBodyFrame::ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ + NS_ASSERTION(mContent == aContainer, "bad content-inserted target"); + + // Pass along the notification to our pseudo frame that maps all the content + return mFirstChild->ContentInserted(aShell, aPresContext, aContainer, + aChild, aIndexInParent); +} + +NS_METHOD +nsBodyFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent, + nsIStyleContext* aStyleContext, + nsIFrame*& aContinuingFrame) +{ + nsBodyFrame* cf = new nsBodyFrame(mContent, aParent); + if (nsnull == cf) { + return NS_ERROR_OUT_OF_MEMORY; + } + PrepareContinuingFrame(aPresContext, aParent, aStyleContext, cf); + aContinuingFrame = cf; + return NS_OK; +} + +///////////////////////////////////////////////////////////////////////////// +// Helper functions + +void nsBodyFrame::CreateColumnFrame(nsIPresContext* aPresContext) +{ + nsIStyleContext* styleContext = + aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo, this); + + // Do we have a prev-in-flow? + if (nsnull == mPrevInFlow) { + // No, create a column pseudo frame + NS_NewCSSBlockFrame(&mFirstChild, mContent, this); + mChildCount = 1; + mFirstChild->SetStyleContext(aPresContext,styleContext); + } else { + // Create a continuing column + nsBodyFrame* prevBody = (nsBodyFrame*)mPrevInFlow; + nsIFrame* prevColumn = prevBody->mFirstChild; + NS_ASSERTION(prevBody->ChildIsPseudoFrame(prevColumn), + "bad previous column"); + + prevColumn->CreateContinuingFrame(aPresContext, this, styleContext, + mFirstChild); + mChildCount = 1; + } + + NS_RELEASE(styleContext); +} + +nsSize nsBodyFrame::GetColumnAvailSpace(nsIPresContext* aPresContext, + const nsMargin& aBorderPadding, + const nsSize& aMaxSize) +{ + nsSize result(aMaxSize); + + // If we're not being used as a pseudo frame then make adjustments + // for border/padding and a vertical scrollbar + if (!mIsPseudoFrame) { + // If our width is constrained then subtract for the border/padding + if (aMaxSize.width != NS_UNCONSTRAINEDSIZE) { + result.width -= aBorderPadding.left + + aBorderPadding.right; + if (! aPresContext->IsPaginated()) { + nsIDeviceContext* dc = aPresContext->GetDeviceContext(); + result.width -= NS_TO_INT_ROUND(dc->GetScrollBarWidth()); + NS_RELEASE(dc); + } + } + // If our height is constrained then subtract for the border/padding + if (aMaxSize.height != NS_UNCONSTRAINEDSIZE) { + result.height -= aBorderPadding.top + + aBorderPadding.bottom; + } + } + + return result; +} + +void +nsBodyFrame::ComputeDesiredSize(const nsRect& aDesiredRect, + const nsSize& aMaxSize, + const nsMargin& aBorderPadding, + nsReflowMetrics& aDesiredSize) +{ + // Note: Body used as a pseudo-frame shrink wraps + aDesiredSize.height = PR_MAX(aDesiredRect.YMost(), mSpaceManager->YMost()); + aDesiredSize.width = aDesiredRect.XMost(); + + // Take into account absolutely positioned elements when computing the + // desired size + for (PRInt32 i = 0; i < mAbsoluteItems.Count(); i++) { + // Get the anchor frame + nsAbsoluteFrame* anchorFrame = (nsAbsoluteFrame*)mAbsoluteItems[i]; + nsIFrame* absoluteFrame = anchorFrame->GetAbsoluteFrame(); + nsRect rect; + + absoluteFrame->GetRect(rect); + if (rect.XMost() > aDesiredSize.width) { + aDesiredSize.width = rect.XMost(); + } + if (rect.YMost() > aDesiredSize.height) { + aDesiredSize.height = rect.YMost(); + } + } + + if (!mIsPseudoFrame) { + // Make sure we're at least as wide as our available width + aDesiredSize.width = PR_MAX(aDesiredSize.width, aMaxSize.width); + aDesiredSize.height += aBorderPadding.top + + aBorderPadding.bottom; + } + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; +} + +// Add the frame to the end of the child list +void nsBodyFrame::AddFrame(nsIFrame* aFrame) +{ + nsIFrame* lastChild; + + LastChild(lastChild); + lastChild->SetNextSibling(aFrame); + aFrame->SetNextSibling(nsnull); + mChildCount++; +} + +///////////////////////////////////////////////////////////////////////////// +// nsIAnchoredItems + +void nsBodyFrame::AddAnchoredItem(nsIFrame* aAnchoredItem, + AnchoringPosition aPosition, + nsIFrame* aContainer) +{ + // Set the geometric parent and add the anchored frame to the child list + aAnchoredItem->SetGeometricParent(this); + AddFrame(aAnchoredItem); +} + +void nsBodyFrame::RemoveAnchoredItem(nsIFrame* aAnchoredItem) +{ + NS_PRECONDITION(IsChild(aAnchoredItem), "bad anchored item"); + NS_ASSERTION(aAnchoredItem != mFirstChild, "unexpected anchored item"); + // Remove the anchored item from the child list + // XXX Implement me + mChildCount--; +} + +///////////////////////////////////////////////////////////////////////////// +// nsIAbsoluteItems + +NS_METHOD nsBodyFrame::AddAbsoluteItem(nsAbsoluteFrame* aAnchorFrame) +{ + // Add the absolute anchor frame to our list of absolutely positioned + // items. + mAbsoluteItems.AppendElement(aAnchorFrame); + return NS_OK; +} + +NS_METHOD nsBodyFrame::RemoveAbsoluteItem(nsAbsoluteFrame* aAnchorFrame) +{ + NS_NOTYETIMPLEMENTED("removing an absolutely positioned frame"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +// Called at the end of the Reflow() member function so we can process +// any abolutely positioned items that need to be reflowed +void nsBodyFrame::ReflowAbsoluteItems(nsIPresContext* aPresContext, + const nsReflowState& aReflowState) +{ + for (PRInt32 i = 0; i < mAbsoluteItems.Count(); i++) { + // Get the anchor frame and its absolutely positioned frame + nsAbsoluteFrame* anchorFrame = (nsAbsoluteFrame*)mAbsoluteItems[i]; + nsIFrame* absoluteFrame = anchorFrame->GetAbsoluteFrame(); + PRBool placeFrame = PR_FALSE; + PRBool reflowFrame = PR_FALSE; + nsReflowReason reflowReason = eReflowReason_Resize; + + // Get its style information + const nsStyleDisplay* display; + const nsStylePosition* position; + + absoluteFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct*&)display); + absoluteFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)position); + + // See whether the frame is a newly added frame + nsIFrame* parent; + absoluteFrame->GetGeometricParent(parent); + if (parent != this) { + // The absolutely position item hasn't yet been added to our child list + absoluteFrame->SetGeometricParent(this); + + // Add the absolutely positioned frame to the end of the child list + AddFrame(absoluteFrame); + + // Make sure the frame has a view + nsIView* view; + absoluteFrame->GetView(view); + if (nsnull == view) { + view = CreateAbsoluteView(position, display); + absoluteFrame->SetView(view); + } + NS_RELEASE(view); + + // See whether this is the frame's initial reflow + nsFrameState frameState; + absoluteFrame->GetFrameState(frameState); + if (frameState & NS_FRAME_FIRST_REFLOW) { + reflowReason = eReflowReason_Initial; + } + + // We need to place and reflow the absolutely positioned frame + placeFrame = reflowFrame = PR_TRUE; + + } else { + // We need to place the frame if the left-offset or the top-offset are + // auto or a percentage + if ((eStyleUnit_Coord != position->mLeftOffset.GetUnit()) || + (eStyleUnit_Coord != position->mTopOffset.GetUnit())) { + placeFrame = PR_TRUE; + } + + // We need to reflow the frame if its width or its height is auto or + // a percentage + if ((eStyleUnit_Coord != position->mWidth.GetUnit()) || + (eStyleUnit_Coord != position->mHeight.GetUnit())) { + reflowFrame = PR_TRUE; + } + } + + if (placeFrame || reflowFrame) { + // Get the rect for the absolutely positioned element + nsRect rect; + ComputeAbsoluteFrameBounds(anchorFrame, aReflowState, position, rect); + + absoluteFrame->WillReflow(*aPresContext); + absoluteFrame->MoveTo(rect.x, rect.y); + + if (reflowFrame) { + // Resize reflow the absolutely positioned element + nsSize availSize(rect.width, rect.height); + + if (NS_STYLE_OVERFLOW_VISIBLE == display->mOverflow) { + // Don't constrain the height since the container should be enlarged + // to contain overflowing frames + availSize.height = NS_UNCONSTRAINEDSIZE; + } + + nsReflowMetrics desiredSize(nsnull); + nsReflowState reflowState(absoluteFrame, aReflowState, availSize, + reflowReason); + nsReflowStatus status; + absoluteFrame->Reflow(aPresContext, desiredSize, reflowState, status); + + // Figure out what size to actually use. If we let the child choose its + // size, then use what the child requested. Otherwise, use the value + // specified in the style information + if ((eStyleUnit_Auto == position->mWidth.GetUnit()) || + ((desiredSize.width > availSize.width) && + (NS_STYLE_OVERFLOW_VISIBLE == display->mOverflow))) { + rect.width = desiredSize.width; + } + if ((eStyleUnit_Auto == position->mHeight.GetUnit()) || + (NS_UNCONSTRAINEDSIZE == rect.height) || + ((desiredSize.height > rect.height) && + (NS_STYLE_OVERFLOW_VISIBLE == display->mOverflow))) { + rect.height = desiredSize.height; + } + absoluteFrame->SetRect(rect); + } + } + } +} + +nsIView* nsBodyFrame::CreateAbsoluteView(const nsStylePosition* aPosition, + const nsStyleDisplay* aDisplay) const +{ + nsIView* view; + + static NS_DEFINE_IID(kViewCID, NS_VIEW_CID); + static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + + // Create the view + nsresult result = NSRepository::CreateInstance(kViewCID, + nsnull, + kIViewIID, + (void **)&view); + if (NS_OK == result) { + // XXX Even though since we're absolutely positioned we should have a view, + // we might not... + nsIView* containingView; + GetView(containingView); + if (nsnull == containingView) { + nsPoint offset; + GetOffsetFromView(offset, containingView); + } + + // Initialize the view + nsIViewManager* viewManager = containingView->GetViewManager(); + NS_ASSERTION(nsnull != viewManager, "null view manager"); + + // Is there a clip rect specified? + nsViewClip clip = {0, 0, 0, 0}; + PRUint8 clipType = (aDisplay->mClipFlags & NS_STYLE_CLIP_TYPE_MASK); + nsViewClip* pClip = nsnull; + + if (NS_STYLE_CLIP_RECT == clipType) { + if ((NS_STYLE_CLIP_LEFT_AUTO & aDisplay->mClipFlags) == 0) { + clip.mLeft = aDisplay->mClip.left; + } + if ((NS_STYLE_CLIP_RIGHT_AUTO & aDisplay->mClipFlags) == 0) { + clip.mRight = aDisplay->mClip.right; + } + if ((NS_STYLE_CLIP_TOP_AUTO & aDisplay->mClipFlags) == 0) { + clip.mTop = aDisplay->mClip.top; + } + if ((NS_STYLE_CLIP_BOTTOM_AUTO & aDisplay->mClipFlags) == 0) { + clip.mBottom = aDisplay->mClip.bottom; + } + pClip = &clip; + } + else if (NS_STYLE_CLIP_INHERIT == clipType) { + // XXX need to handle clip inherit (get from parent style context) + NS_NOTYETIMPLEMENTED("clip inherit"); + } + + // Get the z-index to use + PRInt32 zIndex = 0; + if (aPosition->mZIndex.GetUnit() == eStyleUnit_Integer) { + zIndex = aPosition->mZIndex.GetIntValue(); + } else if (aPosition->mZIndex.GetUnit() == eStyleUnit_Auto) { + zIndex = 0; + } else if (aPosition->mZIndex.GetUnit() == eStyleUnit_Inherit) { + // XXX need to handle z-index "inherit" + NS_NOTYETIMPLEMENTED("zIndex: inherit"); + } + + // Initialize the view with a size of (0, 0). When we're done reflowing + // the frame the view will be sized and positioned + view->Init(viewManager, nsRect(0, 0, 0, 0), containingView, nsnull, + nsnull, nsnull, zIndex, pClip); + viewManager->InsertChild(containingView, view, 0); + NS_RELEASE(viewManager); + NS_RELEASE(containingView); + } + + return view; +} + +// Translate aPoint from aFrameFrom's coordinate space to our coordinate space +void nsBodyFrame::TranslatePoint(nsIFrame* aFrameFrom, nsPoint& aPoint) const +{ + nsIFrame* parent; + + aFrameFrom->GetGeometricParent(parent); + while ((nsnull != parent) && (parent != (nsIFrame*)this)) { + nsPoint origin; + + parent->GetOrigin(origin); + aPoint += origin; + parent->GetGeometricParent(parent); + } +} + +void nsBodyFrame::ComputeAbsoluteFrameBounds(nsIFrame* aAnchorFrame, + const nsReflowState& aReflowState, + const nsStylePosition* aPosition, + nsRect& aRect) const +{ + // Compute the offset and size of the view based on the position properties, + // and the inner rect of the containing block (which we get from the reflow + // state) + // + // If either the left or top are 'auto' then get the offset of the anchor + // frame from this frame + nsPoint offset; + if ((eStyleUnit_Auto == aPosition->mLeftOffset.GetUnit()) || + (eStyleUnit_Auto == aPosition->mTopOffset.GetUnit())) { + aAnchorFrame->GetOrigin(offset); + TranslatePoint(aAnchorFrame, offset); + } + + // left-offset + if (eStyleUnit_Auto == aPosition->mLeftOffset.GetUnit()) { + // Use the current x-offset of the anchor frame translated into our + // coordinate space + aRect.x = offset.x; + } else if (eStyleUnit_Coord == aPosition->mLeftOffset.GetUnit()) { + aRect.x = aPosition->mLeftOffset.GetCoordValue(); + } else { + NS_ASSERTION(eStyleUnit_Percent == aPosition->mLeftOffset.GetUnit(), + "unexpected offset type"); + // Percentage values refer to the width of the containing block. If the + // width is unconstrained then just use 0 + if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.width) { + aRect.x = 0; + } else { + aRect.x = (nscoord)((float)aReflowState.maxSize.width * + aPosition->mLeftOffset.GetPercentValue()); + } + } + + // top-offset + if (eStyleUnit_Auto == aPosition->mTopOffset.GetUnit()) { + // Use the current y-offset of the anchor frame translated into our + // coordinate space + aRect.y = offset.y; + } else if (eStyleUnit_Coord == aPosition->mTopOffset.GetUnit()) { + aRect.y = aPosition->mTopOffset.GetCoordValue(); + } else { + NS_ASSERTION(eStyleUnit_Percent == aPosition->mTopOffset.GetUnit(), + "unexpected offset type"); + // Percentage values refer to the height of the containing block. If the + // height is unconstrained then interpret it like 'auto' + if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.height) { + aRect.y = offset.y; + } else { + aRect.y = (nscoord)((float)aReflowState.maxSize.height * + aPosition->mTopOffset.GetPercentValue()); + } + } + + // XXX We aren't properly handling 'auto' width and height + // XXX The width/height represent the size of the content area only, and not + // the frame size... + + // width + if (eStyleUnit_Auto == aPosition->mWidth.GetUnit()) { + // Use the right-edge of the containing block + aRect.width = aReflowState.maxSize.width; + } else if (eStyleUnit_Coord == aPosition->mWidth.GetUnit()) { + aRect.width = aPosition->mWidth.GetCoordValue(); + } else { + NS_ASSERTION(eStyleUnit_Percent == aPosition->mWidth.GetUnit(), + "unexpected width type"); + // Percentage values refer to the width of the containing block + if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.width) { + aRect.width = NS_UNCONSTRAINEDSIZE; + } else { + aRect.width = (nscoord)((float)aReflowState.maxSize.width * + aPosition->mWidth.GetPercentValue()); + } + } + + // height + if (eStyleUnit_Auto == aPosition->mHeight.GetUnit()) { + // Allow it to be as high as it wants + aRect.height = NS_UNCONSTRAINEDSIZE; + } else if (eStyleUnit_Coord == aPosition->mHeight.GetUnit()) { + aRect.height = aPosition->mHeight.GetCoordValue(); + } else { + NS_ASSERTION(eStyleUnit_Percent == aPosition->mHeight.GetUnit(), + "unexpected height type"); + // Percentage values refer to the height of the containing block. If the + // height is unconstrained, then interpret it like 'auto' and make the + // height unconstrained + if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.height) { + aRect.height = NS_UNCONSTRAINEDSIZE; + } else { + aRect.height = (nscoord)((float)aReflowState.maxSize.height * + aPosition->mHeight.GetPercentValue()); + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// nsHTMLContainerFrame + +// XXX use same logic as block frame? +PRIntn nsBodyFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} + +///////////////////////////////////////////////////////////////////////////// +// Diagnostics + NS_METHOD nsBodyFrame::VerifyTree() const { #ifdef NS_DEBUG @@ -312,95 +775,3 @@ NS_METHOD nsBodyFrame::VerifyTree() const return NS_OK; } -void -nsBodyFrame::ComputeDesiredSize(const nsRect& aDesiredRect, - const nsSize& aMaxSize, - const nsMargin& aBorderPadding, - nsReflowMetrics& aDesiredSize) -{ - // Note: Body used as a pseudo-frame shrink wraps - aDesiredSize.height = PR_MAX(aDesiredRect.YMost(), mSpaceManager->YMost()); - aDesiredSize.width = aDesiredRect.XMost(); - if (!mIsPseudoFrame) { - aDesiredSize.width = PR_MAX(aDesiredSize.width, aMaxSize.width); - aDesiredSize.height += aBorderPadding.top + - aBorderPadding.bottom; - } - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; -} - -NS_METHOD nsBodyFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - NS_ASSERTION(mContent == aContainer, "bad content-appended target"); - - // Pass along the notification to our pseudo frame. It will generate a - // reflow command - return mFirstChild->ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD nsBodyFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - NS_ASSERTION(mContent == aContainer, "bad content-inserted target"); - - // Pass along the notification to our pseudo frame that maps all the content - return mFirstChild->ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -void nsBodyFrame::AddAnchoredItem(nsIFrame* aAnchoredItem, - AnchoringPosition aPosition, - nsIFrame* aContainer) -{ - aAnchoredItem->SetGeometricParent(this); - // Add the item to the end of the child list - nsIFrame* lastChild; - - LastChild(lastChild); - lastChild->SetNextSibling(aAnchoredItem); - aAnchoredItem->SetNextSibling(nsnull); - mChildCount++; -} - -void nsBodyFrame::RemoveAnchoredItem(nsIFrame* aAnchoredItem) -{ - NS_PRECONDITION(IsChild(aAnchoredItem), "bad anchored item"); - NS_ASSERTION(aAnchoredItem != mFirstChild, "unexpected anchored item"); - // Remove the anchored item from the child list - // XXX Implement me - mChildCount--; -} - -NS_METHOD -nsBodyFrame::CreateContinuingFrame(nsIPresContext* aPresContext, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBodyFrame* cf = new nsBodyFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aPresContext, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -// XXX use same logic as block frame? -PRIntn nsBodyFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/html/base/src/nsBodyFrame.h b/mozilla/layout/html/base/src/nsBodyFrame.h index c9180ac5ed3..edc0afbb5b8 100644 --- a/mozilla/layout/html/base/src/nsBodyFrame.h +++ b/mozilla/layout/html/base/src/nsBodyFrame.h @@ -20,11 +20,17 @@ #include "nsHTMLContainerFrame.h" #include "nsIAnchoredItems.h" +#include "nsIAbsoluteItems.h" +#include "nsVoidArray.h" -struct nsBodyReflowState; class nsSpaceManager; -class nsBodyFrame : public nsHTMLContainerFrame, public nsIAnchoredItems { +struct nsStyleDisplay; +struct nsStylePosition; + +class nsBodyFrame : public nsHTMLContainerFrame, + public nsIAnchoredItems, + public nsIAbsoluteItems { public: static nsresult NewFrame(nsIFrame** aInstancePtrResult, nsIContent* aContent, @@ -56,9 +62,12 @@ public: virtual void AddAnchoredItem(nsIFrame* aAnchoredItem, AnchoringPosition aPosition, nsIFrame* aContainer); - virtual void RemoveAnchoredItem(nsIFrame* aAnchoredItem); + // nsIAbsoluteItems + NS_IMETHOD AddAbsoluteItem(nsAbsoluteFrame* aAnchorFrame); + NS_IMETHOD RemoveAbsoluteItem(nsAbsoluteFrame* aAnchorFrame); + NS_IMETHOD VerifyTree() const; protected: @@ -75,8 +84,24 @@ protected: virtual PRIntn GetSkipSides() const; + void ReflowAbsoluteItems(nsIPresContext* aPresContext, + const nsReflowState& aReflowState); + + nsIView* CreateAbsoluteView(const nsStylePosition* aPosition, + const nsStyleDisplay* aDisplay) const; + + void TranslatePoint(nsIFrame* aFrameFrom, nsPoint& aPoint) const; + + void ComputeAbsoluteFrameBounds(nsIFrame* aAnchorFrame, + const nsReflowState& aState, + const nsStylePosition* aPosition, + nsRect& aRect) const; + + void AddFrame(nsIFrame* aFrame); + private: nsSpaceManager* mSpaceManager; + nsVoidArray mAbsoluteItems; void CreateColumnFrame(nsIPresContext* aPresContext); nsSize GetColumnAvailSpace(nsIPresContext* aPresContext, diff --git a/mozilla/layout/html/base/src/nsHTMLIIDs.cpp b/mozilla/layout/html/base/src/nsHTMLIIDs.cpp index 27d79849233..050b18aa6a2 100644 --- a/mozilla/layout/html/base/src/nsHTMLIIDs.cpp +++ b/mozilla/layout/html/base/src/nsHTMLIIDs.cpp @@ -17,12 +17,14 @@ */ #include "nsHTMLIIDs.h" #include "nsIHTMLContent.h" +#include "nsIAbsoluteItems.h" #include "nsIAnchoredItems.h" #include "nsIFloaterContainer.h" #include "nsIRunaround.h" #include "nsIInlineReflow.h" #include "nsCSSBlockFrame.h" +const nsIID kIAbsoluteItemsIID = NS_IABSOLUTE_ITEMS_IID; const nsIID kIAnchoredItemsIID = NS_IANCHORED_ITEMS_IID; const nsIID kIFloaterContainerIID = NS_IFLOATER_CONTAINER_IID; const nsIID kIHTMLContentIID = NS_IHTMLCONTENT_IID; diff --git a/mozilla/layout/html/base/src/nsHTMLIIDs.h b/mozilla/layout/html/base/src/nsHTMLIIDs.h index d59972e1a07..7fcac1261d4 100644 --- a/mozilla/layout/html/base/src/nsHTMLIIDs.h +++ b/mozilla/layout/html/base/src/nsHTMLIIDs.h @@ -22,6 +22,7 @@ extern const nsIID kBlockFrameCID; // XXX temporary +extern const nsIID kIAbsoluteItemsIID; extern const nsIID kIAnchoredItemsIID; extern const nsIID kIFloaterContainerIID; extern const nsIID kIHTMLContentIID; diff --git a/mozilla/layout/html/base/src/nsIAbsoluteItems.h b/mozilla/layout/html/base/src/nsIAbsoluteItems.h new file mode 100644 index 00000000000..7db30558e4d --- /dev/null +++ b/mozilla/layout/html/base/src/nsIAbsoluteItems.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#ifndef nsIAbsoluteItems_h___ +#define nsIAbsoluteItems_h___ + +class nsAbsoluteFrame; + +// IID for the nsIAbsoluteItems interface {28E68A10-0BD4-11d2-85DD-00A02468FAB6} +#define NS_IABSOLUTE_ITEMS_IID \ +{ 0x28e68a10, 0xbd4, 0x11d2, \ + {0x85, 0xdd, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} + +/** + * An interface for managing absolutely positioned items. Note that this interface + * is not an nsISupports interface, and therefore you cannot QueryInterface() back + */ +class nsIAbsoluteItems +{ +public: + /** + * Request to add an absolutely positioned item. The anchor for the + * absolutely positioned item is passed as an argument + * + * @see nsAbsoluteFrame::GetAbsoluteFrame() + */ + NS_IMETHOD AddAbsoluteItem(nsAbsoluteFrame* aAnchorFrame) = 0; + + /** + * Called to remove an absolutely positioned item, most likely because the + * associated piece of content has been removed. + **/ + NS_IMETHOD RemoveAbsoluteItem(nsAbsoluteFrame* aAnchorFrame) = 0; +}; + +#endif /* nsIAbsoluteItems_h___ */