author | Daniel Holbert <dholbert@cs.stanford.edu> |
Fri, 15 Mar 2013 22:40:57 -0700 | |
changeset 125005 | 3a1ab4d115134c4789a54856079af73bb03e16c5 |
parent 125004 | d4c1d68f2d9f9bfbbc7e4f4b22e2b2680b324da9 |
child 125006 | 46585b03426a268600caaaf2f5896023393be6ca |
push id | 24734 |
push user | dholbert@mozilla.com |
push date | Sat, 16 Mar 2013 05:47:59 +0000 |
treeherder | mozilla-inbound@3a1ab4d11513 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dbaron |
bugs | 851607 |
milestone | 22.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -2082,23 +2082,16 @@ nsFlexContainerFrame::Reflow(nsPresConte eStyleUnit_Auto != stylePos->mOffset.GetBottomUnit())) { AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); } #ifdef DEBUG SanityCheckAnonymousFlexItems(); #endif // DEBUG - // If our subtree is dirty (i.e. some of our descendants have changed), we - // reflow _all_ of our children. We have to do this -- we can't just reflow - // select children, as we would in other frame classes. This is because flex - // items' sizes (in both axes) are highly dependent on their siblings' sizes. - bool shouldReflowChildren = - NS_SUBTREE_DIRTY(this) || aReflowState.ShouldReflowAllKids(); - // If we've never reordered our children, then we can trust that they're // already in DOM-order, and we only need to consider their "order" property // when checking them for sortedness & sorting them. // // After we actually sort them, though, we can't trust that they're in DOM // order anymore. So, from that point on, our sort & sorted-order-checking // operations need to use a fancier LEQ function that also takes DOM order // into account, so that we can honor the spec's requirement that frames w/ @@ -2129,227 +2122,207 @@ nsFlexContainerFrame::Reflow(nsPresConte ResolveFlexibleLengths(axisTracker, flexContainerMainSize, items); // Our frame's main-size is the content-box size plus border and padding. nscoord frameMainSize = flexContainerMainSize + axisTracker.GetMarginSizeInMainAxis(aReflowState.mComputedBorderPadding); nscoord frameCrossSize; - if (!shouldReflowChildren) { - // So far, it looks like none of our flex items need a reflow. - // HOWEVER: if we already gave any of them a measuring reflow, then we - // should consider it dirty -- it'll need a "real" reflow to undo the - // effects of our measuring reflow. - for (uint32_t i = 0; i < items.Length(); ++i) { - if (items[i].HadMeasuringReflow()) { - shouldReflowChildren = true; - break; - } - } - } + MainAxisPositionTracker mainAxisPosnTracker(this, axisTracker, + aReflowState, items); - if (!shouldReflowChildren) { - // Children don't need reflow --> assume our content-box size is the same - // since our last reflow. - frameCrossSize = mCachedContentBoxCrossSize + - axisTracker.GetMarginSizeInCrossAxis(aReflowState.mComputedBorderPadding); - } else { - MainAxisPositionTracker mainAxisPosnTracker(this, axisTracker, - aReflowState, items); + // First loop: Compute main axis position & cross-axis size of each item + for (uint32_t i = 0; i < items.Length(); ++i) { + FlexItem& curItem = items[i]; - // First loop: Compute main axis position & cross-axis size of each item - for (uint32_t i = 0; i < items.Length(); ++i) { - FlexItem& curItem = items[i]; - - nsHTMLReflowState childReflowState(aPresContext, aReflowState, - curItem.Frame(), - nsSize(aReflowState.ComputedWidth(), - NS_UNCONSTRAINEDSIZE)); - // Override computed main-size - if (IsAxisHorizontal(axisTracker.GetMainAxis())) { - childReflowState.SetComputedWidth(curItem.GetMainSize()); - } else { - childReflowState.SetComputedHeight(curItem.GetMainSize()); - } - - PositionItemInMainAxis(mainAxisPosnTracker, curItem); - - nsresult rv = - SizeItemInCrossAxis(aPresContext, axisTracker, - childReflowState, curItem); - NS_ENSURE_SUCCESS(rv, rv); + nsHTMLReflowState childReflowState(aPresContext, aReflowState, + curItem.Frame(), + nsSize(aReflowState.ComputedWidth(), + NS_UNCONSTRAINEDSIZE)); + // Override computed main-size + if (IsAxisHorizontal(axisTracker.GetMainAxis())) { + childReflowState.SetComputedWidth(curItem.GetMainSize()); + } else { + childReflowState.SetComputedHeight(curItem.GetMainSize()); } - // SIZE & POSITION THE FLEX LINE (IN CROSS AXIS) - // Set up state for cross-axis alignment, at a high level (outside the - // scope of a particular flex line) - CrossAxisPositionTracker - crossAxisPosnTracker(this, axisTracker, aReflowState); + PositionItemInMainAxis(mainAxisPosnTracker, curItem); - // Set up state for cross-axis-positioning of children _within_ a single - // flex line. - SingleLineCrossAxisPositionTracker - lineCrossAxisPosnTracker(this, axisTracker, items); + nsresult rv = + SizeItemInCrossAxis(aPresContext, axisTracker, + childReflowState, curItem); + NS_ENSURE_SUCCESS(rv, rv); + } + + // SIZE & POSITION THE FLEX LINE (IN CROSS AXIS) + // Set up state for cross-axis alignment, at a high level (outside the + // scope of a particular flex line) + CrossAxisPositionTracker + crossAxisPosnTracker(this, axisTracker, aReflowState); - lineCrossAxisPosnTracker.ComputeLineCrossSize(items); - // XXXdholbert Once we've got multi-line flexbox support: here, after we've - // computed the cross size of all lines, we need to check if if - // 'align-content' is 'stretch' -- if it is, we need to give each line an - // additional share of our flex container's desired cross-size. (if it's - // not NS_AUTOHEIGHT and there's any cross-size left over to distribute) + // Set up state for cross-axis-positioning of children _within_ a single + // flex line. + SingleLineCrossAxisPositionTracker + lineCrossAxisPosnTracker(this, axisTracker, items); - // Figure out our flex container's cross size - mCachedContentBoxCrossSize = - axisTracker.GetCrossComponent(nsSize(aReflowState.ComputedWidth(), - aReflowState.ComputedHeight())); + lineCrossAxisPosnTracker.ComputeLineCrossSize(items); + // XXXdholbert Once we've got multi-line flexbox support: here, after we've + // computed the cross size of all lines, we need to check if if + // 'align-content' is 'stretch' -- if it is, we need to give each line an + // additional share of our flex container's desired cross-size. (if it's + // not NS_AUTOHEIGHT and there's any cross-size left over to distribute) + + // Figure out our flex container's cross size + mCachedContentBoxCrossSize = + axisTracker.GetCrossComponent(nsSize(aReflowState.ComputedWidth(), + aReflowState.ComputedHeight())); - if (mCachedContentBoxCrossSize == NS_AUTOHEIGHT) { - // Unconstrained 'auto' cross-size: shrink-wrap our line(s), subject - // to our min-size / max-size constraints in that axis. - nscoord minCrossSize = - axisTracker.GetCrossComponent(nsSize(aReflowState.mComputedMinWidth, - aReflowState.mComputedMinHeight)); - nscoord maxCrossSize = - axisTracker.GetCrossComponent(nsSize(aReflowState.mComputedMaxWidth, - aReflowState.mComputedMaxHeight)); - mCachedContentBoxCrossSize = - NS_CSS_MINMAX(lineCrossAxisPosnTracker.GetLineCrossSize(), - minCrossSize, maxCrossSize); - } - if (lineCrossAxisPosnTracker.GetLineCrossSize() != - mCachedContentBoxCrossSize) { - // XXXdholbert When we support multi-line flex containers, we should - // distribute any extra space among or between our lines here according - // to 'align-content'. For now, we do the single-line special behavior: - // "If the flex container has only a single line (even if it's a - // multi-line flex container), the cross size of the flex line is the - // flex container's inner cross size." - lineCrossAxisPosnTracker.SetLineCrossSize(mCachedContentBoxCrossSize); - } - frameCrossSize = mCachedContentBoxCrossSize + - axisTracker.GetMarginSizeInCrossAxis(aReflowState.mComputedBorderPadding); + if (mCachedContentBoxCrossSize == NS_AUTOHEIGHT) { + // Unconstrained 'auto' cross-size: shrink-wrap our line(s), subject + // to our min-size / max-size constraints in that axis. + nscoord minCrossSize = + axisTracker.GetCrossComponent(nsSize(aReflowState.mComputedMinWidth, + aReflowState.mComputedMinHeight)); + nscoord maxCrossSize = + axisTracker.GetCrossComponent(nsSize(aReflowState.mComputedMaxWidth, + aReflowState.mComputedMaxHeight)); + mCachedContentBoxCrossSize = + NS_CSS_MINMAX(lineCrossAxisPosnTracker.GetLineCrossSize(), + minCrossSize, maxCrossSize); + } + if (lineCrossAxisPosnTracker.GetLineCrossSize() != + mCachedContentBoxCrossSize) { + // XXXdholbert When we support multi-line flex containers, we should + // distribute any extra space among or between our lines here according + // to 'align-content'. For now, we do the single-line special behavior: + // "If the flex container has only a single line (even if it's a + // multi-line flex container), the cross size of the flex line is the + // flex container's inner cross size." + lineCrossAxisPosnTracker.SetLineCrossSize(mCachedContentBoxCrossSize); + } + frameCrossSize = mCachedContentBoxCrossSize + + axisTracker.GetMarginSizeInCrossAxis(aReflowState.mComputedBorderPadding); - // XXXdholbert FOLLOW ACTUAL RULES FOR FLEX CONTAINER BASELINE - // If we have any baseline-aligned items on first line, use their baseline. - // ...ELSE if we have at least one flex item and our first flex item's - // baseline is parallel to main axis, then use that baseline. - // ...ELSE use "after" edge of content box. - // Default baseline: the "after" edge of content box. (Note: if we have any - // flex items, they'll override this.) - mCachedAscent = mCachedContentBoxCrossSize + - aReflowState.mComputedBorderPadding.top; + // XXXdholbert FOLLOW ACTUAL RULES FOR FLEX CONTAINER BASELINE + // If we have any baseline-aligned items on first line, use their baseline. + // ...ELSE if we have at least one flex item and our first flex item's + // baseline is parallel to main axis, then use that baseline. + // ...ELSE use "after" edge of content box. + // Default baseline: the "after" edge of content box. (Note: if we have any + // flex items, they'll override this.) + mCachedAscent = mCachedContentBoxCrossSize + + aReflowState.mComputedBorderPadding.top; + + // Position the items in cross axis, within their line + for (uint32_t i = 0; i < items.Length(); ++i) { + PositionItemInCrossAxis(crossAxisPosnTracker.GetPosition(), + lineCrossAxisPosnTracker, items[i]); + } - // Position the items in cross axis, within their line - for (uint32_t i = 0; i < items.Length(); ++i) { - PositionItemInCrossAxis(crossAxisPosnTracker.GetPosition(), - lineCrossAxisPosnTracker, items[i]); + // FINAL REFLOW: Give each child frame another chance to reflow, now that + // we know its final size and position. + for (uint32_t i = 0; i < items.Length(); ++i) { + FlexItem& curItem = items[i]; + nsHTMLReflowState childReflowState(aPresContext, aReflowState, + curItem.Frame(), + nsSize(aReflowState.ComputedWidth(), + NS_UNCONSTRAINEDSIZE)); + + // Keep track of whether we've overriden the child's computed height + // and/or width, so we can set its resize flags accordingly. + bool didOverrideComputedWidth = false; + bool didOverrideComputedHeight = false; + + // Override computed main-size + if (IsAxisHorizontal(axisTracker.GetMainAxis())) { + childReflowState.SetComputedWidth(curItem.GetMainSize()); + didOverrideComputedWidth = true; + } else { + childReflowState.SetComputedHeight(curItem.GetMainSize()); + didOverrideComputedHeight = true; } - // FINAL REFLOW: Give each child frame another chance to reflow, now that - // we know its final size and position. - for (uint32_t i = 0; i < items.Length(); ++i) { - FlexItem& curItem = items[i]; - nsHTMLReflowState childReflowState(aPresContext, aReflowState, - curItem.Frame(), - nsSize(aReflowState.ComputedWidth(), - NS_UNCONSTRAINEDSIZE)); - - // Keep track of whether we've overriden the child's computed height - // and/or width, so we can set its resize flags accordingly. - bool didOverrideComputedWidth = false; - bool didOverrideComputedHeight = false; - - // Override computed main-size - if (IsAxisHorizontal(axisTracker.GetMainAxis())) { - childReflowState.SetComputedWidth(curItem.GetMainSize()); + // Override reflow state's computed cross-size, for stretched items. + if (curItem.IsStretched()) { + MOZ_ASSERT(curItem.GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_STRETCH, + "stretched item w/o 'align-self: stretch'?"); + if (IsAxisHorizontal(axisTracker.GetCrossAxis())) { + childReflowState.SetComputedWidth(curItem.GetCrossSize()); didOverrideComputedWidth = true; } else { - childReflowState.SetComputedHeight(curItem.GetMainSize()); + // If this item's height is stretched, it's a relative height. + curItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); + childReflowState.SetComputedHeight(curItem.GetCrossSize()); didOverrideComputedHeight = true; } + } - // Override reflow state's computed cross-size, for stretched items. - if (curItem.IsStretched()) { - MOZ_ASSERT(curItem.GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_STRETCH, - "stretched item w/o 'align-self: stretch'?"); - if (IsAxisHorizontal(axisTracker.GetCrossAxis())) { - childReflowState.SetComputedWidth(curItem.GetCrossSize()); - didOverrideComputedWidth = true; - } else { - // If this item's height is stretched, it's a relative height. - curItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); - childReflowState.SetComputedHeight(curItem.GetCrossSize()); - didOverrideComputedHeight = true; - } - } + // XXXdholbert Might need to actually set the correct margins in the + // reflow state at some point, so that they can be saved on the frame for + // UsedMarginProperty(). Maybe doesn't matter though...? - // XXXdholbert Might need to actually set the correct margins in the - // reflow state at some point, so that they can be saved on the frame for - // UsedMarginProperty(). Maybe doesn't matter though...? - - // If we're overriding the computed width or height, *and* we had an - // earlier "measuring" reflow, then this upcoming reflow needs to be - // treated as a resize. - if (curItem.HadMeasuringReflow()) { - if (didOverrideComputedWidth) { - // (This is somewhat redundant, since the reflow state already - // sets mHResize whenever our computed width has changed since the - // previous reflow. Still, it's nice for symmetry, and it may become - // necessary once we support orthogonal flows.) - childReflowState.mFlags.mHResize = true; - } - if (didOverrideComputedHeight) { - childReflowState.mFlags.mVResize = true; - } + // If we're overriding the computed width or height, *and* we had an + // earlier "measuring" reflow, then this upcoming reflow needs to be + // treated as a resize. + if (curItem.HadMeasuringReflow()) { + if (didOverrideComputedWidth) { + // (This is somewhat redundant, since the reflow state already + // sets mHResize whenever our computed width has changed since the + // previous reflow. Still, it's nice for symmetry, and it may become + // necessary once we support orthogonal flows.) + childReflowState.mFlags.mHResize = true; } - // NOTE: Be very careful about doing anything else with childReflowState - // after this point, because some of its methods (e.g. SetComputedWidth) - // internally call InitResizeFlags and stomp on mVResize & mHResize. + if (didOverrideComputedHeight) { + childReflowState.mFlags.mVResize = true; + } + } + // NOTE: Be very careful about doing anything else with childReflowState + // after this point, because some of its methods (e.g. SetComputedWidth) + // internally call InitResizeFlags and stomp on mVResize & mHResize. - nscoord mainPosn = curItem.GetMainPosition(); - nscoord crossPosn = curItem.GetCrossPosition(); - if (!AxisGrowsInPositiveDirection(axisTracker.GetMainAxis())) { - mainPosn = frameMainSize - mainPosn; - } - if (!AxisGrowsInPositiveDirection(axisTracker.GetCrossAxis())) { - crossPosn = frameCrossSize - crossPosn; - } + nscoord mainPosn = curItem.GetMainPosition(); + nscoord crossPosn = curItem.GetCrossPosition(); + if (!AxisGrowsInPositiveDirection(axisTracker.GetMainAxis())) { + mainPosn = frameMainSize - mainPosn; + } + if (!AxisGrowsInPositiveDirection(axisTracker.GetCrossAxis())) { + crossPosn = frameCrossSize - crossPosn; + } - nsPoint physicalPosn = - axisTracker.PhysicalPositionFromLogicalPosition(mainPosn, crossPosn); + nsPoint physicalPosn = + axisTracker.PhysicalPositionFromLogicalPosition(mainPosn, crossPosn); - nsHTMLReflowMetrics childDesiredSize; - nsReflowStatus childReflowStatus; - nsresult rv = ReflowChild(curItem.Frame(), aPresContext, - childDesiredSize, childReflowState, - physicalPosn.x, physicalPosn.y, - 0, childReflowStatus); - NS_ENSURE_SUCCESS(rv, rv); + nsHTMLReflowMetrics childDesiredSize; + nsReflowStatus childReflowStatus; + nsresult rv = ReflowChild(curItem.Frame(), aPresContext, + childDesiredSize, childReflowState, + physicalPosn.x, physicalPosn.y, + 0, childReflowStatus); + NS_ENSURE_SUCCESS(rv, rv); - // XXXdholbert Once we do pagination / splitting, we'll need to actually - // handle incomplete childReflowStatuses. But for now, we give our kids - // unconstrained available height, which means they should always - // complete. - MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), - "We gave flex item unconstrained available height, so it " - "should be complete"); + // XXXdholbert Once we do pagination / splitting, we'll need to actually + // handle incomplete childReflowStatuses. But for now, we give our kids + // unconstrained available height, which means they should always + // complete. + MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), + "We gave flex item unconstrained available height, so it " + "should be complete"); - // Apply CSS relative positioning - const nsStyleDisplay* styleDisp = curItem.Frame()->StyleDisplay(); - if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) { - physicalPosn.x += childReflowState.mComputedOffsets.left; - physicalPosn.y += childReflowState.mComputedOffsets.top; - } + // Apply CSS relative positioning + const nsStyleDisplay* styleDisp = curItem.Frame()->StyleDisplay(); + if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) { + physicalPosn.x += childReflowState.mComputedOffsets.left; + physicalPosn.y += childReflowState.mComputedOffsets.top; + } - rv = FinishReflowChild(curItem.Frame(), aPresContext, - &childReflowState, childDesiredSize, - physicalPosn.x, physicalPosn.y, 0); - NS_ENSURE_SUCCESS(rv, rv); - } + rv = FinishReflowChild(curItem.Frame(), aPresContext, + &childReflowState, childDesiredSize, + physicalPosn.x, physicalPosn.y, 0); + NS_ENSURE_SUCCESS(rv, rv); } // XXXdholbert This could be more elegant aDesiredSize.width = IsAxisHorizontal(axisTracker.GetMainAxis()) ? frameMainSize : frameCrossSize; aDesiredSize.height = IsAxisHorizontal(axisTracker.GetCrossAxis()) ?