Bug 1176782 part 1 - [css-align] Implement the 'justify-items' property in the style system. r=SimonSapin
authorMats Palmgren <mats@mozilla.com>
Tue, 03 Nov 2015 15:18:05 +0100
changeset 292662 f7d6e92ba3df9f639809c0875a62021f88c867ad
parent 292661 173b3daa4344a15b665304b6acb6bd36bf36fdf9
child 292663 6fb17e670a082fed169a6ca1d26f1e362295800d
push id8824
push userraliiev@mozilla.com
push dateMon, 14 Dec 2015 20:18:56 +0000
treeherdermozilla-aurora@e2031358e2a6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersSimonSapin
bugs1176782
milestone45.0a1
Bug 1176782 part 1 - [css-align] Implement the 'justify-items' property in the style system. r=SimonSapin
layout/style/nsCSSKeywordList.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsComputedDOMStylePropertyList.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleConsts.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -329,17 +329,19 @@ CSS_KEY(keep-all, keep_all)
 CSS_KEY(khz, khz)
 CSS_KEY(korean-hangul-formal, korean_hangul_formal)
 CSS_KEY(korean-hanja-formal, korean_hanja_formal)
 CSS_KEY(korean-hanja-informal, korean_hanja_informal)
 CSS_KEY(landscape, landscape)
 CSS_KEY(large, large)
 CSS_KEY(larger, larger)
 CSS_KEY(layout, layout)
+CSS_KEY(last-baseline, last_baseline)
 CSS_KEY(left, left)
+CSS_KEY(legacy, legacy)
 CSS_KEY(lighten, lighten)
 CSS_KEY(lighter, lighter)
 CSS_KEY(line-through, line_through)
 CSS_KEY(linear, linear)
 CSS_KEY(lining-nums, lining_nums)
 CSS_KEY(list-item, list_item)
 CSS_KEY(local, local)
 CSS_KEY(logical, logical)
@@ -454,16 +456,17 @@ CSS_KEY(rtl, rtl)
 CSS_KEY(ruby, ruby)
 CSS_KEY(ruby-base, ruby_base)
 CSS_KEY(ruby-base-container, ruby_base_container)
 CSS_KEY(ruby-text, ruby_text)
 CSS_KEY(ruby-text-container, ruby_text_container)
 CSS_KEY(running, running)
 CSS_KEY(s, s)
 CSS_KEY(s-resize, s_resize)
+CSS_KEY(safe, safe)
 CSS_KEY(saturate, saturate)
 CSS_KEY(saturation, saturation)
 CSS_KEY(scale, scale)
 CSS_KEY(scale-down, scale_down)
 CSS_KEY(scale3d, scale3d)
 CSS_KEY(scalex, scalex)
 CSS_KEY(scaley, scaley)
 CSS_KEY(scalez, scalez)
@@ -473,16 +476,18 @@ CSS_KEY(scroll, scroll)
 CSS_KEY(scrollbar, scrollbar)
 CSS_KEY(scrollbar-small, scrollbar_small)
 CSS_KEY(se-resize, se_resize)
 CSS_KEY(select-after, select_after)
 CSS_KEY(select-all, select_all)
 CSS_KEY(select-before, select_before)
 CSS_KEY(select-menu, select_menu)
 CSS_KEY(select-same, select_same)
+CSS_KEY(self-end, self_end)
+CSS_KEY(self-start, self_start)
 CSS_KEY(semi-condensed, semi_condensed)
 CSS_KEY(semi-expanded, semi_expanded)
 CSS_KEY(separate, separate)
 CSS_KEY(sepia, sepia)
 CSS_KEY(serif, serif)
 CSS_KEY(show, show)
 CSS_KEY(sideways, sideways)
 CSS_KEY(sideways-lr, sideways_lr)
@@ -501,16 +506,17 @@ CSS_KEY(small-caps, small_caps)
 CSS_KEY(small-caption, small_caption)
 CSS_KEY(smaller, smaller)
 CSS_KEY(smooth, smooth)
 CSS_KEY(soft, soft)
 CSS_KEY(soft-light, soft_light)
 CSS_KEY(solid, solid)
 CSS_KEY(space-around, space_around)
 CSS_KEY(space-between, space_between)
