Bug 1054010: Skip final reflow for flex items that receive an earlier 'measuring reflow' with the right size. r=mats

This commit is contained in:
Daniel Holbert 2015-01-23 14:15:11 -08:00
parent b6016767e6
commit 220f2de2a2
4 changed files with 165 additions and 3 deletions

View File

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.flexRow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.flexColumn {
display: flex;
flex-direction: column;
justify-content: center;
flex-basis: 100%;
}
.flexBlock {
flex: 0;
display: flex;
flex-direction: column;
padding: 5px;
border: 1px solid blue;
}
.flexColumn > .flexBlock:last-child {
flex: 1;
}
</style>
</head>
<body>
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 1
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 2
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 3
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 4
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 5
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 6
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 7
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 8
<div class="flexRow">
<div class="flexColumn">
<div class="flexBlock">
Nested layout 9
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -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

View File

@ -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<nsMargin*>(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,

View File

@ -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.