Bug 951793 - Style support for overscroll-behavior. r=heycam draft
authorBotond Ballo <botond@mozilla.com>
Wed, 22 Nov 2017 19:01:11 -0500
changeset 703283 d70820f9612174ffc8f17f1a2646dc65f46667df
parent 703282 6f8ad222caf73f9e02d772234f188eac4aac9301
child 703284 05f2abc208016ce55bbf2c20c231ab638f0fee3d
push id90783
push userbballo@mozilla.com
push dateFri, 24 Nov 2017 21:22:10 +0000
reviewersheycam
bugs951793
milestone59.0a1
Bug 951793 - Style support for overscroll-behavior. r=heycam MozReview-Commit-ID: IDAfBZy2D5p
devtools/shared/css/generated/properties-db.js
layout/style/Declaration.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.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
modules/libpref/init/all.js
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -3128,16 +3128,18 @@ exports.CSS_PROPERTIES = {
       "pointer-events",
       "position",
       "quotes",
       "resize",
       "right",
       "ruby-align",
       "ruby-position",
       "scroll-behavior",
+      "overscroll-behavior-x",
+      "overscroll-behavior-y",
       "scroll-snap-coordinate",
       "scroll-snap-destination",
       "scroll-snap-points-x",
       "scroll-snap-points-y",
       "scroll-snap-type-x",
       "scroll-snap-type-y",
       "shape-outside",
       "shape-rendering",
@@ -8308,16 +8310,62 @@ exports.CSS_PROPERTIES = {
       "hidden",
       "inherit",
       "initial",
       "scroll",
       "unset",
       "visible"
     ]
   },