+CSS_KEY(space-evenly, space_evenly)
 CSS_KEY(span, span)
 CSS_KEY(spell-out, spell_out)
 CSS_KEY(square, square)
 CSS_KEY(stacked-fractions, stacked_fractions)
 CSS_KEY(start, start)
 CSS_KEY(static, static)
 CSS_KEY(status-bar, status_bar)
 CSS_KEY(step-end, step_end)
@@ -722,17 +728,16 @@ CSS_KEY(-moz-mac-vibrancy-light, _moz_ma
 CSS_KEY(-moz-mac-vibrancy-dark, _moz_mac_vibrancy_dark)
 CSS_KEY(-moz-mac-disclosure-button-closed, _moz_mac_disclosure_button_closed)
 CSS_KEY(-moz-mac-disclosure-button-open, _moz_mac_disclosure_button_open)
 CSS_KEY(alphabetic, alphabetic)
 CSS_KEY(bevel, bevel)
 CSS_KEY(butt, butt)
 CSS_KEY(central, central)
 CSS_KEY(crispedges, crispedges)
-//CSS_KEY(end, end)
 CSS_KEY(evenodd, evenodd)
 CSS_KEY(geometricprecision, geometricprecision)
 CSS_KEY(hanging, hanging)
 CSS_KEY(ideographic, ideographic)
 CSS_KEY(linearrgb, linearrgb)
 CSS_KEY(mathematical, mathematical)
 //CSS_KEY(middle, middle)
 CSS_KEY(miter, miter)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -930,16 +930,21 @@ protected:
   bool ParseGrid();
   bool ParseGridShorthandAutoProps();
   bool ParseGridLine(nsCSSValue& aValue);
   bool ParseGridColumnRowStartEnd(nsCSSProperty aPropID);
   bool ParseGridColumnRow(nsCSSProperty aStartPropID,
                           nsCSSProperty aEndPropID);
   bool ParseGridArea();
 
+  // parsing 'align/justify-items/self' from the css-align spec
+  bool ParseAlignJustifyPosition(nsCSSValue& aResult,
+                                 const KTableValue aTable[]);
+  bool ParseJustifyItems();
+
   // for 'clip' and '-moz-image-region'
   bool ParseRect(nsCSSProperty aPropID);
   bool ParseColumns();
   bool ParseContain(nsCSSValue& aValue);
   bool ParseContent();
   bool ParseCounterData(nsCSSProperty aPropID);
   bool ParseCursor();
   bool ParseFont();
@@ -9373,16 +9378,81 @@ CSSParserImpl::ParseGridArea()
 
   AppendValue(eCSSProperty_grid_row_start, values[0]);
   AppendValue(eCSSProperty_grid_column_start, values[1]);
   AppendValue(eCSSProperty_grid_row_end, values[2]);
   AppendValue(eCSSProperty_grid_column_end, values[3]);
   return true;
 }
 
