Bug 1739260 - Force to advance next band if we cannot get a suitable float available space. r=dholbert

Without this patch, the test case, floats-aspect-ratio-001.html, hangs because:

1. The initial float available space is correct, and its size is 100px x 50px.
   And the bfc element is "width: auto; height: auto; aspect-ratio: 1/1;".
   So its width and height depend on the available space.

2. And then, we try to get a new available area based on the height of
   the bfc element (note: its size is 100px x 100px). However, we get an
   invalid zero-width float available area which is occupied by the element
   with float:right (i.e. the pink one), in the first band, and the size of
   float available space is 0px x 100px. This makes the size of bfc element
   become 0px x 0px when checking `FloatAvoidingBlockFitsInAvailSpace()`.
   So it always fits in this float available area. And because we get two
   different available areas in the first band (i.e. same `aBCoord`), so we
   don't go into the break condition, and contine to get a new
   `childReflowInput`, and then go to the next iteration.

3. In the 2nd loop, we try to get a new float available space by the
   height of the bfc element (note: its size is 0px x 0px now because
   the width of current float available space is 0px), so the
   new float available space is 100px x 0px, and the bfc element fits in
   this available area, but again, we have two different available
   areas, so we still don't go into the break condition. Instead, we use
   the new available area to compute the childReflowInput for the next
   iteration, and now the size of the bfc element becomes 100px x 100px.
   And then we go back to the state of (2).

4. So the bfc element enters a resize oscillation due to the invalid
   float available space together with the aspect-ratio and auto sizes
   (i.e. "widht: auto; height: auto;") I think. And the invalid float
   available space also let |AvailableSpaceShrunk()| be unexpected because
   we hit an assertion: "ASSERTION: available space should not grow on the
   start side and shrink on the end side".

A possible way is to make sure we get a suitable float available area for
`floatAvoidingBlock`, so this can avoid the bfc element from entering
a resize oscillation.

Note:
1. bfc means block-formatting-context, and its variable name is
   `floatAvoidingBlock` in nsBlockFrame.cpp.
2. We don't need to check zere or positive inline size for the float
   available space because `AvailableSpaceShrunk()` should make sure we
   leave the loop properly.
   See https://phabricator.services.mozilla.com/D145524#4766290 for the
   the example when the inline size is exactly zero.

Besides, we also fix contain-inline-size-bfc-floats-001.html with this
patch.

Differential Revision: https://phabricator.services.mozilla.com/D145524
This commit is contained in:
Boris Chiou 2022-05-19 20:48:42 +00:00
Родитель 74d28327be
Коммит 1f362db13a
7 изменённых файлов: 52 добавлений и 3 удалений

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

@ -274,6 +274,15 @@ bool BlockReflowState::FloatAvoidingBlockFitsInAvailSpace(
// somewhat expensive.
return true;
}
// |aFloatAvailableSpace| was computed as having a negative size, which means
// there are floats on both sides pushing inwards past each other, and
// |aFloatAvoidingBlock| would necessarily intersect a float if we put it
// here. So, it doesn't fit.
if (aFloatAvailableSpace.ISizeIsActuallyNegative()) {
return false;
}
WritingMode wm = mReflowInput.GetWritingMode();
nsBlockFrame::FloatAvoidingISizeToClear replacedISize =
nsBlockFrame::ISizeToClearPastFloats(*this, aFloatAvailableSpace.mRect,

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

@ -108,6 +108,14 @@ class BlockReflowState {
*
* Returns whether there are floats present at the given block-direction
* coordinate and within the inline size of the content rect.
*
* Note: some codepaths clamp this structure's inline-size to be >=0 "for
* compatibility with nsSpaceManager". So if you encounter a nsFlowAreaRect
* which appears to have an ISize of 0, you can't necessarily assume that a
* 0-ISize float-avoiding block would actually fit; you need to check the
* InitialISizeIsNegative flag to see whether that 0 is actually a clamped
* negative value (in which case a 0-ISize float-avoiding block *should not*
* be considered as fitting, because it would intersect some float).
*/
nsFlowAreaRect GetFloatAvailableSpace() const {
return GetFloatAvailableSpace(mBCoord);

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

@ -250,6 +250,14 @@ nsFlowAreaRect nsFloatManager::GetFlowArea(
(haveFloats ? nsFlowAreaRectFlags::HasFloats
: nsFlowAreaRectFlags::NoFlags) |
(mayWiden ? nsFlowAreaRectFlags::MayWiden : nsFlowAreaRectFlags::NoFlags);
// Some callers clamp the inline size of nsFlowAreaRect to be nonnegative
// "for compatibility with nsSpaceManager". So, we set a flag here to record
// the fact that the ISize is actually negative, so that downstream code can
// realize that there's no place here where we could put a float-avoiding
// block (even one with ISize of 0).
if (lineRight - lineLeft < 0) {
flags |= nsFlowAreaRectFlags::ISizeIsActuallyNegative;
}
return nsFlowAreaRect(aWM, inlineStart, blockStart - mBlockStart,
lineRight - lineLeft, blockSize, flags);

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

@ -29,7 +29,8 @@ class PresShell;
enum class nsFlowAreaRectFlags : uint32_t {
NoFlags = 0,
HasFloats = 1 << 0,
MayWiden = 1 << 1
MayWiden = 1 << 1,
ISizeIsActuallyNegative = 1 << 2,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsFlowAreaRectFlags)
@ -59,6 +60,9 @@ struct nsFlowAreaRect {
bool MayWiden() const {
return (bool)(mAreaFlags & nsFlowAreaRectFlags::MayWiden);
}
bool ISizeIsActuallyNegative() const {
return (bool)(mAreaFlags & nsFlowAreaRectFlags::ISizeIsActuallyNegative);
}
};
#define NS_FLOAT_MANAGER_CACHE_SIZE 64

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

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

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

@ -0,0 +1,9 @@
<!DOCTYPE html>
<title>CSS aspect-ratio reference: block formatting context with floats</title>
<div style="width: 200px; border: solid 1px; display: flow-root;">
<div style="float: left; width: 50px; height: 50px; background: lime;"></div>
<div style="float: right; width: 50px; height: 50px; background: hotpink;"></div>
<div style="float: left; width: 160px; height: 50px; background: aqua;"></div>
<div style="float: right; width: 40px; height: 40px; background: orange;"></div>
</div>

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

@ -0,0 +1,13 @@
<!DOCTYPE html>
<title>CSS aspect-ratio: block formatting context with floats</title>
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
<link rel="match" href="floats-aspect-ratio-001-ref.html" />
<div style="width: 200px; border: solid 1px; display: flow-root;">
<div style="float: left; width: 50px; height: 50px; background: lime;"></div>
<div style="float: right; width: 50px; height: 50px; background: hotpink;"></div>
<div style="float: left; width: 160px; height: 50px; background: aqua;"></div>
<div style="aspect-ratio: 1/1; background: orange; display: flow-root;"></div>
</div>