Bug 1425599 part 1 - [css-grid] Change the track sizing algorithm for spanning items so that it accumulates individual item contributions to the plan by max() rather than incrementing the planned size directly. r=dholbert

Also, fix a bug when copying back the planned limits after
updating it for the first span group.  It should only copy
back track sizes that were actaully spanned by those items,
other content-sized tracks' limits should remain at "infinity".
This commit is contained in:
Mats Palmgren 2018-03-15 22:41:23 +01:00
Родитель cd3d3ade3d
Коммит c8fd367dc3
1 изменённых файлов: 105 добавлений и 48 удалений

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

@ -195,7 +195,7 @@ struct nsGridContainerFrame::TrackSize
eMaxContentMinSizing = 0x4,
eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
// 0x8 is unused, feel free to take it!
eModified = 0x8,
eAutoMaxSizing = 0x10,
eMinContentMaxSizing = 0x20,
eMaxContentMaxSizing = 0x40,
@ -1192,30 +1192,41 @@ struct nsGridContainerFrame::Tracks
return aGrowableTracks.IsEmpty() ? 0 : space;
}
void SetupGrowthPlan(nsTArray<TrackSize>& aPlan,
const nsTArray<uint32_t>& aTracks) const
void SetupGrowthPlan(nsTArray<TrackSize>& aItemPlan,
const nsTArray<TrackSize>& aSizes,
const nsTArray<uint32_t>& aTracks) const
{
for (uint32_t track : aTracks) {
aPlan[track] = mSizes[track];
auto& sz = aItemPlan[track];
sz.mBase = aSizes[track].mBase;
sz.mLimit = aSizes[track].mLimit;
sz.mState = aSizes[track].mState;
}
}
void CopyPlanToBase(const nsTArray<TrackSize>& aPlan,
const nsTArray<uint32_t>& aTracks)
void ResetBasePlan(nsTArray<TrackSize>& aPlan,
const nsTArray<TrackSize>& aSizes) const
{
for (uint32_t track : aTracks) {
MOZ_ASSERT(mSizes[track].mBase <= aPlan[track].mBase);
mSizes[track].mBase = aPlan[track].mBase;
for (size_t i = 0, len = mSizes.Length(); i < len; ++i) {
aPlan[i].mBase = aSizes[i].mBase;
aPlan[i].mState = aSizes[i].mState;
}
}
void CopyPlanToLimit(const nsTArray<TrackSize>& aPlan,
const nsTArray<uint32_t>& aTracks)
void CopyPlanToBase(const nsTArray<TrackSize>& aPlan)
{
for (uint32_t track : aTracks) {
MOZ_ASSERT(mSizes[track].mLimit == NS_UNCONSTRAINEDSIZE ||
mSizes[track].mLimit <= aPlan[track].mBase);
mSizes[track].mLimit = aPlan[track].mBase;
for (size_t i = 0, len = mSizes.Length(); i < len; ++i) {
mSizes[i].mBase = aPlan[i].mBase;
}
}
void CopyPlanToLimit(const nsTArray<TrackSize>& aPlan)
{
for (size_t i = 0, len = mSizes.Length(); i < len; ++i) {
MOZ_ASSERT(aPlan[i].mBase >= 0);
if (aPlan[i].mState & TrackSize::eModified) {
mSizes[i].mLimit = aPlan[i].mBase;
}
}
}
@ -1386,22 +1397,31 @@ struct nsGridContainerFrame::Tracks
*/
void DistributeToTrackBases(nscoord aAvailableSpace,
nsTArray<TrackSize>& aPlan,
nsTArray<TrackSize>& aItemPlan,
nsTArray<uint32_t>& aGrowableTracks,
TrackSize::StateBits aSelector)
{
SetupGrowthPlan(aPlan, aGrowableTracks);
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks, nullptr);
SetupGrowthPlan(aItemPlan, mSizes, aGrowableTracks);
nscoord space = GrowTracksToLimit(aAvailableSpace, aItemPlan, aGrowableTracks, nullptr);
if (space > 0) {
GrowSelectedTracksUnlimited(space, aPlan, aGrowableTracks, aSelector, nullptr);
GrowSelectedTracksUnlimited(space, aItemPlan, aGrowableTracks, aSelector, nullptr);
}
for (uint32_t track : aGrowableTracks) {
nscoord& plannedSize = aPlan[track].mBase;
nscoord itemIncurredSize = aItemPlan[track].mBase;
if (plannedSize < itemIncurredSize) {
plannedSize = itemIncurredSize;
}
}
CopyPlanToBase(aPlan, aGrowableTracks);
}
/**
* Distribute aAvailableSpace to the planned limits for aGrowableTracks.
*/
void DistributeToTrackLimits(nscoord aAvailableSpace,
const nsTArray<TrackSize>& aSizes,
nsTArray<TrackSize>& aPlan,
nsTArray<TrackSize>& aItemPlan,
nsTArray<uint32_t>& aGrowableTracks,
const TrackSizingFunctions& aFunctions,
nscoord aPercentageBasis)
@ -1417,13 +1437,20 @@ struct nsGridContainerFrame::Tracks
}
return false;
};
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks,
SetupGrowthPlan(aItemPlan, aSizes, aGrowableTracks);
nscoord space = GrowTracksToLimit(aAvailableSpace, aItemPlan, aGrowableTracks,
fitContentClamper);
if (space > 0) {
GrowSelectedTracksUnlimited(aAvailableSpace, aPlan, aGrowableTracks,
GrowSelectedTracksUnlimited(space, aItemPlan, aGrowableTracks,
TrackSize::StateBits(0), fitContentClamper);
}
CopyPlanToLimit(aPlan, aGrowableTracks);
for (uint32_t track : aGrowableTracks) {
nscoord& plannedSize = aPlan[track].mBase;
nscoord itemIncurredSize = aItemPlan[track].mBase;
if (plannedSize < itemIncurredSize) {
plannedSize = itemIncurredSize;
}
}
}
/**
@ -4277,6 +4304,8 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
nsTArray<uint32_t> tracks(maxSpan);
nsTArray<TrackSize> plan(mSizes.Length());
plan.SetLength(mSizes.Length());
nsTArray<TrackSize> itemPlan(mSizes.Length());
itemPlan.SetLength(mSizes.Length());
for (uint32_t i = 0, len = step2Items.Length(); i < len; ) {
// Start / end index for items of the same span length:
const uint32_t spanGroupStartIndex = i;
@ -4293,6 +4322,7 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
TrackSize::StateBits selector(TrackSize::eIntrinsicMinSizing);
if (stateBitsPerSpan[span] & selector) {
// Step 2.1 MinSize to intrinsic min-sizing.
ResetBasePlan(plan, mSizes);
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
Step2ItemData& item = step2Items[i];
if (!(item.mState & selector)) {
@ -4306,16 +4336,20 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
space = CollectGrowable(space, mSizes, item.mLineRange, selector,
tracks);
if (space > 0) {
DistributeToTrackBases(space, plan, tracks, selector);
DistributeToTrackBases(space, plan, itemPlan, tracks, selector);
updatedBase = true;
}
}
if (updatedBase) {
CopyPlanToBase(plan);
}
}
selector = contentBasedMinSelector;
if (stateBitsPerSpan[span] & selector) {
// Step 2.2 MinContentContribution to min-/max-content (and 'auto' when
// sizing under a min-content constraint) min-sizing.
ResetBasePlan(plan, mSizes);
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
Step2ItemData& item = step2Items[i];
if (!(item.mState & selector)) {
@ -4329,16 +4363,20 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
space = CollectGrowable(space, mSizes, item.mLineRange, selector,
tracks);
if (space > 0) {
DistributeToTrackBases(space, plan, tracks, selector);
DistributeToTrackBases(space, plan, itemPlan, tracks, selector);
updatedBase = true;
}
}
if (updatedBase) {
CopyPlanToBase(plan);
}
}
selector = maxContentMinSelector;
if (stateBitsPerSpan[span] & selector) {
// Step 2.3 MaxContentContribution to max-content (and 'auto' when
// sizing under a max-content constraint) min-sizing.
ResetBasePlan(plan, mSizes);
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
Step2ItemData& item = step2Items[i];
if (!(item.mState & selector)) {
@ -4352,10 +4390,13 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
space = CollectGrowable(space, mSizes, item.mLineRange, selector,
tracks);
if (space > 0) {
DistributeToTrackBases(space, plan, tracks, selector);
DistributeToTrackBases(space, plan, itemPlan, tracks, selector);
updatedBase = true;
}
}
if (updatedBase) {
CopyPlanToBase(plan);
}
}
if (updatedBase) {
@ -4366,9 +4407,10 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
}
}
}
if (stateBitsPerSpan[span] & TrackSize::eIntrinsicMaxSizing) {
plan = mSizes;
for (TrackSize& sz : plan) {
nsTArray<TrackSize> limits(mSizes);
for (TrackSize& sz : limits) {
if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
// use mBase as the planned limit
} else {
@ -4377,53 +4419,65 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
}
// Step 2.5 MinSize to intrinsic max-sizing.
ResetBasePlan(plan, limits);
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
Step2ItemData& item = step2Items[i];
if (!(item.mState & TrackSize::eIntrinsicMaxSizing)) {
continue;
}
nscoord space = item.mMinSize;
if (space <= 0) {
continue;
for (auto j = item.mLineRange.mStart, end = item.mLineRange.mEnd; j < end; ++j) {
plan[j].mState |= TrackSize::eModified;
}
tracks.ClearAndRetainStorage();
space = CollectGrowable(space, plan, item.mLineRange,
TrackSize::eIntrinsicMaxSizing,
tracks);
nscoord space = item.mMinSize;
if (space > 0) {
DistributeToTrackLimits(space, plan, tracks, aFunctions,
aPercentageBasis);
tracks.ClearAndRetainStorage();
space = CollectGrowable(space, limits, item.mLineRange,
TrackSize::eIntrinsicMaxSizing,
tracks);
if (space > 0) {
DistributeToTrackLimits(space, limits, plan, itemPlan, tracks, aFunctions,
aPercentageBasis);
}
}
}
for (size_t j = 0, len = mSizes.Length(); j < len; ++j) {
TrackSize& sz = plan[j];
TrackSize& sz = itemPlan[j];
sz.mState &= ~(TrackSize::eFrozen | TrackSize::eSkipGrowUnlimited);
if (sz.mLimit != NS_UNCONSTRAINEDSIZE) {
sz.mLimit = sz.mBase; // collect the results from 2.5
if (plan[j].mState & TrackSize::eModified) {
limits[j].mBase = plan[j].mBase;
mSizes[j].mLimit = plan[j].mBase;
if (limits[j].mLimit != NS_UNCONSTRAINEDSIZE) {
limits[j].mLimit = limits[j].mBase;
}
}
plan[j].mState &= ~(TrackSize::eModified);
}
if (stateBitsPerSpan[span] & TrackSize::eAutoOrMaxContentMaxSizing) {
// Step 2.6 MaxContentContribution to max-content max-sizing.
ResetBasePlan(plan, limits);
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
Step2ItemData& item = step2Items[i];
if (!(item.mState & TrackSize::eAutoOrMaxContentMaxSizing)) {
continue;
}
for (auto j = item.mLineRange.mStart, end = item.mLineRange.mEnd; j < end; ++j) {
plan[j].mState |= TrackSize::eModified;
}
nscoord space = item.mMaxContentContribution;
if (space <= 0) {
continue;
}
tracks.ClearAndRetainStorage();
space = CollectGrowable(space, plan, item.mLineRange,
TrackSize::eAutoOrMaxContentMaxSizing,
tracks);
if (space > 0) {
DistributeToTrackLimits(space, plan, tracks, aFunctions,
aPercentageBasis);
tracks.ClearAndRetainStorage();
space = CollectGrowable(space, limits, item.mLineRange,
TrackSize::eAutoOrMaxContentMaxSizing,
tracks);
if (space > 0) {
DistributeToTrackLimits(space, limits, plan, itemPlan, tracks, aFunctions,
aPercentageBasis);
}
}
}
}
CopyPlanToLimit(plan);
}
}
}
@ -6944,6 +6998,9 @@ nsGridContainerFrame::TrackSize::Dump() const
if (mState & eFrozen) {
printf("frozen ");
}
if (mState & eModified) {
printf("modified ");
}
if (mState & eBreakBefore) {
printf("break-before ");
}