Bug 1675376 - Cache consumed BSize in a frame property for non-first continuations. r=mats

This removes virtually all the time under ConsumedBSize. See the comment for
what ensures the correctness of the cache: Basically, we refresh the cache for
a frame continuation every time we reflow it, which means that when next
continuations go look for it it should be up-to-date (we rely on that already
because we're looking at the content rect).

Differential Revision: https://phabricator.services.mozilla.com/D97357
This commit is contained in:
Emilio Cobos Álvarez 2020-11-18 11:04:35 +00:00
Родитель 2892508f9b
Коммит cdff7e9fe1
6 изменённых файлов: 55 добавлений и 34 удалений

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

@ -1251,7 +1251,7 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
const ReflowInput* reflowInput = &aReflowInput;
WritingMode wm = aReflowInput.GetWritingMode();
nscoord consumedBSize = ConsumedBSize(wm);
nscoord consumedBSize = CalcAndCacheConsumedBSize(wm);
nscoord effectiveComputedBSize =
GetEffectiveComputedBSize(aReflowInput, consumedBSize);
Maybe<ReflowInput> mutableReflowInput;

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

@ -4100,7 +4100,8 @@ void nsFlexContainerFrame::GenerateFlexLines(const SharedFlexData& aData,
// reflow input (specifically, the main-size of *this continuation* of the
// flex container).
nscoord nsFlexContainerFrame::GetMainSizeFromReflowInput(
const ReflowInput& aReflowInput, const FlexboxAxisTracker& aAxisTracker) {
const ReflowInput& aReflowInput, const FlexboxAxisTracker& aAxisTracker,
nscoord aConsumedBSize) {
if (aAxisTracker.IsRowOriented()) {
// Row-oriented --> our main axis is the inline axis, so our main size
// is our inline size (which should already be resolved).
@ -4112,7 +4113,7 @@ nscoord nsFlexContainerFrame::GetMainSizeFromReflowInput(
}
// Note: This may be unconstrained, if our block size is "auto":
return GetEffectiveComputedBSize(aReflowInput);
return GetEffectiveComputedBSize(aReflowInput, aConsumedBSize);
}
// Returns the largest outer hypothetical main-size of any line in |aLines|.
@ -4159,7 +4160,8 @@ nscoord nsFlexContainerFrame::ComputeMainSize(
nscoord nsFlexContainerFrame::ComputeCrossSize(
const ReflowInput& aReflowInput, const FlexboxAxisTracker& aAxisTracker,
nscoord aSumLineCrossSizes, bool* aIsDefinite) const {
nscoord aSumLineCrossSizes, nscoord aConsumedBSize,
bool* aIsDefinite) const {
MOZ_ASSERT(aIsDefinite, "outparam pointer must be non-null");
if (aAxisTracker.IsColumnOriented()) {
@ -4180,7 +4182,8 @@ nscoord nsFlexContainerFrame::ComputeCrossSize(
return aReflowInput.ComputedISize();
}
nscoord effectiveComputedBSize = GetEffectiveComputedBSize(aReflowInput);
nscoord effectiveComputedBSize =
GetEffectiveComputedBSize(aReflowInput, aConsumedBSize);
if (effectiveComputedBSize != NS_UNCONSTRAINEDSIZE) {
// Row-oriented case (cross axis is block-axis), with fixed BSize:
*aIsDefinite = true;
@ -4401,8 +4404,10 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
const LogicalSize availableSizeForItems =
ComputeAvailableSizeForItems(aReflowInput, borderPadding);
const nscoord consumedBSize =
CalcAndCacheConsumedBSize(aReflowInput.GetWritingMode());
nscoord contentBoxMainSize =
GetMainSizeFromReflowInput(aReflowInput, axisTracker);
GetMainSizeFromReflowInput(aReflowInput, axisTracker, consumedBSize);
nscoord contentBoxCrossSize;
nscoord flexContainerAscent;
@ -4413,7 +4418,8 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
mainGapSize = nsLayoutUtils::ResolveGapToLength(stylePos->mColumnGap,
contentBoxMainSize);
crossGapSize = nsLayoutUtils::ResolveGapToLength(
stylePos->mRowGap, GetEffectiveComputedBSize(aReflowInput));
stylePos->mRowGap,
GetEffectiveComputedBSize(aReflowInput, consumedBSize));
} else {
mainGapSize = nsLayoutUtils::ResolveGapToLength(stylePos->mRowGap,
contentBoxMainSize);
@ -4440,7 +4446,7 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
// layout result closer to the one as if there's no fragmentation.
DoFlexLayout(aReflowInput, contentBoxMainSize, contentBoxCrossSize,
flexContainerAscent, lines, struts, placeholders, axisTracker,
mainGapSize, crossGapSize, hasLineClampEllipsis,
mainGapSize, crossGapSize, consumedBSize, hasLineClampEllipsis,
containerInfo);
if (!struts.IsEmpty()) {
@ -4449,8 +4455,8 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
placeholders.Clear();
DoFlexLayout(aReflowInput, contentBoxMainSize, contentBoxCrossSize,
flexContainerAscent, lines, struts, placeholders,
axisTracker, mainGapSize, crossGapSize, hasLineClampEllipsis,
containerInfo);
axisTracker, mainGapSize, crossGapSize, consumedBSize,
hasLineClampEllipsis, containerInfo);
}
} else {
auto* data = FirstInFlow()->GetProperty(SharedFlexData::Prop());
@ -4464,7 +4470,6 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
const LogicalSize contentBoxSize =
axisTracker.LogicalSizeFromFlexRelativeSizes(contentBoxMainSize,
contentBoxCrossSize);
const nscoord consumedBSize = ConsumedBSize(wm);
const nscoord effectiveContentBSize =
contentBoxSize.BSize(wm) - consumedBSize;
@ -4875,7 +4880,8 @@ void nsFlexContainerFrame::DoFlexLayout(
nscoord& aContentBoxCrossSize, nscoord& aFlexContainerAscent,
nsTArray<FlexLine>& aLines, nsTArray<StrutInfo>& aStruts,
nsTArray<nsIFrame*>& aPlaceholders, const FlexboxAxisTracker& aAxisTracker,
nscoord aMainGapSize, nscoord aCrossGapSize, bool aHasLineClampEllipsis,
nscoord aMainGapSize, nscoord aCrossGapSize, nscoord aConsumedBSize,
bool aHasLineClampEllipsis,
ComputedFlexContainerInfo* const aContainerInfo) {
MOZ_ASSERT(aLines.IsEmpty(), "Caller should pass an empty array for lines!");
MOZ_ASSERT(aPlaceholders.IsEmpty(),
@ -4978,8 +4984,9 @@ void nsFlexContainerFrame::DoFlexLayout(
}
bool isCrossSizeDefinite;
aContentBoxCrossSize = ComputeCrossSize(
aReflowInput, aAxisTracker, sumLineCrossSizes, &isCrossSizeDefinite);
aContentBoxCrossSize =
ComputeCrossSize(aReflowInput, aAxisTracker, sumLineCrossSizes,
aConsumedBSize, &isCrossSizeDefinite);
// Set up state for cross-axis alignment, at a high level (outside the
// scope of a particular flex line)

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

@ -321,7 +321,7 @@ class nsFlexContainerFrame final : public nsContainerFrame {
nsTArray<nsIFrame*>& aPlaceholders,
const FlexboxAxisTracker& aAxisTracker,
nscoord aMainGapSize, nscoord aCrossGapSize,
bool aHasLineClampEllipsis,
nscoord aConsumedBSize, bool aHasLineClampEllipsis,
ComputedFlexContainerInfo* const aContainerInfo);
/**
@ -447,7 +447,8 @@ class nsFlexContainerFrame final : public nsContainerFrame {
nsTArray<FlexLine>& aLines);
nscoord GetMainSizeFromReflowInput(const ReflowInput& aReflowInput,
const FlexboxAxisTracker& aAxisTracker);
const FlexboxAxisTracker& aAxisTracker,
nscoord aConsumedBSize);
/**
* Resolves the content-box main-size of a flex container frame,
@ -477,7 +478,8 @@ class nsFlexContainerFrame final : public nsContainerFrame {
nscoord ComputeCrossSize(const ReflowInput& aReflowInput,
const FlexboxAxisTracker& aAxisTracker,
nscoord aSumLineCrossSizes, bool* aIsDefinite) const;
nscoord aSumLineCrossSizes, nscoord aConsumedBSize,
bool* aIsDefinite) const;
/**
* Compute the size of the available space that we'll give to our children to

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

@ -8532,7 +8532,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
}
}
} else {
consumedBSize = ConsumedBSize(wm);
consumedBSize = CalcAndCacheConsumedBSize(wm);
gridReflowInput.InitializeForContinuation(this, consumedBSize);
// XXX Technically incorrect: We're ignoring our row sizes, when really
// we should use them but *they* should be computed as if we had no

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

@ -184,13 +184,27 @@ void nsSplittableFrame::RemoveFromFlow(nsIFrame* aFrame) {
aFrame->SetNextInFlow(nullptr);
}
nscoord nsSplittableFrame::ConsumedBSize(WritingMode aWM) const {
nscoord bSize = 0;
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ConsumedBSizeProperty, nscoord);
for (nsIFrame* prev = GetPrevContinuation(); prev;
prev = prev->GetPrevContinuation()) {
bSize += prev->ContentSize(aWM).BSize(aWM);
nscoord nsSplittableFrame::CalcAndCacheConsumedBSize(WritingMode aWM) {
nsIFrame* prev = GetPrevContinuation();
if (!prev) {
return 0;
}
nscoord bSize = 0;
for (; prev; prev = prev->GetPrevContinuation()) {
bSize += prev->ContentSize(aWM).BSize(aWM);
bool found = false;
nscoord consumed = prev->GetProperty(ConsumedBSizeProperty(), &found);
if (found) {
bSize += consumed;
break;
}
MOZ_ASSERT(!prev->GetPrevContinuation(),
"Property should always be set on prev continuation if not "
"the first continuation");
}
SetProperty(ConsumedBSizeProperty(), bSize);
return bSize;
}
@ -201,10 +215,6 @@ nscoord nsSplittableFrame::GetEffectiveComputedBSize(
return NS_UNCONSTRAINEDSIZE;
}
if (aConsumedBSize == NS_UNCONSTRAINEDSIZE) {
aConsumedBSize = ConsumedBSize(aReflowInput.GetWritingMode());
}
bSize -= aConsumedBSize;
// nsFieldSetFrame's inner frames are special since some of their content-box

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

@ -87,13 +87,16 @@ class nsSplittableFrame : public nsIFrame {
* Return the sum of the block-axis content size of our previous
* continuations.
*
* @param aWM a writing-mode to determine the block-axis
* Classes that call this are _required_ to call this at least once for each
* reflow (unless you're the first continuation, in which case you can skip
* it, because as an optimization we don't cache it there).
*
* @note (bz) This makes laying out a splittable frame with N continuations
* O(N^2)! So, use this function with caution and minimize the number
* of calls to this method.
* This guarantees that the internal cache works, by refreshing it. Calling it
* multiple times in the same reflow is wasteful, but not an error.
*
* @param aWM a writing-mode to determine the block-axis
*/
nscoord ConsumedBSize(mozilla::WritingMode aWM) const;
nscoord CalcAndCacheConsumedBSize(mozilla::WritingMode aWM);
/**
* Retrieve the effective computed block size of this frame, which is the
@ -101,8 +104,7 @@ class nsSplittableFrame : public nsIFrame {
* continuations.
*/
nscoord GetEffectiveComputedBSize(
const ReflowInput& aReflowInput,
nscoord aConsumed = NS_UNCONSTRAINEDSIZE) const;
const ReflowInput& aReflowInput, nscoord aConsumed) const;
/**
* @see nsIFrame::GetLogicalSkipSides()