Bug 1297774 - Implement safe/unsafe for flexbox 'justify-content' and 'align-{content,self,items}'
MozReview-Commit-ID: BHpaSvj5EOW
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -579,17 +579,18 @@ public:
// on which axes those callsites are reasoning about).
bool IsInlineAxisMainAxis() const { return mIsInlineAxisMainAxis; }
bool IsInlineAxisCrossAxis() const { return !mIsInlineAxisMainAxis; }
bool IsBlockAxisMainAxis() const { return !mIsInlineAxisMainAxis; }
bool IsBlockAxisCrossAxis() const { return mIsInlineAxisMainAxis; }
WritingMode GetWritingMode() const { return mWM; }
- uint8_t GetAlignSelf() const { return mAlignSelf; }
+ uint8_t GetAlignSelf() const { return mAlignSelf; }
+ uint8_t GetAlignSelfFlags() const { return mAlignSelfFlags; }
// Returns the flex factor (flex-grow or flex-shrink), depending on
// 'aIsUsingFlexGrow'.
//
// Asserts fatally if called on a frozen item (since frozen items are not
// flexible).
float GetFlexFactor(bool aIsUsingFlexGrow)
{
@@ -873,16 +874,17 @@ protected:
bool mNeedsMinSizeAutoResolution;
// Does this item have an auto margin in either main or cross axis?
bool mHasAnyAutoMargin;
uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
// swapped out for parent"s "align-items" value,
// in our constructor).
+ uint8_t mAlignSelfFlags; // Flags for 'align-self' (safe/unsafe/legacy)
};
/**
* Represents a single flex line in a flex container.
* Manages a linked list of the FlexItems that are in the line.
*/
class nsFlexContainerFrame::FlexLine : public LinkedListElement<FlexLine>
{
@@ -1936,17 +1938,18 @@ FlexItem::FlexItem(ReflowInput& aFlexIte
mAlignSelf = ConvertLegacyStyleToAlignItems(containerStyleXUL);
} else {
mAlignSelf = aFlexItemReflowInput.mStylePosition->UsedAlignSelf(
containerRS->mFrame->Style());
if (MOZ_LIKELY(mAlignSelf == NS_STYLE_ALIGN_NORMAL)) {
mAlignSelf = NS_STYLE_ALIGN_STRETCH;
}
- // XXX strip off the <overflow-position> bit until we implement that
+ // Store and strip off the <overflow-position> bits
+ mAlignSelfFlags = mAlignSelf & NS_STYLE_ALIGN_FLAG_BITS;
mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS;
}
SetFlexBaseSizeAndMainSize(aFlexBaseSize);
CheckForMinSizeAuto(aFlexItemReflowInput, aAxisTracker);
const nsStyleSides& styleMargin =
@@ -2918,42 +2921,48 @@ MainAxisPositionTracker::
nscoord aContentBoxMainSize)
: PositionTracker(aAxisTracker.GetMainAxis(),
aAxisTracker.IsMainAxisReversed()),
mPackingSpaceRemaining(aContentBoxMainSize), // we chip away at this below
mNumAutoMarginsInMainAxis(0),
mNumPackingSpacesRemaining(0),
mJustifyContent(aJustifyContent)
{
+ // Extract the flag portion of mJustifyContent and strip off the flag bits
+ uint8_t justifyContentFlags = mJustifyContent & NS_STYLE_JUSTIFY_FLAG_BITS;
+ mJustifyContent &= ~NS_STYLE_JUSTIFY_FLAG_BITS;
+
// 'normal' behaves as 'stretch', and 'stretch' behaves as 'flex-start',
// in the main axis
// https://drafts.csswg.org/css-align-3/#propdef-justify-content
if (mJustifyContent == NS_STYLE_JUSTIFY_NORMAL ||
mJustifyContent == NS_STYLE_JUSTIFY_STRETCH) {
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
}
- // XXX strip off the <overflow-position> bit until we implement that
- mJustifyContent &= ~NS_STYLE_JUSTIFY_FLAG_BITS;
-
// mPackingSpaceRemaining is initialized to the container's main size. Now
// we'll subtract out the main sizes of our flex items, so that it ends up
// with the *actual* amount of packing space.
for (const FlexItem* item = aLine->GetFirstItem(); item;
item = item->getNext()) {
mPackingSpaceRemaining -= item->GetOuterMainSize(mAxis);
mNumAutoMarginsInMainAxis += item->GetNumAutoMarginsInAxis(mAxis);
}
// Subtract space required for row/col gap from the remaining packing space
mPackingSpaceRemaining -= aLine->GetSumOfGaps();
if (mPackingSpaceRemaining <= 0) {
// No available packing space to use for resolving auto margins.
mNumAutoMarginsInMainAxis = 0;
+ // If packing space is negative and <overflow-position> is set to 'safe'
+ // all justify options fall back to 'start'
+ if (justifyContentFlags & NS_STYLE_JUSTIFY_SAFE) {
+ mJustifyContent = NS_STYLE_JUSTIFY_START;
+ }
}
// If packing space is negative or we only have one item, 'space-between'
// falls back to 'flex-start', and 'space-around' & 'space-evenly' fall back
// to 'center'. In those cases, it's simplest to just pretend we have a
// different 'justify-content' value and share code.
if (mPackingSpaceRemaining < 0 || aLine->NumItems() == 1) {
if (mJustifyContent == NS_STYLE_JUSTIFY_SPACE_BETWEEN) {
@@ -3099,24 +3108,25 @@ CrossAxisPositionTracker::
aAxisTracker.IsCrossAxisReversed()),
mPackingSpaceRemaining(0),
mNumPackingSpacesRemaining(0),
mAlignContent(aReflowInput.mStylePosition->mAlignContent),
mCrossGapSize(aCrossGapSize)
{
MOZ_ASSERT(aFirstLine, "null first line pointer");
+ // Extract and strip the flag bits from alignContent
+ uint8_t alignContentFlags = mAlignContent & NS_STYLE_ALIGN_FLAG_BITS;
+ mAlignContent &= ~NS_STYLE_ALIGN_FLAG_BITS;
+
// 'normal' behaves as 'stretch'
if (mAlignContent == NS_STYLE_ALIGN_NORMAL) {
mAlignContent = NS_STYLE_ALIGN_STRETCH;
}
- // XXX strip of the <overflow-position> bit until we implement that
- mAlignContent &= ~NS_STYLE_ALIGN_FLAG_BITS;
-
const bool isSingleLine =
NS_STYLE_FLEX_WRAP_NOWRAP == aReflowInput.mStylePosition->mFlexWrap;
if (isSingleLine) {
MOZ_ASSERT(!aFirstLine->getNext(),
"If we're styled as single-line, we should only have 1 line");
// "If the flex container is single-line and has a definite cross size, the
// cross size of the flex line is the flex container's inner cross size."
//
@@ -3153,16 +3163,23 @@ CrossAxisPositionTracker::
numLines++;
}
// Subtract space required for row/col gap from the remaining packing space
MOZ_ASSERT(numLines >= 1,
"GenerateFlexLines should've produced at least 1 line");
mPackingSpaceRemaining -= aCrossGapSize * (numLines - 1);
+ // If <overflow-position> is 'safe' and packing space is negative
+ // all align options fall back to 'start'
+ if ((alignContentFlags & NS_STYLE_ALIGN_SAFE) &&
+ mPackingSpaceRemaining < 0) {
+ mAlignContent = NS_STYLE_ALIGN_START;
+ }
+
// If packing space is negative, 'space-between' and 'stretch' behave like
// 'flex-start', and 'space-around' and 'space-evenly' behave like 'center'.
// In those cases, it's simplest to just pretend we have a different
// 'align-content' value and share code. (If we only have one line, all of
// the 'space-*' keywords fall back as well, but 'stretch' doesn't because
// even a single line can still stretch.)
if (mPackingSpaceRemaining < 0 && mAlignContent == NS_STYLE_ALIGN_STRETCH) {
mAlignContent = NS_STYLE_ALIGN_FLEX_START;
@@ -3511,16 +3528,24 @@ SingleLineCrossAxisPositionTracker::
if (aAxisTracker.AreAxesInternallyReversed()) {
if (alignSelf == NS_STYLE_ALIGN_FLEX_START) {
alignSelf = NS_STYLE_ALIGN_FLEX_END;
} else if (alignSelf == NS_STYLE_ALIGN_FLEX_END) {
alignSelf = NS_STYLE_ALIGN_FLEX_START;
}
}
+ // 'align-self' falls back to 'flex-start' if it is 'center'/'flex-end' and we
+ // have cross axis overflow
+ // XXX we should really be falling back to 'start' as of bug 1472843
+ if (aLine.GetLineCrossSize() < aItem.GetOuterCrossSize(mAxis) &&
+ (aItem.GetAlignSelfFlags() & NS_STYLE_ALIGN_SAFE)) {
+ alignSelf = NS_STYLE_ALIGN_FLEX_START;
+ }
+
switch (alignSelf) {
case NS_STYLE_ALIGN_SELF_START:
case NS_STYLE_ALIGN_SELF_END:
NS_WARNING("NYI: align-items/align-self:left/right/self-start/self-end");
MOZ_FALLTHROUGH;
case NS_STYLE_ALIGN_FLEX_START:
// No space to skip over -- we're done.
break;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-safe-overflow-position-001-ref.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0
+-->
+<html>
+<head>
+ <title>Reference: Testing safe overflow-position for align-content, justify-content, and align-items in flex containers</title>
+ <link rel="author" title="Mihir Iyer" href="mailto:miyer@mozilla.com">
+ <meta charset="utf-8">
+ <style>
+ .flex {
+ display: flex;
+ width: 85px;
+ height: 65px;
+ border: 1px solid black;
+ align-content: flex-end;
+ justify-content: center;
+ align-items: center;
+ float: left;
+ clear: both;
+ margin-top: 100px;
+ }
+ .rowNoWrap {
+ flex-flow: row nowrap;
+ }
+ .columnNoWrap {
+ flex-flow: column wrap;
+ }
+ .item {
+ border: 1px solid blue;
+ background: lightblue;
+ width: 28px;
+ height: 28px;
+ flex-shrink: 0;
+ }
+ .bigItem {
+ border: 1px solid blue;
+ background: lightblue;
+ width: 28px;
+ height: 90px;
+ flex-shrink: 0;
+ }
+ .alignContentStart {
+ align-content: start;
+ }
+ .justifyContentStart {
+ justify-content: start;
+ }
+ .alignSelfStart {
+ align-self: start;
+ }
+ </style>
+</head>
+<body>
+ <div class="flex rowNoWrap justifyContentStart">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="bigItem alignSelfStart"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="flex columnNoWrap alignContentStart">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-safe-overflow-position-001.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0
+-->
+<html>
+<head>
+ <title>CSS Test: Testing safe overflow-position for align-content, justify-content, and align-items in flex containers</title>
+ <link rel="author" title="Mihir Iyer" href="mailto:miyer@mozilla.com">
+ <link rel="help" href="https://drafts.csswg.org/css-align-3/#overflow-values">
+ <link rel="match" href="flexbox-safe-overflow-position-001-ref.html">
+ <meta charset="utf-8">
+ <style>
+ .flex {
+ display: flex;
+ width: 85px;
+ height: 65px;
+ border: 1px solid black;
+ align-content: safe flex-end;
+ justify-content: safe center;
+ align-items: safe center;
+ float: left;
+ clear: both;
+ margin-top: 100px;
+ }
+ .rowNoWrap {
+ flex-flow: row nowrap;
+ }
+ .columnNoWrap {
+ flex-flow: column wrap;
+ }
+ .item {
+ border: 1px solid blue;
+ background: lightblue;
+ width: 28px;
+ height: 28px;
+ flex-shrink: 0;
+ }
+ .bigItem {
+ border: 1px solid blue;
+ background: lightblue;
+ width: 28px;
+ height: 90px;
+ flex-shrink: 0;
+ }
+ </style>
+</head>
+<body>
+ <div class="flex rowNoWrap">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="bigItem"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+ <div class="flex columnNoWrap">
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ <div class="item"></div>
+ </div>
+</body>
+</html>
--- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list
+++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list
@@ -209,16 +209,19 @@ fails == flexbox-min-height-auto-002b.ht
== flexbox-paint-ordering-001.xhtml flexbox-paint-ordering-001-ref.xhtml
== flexbox-paint-ordering-002.xhtml flexbox-paint-ordering-002-ref.xhtml
== flexbox-paint-ordering-003.html flexbox-paint-ordering-003-ref.html
# Tests for "display:flex" on root node
== flexbox-root-node-001a.html flexbox-root-node-001-ref.html
== flexbox-root-node-001b.html flexbox-root-node-001-ref.html
+# Tests for <overflow-position> "safe" keyword in CSS Alignment properties
+== flexbox-safe-overflow-position-001.html flexbox-safe-overflow-position-001-ref.html
+
# Tests for sizing of flex containers, e.g. under min/max size constraints
== flexbox-sizing-horiz-001.xhtml flexbox-sizing-horiz-001-ref.xhtml
== flexbox-sizing-horiz-002.xhtml flexbox-sizing-horiz-002-ref.xhtml
== flexbox-sizing-vert-001.xhtml flexbox-sizing-vert-001-ref.xhtml
== flexbox-sizing-vert-002.xhtml flexbox-sizing-vert-002-ref.xhtml
# Tests for table-fixup *not happening* on direct children of a flex container
== flexbox-table-fixup-001.xhtml flexbox-table-fixup-001-ref.xhtml