+// [ $aTable && <overflow-position>? ] ?
+// $aTable is for <content-position> or <self-position>
+bool
+CSSParserImpl::ParseAlignJustifyPosition(nsCSSValue& aResult,
+                                         const KTableValue aTable[])
+{
+  nsCSSValue pos, overflowPos;
+  int32_t value = 0;
+  if (ParseEnum(pos, aTable)) {
+    value = pos.GetIntValue();
+    if (ParseEnum(overflowPos, nsCSSProps::kAlignOverflowPosition)) {
+      value |= overflowPos.GetIntValue();
+    }
+    aResult.SetIntValue(value, eCSSUnit_Enumerated);
+    return true;
+  }
+  if (ParseEnum(overflowPos, nsCSSProps::kAlignOverflowPosition)) {
+    if (ParseEnum(pos, aTable)) {
+      aResult.SetIntValue(pos.GetIntValue() | overflowPos.GetIntValue(),
+                          eCSSUnit_Enumerated);
+      return true;
+    }
+    return false; // <overflow-position> must be followed by a value in $table
+  }
+  return true;
+}
+
+// auto | stretch | <baseline-position> |
+// [ <self-position> && <overflow-position>? ] |
+// [ legacy && [ left | right | center ] ]
+bool
+CSSParserImpl::ParseJustifyItems()
+{
+  nsCSSValue value;
+  if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
+    if (MOZ_UNLIKELY(ParseEnum(value, nsCSSProps::kAlignLegacy))) {
+      nsCSSValue legacy;
+      if (!ParseEnum(legacy, nsCSSProps::kAlignLegacyPosition)) {
+        return false; // leading 'legacy' not followed by 'left' etc is an error
+      }
+      value.SetIntValue(value.GetIntValue() | legacy.GetIntValue(),
+                        eCSSUnit_Enumerated);
+    } else {
+      if (!ParseEnum(value, nsCSSProps::kAlignAutoStretchBaseline)) {
+        if (!ParseAlignJustifyPosition(value, nsCSSProps::kAlignSelfPosition) ||
+            value.GetUnit() == eCSSUnit_Null) {
+          return false;
+        }
+        // check for a trailing 'legacy' after 'left' etc
+        auto val = value.GetIntValue();
+        if (val == NS_STYLE_JUSTIFY_CENTER ||
+            val == NS_STYLE_JUSTIFY_LEFT   ||
+            val == NS_STYLE_JUSTIFY_RIGHT) {
+          nsCSSValue legacy;
+          if (ParseEnum(legacy, nsCSSProps::kAlignLegacy)) {
+            value.SetIntValue(val | legacy.GetIntValue(), eCSSUnit_Enumerated);
+          }
+        }
+      }
+    }
+  }
+  AppendValue(eCSSProperty_justify_items, 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;
@@ -10496,16 +10566,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_items:
+    return ParseJustifyItems();
   case eCSSProperty_list_style:
     return ParseListStyle();
   case eCSSProperty_margin:
     return ParseMargin();
   case eCSSProperty_object_position:
     return ParseObjectPosition();
   case eCSSProperty_outline:
     return ParseOutline();
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -1702,16 +1702,26 @@ CSS_PROP_POSITION(
     justify_content,
     JustifyContent,
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kJustifyContentKTable,
     offsetof(nsStylePosition, mJustifyContent),
     eStyleAnimType_EnumU8)
+CSS_PROP_POSITION(
+    justify-items,
+    justify_items,
+    JustifyItems,
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "",
+    0,
+    nullptr,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
 CSS_PROP_DISPLAY(
     float,
     float,
     CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float),
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
     "",
     VARIANT_HK,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1237,16 +1237,78 @@ KTableValue nsCSSProps::kDisplayKTable[]
 };
 
 const KTableValue nsCSSProps::kEmptyCellsKTable[] = {
   eCSSKeyword_show,                 NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
   eCSSKeyword_hide,                 NS_STYLE_TABLE_EMPTY_CELLS_HIDE,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const KTableValue nsCSSProps::kAlignAllKeywords[] = {
+  eCSSKeyword_auto,          NS_STYLE_ALIGN_AUTO,
+  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_baseline,      NS_STYLE_ALIGN_BASELINE,
+  eCSSKeyword_last_baseline, NS_STYLE_ALIGN_LAST_BASELINE,
+  eCSSKeyword_stretch,       NS_STYLE_ALIGN_STRETCH,
+  eCSSKeyword_self_start,    NS_STYLE_ALIGN_SELF_START,
+  eCSSKeyword_self_end,      NS_STYLE_ALIGN_SELF_END,
+  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_legacy,        NS_STYLE_ALIGN_LEGACY,
+  eCSSKeyword_safe,          NS_STYLE_ALIGN_SAFE,
+  eCSSKeyword_true,          NS_STYLE_ALIGN_TRUE,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+const KTableValue nsCSSProps::kAlignOverflowPosition[] = {
+  eCSSKeyword_true,          NS_STYLE_ALIGN_TRUE,
+  eCSSKeyword_safe,          NS_STYLE_ALIGN_SAFE,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+const KTableValue nsCSSProps::kAlignSelfPosition[] = {
+  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_self_start,    NS_STYLE_ALIGN_SELF_START,
+  eCSSKeyword_self_end,      NS_STYLE_ALIGN_SELF_END,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+const KTableValue nsCSSProps::kAlignLegacy[] = {
+  eCSSKeyword_legacy,        NS_STYLE_ALIGN_LEGACY,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+const KTableValue nsCSSProps::kAlignLegacyPosition[] = {
+  eCSSKeyword_center,        NS_STYLE_ALIGN_CENTER,
+  eCSSKeyword_left,          NS_STYLE_ALIGN_LEFT,
+  eCSSKeyword_right,         NS_STYLE_ALIGN_RIGHT,
+  eCSSKeyword_UNKNOWN,-1
+};
+
+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::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
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -683,22 +683,30 @@ public:
   static const KTableValue kControlCharacterVisibilityKTable[];
   static const KTableValue kCursorKTable[];
   static const KTableValue kDirectionKTable[];
   // Not const because we modify its entries when various 
   // "layout.css.*.enabled" prefs changes:
   static KTableValue kDisplayKTable[];
   static const KTableValue kElevationKTable[];
   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 kAlignContentKTable[];
   static const KTableValue kAlignItemsKTable[];
   static const KTableValue kAlignSelfKTable[];
+  static const KTableValue kJustifyContentKTable[];
+  // ------------------------------------------------------------------
   static const KTableValue kFlexDirectionKTable[];
   static const KTableValue kFlexWrapKTable[];
-  static const KTableValue kJustifyContentKTable[];
   static const KTableValue kFloatKTable[];
   static const KTableValue kFloatEdgeKTable[];
   static const KTableValue kFontKTable[];
   static const KTableValue kFontKerningKTable[];
   static const KTableValue kFontSizeKTable[];
   static const KTableValue kFontSmoothingKTable[];
   static const KTableValue kFontStretchKTable[];
   static const KTableValue kFontStyleKTable[];
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1004,16 +1004,38 @@ nsCSSValue::AppendInsetToString(nsCSSPro
     AppendBasicShapeRadiusToString(subprops, vals, aResult,
                                    aSerialization);
   } else {
     MOZ_ASSERT(array->Item(5).GetUnit() == eCSSUnit_Null,
                "unexpected value");
   }
 }
 
+/* static */ void
+nsCSSValue::AppendAlignJustifyValueToString(int32_t aValue, nsAString& aResult)
+{
+  auto legacy = aValue & NS_STYLE_ALIGN_LEGACY;
+  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");
+  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);
+  }
+}
+
 void
 nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
                            Serialization aSerialization) const
 {
   // eCSSProperty_UNKNOWN gets used for some recursive calls below.
   MOZ_ASSERT((0 <= aProperty &&
               aProperty <= eCSSProperty_COUNT_no_shorthands) ||
              aProperty == eCSSProperty_UNKNOWN,
@@ -1290,16 +1312,20 @@ nsCSSValue::AppendToString(nsCSSProperty
       }
       nsStyleUtil::AppendBitmaskCSSValue(aProperty,
                                          intValue,
                                          NS_STYLE_CONTAIN_STRICT,
                                          NS_STYLE_CONTAIN_PAINT,
                                          aResult);
       break;
 
+    case eCSSProperty_justify_items:
+      AppendAlignJustifyValueToString(intValue, aResult);
+      break;
+
     default:
       const nsAFlatCString& name = nsCSSProps::LookupPropertyValue(aProperty, intValue);
       AppendASCIItoUTF16(name, aResult);
       break;
     }
   }
   else if (eCSSUnit_EnumColor == unit) {
     // we can lookup the property in the ColorTable and then
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -721,16 +721,19 @@ public:
                                const nsCSSValue* aValues[],
                                nsAString& aString,
                                Serialization aSerialization);
   static void
   AppendBasicShapeRadiusToString(const nsCSSProperty aProperties[],
                                  const nsCSSValue* aValues[],
                                  nsAString& aResult,
                                  Serialization aValueSerialization);
+  static void
+  AppendAlignJustifyValueToString(int32_t aValue, nsAString& aResult);
+
 private:
   static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
     return static_cast<char16_t*>(aBuffer->Data());
   }
 
   void AppendPolygonToString(nsCSSProperty aProperty, nsAString& aResult,
                              Serialization aValueSerialization) const;
   void AppendPositionCoordinateToString(const nsCSSValue& aValue,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3977,16 +3977,28 @@ nsComputedDOMStyle::DoGetJustifyContent(
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StylePosition()->mJustifyContent,
                                    nsCSSProps::kJustifyContentKTable));
   return val;
 }
 
 CSSValue*
