Bug 1176782 part 3 - [css-align] Implement additional syntax and values for the 'justify-content' property in the style system. r=cam
authorMats Palmgren <mats@mozilla.com>
Tue, 03 Nov 2015 15:18:05 +0100
changeset 270938 4ea55ddf4b4108f4f6770502a8fad8eacf322126
parent 270937 6fb17e670a082fed169a6ca1d26f1e362295800d
child 270939 b191efb0028a523d18c0db431959be4ce197d8b8
push id67508
push usermpalmgren@mozilla.com
push dateTue, 03 Nov 2015 14:18:18 +0000
treeherdermozilla-inbound@56aebef6afdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscam
bugs1176782
milestone45.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
Bug 1176782 part 3 - [css-align] Implement additional syntax and values for the 'justify-content' property in the style system. r=cam
layout/generic/nsFlexContainerFrame.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsCSSValue.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleConsts.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -3770,17 +3770,19 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
           contentBoxCrossSize, aReflowState, aAxisTracker);
     }
   }
 
   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
 
     // Main-Axis Alignment - Flexbox spec section 9.5
     // ==============================================
-    line->PositionItemsInMainAxis(aReflowState.mStylePosition->mJustifyContent,
+    auto justifyContent =
+      aReflowState.mStylePosition->ComputedJustifyContent(aReflowState.mStyleDisplay);
+    line->PositionItemsInMainAxis(justifyContent,
                                   aContentBoxMainSize,
                                   aAxisTracker);
 
     // Cross-Axis Alignment - Flexbox spec section 9.6
     // ===============================================
     line->PositionItemsInCrossAxis(crossAxisPosnTracker.GetPosition(),
                                    aAxisTracker);
     crossAxisPosnTracker.TraverseLine(*line);
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -935,16 +935,18 @@ protected:
                           nsCSSProperty aEndPropID);
   bool ParseGridArea();
 
   // parsing 'align/justify-items/self' from the css-align spec
   bool ParseAlignJustifyPosition(nsCSSValue& aResult,
                                  const KTableValue aTable[]);
   bool ParseJustifyItems();
   bool ParseJustifySelf();
+  // parsing 'align/justify-content' from the css-align spec
+  bool ParseAlignJustifyContent(nsCSSProperty aPropID);
 
   // for 'clip' and '-moz-image-region'
   bool ParseRect(nsCSSProperty aPropID);
   bool ParseColumns();
   bool ParseContain(nsCSSValue& aValue);
   bool ParseContent();
   bool ParseCounterData(nsCSSProperty aPropID);
   bool ParseCursor();
@@ -9462,16 +9464,56 @@ CSSParserImpl::ParseJustifySelf()
         return false;
       }
     }
   }
   AppendValue(eCSSProperty_justify_self, value);
   return true;
 }
 
