Bug 1460456 part 3 - Add scrollbar-{face,track}-color properties. r?heycam draft
authorXidorn Quan <me@upsuper.org>
Thu, 10 May 2018 10:40:17 +1000
changeset 795172 d6c176f410fd9ab262855845404938ba5fda7ff1
parent 795171 472637b2ade99e94222be7fcafbc0c4070776398
child 795173 d6ad6f16b116a731fb97e8a6969db4411dfdc9bd
push id109884
push userxquan@mozilla.com
push dateTue, 15 May 2018 05:52:23 +0000
reviewersheycam
bugs1460456
milestone62.0a1
Bug 1460456 part 3 - Add scrollbar-{face,track}-color properties. r?heycam MozReview-Commit-ID: ImNfHHfzRdM
gfx/src/nsITheme.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsComputedDOMStylePropertyList.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
layout/style/test/test_transitions_per_property.html
modules/libpref/init/all.js
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/inherited_ui.mako.rs
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -19,16 +19,17 @@ class gfxContext;
 class nsAttrValue;
 class nsPresContext;
 class nsDeviceContext;
 class nsIFrame;
 class nsAtom;
 class nsIWidget;
 
 namespace mozilla {
+class ComputedStyle;
 namespace layers {
 class StackingContextHelper;
 class WebRenderLayerManager;
 }
 namespace wr {
 class DisplayListBuilder;
 class IpcResourceUpdateQueue;
 }
@@ -68,16 +69,24 @@ public:
    */
   NS_IMETHOD DrawWidgetBackground(gfxContext* aContext,
                                   nsIFrame* aFrame,
                                   uint8_t aWidgetType,
                                   const nsRect& aRect,
                                   const nsRect& aDirtyRect) = 0;
 
   /**
+   * Get the used color of the given widget when it's specified as auto.
+   * It's currently only used for scrollbar-*-color properties.
+   */
+  virtual nscolor GetWidgetAutoColor(mozilla::ComputedStyle* aStyle,
+                                     uint8_t aWidgetType)
+  { return NS_RGB(0, 0, 0); }
+
+  /**
    * Create WebRender commands for the theme background.
    * @return true if the theme knows how to create WebRender commands for the
    *         given widget type, false if DrawWidgetBackground need sto be called
    *         instead.
    */
   virtual bool CreateWebRenderCommandsForWidget(mozilla::wr::DisplayListBuilder& aBuilder,
                                                 mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                 const mozilla::layers::StackingContextHelper& aSc,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1176,16 +1176,42 @@ nsComputedDOMStyle::SetToRGBAColor(nsROC
 
 void
 nsComputedDOMStyle::SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
                                              const StyleComplexColor& aColor)
 {
   SetToRGBAColor(aValue, aColor.CalcColor(mComputedStyle));
 }
 
+void
+nsComputedDOMStyle::SetValueForWidgetColor(nsROCSSPrimitiveValue* aValue,
+                                           const StyleComplexColor& aColor,
+                                           uint8_t aWidgetType)
+{
+  if (!aColor.mIsAuto) {
+    SetToRGBAColor(aValue, aColor.CalcColor(mComputedStyle));
+    return;
+  }
+  nsPresContext* presContext = mPresShell->GetPresContext();
+  MOZ_ASSERT(presContext);
+  if (nsContentUtils::ShouldResistFingerprinting(presContext->GetDocShell())) {
+    // Return transparent when resisting fingerprinting.
+    SetToRGBAColor(aValue, NS_RGBA(0, 0, 0, 0));
+    return;
+  }
+  if (nsITheme* theme = presContext->GetTheme()) {
+    nscolor color = theme->GetWidgetAutoColor(mComputedStyle, aWidgetType);
+    SetToRGBAColor(aValue, color);
+  } else {
+    // If we don't have theme, we don't know what value it should be,
+    // just give it a transparent fallback.
+    SetToRGBAColor(aValue, NS_RGBA(0, 0, 0, 0));
+  }
+}
+
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleColor()->mColor);
   return val.forget();
 }
 
@@ -3767,16 +3793,34 @@ nsComputedDOMStyle::DoGetScrollSnapCoord
       SetValueToPosition(sd->mScrollSnapCoordinate[i], itemList);
       valueList->AppendCSSValue(itemList.forget());
     }
     return valueList.forget();
   }
 }
 
 already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollbarFaceColor()