+nsComputedDOMStyle::DoGetJustifyItems()
+{
+  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  nsAutoString str;
+  auto justify = StylePosition()->
+    ComputedJustifyItems(StyleDisplay(), mStyleContext->GetParent());
+  nsCSSValue::AppendAlignJustifyValueToString(justify, str);
+  val->SetString(str);
+  return val;
+}
+
+CSSValue*
 nsComputedDOMStyle::DoGetFloatEdge()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge,
                                    nsCSSProps::kFloatEdgeKTable));
   return val;
 }
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -464,26 +464,31 @@ private:
   mozilla::dom::CSSValue* DoGetAnimationDelay();
   mozilla::dom::CSSValue* DoGetAnimationTimingFunction();
   mozilla::dom::CSSValue* DoGetAnimationDirection();
   mozilla::dom::CSSValue* DoGetAnimationFillMode();
   mozilla::dom::CSSValue* DoGetAnimationIterationCount();
   mozilla::dom::CSSValue* DoGetAnimationPlayState();
 
   /* CSS Flexbox properties */
-  mozilla::dom::CSSValue* DoGetAlignContent();
-  mozilla::dom::CSSValue* DoGetAlignItems();
-  mozilla::dom::CSSValue* DoGetAlignSelf();
   mozilla::dom::CSSValue* DoGetFlexBasis();
   mozilla::dom::CSSValue* DoGetFlexDirection();
   mozilla::dom::CSSValue* DoGetFlexGrow();
   mozilla::dom::CSSValue* DoGetFlexShrink();
   mozilla::dom::CSSValue* DoGetFlexWrap();
