--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -1523,19 +1523,20 @@ ResolveAutoFlexBasisFromRatio(FlexItem&
// we may want to resolve that in this function, too.
void
nsFlexContainerFrame::
ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
FlexItem& aFlexItem,
const ReflowInput& aItemReflowInput,
const FlexboxAxisTracker& aAxisTracker)
{
- // (Note: We should never have a used flex-basis of "auto" if our main axis
- // is horizontal; width values should always be resolvable without reflow.)
- const bool isMainSizeAuto = (!aAxisTracker.IsMainAxisHorizontal() &&
+ // (Note: We can guarantee that the flex-basis will have already been
+ // resolved if the main axis is the same is the same as the item's inline
+ // axis. Inline-axis values should always be resolvable without reflow.)
+ const bool isMainSizeAuto = (!aFlexItem.IsInlineAxisMainAxis() &&
NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
const bool isMainMinSizeAuto = aFlexItem.NeedsMinSizeAutoResolution();
if (!isMainSizeAuto && !isMainMinSizeAuto) {
// Nothing to do; this function is only needed for flex items
// with a used flex-basis of "auto" or a min-main-size of "auto".
return;
@@ -1556,20 +1557,24 @@ nsFlexContainerFrame::
if (NS_STYLE_FLEX_WRAP_NOWRAP == flexContainerRI->mStylePosition->mFlexWrap) {
// XXXdholbert Maybe this should share logic with ComputeCrossSize()...
// Alternately, maybe tentative container cross size should be passed down.
nscoord containerCrossSize =
GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aAxisTracker.GetWritingMode(),
flexContainerRI->ComputedISize(),
flexContainerRI->ComputedBSize());
// Is container's cross size "definite"?
- // (Container's cross size is definite if cross-axis is horizontal, or if
- // cross-axis is vertical and the cross-size is not NS_AUTOHEIGHT.)
- if (aAxisTracker.IsCrossAxisHorizontal() ||
+ // - If it's column-oriented, then "yes", because its cross size is its
+ // inline-size which is always definite from its descendants' perspective.
+ // - Otherwise (if it's row-oriented), then we check the actual size
+ // and call it definite if it's not NS_AUTOHEIGHT.
+ if (aAxisTracker.IsColumnOriented() ||
containerCrossSize != NS_AUTOHEIGHT) {
+ // Container's cross size is "definite", so we can resolve the item's
+ // stretched cross size using that.
aFlexItem.ResolveStretchedCrossSize(containerCrossSize, aAxisTracker);
}
}
nscoord resolvedMinSize; // (only set/used if isMainMinSizeAuto==true)
bool minSizeNeedsToMeasureContent = false; // assume the best
if (isMainMinSizeAuto) {
// Resolve the min-size, except for considering the min-content size.
@@ -1592,51 +1597,53 @@ nsFlexContainerFrame::
if (!ResolveAutoFlexBasisFromRatio(aFlexItem, aItemReflowInput,
aAxisTracker)) {
flexBasisNeedsToMeasureContent = true;
}
}
// Measure content, if needed (w/ intrinsic-width method or a reflow)
if (minSizeNeedsToMeasureContent || flexBasisNeedsToMeasureContent) {
- if (aAxisTracker.IsMainAxisHorizontal()) {
+ if (aFlexItem.IsInlineAxisMainAxis()) {
if (minSizeNeedsToMeasureContent) {
nscoord frameMinISize =
aFlexItem.Frame()->GetMinISize(aItemReflowInput.mRenderingContext);
resolvedMinSize = std::min(resolvedMinSize, frameMinISize);
}
NS_ASSERTION(!flexBasisNeedsToMeasureContent,
"flex-basis:auto should have been resolved in the "
"reflow state, for horizontal flexbox. It shouldn't need "
"special handling here");
} else {
- // If this item is flexible (vertically), or if we're measuring the
- // 'auto' min-height and our main-size is something else, then we assume
- // that the computed-height we're reflowing with now could be different
- // from the one we'll use for this flex item's "actual" reflow later on.
- // In that case, we need to be sure the flex item treats this as a
- // vertical resize, even though none of its ancestors are necessarily
- // being vertically resized.
- // (Note: We don't have to do this for width, because InitResizeFlags
- // will always turn on mHResize on when it sees that the computed width
- // is different from current width, and that's all we need.)
- bool forceVerticalResizeForMeasuringReflow =
+ // If this item is flexible (in its block axis)...
+ // OR if we're measuring its 'auto' min-BSize, with its main-size (in its
+ // block axis) being something non-"auto"...
+ // THEN: we assume that the computed BSize that we're reflowing with now
+ // could be different from the one we'll use for this flex item's
+ // "actual" reflow later on. In that case, we need to be sure the flex
+ // item treats this as a block-axis resize (regardless of whether there
+ // are actually any ancestors being resized in that axis).
+ // (Note: We don't have to do this for the inline axis, because
+ // InitResizeFlags will always turn on mIsIResize on when it sees that
+ // the computed ISize is different from current ISize, and that's all we
+ // need.)
+ bool forceBResizeForMeasuringReflow =
!aFlexItem.IsFrozen() || // Is the item flexible?
!flexBasisNeedsToMeasureContent; // Are we *only* measuring it for
- // 'min-height:auto'?
-
- nscoord contentHeight =
- MeasureFlexItemContentHeight(aPresContext, aFlexItem,
- forceVerticalResizeForMeasuringReflow,
- *flexContainerRI);
+ // 'min-block-size:auto'?
+
+ nscoord contentBSize =
+ MeasureFlexItemContentBSize(aPresContext, aFlexItem,
+ forceBResizeForMeasuringReflow,
+ *flexContainerRI);
if (minSizeNeedsToMeasureContent) {
- resolvedMinSize = std::min(resolvedMinSize, contentHeight);
+ resolvedMinSize = std::min(resolvedMinSize, contentBSize);
}
if (flexBasisNeedsToMeasureContent) {
- aFlexItem.SetFlexBaseSizeAndMainSize(contentHeight);
+ aFlexItem.SetFlexBaseSizeAndMainSize(contentBSize);
}
}
}
if (isMainMinSizeAuto) {
aFlexItem.UpdateMainMinSize(resolvedMinSize);
}
}
@@ -1660,46 +1667,46 @@ nsFlexContainerFrame::
* nested flex and scroll frames.
*
* We store them in the frame property table for simplicity.
*/
class nsFlexContainerFrame::CachedMeasuringReflowResult
{
// Members that are part of the cache key:
const LogicalSize mAvailableSize;
- const nscoord mComputedHeight;
+ const nscoord mComputedBSize;
// Members that are part of the cache value:
- const nscoord mHeight;
+ const nscoord mBSize;
const nscoord mAscent;
public:
CachedMeasuringReflowResult(const ReflowInput& aReflowInput,
const ReflowOutput& aDesiredSize)
: mAvailableSize(aReflowInput.AvailableSize())
- , mComputedHeight(aReflowInput.ComputedHeight())
- , mHeight(aDesiredSize.Height())
+ , mComputedBSize(aReflowInput.ComputedBSize())
+ , mBSize(aDesiredSize.BSize(aReflowInput.GetWritingMode()))
, mAscent(aDesiredSize.BlockStartAscent())
{}
bool IsValidFor(const ReflowInput& aReflowInput) const {
return mAvailableSize == aReflowInput.AvailableSize() &&
- mComputedHeight == aReflowInput.ComputedHeight();
- }
-
- nscoord Height() const { return mHeight; }
+ mComputedBSize == aReflowInput.ComputedBSize();
+ }
+
+ nscoord BSize() const { return mBSize; }
nscoord Ascent() const { return mAscent; }
};
NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedFlexMeasuringReflow,
CachedMeasuringReflowResult);
const CachedMeasuringReflowResult&
-nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem(
+nsFlexContainerFrame::MeasureAscentAndBSizeForFlexItem(
FlexItem& aItem,
nsPresContext* aPresContext,
ReflowInput& aChildReflowInput)
{
if (const auto* cachedResult =
aItem.Frame()->GetProperty(CachedFlexMeasuringReflow())) {
if (cachedResult->IsValidFor(aChildReflowInput)) {
return *cachedResult;
@@ -1740,53 +1747,54 @@ nsFlexContainerFrame::MarkIntrinsicISize
for (nsIFrame* childFrame : mFrames) {
childFrame->DeleteProperty(CachedFlexMeasuringReflow());
}
nsContainerFrame::MarkIntrinsicISizesDirty();
}
nscoord
nsFlexContainerFrame::
- MeasureFlexItemContentHeight(nsPresContext* aPresContext,
- FlexItem& aFlexItem,
- bool aForceVerticalResizeForMeasuringReflow,
- const ReflowInput& aParentReflowInput)
+ MeasureFlexItemContentBSize(nsPresContext* aPresContext,
+ FlexItem& aFlexItem,
+ bool aForceBResizeForMeasuringReflow,
+ const ReflowInput& aParentReflowInput)
{
// Set up a reflow state for measuring the flex item's auto-height:
WritingMode wm = aFlexItem.Frame()->GetWritingMode();
LogicalSize availSize = aParentReflowInput.ComputedSize(wm);
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
ReflowInput
- childRIForMeasuringHeight(aPresContext, aParentReflowInput,
- aFlexItem.Frame(), availSize,
- nullptr, ReflowInput::CALLER_WILL_INIT);
- childRIForMeasuringHeight.mFlags.mIsFlexContainerMeasuringHeight = true;
- childRIForMeasuringHeight.Init(aPresContext);
+ childRIForMeasuringBSize(aPresContext, aParentReflowInput,
+ aFlexItem.Frame(), availSize,
+ nullptr, ReflowInput::CALLER_WILL_INIT);
+ // XXXdholbert NOTE: Next patch will do s/Height/BSize/ on this flag:
+ childRIForMeasuringBSize.mFlags.mIsFlexContainerMeasuringHeight = true;
+ childRIForMeasuringBSize.Init(aPresContext);
if (aFlexItem.IsStretched()) {
- childRIForMeasuringHeight.SetComputedWidth(aFlexItem.GetCrossSize());
- childRIForMeasuringHeight.SetHResize(true);
- }
-
- if (aForceVerticalResizeForMeasuringReflow) {
- childRIForMeasuringHeight.SetVResize(true);
+ childRIForMeasuringBSize.SetComputedISize(aFlexItem.GetCrossSize());
+ childRIForMeasuringBSize.SetIResize(true);
+ }
+
+ if (aForceBResizeForMeasuringReflow) {
+ childRIForMeasuringBSize.SetBResize(true);
}
const CachedMeasuringReflowResult& reflowResult =
- MeasureAscentAndHeightForFlexItem(aFlexItem, aPresContext,
- childRIForMeasuringHeight);
+ MeasureAscentAndBSizeForFlexItem(aFlexItem, aPresContext,
+ childRIForMeasuringBSize);
aFlexItem.SetAscent(reflowResult.Ascent());
- // Subtract border/padding in vertical axis, to get _just_
- // the effective computed value of the "height" property.
- nscoord childDesiredHeight = reflowResult.Height() -
- childRIForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom();
-
- return std::max(0, childDesiredHeight);
+ // Subtract border/padding in block axis, to get _just_
+ // the effective computed value of the BSize property.
+ nscoord childDesiredBSize = reflowResult.BSize() -
+ childRIForMeasuringBSize.ComputedLogicalBorderPadding().BStartEnd(wm);
+
+ return std::max(0, childDesiredBSize);
}
FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput,
float aFlexGrow, float aFlexShrink, nscoord aFlexBaseSize,
nscoord aMainMinSize, nscoord aMainMaxSize,
nscoord aTentativeCrossSize,
nscoord aCrossMinSize, nscoord aCrossMaxSize,
const FlexboxAxisTracker& aAxisTracker)
@@ -2024,25 +2032,38 @@ FlexItem::CanMainSizeInfluenceCrossSize(
if (HasIntrinsicRatio()) {
// For flex items that have an intrinsic ratio (and maintain it, i.e. are
// not stretched, which we already checked above): changes to main-size
// *do* influence the cross size.
return true;
}
- if (aAxisTracker.IsCrossAxisHorizontal()) {
- // If the cross axis is horizontal, then changes to the item's main size
- // (height) can't influence its cross size (width), if the item is a block
- // with a horizontal writing-mode.
- // XXXdholbert This doesn't account for vertical writing-modes, items with
- // aspect ratios, items that are multicol elements, & items that are
- // multi-line vertical flex containers. In all of those cases, a change to
- // the height could influence the width.
- return false;
+ if (IsInlineAxisCrossAxis()) {
+ // If we get here, this function is really asking: "can changes to this
+ // item's block size have an influence on its inline size"? For blocks and
+ // tables, the answer is "no".
+ if (mFrame->IsBlockFrame() ||
+ mFrame->IsTableWrapperFrame()) {
+ // XXXdholbert (Maybe use an IsFrameOfType query or something more
+ // general to test this across all frame types? For now, I'm just
+ // optimizing for block and table, since those are common containers that
+ // can contain arbitrarily-large subtrees (and that reliably have ISize
+ // being unaffected by BSize, per CSS2). So optimizing away needless
+ // relayout is possible & especially valuable for these containers.)
+ return false;
+ }
+ // Other opt-outs can go here, as they're identified as being useful
+ // (particularly for containers where an extra reflow is expensive). But in
+ // general, we have to assume that a flexed BSize *could* influence the
+ // ISize. Some examples where this can definitely happen:
+ // * Intrinsically-sized multicol with fixed-ISize columns, which adds
+ // columns (i.e. grows in inline axis) depending on its block size.
+ // * Intrinsically-sized multi-line column-oriented flex container, which
+ // adds flex lines (i.e. grows in inline axis) depending on its block size.
}
// Default assumption, if we haven't proven otherwise: the resolved main size
// *can* change the cross size.
return true;
}
// Keeps track of our position along a particular axis (where a '0' position
@@ -4004,72 +4025,65 @@ ComputePhysicalAscentFromFlexRelativeAsc
void
nsFlexContainerFrame::SizeItemInCrossAxis(
nsPresContext* aPresContext,
const FlexboxAxisTracker& aAxisTracker,
ReflowInput& aChildReflowInput,
FlexItem& aItem)
{
- if (aAxisTracker.IsCrossAxisHorizontal()) {
- MOZ_ASSERT(aItem.HasIntrinsicRatio(),
- "For now, caller's CanMainSizeInfluenceCrossSize check should "
- "only allow us to get here for items with intrinsic ratio");
- // XXXdholbert When we finish support for vertical writing-modes,
- // (in bug 1079155 or a dependency), we'll relax the horizontal check in
- // CanMainSizeInfluenceCrossSize, and this function will need to be able
- // to measure the baseline & width (given our resolved height)
- // of vertical-writing-mode flex items here.
- // For now, we only expect to get here for items with an intrinsic aspect
- // ratio; and for those items, we can just read the size off of the reflow
- // state, without performing reflow.
- aItem.SetCrossSize(aChildReflowInput.ComputedWidth());
+ // If cross axis is the item's inline axis, just use ISize from reflow state,
+ // and don't bother with a full reflow.
+ if (aItem.IsInlineAxisCrossAxis()) {
+ aItem.SetCrossSize(aChildReflowInput.ComputedISize());
return;
}
MOZ_ASSERT(!aItem.HadMeasuringReflow(),
"We shouldn't need more than one measuring reflow");
if (aItem.GetAlignSelf() == NS_STYLE_ALIGN_STRETCH) {
// This item's got "align-self: stretch", so we probably imposed a
- // stretched computed height on it during its previous reflow. We're
- // not imposing that height for *this* measuring reflow, so we need to
- // tell it to treat this reflow as a vertical resize (regardless of
- // whether any of its ancestors are being resized).
- aChildReflowInput.SetVResize(true);
+ // stretched computed cross-size on it during its previous
+ // reflow. We're not imposing that BSize for *this* "measuring" reflow, so
+ // we need to tell it to treat this reflow as a resize in its block axis
+ // (regardless of whether any of its ancestors are actually being resized).
+ // (Note: we know that the cross axis is the item's *block* axis -- if it
+ // weren't, then we would've taken the early-return above.)
+ aChildReflowInput.SetBResize(true);
}
// Potentially reflow the item, and get the sizing info.
const CachedMeasuringReflowResult& reflowResult =
- MeasureAscentAndHeightForFlexItem(aItem, aPresContext, aChildReflowInput);
+ MeasureAscentAndBSizeForFlexItem(aItem, aPresContext, aChildReflowInput);
// Save the sizing info that we learned from this reflow
// -----------------------------------------------------
// Tentatively store the child's desired content-box cross-size.
// Note that childDesiredSize is the border-box size, so we have to
// subtract border & padding to get the content-box size.
// (Note that at this point in the code, we know our cross axis is vertical,
// so we don't bother with making aAxisTracker pick the cross-axis component
// for us.)
nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom();
- if (reflowResult.Height() < crossAxisBorderPadding) {
+ if (reflowResult.BSize() < crossAxisBorderPadding) {
// Child's requested size isn't large enough for its border/padding!
// This is OK for the trivial nsFrame::Reflow() impl, but other frame
// classes should know better. So, if we get here, the child had better be
// an instance of nsFrame (i.e. it should return null from GetType()).
// XXXdholbert Once we've fixed bug 765861, we should upgrade this to an
// assertion that trivially passes if bug 765861's flag has been flipped.
NS_WARNING_ASSERTION(
aItem.Frame()->Type() == LayoutFrameType::None,
"Child should at least request space for border/padding");
aItem.SetCrossSize(0);
} else {
// (normal case)
- aItem.SetCrossSize(reflowResult.Height() - crossAxisBorderPadding);
+ aItem.SetCrossSize(reflowResult.BSize() - crossAxisBorderPadding);
}
aItem.SetAscent(reflowResult.Ascent());
}
void
FlexLine::PositionItemsInCrossAxis(nscoord aLineStartPosition,
const FlexboxAxisTracker& aAxisTracker)