Bug 1781097 - Obey contain-intrinsic-size in block containers. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D152666
This commit is contained in:
Oriol Brufau 2022-07-25 16:40:07 +00:00
Родитель 90013f044d
Коммит 90681da9ee
20 изменённых файлов: 112 добавлений и 119 удалений

Просмотреть файл

@ -788,8 +788,8 @@ nscoord nsBlockFrame::GetMinISize(gfxContext* aRenderingContext) {
return mCachedMinISize;
}
if (StyleDisplay()->GetContainSizeAxes().mIContained) {
mCachedMinISize = 0;
if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
mCachedMinISize = *containISize;
return mCachedMinISize;
}
@ -878,8 +878,8 @@ nscoord nsBlockFrame::GetPrefISize(gfxContext* aRenderingContext) {
return mCachedPrefISize;
}
if (StyleDisplay()->GetContainSizeAxes().mIContained) {
mCachedPrefISize = 0;
if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
mCachedPrefISize = *containISize;
return mCachedPrefISize;
}
@ -1935,80 +1935,85 @@ void nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
// calculated from aspect-ratio. i.e. Don't carry out block margin-end if it
// is replaced by the block size from aspect-ratio and inline size.
aMetrics.mCarriedOutBEndMargin.Zero();
} else if (!IsComboboxControlFrame() &&
aReflowInput.mStyleDisplay->GetContainSizeAxes().mBContained) {
// If we're size-containing in block axis and we don't have a specified
// block size, then our final size should actually be computed from only our
// border and padding, as though we were empty. Hence this case is a
// simplified version of the case below.
//
// NOTE: We exempt the nsComboboxControlFrame subclass from taking this
// special case, because comboboxes implicitly honors the size-containment
// behavior on its nsComboboxDisplayFrame child (which it shrinkwraps)
// rather than on the nsComboboxControlFrame. (Moreover, the DisplayFrame
// child doesn't even need any special content-size-ignoring behavior in
// its reflow method, because that method just resolves "auto" BSize values
// to one line-height rather than by measuring its contents' BSize.)
nscoord contentBSize = 0;
nscoord autoBSize =
aReflowInput.ApplyMinMaxBSize(contentBSize, aState.mConsumedBSize);
aMetrics.mCarriedOutBEndMargin.Zero();
autoBSize += borderPadding.BStartEnd(wm);
finalSize.BSize(wm) = autoBSize;
} else if (aState.mReflowStatus.IsInlineBreakBefore()) {
// Our parent is expected to push this frame to the next page/column so what
// size we set here doesn't really matter.
finalSize.BSize(wm) = aReflowInput.AvailableBSize();
} else if (aState.mReflowStatus.IsComplete()) {
nscoord contentBSize = blockEndEdgeOfChildren - borderPadding.BStart(wm);
nscoord lineClampedContentBSize =
ApplyLineClamp(aReflowInput, this, contentBSize);
nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(lineClampedContentBSize,
aState.mConsumedBSize);
if (autoBSize != contentBSize) {
// Our min-block-size, max-block-size, or -webkit-line-clamp value made
// our bsize change. Don't carry out our kids' block-end margins.
aMetrics.mCarriedOutBEndMargin.Zero();
}
nscoord bSize = autoBSize + borderPadding.BStartEnd(wm);
if (MOZ_UNLIKELY(autoBSize > contentBSize &&
bSize > aReflowInput.AvailableBSize() &&
aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE)) {
// Applying `min-size` made us overflow our available size.
// Clamp it and report that we're Incomplete, or BreakBefore if we have
// 'break-inside: avoid' that is applicable.
bSize = aReflowInput.AvailableBSize();
if (ShouldAvoidBreakInside(aReflowInput)) {
aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
} else {
aState.mReflowStatus.SetIncomplete();
}
}
finalSize.BSize(wm) = bSize;
} else {
NS_ASSERTION(aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
"Shouldn't be incomplete if availableBSize is UNCONSTRAINED.");
nscoord bSize = std::max(aState.mBCoord, aReflowInput.AvailableBSize());
if (aReflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
// This should never happen, but it does. See bug 414255
bSize = aState.mBCoord;
}
const nscoord maxBSize = aReflowInput.ComputedMaxBSize();
if (maxBSize != NS_UNCONSTRAINEDSIZE &&
aState.mConsumedBSize + bSize - borderPadding.BStart(wm) > maxBSize) {
nscoord bEnd = std::max(0, maxBSize - aState.mConsumedBSize) +
borderPadding.BStart(wm);
// Note that |borderPadding| has GetSkipSides applied, so we ask
// aReflowInput for the actual value we'd use on a last fragment here:
bEnd += aReflowInput.ComputedLogicalBorderPadding(wm).BEnd(wm);
if (bEnd <= aReflowInput.AvailableBSize()) {
// We actually fit after applying `max-size` so we should be
// Overflow-Incomplete instead.
bSize = bEnd;
aState.mReflowStatus.SetOverflowIncomplete();
Maybe<nscoord> containBSize = ContainIntrinsicBSize();
if (!IsComboboxControlFrame() && containBSize) {
// If we're size-containing in block axis and we don't have a specified
// block size, then our final size should actually be computed from only
// our border, padding and contain-intrinsic-block-size, ignoring the
// actual contents. Hence this case is a simplified version of the case
// below.
//
// NOTE: We exempt the nsComboboxControlFrame subclass from taking this
// special case, because comboboxes implicitly honors the size-containment
// behavior on its nsComboboxDisplayFrame child (which it shrinkwraps)
// rather than on the nsComboboxControlFrame. (Moreover, the DisplayFrame
// child doesn't even need any special content-size-ignoring behavior in
// its reflow method, because that method just resolves "auto" BSize
// values to one line-height rather than by measuring its contents'
// BSize.)
nscoord contentBSize = *containBSize;
nscoord autoBSize =
aReflowInput.ApplyMinMaxBSize(contentBSize, aState.mConsumedBSize);
aMetrics.mCarriedOutBEndMargin.Zero();
autoBSize += borderPadding.BStartEnd(wm);
finalSize.BSize(wm) = autoBSize;
} else if (aState.mReflowStatus.IsInlineBreakBefore()) {
// Our parent is expected to push this frame to the next page/column so
// what size we set here doesn't really matter.
finalSize.BSize(wm) = aReflowInput.AvailableBSize();
} else if (aState.mReflowStatus.IsComplete()) {
nscoord contentBSize = blockEndEdgeOfChildren - borderPadding.BStart(wm);
nscoord lineClampedContentBSize =
ApplyLineClamp(aReflowInput, this, contentBSize);
nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(lineClampedContentBSize,
aState.mConsumedBSize);
if (autoBSize != contentBSize) {
// Our min-block-size, max-block-size, or -webkit-line-clamp value made
// our bsize change. Don't carry out our kids' block-end margins.
aMetrics.mCarriedOutBEndMargin.Zero();
}
nscoord bSize = autoBSize + borderPadding.BStartEnd(wm);
if (MOZ_UNLIKELY(autoBSize > contentBSize &&
bSize > aReflowInput.AvailableBSize() &&
aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE)) {
// Applying `min-size` made us overflow our available size.
// Clamp it and report that we're Incomplete, or BreakBefore if we have
// 'break-inside: avoid' that is applicable.
bSize = aReflowInput.AvailableBSize();
if (ShouldAvoidBreakInside(aReflowInput)) {
aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
} else {
aState.mReflowStatus.SetIncomplete();
}
}
finalSize.BSize(wm) = bSize;
} else {
NS_ASSERTION(
aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
"Shouldn't be incomplete if availableBSize is UNCONSTRAINED.");
nscoord bSize = std::max(aState.mBCoord, aReflowInput.AvailableBSize());
if (aReflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
// This should never happen, but it does. See bug 414255
bSize = aState.mBCoord;
}
const nscoord maxBSize = aReflowInput.ComputedMaxBSize();
if (maxBSize != NS_UNCONSTRAINEDSIZE &&
aState.mConsumedBSize + bSize - borderPadding.BStart(wm) > maxBSize) {
nscoord bEnd = std::max(0, maxBSize - aState.mConsumedBSize) +
borderPadding.BStart(wm);
// Note that |borderPadding| has GetSkipSides applied, so we ask
// aReflowInput for the actual value we'd use on a last fragment here:
bEnd += aReflowInput.ComputedLogicalBorderPadding(wm).BEnd(wm);
if (bEnd <= aReflowInput.AvailableBSize()) {
// We actually fit after applying `max-size` so we should be
// Overflow-Incomplete instead.
bSize = bEnd;
aState.mReflowStatus.SetOverflowIncomplete();
}
}
finalSize.BSize(wm) = bSize;
}
finalSize.BSize(wm) = bSize;
}
if (IsTrueOverflowContainer()) {

Просмотреть файл

@ -3977,6 +3977,14 @@ class nsIFrame : public nsQueryFrame {
}
}
Maybe<nscoord> ContainIntrinsicBSize() const {
return StyleDisplay()->GetContainSizeAxes().ContainIntrinsicBSize(*this);
}
Maybe<nscoord> ContainIntrinsicISize() const {
return StyleDisplay()->GetContainSizeAxes().ContainIntrinsicISize(*this);
}
protected:
// This does the actual work of UpdateStyleOfOwnedAnonBoxes. It calls
// AppendDirectlyOwnedAnonBoxes to find all of the anonymous boxes

Просмотреть файл

@ -3619,3 +3619,25 @@ IntrinsicSize ContainSizeAxes::ContainIntrinsicSize(
}
return result;
}
Maybe<nscoord> ContainSizeAxes::ContainIntrinsicBSize(
const nsIFrame& aFrame) const {
if (!mBContained) {
return Nothing();
}
const nsStylePosition* stylePos = aFrame.StylePosition();
return Some(Resolve(aFrame.GetWritingMode().IsVertical()
? stylePos->mContainIntrinsicWidth
: stylePos->mContainIntrinsicHeight));
}
Maybe<nscoord> ContainSizeAxes::ContainIntrinsicISize(
const nsIFrame& aFrame) const {
if (!mIContained) {
return Nothing();
}
const nsStylePosition* stylePos = aFrame.StylePosition();
return Some(Resolve(aFrame.GetWritingMode().IsVertical()
? stylePos->mContainIntrinsicHeight
: stylePos->mContainIntrinsicWidth));
}

Просмотреть файл

@ -90,6 +90,8 @@ struct ContainSizeAxes {
const nsIFrame& aFrame) const;
IntrinsicSize ContainIntrinsicSize(const IntrinsicSize& aUncontainedSize,
const nsIFrame& aFrame) const;
Maybe<nscoord> ContainIntrinsicBSize(const nsIFrame& aFrame) const;
Maybe<nscoord> ContainIntrinsicISize(const nsIFrame& aFrame) const;
const bool mIContained;
const bool mBContained;

Просмотреть файл

@ -1,3 +0,0 @@
[auto-004.html]
[contain-intrinsic-size: auto]
expected: FAIL

Просмотреть файл

@ -1,3 +0,0 @@
[auto-005.html]
[contain-intrinsic-size: auto]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-001.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-002.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-003.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-004.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-005.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-006.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-007.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-010.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-011.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-013.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-016.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-019.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[contain-intrinsic-size-021.html]
expected: FAIL

Просмотреть файл

@ -1,12 +0,0 @@
[contain-intrinsic-size-028.html]
[.test 3]
expected: FAIL
[.test 4]
expected: FAIL
[.test 6]
expected: FAIL
[.test 8]
expected: FAIL