+// auto | <baseline-position> | [ <content-distribution> ||
+//   [ <overflow-position>? && <content-position> ] ]
+// (the part after the || is called <*-position> below)
+bool
+CSSParserImpl::ParseAlignJustifyContent(nsCSSProperty aPropID)
+{
+  nsCSSValue value;
+  if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
+    if (!ParseEnum(value, nsCSSProps::kAlignAutoBaseline)) {
+      nsCSSValue fallbackValue;
+      if (!ParseEnum(value, nsCSSProps::kAlignContentDistribution)) {
+        if (!ParseAlignJustifyPosition(fallbackValue,
+                                       nsCSSProps::kAlignContentPosition) ||
+            fallbackValue.GetUnit() == eCSSUnit_Null) {
+          return false;
+        }
+        // optional <content-distribution> after <*-position> ...
+        if (!ParseEnum(value, nsCSSProps::kAlignContentDistribution)) {
+          // ... is missing so the <*-position> is the value, not the fallback
+          value = fallbackValue;
+          fallbackValue.Reset();
+        }
+      } else {
+        // any optional <*-position> is a fallback value
+        if (!ParseAlignJustifyPosition(fallbackValue,
+                                       nsCSSProps::kAlignContentPosition)) {
+          return false;
+        }
+      }
+      if (fallbackValue.GetUnit() != eCSSUnit_Null) {
+        auto fallback = fallbackValue.GetIntValue();
+        value.SetIntValue(value.GetIntValue() | (fallback << 8),
+                          eCSSUnit_Enumerated);
+      }
+    }
+  }
+  AppendValue(aPropID, value);
+  return true;
+}
+
 // <color-stop> : <color> [ <percentage> | <length> ]?
 bool
 CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient)
 {
   nsCSSValueGradientStop* stop = aGradient->mStops.AppendElement();
   CSSParseResult result = ParseVariant(stop->mColor, VARIANT_COLOR, nullptr);
   if (result == CSSParseResult::Error) {
     return false;
@@ -10585,16 +10627,18 @@ CSSParserImpl::ParsePropertyByFunction(n
                               eCSSProperty_grid_column_end);
   case eCSSProperty_grid_row:
     return ParseGridColumnRow(eCSSProperty_grid_row_start,
                               eCSSProperty_grid_row_end);
   case eCSSProperty_grid_area:
     return ParseGridArea();
   case eCSSProperty_image_region:
     return ParseRect(eCSSProperty_image_region);
+  case eCSSProperty_justify_content:
+    return ParseAlignJustifyContent(aPropID);
   case eCSSProperty_justify_items:
     return ParseJustifyItems();
   case eCSSProperty_justify_self:
     return ParseJustifySelf();
   case eCSSProperty_list_style:
     return ParseListStyle();
   case eCSSProperty_margin:
     return ParseMargin();
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -1696,22 +1696,22 @@ CSS_PROP_POSITION(
     VARIANT_HI,
     nullptr,
     offsetof(nsStylePosition, mOrder),
     eStyleAnimType_Custom) // <integer>
 CSS_PROP_POSITION(
     justify-content,
     justify_content,
     JustifyContent,
-    CSS_PROPERTY_PARSE_VALUE,
-    "",
-    VARIANT_HK,
-    kJustifyContentKTable,
-    offsetof(nsStylePosition, mJustifyContent),
-    eStyleAnimType_EnumU8)
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "",
+    0,
+    nullptr,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_POSITION(
     justify-items,
     justify_items,
     JustifyItems,
     CSS_PROPERTY_PARSE_FUNCTION,
     "",
     0,
     nullptr,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1299,16 +1299,42 @@ const KTableValue nsCSSProps::kAlignLega
 const KTableValue nsCSSProps::kAlignAutoStretchBaseline[] = {
   eCSSKeyword_auto,          NS_STYLE_ALIGN_AUTO,
   eCSSKeyword_stretch,       NS_STYLE_ALIGN_STRETCH,
   eCSSKeyword_baseline,      NS_STYLE_ALIGN_BASELINE,
   eCSSKeyword_last_baseline, NS_STYLE_ALIGN_LAST_BASELINE,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const KTableValue nsCSSProps::kAlignAutoBaseline[] = {
+  eCSSKeyword_auto,          NS_STYLE_ALIGN_AUTO,
+  eCSSKeyword_baseline,      NS_STYLE_ALIGN_BASELINE,
+  eCSSKeyword_last_baseline, NS_STYLE_ALIGN_LAST_BASELINE,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+const KTableValue nsCSSProps::kAlignContentDistribution[] = {
+  eCSSKeyword_stretch,       NS_STYLE_ALIGN_STRETCH,
+  eCSSKeyword_space_between, NS_STYLE_ALIGN_SPACE_BETWEEN,
+  eCSSKeyword_space_around,  NS_STYLE_ALIGN_SPACE_AROUND,
+  eCSSKeyword_space_evenly,  NS_STYLE_ALIGN_SPACE_EVENLY,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+const KTableValue nsCSSProps::kAlignContentPosition[] = {
+  eCSSKeyword_start,         NS_STYLE_ALIGN_START,
+  eCSSKeyword_end,           NS_STYLE_ALIGN_END,
+  eCSSKeyword_flex_start,    NS_STYLE_ALIGN_FLEX_START,
+  eCSSKeyword_flex_end,      NS_STYLE_ALIGN_FLEX_END,
+  eCSSKeyword_center,        NS_STYLE_ALIGN_CENTER,
+  eCSSKeyword_left,          NS_STYLE_ALIGN_LEFT,
+  eCSSKeyword_right,         NS_STYLE_ALIGN_RIGHT,
+  eCSSKeyword_UNKNOWN,-1
+};
+
 const KTableValue nsCSSProps::kAlignContentKTable[] = {
   eCSSKeyword_flex_start,    NS_STYLE_ALIGN_CONTENT_FLEX_START,
   eCSSKeyword_flex_end,      NS_STYLE_ALIGN_CONTENT_FLEX_END,
   eCSSKeyword_center,        NS_STYLE_ALIGN_CONTENT_CENTER,
   eCSSKeyword_space_between, NS_STYLE_ALIGN_CONTENT_SPACE_BETWEEN,
   eCSSKeyword_space_around,  NS_STYLE_ALIGN_CONTENT_SPACE_AROUND,
   eCSSKeyword_stretch,       NS_STYLE_ALIGN_CONTENT_STRETCH,
   eCSSKeyword_UNKNOWN,-1
@@ -1351,25 +1377,16 @@ const KTableValue nsCSSProps::kFlexWrapK
 
 const KTableValue nsCSSProps::kHyphensKTable[] = {
   eCSSKeyword_none, NS_STYLE_HYPHENS_NONE,
   eCSSKeyword_manual, NS_STYLE_HYPHENS_MANUAL,
   eCSSKeyword_auto, NS_STYLE_HYPHENS_AUTO,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const KTableValue nsCSSProps::kJustifyContentKTable[] = {
-  eCSSKeyword_flex_start,    NS_STYLE_JUSTIFY_CONTENT_FLEX_START,
-  eCSSKeyword_flex_end,      NS_STYLE_JUSTIFY_CONTENT_FLEX_END,
-  eCSSKeyword_center,        NS_STYLE_JUSTIFY_CONTENT_CENTER,
-  eCSSKeyword_space_between, NS_STYLE_JUSTIFY_CONTENT_SPACE_BETWEEN,
-  eCSSKeyword_space_around,  NS_STYLE_JUSTIFY_CONTENT_SPACE_AROUND,
-  eCSSKeyword_UNKNOWN,-1
-};
-
 const KTableValue nsCSSProps::kFloatKTable[] = {
   eCSSKeyword_none,  NS_STYLE_FLOAT_NONE,
   eCSSKeyword_left,  NS_STYLE_FLOAT_LEFT,
   eCSSKeyword_right, NS_STYLE_FLOAT_RIGHT,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kFloatEdgeKTable[] = {
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -690,16 +690,19 @@ public:
   static const KTableValue kEmptyCellsKTable[];
   // -- tables for the align-/justify-content/items/self properties --
   static const KTableValue kAlignAllKeywords[];
   static const KTableValue kAlignOverflowPosition[]; // <overflow-position>
   static const KTableValue kAlignSelfPosition[];     // <self-position>
   static const KTableValue kAlignLegacy[];           // 'legacy'
   static const KTableValue kAlignLegacyPosition[];   // 'left/right/center'
   static const KTableValue kAlignAutoStretchBaseline[]; // 'auto/stretch/baseline/last-baseline'
+  static const KTableValue kAlignAutoBaseline[]; // 'auto/baseline/last-baseline'
+  static const KTableValue kAlignContentDistribution[]; // <content-distribution>
+  static const KTableValue kAlignContentPosition[]; // <content-position>
   static const KTableValue kAlignContentKTable[];
   static const KTableValue kAlignItemsKTable[];
   static const KTableValue kAlignSelfKTable[];
   static const KTableValue kJustifyContentKTable[];
   // ------------------------------------------------------------------
   static const KTableValue kFlexDirectionKTable[];
   static const KTableValue kFlexWrapKTable[];
   static const KTableValue kFloatKTable[];
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1016,16 +1016,21 @@ nsCSSValue::AppendAlignJustifyValueToStr
   if (legacy) {
     aValue &= ~legacy;
     aResult.AppendLiteral("legacy ");
   }
   auto overflowPos = aValue & (NS_STYLE_ALIGN_SAFE | NS_STYLE_ALIGN_TRUE);
   aValue &= ~overflowPos;
   MOZ_ASSERT(!(aValue & NS_STYLE_ALIGN_FLAG_BITS),
              "unknown bits in align/justify value");
+  MOZ_ASSERT((aValue != NS_STYLE_ALIGN_AUTO &&
+              aValue != NS_STYLE_ALIGN_BASELINE &&
+              aValue != NS_STYLE_ALIGN_LAST_BASELINE) ||
+             (!legacy && !overflowPos),
+             "auto/baseline/last-baseline never have any flags");
   const auto& kwtable(nsCSSProps::kAlignAllKeywords);
   AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(aValue, kwtable), aResult);
   if (MOZ_UNLIKELY(overflowPos != 0)) {
     MOZ_ASSERT(legacy == 0, "'legacy' together with <overflow-position>");
     aResult.Append(' ');
     AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(overflowPos, kwtable),
                        aResult);
   }
@@ -1312,16 +1317,29 @@ nsCSSValue::AppendToString(nsCSSProperty
       }
       nsStyleUtil::AppendBitmaskCSSValue(aProperty,
                                          intValue,
                                          NS_STYLE_CONTAIN_STRICT,
                                          NS_STYLE_CONTAIN_PAINT,
                                          aResult);
       break;
 
+    case eCSSProperty_justify_content: {
+      AppendAlignJustifyValueToString(intValue & NS_STYLE_ALIGN_ALL_BITS, aResult);
+      auto fallback = intValue >> NS_STYLE_ALIGN_ALL_SHIFT;
+      if (fallback) {
+        MOZ_ASSERT(nsCSSProps::ValueToKeywordEnum(fallback & ~NS_STYLE_ALIGN_FLAG_BITS,
+                                                  nsCSSProps::kAlignSelfPosition)
+                   != eCSSKeyword_UNKNOWN, "unknown fallback value");
+        aResult.Append(' ');
+        AppendAlignJustifyValueToString(fallback, aResult);
+      }
+      break;
+    }
+
     case eCSSProperty_justify_items:
     case eCSSProperty_justify_self:
       AppendAlignJustifyValueToString(intValue, aResult);
       break;
 
     default:
       const nsAFlatCString& name = nsCSSProps::LookupPropertyValue(aProperty, intValue);
       AppendASCIItoUTF16(name, aResult);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3970,19 +3970,28 @@ nsComputedDOMStyle::DoGetOrder()
   val->SetNumber(StylePosition()->mOrder);
   return val;
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetJustifyContent()
 {
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
-  val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StylePosition()->mJustifyContent,
-                                   nsCSSProps::kJustifyContentKTable));
+  nsAutoString str;
+  auto justify = StylePosition()->ComputedJustifyContent(StyleDisplay());
+  nsCSSValue::AppendAlignJustifyValueToString(justify & NS_STYLE_JUSTIFY_ALL_BITS, str);
+  auto fallback = justify >> NS_STYLE_JUSTIFY_ALL_SHIFT;
+  if (fallback) {
+    MOZ_ASSERT(nsCSSProps::ValueToKeywordEnum(fallback & ~NS_STYLE_JUSTIFY_FLAG_BITS,
+                                              nsCSSProps::kAlignSelfPosition)
+               != eCSSKeyword_UNKNOWN, "unknown fallback value");
+    str.Append(' ');
+    nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
+  }
+  val->SetString(str);
   return val;
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetJustifyItems()
 {
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
   nsAutoString str;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7854,16 +7854,34 @@ nsRuleNode::ComputePositionData(void* aS
     SetDiscrete(*aRuleData->ValueForAlignSelf(),
                 pos->mAlignSelf, conditions,
                 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
                 parentPos->mAlignSelf, // (unused -- we handled inherit above)
                 NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
                 0, 0, 0, 0);
   }
 
+  // justify-content: enum, inherit, initial
+  const auto& justifyContentValue = *aRuleData->ValueForJustifyContent();
+  if (MOZ_UNLIKELY(justifyContentValue.GetUnit() == eCSSUnit_Inherit)) {
+    if (MOZ_LIKELY(parentContext)) {
+      pos->mJustifyContent =
+        parentPos->ComputedJustifyContent(parentContext->StyleDisplay());
+    } else {
+      pos->mJustifyContent = NS_STYLE_JUSTIFY_AUTO;
+    }
+    conditions.SetUncacheable();
+  } else {
+    SetDiscrete(justifyContentValue,
+                pos->mJustifyContent, conditions,
+                SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+                parentPos->mJustifyContent, // unused, we handle 'inherit' above
+                NS_STYLE_JUSTIFY_AUTO, 0, 0, 0, 0);
+  }
+
   // justify-items: enum, inherit, initial
   const auto& justifyItemsValue = *aRuleData->ValueForJustifyItems();
   if (MOZ_UNLIKELY(justifyItemsValue.GetUnit() == eCSSUnit_Inherit)) {
     if (MOZ_LIKELY(parentContext)) {
       pos->mJustifyItems =
         parentPos->ComputedJustifyItems(parentContext->StyleDisplay(),
                                         parentContext);
     } else {
@@ -7936,23 +7954,16 @@ nsRuleNode::ComputePositionData(void* aS
 
   // order: integer, inherit, initial
   SetDiscrete(*aRuleData->ValueForOrder(),
               pos->mOrder, conditions,
               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
               parentPos->mOrder,
               NS_STYLE_ORDER_INITIAL, 0, 0, 0, 0);
 
-  // justify-content: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForJustifyContent(),
-              pos->mJustifyContent, conditions,
-              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
-              parentPos->mJustifyContent,
-              NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0);
-
   // object-fit: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForObjectFit(),
               pos->mObjectFit, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mObjectFit,
               NS_STYLE_OBJECT_FIT_FILL, 0, 0, 0, 0);
 
   // object-position
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -553,22 +553,22 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_FLEX_WRAP_WRAP                 1
 #define NS_STYLE_FLEX_WRAP_WRAP_REVERSE         2
 
 // See nsStylePosition
 // NOTE: This is the initial value of the integer-valued 'order' property
 // (rather than an internal numerical representation of some keyword).
 #define NS_STYLE_ORDER_INITIAL                  0
 
-// See nsStylePosition
-#define NS_STYLE_JUSTIFY_CONTENT_FLEX_START     0
-#define NS_STYLE_JUSTIFY_CONTENT_FLEX_END       1
-#define NS_STYLE_JUSTIFY_CONTENT_CENTER         2
-#define NS_STYLE_JUSTIFY_CONTENT_SPACE_BETWEEN  3
-#define NS_STYLE_JUSTIFY_CONTENT_SPACE_AROUND   4
+// XXX remove in a later patch after updating flexbox code with the new names
+#define NS_STYLE_JUSTIFY_CONTENT_FLEX_START     NS_STYLE_JUSTIFY_FLEX_START
+#define NS_STYLE_JUSTIFY_CONTENT_FLEX_END       NS_STYLE_JUSTIFY_FLEX_END
+#define NS_STYLE_JUSTIFY_CONTENT_CENTER         NS_STYLE_JUSTIFY_CENTER
+#define NS_STYLE_JUSTIFY_CONTENT_SPACE_BETWEEN  NS_STYLE_JUSTIFY_SPACE_BETWEEN
+#define NS_STYLE_JUSTIFY_CONTENT_SPACE_AROUND   NS_STYLE_JUSTIFY_SPACE_AROUND
 
 // See nsStyleDisplay
 #define NS_STYLE_FLOAT_NONE                     0
 #define NS_STYLE_FLOAT_LEFT                     1
 #define NS_STYLE_FLOAT_RIGHT                    2
 
 // See nsStyleClipPath
 #define NS_STYLE_CLIP_PATH_NONE                 0
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1429,21 +1429,21 @@ nsStylePosition::nsStylePosition(void)
   mGridAutoRowsMin.SetAutoValue();
   mGridAutoRowsMax.SetAutoValue();
 
   mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
   mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
   mAlignContent = NS_STYLE_ALIGN_CONTENT_STRETCH;
   mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
   mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO;
+  mJustifyContent = NS_STYLE_JUSTIFY_AUTO;
   mJustifyItems = NS_STYLE_JUSTIFY_AUTO;
   mJustifySelf = NS_STYLE_JUSTIFY_AUTO;
   mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW;
   mFlexWrap = NS_STYLE_FLEX_WRAP_NOWRAP;
-  mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START;
   mObjectFit = NS_STYLE_OBJECT_FIT_FILL;
   mOrder = NS_STYLE_ORDER_INITIAL;
   mFlexGrow = 0.0f;
   mFlexShrink = 1.0f;
   mZIndex.SetAutoValue();
   // Other members get their default constructors
   // which initialize them to representations of their respective initial value.
   // mGridTemplateAreas: nullptr for 'none'
@@ -1470,21 +1470,21 @@ nsStylePosition::nsStylePosition(const n
   , mGridAutoColumnsMax(aSource.mGridAutoColumnsMax)
   , mGridAutoRowsMin(aSource.mGridAutoRowsMin)
   , mGridAutoRowsMax(aSource.mGridAutoRowsMax)
   , mGridAutoFlow(aSource.mGridAutoFlow)
   , mBoxSizing(aSource.mBoxSizing)
   , mAlignContent(aSource.mAlignContent)
   , mAlignItems(aSource.mAlignItems)
   , mAlignSelf(aSource.mAlignSelf)
+  , mJustifyContent(aSource.mJustifyContent)
   , mJustifyItems(aSource.mJustifyItems)
   , mJustifySelf(aSource.mJustifySelf)
   , mFlexDirection(aSource.mFlexDirection)
   , mFlexWrap(aSource.mFlexWrap)
-  , mJustifyContent(aSource.mJustifyContent)
   , mObjectFit(aSource.mObjectFit)
   , mOrder(aSource.mOrder)
   , mFlexGrow(aSource.mFlexGrow)
   , mFlexShrink(aSource.mFlexShrink)
   , mZIndex(aSource.mZIndex)
   , mGridTemplateColumns(aSource.mGridTemplateColumns)
   , mGridTemplateRows(aSource.mGridTemplateRows)
   , mGridTemplateAreas(aSource.mGridTemplateAreas)
@@ -1670,32 +1670,16 @@ nsStylePosition::CalcDifference(const ns
 nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord)
 {
   return aCoord.HasPercent() ||
          (aCoord.GetUnit() == eStyleUnit_Enumerated &&
           (aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT ||
            aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE));
 }
 
-static nsStyleContext*
-GetAlignmentContainer(nsStyleContext* aParent,
-                      const nsStylePosition** aPosition,
-                      const nsStyleDisplay** aDisplay)
-{
-  while (aParent &&
-         aParent->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_CONTENTS) {
-    aParent = aParent->GetParent();
-  }
-  if (aParent) {
-    *aPosition = aParent->StylePosition();
-    *aDisplay = aParent->StyleDisplay();
-  }
-  return aParent;
-}
-
 uint8_t
 nsStylePosition::MapLeftRightToStart(uint8_t aAlign, LogicalAxis aAxis,
                                      const nsStyleDisplay* aDisplay) const
 {
   auto val = aAlign & ~NS_STYLE_ALIGN_FLAG_BITS;
   if (val == NS_STYLE_ALIGN_LEFT || val == NS_STYLE_ALIGN_RIGHT) {
     switch (aDisplay->mDisplay) {
     case NS_STYLE_DISPLAY_FLEX:
@@ -1707,22 +1691,42 @@ nsStylePosition::MapLeftRightToStart(uin
       if (aAxis == eLogicalAxisBlock) {
         return NS_STYLE_ALIGN_START | (aAlign & NS_STYLE_ALIGN_FLAG_BITS);
       }
     }
   }
   return aAlign;
 }
 
+uint16_t
+nsStylePosition::ComputedJustifyContent(const nsStyleDisplay* aDisplay) const
+{
+  switch (aDisplay->mDisplay) {
+    case NS_STYLE_DISPLAY_FLEX:
+    case NS_STYLE_DISPLAY_INLINE_FLEX:
+      // XXX maybe map 'auto' too? (ISSUE 8 in the spec)
+      // https://drafts.csswg.org/css-align-3/#content-distribution
+      if (mJustifyContent == NS_STYLE_JUSTIFY_STRETCH) {
+        return NS_STYLE_JUSTIFY_FLEX_START;
+      }
+      break;
+  }
+  uint8_t val = mJustifyContent & NS_STYLE_JUSTIFY_ALL_BITS;
+  val = MapLeftRightToStart(val, eLogicalAxisInline, aDisplay);
+  uint8_t fallback = mJustifyContent >> NS_STYLE_JUSTIFY_ALL_SHIFT;
+  fallback = MapLeftRightToStart(fallback, eLogicalAxisInline, aDisplay);
+  return (uint16_t(fallback) << NS_STYLE_JUSTIFY_ALL_SHIFT) | uint16_t(val);
+}
+
 uint8_t
 nsStylePosition::ComputedJustifyItems(const nsStyleDisplay* aDisplay,
                                       nsStyleContext* aParent) const
 {
   if (mJustifyItems != NS_STYLE_JUSTIFY_AUTO) {
-    return mJustifyItems;
+    return MapLeftRightToStart(mJustifyItems, eLogicalAxisInline, aDisplay);
   }
   if (MOZ_LIKELY(aParent)) {
     auto inheritedJustifyItems =
       aParent->StylePosition()->ComputedJustifyItems(aParent->StyleDisplay(),
                                                      aParent->GetParent());
     if (inheritedJustifyItems & NS_STYLE_JUSTIFY_LEGACY) {
       return inheritedJustifyItems;
     }
@@ -1730,32 +1734,28 @@ nsStylePosition::ComputedJustifyItems(co
   return aDisplay->IsFlexOrGridDisplayType() ? NS_STYLE_JUSTIFY_STRETCH
                                              : NS_STYLE_JUSTIFY_START;
 }
 
 uint8_t
 nsStylePosition::ComputedJustifySelf(const nsStyleDisplay* aDisplay,
                                      nsStyleContext* aParent) const
 {
-  const nsStylePosition* containerPos = this;
-  const nsStyleDisplay* containerDisp = aDisplay;
-  GetAlignmentContainer(aParent, &containerPos, &containerDisp);
   if (mJustifySelf != NS_STYLE_JUSTIFY_AUTO) {
-    return containerPos->MapLeftRightToStart(mJustifySelf, eLogicalAxisInline,
-                                             containerDisp);
+    return MapLeftRightToStart(mJustifySelf, eLogicalAxisInline, aDisplay);
   }
   if (MOZ_UNLIKELY(aDisplay->IsAbsolutelyPositionedStyle())) {
     return NS_STYLE_JUSTIFY_AUTO;
   }
   if (MOZ_LIKELY(aParent)) {
     auto inheritedJustifyItems = aParent->StylePosition()->
       ComputedJustifyItems(aParent->StyleDisplay(), aParent->GetParent());
     inheritedJustifyItems &= ~NS_STYLE_JUSTIFY_LEGACY;
-    return containerPos->MapLeftRightToStart(inheritedJustifyItems,
-                                             eLogicalAxisInline, containerDisp);
+    return MapLeftRightToStart(inheritedJustifyItems, eLogicalAxisInline,
+                               aDisplay);
   }
   return NS_STYLE_JUSTIFY_START;
 }
 
 // --------------------
 // nsStyleTable
 //
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1392,16 +1392,22 @@ struct nsStylePosition {
     return nsChangeHint(0);
   }
 
   // XXXdholbert nsStyleBackground::Position should probably be moved to a
   // different scope, since we're now using it in multiple style structs.
   typedef nsStyleBackground::Position Position;
 
   /**
+   * Return the computed value for 'justify-content' given our 'display' value
+   * in aDisplay.
+   */
+  uint16_t ComputedJustifyContent(const nsStyleDisplay* aDisplay) const;
+
+  /**
    * Return the computed value for 'justify-items' given our 'display' value in
    * aDisplay and the parent StyleContext aParent (or null for the root).
    */
   uint8_t ComputedJustifyItems(const nsStyleDisplay* aDisplay,
                                nsStyleContext* aParent) const;
 
   /**
    * Return the computed value for 'justify-self' given our 'display' value in
@@ -1429,22 +1435,22 @@ struct nsStylePosition {
   uint8_t       mAlignItems;            // [reset] see nsStyleConsts.h
   uint8_t       mAlignSelf;             // [reset] see nsStyleConsts.h
 private:
   friend class nsRuleNode;
   // Helper for the ComputedAlign/Justify* methods.
   uint8_t MapLeftRightToStart(uint8_t aAlign, mozilla::LogicalAxis aAxis,
                               const nsStyleDisplay* aDisplay) const;
 
+  uint16_t      mJustifyContent;        // [reset] fallback value in the high byte
   uint8_t       mJustifyItems;          // [reset] see nsStyleConsts.h
   uint8_t       mJustifySelf;           // [reset] see nsStyleConsts.h
 public:
   uint8_t       mFlexDirection;         // [reset] see nsStyleConsts.h
   uint8_t       mFlexWrap;              // [reset] see nsStyleConsts.h
-  uint8_t       mJustifyContent;        // [reset] see nsStyleConsts.h
   uint8_t       mObjectFit;             // [reset] see nsStyleConsts.h
   int32_t       mOrder;                 // [reset] integer
   float         mFlexGrow;              // [reset] float
   float         mFlexShrink;            // [reset] float
   nsStyleCoord  mZIndex;                // [reset] integer, auto
   nsStyleGridTemplate mGridTemplateColumns;
   nsStyleGridTemplate mGridTemplateRows;
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4066,16 +4066,31 @@ var gCSSProperties = {
     domProp: "alignSelf",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     // (Assuming defaults on the parent, 'auto' will compute to 'stretch'.)
     initial_values: [ "auto", "stretch" ],
     other_values: [ "flex-start", "flex-end", "center", "baseline" ],
     invalid_values: [ "space-between", "abc", "30px" ]
   },
+  "justify-content": {
+    domProp: "justifyContent",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "start", "end", "flex-start", "flex-end", "center", "left",
+                    "right", "space-between", "space-around", "space-evenly",
+                    "baseline", "last-baseline", "stretch", "start safe",
+                    "true end", "true end stretch", "end safe space-evenly" ],
+    invalid_values: [ "30px", "5%", "self-end", "safe", "auto true", "true safe",
+                      "safe baseline", "baseline true", "baseline end", "auto end",
+                      "safe end true start", "safe end true", "auto safe start",
+                      "true end start", "end start safe", "space-around true",
+                      "safe stretch"]
+  },
   "justify-items": {
     domProp: "justifyItems",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto", "start" ],
     other_values: [ "end", "flex-start", "flex-end", "self-start", "self-end",
                     "center", "left", "right", "baseline", "stretch",
                     "legacy left", "right legacy", "legacy center",
@@ -4281,24 +4296,16 @@ var gCSSProperties = {
   "order": {
     domProp: "order",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "0" ],
     other_values: [ "1", "99999", "-1", "-50" ],
     invalid_values: [ "0px", "1.0", "1.", "1%", "0.2", "3em", "stretch" ]
   },
-  "justify-content": {
-    domProp: "justifyContent",
-    inherited: false,
-    type: CSS_TYPE_LONGHAND,
-    initial_values: [ "flex-start" ],
-    other_values: [ "flex-end", "center", "space-between", "space-around" ],
-    invalid_values: [ "baseline", "stretch", "30px", "5%" ]
-  },
 
   // Aliases
   "-moz-transform": {
     domProp: "MozTransform",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
     alias_for: "transform",
     subproperties: [ "transform" ],