mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1742042 Part 4 - Apply flex item's stretched cross-size when computing flex container's intrinsic inline size. r=dholbert
For flex items with an aspect-ratio, the expectation is that the stretched cross-sizes can be transferred to the main axis, affecting their intrinsic inline-size contribution to the flex container's intrinsic inline-size. Add `aspect-ratio-intrinsic-size-008.html` (adapted from 003.html) to test a flex item with border and padding since the existing tests do not cover this. Differential Revision: https://phabricator.services.mozilla.com/D222050
This commit is contained in:
parent
3550beeb50
commit
0f96ec1864
@ -4530,7 +4530,8 @@ static void AddStateBitToAncestors(nsIFrame* aFrame, nsFrameState aBit) {
|
||||
nscoord nsLayoutUtils::IntrinsicForAxis(
|
||||
PhysicalAxis aAxis, gfxContext* aRenderingContext, nsIFrame* aFrame,
|
||||
IntrinsicISizeType aType, const Maybe<LogicalSize>& aPercentageBasis,
|
||||
uint32_t aFlags, nscoord aMarginBoxMinSizeClamp) {
|
||||
uint32_t aFlags, nscoord aMarginBoxMinSizeClamp,
|
||||
const StyleSizeOverrides& aSizeOverrides) {
|
||||
MOZ_ASSERT(aFrame, "null frame");
|
||||
MOZ_ASSERT(aFrame->GetParent(),
|
||||
"IntrinsicForAxis called on frame not in tree");
|
||||
@ -4549,23 +4550,28 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
|
||||
// its parent, we'll need to look at its BSize instead of min/pref-ISize.
|
||||
const nsStylePosition* stylePos = aFrame->StylePosition();
|
||||
StyleBoxSizing boxSizing = stylePos->mBoxSizing;
|
||||
PhysicalAxis ourInlineAxis =
|
||||
aFrame->GetWritingMode().PhysicalAxis(LogicalAxis::Inline);
|
||||
const bool isInlineAxis = aAxis == ourInlineAxis;
|
||||
|
||||
StyleSize styleMinISize =
|
||||
horizontalAxis ? stylePos->mMinWidth : stylePos->mMinHeight;
|
||||
StyleSize styleISize =
|
||||
(aFlags & MIN_INTRINSIC_ISIZE)
|
||||
? styleMinISize
|
||||
: (horizontalAxis ? stylePos->mWidth : stylePos->mHeight);
|
||||
StyleSize styleISize = [&]() {
|
||||
if (aFlags & MIN_INTRINSIC_ISIZE) {
|
||||
return styleMinISize;
|
||||
}
|
||||
const Maybe<StyleSize>& styleISizeOverride =
|
||||
isInlineAxis ? aSizeOverrides.mStyleISize : aSizeOverrides.mStyleBSize;
|
||||
return styleISizeOverride
|
||||
? *styleISizeOverride
|
||||
: (horizontalAxis ? stylePos->mWidth : stylePos->mHeight);
|
||||
}();
|
||||
MOZ_ASSERT(!(aFlags & MIN_INTRINSIC_ISIZE) || styleISize.IsAuto() ||
|
||||
nsIFrame::ToExtremumLength(styleISize),
|
||||
"should only use MIN_INTRINSIC_ISIZE for intrinsic values");
|
||||
StyleMaxSize styleMaxISize =
|
||||
horizontalAxis ? stylePos->mMaxWidth : stylePos->mMaxHeight;
|
||||
|
||||
PhysicalAxis ourInlineAxis =
|
||||
aFrame->GetWritingMode().PhysicalAxis(LogicalAxis::Inline);
|
||||
const bool isInlineAxis = aAxis == ourInlineAxis;
|
||||
|
||||
auto ResetIfKeywords = [](StyleSize& aSize, StyleSize& aMinSize,
|
||||
StyleMaxSize& aMaxSize) {
|
||||
if (!aSize.IsLengthPercentage()) {
|
||||
@ -4616,7 +4622,12 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
|
||||
// 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;
|
||||
const Maybe<StyleSize>& styleBSizeOverride =
|
||||
isInlineAxis ? aSizeOverrides.mStyleBSize : aSizeOverrides.mStyleISize;
|
||||
StyleSize styleBSize =
|
||||
styleBSizeOverride
|
||||
? *styleBSizeOverride
|
||||
: (horizontalAxis ? stylePos->mHeight : stylePos->mWidth);
|
||||
StyleSize styleMinBSize =
|
||||
horizontalAxis ? stylePos->mMinHeight : stylePos->mMinWidth;
|
||||
StyleMaxSize styleMaxBSize =
|
||||
@ -4859,10 +4870,6 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
|
||||
(nsIFrame::IsIntrinsicKeyword(styleISize) ||
|
||||
nsIFrame::IsIntrinsicKeyword(styleMinISize) ||
|
||||
nsIFrame::IsIntrinsicKeyword(styleMaxISize))) {
|
||||
// This 'B' in |styleBSize| means the block size of |aFrame|. We go into
|
||||
// this branch only if |aAxis| is the inline axis of |aFrame|.
|
||||
const StyleSize& styleBSize =
|
||||
horizontalAxis ? stylePos->mHeight : stylePos->mWidth;
|
||||
if (Maybe<nscoord> bSize = GetBSize(styleBSize)) {
|
||||
// We cannot reuse |boxSizing| because it may be updated to content-box
|
||||
// in the above if-branch.
|
||||
@ -4898,13 +4905,14 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
|
||||
/* static */
|
||||
nscoord nsLayoutUtils::IntrinsicForContainer(
|
||||
gfxContext* aRenderingContext, nsIFrame* aFrame, IntrinsicISizeType aType,
|
||||
const Maybe<LogicalSize>& aPercentageBasis, uint32_t aFlags) {
|
||||
const Maybe<LogicalSize>& aPercentageBasis, uint32_t aFlags,
|
||||
const StyleSizeOverrides& aSizeOverrides) {
|
||||
MOZ_ASSERT(aFrame && aFrame->GetParent());
|
||||
// We want the size aFrame will contribute to its parent's inline-size.
|
||||
PhysicalAxis axis =
|
||||
aFrame->GetParent()->GetWritingMode().PhysicalAxis(LogicalAxis::Inline);
|
||||
return IntrinsicForAxis(axis, aRenderingContext, aFrame, aType,
|
||||
aPercentageBasis, aFlags);
|
||||
aPercentageBasis, aFlags, NS_MAXSIZE, aSizeOverrides);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layers/ScrollableLayerGuid.h"
|
||||
#include "mozilla/LayoutStructs.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
@ -1470,6 +1471,8 @@ class nsLayoutUtils {
|
||||
* @param aMarginBoxMinSizeClamp make the result fit within this margin-box
|
||||
* size by reducing the *content size* (flooring at zero). This is used for:
|
||||
* https://drafts.csswg.org/css-grid/#min-size-auto
|
||||
* @param aSizeOverrides optional override values for size properties, which
|
||||
* this function will use internally instead of the actual property values.
|
||||
*/
|
||||
enum {
|
||||
IGNORE_PADDING = 0x01,
|
||||
@ -1480,7 +1483,8 @@ class nsLayoutUtils {
|
||||
mozilla::PhysicalAxis aAxis, gfxContext* aRenderingContext,
|
||||
nsIFrame* aFrame, mozilla::IntrinsicISizeType aType,
|
||||
const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
|
||||
uint32_t aFlags = 0, nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE);
|
||||
uint32_t aFlags = 0, nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE,
|
||||
const mozilla::StyleSizeOverrides& aSizeOverrides = {});
|
||||
/**
|
||||
* Calls IntrinsicForAxis with aFrame's parent's inline physical axis.
|
||||
*/
|
||||
@ -1488,7 +1492,8 @@ class nsLayoutUtils {
|
||||
gfxContext* aRenderingContext, nsIFrame* aFrame,
|
||||
mozilla::IntrinsicISizeType aType,
|
||||
const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
|
||||
uint32_t aFlags = 0);
|
||||
uint32_t aFlags = 0,
|
||||
const mozilla::StyleSizeOverrides& aSizeOverrides = {});
|
||||
|
||||
/**
|
||||
* Get the definite size contribution of aFrame for the given physical axis.
|
||||
|
@ -3863,6 +3863,7 @@ void FlexItem::ResolveStretchedCrossSize(nscoord aLineCrossSize) {
|
||||
// We stretch IFF we are align-self:stretch, have no auto margins in
|
||||
// cross axis, and have cross-axis size property == "auto". If any of those
|
||||
// conditions don't hold up, we won't stretch.
|
||||
// https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-stretch
|
||||
if (mAlignSelf._0 != StyleAlignFlags::STRETCH ||
|
||||
NumAutoMarginsInCrossAxis() != 0 || !IsCrossSizeAuto()) {
|
||||
return;
|
||||
@ -6433,6 +6434,8 @@ nscoord nsFlexContainerFrame::ComputeIntrinsicISize(
|
||||
|
||||
const bool useMozBoxCollapseBehavior =
|
||||
StyleVisibility()->UseLegacyCollapseBehavior();
|
||||
const bool isSingleLine = StyleFlexWrap::Nowrap == stylePos->mFlexWrap;
|
||||
const auto flexWM = GetWritingMode();
|
||||
|
||||
// The loop below sets aside space for a gap before each item besides the
|
||||
// first. This bool helps us handle that special-case.
|
||||
@ -6451,11 +6454,79 @@ nscoord nsFlexContainerFrame::ComputeIntrinsicISize(
|
||||
continue;
|
||||
}
|
||||
|
||||
const IntrinsicSizeInput childInput(aInput, childFrame->GetWritingMode(),
|
||||
GetWritingMode());
|
||||
const auto childWM = childFrame->GetWritingMode();
|
||||
const IntrinsicSizeInput childInput(aInput, childWM, flexWM);
|
||||
const auto* childStylePos =
|
||||
nsLayoutUtils::GetStyleFrame(childFrame)->StylePosition();
|
||||
|
||||
// A flex item with a preferred aspect-ratio and a definite size in the flex
|
||||
// container's block axis can transfer its block size to the inline axis,
|
||||
// affecting its intrinsic inline size contribution to the flex container's
|
||||
// intrinsic inline size. This helper function determines whether we should
|
||||
// "pre-stretch" a flex item's cross-size (with that size considered to be
|
||||
// definite) based on the flex container's definite cross-size.
|
||||
//
|
||||
// Note: The logic here is similar to the "pre-stretch" in
|
||||
// GenerateFlexItemForChild(), except that we do not construct a full
|
||||
// FlexItem object.
|
||||
const bool childShouldStretchCrossSize = [&]() {
|
||||
if (!isSingleLine || axisTracker.IsColumnOriented()) {
|
||||
// We only perform "pre-stretch" for the item's cross-size if the flex
|
||||
// container is single-line and row-oriented.
|
||||
return false;
|
||||
}
|
||||
if (!aInput.mPercentageBasisForChildren ||
|
||||
aInput.mPercentageBasisForChildren->BSize(flexWM) ==
|
||||
NS_UNCONSTRAINEDSIZE) {
|
||||
// The flex container does not have a definite cross-size to stretch the
|
||||
// items.
|
||||
//
|
||||
// Note: if the flex container has a definite cross-size (for items to
|
||||
// pre-stretch to fill), it should be passed down in
|
||||
// mPercentageBasisForChildren -- specifically in the BSize component,
|
||||
// given that we know the flex container is row-oriented at this point.
|
||||
return false;
|
||||
}
|
||||
const StyleAlignFlags alignSelf =
|
||||
childStylePos->UsedAlignSelf(Style())._0;
|
||||
if ((alignSelf != StyleAlignFlags::STRETCH &&
|
||||
alignSelf != StyleAlignFlags::NORMAL) ||
|
||||
childFrame->StyleMargin()->HasBlockAxisAuto(flexWM) ||
|
||||
!childStylePos->BSize(flexWM).IsAuto()) {
|
||||
// Similar to FlexItem::ResolveStretchedCrossSize(), we only stretch
|
||||
// the item if it satisfies all the following conditions:
|
||||
// - align-self: stretch or align-self: normal (which behaves as
|
||||
// stretch) https://drafts.csswg.org/css-align-3/#align-flex
|
||||
// - no auto margins in the cross axis
|
||||
// - a cross-axis size property of value "auto"
|
||||
// https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-stretch
|
||||
return false;
|
||||
}
|
||||
// Let's stretch the item's cross-size.
|
||||
return true;
|
||||
}();
|
||||
|
||||
StyleSizeOverrides sizeOverrides;
|
||||
if (childShouldStretchCrossSize) {
|
||||
nscoord stretchedCrossSize =
|
||||
aInput.mPercentageBasisForChildren->BSize(flexWM);
|
||||
if (childStylePos->mBoxSizing == StyleBoxSizing::Content) {
|
||||
const nscoord mbp =
|
||||
childFrame->IntrinsicBSizeOffsets().MarginBorderPadding();
|
||||
stretchedCrossSize = std::max(0, stretchedCrossSize - mbp);
|
||||
}
|
||||
const auto stretchedStyleCrossSize = StyleSize::LengthPercentage(
|
||||
LengthPercentage::FromAppUnits(stretchedCrossSize));
|
||||
// The size override is in the child's own writing mode.
|
||||
if (flexWM.IsOrthogonalTo(childWM)) {
|
||||
sizeOverrides.mStyleISize.emplace(stretchedStyleCrossSize);
|
||||
} else {
|
||||
sizeOverrides.mStyleBSize.emplace(stretchedStyleCrossSize);
|
||||
}
|
||||
}
|
||||
nscoord childISize = nsLayoutUtils::IntrinsicForContainer(
|
||||
childInput.mContext, childFrame, aType,
|
||||
childInput.mPercentageBasisForChildren);
|
||||
childInput.mPercentageBasisForChildren, 0, sizeOverrides);
|
||||
|
||||
// * For a row-oriented single-line flex container, the intrinsic
|
||||
// {min/pref}-isize is the sum of its items' {min/pref}-isizes and
|
||||
@ -6464,7 +6535,6 @@ nscoord nsFlexContainerFrame::ComputeIntrinsicISize(
|
||||
// is the max of its items' min isizes.
|
||||
// * For a row-oriented multi-line flex container, the intrinsic
|
||||
// pref isize is former (sum), and its min isize is the latter (max).
|
||||
bool isSingleLine = (StyleFlexWrap::Nowrap == stylePos->mFlexWrap);
|
||||
if (axisTracker.IsRowOriented() &&
|
||||
(isSingleLine || aType == IntrinsicISizeType::PrefISize)) {
|
||||
containerISize += childISize;
|
||||
|
@ -2815,6 +2815,7 @@ class nsIFrame : public nsQueryFrame {
|
||||
nscoord border = 0;
|
||||
nscoord margin = 0;
|
||||
nscoord BorderPadding() const { return border + padding; };
|
||||
nscoord MarginBorderPadding() const { return margin + border + padding; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -256,8 +256,8 @@ nscoord nsTableWrapperFrame::IntrinsicISize(const IntrinsicSizeInput& aInput,
|
||||
// margin-box inline size as the contribution in the inline axis.
|
||||
const IntrinsicSizeOffsetData offset =
|
||||
InnerTableFrame()->IntrinsicISizeOffsets();
|
||||
const nscoord innerTableMinISize = InnerTableFrame()->GetMinISize(input) +
|
||||
offset.BorderPadding() + offset.margin;
|
||||
const nscoord innerTableMinISize =
|
||||
InnerTableFrame()->GetMinISize(input) + offset.MarginBorderPadding();
|
||||
iSize = std::max(iSize, innerTableMinISize);
|
||||
}
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
[aspect-ratio-intrinsic-size-001.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[aspect-ratio-intrinsic-size-002.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[aspect-ratio-intrinsic-size-003.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[aspect-ratio-intrinsic-size-004.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[aspect-ratio-intrinsic-size-005.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[aspect-ratio-intrinsic-size-006.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[flexbox-min-width-auto-005.html]
|
||||
expected: FAIL
|
@ -1,2 +0,0 @@
|
||||
[flexbox-min-width-auto-006.html]
|
||||
expected: FAIL
|
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-stretch">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes">
|
||||
<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
|
||||
<meta name="assert" content="This checks that a flex item with an aspect-ratio transfers its size when it also has stretch alignment.">
|
||||
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div style="display: inline-flex; height: 100px; background: green;">
|
||||
<div style="padding: 3px; border: 7px solid green; margin: 10px;
|
||||
aspect-ratio: 1/1;"></div>
|
||||
</div>
|
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#valdef-align-items-stretch">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes">
|
||||
<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
|
||||
<meta name="assert" content="This checks that a flex item with an aspect-ratio transfers its size when it also has stretch alignment.">
|
||||
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div style="display: inline-flex; height: 100px; background: green;">
|
||||
<div style="padding: 3px; border: 7px solid green; margin: 10px;
|
||||
aspect-ratio: 1/1; writing-mode: vertical-rl;"></div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user