+{
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  SetValueForWidgetColor(val, StyleUserInterface()->mScrollbarFaceColor,
+                         NS_THEME_SCROLLBARTHUMB_VERTICAL);
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollbarTrackColor()
+{
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  SetValueForWidgetColor(val, StyleUserInterface()->mScrollbarTrackColor,
+                         NS_THEME_SCROLLBAR_VERTICAL);
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineWidth()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleOutline* outline = StyleOutline();
 
   nscoord width;
   if (outline->mOutlineStyle == NS_STYLE_BORDER_STYLE_NONE) {
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -504,16 +504,18 @@ private:
   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> DoGetScrollbarFaceColor();
+  already_AddRefed<CSSValue> DoGetScrollbarTrackColor();
   already_AddRefed<CSSValue> DoGetShapeImageThreshold();
   already_AddRefed<CSSValue> DoGetShapeMargin();
   already_AddRefed<CSSValue> DoGetShapeOutside();
 
   /* User interface properties */
   already_AddRefed<CSSValue> DoGetCaretColor();
   already_AddRefed<CSSValue> DoGetCursor();
   already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
@@ -616,16 +618,19 @@ private:
 
   /* Custom properties */
   already_AddRefed<CSSValue> DoGetCustomProperty(const nsAString& aPropertyName);
 
   /* Helper functions */
   void SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
   void SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
                                 const mozilla::StyleComplexColor& aColor);
+  void SetValueForWidgetColor(nsROCSSPrimitiveValue* aValue,
+                              const mozilla::StyleComplexColor& aColor,
+                              uint8_t aWidgetType);
   void SetValueToStyleImage(const nsStyleImage& aStyleImage,
                             nsROCSSPrimitiveValue* aValue);
   void SetValueToPositionCoord(const mozilla::Position::Coord& aCoord,
                                nsROCSSPrimitiveValue* aValue);
   void SetValueToPosition(const mozilla::Position& aPosition,
                           nsDOMCSSValueList* aValueList);
   void SetValueToURLValue(const mozilla::css::URLValueData* aURL,
                           nsROCSSPrimitiveValue* aValue);
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -228,16 +228,18 @@ COMPUTED_STYLE_PROP(ruby_position,      
 COMPUTED_STYLE_PROP(scale,                         Scale)
 COMPUTED_STYLE_PROP(scroll_behavior,               ScrollBehavior)
 COMPUTED_STYLE_PROP(scroll_snap_coordinate,        ScrollSnapCoordinate)
 COMPUTED_STYLE_PROP(scroll_snap_destination,       ScrollSnapDestination)
 COMPUTED_STYLE_PROP(scroll_snap_points_x,          ScrollSnapPointsX)
 COMPUTED_STYLE_PROP(scroll_snap_points_y,          ScrollSnapPointsY)
 COMPUTED_STYLE_PROP(scroll_snap_type_x,            ScrollSnapTypeX)
 COMPUTED_STYLE_PROP(scroll_snap_type_y,            ScrollSnapTypeY)
+COMPUTED_STYLE_PROP(scrollbar_face_color,          ScrollbarFaceColor)
+COMPUTED_STYLE_PROP(scrollbar_track_color,         ScrollbarTrackColor)
 COMPUTED_STYLE_PROP(shape_image_threshold,         ShapeImageThreshold)
 COMPUTED_STYLE_PROP(shape_margin,                  ShapeMargin)
 COMPUTED_STYLE_PROP(shape_outside,                 ShapeOutside)
 //// COMPUTED_STYLE_PROP(size,                     Size)
 COMPUTED_STYLE_PROP(table_layout,                  TableLayout)
 COMPUTED_STYLE_PROP(text_align,                    TextAlign)
 COMPUTED_STYLE_PROP(text_align_last,               TextAlignLast)
 COMPUTED_STYLE_PROP(text_combine_upright,          TextCombineUpright)
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -4614,28 +4614,32 @@ nsCursorImage::operator==(const nsCursor
 
 nsStyleUserInterface::nsStyleUserInterface(const nsPresContext* aContext)
   : mUserInput(StyleUserInput::Auto)
   , mUserModify(StyleUserModify::ReadOnly)
   , mUserFocus(StyleUserFocus::None)
   , mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
   , mCursor(NS_STYLE_CURSOR_AUTO)
   , mCaretColor(StyleComplexColor::Auto())
+  , mScrollbarFaceColor(StyleComplexColor::Auto())
+  , mScrollbarTrackColor(StyleComplexColor::Auto())
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
 }
 
 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
   : mUserInput(aSource.mUserInput)
   , mUserModify(aSource.mUserModify)
   , mUserFocus(aSource.mUserFocus)
   , mPointerEvents(aSource.mPointerEvents)
   , mCursor(aSource.mCursor)
   , mCursorImages(aSource.mCursorImages)
   , mCaretColor(aSource.mCaretColor)
+  , mScrollbarFaceColor(aSource.mScrollbarFaceColor)
+  , mScrollbarTrackColor(aSource.mScrollbarTrackColor)
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
 }
 
 nsStyleUserInterface::~nsStyleUserInterface()
 {
   MOZ_COUNT_DTOR(nsStyleUserInterface);
 }
@@ -4694,17 +4698,19 @@ nsStyleUserInterface::CalcDifference(con
       hint |= nsChangeHint_NeutralChange;
     }
   }
 
   if (mUserFocus != aNewData.mUserFocus) {
     hint |= nsChangeHint_NeutralChange;
   }
 
-  if (mCaretColor != aNewData.mCaretColor) {
+  if (mCaretColor != aNewData.mCaretColor ||
+      mScrollbarFaceColor != aNewData.mScrollbarFaceColor ||
+      mScrollbarTrackColor != aNewData.mScrollbarTrackColor) {
     hint |= nsChangeHint_RepaintFrame;
   }
 
   return hint;
 }
 
 //-----------------------
 // nsStyleUIReset
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2886,17 +2886,25 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   mozilla::StyleUserModify  mUserModify;      // [inherited] (modify-content)
   mozilla::StyleUserFocus   mUserFocus;       // [inherited] (auto-select)
   uint8_t                   mPointerEvents;   // [inherited] see nsStyleConsts.h
 
   uint8_t mCursor;                            // [inherited] See nsStyleConsts.h
   nsTArray<nsCursorImage> mCursorImages;      // [inherited] images and coords
   mozilla::StyleComplexColor mCaretColor;     // [inherited]
 
+  mozilla::StyleComplexColor mScrollbarFaceColor;   // [inherited]
+  mozilla::StyleComplexColor mScrollbarTrackColor;  // [inherited]
+
   inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
+
+  bool HasCustomScrollbars() const
+  {
+    return !mScrollbarFaceColor.mIsAuto || !mScrollbarTrackColor.mIsAuto;
+  }
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL
 {
   explicit nsStyleXUL(const nsPresContext* aContext);
   nsStyleXUL(const nsStyleXUL& aSource);
   ~nsStyleXUL();
   void FinishStyle(nsPresContext*, const nsStyleXUL*) {}
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -8358,8 +8358,27 @@ if (IsCSSPropertyPrefEnabled("layout.css
   if (IsCSSPropertyPrefEnabled("layout.css.prefixes.gradients")) {
     gCSSProperties["background-image"].invalid_values.push(
       "-moz-linear-gradient(unset, 10px 10px, from(blue))",
       "-moz-linear-gradient(unset, 10px 10px, blue 0)",
       "-moz-repeating-linear-gradient(unset, 10px 10px, blue 0)",
     );
   }
 }
+
+if (IsCSSPropertyPrefEnabled("layout.css.scrollbar-colors.enabled")) {
+  gCSSProperties["scrollbar-face-color"] = {
+    domProp: "scrollbarFaceColor",
+    inherited: true,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "red", "blue", "#ffff00" ],
+    invalid_values: [ "ffff00" ]
+  };
+  gCSSProperties["scrollbar-track-color"] = {
+    domProp: "scrollbarTrackColor",
+    inherited: true,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "red", "blue", "#ffff00" ],
+    invalid_values: [ "ffff00" ]
+  };
+}
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -331,16 +331,29 @@ if (IsCSSPropertyPrefEnabled("layout.css
 
 if (IsCSSPropertyPrefEnabled("layout.css.individual-transform.enabled") &&
     SpecialPowers.DOMWindowUtils.isStyledByServo) {
   supported_properties["rotate"] = [ test_rotate_transition ];
   supported_properties["scale"] = [ test_scale_transition ];
   supported_properties["translate"] = [ test_translate_transition ];
 }
 
+if (IsCSSPropertyPrefEnabled("layout.css.scrollbar-colors.enabled")) {
+  supported_properties["scrollbar-face-color"] = [
+    test_color_transition,
+    test_true_currentcolor_transition,
+    test_auto_color_transition,
+  ];
+  supported_properties["scrollbar-track-color"] = [
+    test_color_transition,
+    test_true_currentcolor_transition,
+    test_auto_color_transition,
+  ];
+}
+
 var div = document.getElementById("display");
 var OMTAdiv = document.getElementById("transformTest");
 var cs = getComputedStyle(div, "");
 var OMTACs = getComputedStyle(OMTAdiv, "");
 var winUtils = SpecialPowers.getDOMWindowUtils(window);
 
 function computeMatrix(v) {
   div.style.setProperty("transform", v, "");
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2837,16 +2837,19 @@ pref("layout.css.initial-letter.enabled"
 pref("layout.css.mix-blend-mode.enabled", true);
 
 // Is support for isolation enabled?
 pref("layout.css.isolation.enabled", true);
 
 // Is support for CSS Filters enabled?
 pref("layout.css.filters.enabled", true);
 
+// Is support for CSS Scrollbar color properties enabled?
+pref("layout.css.scrollbar-colors.enabled", false);
+
 // Set the threshold distance in CSS pixels below which scrolling will snap to
 // an edge, when scroll snapping is set to "proximity".
 pref("layout.css.scroll-snap.proximity-threshold", 200);
 
 // When selecting the snap point for CSS scroll snapping, the velocity of the
 // scroll frame is clamped to this speed, in CSS pixels / s.
 pref("layout.css.scroll-snap.prediction-max-velocity", 2000);
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1436,16 +1436,17 @@ impl Clone for ${style_struct.gecko_stru
 <%
     style_struct = next(x for x in data.style_structs if x.name == style_struct_name)
     longhands = [x for x in style_struct.longhands
                 if not (skip_longhands == "*" or x.name in skip_longhands.split())]
 
     # Types used with predefined_type()-defined properties that we can auto-generate.
     predefined_types = {
         "Color": impl_color,
+        "ColorOrAuto": impl_color,
         "GreaterThanOrEqualToOneNumber": impl_simple,
         "Integer": impl_simple,
         "length::LengthOrAuto": impl_style_coord,
         "length::LengthOrNormal": impl_style_coord,
         "length::NonNegativeLengthOrAuto": impl_style_coord,
         "length::NonNegativeLengthOrPercentageOrNormal": impl_style_coord,
         "FlexBasis": impl_style_coord,
         "Length": impl_absolute_length,
@@ -5258,17 +5259,17 @@ clip-path
 
     pub fn clone_color(&self) -> longhands::color::computed_value::T {
         let color = ${get_gecko_property("mColor")} as u32;
         convert_nscolor_to_rgba(color)
     }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="InheritedUI"
-                  skip_longhands="cursor caret-color">
+                  skip_longhands="cursor">
     pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
         use style_traits::cursor::CursorKind;
 
         self.gecko.mCursor = match v.keyword {
             CursorKind::Auto => structs::NS_STYLE_CURSOR_AUTO,
             CursorKind::None => structs::NS_STYLE_CURSOR_NONE,
             CursorKind::Default => structs::NS_STYLE_CURSOR_DEFAULT,
             CursorKind::Pointer => structs::NS_STYLE_CURSOR_POINTER,
@@ -5405,18 +5406,16 @@ clip-path
                     None
                 };
 
             CursorImage { url, hotspot }
         }).collect::<Vec<_>>().into_boxed_slice();
 
         longhands::cursor::computed_value::T { images, keyword }
     }
-
-    <%call expr="impl_color('caret_color', 'mCaretColor')"></%call>
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Column"
                   skip_longhands="column-count column-rule-width">
 
     #[allow(unused_unsafe)]
     pub fn set_column_count(&mut self, v: longhands::column_count::computed_value::T) {
         use gecko_bindings::structs::{NS_STYLE_COLUMN_COUNT_AUTO, nsStyleColumn_kMaxColumnCount};
--- a/servo/components/style/properties/longhand/inherited_ui.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_ui.mako.rs
@@ -45,8 +45,30 @@
     "caret-color",
     "ColorOrAuto",
     "Either::Second(Auto)",
     spec="https://drafts.csswg.org/css-ui/#caret-color",
     animation_value_type="AnimatedCaretColor",
     ignored_when_colors_disabled=True,
     products="gecko",
 )}
+
+// Only scrollbar-face-color and scrollbar-track-color are added here.
+// These two are the only common parts of scrollbar among Windows and
+// macOS. We may or may not want to provide other properties to allow
+// finer-grain control.
+//
+// NOTE The syntax in spec is currently `normal | <color>`, but I think
+//      reusing `auto | <color>` as `caret-color` makes more sense. See
+//      https://github.com/w3c/csswg-drafts/issues/2660
+% for part in ["face", "track"]:
+${helpers.predefined_type(
+    "scrollbar-%s-color" % part,
+    "ColorOrAuto",
+    "Either::Second(Auto)",
+    spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-color-properties",
+    gecko_pref="layout.css.scrollbar-colors.enabled",
+    animation_value_type="ColorOrAuto",
+    ignored_when_colors_disabled=True,
+    enabled_in="chrome",
+    products="gecko",
+)}
+% endfor