Better computation of computed width and height and margins for block-level
elements git-svn-id: svn://10.0.0.236/trunk@17037 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -167,27 +167,21 @@ RootFrame::Reflow(nsIPresContext& aPresContext,
|
||||
// Reflow our one and only child frame
|
||||
if (nsnull != mFirstChild) {
|
||||
// Note: the root frame does not have border or padding...
|
||||
|
||||
// Compute the margins around the child frame
|
||||
nsMargin childMargin;
|
||||
nsHTMLReflowState::ComputeMarginFor(mFirstChild, &aReflowState, childMargin);
|
||||
|
||||
// Compute the child frame's available space
|
||||
nsSize kidMaxSize(aReflowState.maxSize.width - childMargin.left - childMargin.right,
|
||||
aReflowState.maxSize.height - childMargin.top - childMargin.bottom);
|
||||
nsHTMLReflowMetrics desiredSize(nsnull);
|
||||
// We must pass in that the available height is unconstrained, because
|
||||
// constrained is only for when we're paginated...
|
||||
nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState,
|
||||
nsSize(kidMaxSize.width, NS_UNCONSTRAINEDSIZE));
|
||||
nsSize(aReflowState.maxSize.width, NS_UNCONSTRAINEDSIZE));
|
||||
if (isChildInitialReflow) {
|
||||
kidReflowState.reason = eReflowReason_Initial;
|
||||
kidReflowState.reflowCommand = nsnull;
|
||||
}
|
||||
|
||||
// For a height that's 'auto', make the frame as big as the available space
|
||||
if (!kidReflowState.HaveFixedContentHeight()) {
|
||||
kidReflowState.computedHeight = kidMaxSize.height;
|
||||
// minus and top and bottom margins
|
||||
if (NS_AUTOHEIGHT == kidReflowState.computedHeight) {
|
||||
kidReflowState.computedHeight = aReflowState.maxSize.height -
|
||||
kidReflowState.computedTopMargin - kidReflowState.computedTopMargin;
|
||||
|
||||
// Computed height is for the content area so reduce it by the amount of
|
||||
// space taken up by border and padding
|
||||
@@ -201,7 +195,8 @@ RootFrame::Reflow(nsIPresContext& aPresContext,
|
||||
if (NS_OK == mFirstChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
|
||||
ReflowChild(mFirstChild, aPresContext, desiredSize, kidReflowState, aStatus);
|
||||
|
||||
nsRect rect(childMargin.left, childMargin.top, desiredSize.width, desiredSize.height);
|
||||
nsRect rect(kidReflowState.computedLeftMargin, kidReflowState.computedTopMargin,
|
||||
desiredSize.width, desiredSize.height);
|
||||
mFirstChild->SetRect(rect);
|
||||
|
||||
// XXX We should resolve the details of who/when DidReflow()
|
||||
|
||||
@@ -175,12 +175,15 @@ nsHTMLReflowState::InitConstraints(nsIPresContext& aPresContext)
|
||||
nsresult result = frame->GetStyleData(eStyleStruct_Position,
|
||||
(const nsStyleStruct*&)pos);
|
||||
|
||||
// Initialize the computed values to default values
|
||||
// XXX Use specified values as defaults
|
||||
computedWidth = 0;
|
||||
computedLeftMargin = computedRightMargin = 0;
|
||||
computedHeight = 0;
|
||||
computedTopMargin = computedBottomMargin = 0;
|
||||
// Compute margins from the specified margin style information
|
||||
nsMargin margin;
|
||||
ComputeMarginFor(frame, parentReflowState, margin);
|
||||
|
||||
// These become the default computed values, and may be adjusted below
|
||||
computedLeftMargin = margin.left;
|
||||
computedRightMargin = margin.right;
|
||||
computedTopMargin = margin.top;
|
||||
computedBottomMargin = margin.bottom;
|
||||
|
||||
mLineHeight = CalcLineHeight(aPresContext, frame);
|
||||
|
||||
@@ -200,89 +203,117 @@ nsHTMLReflowState::InitConstraints(nsIPresContext& aPresContext)
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for stylistic constraints on the width/height
|
||||
if (NS_OK == result) {
|
||||
nscoord containingBlockWidth, containingBlockHeight;
|
||||
nscoord width = -1, height = -1;
|
||||
PRIntn widthUnit = pos->mWidth.GetUnit();
|
||||
PRIntn heightUnit = pos->mHeight.GetUnit();
|
||||
// If this is the root frame then set the computed width and
|
||||
// height equal to the available space
|
||||
if (nsnull == parentReflowState) {
|
||||
computedWidth = maxSize.width;
|
||||
computedHeight = maxSize.height;
|
||||
|
||||
// When a percentage is specified we need to find the containing
|
||||
// block to use as the basis for the percentage computation.
|
||||
if ((eStyleUnit_Percent == widthUnit) ||
|
||||
(eStyleUnit_Percent == heightUnit)) {
|
||||
const nsHTMLReflowState* cbrs =
|
||||
GetContainingBlockReflowState(parentReflowState);
|
||||
} else {
|
||||
// Get the containing block reflow state, because we'll need its
|
||||
// computed width
|
||||
const nsHTMLReflowState* cbrs =
|
||||
GetContainingBlockReflowState(parentReflowState);
|
||||
NS_ASSERTION(nsnull != cbrs, "no containing block");
|
||||
|
||||
// If there is no containing block then pretend the width or
|
||||
// height units are auto.
|
||||
if (nsnull == cbrs) {
|
||||
if (eStyleUnit_Percent == widthUnit) {
|
||||
widthUnit = eStyleUnit_Auto;
|
||||
}
|
||||
if (eStyleUnit_Percent == heightUnit) {
|
||||
heightUnit = eStyleUnit_Auto;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (eStyleUnit_Percent == widthUnit) {
|
||||
containingBlockWidth = cbrs->computedWidth;
|
||||
}
|
||||
if (eStyleUnit_Percent == heightUnit) {
|
||||
if (NS_UNCONSTRAINEDSIZE == cbrs->maxSize.height) {
|
||||
// CSS2 spec, 10.5: if the height of the containing block
|
||||
// is not specified explicitly then the value is
|
||||
// interpreted like auto.
|
||||
heightUnit = eStyleUnit_Auto;
|
||||
}
|
||||
else {
|
||||
containingBlockHeight = cbrs->maxSize.height;
|
||||
}
|
||||
}
|
||||
// Get the containing block width and height. We'll need them when
|
||||
// calculating the computed width and height
|
||||
nscoord containingBlockWidth = cbrs->computedWidth;
|
||||
nscoord containingBlockHeight = cbrs->computedHeight;
|
||||
PRIntn widthUnit = pos->mWidth.GetUnit();
|
||||
PRIntn heightUnit = pos->mHeight.GetUnit();
|
||||
|
||||
// Check for a percentage based height
|
||||
if (eStyleUnit_Percent == heightUnit) {
|
||||
// If the height of the containing block depends on the content height,
|
||||
// the height is interpreted like 'auto'
|
||||
if (NS_AUTOHEIGHT == cbrs->computedHeight) {
|
||||
heightUnit = eStyleUnit_Auto;
|
||||
}
|
||||
}
|
||||
|
||||
switch (widthUnit) {
|
||||
case eStyleUnit_Coord:
|
||||
width = pos->mWidth.GetCoordValue();
|
||||
break;
|
||||
case eStyleUnit_Percent:
|
||||
width = nscoord(pos->mWidth.GetPercentValue() * containingBlockWidth);
|
||||
break;
|
||||
case eStyleUnit_Auto:
|
||||
{
|
||||
// XXX See section 10.3 of the css2 spec and then write this code!
|
||||
nsMargin margin;
|
||||
nsMargin borderPadding;
|
||||
ComputeMarginFor(frame, parentReflowState, margin);
|
||||
ComputeBorderPaddingFor(frame, parentReflowState, borderPadding);
|
||||
width = maxSize.width - margin.left - margin.right - borderPadding.left -
|
||||
borderPadding.right;
|
||||
break;
|
||||
// Compute border and padding
|
||||
nsMargin borderPadding;
|
||||
ComputeBorderPaddingFor(frame, parentReflowState, borderPadding);
|
||||
|
||||
// Get the spacing style information
|
||||
const nsStyleSpacing* spacing;
|
||||
frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing);
|
||||
|
||||
// Compute the content width
|
||||
PRBool isAutoLeftMargin = eStyleUnit_Auto == spacing->mMargin.GetLeftUnit();
|
||||
PRBool isAutoRightMargin = eStyleUnit_Auto == spacing->mMargin.GetRightUnit();
|
||||
|
||||
if (eStyleUnit_Auto == widthUnit) {
|
||||
// 'auto' values for left or right margins become 0
|
||||
if (isAutoLeftMargin) {
|
||||
computedLeftMargin = 0;
|
||||
}
|
||||
if (isAutoRightMargin) {
|
||||
computedRightMargin = 0;
|
||||
}
|
||||
|
||||
computedWidth = containingBlockWidth - computedLeftMargin -
|
||||
computedRightMargin - borderPadding.left - borderPadding.right;
|
||||
|
||||
} else {
|
||||
if (eStyleUnit_Coord == widthUnit) {
|
||||
computedWidth = pos->mWidth.GetCoordValue();
|
||||
} else if (eStyleUnit_Percent == widthUnit) {
|
||||
computedWidth = nscoord(pos->mWidth.GetPercentValue() * containingBlockWidth);
|
||||
} else {
|
||||
NS_ASSERTION(PR_FALSE, "unexpected width constraint");
|
||||
}
|
||||
|
||||
// Calculate the computed left and right margin
|
||||
nscoord extra = containingBlockWidth - computedWidth - borderPadding.left -
|
||||
borderPadding.right;
|
||||
|
||||
// See whether we're over constrained
|
||||
if (!isAutoLeftMargin && !isAutoRightMargin) {
|
||||
// Neither margin is 'auto' so we're over constrained. Use the
|
||||
// 'direction' property to tell which margin to ignore
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
||||
|
||||
if (NS_STYLE_DIRECTION_LTR == display->mDirection) {
|
||||
isAutoRightMargin = PR_TRUE;
|
||||
} else {
|
||||
isAutoLeftMargin = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAutoLeftMargin) {
|
||||
if (isAutoRightMargin) {
|
||||
// Both margins are 'auto' so their computed values are equal
|
||||
if (extra <= 0) {
|
||||
computedLeftMargin = computedRightMargin = 0;
|
||||
} else {
|
||||
computedLeftMargin = (extra + 1) / 2;
|
||||
computedRightMargin = extra - computedLeftMargin;
|
||||
}
|
||||
} else {
|
||||
computedLeftMargin = PR_MAX(0, extra - computedRightMargin);
|
||||
}
|
||||
|
||||
} else if (isAutoRightMargin) {
|
||||
computedRightMargin = PR_MAX(0, extra - computedLeftMargin);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the content height
|
||||
switch (heightUnit) {
|
||||
case eStyleUnit_Coord:
|
||||
height = pos->mHeight.GetCoordValue();
|
||||
computedHeight = pos->mHeight.GetCoordValue();
|
||||
break;
|
||||
case eStyleUnit_Percent:
|
||||
height = nscoord(pos->mHeight.GetPercentValue() * containingBlockHeight);
|
||||
computedHeight = nscoord(pos->mHeight.GetPercentValue() * containingBlockHeight);
|
||||
break;
|
||||
case eStyleUnit_Auto:
|
||||
// XXX See section 10.6 of the css2 spec and then write this code!
|
||||
computedHeight = NS_AUTOHEIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (width > 0) {
|
||||
computedWidth = width;
|
||||
}
|
||||
if (height > 0) {
|
||||
computedHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX this is probably a good place to calculate auto margins too
|
||||
// (section 10.3/10.6 of the spec)
|
||||
}
|
||||
|
||||
nscoord
|
||||
|
||||
@@ -167,27 +167,21 @@ RootFrame::Reflow(nsIPresContext& aPresContext,
|
||||
// Reflow our one and only child frame
|
||||
if (nsnull != mFirstChild) {
|
||||
// Note: the root frame does not have border or padding...
|
||||
|
||||
// Compute the margins around the child frame
|
||||
nsMargin childMargin;
|
||||
nsHTMLReflowState::ComputeMarginFor(mFirstChild, &aReflowState, childMargin);
|
||||
|
||||
// Compute the child frame's available space
|
||||
nsSize kidMaxSize(aReflowState.maxSize.width - childMargin.left - childMargin.right,
|
||||
aReflowState.maxSize.height - childMargin.top - childMargin.bottom);
|
||||
nsHTMLReflowMetrics desiredSize(nsnull);
|
||||
// We must pass in that the available height is unconstrained, because
|
||||
// constrained is only for when we're paginated...
|
||||
nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState,
|
||||
nsSize(kidMaxSize.width, NS_UNCONSTRAINEDSIZE));
|
||||
nsSize(aReflowState.maxSize.width, NS_UNCONSTRAINEDSIZE));
|
||||
if (isChildInitialReflow) {
|
||||
kidReflowState.reason = eReflowReason_Initial;
|
||||
kidReflowState.reflowCommand = nsnull;
|
||||
}
|
||||
|
||||
// For a height that's 'auto', make the frame as big as the available space
|
||||
if (!kidReflowState.HaveFixedContentHeight()) {
|
||||
kidReflowState.computedHeight = kidMaxSize.height;
|
||||
// minus and top and bottom margins
|
||||
if (NS_AUTOHEIGHT == kidReflowState.computedHeight) {
|
||||
kidReflowState.computedHeight = aReflowState.maxSize.height -
|
||||
kidReflowState.computedTopMargin - kidReflowState.computedTopMargin;
|
||||
|
||||
// Computed height is for the content area so reduce it by the amount of
|
||||
// space taken up by border and padding
|
||||
@@ -201,7 +195,8 @@ RootFrame::Reflow(nsIPresContext& aPresContext,
|
||||
if (NS_OK == mFirstChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
|
||||
ReflowChild(mFirstChild, aPresContext, desiredSize, kidReflowState, aStatus);
|
||||
|
||||
nsRect rect(childMargin.left, childMargin.top, desiredSize.width, desiredSize.height);
|
||||
nsRect rect(kidReflowState.computedLeftMargin, kidReflowState.computedTopMargin,
|
||||
desiredSize.width, desiredSize.height);
|
||||
mFirstChild->SetRect(rect);
|
||||
|
||||
// XXX We should resolve the details of who/when DidReflow()
|
||||
|
||||
@@ -306,13 +306,12 @@ struct nsHTMLReflowState : nsReflowState {
|
||||
nsIFrame* aFrame);
|
||||
|
||||
protected:
|
||||
// This method initializes the widthConstraint, heightConstraint and
|
||||
// minSize values appropriately. It also initializes the frameType
|
||||
// value as well. This method is automatically called by the various
|
||||
// constructors.
|
||||
// This method initializes various data members. It is automatically
|
||||
// called by the various constructors
|
||||
void Init(nsIPresContext& aPresContext) {
|
||||
mRunInFrame = nsnull;
|
||||
mCompactMarginWidth = 0;
|
||||
computedWidth = computedHeight = 0;
|
||||
DetermineFrameType(aPresContext);
|
||||
InitConstraints(aPresContext);
|
||||
}
|
||||
|
||||
@@ -533,6 +533,7 @@ NOFRAMES {
|
||||
}
|
||||
|
||||
:ROOT {
|
||||
display: block;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
|
||||
@@ -533,6 +533,7 @@ NOFRAMES {
|
||||
}
|
||||
|
||||
:ROOT {
|
||||
display: block;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user