Bug 851379 part 2: Make ComputeMargin, ComputePadding, and InitOffsets take a horizontal *and* vertical percent basis, so that we can resolve vertical margins and padding against containing block *height* in flex items. r=mats

This commit is contained in:
Daniel Holbert 2013-04-11 07:51:52 -07:00
parent cee9a2f474
commit a0d53d01a9
2 changed files with 84 additions and 34 deletions

View File

@ -1839,8 +1839,17 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
// If this is the root frame, then set the computed width and
// height equal to the available space
if (nullptr == parentReflowState) {
MOZ_ASSERT(!frame->IsFlexItem(),
"the root frame can't be a flex item, since being a flex item "
"requires that you have a parent");
// Note that we pass the containing block width as the percent basis for
// both horizontal *and* vertical margins & padding, in our InitOffsets
// call here. This is correct per CSS 2.1; it'd be incorrect for e.g. flex
// items and grid items, but the root frame can't be either of those.
// XXXldb This doesn't mean what it used to!
InitOffsets(aContainingBlockWidth, aFrameType, aBorder, aPadding);
InitOffsets(aContainingBlockWidth,
aContainingBlockWidth,
aFrameType, aBorder, aPadding);
// Override mComputedMargin since reflow roots start from the
// frame's boundary, which is inside the margin.
mComputedMargin.SizeTo(0, 0, 0, 0);
@ -1887,7 +1896,20 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
}
}
InitOffsets(aContainingBlockWidth, aFrameType, aBorder, aPadding);
// Flex containers resolve percentage margin & padding against the flex
// container's height (which is the containing block height).
// For everything else: the CSS21 spec requires that margin and padding
// percentage values are calculated with respect to the *width* of the
// containing block, even for margin & padding in the vertical axis.
// XXX Might need to also pass the CB height (not width) for page boxes,
// too, if we implement them.
nscoord verticalPercentBasis = aContainingBlockWidth;
if (frame->IsFlexItem()) {
verticalPercentBasis =
aContainingBlockHeight == NS_AUTOHEIGHT ? 0 : aContainingBlockHeight;
}
InitOffsets(aContainingBlockWidth, verticalPercentBasis,
aFrameType, aBorder, aPadding);
const nsStyleCoord &height = mStylePosition->mHeight;
nsStyleUnit heightUnit = height.GetUnit();
@ -2110,12 +2132,14 @@ UpdateProp(FrameProperties& aProps,
}
void
nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth,
nsCSSOffsetState::InitOffsets(nscoord aHorizontalPercentBasis,
nscoord aVerticalPercentBasis,
nsIAtom* aFrameType,
const nsMargin *aBorder,
const nsMargin *aPadding)
{
DISPLAY_INIT_OFFSETS(frame, this, aContainingBlockWidth, aBorder, aPadding);
// XXXdholbert This macro probably needs to take aVerticalPercentBasis too
DISPLAY_INIT_OFFSETS(frame, this, aHorizontalPercentBasis, aBorder, aPadding);
// Since we are in reflow, we don't need to store these properties anymore
// unless they are dependent on width, in which case we store the new value.
@ -2127,7 +2151,8 @@ nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth,
// become the default computed values, and may be adjusted below
// XXX fix to provide 0,0 for the top&bottom margins for
// inline-non-replaced elements
bool needMarginProp = ComputeMargin(aContainingBlockWidth);
bool needMarginProp = ComputeMargin(aHorizontalPercentBasis,
aVerticalPercentBasis);
// XXX We need to include 'auto' horizontal margins in this too!
// ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
// to use it even when the margins are all zero (since sometimes
@ -2159,7 +2184,8 @@ nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth,
needPaddingProp = frame->StylePadding()->IsWidthDependent();
}
else {
needPaddingProp = ComputePadding(aContainingBlockWidth, aFrameType);
needPaddingProp = ComputePadding(aHorizontalPercentBasis,
aVerticalPercentBasis, aFrameType);
}
if (isThemed) {
@ -2419,7 +2445,8 @@ nsHTMLReflowState::CalcLineHeight(nsStyleContext* aStyleContext,
}
bool
nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth)
nsCSSOffsetState::ComputeMargin(nscoord aHorizontalPercentBasis,
nscoord aVerticalPercentBasis)
{
// SVG text frames have no margin.
if (frame->IsSVGText()) {
@ -2428,25 +2455,21 @@ nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth)
// If style style can provide us the margin directly, then use it.
const nsStyleMargin *styleMargin = frame->StyleMargin();
bool isWidthDependent = !styleMargin->GetMargin(mComputedMargin);
if (isWidthDependent) {
bool isCBDependent = !styleMargin->GetMargin(mComputedMargin);
if (isCBDependent) {
// We have to compute the value
mComputedMargin.left = nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aHorizontalPercentBasis,
styleMargin->mMargin.GetLeft());
mComputedMargin.right = nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aHorizontalPercentBasis,
styleMargin->mMargin.GetRight());
// 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.
// XXX This isn't true for page boxes, if we implement them.
mComputedMargin.top = nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aVerticalPercentBasis,
styleMargin->mMargin.GetTop());
mComputedMargin.bottom = nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aVerticalPercentBasis,
styleMargin->mMargin.GetBottom());
}
@ -2461,15 +2484,17 @@ nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth)
}
}
return isWidthDependent;
return isCBDependent;
}
bool
nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth, nsIAtom* aFrameType)
nsCSSOffsetState::ComputePadding(nscoord aHorizontalPercentBasis,
nscoord aVerticalPercentBasis,
nsIAtom* aFrameType)
{
// If style can provide us the padding directly, then use it.
const nsStylePadding *stylePadding = frame->StylePadding();
bool isWidthDependent = !stylePadding->GetPadding(mComputedPadding);
bool isCBDependent = !stylePadding->GetPadding(mComputedPadding);
// a table row/col group, row/col doesn't have padding
// XXXldb Neither do border-collapse tables.
if (nsGkAtoms::tableRowGroupFrame == aFrameType ||
@ -2478,26 +2503,24 @@ nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth, nsIAtom* aFrameT
nsGkAtoms::tableColFrame == aFrameType) {
mComputedPadding.SizeTo(0,0,0,0);
}
else if (isWidthDependent) {
else if (isCBDependent) {
// We have to compute the value
// clamp negative calc() results to 0
mComputedPadding.left = std::max(0, nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aHorizontalPercentBasis,
stylePadding->mPadding.GetLeft()));
mComputedPadding.right = std::max(0, nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aHorizontalPercentBasis,
stylePadding->mPadding.GetRight()));
// According to the CSS2 spec, percentages are calculated with respect to
// containing block width for padding-top and padding-bottom
mComputedPadding.top = std::max(0, nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aVerticalPercentBasis,
stylePadding->mPadding.GetTop()));
mComputedPadding.bottom = std::max(0, nsLayoutUtils::
ComputeCBDependentValue(aContainingBlockWidth,
ComputeCBDependentValue(aVerticalPercentBasis,
stylePadding->mPadding.GetBottom()));
}
return isWidthDependent;
return isCBDependent;
}
void

