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