+
+  /* CSS Flexbox/Grid properties */
   mozilla::dom::CSSValue* DoGetOrder();
+
+  /* CSS Box Alignment properties */
+  mozilla::dom::CSSValue* DoGetAlignContent();
+  mozilla::dom::CSSValue* DoGetAlignItems();
+  mozilla::dom::CSSValue* DoGetAlignSelf();
   mozilla::dom::CSSValue* DoGetJustifyContent();
+  mozilla::dom::CSSValue* DoGetJustifyItems();
 
   /* SVG properties */
   mozilla::dom::CSSValue* DoGetFill();
   mozilla::dom::CSSValue* DoGetStroke();
   mozilla::dom::CSSValue* DoGetMarkerEnd();
   mozilla::dom::CSSValue* DoGetMarkerMid();
   mozilla::dom::CSSValue* DoGetMarkerStart();
   mozilla::dom::CSSValue* DoGetStrokeDasharray();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -145,16 +145,17 @@ COMPUTED_STYLE_PROP(grid_template_areas,
 COMPUTED_STYLE_PROP(grid_template_columns,         GridTemplateColumns)
 COMPUTED_STYLE_PROP(grid_template_rows,            GridTemplateRows)
 COMPUTED_STYLE_PROP(height,                        Height)
 COMPUTED_STYLE_PROP(hyphens,                       Hyphens)
 COMPUTED_STYLE_PROP(image_orientation,             ImageOrientation)
 COMPUTED_STYLE_PROP(ime_mode,                      IMEMode)
 COMPUTED_STYLE_PROP(isolation,                     Isolation)
 COMPUTED_STYLE_PROP(justify_content,               JustifyContent)
+COMPUTED_STYLE_PROP(justify_items,                 JustifyItems)
 COMPUTED_STYLE_PROP(left,                          Left)
 COMPUTED_STYLE_PROP(letter_spacing,                LetterSpacing)
 COMPUTED_STYLE_PROP(line_height,                   LineHeight)
 //// COMPUTED_STYLE_PROP(list_style,               ListStyle)
 COMPUTED_STYLE_PROP(list_style_image,              ListStyleImage)
 COMPUTED_STYLE_PROP(list_style_position,           ListStylePosition)
 COMPUTED_STYLE_PROP(list_style_type,               ListStyleType)
 //// COMPUTED_STYLE_PROP(margin,                   Margin)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7854,16 +7854,35 @@ 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-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 {
+      pos->mJustifyItems = NS_STYLE_JUSTIFY_AUTO;
+    }
+    conditions.SetUncacheable();
+  } else {
+    SetDiscrete(justifyItemsValue,
+                pos->mJustifyItems, conditions,
+                SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+                parentPos->mJustifyItems, // unused, we handle 'inherit' above
+                NS_STYLE_JUSTIFY_AUTO, 0, 0, 0, 0);
+  }
+
   // flex-basis: auto, length, percent, enum, calc, inherit, initial
   // (Note: The flags here should match those used for 'width' property above.)
   SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
            SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
            aContext, mPresContext, conditions);
 
   // flex-direction: enum, inherit, initial
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -466,16 +466,63 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_CONTAIN_LAYOUT                 0x2
 #define NS_STYLE_CONTAIN_STYLE                  0x4
 #define NS_STYLE_CONTAIN_PAINT                  0x8
 // NS_STYLE_CONTAIN_ALL_BITS does not correspond to a keyword.
 #define NS_STYLE_CONTAIN_ALL_BITS               (NS_STYLE_CONTAIN_LAYOUT | \
                                                  NS_STYLE_CONTAIN_STYLE  | \
                                                  NS_STYLE_CONTAIN_PAINT)
 