View File

@ -12,6 +12,7 @@
#include "nsStyleCoord.h"
#include "nsStyleStructInlines.h"
#include "nsIFrame.h"
#include "mozilla/Assertions.h"
#include <algorithm>
class nsPresContext;
@ -144,12 +145,19 @@ public:
{
}
// NOTE: If we ever want to use nsCSSOffsetState for a flex item or a grid
// item, we need to make it take the containing-block height as well as the
// width, since flex items and grid items resolve vertical percent margins
// and padding against the containing-block height, rather than its width.
nsCSSOffsetState(nsIFrame *aFrame, nsRenderingContext *aRenderingContext,
nscoord aContainingBlockWidth)
: frame(aFrame)
, rendContext(aRenderingContext)
{
InitOffsets(aContainingBlockWidth, frame->GetType());
MOZ_ASSERT(!aFrame->IsFlexItem(),
"We're about to resolve vertical percent margin & padding "
"values against CB width, which is incorrect for flex items");
InitOffsets(aContainingBlockWidth, aContainingBlockWidth, frame->GetType());
}
#ifdef DEBUG
@ -169,20 +177,39 @@ private:
/**
* Computes margin values from the specified margin style information, and
* fills in the mComputedMargin member.
* @return true if the margin is dependent on the containing block width
*
* @param aHorizontalPercentBasis
* Length to use for resolving percentage margin values in the horizontal
* axis. Usually the containing block width.
* @param aVerticalPercentBasis
* Length to use for resolving percentage margin values in the vertical
* axis. Usually the containing block width, per CSS21 sec 8.3, but may
* be the containing block *height*, e.g. in CSS3 Flexbox and Grid.
* @return true if the margin is dependent on the containing block size.
*/
bool ComputeMargin(nscoord aContainingBlockWidth);
bool ComputeMargin(nscoord aHorizontalPercentBasis,
nscoord aVerticalPercentBasis);
/**
* Computes padding values from the specified padding style information, and
* fills in the mComputedPadding member.
* @return true if the padding is dependent on the containing block width
*
* @param aHorizontalPercentBasis
* Length to use for resolving percentage padding values in the horizontal
* axis. Usually the containing block width.
* @param aVerticalPercentBasis
* Length to use for resolving percentage padding values in the vertical
* axis. Usually the containing block width, per CSS21 sec 8.4, but may
* be the containing block *height* in e.g. CSS3 Flexbox and Grid.
* @return true if the padding is dependent on the containing block size.
*/
bool ComputePadding(nscoord aContainingBlockWidth, nsIAtom* aFrameType);
bool ComputePadding(nscoord aHorizontalPercentBasis,
nscoord aVerticalPercentBasis, nsIAtom* aFrameType);
protected:
void InitOffsets(nscoord aContainingBlockWidth,
void InitOffsets(nscoord aHorizontalPercentBasis,
nscoord aVerticalPercentBasis,
nsIAtom* aFrameType,
const nsMargin *aBorder = nullptr,
const nsMargin *aPadding = nullptr);