Bug 1176782 part 2 - [css-align] Implement the 'justify-self' property in the style system. r=SimonSapin
authorMats Palmgren <mats@mozilla.com>
Tue, 03 Nov 2015 15:18:05 +0100
changeset 270937 6fb17e670a082fed169a6ca1d26f1e362295800d
parent 270936 f7d6e92ba3df9f639809c0875a62021f88c867ad
child 270938 4ea55ddf4b4108f4f6770502a8fad8eacf322126
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)
reviewersSimonSapin
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 2 - [css-align] Implement the 'justify-self' property in the style system. r=SimonSapin
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsCSSValue.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsComputedDOMStylePropertyList.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -934,16 +934,17 @@ protected:
   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();
+  bool ParseJustifySelf();
 
   // for 'clip' and '-moz-image-region'
   bool ParseRect(nsCSSProperty aPropID);
   bool ParseColumns();
   bool ParseContain(nsCSSValue& aValue);
   bool ParseContent();
   bool ParseCounterData(nsCSSProperty aPropID);
   bool ParseCursor();
@@ -9443,16 +9444,34 @@ CSSParserImpl::ParseJustifyItems()
         }
       }
     }
   }
   AppendValue(eCSSProperty_justify_items, value);
   return true;
 }
 
+// auto | stretch | <baseline-position> |
+// [ <overflow-position>? && <self-position> ] 
+bool
+CSSParserImpl::ParseJustifySelf()
+{
+  nsCSSValue value;
+  if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
+    if (!ParseEnum(value, nsCSSProps::kAlignAutoStretchBaseline)) {
+      if (!ParseAlignJustifyPosition(value, nsCSSProps::kAlignSelfPosition) ||
+          value.GetUnit() == eCSSUnit_Null) {
+        return false;
+      }
+    }
+  }
+  AppendValue(eCSSProperty_justify_self, 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;
@@ -10568,16 +10587,18 @@ CSSParserImpl::ParsePropertyByFunction(n
     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_justify_self:
+    return ParseJustifySelf();
   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
@@ -1712,16 +1712,26 @@ CSS_PROP_POSITION(
     justify_items,
     JustifyItems,
     CSS_PROPERTY_PARSE_FUNCTION,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
+CSS_PROP_POSITION(
+    justify-self,
+    justify_self,
+    JustifySelf,
+    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/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1313,16 +1313,17 @@ nsCSSValue::AppendToString(nsCSSProperty
       nsStyleUtil::AppendBitmaskCSSValue(aProperty,
                                          intValue,
                                          NS_STYLE_CONTAIN_STRICT,
                                          NS_STYLE_CONTAIN_PAINT,
                                          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);
       break;
     }
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3989,16 +3989,28 @@ nsComputedDOMStyle::DoGetJustifyItems()
   auto justify = StylePosition()->
     ComputedJustifyItems(StyleDisplay(), mStyleContext->GetParent());
   nsCSSValue::AppendAlignJustifyValueToString(justify, str);
   val->SetString(str);
   return val;
 }
 
 CSSValue*
+nsComputedDOMStyle::DoGetJustifySelf()
+{
+  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  nsAutoString str;
+  auto justify = StylePosition()->
+    ComputedJustifySelf(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
@@ -479,16 +479,17 @@ private:
   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();
+  mozilla::dom::CSSValue* DoGetJustifySelf();
 
   /* 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
@@ -146,16 +146,17 @@ COMPUTED_STYLE_PROP(grid_template_column
 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(justify_self,                  JustifySelf)
 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
@@ -7873,16 +7873,39 @@ nsRuleNode::ComputePositionData(void* aS
   } 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);
   }
 
+  // justify-self: enum, inherit, initial
+  const auto& justifySelfValue = *aRuleData->ValueForJustifySelf();
+  if (MOZ_UNLIKELY(justifySelfValue.GetUnit() == eCSSUnit_Inherit)) {
+    if (MOZ_LIKELY(parentContext)) {
+      nsStyleContext* grandparentContext = parentContext->GetParent();
+      if (MOZ_LIKELY(grandparentContext)) {
+        aContext->AddStyleBit(NS_STYLE_USES_GRANDANCESTOR_STYLE);
+      }
+      pos->mJustifySelf =
+        parentPos->ComputedJustifySelf(parentContext->StyleDisplay(),
+                                       grandparentContext);
+    } else {
+      pos->mJustifySelf = NS_STYLE_JUSTIFY_START;
+    }
+    conditions.SetUncacheable();
+  } else {
+    SetDiscrete(justifySelfValue,
+                pos->mJustifySelf, conditions,
+                SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+                parentPos->mJustifySelf, // not used, 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/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1430,16 +1430,17 @@ nsStylePosition::nsStylePosition(void)
   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;
+  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();
@@ -1470,16 +1471,17 @@ nsStylePosition::nsStylePosition(const n
   , mGridAutoRowsMin(aSource.mGridAutoRowsMin)
   , mGridAutoRowsMax(aSource.mGridAutoRowsMax)
   , mGridAutoFlow(aSource.mGridAutoFlow)
   , mBoxSizing(aSource.mBoxSizing)
   , mAlignContent(aSource.mAlignContent)
   , mAlignItems(aSource.mAlignItems)
   , mAlignSelf(aSource.mAlignSelf)
   , 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)
@@ -1582,20 +1584,21 @@ 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/items' might affect the positioning,
+  // Changing 'justify-content/items/self' might affect the positioning,
   // but it won't affect any sizing.
   if (mJustifyContent != aOther.mJustifyContent ||
-      mJustifyItems != aOther.mJustifyItems) {
+      mJustifyItems != aOther.mJustifyItems ||
+      mJustifySelf != aOther.mJustifySelf) {
     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);
   }
@@ -1667,16 +1670,53 @@ 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:
+    case NS_STYLE_DISPLAY_INLINE_FLEX:
+      // XXX TODO
+      // NOTE: make sure to strip off 'legacy' bit when mapping to 'start'
+      break;
+    default:
+      if (aAxis == eLogicalAxisBlock) {
+        return NS_STYLE_ALIGN_START | (aAlign & NS_STYLE_ALIGN_FLAG_BITS);
+      }
+    }
+  }
+  return aAlign;
+}
+
 uint8_t
 nsStylePosition::ComputedJustifyItems(const nsStyleDisplay* aDisplay,
                                       nsStyleContext* aParent) const
 {
   if (mJustifyItems != NS_STYLE_JUSTIFY_AUTO) {
     return mJustifyItems;
   }
   if (MOZ_LIKELY(aParent)) {
@@ -1686,16 +1726,40 @@ nsStylePosition::ComputedJustifyItems(co
     if (inheritedJustifyItems & NS_STYLE_JUSTIFY_LEGACY) {
       return inheritedJustifyItems;
     }
   }
   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);
+  }
+  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 NS_STYLE_JUSTIFY_START;
+}
+
 // --------------------
 // nsStyleTable
 //
 
 nsStyleTable::nsStyleTable() 
 { 
   MOZ_COUNT_CTOR(nsStyleTable);
   // values not inherited
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1398,16 +1398,23 @@ struct nsStylePosition {
 
   /**
    * 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
+   * aDisplay and the parent StyleContext aParent (or null for the root).
+   */
+  uint8_t ComputedJustifySelf(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
@@ -1418,17 +1425,22 @@ struct nsStylePosition {
   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;
+  // Helper for the ComputedAlign/Justify* methods.
+  uint8_t MapLeftRightToStart(uint8_t aAlign, mozilla::LogicalAxis aAxis,
+                              const nsStyleDisplay* aDisplay) const;
+
   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
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4081,16 +4081,28 @@ var gCSSProperties = {
                     "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" ]
   },
+  "justify-self": {
+    domProp: "justifySelf",
+    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",
+                    "last-baseline", "stretch", "left true", "true right",
+                    "safe right", "center safe" ],
+    invalid_values: [ "space-between", "abc", "30px", "none",
+                      "legacy left", "right legacy" ]
+  },
   "flex": {
     domProp: "flex",
     inherited: false,
     type: CSS_TYPE_TRUE_SHORTHAND,
     subproperties: [
       "flex-grow",
       "flex-shrink",
       "flex-basis"