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 "nsLayoutUtils.h"
|
||||||
#include "nsPlaceholderFrame.h"
|
#include "nsPlaceholderFrame.h"
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
|
#include "nsRenderingContext.h"
|
||||||
#include "nsStyleContext.h"
|
#include "nsStyleContext.h"
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -271,7 +272,11 @@ public:
|
|||||||
nsIFrame* Frame() const { return mFrame; }
|
nsIFrame* Frame() const { return mFrame; }
|
||||||
nscoord GetFlexBaseSize() const { return mFlexBaseSize; }
|
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; }
|
nscoord GetMainMaxSize() const { return mMainMaxSize; }
|
||||||
|
|
||||||
// Note: These return the main-axis position and size of our *content box*.
|
// Note: These return the main-axis position and size of our *content box*.
|
||||||
@ -322,6 +327,11 @@ public:
|
|||||||
// cross axis).
|
// cross axis).
|
||||||
bool IsStretched() const { return mIsStretched; }
|
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
|
// Indicates whether this item is a "strut" left behind by an element with
|
||||||
// visibility:collapse.
|
// visibility:collapse.
|
||||||
bool IsStrut() const { return mIsStrut; }
|
bool IsStrut() const { return mIsStrut; }
|
||||||
@ -417,21 +427,27 @@ public:
|
|||||||
|
|
||||||
// Setters
|
// 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)
|
void UpdateMainMinSize(nscoord aNewMinSize)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mMainMinSize == 0 ||
|
NS_ASSERTION(aNewMinSize >= 0,
|
||||||
mFrame->IsThemed(mFrame->StyleDisplay()),
|
"How did we end up with a negative min-size?");
|
||||||
"Should only update main min-size for min-height:auto, "
|
MOZ_ASSERT(mMainMaxSize >= aNewMinSize,
|
||||||
"which would initially be resolved as 0 (unless we have an "
|
"Should only use this function for resolving min-size:auto, "
|
||||||
"additional themed-widget-imposed minimum size)");
|
"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) {
|
if (aNewMinSize > mMainMinSize) {
|
||||||
mMainMinSize = aNewMinSize;
|
mMainMinSize = aNewMinSize;
|
||||||
// Clamp main-max-size & main-size to be >= new min-size:
|
// Also clamp main-size to be >= new min-size:
|
||||||
mMainMaxSize = std::max(mMainMaxSize, aNewMinSize);
|
|
||||||
mMainSize = std::max(mMainSize, aNewMinSize);
|
mMainSize = std::max(mMainSize, aNewMinSize);
|
||||||
}
|
}
|
||||||
|
mNeedsMinSizeAutoResolution = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This sets our flex base size, and then sets our main size to the
|
// 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;
|
uint32_t GetNumAutoMarginsInAxis(AxisOrientationType aAxis) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Helper called by the constructor, to set mNeedsMinSizeAutoResolution:
|
||||||
|
void CheckForMinSizeAuto(const nsHTMLReflowState& aFlexItemReflowState,
|
||||||
|
const FlexboxAxisTracker& aAxisTracker);
|
||||||
|
|
||||||
// Our frame:
|
// Our frame:
|
||||||
nsIFrame* const mFrame;
|
nsIFrame* const mFrame;
|
||||||
|
|
||||||
@ -582,6 +602,10 @@ protected:
|
|||||||
bool mIsStretched; // See IsStretched() documentation
|
bool mIsStretched; // See IsStretched() documentation
|
||||||
bool mIsStrut; // Is this item a "strut" left behind by an element
|
bool mIsStrut; // Is this item a "strut" left behind by an element
|
||||||
// with visibility:collapse?
|
// 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"
|
uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
|
||||||
// swapped out for parent"s "align-items" value,
|
// swapped out for parent"s "align-items" value,
|
||||||
// in our constructor).
|
// in our constructor).
|
||||||
@ -1030,80 +1054,321 @@ nsFlexContainerFrame::GenerateFlexItemForChild(
|
|||||||
item->Freeze();
|
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)
|
// require us to reflow the item to measure content height)
|
||||||
ResolveAutoFlexBasisAndMinSize(aPresContext, *item,
|
ResolveAutoFlexBasisAndMinSize(aPresContext, *item,
|
||||||
aParentReflowState, aAxisTracker);
|
childRS, aAxisTracker);
|
||||||
|
|
||||||
return item;
|
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
|
void
|
||||||
nsFlexContainerFrame::
|
nsFlexContainerFrame::
|
||||||
ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
||||||
FlexItem& aFlexItem,
|
FlexItem& aFlexItem,
|
||||||
const nsHTMLReflowState& aParentReflowState,
|
const nsHTMLReflowState& aItemReflowState,
|
||||||
const FlexboxAxisTracker& aAxisTracker)
|
const FlexboxAxisTracker& aAxisTracker)
|
||||||
{
|
{
|
||||||
if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
|
// (Note: We should never have a used flex-basis of "auto" if our main axis
|
||||||
// Nothing to do -- this function is only for measuring flex items
|
// is horizontal; width values should always be resolvable without reflow.)
|
||||||
// in a vertical flex container.
|
const bool isMainSizeAuto = (!IsAxisHorizontal(aAxisTracker.GetMainAxis()) &&
|
||||||
return;
|
NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
|
||||||
}
|
|
||||||
|
|
||||||
// Both "flex-basis:auto;height:auto" & "min-height:auto" require that we
|
const bool isMainMinSizeAuto = aFlexItem.NeedsMinSizeAutoResolution();
|
||||||
// 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());
|
|
||||||
|
|
||||||
if (!isMainSizeAuto && !isMainMinSizeAuto) {
|
if (!isMainSizeAuto && !isMainMinSizeAuto) {
|
||||||
// Nothing to do; this function's only relevant for flex items
|
// Nothing to do; this function is only needed for flex items
|
||||||
// with a base size of "auto" (or equivalent).
|
// with a used flex-basis of "auto" or a min-main-size of "auto".
|
||||||
// XXXdholbert If & when we handle "min-height: min-content" for flex items,
|
|
||||||
// we'll want to resolve that in this function, too.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For single-line vertical flexbox, we need to give our flex items an early
|
// We may be about to do computations based on our item's cross-size
|
||||||
// opportunity to stretch, since any stretching of their cross-size (width)
|
// (e.g. using it as a contstraint when measuring our content in the
|
||||||
// will likely impact the max-content main-size (height) that we're about to
|
// main axis, or using it with the intrinsic ratio to obtain a main size).
|
||||||
// measure for them. (We can't do this for multi-line, since we don't know
|
// BEFORE WE DO THAT, we need let the item "pre-stretch" its cross size (if
|
||||||
// yet how many lines there will be & how much each line will stretch.)
|
// it's got 'align-self:stretch'), for a certain case where the spec says
|
||||||
if (NS_STYLE_FLEX_WRAP_NOWRAP ==
|
// the stretched cross size is considered "definite". That case is if we
|
||||||
aParentReflowState.mStylePosition->mFlexWrap) {
|
// have a single-line (nowrap) flex container which itself has a definite
|
||||||
aFlexItem.ResolveStretchedCrossSize(aParentReflowState.ComputedWidth(),
|
// cross-size. Otherwise, we'll wait to do stretching, since (in other
|
||||||
aAxisTracker);
|
// 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
|
// We'll need the intrinsic ratio (if there is one), regardless of whether
|
||||||
// 'auto' min-height and our main-size is something else, then we assume
|
// we're resolving min-[width|height]:auto or flex-basis:auto.
|
||||||
// that the computed-height we're reflowing with now could be different
|
const nsSize ratio = aFlexItem.Frame()->GetIntrinsicRatio();
|
||||||
// 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'?
|
|
||||||
|
|
||||||
nscoord contentHeight =
|
nscoord resolvedMinSize; // (only set/used if isMainMinSizeAuto==true)
|
||||||
MeasureFlexItemContentHeight(aPresContext, aFlexItem,
|
bool minSizeNeedsToMeasureContent = false; // assume the best
|
||||||
forceVerticalResizeForMeasuringReflow,
|
|
||||||
aParentReflowState);
|
|
||||||
|
|
||||||
if (isMainSizeAuto) {
|
|
||||||
aFlexItem.SetFlexBaseSizeAndMainSize(contentHeight);
|
|
||||||
}
|
|
||||||
if (isMainMinSizeAuto) {
|
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),
|
mHadMeasuringReflow(false),
|
||||||
mIsStretched(false),
|
mIsStretched(false),
|
||||||
mIsStrut(false),
|
mIsStrut(false),
|
||||||
|
// mNeedsMinSizeAutoResolution is initialized in CheckForMinSizeAuto()
|
||||||
mAlignSelf(aFlexItemReflowState.mStylePosition->mAlignSelf)
|
mAlignSelf(aFlexItemReflowState.mStylePosition->mAlignSelf)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mFrame, "expecting a non-null child frame");
|
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");
|
"out-of-flow frames should not be treated as flex items");
|
||||||
|
|
||||||
SetFlexBaseSizeAndMainSize(aFlexBaseSize);
|
SetFlexBaseSizeAndMainSize(aFlexBaseSize);
|
||||||
|
CheckForMinSizeAuto(aFlexItemReflowState, aAxisTracker);
|
||||||
|
|
||||||
// Assert that any "auto" margin components are set to 0.
|
// 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.)
|
// (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),
|
mHadMeasuringReflow(false),
|
||||||
mIsStretched(false),
|
mIsStretched(false),
|
||||||
mIsStrut(true), // (this is the constructor for making struts, after all)
|
mIsStrut(true), // (this is the constructor for making struts, after all)
|
||||||
|
mNeedsMinSizeAutoResolution(false),
|
||||||
mAlignSelf(NS_STYLE_ALIGN_ITEMS_FLEX_START)
|
mAlignSelf(NS_STYLE_ALIGN_ITEMS_FLEX_START)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mFrame, "expecting a non-null child frame");
|
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");
|
"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
|
nscoord
|
||||||
FlexItem::GetBaselineOffsetFromOuterCrossEdge(AxisOrientationType aCrossAxis,
|
FlexItem::GetBaselineOffsetFromOuterCrossEdge(AxisOrientationType aCrossAxis,
|
||||||
AxisEdgeType aEdge) const
|
AxisEdgeType aEdge) const
|
||||||
|
@ -140,7 +140,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
||||||
FlexItem& aFlexItem,
|
FlexItem& aFlexItem,
|
||||||
const nsHTMLReflowState& aParentReflowState,
|
const nsHTMLReflowState& aItemReflowState,
|
||||||
const FlexboxAxisTracker& aAxisTracker);
|
const FlexboxAxisTracker& aAxisTracker);
|
||||||
|
|
||||||
// Creates FlexItems for all of our child frames, arranged in a list of
|
// Creates FlexItems for all of our child frames, arranged in a list of
|
||||||
|
@ -2595,18 +2595,11 @@ nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
|
|||||||
nscoord aContainingBlockHeight,
|
nscoord aContainingBlockHeight,
|
||||||
const nsHTMLReflowState* aContainingBlockRS)
|
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()) {
|
if (eStyleUnit_Auto == mStylePosition->mMinWidth.GetUnit()) {
|
||||||
nsFlexContainerFrame* flexContainerFrame = GetFlexContainer(frame);
|
ComputedMinWidth() = 0;
|
||||||
if (flexContainerFrame && flexContainerFrame->IsHorizontal()) {
|
|
||||||
ComputedMinWidth() =
|
|
||||||
ComputeWidthValue(aContainingBlockWidth,
|
|
||||||
mStylePosition->mBoxSizing,
|
|
||||||
nsStyleCoord(NS_STYLE_WIDTH_MIN_CONTENT,
|
|
||||||
eStyleUnit_Enumerated));
|
|
||||||
} else {
|
|
||||||
ComputedMinWidth() = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ComputedMinWidth() = ComputeWidthValue(aContainingBlockWidth,
|
ComputedMinWidth() = ComputeWidthValue(aContainingBlockWidth,
|
||||||
mStylePosition->mBoxSizing,
|
mStylePosition->mBoxSizing,
|
||||||
@ -2635,10 +2628,9 @@ nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
|
|||||||
// Likewise, if we're a child of a flex container who's measuring our
|
// Likewise, if we're a child of a flex container who's measuring our
|
||||||
// intrinsic height, then we want to disregard our min-height.
|
// intrinsic height, then we want to disregard our min-height.
|
||||||
|
|
||||||
// NOTE: We treat "min-height:auto" as "0" for the purpose of this code,
|
// NOTE: min-height:auto resolves to 0, except on a flex item. (But
|
||||||
// since that's what it means in all cases except for on flex items -- and
|
// even there, it's supposed to be ignored (i.e. treated as 0) until
|
||||||
// even there, we're supposed to ignore it (i.e. treat it as 0) until the
|
// the flex container explicitly resolves & considers it.)
|
||||||
// flex container explicitly considers it.
|
|
||||||
const nsStyleCoord &minHeight = mStylePosition->mMinHeight;
|
const nsStyleCoord &minHeight = mStylePosition->mMinHeight;
|
||||||
if (eStyleUnit_Auto == minHeight.GetUnit() ||
|
if (eStyleUnit_Auto == minHeight.GetUnit() ||
|
||||||
(NS_AUTOHEIGHT == aContainingBlockHeight &&
|
(NS_AUTOHEIGHT == aContainingBlockHeight &&
|
||||||
|
Loading…
Reference in New Issue
Block a user