mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1005660: Add an "early freeze" step, to freeze flex items that clearly can't grow (or shrink, if we're shrinking). r=mats
This commit is contained in:
parent
1b7d4536c1
commit
de1b127bc9
@ -523,7 +523,7 @@ test-pref(layout.css.sticky.enabled,true) load 914891.html
|
||||
test-pref(layout.css.sticky.enabled,true) load 915475.xhtml
|
||||
load 927558.html
|
||||
load 943509-1.html
|
||||
asserts(4-8) load 944909-1.html
|
||||
asserts(3-6) load 944909-1.html
|
||||
test-pref(layout.css.sticky.enabled,true) load 949932.html
|
||||
load 973701-1.xhtml
|
||||
load 973701-2.xhtml
|
||||
|
@ -458,8 +458,9 @@ public:
|
||||
// Setters
|
||||
// =======
|
||||
|
||||
// This sets our flex base size, and then updates the main size to the
|
||||
// base size clamped to our main-axis [min,max] constraints.
|
||||
// This sets our flex base size, and then sets our main size to the
|
||||
// resulting "hypothetical main size" (the base size clamped to our
|
||||
// main-axis [min,max] sizing constraints).
|
||||
void SetFlexBaseSizeAndMainSize(nscoord aNewFlexBaseSize)
|
||||
{
|
||||
MOZ_ASSERT(!mIsFrozen || mFlexBaseSize == NS_INTRINSICSIZE,
|
||||
@ -723,7 +724,9 @@ public:
|
||||
friend class AutoFlexLineListClearer; // (needs access to mItems)
|
||||
|
||||
private:
|
||||
// Helper for ResolveFlexibleLengths():
|
||||
// Helpers for ResolveFlexibleLengths():
|
||||
void FreezeItemsEarly(bool aIsUsingFlexGrow);
|
||||
|
||||
void FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
|
||||
bool aIsFinalIteration);
|
||||
|
||||
@ -1592,6 +1595,56 @@ nsFlexContainerFrame::SanityCheckAnonymousFlexItems() const
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow)
|
||||
{
|
||||
// After we've established the type of flexing we're doing (growing vs.
|
||||
// shrinking), and before we try to flex any items, we freeze items that
|
||||
// obviously *can't* flex.
|
||||
//
|
||||
// Quoting the spec:
|
||||
// # Freeze, setting its target main size to its hypothetical main size...
|
||||
// # - any item that has a flex factor of zero
|
||||
// # - if using the flex grow factor: any item that has a flex base size
|
||||
// # greater than its hypothetical main size
|
||||
// # - if using the flex shrink factor: any item that has a flex base size
|
||||
// # smaller than its hypothetical main size
|
||||
// http://dev.w3.org/csswg/css-flexbox/#resolve-flexible-lengths-flex-factors
|
||||
//
|
||||
// (NOTE: At this point, item->GetMainSize() *is* the item's hypothetical
|
||||
// main size, since SetFlexBaseSizeAndMainSize() sets it up that way, and the
|
||||
// item hasn't had a chance to flex away from that yet.)
|
||||
|
||||
// Since this loop only operates on unfrozen flex items, we can break as
|
||||
// soon as we have seen all of them.
|
||||
uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
|
||||
for (FlexItem* item = mItems.getFirst();
|
||||
numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
|
||||
MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
|
||||
|
||||
if (!item->IsFrozen()) {
|
||||
numUnfrozenItemsToBeSeen--;
|
||||
bool shouldFreeze = (0.0f == item->GetFlexFactor(aIsUsingFlexGrow));
|
||||
if (!shouldFreeze) {
|
||||
if (aIsUsingFlexGrow) {
|
||||
if (item->GetFlexBaseSize() > item->GetMainSize()) {
|
||||
shouldFreeze = true;
|
||||
}
|
||||
} else { // using flex-shrink
|
||||
if (item->GetFlexBaseSize() < item->GetMainSize()) {
|
||||
shouldFreeze = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldFreeze) {
|
||||
// Freeze item! (at its hypothetical main size)
|
||||
item->Freeze();
|
||||
mNumFrozenItems++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Based on the sign of aTotalViolation, this function freezes a subset of our
|
||||
// flexible sizes, and restores the remaining ones to their initial pref sizes.
|
||||
void
|
||||
@ -1656,11 +1709,19 @@ void
|
||||
FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize)
|
||||
{
|
||||
PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG, ("ResolveFlexibleLengths\n"));
|
||||
|
||||
// Determine whether we're going to be growing or shrinking items.
|
||||
const bool isUsingFlexGrow =
|
||||
(mTotalOuterHypotheticalMainSize < aFlexContainerMainSize);
|
||||
|
||||
// Do an "early freeze" for flex items that obviously can't flex in the
|
||||
// direction we've chosen:
|
||||
FreezeItemsEarly(isUsingFlexGrow);
|
||||
|
||||
if (mNumFrozenItems == mNumItems) {
|
||||
// All our items are frozen, so we have no flexible lengths to resolve.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsEmpty(), "empty lines should take the early-return above");
|
||||
|
||||
// Subtract space occupied by our items' margins/borders/padding, so we can
|
||||
@ -1672,10 +1733,6 @@ FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize)
|
||||
nscoord spaceAvailableForFlexItemsContentBoxes =
|
||||
aFlexContainerMainSize - spaceReservedForMarginBorderPadding;
|
||||
|
||||
// Determine whether we're going to be growing or shrinking items.
|
||||
const bool isUsingFlexGrow =
|
||||
(mTotalOuterHypotheticalMainSize < aFlexContainerMainSize);
|
||||
|
||||
nscoord origAvailableFreeSpace;
|
||||
bool isOrigAvailFreeSpaceInitialized = false;
|
||||
|
||||
@ -1704,6 +1761,9 @@ FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize)
|
||||
|
||||
// If sign of free space matches the type of flexing that we're doing, give
|
||||
// each flexible item a portion of availableFreeSpace.
|
||||
// XXXdholbert I think FreezeItemsThatAreObviouslyClamped might remove
|
||||
// the need for this check. We can just check if availableFreeSpace is
|
||||
// nonzero, and initialize origAvailableFreeSpace before we do that.
|
||||
if ((availableFreeSpace > 0 && isUsingFlexGrow) ||
|
||||
(availableFreeSpace < 0 && !isUsingFlexGrow)) {
|
||||
|
||||
|
@ -893,17 +893,19 @@ var gFlexboxTestcases =
|
||||
]
|
||||
},
|
||||
// ...and now with a max-size smaller than our flex-basis:
|
||||
// (This makes us freeze the second item right away, before we compute
|
||||
// the initial free space.)
|
||||
{
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0.4 70px",
|
||||
"_main-size": [ null, "110px" ] // +40% of free space
|
||||
"_main-size": [ null, "118px" ] // +40% of 200px-70px-10px
|
||||
},
|
||||
{
|
||||
"flex": "0.2 30px",
|
||||
"_max-main-size": "10px",
|
||||
"_main-size": [ null, "10px" ] // +20% free space, then clamped
|
||||
"_main-size": [ null, "10px" ] // immediately frozen
|
||||
},
|
||||
]
|
||||
},
|
||||
@ -1006,21 +1008,20 @@ var gFlexboxTestcases =
|
||||
]
|
||||
},
|
||||
|
||||
// XXXdholbert The algorithm we're currently using has an unfortunate
|
||||
// discontinuity between the following two cases, as described in bug 985304
|
||||
// comment 28, due to when we determine the "original free space". We could
|
||||
// fix this by always determining "original free space" up-front, but that
|
||||
// causes other discontinuities. I'm waiting until the discussion sorts out a
|
||||
// bit on www-style before deciding how to resolve this.
|
||||
// Make sure we calculate "original free space" correctly when one of our
|
||||
// flex items will be clamped right away, due to max-size preventing it from
|
||||
// growing at all:
|
||||
{
|
||||
// First example:
|
||||
// Here, we have an "original free space" of 2px, so our first item ends up
|
||||
// getting 0.5 * 2px = 1px.
|
||||
// Here, the second flex item is effectively inflexible; it's
|
||||
// immediately frozen at 40px since we're growing & this item's max size
|
||||
// trivially prevents it from growing. This leaves us with an "original
|
||||
// free space" of 60px. The first flex item takes half of that, due to
|
||||
// its flex-grow value of 0.5.
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0.5 100px",
|
||||
"_main-size": [ null, "101px" ]
|
||||
"_main-size": [ null, "130px" ]
|
||||
},
|
||||
{
|
||||
"flex": "1 98px",
|
||||
@ -1030,12 +1031,9 @@ var gFlexboxTestcases =
|
||||
]
|
||||
},
|
||||
{
|
||||
// Second example (with 2nd flex item having 3px larger flex-basis):
|
||||
// Here, our "original free space" is negative, but we're using flex-grow
|
||||
// based on the sum of the items' hypothetical main sizes -- so we wait to
|
||||
// establish the "original free space" until after we've frozen the second
|
||||
// item. At that point, we have 60px free space. So our first item ends up
|
||||
// getting 0.5 * 60px = 30px.
|
||||
// Same as previous example, but with a larger flex-basis on the second
|
||||
// element (which shouldn't ultimately matter, because its max size clamps
|
||||
// its size immediately anyway).
|
||||
items:
|
||||
[
|
||||
{
|
||||
@ -1050,25 +1048,21 @@ var gFlexboxTestcases =
|
||||
]
|
||||
},
|
||||
|
||||
// XXXdholbert Here's another pair of testcases where we have another
|
||||
// discontinuity, mentioned at the end of bug 985304 comment 28. Here, the
|
||||
// "original free space" is small, and then a flex item gets clamped, making
|
||||
// more free space available. If our flex items' sum is < 1, then this new
|
||||
// free space won't be distributed (since it's not part of the *original* free
|
||||
// space). But if we tweak a flex-grow value to push the sum over 1, then
|
||||
// suddenly this extra free space *will* be distributed. Hence, discontinuity.
|
||||
{
|
||||
// First example: flex items' sum is 0.9 (just under 1)
|
||||
// We only distribute shares of the "original free space", which is 10px.
|
||||
// Here, the third flex item is effectively inflexible; it's immediately
|
||||
// frozen at 0px since we're growing & this item's max size trivially
|
||||
// prevents it from growing. This leaves us with an "original free space" of
|
||||
// 100px. The first flex item takes 40px, and the third takes 50px, due to
|
||||
// their flex values of 0.4 and 0.5.
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0.4 50px",
|
||||
"_main-size": [ null, "54px" ]
|
||||
"_main-size": [ null, "90px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0.5 50px",
|
||||
"_main-size": [ null, "55px" ]
|
||||
"_main-size": [ null, "100px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 90px",
|
||||
@ -1078,11 +1072,10 @@ var gFlexboxTestcases =
|
||||
]
|
||||
},
|
||||
{
|
||||
// Second example: flex items' sum is exactly 1.0
|
||||
// We distribute all of the current free space, in each loop of the
|
||||
// algorithm. (In particular, after we've clamped the third item & freed up
|
||||
// some more space.) So, the first and second item end up substantially
|
||||
// larger than in the previous example.
|
||||
// Same as previous example, but with slightly larger flex-grow values on
|
||||
// the first and second items, which sum to 1.0 and produce slightly larger
|
||||
// main sizes. This demonstrates that there's no discontinuity between the
|
||||
// "< 1.0 sum" to ">= 1.0 sum" behavior, in this situation at least.
|
||||
items:
|
||||
[
|
||||
{
|
||||
@ -1202,17 +1195,19 @@ var gFlexboxTestcases =
|
||||
},
|
||||
|
||||
// ...now with min-size larger than our flex-basis:
|
||||
// (This makes us freeze the second item right away, before we compute
|
||||
// the initial free space.)
|
||||
{
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0 0.3 100px",
|
||||
"_main-size": [ null, "70px" ]
|
||||
"_main-size": [ null, "55px" ] // +30% of 200px-100px-250px
|
||||
},
|
||||
{
|
||||
"flex": "0 0.1 200px",
|
||||
"_min-main-size": "250px",
|
||||
"_main-size": [ null, "250px" ]
|
||||
"_main-size": [ null, "250px" ] // immediately frozen
|
||||
}
|
||||
]
|
||||
// (Same as previous example, except the min-main-size prevents the
|
||||
@ -1310,11 +1305,11 @@ var gFlexboxTestcases =
|
||||
[
|
||||
{
|
||||
"flex": "0 0.3 100px",
|
||||
"_main-size": [ null, "84px" ]
|
||||
"_main-size": [ null, "76px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 0.1 150px",
|
||||
"_main-size": [ null, "142px" ]
|
||||
"_main-size": [ null, "138px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 0.8 10px",
|
||||
@ -1323,60 +1318,81 @@ var gFlexboxTestcases =
|
||||
}
|
||||
]
|
||||
// Notes:
|
||||
// - For the first round of flexing, we shrink everything and trivially
|
||||
// violate the third items' min-size. So we freeze it and restart.
|
||||
// We also establish a "original free space" of -60px.
|
||||
// - We immediately freeze the 3rd item, since we're shrinking and its
|
||||
// min size obviously prevents it from shrinking at all. This leaves
|
||||
// 200px - 100px - 150px - 40px = -90px of "initial free space".
|
||||
//
|
||||
// - For the second round, we have -40px of free space, and a total
|
||||
// flex-shrink of 0.4, and -60px *original* free space.
|
||||
// So our remaining items will collectively shrink by
|
||||
// 0.4 * -60px = -24px.
|
||||
// - Our remaining flexible items have a total flex-shrink of 0.4,
|
||||
// so we can distribute a total of 0.4 * -90px = -36px
|
||||
//
|
||||
// - 1st item's scaled flex factor: 0.3 * 100px = 30
|
||||
// - 2nd item's scaled flex factor: 0.1 * 150px = 15
|
||||
//
|
||||
// - 1st item's share of distributed free space: 30/(30+15) = 2/3
|
||||
// - 2nd item's share of distributed free space: 15/(30+15) = 1/3
|
||||
// - We distribute that space using *scaled* flex factors:
|
||||
// * 1st item's scaled flex factor: 0.3 * 100px = 30
|
||||
// * 2nd item's scaled flex factor: 0.1 * 150px = 15
|
||||
// ...which means...
|
||||
// * 1st item's share of distributed free space: 30/(30+15) = 2/3
|
||||
// * 2nd item's share of distributed free space: 15/(30+15) = 1/3
|
||||
//
|
||||
// SO:
|
||||
// - 1st item gets 2/3 * -24px = -16px. 100px - 16px = 84px
|
||||
// - 2nd item gets 1/3 * -24px = -8px. 150px - 8px = 142px
|
||||
// - 1st item gets 2/3 * -36px = -24px. 100px - 24px = 76px
|
||||
// - 2nd item gets 1/3 * -36px = -12px. 150px - 12px = 138px
|
||||
},
|
||||
|
||||
// In this case, the items' flexibilities sum to > 1, in part due to an item
|
||||
// that *can't actually shrink* due to its 0 flex-basis (which gives it a
|
||||
// "scaled flex factor" of 0). So that item can't shrink, but it does prevent
|
||||
// the others from getting the "flex-shrink sum less than 1" code-path.
|
||||
// "scaled flex factor" of 0). This prevents us from triggering the special
|
||||
// behavior for flexibilities that sum to less than 1, and as a result, the
|
||||
// first item ends up absorbing all of the free space.
|
||||
{
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0 .3 150px",
|
||||
"_main-size": [ null, "90px" ]
|
||||
"flex": "0 .5 300px",
|
||||
"_main-size": [ null, "200px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 .2 150px",
|
||||
"_main-size": [ null, "110px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 2 0px",
|
||||
"flex": "0 5 0px",
|
||||
"_main-size": [ null, "0px" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
// For comparison, the above testcase should behave just like this one with
|
||||
// all >1 flex-shrink values (it shouldn't trigger any special <1 behavior):
|
||||
|
||||
// This case is similar to the one above, but with a *barely* nonzero base
|
||||
// size for the second item. This should produce a result similar to the case
|
||||
// above. (In particular, we should first distribute a very small amount of
|
||||
// negative free space to the second item, getting it to approximately zero,
|
||||
// and distribute the bulk of the negative free space to the first item,
|
||||
// getting it to approximately 200px.)
|
||||
{
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0 3 150px",
|
||||
"_main-size": [ null, "90px" ]
|
||||
"flex": "0 .5 300px",
|
||||
"_main-size": [ null, "200px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 2 150px",
|
||||
"_main-size": [ null, "110px" ]
|
||||
},
|
||||
]
|
||||
"flex": "0 1 0.01px",
|
||||
"_main-size": [ null, "0px" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
// This case is similar to the ones above, but now we've increased the
|
||||
// flex-shrink value on the second-item so that it claims enough of the
|
||||
// negative free space to go below its min-size (0px). So, it triggers a min
|
||||
// violation & is frozen. For the loop *after* the min violation, the sum of
|
||||
// the remaining flex items' flex-shrink values is less than 1, so we trigger
|
||||
// the special <1 behavior and only distribute half of the remaining
|
||||
// (negative) free space to the first item (instead of all of it).
|
||||
{
|
||||
items:
|
||||
[
|
||||
{
|
||||
"flex": "0 .5 300px",
|
||||
"_main-size": [ null, "250px" ]
|
||||
},
|
||||
{
|
||||
"flex": "0 5 0.01px",
|
||||
"_main-size": [ null, "0px" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user