From f3f221e5664c6e8de9663cf495652781c45ddc73 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Fri, 23 Jan 2015 14:15:11 -0800 Subject: [PATCH] Bug 1054010: Skip final reflow for flex items that receive an earlier 'measuring reflow' with the right size. r=mats --- layout/generic/crashtests/1054010-1.html | 97 +++++++++++++++++++++++ layout/generic/crashtests/crashtests.list | 3 +- layout/generic/nsFlexContainerFrame.cpp | 49 +++++++++++- layout/generic/nsFlexContainerFrame.h | 19 +++++ 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 layout/generic/crashtests/1054010-1.html diff --git a/layout/generic/crashtests/1054010-1.html b/layout/generic/crashtests/1054010-1.html new file mode 100644 index 000000000000..52557340a131 --- /dev/null +++ b/layout/generic/crashtests/1054010-1.html @@ -0,0 +1,97 @@ + + + + + + +
+
+
+ Nested layout 1 +
+
+
+ Nested layout 2 +
+
+
+ Nested layout 3 +
+
+
+ Nested layout 4 +
+
+
+ Nested layout 5 +
+
+
+ Nested layout 6 +
+
+
+ Nested layout 7 +
+
+
+ Nested layout 8 +
+
+
+ Nested layout 9 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index ddc4fd536dd1..9c4de90873ac 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -496,7 +496,7 @@ load 785555.html load 786740-1.html asserts(0-4) test-pref(font.size.inflation.emPerLine,15) load 791601.xhtml # 3 counts of bug 871327, 1 bug 367185 test-pref(font.size.inflation.minTwips,120) load 794693.html -asserts-if(!Android,8) load 798020-1.html +asserts-if(!Android,4) load 798020-1.html load 798235-1.html load 799207-1.html load 799207-2.html @@ -565,4 +565,5 @@ pref(font.size.inflation.minTwips,200) load 1032450.html load 1037903.html load 1039454-1.html load 1042489.html +load 1054010-1.html load 1058954-1.html diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 548bec401718..8f691749e11c 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -3683,8 +3683,27 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext, // maybe use for setting the flex container's baseline.) const nscoord itemNormalBPos = framePos.B(outerWM); - ReflowFlexItem(aPresContext, aAxisTracker, aReflowState, - *item, framePos, containerWidth); + // Check if we actually need to reflow the item -- if we already reflowed + // it with the right size, we can just reposition it as-needed. + bool itemNeedsReflow = true; // (Start out assuming the worst.) + if (item->HadMeasuringReflow()) { + // We've already reflowed the child once. Was the size we gave it in + // that reflow the same as its final (post-flexing/stretching) size? + nsSize finalFlexedPhysicalSize = + aAxisTracker.PhysicalSizeFromLogicalSizes(item->GetMainSize(), + item->GetCrossSize()); + if (item->Frame()->GetSize() == finalFlexedPhysicalSize) { + // It has the correct size --> no need to reflow! Just make sure it's + // at the right position. + itemNeedsReflow = false; + MoveFlexItemToFinalPosition(aReflowState, *item, framePos, + containerWidth); + } + } + if (itemNeedsReflow) { + ReflowFlexItem(aPresContext, aAxisTracker, aReflowState, + *item, framePos, containerWidth); + } // If this is our first child and we haven't established a baseline for // the container yet (i.e. if we don't have 'align-self: baseline' on any @@ -3758,6 +3777,32 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext, NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize) } +void +nsFlexContainerFrame::MoveFlexItemToFinalPosition( + const nsHTMLReflowState& aReflowState, + const FlexItem& aItem, + LogicalPoint& aFramePos, + nscoord aContainerWidth) +{ + WritingMode outerWM = aReflowState.GetWritingMode(); + + // If item is relpos, look up its offsets (cached from prev reflow) + LogicalMargin logicalOffsets(outerWM); + if (NS_STYLE_POSITION_RELATIVE == aItem.Frame()->StyleDisplay()->mPosition) { + FrameProperties props = aItem.Frame()->Properties(); + nsMargin* cachedOffsets = + static_cast(props.Get(nsIFrame::ComputedOffsetProperty())); + MOZ_ASSERT(cachedOffsets, + "relpos previously-reflowed frame should've cached its offsets"); + logicalOffsets = LogicalMargin(outerWM, *cachedOffsets); + } + nsHTMLReflowState::ApplyRelativePositioning(aItem.Frame(), outerWM, + logicalOffsets, &aFramePos, + aContainerWidth); + aItem.Frame()->SetPosition(outerWM, aFramePos, aContainerWidth); + PositionChildViews(aItem.Frame()); +} + void nsFlexContainerFrame::ReflowFlexItem(nsPresContext* aPresContext, const FlexboxAxisTracker& aAxisTracker, diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index d38ecc4c2032..191db4532aac 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -171,6 +171,25 @@ protected: nsHTMLReflowState& aChildReflowState, FlexItem& aItem); + /** + * Moves the given flex item's frame to the given LogicalPosition (modulo any + * relative positioning). + * + * This can be used in cases where we've already done a "measuring reflow" + * for the flex item at the correct size, and hence can skip its final reflow + * (but still need to move it to the right final position). + * + * @param aReflowState The flex container's reflow state. + * @param aItem The flex item whose frame should be moved. + * @param aFramePos The position where the flex item's frame should + * be placed. (pre-relative positioning) + * @param aContainerWidth The flex container's width (required by some methods + * that we call, to interpret aFramePos correctly). + */ + void MoveFlexItemToFinalPosition(const nsHTMLReflowState& aReflowState, + const FlexItem& aItem, + mozilla::LogicalPoint& aFramePos, + nscoord aContainerWidth); /** * Helper-function to reflow a child frame, at its final position determined * by flex layout.