Define new API's to compute margin/border/padding/border+padding and handle percentages correctly

git-svn-id: svn://10.0.0.236/trunk@15012 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kipp%netscape.com 1998-11-20 17:19:26 +00:00
parent 74b2e97658
commit 257cb2e34e
3 changed files with 312 additions and 12 deletions

View File

@ -25,15 +25,14 @@
#include "nsHTMLAtoms.h"
const nsHTMLReflowState*
nsHTMLReflowState::GetContainingBlockReflowState() const
nsHTMLReflowState::GetContainingBlockReflowState(const nsReflowState* aParentRS)
{
const nsReflowState* rs = parentReflowState;
while (nsnull != rs) {
if (nsnull != rs->frame) {
while (nsnull != aParentRS) {
if (nsnull != aParentRS->frame) {
const nsStyleDisplay* display;
nsresult rv;
rv = rs->frame->GetStyleData(eStyleStruct_Display,
(const nsStyleStruct*&) display);
rv = aParentRS->frame->GetStyleData(eStyleStruct_Display,
(const nsStyleStruct*&) display);
if (NS_SUCCEEDED(rv) && (nsnull != display)) {
switch (display->mDisplay) {
case NS_STYLE_DISPLAY_BLOCK:
@ -41,20 +40,28 @@ nsHTMLReflowState::GetContainingBlockReflowState() const
case NS_STYLE_DISPLAY_RUN_IN:
case NS_STYLE_DISPLAY_LIST_ITEM:
// XXX This cast is Not Good
return (const nsHTMLReflowState*)rs;
return (const nsHTMLReflowState*)aParentRS;
}
}
}
rs = rs->parentReflowState;
aParentRS = aParentRS->parentReflowState;
}
return nsnull;
}
const nsHTMLReflowState*
nsHTMLReflowState::GetPageBoxReflowState(const nsReflowState* aParentRS)
{
// XXX write me as soon as we can ask a frame if it's a page frame...
return nsnull;
}
nscoord
nsHTMLReflowState::GetContainingBlockContentWidth() const
{
nscoord width = 0;
const nsHTMLReflowState* rs = GetContainingBlockReflowState();
const nsHTMLReflowState* rs =
GetContainingBlockReflowState(parentReflowState);
if (nsnull != rs) {
if (rs->HaveFixedContentWidth()) {
width = rs->minWidth;
@ -71,7 +78,9 @@ nsHTMLReflowState::GetContainingBlockContentWidth() const
(const nsStyleStruct*&) spacing);
if (NS_SUCCEEDED(rv) && (nsnull != spacing)) {
nsMargin borderPadding;
spacing->CalcBorderPaddingFor(rs->frame, borderPadding);
rs->ComputeBorderPaddingFor(rs->frame,
(nsHTMLReflowState*) rs->parentReflowState,
borderPadding);
width -= borderPadding.left + borderPadding.right;
}
}
@ -301,6 +310,205 @@ nsHTMLReflowState::InitConstraints(nsIPresContext& aPresContext)
// (section 10.3/10.6 of the spec)
}
void
nsHTMLReflowState::ComputeHorizontalValue(const nsHTMLReflowState& aRS,
nsStyleUnit aUnit,
nsStyleCoord& aCoord,
nscoord& aResult)
{
aResult = 0;
if (eStyleUnit_Percent == aUnit) {
nscoord width = aRS.GetContainingBlockContentWidth();
float pct = aCoord.GetPercentValue();
aResult = NSToCoordFloor(width * pct);
}
}
void
nsHTMLReflowState::ComputeVerticalValue(const nsHTMLReflowState& aRS,
nsStyleUnit aUnit,
nsStyleCoord& aCoord,
nscoord& aResult)
{
aResult = 0;
if (eStyleUnit_Percent == aUnit) {
// XXX temporary!
nscoord width = aRS.GetContainingBlockContentWidth();
float pct = aCoord.GetPercentValue();
aResult = NSToCoordFloor(width * pct);
}
}
void
nsHTMLReflowState::ComputeMarginFor(nsIFrame* aFrame,
const nsReflowState* aParentRS,
nsMargin& aResult)
{
const nsStyleSpacing* spacing;
nsresult rv;
rv = aFrame->GetStyleData(eStyleStruct_Spacing,
(const nsStyleStruct*&) spacing);
if (NS_SUCCEEDED(rv) && (nsnull != spacing)) {
// If style style can provide us the margin directly, then use it.
if (!spacing->GetMargin(aResult) && (nsnull != aParentRS)) {
// We have to compute the value (because it's uncomputable by
// the style code).
const nsHTMLReflowState* rs = GetContainingBlockReflowState(aParentRS);
if (nsnull != rs) {
nsStyleCoord left, right;
ComputeHorizontalValue(*rs, spacing->mMargin.GetLeftUnit(),
spacing->mMargin.GetLeft(left), aResult.left);
ComputeHorizontalValue(*rs, spacing->mMargin.GetRightUnit(),
spacing->mMargin.GetRight(right),
aResult.right);
}
else {
aResult.left = 0;
aResult.right = 0;
}
const nsHTMLReflowState* rs2 = GetPageBoxReflowState(aParentRS);
nsStyleCoord top, bottom;
if (nsnull != rs2) {
// According to the CSS2 spec, margin percentages are
// calculated with respect to the *height* of the containing
// block when in a paginated context.
ComputeVerticalValue(*rs2, spacing->mMargin.GetTopUnit(),
spacing->mMargin.GetTop(top), aResult.top);
ComputeVerticalValue(*rs2, spacing->mMargin.GetBottomUnit(),
spacing->mMargin.GetBottom(bottom),
aResult.bottom);
}
else if (nsnull != rs) {
// According to the CSS2 spec, margin percentages are
// calculated with respect to the *width* of the containing
// block, even for margin-top and margin-bottom.
ComputeHorizontalValue(*rs, spacing->mMargin.GetTopUnit(),
spacing->mMargin.GetTop(top), aResult.top);
ComputeHorizontalValue(*rs, spacing->mMargin.GetBottomUnit(),
spacing->mMargin.GetBottom(bottom),
aResult.bottom);
}
else {
aResult.top = 0;
aResult.bottom = 0;
}
}
}
}
void
nsHTMLReflowState::ComputePaddingFor(nsIFrame* aFrame,
const nsReflowState* aParentRS,
nsMargin& aResult)
{
const nsStyleSpacing* spacing;
nsresult rv;
rv = aFrame->GetStyleData(eStyleStruct_Spacing,
(const nsStyleStruct*&) spacing);
if (NS_SUCCEEDED(rv) && (nsnull != spacing)) {
// If style can provide us the padding directly, then use it.
if (!spacing->GetPadding(aResult) && (nsnull != aParentRS)) {
// We have to compute the value (because it's uncomputable by
// the style code).
const nsHTMLReflowState* rs = GetContainingBlockReflowState(aParentRS);
if (nsnull != rs) {
nsStyleCoord left, right, top, bottom;
ComputeHorizontalValue(*rs, spacing->mPadding.GetLeftUnit(),
spacing->mPadding.GetLeft(left), aResult.left);
ComputeHorizontalValue(*rs, spacing->mPadding.GetRightUnit(),
spacing->mPadding.GetRight(right),
aResult.right);
// According to the CSS2 spec, padding percentages are
// calculated with respect to the *width* of the containing
// block, even for padding-top and padding-bottom.
ComputeHorizontalValue(*rs, spacing->mPadding.GetTopUnit(),
spacing->mPadding.GetTop(top), aResult.top);
ComputeHorizontalValue(*rs, spacing->mPadding.GetBottomUnit(),
spacing->mPadding.GetBottom(bottom),
aResult.bottom);
}
else {
aResult.SizeTo(0, 0, 0, 0);
}
}
}
else {
aResult.SizeTo(0, 0, 0, 0);
}
}
void
nsHTMLReflowState::ComputeBorderFor(nsIFrame* aFrame,
nsMargin& aResult)
{
const nsStyleSpacing* spacing;
nsresult rv;
rv = aFrame->GetStyleData(eStyleStruct_Spacing,
(const nsStyleStruct*&) spacing);
if (NS_SUCCEEDED(rv) && (nsnull != spacing)) {
// If style can provide us the border directly, then use it.
if (!spacing->GetBorder(aResult)) {
// CSS2 has no percentage borders
aResult.SizeTo(0, 0, 0, 0);
}
}
else {
aResult.SizeTo(0, 0, 0, 0);
}
}
void
nsHTMLReflowState::ComputeBorderPaddingFor(nsIFrame* aFrame,
const nsReflowState* aParentRS,
nsMargin& aResult)
{
const nsStyleSpacing* spacing;
nsresult rv;
rv = aFrame->GetStyleData(eStyleStruct_Spacing,
(const nsStyleStruct*&) spacing);
if (NS_SUCCEEDED(rv) && (nsnull != spacing)) {
nsMargin b, p;
// If style style can provide us the margin directly, then use it.
if (!spacing->GetBorder(b)) {
b.SizeTo(0, 0, 0, 0);
}
if (!spacing->GetPadding(p) && (nsnull != aParentRS)) {
// We have to compute the value (because it's uncomputable by
// the style code).
const nsHTMLReflowState* rs = GetContainingBlockReflowState(aParentRS);
if (nsnull != rs) {
nsStyleCoord left, right, top, bottom;
ComputeHorizontalValue(*rs, spacing->mPadding.GetLeftUnit(),
spacing->mPadding.GetLeft(left), p.left);
ComputeHorizontalValue(*rs, spacing->mPadding.GetRightUnit(),
spacing->mPadding.GetRight(right), p.right);
// According to the CSS2 spec, padding percentages are
// calculated with respect to the *width* of the containing
// block, even for padding-top and padding-bottom.
ComputeHorizontalValue(*rs, spacing->mPadding.GetTopUnit(),
spacing->mPadding.GetTop(top), p.top);
ComputeHorizontalValue(*rs, spacing->mPadding.GetBottomUnit(),
spacing->mPadding.GetBottom(bottom), p.bottom);
}
else {
p.SizeTo(0, 0, 0, 0);
}
}
aResult.top = b.top + p.top;
aResult.right = b.right + p.right;
aResult.bottom = b.bottom + p.bottom;
aResult.left = b.left + p.left;
}
else {
aResult.SizeTo(0, 0, 0, 0);
}
}
//----------------------------------------------------------------------
nsFrameReflowState::nsFrameReflowState(nsIPresContext& aPresContext,
@ -329,7 +537,9 @@ nsFrameReflowState::nsFrameReflowState(nsIPresContext& aPresContext,
(const nsStyleStruct*&) mStyleSpacing);
// Calculate our border and padding value
mStyleSpacing->CalcBorderPaddingFor(frame, mBorderPadding);
ComputeBorderPaddingFor(frame,
(nsHTMLReflowState*)parentReflowState,
mBorderPadding);
// Set mNoWrap flag
switch (mStyleText->mWhiteSpace) {
@ -359,3 +569,27 @@ nsFrameReflowState::nsFrameReflowState(nsIPresContext& aPresContext,
nsFrameReflowState::~nsFrameReflowState()
{
}
void
nsFrameReflowState::SetupChildReflowState(nsHTMLReflowState& aChildRS)
{
// Get reflow reason set correctly. It's possible that a child was
// created and then it was decided that it could not be reflowed
// (for example, a block frame that isn't at the start of a
// line). In this case the reason will be wrong so we need to check
// the frame state.
nsReflowReason reason = eReflowReason_Resize;
nsIFrame* frame = aChildRS.frame;
nsFrameState state;
frame->GetFrameState(state);
if (NS_FRAME_FIRST_REFLOW & state) {
reason = eReflowReason_Initial;
}
else if (mNextRCFrame == frame) {
reason = eReflowReason_Incremental;
// Make sure we only incrementally reflow once
mNextRCFrame = nsnull;/* XXX bad coupling */
}
aChildRS.reason = reason;
}

View File

@ -35,6 +35,8 @@ public:
const nsHTMLReflowMetrics& aMetrics);
~nsFrameReflowState();
void SetupChildReflowState(nsHTMLReflowState& aChildReflowState);
nsIPresContext& mPresContext;
nsIFrame* mNextRCFrame;

View File

@ -20,6 +20,7 @@
#include "nsIFrameReflow.h"
#include "nsStyleConsts.h"
#include "nsStyleCoord.h"
#include "nsRect.h"
class nsISpaceManager;
class nsBlockFrame;
@ -225,7 +226,62 @@ struct nsHTMLReflowState : nsReflowState {
nscoord GetContainingBlockContentWidth() const;
const nsHTMLReflowState* GetContainingBlockReflowState() const;
/**
* Get the containing block reflow state, starting from a frames
* <B>parent</B> reflow state (the parent reflow state may or may not end
* up being the containing block reflow state)
*/
static const nsHTMLReflowState*
GetContainingBlockReflowState(const nsReflowState* aParentRS);
/**
* Get the page box reflow state, starting from a frames
* <B>parent</B> reflow state (the parent reflow state may or may not end
* up being the containing block reflow state)
*/
static const nsHTMLReflowState*
GetPageBoxReflowState(const nsReflowState* aParentRS);
/**
* Compute the margin for <TT>aFrame</TT>. If a percentage needs to
* be computed it will be computed by finding the containing block,
* use GetContainingBlockReflowState. aParentReflowState is aFrame's
* parent's reflow state. The resulting computed margin is returned
* in aResult.
*/
static void ComputeMarginFor(nsIFrame* aFrame,
const nsReflowState* aParentReflowState,
nsMargin& aResult);
/**
* Compute the padding for <TT>aFrame</TT>. If a percentage needs to
* be computed it will be computed by finding the containing block,
* use GetContainingBlockReflowState. aParentReflowState is aFrame's
* parent's reflow state. The resulting computed padding is returned
* in aResult.
*/
static void ComputePaddingFor(nsIFrame* aFrame,
const nsReflowState* aParentReflowState,
nsMargin& aResult);
/**
* Compute the border for <TT>aFrame</TT>.The resulting computed
* padding is returned in aResult.
*/
static void ComputeBorderFor(nsIFrame* aFrame,
nsMargin& aResult);
/**
* Compute the border plus padding for <TT>aFrame</TT>. If a
* percentage needs to be computed it will be computed by finding
* the containing block, use GetContainingBlockReflowState.
* aParentReflowState is aFrame's
* parent's reflow state. The resulting computed border plus padding
* is returned in aResult.
*/
static void ComputeBorderPaddingFor(nsIFrame* aFrame,
const nsReflowState* aParentRS,
nsMargin& aResult);
protected:
// This method initializes the widthConstraint, heightConstraint and
@ -242,6 +298,14 @@ protected:
void DetermineFrameType(nsIPresContext& aPresContext);
void InitConstraints(nsIPresContext& aPresContext);
static void ComputeHorizontalValue(const nsHTMLReflowState& aReflowState,
nsStyleUnit aUnit, nsStyleCoord& aCoord,
nscoord& aResult);
static void ComputeVerticalValue(const nsHTMLReflowState& aReflowState,
nsStyleUnit aUnit, nsStyleCoord& aCoord,
nscoord& aResult);
};
//----------------------------------------------------------------------