+// Shared constants for all align/justify properties (nsStylePosition):
+#define NS_STYLE_ALIGN_AUTO             0
+#define NS_STYLE_ALIGN_START            1
+#define NS_STYLE_ALIGN_END              2
+#define NS_STYLE_ALIGN_FLEX_START       3
+#define NS_STYLE_ALIGN_FLEX_END         4
+#define NS_STYLE_ALIGN_CENTER           5
+#define NS_STYLE_ALIGN_LEFT             6
+#define NS_STYLE_ALIGN_RIGHT            7
+#define NS_STYLE_ALIGN_BASELINE         8
+#define NS_STYLE_ALIGN_LAST_BASELINE    9
+#define NS_STYLE_ALIGN_STRETCH          10
+#define NS_STYLE_ALIGN_SELF_START       11
+#define NS_STYLE_ALIGN_SELF_END         12
+#define NS_STYLE_ALIGN_SPACE_BETWEEN    13
+#define NS_STYLE_ALIGN_SPACE_AROUND     14
+#define NS_STYLE_ALIGN_SPACE_EVENLY     15
+#define NS_STYLE_ALIGN_LEGACY        0x10 // mutually exclusive w. SAFE & TRUE
+#define NS_STYLE_ALIGN_SAFE          0x20
+#define NS_STYLE_ALIGN_TRUE          0x40 // mutually exclusive w. SAFE
+#define NS_STYLE_ALIGN_FLAG_BITS     0xF0
+#define NS_STYLE_ALIGN_ALL_BITS      0xFF
+#define NS_STYLE_ALIGN_ALL_SHIFT        8
+
+#define NS_STYLE_JUSTIFY_AUTO             NS_STYLE_ALIGN_AUTO
+#define NS_STYLE_JUSTIFY_START            NS_STYLE_ALIGN_START
+#define NS_STYLE_JUSTIFY_END              NS_STYLE_ALIGN_END
+#define NS_STYLE_JUSTIFY_FLEX_START       NS_STYLE_ALIGN_FLEX_START
+#define NS_STYLE_JUSTIFY_FLEX_END         NS_STYLE_ALIGN_FLEX_END
+#define NS_STYLE_JUSTIFY_CENTER           NS_STYLE_ALIGN_CENTER
+#define NS_STYLE_JUSTIFY_LEFT             NS_STYLE_ALIGN_LEFT
+#define NS_STYLE_JUSTIFY_RIGHT            NS_STYLE_ALIGN_RIGHT
+#define NS_STYLE_JUSTIFY_BASELINE         NS_STYLE_ALIGN_BASELINE
+#define NS_STYLE_JUSTIFY_LAST_BASELINE    NS_STYLE_ALIGN_LAST_BASELINE
+#define NS_STYLE_JUSTIFY_STRETCH          NS_STYLE_ALIGN_STRETCH
+#define NS_STYLE_JUSTIFY_SELF_START       NS_STYLE_ALIGN_SELF_START
+#define NS_STYLE_JUSTIFY_SELF_END         NS_STYLE_ALIGN_SELF_END
+#define NS_STYLE_JUSTIFY_SPACE_BETWEEN    NS_STYLE_ALIGN_SPACE_BETWEEN
+#define NS_STYLE_JUSTIFY_SPACE_AROUND     NS_STYLE_ALIGN_SPACE_AROUND
+#define NS_STYLE_JUSTIFY_SPACE_EVENLY     NS_STYLE_ALIGN_SPACE_EVENLY
+#define NS_STYLE_JUSTIFY_LEGACY           NS_STYLE_ALIGN_LEGACY
+#define NS_STYLE_JUSTIFY_SAFE             NS_STYLE_ALIGN_SAFE
+#define NS_STYLE_JUSTIFY_TRUE             NS_STYLE_ALIGN_TRUE
+#define NS_STYLE_JUSTIFY_FLAG_BITS        NS_STYLE_ALIGN_FLAG_BITS
+#define NS_STYLE_JUSTIFY_ALL_BITS         NS_STYLE_ALIGN_ALL_BITS
+#define NS_STYLE_JUSTIFY_ALL_SHIFT        NS_STYLE_ALIGN_ALL_SHIFT
+
 // See nsStylePosition
 #define NS_STYLE_ALIGN_CONTENT_FLEX_START       0
 #define NS_STYLE_ALIGN_CONTENT_FLEX_END         1
 #define NS_STYLE_ALIGN_CONTENT_CENTER           2
 #define NS_STYLE_ALIGN_CONTENT_SPACE_BETWEEN    3
 #define NS_STYLE_ALIGN_CONTENT_SPACE_AROUND     4
 #define NS_STYLE_ALIGN_CONTENT_STRETCH          5
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1429,16 +1429,17 @@ 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;
+  mJustifyItems = 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();
@@ -1468,16 +1469,17 @@ 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)
+  , mJustifyItems(aSource.mJustifyItems)
   , mFlexDirection(aSource.mFlexDirection)
   , mFlexWrap(aSource.mFlexWrap)
   , mJustifyContent(aSource.mJustifyContent)
   , mObjectFit(aSource.mObjectFit)
   , mOrder(aSource.mOrder)
   , mFlexGrow(aSource.mFlexGrow)
   , mFlexShrink(aSource.mFlexShrink)
   , mZIndex(aSource.mZIndex)
