diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index 37b65c633d3..f6d3d424e26 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -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 diff --git a/layout/generic/nsHTMLReflowState.h b/layout/generic/nsHTMLReflowState.h index e5b5ad455a8..42aa0b3ae99 100644 --- a/layout/generic/nsHTMLReflowState.h +++ b/layout/generic/nsHTMLReflowState.h @@ -12,6 +12,7 @@ #include "nsStyleCoord.h" #include "nsStyleStructInlines.h" #include "nsIFrame.h" +#include "mozilla/Assertions.h" #include 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);