diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index ac0cceb72e55..2f79494cced5 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -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 mutableReflowInput; diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 0ead2965714a..bfda53e6787e 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -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& aLines, nsTArray& aStruts, nsTArray& 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) diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index 9c4a82f3b59f..6e9d73e4513b 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -321,7 +321,7 @@ class nsFlexContainerFrame final : public nsContainerFrame { nsTArray& 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& 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 diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index 5c26a3486b4d..60132700f0bb 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -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 diff --git a/layout/generic/nsSplittableFrame.cpp b/layout/generic/nsSplittableFrame.cpp index dffa97d382dd..582eb33d931c 100644 --- a/layout/generic/nsSplittableFrame.cpp +++ b/layout/generic/nsSplittableFrame.cpp @@ -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 diff --git a/layout/generic/nsSplittableFrame.h b/layout/generic/nsSplittableFrame.h index 9a94289f3599..2240e8db2327 100644 --- a/layout/generic/nsSplittableFrame.h +++ b/layout/generic/nsSplittableFrame.h @@ -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()