diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 3a0903e27b62..dbfe7c24805d 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5432,366 +5432,6 @@ nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame) } while (stack.Length() != 0); } -/* static */ -LogicalSize -nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM, - nsRenderingContext* aRenderingContext, nsIFrame* aFrame, - const IntrinsicSize& aIntrinsicSize, - nsSize aIntrinsicRatio, - const mozilla::LogicalSize& aCBSize, - const mozilla::LogicalSize& aMargin, - const mozilla::LogicalSize& aBorder, - const mozilla::LogicalSize& aPadding) -{ - const nsStylePosition* stylePos = aFrame->StylePosition(); - const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM); - const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM); - const nsIAtom* parentFrameType = - aFrame->GetParent() ? aFrame->GetParent()->GetType() : nullptr; - const bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame && - !(aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)); - const bool isFlexItem = (parentFrameType == nsGkAtoms::flexContainerFrame && - !(aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)); - bool isInlineFlexItem = false; - Maybe imposedMainSizeStyleCoord; - - // If this is a flex item, and we're measuring its cross size after flexing - // to resolve its main size, then we need to use the resolved main size - // that the container provides to us *instead of* the main-size coordinate - // from our style struct. (Otherwise, we'll be using an irrelevant value in - // the aspect-ratio calculations below.) - if (isFlexItem) { - uint32_t flexDirection = - aFrame->GetParent()->StylePosition()->mFlexDirection; - isInlineFlexItem = - flexDirection == NS_STYLE_FLEX_DIRECTION_ROW || - flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE; - - // If FlexItemMainSizeOverride frame-property is set, then that means the - // flex container is imposing a main-size on this flex item for it to use - // as its size in the container's main axis. - FrameProperties props = aFrame->Properties(); - bool didImposeMainSize; - nscoord imposedMainSize = - props.Get(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize); - if (didImposeMainSize) { - imposedMainSizeStyleCoord.emplace(imposedMainSize, - nsStyleCoord::CoordConstructor); - if (isInlineFlexItem) { - inlineStyleCoord = imposedMainSizeStyleCoord.ptr(); - } else { - blockStyleCoord = imposedMainSizeStyleCoord.ptr(); - } - - } else { - // Flex items use their "flex-basis" property in place of their main-size - // property (e.g. "width") for sizing purposes, *unless* they have - // "flex-basis:auto", in which case they use their main-size property - // after all. - // NOTE: The logic here should match the similar chunk for determining - // inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize(). - const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis); - if (flexBasis->GetUnit() != eStyleUnit_Auto) { - if (isInlineFlexItem) { - inlineStyleCoord = flexBasis; - } else { - // One caveat for vertical flex items: We don't support enumerated - // values (e.g. "max-content") for height properties yet. So, if our - // computed flex-basis is an enumerated value, we'll just behave as if - // it were "auto", which means "use the main-size property after all" - // (which is "height", in this case). - // NOTE: Once we support intrinsic sizing keywords for "height", - // we should remove this check. - if (flexBasis->GetUnit() != eStyleUnit_Enumerated) { - blockStyleCoord = flexBasis; - } - } - } - } - } - - // Handle intrinsic sizes and their interaction with - // {min-,max-,}{width,height} according to the rules in - // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths - - // Note: throughout the following section of the function, I avoid - // a * (b / c) because of its reduced accuracy relative to a * b / c - // or (a * b) / c (which are equivalent). - - const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto; - const bool isAutoBSize = IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM)); - - LogicalSize boxSizingAdjust(aWM); - if (stylePos->mBoxSizing == StyleBoxSizing::Border) { - boxSizingAdjust = aBorder + aPadding; - } - nscoord boxSizingToMarginEdgeISize = - aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) - - boxSizingAdjust.ISize(aWM); - - nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize; - // true if we are stretching a Grid item in the inline dimension - bool stretchI = false; - // true if we are stretching a Grid item in the block dimension - bool stretchB = false; - - if (!isAutoISize) { - iSize = nsLayoutUtils::ComputeISizeValue(aRenderingContext, - aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), - boxSizingToMarginEdgeISize, *inlineStyleCoord); - } else if (MOZ_UNLIKELY(isGridItem)) { - MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(aFrame)); - // 'auto' inline-size for grid-level box - apply 'stretch' as needed: - auto cbSize = aCBSize.ISize(aWM); - if (cbSize != NS_UNCONSTRAINEDSIZE && - !aFrame->StyleMargin()->HasInlineAxisAuto(aWM)) { - auto inlineAxisAlignment = - aWM.IsOrthogonalTo(aFrame->GetParent()->GetWritingMode()) ? - stylePos->UsedAlignSelf(aFrame->GetParent()->StyleContext()) : - stylePos->UsedJustifySelf(aFrame->GetParent()->StyleContext()); - stretchI = inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL || - inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH; - if (stretchI) { - iSize = std::max(nscoord(0), cbSize - - aPadding.ISize(aWM) - - aBorder.ISize(aWM) - - aMargin.ISize(aWM)); - } - } - } - - const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM); - - if (maxISizeCoord.GetUnit() != eStyleUnit_None && - !(isFlexItem && isInlineFlexItem)) { - maxISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext, - aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), - boxSizingToMarginEdgeISize, maxISizeCoord); - } else { - maxISize = nscoord_MAX; - } - - // NOTE: Flex items ignore their min & max sizing properties in their - // flex container's main-axis. (Those properties get applied later in - // the flexbox algorithm.) - - const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM); - - if (minISizeCoord.GetUnit() != eStyleUnit_Auto && - !(isFlexItem && isInlineFlexItem)) { - minISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext, - aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), - boxSizingToMarginEdgeISize, minISizeCoord); - } else { - // Treat "min-width: auto" as 0. - // NOTE: Technically, "auto" is supposed to behave like "min-content" on - // flex items. However, we don't need to worry about that here, because - // flex items' min-sizes are intentionally ignored until the flex - // container explicitly considers them during space distribution. - minISize = 0; - } - - if (!isAutoBSize) { - bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM), - boxSizingAdjust.BSize(aWM), - *blockStyleCoord); - } else if (MOZ_UNLIKELY(isGridItem)) { - MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(aFrame)); - // 'auto' block-size for grid-level box - apply 'stretch' as needed: - auto cbSize = aCBSize.BSize(aWM); - if (cbSize != NS_AUTOHEIGHT && - !aFrame->StyleMargin()->HasBlockAxisAuto(aWM)) { - auto blockAxisAlignment = - !aWM.IsOrthogonalTo(aFrame->GetParent()->GetWritingMode()) ? - stylePos->UsedAlignSelf(aFrame->GetParent()->StyleContext()) : - stylePos->UsedJustifySelf(aFrame->GetParent()->StyleContext()); - stretchB = blockAxisAlignment == NS_STYLE_ALIGN_NORMAL || - blockAxisAlignment == NS_STYLE_ALIGN_STRETCH; - if (stretchB) { - bSize = std::max(nscoord(0), cbSize - - aPadding.BSize(aWM) - - aBorder.BSize(aWM) - - aMargin.BSize(aWM)); - } - } - } - - const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM); - - if (!IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) && - !(isFlexItem && !isInlineFlexItem)) { - maxBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM), - boxSizingAdjust.BSize(aWM), maxBSizeCoord); - } else { - maxBSize = nscoord_MAX; - } - - const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM); - - if (!IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) && - !(isFlexItem && !isInlineFlexItem)) { - minBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM), - boxSizingAdjust.BSize(aWM), minBSizeCoord); - } else { - minBSize = 0; - } - - // Resolve percentage intrinsic iSize/bSize as necessary: - - NS_ASSERTION(aCBSize.ISize(aWM) != NS_UNCONSTRAINEDSIZE, - "Our containing block must not have unconstrained inline-size!"); - - const bool isVertical = aWM.IsVertical(); - const nsStyleCoord& isizeCoord = - isVertical ? aIntrinsicSize.height : aIntrinsicSize.width; - const nsStyleCoord& bsizeCoord = - isVertical ? aIntrinsicSize.width : aIntrinsicSize.height; - - bool hasIntrinsicISize, hasIntrinsicBSize; - nscoord intrinsicISize, intrinsicBSize; - - if (isizeCoord.GetUnit() == eStyleUnit_Coord) { - hasIntrinsicISize = true; - intrinsicISize = isizeCoord.GetCoordValue(); - if (intrinsicISize < 0) - intrinsicISize = 0; - } else { - NS_ASSERTION(isizeCoord.GetUnit() == eStyleUnit_None, - "unexpected unit"); - hasIntrinsicISize = false; - intrinsicISize = 0; - } - - if (bsizeCoord.GetUnit() == eStyleUnit_Coord) { - hasIntrinsicBSize = true; - intrinsicBSize = bsizeCoord.GetCoordValue(); - if (intrinsicBSize < 0) - intrinsicBSize = 0; - } else { - NS_ASSERTION(bsizeCoord.GetUnit() == eStyleUnit_None, - "unexpected unit"); - hasIntrinsicBSize = false; - intrinsicBSize = 0; - } - - NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0, - "Intrinsic ratio has a negative component!"); - LogicalSize logicalRatio(aWM, aIntrinsicRatio); - - // Now calculate the used values for iSize and bSize: - - if (isAutoISize) { - if (isAutoBSize) { - - // 'auto' iSize, 'auto' bSize - - // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2: - - nscoord tentISize, tentBSize; - - if (hasIntrinsicISize) { - tentISize = intrinsicISize; - } else if (hasIntrinsicBSize && logicalRatio.BSize(aWM) > 0) { - tentISize = NSCoordMulDiv(intrinsicBSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } else if (logicalRatio.ISize(aWM) > 0) { - tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar? - if (tentISize < 0) tentISize = 0; - } else { - tentISize = nsPresContext::CSSPixelsToAppUnits(300); - } - - if (hasIntrinsicBSize) { - tentBSize = intrinsicBSize; - } else if (logicalRatio.ISize(aWM) > 0) { - tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); - } else { - tentBSize = nsPresContext::CSSPixelsToAppUnits(150); - } - - if (aIntrinsicRatio != nsSize(0, 0)) { - if (stretchI || stretchB) { - // Stretch within the CB size with preserved intrinsic ratio. - if (stretchI && tentISize != iSize) { - tentISize = iSize; // fill the CB iSize - if (logicalRatio.ISize(aWM) > 0) { - tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); - if (tentBSize > bSize && stretchB) { - // We're stretching in both dimensions and the bSize calculated - // from the iSize / ratio would overflow the CB bSize, so stretch - // the bSize instead and derive the iSize which will then fit. - tentBSize = bSize; // fill the CB bSize - if (logicalRatio.BSize(aWM) > 0) { - tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } - } - } - } else if (stretchB && tentBSize != bSize) { - tentBSize = bSize; // fill the CB bSize - if (logicalRatio.BSize(aWM) > 0) { - tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } - } - } - - nsSize autoSize = - ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize, - maxISize, maxBSize, - tentISize, tentBSize); - // The nsSize that ComputeAutoSizeWithIntrinsicDimensions returns will - // actually contain logical values if the parameters passed to it were - // logical coordinates, so we do NOT perform a physical-to-logical - // conversion here, but just assign the fields directly to our result. - iSize = autoSize.width; - bSize = autoSize.height; - } else { - // No intrinsic ratio, so just clamp the dimensions - // independently without calling - // ComputeAutoSizeWithIntrinsicDimensions, which deals with - // propagating these changes to the other dimension (and would - // be incorrect when there is no intrinsic ratio). - iSize = NS_CSS_MINMAX(tentISize, minISize, maxISize); - bSize = NS_CSS_MINMAX(tentBSize, minBSize, maxBSize); - } - } else { - - // 'auto' iSize, non-'auto' bSize - bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); - if (logicalRatio.BSize(aWM) > 0) { - iSize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); - } else if (hasIntrinsicISize) { - iSize = intrinsicISize; - } else { - iSize = nsPresContext::CSSPixelsToAppUnits(300); - } - iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); - - } - } else { - if (isAutoBSize) { - - // non-'auto' iSize, 'auto' bSize - iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); - if (logicalRatio.ISize(aWM) > 0) { - bSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); - } else if (hasIntrinsicBSize) { - bSize = intrinsicBSize; - } else { - bSize = nsPresContext::CSSPixelsToAppUnits(150); - } - bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); - - } else { - - // non-'auto' iSize, non-'auto' bSize - iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); - bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); - - } - } - - return LogicalSize(aWM, iSize, bSize); -} - nsSize nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(nscoord minWidth, nscoord minHeight, nscoord maxWidth, nscoord maxHeight, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 2be43b1b7f57..27577d965d29 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1526,21 +1526,6 @@ public: static void MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame); - /* - * Calculate the used values for 'width' and 'height' for a replaced element. - * - * http://www.w3.org/TR/CSS21/visudet.html#min-max-widths - */ - static mozilla::LogicalSize - ComputeSizeWithIntrinsicDimensions(mozilla::WritingMode aWM, - nsRenderingContext* aRenderingContext, nsIFrame* aFrame, - const mozilla::IntrinsicSize& aIntrinsicSize, - nsSize aIntrinsicRatio, - const mozilla::LogicalSize& aCBSize, - const mozilla::LogicalSize& aMargin, - const mozilla::LogicalSize& aBorder, - const mozilla::LogicalSize& aPadding); - /* * Calculate the used values for 'width' and 'height' when width * and height are 'auto'. The tentWidth and tentHeight arguments should be diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 57b5535fa667..440834066eb2 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -1464,7 +1464,7 @@ nsFlexContainerFrame::GenerateFlexItemForChild( // ------------------------------------------------------------- // Indicates whether the cross-size property is set to something definite. // The logic here should be similar to the logic for isAutoWidth/isAutoHeight -// in nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(). +// in nsFrame::ComputeSizeWithIntrinsicDimensions(). static bool IsCrossSizeDefinite(const ReflowInput& aItemReflowInput, const FlexboxAxisTracker& aAxisTracker) @@ -4089,7 +4089,7 @@ private: // Class to let us temporarily provide an override value for the the main-size // CSS property ('width' or 'height') on a flex item, for use in -// nsLayoutUtils::ComputeSizeWithIntrinsicDimensions. +// nsFrame::ComputeSizeWithIntrinsicDimensions. // (We could use this overridden size more broadly, too, but it's probably // better to avoid property-table accesses. So, where possible, we communicate // the resolved main-size to the child via modifying its reflow state directly, diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 657eaf7bc7b6..8b3276a2ad21 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4650,7 +4650,7 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext, { MOZ_ASSERT(GetIntrinsicRatio() == nsSize(0,0), "Please override this method and call " - "nsLayoutUtils::ComputeSizeWithIntrinsicDimensions instead."); + "nsFrame::ComputeSizeWithIntrinsicDimensions instead."); LogicalSize result = ComputeAutoSize(aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin, aBorder, aPadding, @@ -4686,7 +4686,7 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext, // NOTE: The logic here should match the similar chunk for determining // inlineStyleCoord and blockStyleCoord in - // nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(). + // nsFrame::ComputeSizeWithIntrinsicDimensions(). const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis); if (flexBasis->GetUnit() != eStyleUnit_Auto) { if (isInlineFlexItem) { @@ -4856,6 +4856,366 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext, return result; } +LogicalSize +nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingContext, + WritingMode aWM, + const IntrinsicSize& aIntrinsicSize, + nsSize aIntrinsicRatio, + const LogicalSize& aCBSize, + const LogicalSize& aMargin, + const LogicalSize& aBorder, + const LogicalSize& aPadding) +{ + const nsStylePosition* stylePos = StylePosition(); + const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM); + const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM); + const nsIAtom* parentFrameType = + GetParent() ? GetParent()->GetType() : nullptr; + const bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame && + !(GetStateBits() & NS_FRAME_OUT_OF_FLOW)); + const bool isFlexItem = (parentFrameType == nsGkAtoms::flexContainerFrame && + !(GetStateBits() & NS_FRAME_OUT_OF_FLOW)); + bool isInlineFlexItem = false; + Maybe imposedMainSizeStyleCoord; + + // If this is a flex item, and we're measuring its cross size after flexing + // to resolve its main size, then we need to use the resolved main size + // that the container provides to us *instead of* the main-size coordinate + // from our style struct. (Otherwise, we'll be using an irrelevant value in + // the aspect-ratio calculations below.) + if (isFlexItem) { + uint32_t flexDirection = + GetParent()->StylePosition()->mFlexDirection; + isInlineFlexItem = + flexDirection == NS_STYLE_FLEX_DIRECTION_ROW || + flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE; + + // If FlexItemMainSizeOverride frame-property is set, then that means the + // flex container is imposing a main-size on this flex item for it to use + // as its size in the container's main axis. + FrameProperties props = Properties(); + bool didImposeMainSize; + nscoord imposedMainSize = + props.Get(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize); + if (didImposeMainSize) { + imposedMainSizeStyleCoord.emplace(imposedMainSize, + nsStyleCoord::CoordConstructor); + if (isInlineFlexItem) { + inlineStyleCoord = imposedMainSizeStyleCoord.ptr(); + } else { + blockStyleCoord = imposedMainSizeStyleCoord.ptr(); + } + + } else { + // Flex items use their "flex-basis" property in place of their main-size + // property (e.g. "width") for sizing purposes, *unless* they have + // "flex-basis:auto", in which case they use their main-size property + // after all. + // NOTE: The logic here should match the similar chunk for determining + // inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize(). + const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis); + if (flexBasis->GetUnit() != eStyleUnit_Auto) { + if (isInlineFlexItem) { + inlineStyleCoord = flexBasis; + } else { + // One caveat for vertical flex items: We don't support enumerated + // values (e.g. "max-content") for height properties yet. So, if our + // computed flex-basis is an enumerated value, we'll just behave as if + // it were "auto", which means "use the main-size property after all" + // (which is "height", in this case). + // NOTE: Once we support intrinsic sizing keywords for "height", + // we should remove this check. + if (flexBasis->GetUnit() != eStyleUnit_Enumerated) { + blockStyleCoord = flexBasis; + } + } + } + } + } + + // Handle intrinsic sizes and their interaction with + // {min-,max-,}{width,height} according to the rules in + // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths + + // Note: throughout the following section of the function, I avoid + // a * (b / c) because of its reduced accuracy relative to a * b / c + // or (a * b) / c (which are equivalent). + + const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto; + const bool isAutoBSize = + nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM)); + + LogicalSize boxSizingAdjust(aWM); + if (stylePos->mBoxSizing == StyleBoxSizing::Border) { + boxSizingAdjust = aBorder + aPadding; + } + nscoord boxSizingToMarginEdgeISize = + aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) - + boxSizingAdjust.ISize(aWM); + + nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize; + // true if we are stretching a Grid item in the inline dimension + bool stretchI = false; + // true if we are stretching a Grid item in the block dimension + bool stretchB = false; + + if (!isAutoISize) { + iSize = nsLayoutUtils::ComputeISizeValue(aRenderingContext, + this, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), + boxSizingToMarginEdgeISize, *inlineStyleCoord); + } else if (MOZ_UNLIKELY(isGridItem)) { + MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this)); + // 'auto' inline-size for grid-level box - apply 'stretch' as needed: + auto cbSize = aCBSize.ISize(aWM); + if (cbSize != NS_UNCONSTRAINEDSIZE && + !StyleMargin()->HasInlineAxisAuto(aWM)) { + auto inlineAxisAlignment = + aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ? + stylePos->UsedAlignSelf(GetParent()->StyleContext()) : + stylePos->UsedJustifySelf(GetParent()->StyleContext()); + stretchI = inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL || + inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH; + if (stretchI) { + iSize = std::max(nscoord(0), cbSize - + aPadding.ISize(aWM) - + aBorder.ISize(aWM) - + aMargin.ISize(aWM)); + } + } + } + + const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM); + + if (maxISizeCoord.GetUnit() != eStyleUnit_None && + !(isFlexItem && isInlineFlexItem)) { + maxISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext, + this, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), + boxSizingToMarginEdgeISize, maxISizeCoord); + } else { + maxISize = nscoord_MAX; + } + + // NOTE: Flex items ignore their min & max sizing properties in their + // flex container's main-axis. (Those properties get applied later in + // the flexbox algorithm.) + + const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM); + + if (minISizeCoord.GetUnit() != eStyleUnit_Auto && + !(isFlexItem && isInlineFlexItem)) { + minISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext, + this, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), + boxSizingToMarginEdgeISize, minISizeCoord); + } else { + // Treat "min-width: auto" as 0. + // NOTE: Technically, "auto" is supposed to behave like "min-content" on + // flex items. However, we don't need to worry about that here, because + // flex items' min-sizes are intentionally ignored until the flex + // container explicitly considers them during space distribution. + minISize = 0; + } + + if (!isAutoBSize) { + bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM), + boxSizingAdjust.BSize(aWM), + *blockStyleCoord); + } else if (MOZ_UNLIKELY(isGridItem)) { + MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this)); + // 'auto' block-size for grid-level box - apply 'stretch' as needed: + auto cbSize = aCBSize.BSize(aWM); + if (cbSize != NS_AUTOHEIGHT && + !StyleMargin()->HasBlockAxisAuto(aWM)) { + auto blockAxisAlignment = + !aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ? + stylePos->UsedAlignSelf(GetParent()->StyleContext()) : + stylePos->UsedJustifySelf(GetParent()->StyleContext()); + stretchB = blockAxisAlignment == NS_STYLE_ALIGN_NORMAL || + blockAxisAlignment == NS_STYLE_ALIGN_STRETCH; + if (stretchB) { + bSize = std::max(nscoord(0), cbSize - + aPadding.BSize(aWM) - + aBorder.BSize(aWM) - + aMargin.BSize(aWM)); + } + } + } + + const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM); + + if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) && + !(isFlexItem && !isInlineFlexItem)) { + maxBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM), + boxSizingAdjust.BSize(aWM), maxBSizeCoord); + } else { + maxBSize = nscoord_MAX; + } + + const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM); + + if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) && + !(isFlexItem && !isInlineFlexItem)) { + minBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM), + boxSizingAdjust.BSize(aWM), minBSizeCoord); + } else { + minBSize = 0; + } + + // Resolve percentage intrinsic iSize/bSize as necessary: + + NS_ASSERTION(aCBSize.ISize(aWM) != NS_UNCONSTRAINEDSIZE, + "Our containing block must not have unconstrained inline-size!"); + + const bool isVertical = aWM.IsVertical(); + const nsStyleCoord& isizeCoord = + isVertical ? aIntrinsicSize.height : aIntrinsicSize.width; + const nsStyleCoord& bsizeCoord = + isVertical ? aIntrinsicSize.width : aIntrinsicSize.height; + + bool hasIntrinsicISize, hasIntrinsicBSize; + nscoord intrinsicISize, intrinsicBSize; + + if (isizeCoord.GetUnit() == eStyleUnit_Coord) { + hasIntrinsicISize = true; + intrinsicISize = isizeCoord.GetCoordValue(); + if (intrinsicISize < 0) + intrinsicISize = 0; + } else { + NS_ASSERTION(isizeCoord.GetUnit() == eStyleUnit_None, + "unexpected unit"); + hasIntrinsicISize = false; + intrinsicISize = 0; + } + + if (bsizeCoord.GetUnit() == eStyleUnit_Coord) { + hasIntrinsicBSize = true; + intrinsicBSize = bsizeCoord.GetCoordValue(); + if (intrinsicBSize < 0) + intrinsicBSize = 0; + } else { + NS_ASSERTION(bsizeCoord.GetUnit() == eStyleUnit_None, + "unexpected unit"); + hasIntrinsicBSize = false; + intrinsicBSize = 0; + } + + NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0, + "Intrinsic ratio has a negative component!"); + LogicalSize logicalRatio(aWM, aIntrinsicRatio); + + // Now calculate the used values for iSize and bSize: + + if (isAutoISize) { + if (isAutoBSize) { + + // 'auto' iSize, 'auto' bSize + + // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2: + + nscoord tentISize, tentBSize; + + if (hasIntrinsicISize) { + tentISize = intrinsicISize; + } else if (hasIntrinsicBSize && logicalRatio.BSize(aWM) > 0) { + tentISize = NSCoordMulDiv(intrinsicBSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); + } else if (logicalRatio.ISize(aWM) > 0) { + tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar? + if (tentISize < 0) tentISize = 0; + } else { + tentISize = nsPresContext::CSSPixelsToAppUnits(300); + } + + if (hasIntrinsicBSize) { + tentBSize = intrinsicBSize; + } else if (logicalRatio.ISize(aWM) > 0) { + tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); + } else { + tentBSize = nsPresContext::CSSPixelsToAppUnits(150); + } + + if (aIntrinsicRatio != nsSize(0, 0)) { + if (stretchI || stretchB) { + // Stretch within the CB size with preserved intrinsic ratio. + if (stretchI && tentISize != iSize) { + tentISize = iSize; // fill the CB iSize + if (logicalRatio.ISize(aWM) > 0) { + tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); + if (tentBSize > bSize && stretchB) { + // We're stretching in both dimensions and the bSize calculated + // from the iSize / ratio would overflow the CB bSize, so stretch + // the bSize instead and derive the iSize which will then fit. + tentBSize = bSize; // fill the CB bSize + if (logicalRatio.BSize(aWM) > 0) { + tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); + } + } + } + } else if (stretchB && tentBSize != bSize) { + tentBSize = bSize; // fill the CB bSize + if (logicalRatio.BSize(aWM) > 0) { + tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); + } + } + } + + nsSize autoSize = nsLayoutUtils:: + ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize, + maxISize, maxBSize, + tentISize, tentBSize); + // The nsSize that ComputeAutoSizeWithIntrinsicDimensions returns will + // actually contain logical values if the parameters passed to it were + // logical coordinates, so we do NOT perform a physical-to-logical + // conversion here, but just assign the fields directly to our result. + iSize = autoSize.width; + bSize = autoSize.height; + } else { + // No intrinsic ratio, so just clamp the dimensions + // independently without calling + // ComputeAutoSizeWithIntrinsicDimensions, which deals with + // propagating these changes to the other dimension (and would + // be incorrect when there is no intrinsic ratio). + iSize = NS_CSS_MINMAX(tentISize, minISize, maxISize); + bSize = NS_CSS_MINMAX(tentBSize, minBSize, maxBSize); + } + } else { + + // 'auto' iSize, non-'auto' bSize + bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); + if (logicalRatio.BSize(aWM) > 0) { + iSize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM)); + } else if (hasIntrinsicISize) { + iSize = intrinsicISize; + } else { + iSize = nsPresContext::CSSPixelsToAppUnits(300); + } + iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); + + } + } else { + if (isAutoBSize) { + + // non-'auto' iSize, 'auto' bSize + iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); + if (logicalRatio.ISize(aWM) > 0) { + bSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM)); + } else if (hasIntrinsicBSize) { + bSize = intrinsicBSize; + } else { + bSize = nsPresContext::CSSPixelsToAppUnits(150); + } + bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); + + } else { + + // non-'auto' iSize, non-'auto' bSize + iSize = NS_CSS_MINMAX(iSize, minISize, maxISize); + bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize); + + } + } + + return LogicalSize(aWM, iSize, bSize); +} + nsRect nsIFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const { diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 8e7a396870b5..8e773de9451d 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -275,6 +275,21 @@ public: const mozilla::LogicalSize& aPadding, ComputeSizeFlags aFlags) override; + /** + * Calculate the used values for 'width' and 'height' for a replaced element. + * http://www.w3.org/TR/CSS21/visudet.html#min-max-widths + */ + mozilla::LogicalSize + ComputeSizeWithIntrinsicDimensions( + nsRenderingContext* aRenderingContext, + mozilla::WritingMode aWM, + const mozilla::IntrinsicSize& aIntrinsicSize, + nsSize aIntrinsicRatio, + const mozilla::LogicalSize& aCBSize, + const mozilla::LogicalSize& aMargin, + const mozilla::LogicalSize& aBorder, + const mozilla::LogicalSize& aPadding); + // Compute tight bounds assuming this frame honours its border, background // and outline, its children's tight bounds, and nothing else. nsRect ComputeSimpleTightBounds(mozilla::gfx::DrawTarget* aDrawTarget) const; diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 4158598aa02c..ad41c01d1b26 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -236,14 +236,9 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext, nsSize intrinsicRatio = GetIntrinsicRatio(); // won't actually be used - return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions( - aWM, - aRenderingContext, this, - intrinsicSize, intrinsicRatio, - aCBSize, - aMargin, - aBorder, - aPadding); + return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, + intrinsicSize, intrinsicRatio, + aCBSize, aMargin, aBorder, aPadding); } void diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 364efdac0bf5..142bb9395745 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -870,13 +870,9 @@ nsImageFrame::ComputeSize(nsRenderingContext *aRenderingContext, } } - return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM, - aRenderingContext, this, - intrinsicSize, mIntrinsicRatio, - aCBSize, - aMargin, - aBorder, - aPadding); + return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, + intrinsicSize, mIntrinsicRatio, + aCBSize, aMargin, aBorder, aPadding); } // XXXdholbert This function's clients should probably just be calling diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index aca0bbab7d70..faa937d6617f 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -717,14 +717,11 @@ nsSubDocumentFrame::ComputeSize(nsRenderingContext* aRenderingContext, { nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame(); if (subDocRoot) { - return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM, - aRenderingContext, this, - subDocRoot->GetIntrinsicSize(), - subDocRoot->GetIntrinsicRatio(), - aCBSize, - aMargin, - aBorder, - aPadding); + return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, + subDocRoot->GetIntrinsicSize(), + subDocRoot->GetIntrinsicRatio(), + aCBSize, aMargin, aBorder, + aPadding); } return nsAtomicContainerFrame::ComputeSize(aRenderingContext, aWM, aCBSize, aAvailableISize, diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index e6a9fa0febe8..6c6bd1fe681c 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -535,15 +535,9 @@ nsVideoFrame::ComputeSize(nsRenderingContext *aRenderingContext, // Only video elements have an intrinsic ratio. nsSize intrinsicRatio = HasVideoElement() ? size : nsSize(0, 0); - return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM, - aRenderingContext, - this, - intrinsicSize, - intrinsicRatio, - aCBSize, - aMargin, - aBorder, - aPadding); + return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, + intrinsicSize, intrinsicRatio, + aCBSize, aMargin, aBorder, aPadding); } nscoord nsVideoFrame::GetMinISize(nsRenderingContext *aRenderingContext) diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp index d993817d2c2a..e6f3b80877a8 100644 --- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -347,13 +347,9 @@ nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext, "we lack an intrinsic height or width."); } - return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM, - aRenderingContext, this, - intrinsicSize, GetIntrinsicRatio(), - cbSize, - aMargin, - aBorder, - aPadding); + return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM, + intrinsicSize, GetIntrinsicRatio(), + cbSize, aMargin, aBorder, aPadding); } void