@@ -1580,19 +1582,20 @@ nsStylePosition::CalcDifference(const ns
   // (ie. parent frame is 'display: grid' or 'display: inline-grid')
   if (mGridColumnStart != aOther.mGridColumnStart ||
       mGridColumnEnd != aOther.mGridColumnEnd ||
       mGridRowStart != aOther.mGridRowStart ||
       mGridRowEnd != aOther.mGridRowEnd) {
     return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
   }
 
-  // Changing justify-content on a flexbox might affect the positioning of its
-  // children, but it won't affect any sizing.
-  if (mJustifyContent != aOther.mJustifyContent) {
+  // Changing 'justify-content/items' might affect the positioning,
+  // but it won't affect any sizing.
+  if (mJustifyContent != aOther.mJustifyContent ||
+      mJustifyItems != aOther.mJustifyItems) {
     NS_UpdateHint(hint, nsChangeHint_NeedReflow);
   }
 
   // 'align-content' doesn't apply to a single-line flexbox but we don't know
   // if we're a flex container at this point so we can't optimize for that.
   if (mAlignContent != aOther.mAlignContent) {
     NS_UpdateHint(hint, nsChangeHint_NeedReflow);
   }
@@ -1664,16 +1667,35 @@ 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));
 }
 
+uint8_t
+nsStylePosition::ComputedJustifyItems(const nsStyleDisplay* aDisplay,
+                                      nsStyleContext* aParent) const
+{
+  if (mJustifyItems != NS_STYLE_JUSTIFY_AUTO) {
+    return mJustifyItems;
+  }
+  if (MOZ_LIKELY(aParent)) {
+    auto inheritedJustifyItems =
+      aParent->StylePosition()->ComputedJustifyItems(aParent->StyleDisplay(),
+                                                     aParent->GetParent());
+    if (inheritedJustifyItems & NS_STYLE_JUSTIFY_LEGACY) {
+      return inheritedJustifyItems;
+    }
+  }
+  return aDisplay->IsFlexOrGridDisplayType() ? NS_STYLE_JUSTIFY_STRETCH
+                                             : NS_STYLE_JUSTIFY_START;
+}
+
 // --------------------
 // nsStyleTable
 //
 
 nsStyleTable::nsStyleTable() 
 { 
   MOZ_COUNT_CTOR(nsStyleTable);
   // values not inherited
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1391,16 +1391,23 @@ struct nsStylePosition {
     // descendants.
     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-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;
+
   Position      mObjectPosition;        // [reset]
   nsStyleSides  mOffset;                // [reset] coord, percent, calc, auto
   nsStyleCoord  mWidth;                 // [reset] coord, percent, enum, calc, auto
   nsStyleCoord  mMinWidth;              // [reset] coord, percent, enum, calc
   nsStyleCoord  mMaxWidth;              // [reset] coord, percent, enum, calc, none
   nsStyleCoord  mHeight;                // [reset] coord, percent, calc, auto
   nsStyleCoord  mMinHeight;             // [reset] coord, percent, calc
   nsStyleCoord  mMaxHeight;             // [reset] coord, percent, calc, none
@@ -1409,16 +1416,20 @@ struct nsStylePosition {
   nsStyleCoord  mGridAutoColumnsMax;    // [reset] coord, percent, enum, calc, flex
   nsStyleCoord  mGridAutoRowsMin;       // [reset] coord, percent, enum, calc, flex
   nsStyleCoord  mGridAutoRowsMax;       // [reset] coord, percent, enum, calc, flex
   uint8_t       mGridAutoFlow;          // [reset] enumerated. See nsStyleConsts.h
   uint8_t       mBoxSizing;             // [reset] see nsStyleConsts.h
   uint8_t       mAlignContent;          // [reset] see nsStyleConsts.h
   uint8_t       mAlignItems;            // [reset] see nsStyleConsts.h
   uint8_t       mAlignSelf;             // [reset] see nsStyleConsts.h
+private:
+  friend class nsRuleNode;
+  uint8_t       mJustifyItems;          // [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
--- 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-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",
+                    "true right", "left true", "safe right", "center safe" ],
+    invalid_values: [ "space-between", "abc", "30px", "legacy", "legacy start",
+                      "end legacy", "legacy baseline", "legacy legacy", "true",
+                      "safe legacy left", "legacy left safe", "legacy safe left",
+                      "safe left legacy", "legacy left legacy", "baseline true",
+                      "safe true", "safe left true", "safe stretch" ]
+  },
   "flex": {
     domProp: "flex",
     inherited: false,
     type: CSS_TYPE_TRUE_SHORTHAND,
     subproperties: [
       "flex-grow",
       "flex-shrink",
       "flex-basis"