diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index e58959970edd..27363211c209 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2622,7 +2622,7 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP nsDocumentViewer::GetContentSize( const nscoord minISize = wm.IsVertical() ? constraints.mMinSize.height : constraints.mMinSize.width; const nscoord maxISize = wm.IsVertical() ? aMaxHeight : aMaxWidth; - const IntrinsicSizeInput input(rcx.get()); + const IntrinsicSizeInput input(rcx.get(), Nothing()); if (aPrefWidth) { prefISize = std::max(root->GetMinISize(input), aPrefWidth); } else { diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 956441d2cf58..35fed5e7c0d9 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4041,6 +4041,9 @@ static Maybe GetPercentBSize(const LengthPercentage& aSize, nsIFrame* aFrame, bool aHorizontalAxis); // Only call on aSize for which GetAbsoluteSize returned Nothing(). +// +// Bug 1363918: We can remove GetPercentBSize() after we've updated all of +// IntrinsicForAxis()'s callsites to pass it a percentage basis. template static Maybe GetPercentBSize(const SizeOrMaxSize& aSize, nsIFrame* aFrame, bool aHorizontalAxis) { @@ -4309,7 +4312,9 @@ static Maybe GetIntrinsicSize(nsIFrame::ExtremumLength aLength, if (aISizeFromAspectRatio) { result = *aISizeFromAspectRatio; } else { - const IntrinsicSizeInput input(aRenderingContext); + // Bug 1363918: We need to refactor this function to compute a percentage + // basis when computing intrinsic sizes. + const IntrinsicSizeInput input(aRenderingContext, Nothing()); auto type = aLength == nsIFrame::ExtremumLength::MaxContent ? IntrinsicISizeType::PrefISize : IntrinsicISizeType::MinISize; @@ -4439,7 +4444,9 @@ static nscoord AddIntrinsicSizeOffset( if (aISizeFromAspectRatio) { minContent = maxContent = *aISizeFromAspectRatio; } else { - const IntrinsicSizeInput input(aRenderingContext); + // Bug 1363918: We need to refactor this function to compute a percentage + // basis when computing intrinsic sizes. + const IntrinsicSizeInput input(aRenderingContext, Nothing()); minContent = aFrame->GetMinISize(input); maxContent = aFrame->GetPrefISize(input); } @@ -4643,6 +4650,32 @@ nscoord nsLayoutUtils::IntrinsicForAxis( fixedMinISize = GetAbsoluteSize(styleMinISize); } + // Handle elements with an intrinsic ratio (or size) and a specified + // height, min-height, or max-height. + // NOTE: + // 1. We treat "min-height:auto" as "0" for the purpose of this code, + // since that's what it means in all cases except for on flex items -- and + // even there, we're supposed to ignore it (i.e. treat it as 0) until the + // flex container explicitly considers it. + // 2. The 'B' in |styleBSize|, |styleMinBSize|, and |styleMaxBSize| + // represents the ratio-determining axis of |aFrame|. It could be the inline + // axis or the block axis of |aFrame|. (So we are calculating the size + // along the ratio-dependent axis in this if-branch.) + StyleSize styleBSize = horizontalAxis ? stylePos->mHeight : stylePos->mWidth; + StyleSize styleMinBSize = + horizontalAxis ? stylePos->mMinHeight : stylePos->mMinWidth; + StyleMaxSize styleMaxBSize = + horizontalAxis ? stylePos->mMaxHeight : stylePos->mMaxWidth; + + // According to the spec, max-content and min-content should behave as the + // property's initial values in block axis. + // It also make senses to use the initial values for -moz-fit-content and + // -moz-available for intrinsic size in block axis. Therefore, we reset them + // if needed. + if (isInlineAxis) { + ResetIfKeywords(styleBSize, styleMinBSize, styleMaxBSize); + } + auto childWM = aFrame->GetWritingMode(); nscoord pmPercentageBasis = NS_UNCONSTRAINEDSIZE; if (aPercentageBasis.isSome()) { @@ -4734,7 +4767,37 @@ nscoord nsLayoutUtils::IntrinsicForAxis( result = aFrame->BSize(); } } else { - const IntrinsicSizeInput input(aRenderingContext); + // To resolve aFrame's intrinsic inline size, we first check if we can + // resolve a block-axis percentage basis for aFrame's children. This can + // influence their inline size contributions, e.g. if they have an + // aspect-ratio and a percentage-based block size. + const nscoord percentageBasisBSizeForFrame = + aPercentageBasis ? aPercentageBasis->BSize(childWM) + : NS_UNCONSTRAINEDSIZE; + nscoord percentageBasisBSizeForChildren; + if (aFrame->IsBlockContainer()) { + // Compute and cache the box-sizing adjustment in contentEdgeToBoxSizing + // for later use within this function. + contentEdgeToBoxSizing.emplace(GetContentEdgeToBoxSizing(boxSizing)); + + // aFrame is a containing block, so its block size (with min and max + // block size constraints applied) serves as the percentage basis for + // its children. + percentageBasisBSizeForChildren = + nsIFrame::ComputeBSizeValueAsPercentageBasis( + styleBSize, styleMinBSize, styleMaxBSize, + percentageBasisBSizeForFrame, + contentEdgeToBoxSizing->BSize(childWM)); + } else { + // aFrame is not a containing block, so its children share the same + // containing block as aFrame. Therefore, the percentage basis for + // aFrame's children is the same as that for aFrame. + percentageBasisBSizeForChildren = percentageBasisBSizeForFrame; + } + const IntrinsicSizeInput input( + aRenderingContext, + Some(LogicalSize(childWM, NS_UNCONSTRAINEDSIZE, + percentageBasisBSizeForChildren))); result = aFrame->IntrinsicISize(input, aType); } #ifdef DEBUG_INTRINSIC_WIDTH @@ -4746,33 +4809,6 @@ nscoord nsLayoutUtils::IntrinsicForAxis( horizontalAxis ? "horizontal" : "vertical", result); #endif - // Handle elements with an intrinsic ratio (or size) and a specified - // height, min-height, or max-height. - // NOTE: - // 1. We treat "min-height:auto" as "0" for the purpose of this code, - // since that's what it means in all cases except for on flex items -- and - // even there, we're supposed to ignore it (i.e. treat it as 0) until the - // flex container explicitly considers it. - // 2. The 'B' in |styleBSize|, |styleMinBSize|, and |styleMaxBSize| - // represents the ratio-determining axis of |aFrame|. It could be the inline - // axis or the block axis of |aFrame|. (So we are calculating the size - // along the ratio-dependent axis in this if-branch.) - StyleSize styleBSize = - horizontalAxis ? stylePos->mHeight : stylePos->mWidth; - StyleSize styleMinBSize = - horizontalAxis ? stylePos->mMinHeight : stylePos->mMinWidth; - StyleMaxSize styleMaxBSize = - horizontalAxis ? stylePos->mMaxHeight : stylePos->mMaxWidth; - - // According to the spec, max-content and min-content should behave as the - // property's initial values in block axis. - // It also make senses to use the initial values for -moz-fit-content and - // -moz-available for intrinsic size in block axis. Therefore, we reset them - // if needed. - if (isInlineAxis) { - ResetIfKeywords(styleBSize, styleMinBSize, styleMaxBSize); - } - // If our BSize or min/max-BSize properties are set to values that we can // resolve and that will impose a constraint when transferred through our // aspect ratio (if we have one), then compute and apply that constraint. @@ -4808,7 +4844,10 @@ nscoord nsLayoutUtils::IntrinsicForAxis( nscoord bSizeTakenByBoxSizing = GetDefiniteSizeTakenByBoxSizing( boxSizing, aFrame, !isInlineAxis, ignorePadding, aPercentageBasis); - contentEdgeToBoxSizing.emplace(GetContentEdgeToBoxSizing(boxSizing)); + if (!contentEdgeToBoxSizing) { + contentEdgeToBoxSizing.emplace(GetContentEdgeToBoxSizing(boxSizing)); + } + // NOTE: This is only the minContentSize if we've been passed // MIN_INTRINSIC_ISIZE (which is fine, because this should only be used // inside a check for that flag). @@ -4869,7 +4908,7 @@ nscoord nsLayoutUtils::IntrinsicForAxis( if (aFrame->IsTableFrame()) { // Tables can't shrink smaller than their intrinsic minimum inline size, // no matter what. - const IntrinsicSizeInput input(aRenderingContext); + const IntrinsicSizeInput input(aRenderingContext, Nothing()); min = aFrame->GetMinISize(input); } diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index 5900b6fa6f04..fee546d72504 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -249,7 +249,7 @@ LogicalSize nsTextControlFrame::CalcIntrinsicSize(gfxContext* aRenderingContext, // Add the inline size of the button if our char size is explicit, so as to // make sure to make enough space for it. if (maybeCols.isSome() && mButton && mButton->GetPrimaryFrame()) { - const IntrinsicSizeInput input(aRenderingContext); + const IntrinsicSizeInput input(aRenderingContext, Nothing()); intrinsicSize.ISize(aWM) += mButton->GetPrimaryFrame()->GetMinISize(input); } diff --git a/layout/generic/ColumnSetWrapperFrame.cpp b/layout/generic/ColumnSetWrapperFrame.cpp index 71735bcefde6..452fe245a387 100644 --- a/layout/generic/ColumnSetWrapperFrame.cpp +++ b/layout/generic/ColumnSetWrapperFrame.cpp @@ -199,8 +199,9 @@ nscoord ColumnSetWrapperFrame::MinISize(const IntrinsicSizeInput& aInput) { } } else { for (nsIFrame* f : PrincipalChildList()) { - const IntrinsicSizeInput input(aInput.mContext); - iSize = std::max(iSize, f->GetMinISize(input)); + const IntrinsicSizeInput childInput(aInput, f->GetWritingMode(), + GetWritingMode()); + iSize = std::max(iSize, f->GetMinISize(childInput)); } } @@ -236,8 +237,9 @@ nscoord ColumnSetWrapperFrame::PrefISize(const IntrinsicSizeInput& aInput) { iSize = ColumnUtils::IntrinsicISize(numColumns, colGap, colISize); } else { for (nsIFrame* f : PrincipalChildList()) { - const IntrinsicSizeInput input(aInput.mContext); - iSize = std::max(iSize, f->GetPrefISize(input)); + const IntrinsicSizeInput childInput(aInput, f->GetWritingMode(), + GetWritingMode()); + iSize = std::max(iSize, f->GetPrefISize(childInput)); } } diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 6bc9bd93d2b1..43d252c1f112 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -871,8 +871,12 @@ nscoord nsBlockFrame::MinISize(const IntrinsicSizeInput& aInput) { #endif if (line->IsBlock()) { data.ForceBreak(); + nsIFrame* kid = line->mFirstChild; + const IntrinsicSizeInput kidInput(aInput, kid->GetWritingMode(), + GetWritingMode()); data.mCurrentLine = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, line->mFirstChild, IntrinsicISizeType::MinISize); + kidInput.mContext, kid, IntrinsicISizeType::MinISize, + kidInput.mPercentageBasis); data.ForceBreak(); } else { if (!curFrame->GetPrevContinuation() && TextIndentAppliesTo(line)) { @@ -883,7 +887,8 @@ nscoord nsBlockFrame::MinISize(const IntrinsicSizeInput& aInput) { nsIFrame* kid = line->mFirstChild; for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end; ++i, kid = kid->GetNextSibling()) { - const IntrinsicSizeInput kidInput(aInput.mContext); + const IntrinsicSizeInput kidInput(aInput, kid->GetWritingMode(), + GetWritingMode()); kid->AddInlineMinISize(kidInput, &data); if (whiteSpaceCanWrap && data.mTrailingWhitespace) { data.OptionallyBreak(); @@ -942,15 +947,19 @@ nscoord nsBlockFrame::PrefISize(const IntrinsicSizeInput& aInput) { AutoNoisyIndenter lineindent(gNoisyIntrinsic); #endif if (line->IsBlock()) { + nsIFrame* kid = line->mFirstChild; StyleClear clearType; - if (!data.mLineIsEmpty || BlockCanIntersectFloats(line->mFirstChild)) { + if (!data.mLineIsEmpty || BlockCanIntersectFloats(kid)) { clearType = StyleClear::Both; } else { - clearType = line->mFirstChild->StyleDisplay()->mClear; + clearType = kid->StyleDisplay()->mClear; } data.ForceBreak(clearType); + const IntrinsicSizeInput kidInput(aInput, kid->GetWritingMode(), + GetWritingMode()); data.mCurrentLine = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, line->mFirstChild, IntrinsicISizeType::PrefISize); + kidInput.mContext, kid, IntrinsicISizeType::PrefISize, + kidInput.mPercentageBasis); data.ForceBreak(); } else { if (!curFrame->GetPrevContinuation() && TextIndentAppliesTo(line)) { @@ -966,7 +975,8 @@ nscoord nsBlockFrame::PrefISize(const IntrinsicSizeInput& aInput) { nsIFrame* kid = line->mFirstChild; for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end; ++i, kid = kid->GetNextSibling()) { - const IntrinsicSizeInput kidInput(aInput.mContext); + const IntrinsicSizeInput kidInput(aInput, kid->GetWritingMode(), + GetWritingMode()); kid->AddInlinePrefISize(kidInput, &data); } } @@ -1024,7 +1034,12 @@ nsresult nsBlockFrame::GetPrefWidthTightBounds(gfxContext* aRenderingContext, data.mLine = &line; data.SetLineContainer(curFrame); nsIFrame* kid = line->mFirstChild; - const IntrinsicSizeInput kidInput(aRenderingContext); + // Per comment in nsIFrame::GetPrefWidthTightBounds(), the function is + // only implemented for nsBlockFrame and nsTextFrame and is used to + // determine the intrinsic inline sizes of MathML token elements. These + // elements shouldn't have percentage block sizes that require a + // percentage basis for resolution. + const IntrinsicSizeInput kidInput(aRenderingContext, Nothing()); for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end; ++i, kid = kid->GetNextSibling()) { rv = kid->GetPrefWidthTightBounds(aRenderingContext, &childX, diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 483ed64e45cf..d7a197139c6f 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -792,7 +792,8 @@ void nsContainerFrame::DoInlineMinISize(const IntrinsicSizeInput& aInput, InlineMinISizeData* aData) { auto handleChildren = [&](auto frame, auto data) { for (nsIFrame* kid : frame->mFrames) { - const IntrinsicSizeInput kidInput(aInput.mContext); + const IntrinsicSizeInput kidInput(aInput, kid->GetWritingMode(), + GetWritingMode()); kid->AddInlineMinISize(kidInput, data); } }; @@ -803,7 +804,8 @@ void nsContainerFrame::DoInlinePrefISize(const IntrinsicSizeInput& aInput, InlinePrefISizeData* aData) { auto handleChildren = [&](auto frame, auto data) { for (nsIFrame* kid : frame->mFrames) { - const IntrinsicSizeInput kidInput(aInput.mContext); + const IntrinsicSizeInput kidInput(aInput, kid->GetWritingMode(), + GetWritingMode()); kid->AddInlinePrefISize(kidInput, data); } }; @@ -835,7 +837,7 @@ LogicalSize nsContainerFrame::ComputeAutoSize( AutoMaybeDisableFontInflation an(this); WritingMode tableWM = GetParent()->GetWritingMode(); - const IntrinsicSizeInput input(aRenderingContext); + const IntrinsicSizeInput input(aRenderingContext, Nothing()); if (aWM.IsOrthogonalTo(tableWM)) { // For an orthogonal caption on a block-dir side of the table, shrink-wrap // to min-isize. diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 749e72c1e30b..778566d6a252 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -6454,8 +6454,10 @@ nscoord nsFlexContainerFrame::ComputeIntrinsicISize( continue; } + const IntrinsicSizeInput childInput(aInput, childFrame->GetWritingMode(), + GetWritingMode()); nscoord childISize = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, childFrame, aType); + childInput.mContext, childFrame, aType, childInput.mPercentageBasis); // * For a row-oriented single-line flex container, the intrinsic // {min/pref}-isize is the sum of its items' {min/pref}-isizes and diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 1f6f5b0cf114..426ddc258da8 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -6016,7 +6016,8 @@ void nsIFrame::MarkSubtreeDirty() { void nsIFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput, InlineMinISizeData* aData) { nscoord isize = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, this, IntrinsicISizeType::MinISize); + aInput.mContext, this, IntrinsicISizeType::MinISize, + aInput.mPercentageBasis); aData->DefaultAddInlineMinISize(this, isize); } @@ -6024,7 +6025,8 @@ void nsIFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput, void nsIFrame::AddInlinePrefISize(const IntrinsicSizeInput& aInput, nsIFrame::InlinePrefISizeData* aData) { nscoord isize = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, this, IntrinsicISizeType::PrefISize); + aInput.mContext, this, IntrinsicISizeType::PrefISize, + aInput.mPercentageBasis); aData->DefaultAddInlinePrefISize(isize); } @@ -6515,7 +6517,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize( result.ISize(aWM) = std::min(maxISize, result.ISize(aWM)); } - const IntrinsicSizeInput input(aRenderingContext); + const IntrinsicSizeInput input(aRenderingContext, Nothing()); const auto& minISizeCoord = stylePos->MinISize(aWM); nscoord minISize; if (!minISizeCoord.IsAuto() && !shouldIgnoreMinMaxISize) { @@ -6684,6 +6686,31 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize( return {result, aspectRatioUsage}; } +nscoord nsIFrame::ComputeBSizeValueAsPercentageBasis( + const StyleSize& aStyleBSize, const StyleSize& aStyleMinBSize, + const StyleMaxSize& aStyleMaxBSize, nscoord aCBBSize, + nscoord aContentEdgeToBoxSizingBSize) { + const nscoord bSize = nsLayoutUtils::IsAutoBSize(aStyleBSize, aCBBSize) + ? NS_UNCONSTRAINEDSIZE + : nsLayoutUtils::ComputeBSizeValue( + aCBBSize, aContentEdgeToBoxSizingBSize, + aStyleBSize.AsLengthPercentage()); + + const nscoord minBSize = nsLayoutUtils::IsAutoBSize(aStyleMinBSize, aCBBSize) + ? 0 + : nsLayoutUtils::ComputeBSizeValue( + aCBBSize, aContentEdgeToBoxSizingBSize, + aStyleMinBSize.AsLengthPercentage()); + + const nscoord maxBSize = nsLayoutUtils::IsAutoBSize(aStyleMaxBSize, aCBBSize) + ? NS_UNCONSTRAINEDSIZE + : nsLayoutUtils::ComputeBSizeValue( + aCBBSize, aContentEdgeToBoxSizingBSize, + aStyleMaxBSize.AsLengthPercentage()); + + return CSSMinMax(bSize, minBSize, maxBSize); +} + nsRect nsIFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const { return InkOverflowRect(); } @@ -6711,7 +6738,19 @@ LogicalSize nsIFrame::ComputeAutoSize( if (styleISize.IsAuto()) { nscoord availBased = aAvailableISize - aMargin.ISize(aWM) - aBorderPadding.ISize(aWM); - const IntrinsicSizeInput input(aRenderingContext); + const auto* stylePos = StylePosition(); + const auto& styleBSize = aSizeOverrides.mStyleBSize + ? *aSizeOverrides.mStyleBSize + : stylePos->BSize(aWM); + const LogicalSize contentEdgeToBoxSizing = + stylePos->mBoxSizing == StyleBoxSizing::Border ? aBorderPadding + : LogicalSize(aWM); + const nscoord bSize = ComputeBSizeValueAsPercentageBasis( + styleBSize, stylePos->MinBSize(aWM), stylePos->MaxBSize(aWM), + aCBSize.BSize(aWM), contentEdgeToBoxSizing.BSize(aWM)); + const IntrinsicSizeInput input( + aRenderingContext, Some(LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, bSize) + .ConvertTo(GetWritingMode(), aWM))); result.ISize(aWM) = ShrinkISizeToFit(input, availBased, aFlags); } return result; @@ -6802,7 +6841,12 @@ nsIFrame::ISizeComputationResult nsIFrame::ComputeISizeValue( aAspectRatio)); }(); - const IntrinsicSizeInput input(aRenderingContext); + const auto* stylePos = StylePosition(); + const nscoord bSize = ComputeBSizeValueAsPercentageBasis( + aStyleBSize, stylePos->MinBSize(aWM), stylePos->MaxBSize(aWM), + aCBSize.BSize(aWM), aContentEdgeToBoxSizing.BSize(aWM)); + const IntrinsicSizeInput input( + aRenderingContext, Some(LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, bSize))); nscoord result; switch (aSize) { case ExtremumLength::MaxContent: diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index c90ddd236d2b..e8731ac8f7ac 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -422,9 +422,32 @@ struct FrameBidiData { struct MOZ_STACK_CLASS IntrinsicSizeInput final { gfxContext* const mContext; - explicit IntrinsicSizeInput(gfxContext* aContext) : mContext(aContext) { + // The content-box size of a frame, served as a percentage basis when + // computing the children's intrinsic contributions. If the basis is + // indefinite in a given axis, use NS_UNCONSTRAINEDSIZE for that component. + // + // In most scenarios, this struct is used when computing the inline size + // contribution, so the inline component of the percentage basis should be set + // to NS_UNCONSTRAINEDSIZE. + Maybe mPercentageBasis; + + IntrinsicSizeInput(gfxContext* aContext, + const Maybe& aPercentageBasis) + : mContext(aContext), mPercentageBasis(aPercentageBasis) { MOZ_ASSERT(mContext); } + + // Construct a new IntrinsicSizeInput by copying from aSource. + // + // This constructor converts mPercentageBasis' writing mode, if it exists. The + // original mPercentageBasis in aSource is expected to be in the writing mode + // aFromWM, and it will be converted to the writing mode aToWM. + IntrinsicSizeInput(const IntrinsicSizeInput& aSource, + mozilla::WritingMode aToWM, mozilla::WritingMode aFromWM) + : IntrinsicSizeInput(aSource.mContext, + aSource.mPercentageBasis.map([&](const auto& aPB) { + return aPB.ConvertTo(aToWM, aFromWM); + })) {} }; } // namespace mozilla @@ -2872,6 +2895,12 @@ class nsIFrame : public nsQueryFrame { const mozilla::StyleSizeOverrides& aSizeOverrides, mozilla::ComputeSizeFlags aFlags); + static nscoord ComputeBSizeValueAsPercentageBasis( + const mozilla::StyleSize& aStyleBSize, + const mozilla::StyleSize& aStyleMinBSize, + const mozilla::StyleMaxSize& aStyleMaxBSize, nscoord aCBBSize, + nscoord aContentEdgeToBoxSizingBSize); + protected: /** * A helper, used by |nsIFrame::ComputeSize| (for frames that need to diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index d747cab6edb9..4a6abc445ef5 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -2850,7 +2850,8 @@ static bool IsInAutoWidthTableCellForQuirk(nsIFrame* aFrame) { void nsImageFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput, InlineMinISizeData* aData) { nscoord isize = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, this, IntrinsicISizeType::MinISize); + aInput.mContext, this, IntrinsicISizeType::MinISize, + aInput.mPercentageBasis); bool canBreak = !IsInAutoWidthTableCellForQuirk(this); aData->DefaultAddInlineMinISize(this, isize, canBreak); } diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp index d277da0a39b7..29f9cd5071a4 100644 --- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -75,8 +75,11 @@ void nsPlaceholderFrame::AddFloatToIntrinsicISizeData( const IntrinsicSizeInput& aInput, IntrinsicISizeType aType, InlineIntrinsicISizeData* aData) const { if (mOutOfFlowFrame->IsFloating()) { + const IntrinsicSizeInput floatInput( + aInput, mOutOfFlowFrame->GetWritingMode(), GetWritingMode()); const nscoord floatISize = nsLayoutUtils::IntrinsicForContainer( - aInput.mContext, mOutOfFlowFrame, aType); + floatInput.mContext, mOutOfFlowFrame, aType, + floatInput.mPercentageBasis); aData->mFloats.EmplaceBack(mOutOfFlowFrame, floatISize); } } diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp index 501ca598a641..7b6de00bff99 100644 --- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -214,7 +214,7 @@ void nsRubyBaseContainerFrame::AddInlineMinISize( void nsRubyBaseContainerFrame::AddInlinePrefISize( const IntrinsicSizeInput& aInput, InlinePrefISizeData* aData) { AutoRubyTextContainerArray textContainers(this); - const IntrinsicSizeInput input(aInput.mContext); + const IntrinsicSizeInput input(aInput.mContext, Nothing()); nscoord sum = 0; for (nsIFrame* frame = this; frame; frame = frame->GetNextInFlow()) { diff --git a/layout/generic/nsRubyFrame.cpp b/layout/generic/nsRubyFrame.cpp index 73c55d881b16..5d44427d93d0 100644 --- a/layout/generic/nsRubyFrame.cpp +++ b/layout/generic/nsRubyFrame.cpp @@ -54,7 +54,9 @@ nsresult nsRubyFrame::GetFrameName(nsAString& aResult) const { void nsRubyFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput, InlineMinISizeData* aData) { auto handleChildren = [&](auto frame, auto data) { - const IntrinsicSizeInput input(aInput.mContext); + // Ruby frames shouldn't have percentage block sizes that require a + // percentage basis for resolution. + const IntrinsicSizeInput input(aInput.mContext, Nothing()); for (RubySegmentEnumerator e(static_cast(frame)); !e.AtEnd(); e.Next()) { e.GetBaseContainer()->AddInlineMinISize(input, data); @@ -67,7 +69,9 @@ void nsRubyFrame::AddInlineMinISize(const IntrinsicSizeInput& aInput, void nsRubyFrame::AddInlinePrefISize(const IntrinsicSizeInput& aInput, InlinePrefISizeData* aData) { auto handleChildren = [&](auto frame, auto data) { - const IntrinsicSizeInput input(aInput.mContext); + // Ruby frames shouldn't have percentage block sizes that require a + // percentage basis for resolution. + const IntrinsicSizeInput input(aInput.mContext, Nothing()); for (RubySegmentEnumerator e(static_cast(frame)); !e.AtEnd(); e.Next()) { e.GetBaseContainer()->AddInlinePrefISize(input, data); diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp index 7d7d45ae42af..441632849b26 100644 --- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -5105,7 +5105,7 @@ void SVGTextFrame::DoReflow() { kid->MarkIntrinsicISizesDirty(); } - const IntrinsicSizeInput input(renderingContext.get()); + const IntrinsicSizeInput input(renderingContext.get(), Nothing()); nscoord inlineSize = kid->GetPrefISize(input); WritingMode wm = kid->GetWritingMode(); ReflowInput reflowInput(presContext, kid, renderingContext.get(), diff --git a/layout/tables/BasicTableLayoutStrategy.cpp b/layout/tables/BasicTableLayoutStrategy.cpp index 2a29560defde..93e4535eb393 100644 --- a/layout/tables/BasicTableLayoutStrategy.cpp +++ b/layout/tables/BasicTableLayoutStrategy.cpp @@ -69,11 +69,14 @@ struct CellISizeInfo { float prefPercent; }; -// Used for both column and cell calculations. The parts needed only -// for cells are skipped when aIsCell is false. +// A helper for ComputeColumnIntrinsicISizes(), used for both column and cell +// intrinsic inline size calculations. The parts needed only for cells are +// skipped when aIsCell is false. static CellISizeInfo GetISizeInfo(gfxContext* aRenderingContext, nsIFrame* aFrame, WritingMode aWM, bool aIsCell) { + MOZ_ASSERT(aFrame->GetWritingMode() == aWM, + "The caller is expected to pass aFrame's writing mode!"); nscoord minCoord, prefCoord; const nsStylePosition* stylePos = aFrame->StylePosition(); bool isQuirks = @@ -84,7 +87,28 @@ static CellISizeInfo GetISizeInfo(gfxContext* aRenderingContext, // wrapping inside of it should not apply font size inflation. AutoMaybeDisableFontInflation an(aFrame); - const IntrinsicSizeInput input(aRenderingContext); + // Resolve the cell's block size 'cellBSize' as a percentage basis, in case + // it impacts its children's inline-size contributions (e.g. via percentage + // block size + aspect-ratio). However, this behavior might not be + // web-compatible (Bug 1461852). + // + // Note that if the cell *itself* has a percentage-based block size, we + // treat it as unresolvable here by using an unconstrained cbBSize. It will + // be resolved during the "special bsize reflow" pass if the table has a + // specified block size. See nsTableFrame::Reflow() and + // ReflowInput::Flags::mSpecialBSizeReflow. + const nscoord cbBSize = NS_UNCONSTRAINEDSIZE; + const nscoord contentEdgeToBoxSizingBSize = + stylePos->mBoxSizing == StyleBoxSizing::Border + ? aFrame->IntrinsicBSizeOffsets().BorderPadding() + : 0; + const nscoord cellBSize = nsIFrame::ComputeBSizeValueAsPercentageBasis( + stylePos->BSize(aWM), stylePos->MinBSize(aWM), stylePos->MaxBSize(aWM), + cbBSize, contentEdgeToBoxSizingBSize); + + const IntrinsicSizeInput input( + aRenderingContext, + Some(LogicalSize(aWM, NS_UNCONSTRAINEDSIZE, cellBSize))); minCoord = aFrame->GetMinISize(input); prefCoord = aFrame->GetPrefISize(input); // Until almost the end of this function, minCoord and prefCoord diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index a2b2aac4917c..0300ba1f4f32 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -598,9 +598,14 @@ ScrollContainerFrame* nsTableCellFrame::GetScrollTargetFrame() const { nscoord nsTableCellFrame::IntrinsicISize(const IntrinsicSizeInput& aInput, IntrinsicISizeType aType) { - return nsLayoutUtils::IntrinsicForContainer(aInput.mContext, Inner(), aType, - Nothing(), - nsLayoutUtils::IGNORE_PADDING); + // Note: a table cell has the same writing mode as its table ancestor, which + // may differ from its inner frame that derives its writing mode from the + // style of the element. See nsTableCellFrame::Init(). + const IntrinsicSizeInput innerInput(aInput, Inner()->GetWritingMode(), + GetWritingMode()); + return nsLayoutUtils::IntrinsicForContainer( + innerInput.mContext, Inner(), aType, innerInput.mPercentageBasis, + nsLayoutUtils::IGNORE_PADDING); } /* virtual */ nsIFrame::IntrinsicSizeOffsetData diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index dd84d3db090f..128cc4bcbdfb 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1403,7 +1403,7 @@ nsIFrame::SizeComputationResult nsTableFrame::ComputeSize( AutoMaybeDisableFontInflation an(this); // Tables never shrink below their min inline-size. - const IntrinsicSizeInput input(aRenderingContext); + const IntrinsicSizeInput input(aRenderingContext, Nothing()); nscoord minISize = GetMinISize(input); if (minISize > result.mLogicalSize.ISize(aWM)) { result.mLogicalSize.ISize(aWM) = minISize; @@ -1419,7 +1419,7 @@ nscoord nsTableFrame::TableShrinkISizeToFit(gfxContext* aRenderingContext, AutoMaybeDisableFontInflation an(this); nscoord result; - const IntrinsicSizeInput input(aRenderingContext); + const IntrinsicSizeInput input(aRenderingContext, Nothing()); nscoord minISize = GetMinISize(input); if (minISize > aISizeInCB) { result = minISize; diff --git a/testing/web-platform/meta/css/css-position/position-absolute-percentage-height.html.ini b/testing/web-platform/meta/css/css-position/position-absolute-percentage-height.html.ini index 2b18165eec2b..3e64ab156ce4 100644 --- a/testing/web-platform/meta/css/css-position/position-absolute-percentage-height.html.ini +++ b/testing/web-platform/meta/css/css-position/position-absolute-percentage-height.html.ini @@ -3,6 +3,3 @@ if (os == "android") and fission: [OK, TIMEOUT] [#target height matches containing block height, and target parent width matches #target width after resize] expected: FAIL - - [#target height matches containing block height, and target parent width matches #target width] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-sizing/aspect-ratio/grid-aspect-ratio-041.html.ini b/testing/web-platform/meta/css/css-sizing/aspect-ratio/grid-aspect-ratio-041.html.ini new file mode 100644 index 000000000000..d329b6b00f59 --- /dev/null +++ b/testing/web-platform/meta/css/css-sizing/aspect-ratio/grid-aspect-ratio-041.html.ini @@ -0,0 +1,7 @@ +[grid-aspect-ratio-041.html] + # Before bug 1909761, we pass this test by accident. To pass this test, we + # need to resolve row size based on the grid container's definite height, and + # use that row size to resolve "height: 100%" when computing the intrinsic + # size of the middle div. Bug 1300366 might fix this. + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1300366 diff --git a/testing/web-platform/meta/css/css-writing-modes/abs-pos-with-replaced-child.html.ini b/testing/web-platform/meta/css/css-writing-modes/abs-pos-with-replaced-child.html.ini deleted file mode 100644 index 2ec2366d5aad..000000000000 --- a/testing/web-platform/meta/css/css-writing-modes/abs-pos-with-replaced-child.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[abs-pos-with-replaced-child.html] - expected: FAIL