mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1015474 part 1: Update behavior of "min-width:auto"/"min-height:auto" to match current spec text. r=mats
This updates min-width:auto / min-height:auto to now take several more things into account, beyond just a flex item's min-content size. Now we'll also consider its used 'flex-basis', its main max-size property ('max-width' or 'max-height'), and its intrinsic ratio & any constraints in the other dimension.
This commit is contained in:
parent
17b1051d8a
commit
2f8e9dec2a
@ -15,6 +15,7 @@
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRenderingContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "prlog.h"
|
||||
#include <algorithm>
|
||||
@ -271,7 +272,11 @@ public:
|
||||
nsIFrame* Frame() const { return mFrame; }
|
||||
nscoord GetFlexBaseSize() const { return mFlexBaseSize; }
|
||||
|
||||
nscoord GetMainMinSize() const { return mMainMinSize; }
|
||||
nscoord GetMainMinSize() const {
|
||||
MOZ_ASSERT(!mNeedsMinSizeAutoResolution,
|
||||
"Someone's using an unresolved 'auto' main min-size");
|
||||
return mMainMinSize;
|
||||
}
|
||||
nscoord GetMainMaxSize() const { return mMainMaxSize; }
|
||||
|
||||
// Note: These return the main-axis position and size of our *content box*.
|
||||
@ -322,6 +327,11 @@ public:
|
||||
// cross axis).
|
||||
bool IsStretched() const { return mIsStretched; }
|
||||
|
||||
// Indicates whether we need to resolve an 'auto' value for the main-axis
|
||||
// min-[width|height] property.
|
||||
bool NeedsMinSizeAutoResolution() const
|
||||
{ return mNeedsMinSizeAutoResolution; }
|
||||
|
||||
// Indicates whether this item is a "strut" left behind by an element with
|
||||
// visibility:collapse.
|
||||
bool IsStrut() const { return mIsStrut; }
|
||||
@ -417,21 +427,27 @@ public:
|
||||
|
||||
// Setters
|
||||
// =======
|
||||
|
||||
// Helper to set the resolved value of min-[width|height]:auto for the main
|
||||
// axis. (Should only be used if NeedsMinSizeAutoResolution() returns true.)
|
||||
void UpdateMainMinSize(nscoord aNewMinSize)
|
||||
{
|
||||
MOZ_ASSERT(mMainMinSize == 0 ||
|
||||
mFrame->IsThemed(mFrame->StyleDisplay()),
|
||||
"Should only update main min-size for min-height:auto, "
|
||||
"which would initially be resolved as 0 (unless we have an "
|
||||
"additional themed-widget-imposed minimum size)");
|
||||
NS_ASSERTION(aNewMinSize >= 0,
|
||||
"How did we end up with a negative min-size?");
|
||||
MOZ_ASSERT(mMainMaxSize >= aNewMinSize,
|
||||
"Should only use this function for resolving min-size:auto, "
|
||||
"and main max-size should be an upper-bound for resolved val");
|
||||
MOZ_ASSERT(mNeedsMinSizeAutoResolution &&
|
||||
(mMainMinSize == 0 || mFrame->IsThemed(mFrame->StyleDisplay())),
|
||||
"Should only use this function for resolving min-size:auto, "
|
||||
"so we shouldn't already have a nonzero min-size established "
|
||||
"(unless it's a themed-widget-imposed minimum size)");
|
||||
|
||||
if (aNewMinSize > mMainMinSize) {
|
||||
mMainMinSize = aNewMinSize;
|
||||
// Clamp main-max-size & main-size to be >= new min-size:
|
||||
mMainMaxSize = std::max(mMainMaxSize, aNewMinSize);
|
||||
// Also clamp main-size to be >= new min-size:
|
||||
mMainSize = std::max(mMainSize, aNewMinSize);
|
||||
}
|
||||
mNeedsMinSizeAutoResolution = false;
|
||||
}
|
||||
|
||||
// This sets our flex base size, and then sets our main size to the
|
||||
@ -539,6 +555,10 @@ public:
|
||||
uint32_t GetNumAutoMarginsInAxis(AxisOrientationType aAxis) const;
|
||||
|
||||
protected:
|
||||
// Helper called by the constructor, to set mNeedsMinSizeAutoResolution:
|
||||
void CheckForMinSizeAuto(const nsHTMLReflowState& aFlexItemReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker);
|
||||
|
||||
// Our frame:
|
||||
nsIFrame* const mFrame;
|
||||
|
||||
@ -582,6 +602,10 @@ protected:
|
||||
bool mIsStretched; // See IsStretched() documentation
|
||||
bool mIsStrut; // Is this item a "strut" left behind by an element
|
||||
// with visibility:collapse?
|
||||
|
||||
// Does this item need to resolve a min-[width|height]:auto (in main-axis).
|
||||
bool mNeedsMinSizeAutoResolution;
|
||||
|
||||
uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
|
||||
// swapped out for parent"s "align-items" value,
|
||||
// in our constructor).
|
||||
@ -1030,80 +1054,321 @@ nsFlexContainerFrame::GenerateFlexItemForChild(
|
||||
item->Freeze();
|
||||
}
|
||||
|
||||
// Resolve "flex-basis:auto" and/or "min-height:auto" (which might
|
||||
// Resolve "flex-basis:auto" and/or "min-[width|height]:auto" (which might
|
||||
// require us to reflow the item to measure content height)
|
||||
ResolveAutoFlexBasisAndMinSize(aPresContext, *item,
|
||||
aParentReflowState, aAxisTracker);
|
||||
|
||||
childRS, aAxisTracker);
|
||||
return item;
|
||||
}
|
||||
|
||||
// Static helper-functions for ResolveAutoFlexBasisAndMinSize():
|
||||
// -------------------------------------------------------------
|
||||
// Indicates whether the cross-size property is set to something definite.
|
||||
// The logic here should be similar to the logic for isAutoWidth/isAutoHeight
|
||||
// in nsLayoutUtils::ComputeSizeWithIntrinsicDimensions().
|
||||
static bool
|
||||
IsCrossSizeDefinite(const nsHTMLReflowState& aItemReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
const nsStylePosition* pos = aItemReflowState.mStylePosition;
|
||||
if (IsAxisHorizontal(aAxisTracker.GetCrossAxis())) {
|
||||
return pos->mWidth.GetUnit() != eStyleUnit_Auto;
|
||||
}
|
||||
// else, vertical. (We need to use IsAutoHeight() to catch e.g. %-height
|
||||
// applied to indefinite-height containing block, which counts as auto.)
|
||||
nscoord cbHeight = aItemReflowState.mCBReflowState->ComputedHeight();
|
||||
return !nsLayoutUtils::IsAutoHeight(pos->mHeight, cbHeight);
|
||||
}
|
||||
|
||||
// If aFlexItem has a definite cross size, this function returns it, for usage
|
||||
// (in combination with an intrinsic ratio) for resolving the item's main size
|
||||
// or main min-size.
|
||||
//
|
||||
// The parameter "aMinSizeFallback" indicates whether we should fall back to
|
||||
// returning the cross min-size, when the cross size is indefinite. (This param
|
||||
// should be set IFF the caller intends to resolve the main min-size.) If this
|
||||
// param is true, then this function is guaranteed to return a definite value
|
||||
// (i.e. not NS_AUTOHEIGHT, excluding cases where huge sizes are involved).
|
||||
//
|
||||
// XXXdholbert the min-size behavior here is based on my understanding in
|
||||
// http://lists.w3.org/Archives/Public/www-style/2014Jul/0053.html
|
||||
// If my understanding there ends up being wrong, we'll need to update this.
|
||||
static nscoord
|
||||
CrossSizeToUseWithRatio(const FlexItem& aFlexItem,
|
||||
const nsHTMLReflowState& aItemReflowState,
|
||||
bool aMinSizeFallback,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
if (aFlexItem.IsStretched()) {
|
||||
// Definite cross-size, imposed via 'align-self:stretch' & flex container.
|
||||
return aFlexItem.GetCrossSize();
|
||||
}
|
||||
|
||||
if (IsCrossSizeDefinite(aItemReflowState, aAxisTracker)) {
|
||||
// Definite cross size.
|
||||
return GET_CROSS_COMPONENT(aAxisTracker,
|
||||
aItemReflowState.ComputedWidth(),
|
||||
aItemReflowState.ComputedHeight());
|
||||
}
|
||||
|
||||
if (aMinSizeFallback) {
|
||||
// Indefinite cross-size, and we're resolving main min-size, so we'll fall
|
||||
// back to ussing the cross min-size (which should be definite).
|
||||
return GET_CROSS_COMPONENT(aAxisTracker,
|
||||
aItemReflowState.ComputedMinWidth(),
|
||||
aItemReflowState.ComputedMinHeight());
|
||||
}
|
||||
|
||||
// Indefinite cross-size.
|
||||
return NS_AUTOHEIGHT;
|
||||
}
|
||||
|
||||
// XXX This macro shamelessly stolen from nsLayoutUtils.cpp.
|
||||
// (Maybe it should be exposed via a nsLayoutUtils method?)
|
||||
#define MULDIV(a,b,c) (nscoord(int64_t(a) * int64_t(b) / int64_t(c)))
|
||||
|
||||
// Convenience function; returns a main-size, given a cross-size and an
|
||||
// intrinsic ratio. The intrinsic ratio must not have 0 in its cross-axis
|
||||
// component (or else we'll divide by 0).
|
||||
static nscoord
|
||||
MainSizeFromAspectRatio(nscoord aCrossSize,
|
||||
const nsSize& aIntrinsicRatio,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
MOZ_ASSERT(aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0,
|
||||
"Invalid ratio; will divide by 0! Caller should've checked...");
|
||||
|
||||
if (IsAxisHorizontal(aAxisTracker.GetCrossAxis())) {
|
||||
// cross axis horiz --> aCrossSize is a width. Converting to height.
|
||||
return MULDIV(aCrossSize, aIntrinsicRatio.height, aIntrinsicRatio.width);
|
||||
}
|
||||
// cross axis vert --> aCrossSize is a height. Converting to width.
|
||||
return MULDIV(aCrossSize, aIntrinsicRatio.width, aIntrinsicRatio.height);
|
||||
}
|
||||
|
||||
// Partially resolves "min-[width|height]:auto" and returns the resulting value.
|
||||
// By "partially", I mean we don't consider the min-content size (but we do
|
||||
// consider flex-basis, main max-size, and the intrinsic aspect ratio).
|
||||
// The caller is responsible for computing & considering the min-content size
|
||||
// in combination with the partially-resolved value that this function returns.
|
||||
//
|
||||
// Spec reference: http://dev.w3.org/csswg/css-flexbox/#min-size-auto
|
||||
static nscoord
|
||||
PartiallyResolveAutoMinSize(const FlexItem& aFlexItem,
|
||||
const nsHTMLReflowState& aItemReflowState,
|
||||
const nsSize& aIntrinsicRatio,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
MOZ_ASSERT(aFlexItem.NeedsMinSizeAutoResolution(),
|
||||
"only call for FlexItems that need min-size auto resolution");
|
||||
|
||||
nscoord minMainSize = nscoord_MAX; // Intentionally huge; we'll shrink it
|
||||
// from here, w/ std::min().
|
||||
|
||||
// We need the smallest of:
|
||||
// * the used flex-basis, if the computed flex-basis was 'auto':
|
||||
// XXXdholbert ('auto' might be renamed to 'main-size'; see bug 1032922)
|
||||
if (eStyleUnit_Auto ==
|
||||
aItemReflowState.mStylePosition->mFlexBasis.GetUnit() &&
|
||||
aFlexItem.GetFlexBaseSize() != NS_AUTOHEIGHT) {
|
||||
// NOTE: We skip this if the flex base size depends on content & isn't yet
|
||||
// resolved. This is OK, because the caller is responsible for computing
|
||||
// the min-content height and min()'ing it with the value we return, which
|
||||
// is equivalent to what would happen if we min()'d that at this point.
|
||||
minMainSize = std::min(minMainSize, aFlexItem.GetFlexBaseSize());
|
||||
}
|
||||
|
||||
// * the computed max-width (max-height), if that value is definite:
|
||||
nscoord maxSize =
|
||||
GET_MAIN_COMPONENT(aAxisTracker,
|
||||
aItemReflowState.ComputedMaxWidth(),
|
||||
aItemReflowState.ComputedMaxHeight());
|
||||
if (maxSize != NS_UNCONSTRAINEDSIZE) {
|
||||
minMainSize = std::min(minMainSize, maxSize);
|
||||
}
|
||||
|
||||
// * if the item has no intrinsic aspect ratio, its min-content size:
|
||||
// --- SKIPPING THIS IN THIS FUNCTION --- caller's responsibility.
|
||||
|
||||
// * if the item has an intrinsic aspect ratio, the width (height) calculated
|
||||
// from the aspect ratio and any definite size constraints in the opposite
|
||||
// dimension.
|
||||
if (aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0) {
|
||||
// We have a usable aspect ratio. (not going to divide by 0)
|
||||
const bool useMinSizeIfCrossSizeIsIndefinite = true;
|
||||
nscoord crossSizeToUseWithRatio =
|
||||
CrossSizeToUseWithRatio(aFlexItem, aItemReflowState,
|
||||
useMinSizeIfCrossSizeIsIndefinite,
|
||||
aAxisTracker);
|
||||
nscoord minMainSizeFromRatio =
|
||||
MainSizeFromAspectRatio(crossSizeToUseWithRatio,
|
||||
aIntrinsicRatio, aAxisTracker);
|
||||
minMainSize = std::min(minMainSize, minMainSizeFromRatio);
|
||||
}
|
||||
|
||||
return minMainSize;
|
||||
}
|
||||
|
||||
// Resolves flex-basis:auto, using the given intrinsic ratio and the flex
|
||||
// item's cross size. On success, updates the flex item with its resolved
|
||||
// flex-basis and returns true. On failure (e.g. if the ratio is invalid or
|
||||
// the cross-size is indefinite), returns false.
|
||||
static bool
|
||||
ResolveAutoFlexBasisFromRatio(FlexItem& aFlexItem,
|
||||
const nsHTMLReflowState& aItemReflowState,
|
||||
const nsSize& aIntrinsicRatio,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
MOZ_ASSERT(NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize(),
|
||||
"Should only be called to resolve an 'auto' flex-basis");
|
||||
// If the flex item has ...
|
||||
// - an intrinsic aspect ratio,
|
||||
// - a [used] flex-basis of 'main-size' [auto?] [We have this, if we're here.]
|
||||
// - a definite cross size
|
||||
// then the flex base size is calculated from its inner cross size and the
|
||||
// flex item’s intrinsic aspect ratio.
|
||||
if (aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0) {
|
||||
// We have a usable aspect ratio. (not going to divide by 0)
|
||||
const bool useMinSizeIfCrossSizeIsIndefinite = false;
|
||||
nscoord crossSizeToUseWithRatio =
|
||||
CrossSizeToUseWithRatio(aFlexItem, aItemReflowState,
|
||||
useMinSizeIfCrossSizeIsIndefinite,
|
||||
aAxisTracker);
|
||||
if (crossSizeToUseWithRatio != NS_AUTOHEIGHT) {
|
||||
// We have a definite cross-size
|
||||
nscoord mainSizeFromRatio =
|
||||
MainSizeFromAspectRatio(crossSizeToUseWithRatio,
|
||||
aIntrinsicRatio, aAxisTracker);
|
||||
aFlexItem.SetFlexBaseSizeAndMainSize(mainSizeFromRatio);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: If & when we handle "min-height: min-content" for flex items,
|
||||
// we may want to resolve that in this function, too.
|
||||
void
|
||||
nsFlexContainerFrame::
|
||||
ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
||||
FlexItem& aFlexItem,
|
||||
const nsHTMLReflowState& aParentReflowState,
|
||||
const nsHTMLReflowState& aItemReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
|
||||
// Nothing to do -- this function is only for measuring flex items
|
||||
// in a vertical flex container.
|
||||
return;
|
||||
}
|
||||
// (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 = (!IsAxisHorizontal(aAxisTracker.GetMainAxis()) &&
|
||||
NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
|
||||
|
||||
// Both "flex-basis:auto;height:auto" & "min-height:auto" require that we
|
||||
// resolve our max-content height.
|
||||
bool isMainSizeAuto = (NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
|
||||
|
||||
// 'min-height:auto' is treated as 0 in most code (e.g. in the reflow state),
|
||||
// so we have to actually go the source & check the style struct:
|
||||
bool isMainMinSizeAuto =
|
||||
(eStyleUnit_Auto ==
|
||||
aFlexItem.Frame()->StylePosition()->mMinHeight.GetUnit());
|
||||
const bool isMainMinSizeAuto = aFlexItem.NeedsMinSizeAutoResolution();
|
||||
|
||||
if (!isMainSizeAuto && !isMainMinSizeAuto) {
|
||||
// Nothing to do; this function's only relevant for flex items
|
||||
// with a base size of "auto" (or equivalent).
|
||||
// XXXdholbert If & when we handle "min-height: min-content" for flex items,
|
||||
// we'll want to resolve that in this function, too.
|
||||
// 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;
|
||||
}
|
||||
|
||||
// For single-line vertical flexbox, we need to give our flex items an early
|
||||
// opportunity to stretch, since any stretching of their cross-size (width)
|
||||
// will likely impact the max-content main-size (height) that we're about to
|
||||
// measure for them. (We can't do this for multi-line, since we don't know
|
||||
// yet how many lines there will be & how much each line will stretch.)
|
||||
if (NS_STYLE_FLEX_WRAP_NOWRAP ==
|
||||
aParentReflowState.mStylePosition->mFlexWrap) {
|
||||
aFlexItem.ResolveStretchedCrossSize(aParentReflowState.ComputedWidth(),
|
||||
aAxisTracker);
|
||||
// We may be about to do computations based on our item's cross-size
|
||||
// (e.g. using it as a contstraint when measuring our content in the
|
||||
// main axis, or using it with the intrinsic ratio to obtain a main size).
|
||||
// BEFORE WE DO THAT, we need let the item "pre-stretch" its cross size (if
|
||||
// it's got 'align-self:stretch'), for a certain case where the spec says
|
||||
// the stretched cross size is considered "definite". That case is if we
|
||||
// have a single-line (nowrap) flex container which itself has a definite
|
||||
// cross-size. Otherwise, we'll wait to do stretching, since (in other
|
||||
// cases) we don't know how much the item should stretch yet.
|
||||
const nsHTMLReflowState* flexContainerRS = aItemReflowState.parentReflowState;
|
||||
MOZ_ASSERT(flexContainerRS,
|
||||
"flex item's reflow state should have ptr to container's state");
|
||||
if (NS_STYLE_FLEX_WRAP_NOWRAP == flexContainerRS->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(aAxisTracker,
|
||||
flexContainerRS->ComputedWidth(),
|
||||
flexContainerRS->ComputedHeight());
|
||||
// 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 (IsAxisHorizontal(aAxisTracker.GetCrossAxis()) ||
|
||||
containerCrossSize != NS_AUTOHEIGHT) {
|
||||
aFlexItem.ResolveStretchedCrossSize(containerCrossSize, aAxisTracker);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 =
|
||||
!aFlexItem.IsFrozen() || // Is the item flexible?
|
||||
!isMainSizeAuto; // Are we *only* measuring it for 'min-height:auto'?
|
||||
// We'll need the intrinsic ratio (if there is one), regardless of whether
|
||||
// we're resolving min-[width|height]:auto or flex-basis:auto.
|
||||
const nsSize ratio = aFlexItem.Frame()->GetIntrinsicRatio();
|
||||
|
||||
nscoord contentHeight =
|
||||
MeasureFlexItemContentHeight(aPresContext, aFlexItem,
|
||||
forceVerticalResizeForMeasuringReflow,
|
||||
aParentReflowState);
|
||||
|
||||
if (isMainSizeAuto) {
|
||||
aFlexItem.SetFlexBaseSizeAndMainSize(contentHeight);
|
||||
}
|
||||
nscoord resolvedMinSize; // (only set/used if isMainMinSizeAuto==true)
|
||||
bool minSizeNeedsToMeasureContent = false; // assume the best
|
||||
if (isMainMinSizeAuto) {
|
||||
aFlexItem.UpdateMainMinSize(contentHeight);
|
||||
// Resolve the min-size, except for considering the min-content size.
|
||||
// (We'll consider that later, if we need to.)
|
||||
resolvedMinSize = PartiallyResolveAutoMinSize(aFlexItem, aItemReflowState,
|
||||
ratio, aAxisTracker);
|
||||
if (resolvedMinSize > 0 &&
|
||||
aAxisTracker.GetCrossComponent(ratio) == 0) {
|
||||
// We don't have a usable aspect ratio, so we need to consider our
|
||||
// min-content size as another candidate min-size, which we'll have to
|
||||
// min() with the current resolvedMinSize.
|
||||
// (If resolvedMinSize were already at 0, we could skip this measurement
|
||||
// because it can't go any lower. But it's not 0, so we need it.)
|
||||
minSizeNeedsToMeasureContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool flexBasisNeedsToMeasureContent = false; // assume the best
|
||||
if (isMainSizeAuto) {
|
||||
if (!ResolveAutoFlexBasisFromRatio(aFlexItem, aItemReflowState,
|
||||
ratio, aAxisTracker)) {
|
||||
flexBasisNeedsToMeasureContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Measure content, if needed (w/ intrinsic-width method or a reflow)
|
||||
if (minSizeNeedsToMeasureContent || flexBasisNeedsToMeasureContent) {
|
||||
if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
|
||||
nsRefPtr<nsRenderingContext> rctx =
|
||||
aPresContext->PresShell()->CreateReferenceRenderingContext();
|
||||
if (minSizeNeedsToMeasureContent) {
|
||||
resolvedMinSize = std::min(resolvedMinSize, aFlexItem.Frame()->GetMinWidth(rctx));
|
||||
}
|
||||
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 =
|
||||
!aFlexItem.IsFrozen() || // Is the item flexible?
|
||||
!flexBasisNeedsToMeasureContent; // Are we *only* measuring it for
|
||||
// 'min-height:auto'?
|
||||
|
||||
nscoord contentHeight =
|
||||
MeasureFlexItemContentHeight(aPresContext, aFlexItem,
|
||||
forceVerticalResizeForMeasuringReflow,
|
||||
*flexContainerRS);
|
||||
if (minSizeNeedsToMeasureContent) {
|
||||
resolvedMinSize = std::min(resolvedMinSize, contentHeight);
|
||||
}
|
||||
if (flexBasisNeedsToMeasureContent) {
|
||||
aFlexItem.SetFlexBaseSizeAndMainSize(contentHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isMainMinSizeAuto) {
|
||||
aFlexItem.UpdateMainMinSize(resolvedMinSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1183,6 +1448,7 @@ FlexItem::FlexItem(nsHTMLReflowState& aFlexItemReflowState,
|
||||
mHadMeasuringReflow(false),
|
||||
mIsStretched(false),
|
||||
mIsStrut(false),
|
||||
// mNeedsMinSizeAutoResolution is initialized in CheckForMinSizeAuto()
|
||||
mAlignSelf(aFlexItemReflowState.mStylePosition->mAlignSelf)
|
||||
{
|
||||
MOZ_ASSERT(mFrame, "expecting a non-null child frame");
|
||||
@ -1192,6 +1458,7 @@ FlexItem::FlexItem(nsHTMLReflowState& aFlexItemReflowState,
|
||||
"out-of-flow frames should not be treated as flex items");
|
||||
|
||||
SetFlexBaseSizeAndMainSize(aFlexBaseSize);
|
||||
CheckForMinSizeAuto(aFlexItemReflowState, aAxisTracker);
|
||||
|
||||
// Assert that any "auto" margin components are set to 0.
|
||||
// (We'll resolve them later; until then, we want to treat them as 0-sized.)
|
||||
@ -1256,6 +1523,7 @@ FlexItem::FlexItem(nsIFrame* aChildFrame, nscoord aCrossSize)
|
||||
mHadMeasuringReflow(false),
|
||||
mIsStretched(false),
|
||||
mIsStrut(true), // (this is the constructor for making struts, after all)
|
||||
mNeedsMinSizeAutoResolution(false),
|
||||
mAlignSelf(NS_STYLE_ALIGN_ITEMS_FLEX_START)
|
||||
{
|
||||
MOZ_ASSERT(mFrame, "expecting a non-null child frame");
|
||||
@ -1268,6 +1536,30 @@ FlexItem::FlexItem(nsIFrame* aChildFrame, nscoord aCrossSize)
|
||||
"out-of-flow frames should not be treated as flex items");
|
||||
}
|
||||
|
||||
void
|
||||
FlexItem::CheckForMinSizeAuto(const nsHTMLReflowState& aFlexItemReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker)
|
||||
{
|
||||
const nsStylePosition* pos = aFlexItemReflowState.mStylePosition;
|
||||
const nsStyleDisplay* disp = aFlexItemReflowState.mStyleDisplay;
|
||||
|
||||
// We'll need special behavior for "min-[width|height]:auto" (whichever is in
|
||||
// the main axis) iff:
|
||||
// (a) its computed value is "auto"
|
||||
// (b) the "overflow" sub-property in the same axis (the main axis) has a
|
||||
// computed value of "visible"
|
||||
const nsStyleCoord& minSize = GET_MAIN_COMPONENT(aAxisTracker,
|
||||
pos->mMinWidth,
|
||||
pos->mMinHeight);
|
||||
|
||||
const uint8_t overflowVal = GET_MAIN_COMPONENT(aAxisTracker,
|
||||
disp->mOverflowX,
|
||||
disp->mOverflowY);
|
||||
|
||||
mNeedsMinSizeAutoResolution = (minSize.GetUnit() == eStyleUnit_Auto &&
|
||||
overflowVal == NS_STYLE_OVERFLOW_VISIBLE);
|
||||
}
|
||||
|
||||
nscoord
|
||||
FlexItem::GetBaselineOffsetFromOuterCrossEdge(AxisOrientationType aCrossAxis,
|
||||
AxisEdgeType aEdge) const
|
||||
|
@ -140,7 +140,7 @@ protected:
|
||||
*/
|
||||
void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
||||
FlexItem& aFlexItem,
|
||||
const nsHTMLReflowState& aParentReflowState,
|
||||
const nsHTMLReflowState& aItemReflowState,
|
||||
const FlexboxAxisTracker& aAxisTracker);
|
||||
|
||||
// Creates FlexItems for all of our child frames, arranged in a list of
|
||||
|
@ -2595,18 +2595,11 @@ nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
|
||||
nscoord aContainingBlockHeight,
|
||||
const nsHTMLReflowState* aContainingBlockRS)
|
||||
{
|
||||
// Handle "min-width: auto"
|
||||
// NOTE: min-width:auto resolves to 0, except on a flex item. (But
|
||||
// even there, it's supposed to be ignored (i.e. treated as 0) until
|
||||
// the flex container explicitly resolves & considers it.)
|
||||
if (eStyleUnit_Auto == mStylePosition->mMinWidth.GetUnit()) {
|
||||
nsFlexContainerFrame* flexContainerFrame = GetFlexContainer(frame);
|
||||
if (flexContainerFrame && flexContainerFrame->IsHorizontal()) {
|
||||
ComputedMinWidth() =
|
||||
ComputeWidthValue(aContainingBlockWidth,
|
||||
mStylePosition->mBoxSizing,
|
||||
nsStyleCoord(NS_STYLE_WIDTH_MIN_CONTENT,
|
||||
eStyleUnit_Enumerated));
|
||||
} else {
|
||||
ComputedMinWidth() = 0;
|
||||
}
|
||||
ComputedMinWidth() = 0;
|
||||
} else {
|
||||
ComputedMinWidth() = ComputeWidthValue(aContainingBlockWidth,
|
||||
mStylePosition->mBoxSizing,
|
||||
@ -2635,10 +2628,9 @@ nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
|
||||
// Likewise, if we're a child of a flex container who's measuring our
|
||||
// intrinsic height, then we want to disregard our min-height.
|
||||
|
||||
// NOTE: We treat "min-height:auto" as "0" for the purpose of this code,
|
||||
// since that's what it means in all cases except for on flex items -- and
|
||||
// even there, we're supposed to ignore it (i.e. treat it as 0) until the
|
||||
// flex container explicitly considers it.
|
||||
// NOTE: min-height:auto resolves to 0, except on a flex item. (But
|
||||
// even there, it's supposed to be ignored (i.e. treated as 0) until
|
||||
// the flex container explicitly resolves & considers it.)
|
||||
const nsStyleCoord &minHeight = mStylePosition->mMinHeight;
|
||||
if (eStyleUnit_Auto == minHeight.GetUnit() ||
|
||||
(NS_AUTOHEIGHT == aContainingBlockHeight &&
|
||||
|
Loading…
Reference in New Issue
Block a user