Changed absolutely positioned elements to have the body as their

geometric parent
This commit is contained in:
troy 1998-06-26 18:49:30 +00:00
parent 427ffec39f
commit 09eaa8f230
7 changed files with 664 additions and 436 deletions

View File

@ -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);

View File

@ -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___ */

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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___ */