+  "overscroll-behavior": {
+    "isInherited": false,
+    "subproperties": [
+      "overscroll-behavior-x",
+      "overscroll-behavior-y"
+    ],
+    "supports": [],
+    "values": [
+      "auto",
+      "contain",
+      "inherit",
+      "initial",
+      "none",
+      "unset"
+    ]
+  },
+  "overscroll-behavior-x": {
+    "isInherited": false,
+    "subproperties": [
+      "overscroll-behavior-x"
+    ],
+    "supports": [],
+    "values": [
+      "auto",
+      "contain",
+      "inherit",
+      "initial",
+      "none",
+      "unset"
+    ]
+  },
+  "overscroll-behavior-y": {
+    "isInherited": false,
+    "subproperties": [
+      "overscroll-behavior-y"
+    ],
+    "supports": [],
+    "values": [
+      "auto",
+      "contain",
+      "inherit",
+      "initial",
+      "none",
+      "unset"
+    ]
+  },
   "padding": {
     "isInherited": false,
     "subproperties": [
       "padding-top",
       "padding-right",
       "padding-bottom",
       "padding-left"
     ],
@@ -9966,16 +10014,28 @@ exports.PREFERENCES = [
     "paint-order",
     "svg.paint-order.enabled"
   ],
   [
     "scroll-behavior",
     "layout.css.scroll-behavior.property-enabled"
   ],
   [
+    "overscroll-behavior",
+    "layout.css.overscroll-behavior.enabled"
+  ],
+  [
+    "overscroll-behavior-x",
+    "layout.css.overscroll-behavior.enabled"
+  ],
+  [
+    "overscroll-behavior-y",
+    "layout.css.overscroll-behavior.enabled"
+  ],
+  [
     "scroll-snap-coordinate",
     "layout.css.scroll-snap.enabled"
   ],
   [
     "scroll-snap-destination",
     "layout.css.scroll-snap.enabled"
   ],
   [
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -1463,16 +1463,28 @@ Declaration::GetPropertyValueInternal(
       // shorthands that are just aliases with different parsing rules
       const nsCSSPropertyID* subprops =
         nsCSSProps::SubpropertyEntryFor(aProperty);
       MOZ_ASSERT(subprops[1] == eCSSProperty_UNKNOWN,
                  "must have exactly one subproperty");
       AppendValueToString(subprops[0], aValue);
       break;
     }
+    case eCSSProperty_overscroll_behavior: {
+      const nsCSSValue& xValue =
+        *data->ValueFor(eCSSProperty_overscroll_behavior_x);
+      const nsCSSValue& yValue =
+        *data->ValueFor(eCSSProperty_overscroll_behavior_y);
+      AppendValueToString(eCSSProperty_overscroll_behavior_x, aValue);
+      if (yValue != xValue) {
+        aValue.Append(char16_t(' '));
+        AppendValueToString(eCSSProperty_overscroll_behavior_y, aValue);
+      }
+      break;
+    }
     case eCSSProperty_scroll_snap_type: {
       const nsCSSValue& xValue =
         *data->ValueFor(eCSSProperty_scroll_snap_type_x);
       const nsCSSValue& yValue =
         *data->ValueFor(eCSSProperty_scroll_snap_type_y);
       if (xValue == yValue) {
         AppendValueToString(eCSSProperty_scroll_snap_type_x, aValue);
       }
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -991,16 +991,17 @@ protected:
   bool ParseDasharray();
   bool ParseMarker();
   bool ParsePaintOrder();
   bool ParseAll();
   bool ParseScrollSnapType();
   bool ParseScrollSnapPoints(nsCSSValue& aValue, nsCSSPropertyID aPropID);
   bool ParseScrollSnapDestination(nsCSSValue& aValue);
   bool ParseScrollSnapCoordinate(nsCSSValue& aValue);
+  bool ParseOverscrollBehavior();
   bool ParseWebkitTextStroke();
 
   /**
    * Parses a variable value from a custom property declaration.
    *
    * @param aType Out parameter into which will be stored the type of variable
    *   value, indicating whether the parsed value was a token stream or one of
    *   the CSS-wide keywords.
@@ -10653,17 +10654,17 @@ CSSParserImpl::ParseWebkitGradientRadius
 //  from(color)
 //  to(color)
 //
 // Quoting https://www.webkit.org/blog/175/introducing-css-gradients/ :
 //   A stop is a function, color-stop, that takes two arguments, the stop value
 //   (either a percentage or a number between 0 and 1.0), and a color (any
 //   valid CSS color). In addition the shorthand functions from and to are
 //   supported. These functions only require a color argument and are
-//   equivalent to color-stop(0, ...) and color-stop(1.0, …) respectively.
+//   equivalent to color-stop(0, ...) and color-stop(1.0, ...) respectively.
 bool
 CSSParserImpl::ParseWebkitGradientColorStop(nsCSSValueGradient* aGradient)
 {
   MOZ_ASSERT(aGradient, "null gradient");
 
   if (!GetToken(true)) {
     return false;
   }
@@ -11806,16 +11807,18 @@ CSSParserImpl::ParsePropertyByFunction(n
   case eCSSProperty_stroke:
     return ParsePaint(aPropID);
   case eCSSProperty_stroke_dasharray:
     return ParseDasharray();
   case eCSSProperty_marker:
     return ParseMarker();
   case eCSSProperty_paint_order:
     return ParsePaintOrder();
+  case eCSSProperty_overscroll_behavior:
+    return ParseOverscrollBehavior();
   case eCSSProperty_scroll_snap_type:
     return ParseScrollSnapType();
   case eCSSProperty_mask:
     return ParseImageLayers(nsStyleImageLayers::kMaskLayerTable);
   case eCSSProperty_mask_repeat:
     return ParseImageLayerRepeat(eCSSProperty_mask_repeat);
   case eCSSProperty_mask_position:
     return ParseImageLayerPosition(nsStyleImageLayers::kMaskLayerTable);
@@ -17488,16 +17491,41 @@ CSSParserImpl::ParseVariableDeclaration(
   }
 
   *aType = type;
   aValue = variableValue;
   return true;
 }
 
 bool
+CSSParserImpl::ParseOverscrollBehavior()
+{
+  static const nsCSSPropertyID ids[] = {
+    eCSSProperty_overscroll_behavior_x,
+    eCSSProperty_overscroll_behavior_y
+  };
+  const int32_t numProps = MOZ_ARRAY_LENGTH(ids);
+
+  nsCSSValue values[numProps];
+  int32_t found = ParseChoice(values, ids, numProps);
+  if (found < 1) {
+    return false;
+  }
+
+  // If only one value is specified, it's used for both axes.
+  if (found == 1) {
+    values[1] = values[0];
+  }
+
+  AppendValue(eCSSProperty_overscroll_behavior_x, values[0]);
+  AppendValue(eCSSProperty_overscroll_behavior_y, values[1]);
+  return true;
+}
+
+bool
 CSSParserImpl::ParseScrollSnapType()
 {
   nsCSSValue value;
   if (!ParseSingleTokenVariant(value, VARIANT_HK,
                                nsCSSProps::kScrollSnapTypeKTable)) {
     return false;
   }
   AppendValue(eCSSProperty_scroll_snap_type_x, value);
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3652,16 +3652,42 @@ CSS_PROP_DISPLAY(
     scroll_behavior,
     ScrollBehavior,
     CSS_PROPERTY_PARSE_VALUE,
     "layout.css.scroll-behavior.property-enabled",
     VARIANT_HK,
     kScrollBehaviorKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Discrete)
+CSS_PROP_SHORTHAND(
+    overscroll-behavior,
+    overscroll_behavior,
+    OverscrollBehavior,
+    CSS_PROPERTY_PARSE_FUNCTION,
+    "layout.css.overscroll-behavior.enabled")
+CSS_PROP_DISPLAY(
+    overscroll-behavior-x,
+    overscroll_behavior_x,
+    OverscrollBehaviorX,
+    CSS_PROPERTY_PARSE_VALUE,
+    "layout.css.overscroll-behavior.enabled",
+    VARIANT_HK,
+    kOverscrollBehaviorKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_Discrete)
+CSS_PROP_DISPLAY(
+    overscroll-behavior-y,
+    overscroll_behavior_y,
+    OverscrollBehaviorY,
+    CSS_PROPERTY_PARSE_VALUE,
+    "layout.css.overscroll-behavior.enabled",
+    VARIANT_HK,
+    kOverscrollBehaviorKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_Discrete)
 CSS_PROP_DISPLAY(
     scroll-snap-coordinate,
     scroll_snap_coordinate,
     ScrollSnapCoordinate,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_PARSER_FUNCTION |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
         CSS_PROPERTY_STORES_CALC,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1934,16 +1934,23 @@ const KTableEntry nsCSSProps::kRubyPosit
 };
 
 const KTableEntry nsCSSProps::kScrollBehaviorKTable[] = {
   { eCSSKeyword_auto,       NS_STYLE_SCROLL_BEHAVIOR_AUTO },
   { eCSSKeyword_smooth,     NS_STYLE_SCROLL_BEHAVIOR_SMOOTH },
   { eCSSKeyword_UNKNOWN,    -1 }
 };
 
+const KTableEntry nsCSSProps::kOverscrollBehaviorKTable[] = {
+  { eCSSKeyword_auto,       StyleOverscrollBehavior::Auto },
+  { eCSSKeyword_contain,    StyleOverscrollBehavior::Contain },
+  { eCSSKeyword_none,       StyleOverscrollBehavior::None },
+  { eCSSKeyword_UNKNOWN,    -1 }
+};
+
 const KTableEntry nsCSSProps::kScrollSnapTypeKTable[] = {
   { eCSSKeyword_none,      NS_STYLE_SCROLL_SNAP_TYPE_NONE },
   { eCSSKeyword_mandatory, NS_STYLE_SCROLL_SNAP_TYPE_MANDATORY },
   { eCSSKeyword_proximity, NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY },
   { eCSSKeyword_UNKNOWN,   -1 }
 };
 
 const KTableEntry nsCSSProps::kStackSizingKTable[] = {
@@ -2998,16 +3005,22 @@ static const nsCSSPropertyID gPlaceSelfS
 
 // Subproperty tables for shorthands that are just aliases with
 // different parsing rules.
 static const nsCSSPropertyID gMozTransformSubpropTable[] = {
   eCSSProperty_transform,
   eCSSProperty_UNKNOWN
 };
 
+static const nsCSSPropertyID gOverscrollBehaviorSubpropTable[] = {
+  eCSSProperty_overscroll_behavior_x,
+  eCSSProperty_overscroll_behavior_y,
+  eCSSProperty_UNKNOWN
+};
+
 static const nsCSSPropertyID gScrollSnapTypeSubpropTable[] = {
   eCSSProperty_scroll_snap_type_x,
   eCSSProperty_scroll_snap_type_y,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSPropertyID gMaskSubpropTable[] = {
   eCSSProperty_mask_image,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -832,16 +832,17 @@ public:
   static const KTableEntry kPositionKTable[];
   static const KTableEntry kRadialGradientShapeKTable[];
   static const KTableEntry kRadialGradientSizeKTable[];
   static const KTableEntry kRadialGradientLegacySizeKTable[];
   static const KTableEntry kResizeKTable[];
   static const KTableEntry kRubyAlignKTable[];
   static const KTableEntry kRubyPositionKTable[];
   static const KTableEntry kScrollBehaviorKTable[];
+  static const KTableEntry kOverscrollBehaviorKTable[];
   static const KTableEntry kScrollSnapTypeKTable[];
   static const KTableEntry kSpeakKTable[];
   static const KTableEntry kSpeakHeaderKTable[];
   static const KTableEntry kSpeakNumeralKTable[];
   static const KTableEntry kSpeakPunctuationKTable[];
   static const KTableEntry kSpeechRateKTable[];
   static const KTableEntry kStackSizingKTable[];
   static const KTableEntry kTableLayoutKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3618,16 +3618,36 @@ nsComputedDOMStyle::DoGetScrollBehavior(
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollBehavior,
                                    nsCSSProps::kScrollBehaviorKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverscrollBehaviorX()
+{
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverscrollBehaviorX,
+                                   nsCSSProps::kOverscrollBehaviorKTable));
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverscrollBehaviorY()
+{
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverscrollBehaviorY,
+                                   nsCSSProps::kOverscrollBehaviorKTable));
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapType()
 {
   const nsStyleDisplay* display = StyleDisplay();
   if (display->mScrollSnapTypeX != display->mScrollSnapTypeY) {
     // No value to return.  We can't express this combination of
     // values as a shorthand.
     return nullptr;
   }
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -511,16 +511,18 @@ private:
   already_AddRefed<CSSValue> DoGetTransformBox();
   already_AddRefed<CSSValue> DoGetTransformOrigin();
   already_AddRefed<CSSValue> DoGetPerspective();
   already_AddRefed<CSSValue> DoGetBackfaceVisibility();
   already_AddRefed<CSSValue> DoGetPerspectiveOrigin();
   already_AddRefed<CSSValue> DoGetTransformStyle();
   already_AddRefed<CSSValue> DoGetOrient();
   already_AddRefed<CSSValue> DoGetScrollBehavior();
+  already_AddRefed<CSSValue> DoGetOverscrollBehaviorX();
+  already_AddRefed<CSSValue> DoGetOverscrollBehaviorY();
   already_AddRefed<CSSValue> DoGetScrollSnapType();
   already_AddRefed<CSSValue> DoGetScrollSnapTypeX();
   already_AddRefed<CSSValue> DoGetScrollSnapTypeY();
   already_AddRefed<CSSValue> DoGetScrollSnapPointsX();
   already_AddRefed<CSSValue> DoGetScrollSnapPointsY();
   already_AddRefed<CSSValue> DoGetScrollSnapDestination();
   already_AddRefed<CSSValue> DoGetScrollSnapCoordinate();
   already_AddRefed<CSSValue> DoGetShapeOutside();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -198,16 +198,18 @@ COMPUTED_STYLE_PROP(outline_color,      
 COMPUTED_STYLE_PROP(outline_offset,                OutlineOffset)
 COMPUTED_STYLE_PROP(outline_style,                 OutlineStyle)
 COMPUTED_STYLE_PROP(outline_width,                 OutlineWidth)
 COMPUTED_STYLE_PROP(overflow,                      Overflow)
 COMPUTED_STYLE_PROP(overflow_clip_box,             OverflowClipBox)
 COMPUTED_STYLE_PROP(overflow_wrap,                 OverflowWrap)
 COMPUTED_STYLE_PROP(overflow_x,                    OverflowX)
 COMPUTED_STYLE_PROP(overflow_y,                    OverflowY)
+COMPUTED_STYLE_PROP(overscroll_behavior_x,         OverscrollBehaviorX)
+COMPUTED_STYLE_PROP(overscroll_behavior_y,         OverscrollBehaviorY)
 //// COMPUTED_STYLE_PROP(padding,                  Padding)
 COMPUTED_STYLE_PROP(padding_bottom,                PaddingBottom)
 COMPUTED_STYLE_PROP(padding_left,                  PaddingLeft)
 COMPUTED_STYLE_PROP(padding_right,                 PaddingRight)
 COMPUTED_STYLE_PROP(padding_top,                   PaddingTop)
 // COMPUTED_STYLE_PROP(page,                       Page)
 COMPUTED_STYLE_PROP(page_break_after,              PageBreakAfter)
 COMPUTED_STYLE_PROP(page_break_before,             PageBreakBefore)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1432,16 +1432,17 @@ struct SetEnumValueHelper
   DEFINE_ENUM_CLASS_SETTER(StyleBoxPack, Start, Justify)
   DEFINE_ENUM_CLASS_SETTER(StyleBoxSizing, Content, Border)
   DEFINE_ENUM_CLASS_SETTER(StyleClear, None, Both)
   DEFINE_ENUM_CLASS_SETTER(StyleContent, OpenQuote, AltContent)
   DEFINE_ENUM_CLASS_SETTER(StyleFillRule, Nonzero, Evenodd)
   DEFINE_ENUM_CLASS_SETTER(StyleFloat, None, InlineEnd)
   DEFINE_ENUM_CLASS_SETTER(StyleFloatEdge, ContentBox, MarginBox)
   DEFINE_ENUM_CLASS_SETTER(StyleHyphens, None, Auto)
+  DEFINE_ENUM_CLASS_SETTER(StyleOverscrollBehavior, Auto, None)
   DEFINE_ENUM_CLASS_SETTER(StyleStackSizing, Ignore, IgnoreVertical)
   DEFINE_ENUM_CLASS_SETTER(StyleTextJustify, None, InterCharacter)
   DEFINE_ENUM_CLASS_SETTER(StyleUserFocus, None, SelectMenu)
   DEFINE_ENUM_CLASS_SETTER(StyleUserSelect, None, MozText)
   DEFINE_ENUM_CLASS_SETTER(StyleUserInput, None, Auto)
   DEFINE_ENUM_CLASS_SETTER(StyleUserModify, ReadOnly, WriteOnly)
   DEFINE_ENUM_CLASS_SETTER(StyleWindowDragging, Default, NoDrag)
   DEFINE_ENUM_CLASS_SETTER(StyleOrient, Inline, Vertical)
@@ -5806,16 +5807,32 @@ nsRuleNode::ComputeDisplayData(void* aSt
            NS_STYLE_CONTAIN_NONE, Unused, Unused);
 
   // scroll-behavior: enum, inherit, initial
   SetValue(*aRuleData->ValueForScrollBehavior(), display->mScrollBehavior,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentDisplay->mScrollBehavior, NS_STYLE_SCROLL_BEHAVIOR_AUTO);
 
+  // overscroll-behavior-x: none, enum, inherit, initial
+  SetValue(*aRuleData->ValueForOverscrollBehaviorX(),
+           display->mOverscrollBehaviorX,
+           conditions,
+           SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
+           parentDisplay->mOverscrollBehaviorX,
+           StyleOverscrollBehavior::Auto);
+
+  // overscroll-behavior-y: none, enum, inherit, initial
+  SetValue(*aRuleData->ValueForOverscrollBehaviorY(),
+           display->mOverscrollBehaviorY,
+           conditions,
+           SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
+           parentDisplay->mOverscrollBehaviorY,
+           StyleOverscrollBehavior::Auto);
+
   // scroll-snap-type-x: none, enum, inherit, initial
   SetValue(*aRuleData->ValueForScrollSnapTypeX(), display->mScrollSnapTypeX,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentDisplay->mScrollSnapTypeX, NS_STYLE_SCROLL_SNAP_TYPE_NONE);
 
   // scroll-snap-type-y: none, enum, inherit, initial
   SetValue(*aRuleData->ValueForScrollSnapTypeY(), display->mScrollSnapTypeY,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -1183,16 +1183,23 @@ enum class StyleWhiteSpace : uint8_t {
 #define NS_STYLE_COUNTER_SPEAKAS_WORDS      2
 #define NS_STYLE_COUNTER_SPEAKAS_SPELL_OUT  3
 #define NS_STYLE_COUNTER_SPEAKAS_OTHER      255 // refer to another style
 
 // See nsStyleDisplay::mScrollBehavior
 #define NS_STYLE_SCROLL_BEHAVIOR_AUTO       0
 #define NS_STYLE_SCROLL_BEHAVIOR_SMOOTH     1
 
+// See nsStyleDisplay::mOverscrollBehavior{X,Y}
+enum class StyleOverscrollBehavior : uint8_t {
+  Auto = 0,
+  Contain,
+  None,
+};
+
 // See nsStyleDisplay::mScrollSnapType{X,Y}
 #define NS_STYLE_SCROLL_SNAP_TYPE_NONE              0
 #define NS_STYLE_SCROLL_SNAP_TYPE_MANDATORY         1
 #define NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY         2
 
 /*****************************************************************************
  * Constants for media features.                                             *
  *****************************************************************************/
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3563,16 +3563,18 @@ nsStyleDisplay::nsStyleDisplay(const nsP
   , mOverflowClipBox(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
   , mResize(NS_STYLE_RESIZE_NONE)
   , mOrient(StyleOrient::Inline)
   , mIsolation(NS_STYLE_ISOLATION_AUTO)
   , mTopLayer(NS_STYLE_TOP_LAYER_NONE)
   , mWillChangeBitField(0)
   , mTouchAction(NS_STYLE_TOUCH_ACTION_AUTO)
   , mScrollBehavior(NS_STYLE_SCROLL_BEHAVIOR_AUTO)
+  , mOverscrollBehaviorX(StyleOverscrollBehavior::Auto)
+  , mOverscrollBehaviorY(StyleOverscrollBehavior::Auto)
   , mScrollSnapTypeX(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
   , mScrollSnapTypeY(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
   , mScrollSnapPointsX(eStyleUnit_None)
   , mScrollSnapPointsY(eStyleUnit_None)
   , mBackfaceVisibility(NS_STYLE_BACKFACE_VISIBILITY_VISIBLE)
   , mTransformStyle(NS_STYLE_TRANSFORM_STYLE_FLAT)
   , mTransformBox(StyleGeometryBox::BorderBox)
   , mSpecifiedTransform(nullptr)
@@ -3626,16 +3628,18 @@ nsStyleDisplay::nsStyleDisplay(const nsS
   , mResize(aSource.mResize)
   , mOrient(aSource.mOrient)
   , mIsolation(aSource.mIsolation)
   , mTopLayer(aSource.mTopLayer)
   , mWillChangeBitField(aSource.mWillChangeBitField)
   , mWillChange(aSource.mWillChange)
   , mTouchAction(aSource.mTouchAction)
   , mScrollBehavior(aSource.mScrollBehavior)
+  , mOverscrollBehaviorX(aSource.mOverscrollBehaviorX)
+  , mOverscrollBehaviorY(aSource.mOverscrollBehaviorY)
   , mScrollSnapTypeX(aSource.mScrollSnapTypeX)
   , mScrollSnapTypeY(aSource.mScrollSnapTypeY)
   , mScrollSnapPointsX(aSource.mScrollSnapPointsX)
   , mScrollSnapPointsY(aSource.mScrollSnapPointsY)
   , mScrollSnapDestination(aSource.mScrollSnapDestination)
   , mScrollSnapCoordinate(aSource.mScrollSnapCoordinate)
   , mBackfaceVisibility(aSource.mBackfaceVisibility)
   , mTransformStyle(aSource.mTransformStyle)
@@ -3700,16 +3704,18 @@ nsStyleDisplay::CalcDifference(const nsS
   nsChangeHint hint = nsChangeHint(0);
 
   if (!DefinitelyEqualURIsAndPrincipal(mBinding.ForceGet(), aNewData.mBinding.ForceGet())
       || mPosition != aNewData.mPosition
       || mDisplay != aNewData.mDisplay
       || mContain != aNewData.mContain
       || (mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None)
       || mScrollBehavior != aNewData.mScrollBehavior
+      || mOverscrollBehaviorX != aNewData.mOverscrollBehaviorX
+      || mOverscrollBehaviorY != aNewData.mOverscrollBehaviorY
       || mScrollSnapTypeX != aNewData.mScrollSnapTypeX
       || mScrollSnapTypeY != aNewData.mScrollSnapTypeY
       || mScrollSnapPointsX != aNewData.mScrollSnapPointsX
       || mScrollSnapPointsY != aNewData.mScrollSnapPointsY
       || mScrollSnapDestination != aNewData.mScrollSnapDestination
       || mTopLayer != aNewData.mTopLayer
       || mResize != aNewData.mResize) {
     return nsChangeHint_ReconstructFrame;
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2582,16 +2582,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
                                 // that are frequently queried. This should
                                 // match mWillChange. Also tracks if any of the
                                 // properties in the will-change list require
                                 // a stacking context.
   nsTArray<RefPtr<nsAtom>> mWillChange;
 
   uint8_t mTouchAction;         // [reset] see nsStyleConsts.h
   uint8_t mScrollBehavior;      // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_BEHAVIOR_*
+  mozilla::StyleOverscrollBehavior mOverscrollBehaviorX;  // [reset] see nsStyleConsts.h
+  mozilla::StyleOverscrollBehavior mOverscrollBehaviorY;  // [reset] see nsStyleConsts.h
   uint8_t mScrollSnapTypeX;     // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_SNAP_TYPE_*
   uint8_t mScrollSnapTypeY;     // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_SNAP_TYPE_*
   nsStyleCoord mScrollSnapPointsX; // [reset]
   nsStyleCoord mScrollSnapPointsY; // [reset]
   mozilla::Position mScrollSnapDestination; // [reset]
   nsTArray<mozilla::Position> mScrollSnapCoordinate; // [reset]
 
   // mSpecifiedTransform is the list of transform functions as
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -7447,16 +7447,44 @@ if (IsCSSPropertyPrefEnabled("layout.css
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto" ],
     other_values: [ "smooth" ],
     invalid_values: [ "none",  "1px" ]
   };
 }
 
+if (IsCSSPropertyPrefEnabled("layout.css.overscroll-behavior.enabled")) {
+  gCSSProperties["overscroll-behavior-x"] = {
+    domProp: "overscrollBehaviorX",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "contain", "none" ],
+    invalid_values: [ "left", "1px" ]
+  };
+  gCSSProperties["overscroll-behavior-y"] = {
+    domProp: "overscrollBehaviorY",
+    inherited: false,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "contain", "none" ],
+    invalid_values: [ "left", "1px" ]
+  };
+  gCSSProperties["overscroll-behavior"] = {
+    domProp: "overscrollBehavior",
+    inherited: false,
+    type: CSS_TYPE_TRUE_SHORTHAND,
+    subproperties: [ "overscroll-behavior-x", "overscroll-behavior-y" ],
+    initial_values: [ "auto" ],
+    other_values: [ "contain", "none", "contain contain", "contain auto", "none contain" ],
+    invalid_values: [ "left", "1px", "contain auto none", "contain nonsense" ]
+  };
+}
+
 if (IsCSSPropertyPrefEnabled("layout.css.scroll-snap.enabled")) {
   gCSSProperties["scroll-snap-coordinate"] = {
     domProp: "scrollSnapCoordinate",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "none" ],
     other_values: [ "25% 25%", "top", "0px 100px, 10em 50%",
                     "top left, top right, bottom left, bottom right, center",
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3025,16 +3025,23 @@ pref("layout.css.control-characters.visi
 #endif
 
 // Is support for column-span enabled?
 pref("layout.css.column-span.enabled", false);
 
 // Are inter-character ruby annotations enabled?
 pref("layout.css.ruby.intercharacter.enabled", false);
 
+// Is support for overscroll-behavior enabled?
+#ifdef RELEASE_OR_BETA
+pref("layout.css.overscroll-behavior.enabled", false);
+#else
+pref("layout.css.overscroll-behavior.enabled", true);
+#endif
+
 // pref for which side vertical scrollbars should be on
 // 0 = end-side in UI direction
 // 1 = end-side in document/content direction
 // 2 = right
 // 3 = left
 pref("layout.scrollbar.side", 0);
 
 // pref to stop overlay scrollbars from fading out, for testing purposes