Bug 1690700 - Improve scrollbars for non-native GTK theme. r=mstange
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 04 Feb 2021 16:15:27 +0000
changeset 566014 0f49cded2ff868b4a4048f07d4cf892db8e542ab
parent 566013 8529f7bef5b95ec28712fc89c9f2748a87361e14
child 566015 86bbfadfe291974fe3decce632317a7a4a36968a
push id38173
push userbtara@mozilla.com
push dateFri, 05 Feb 2021 09:34:54 +0000
treeherdermozilla-central@48895a7f84a6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1690700
milestone87.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 1690700 - Improve scrollbars for non-native GTK theme. r=mstange This is based on the windows implementation and has two nice things: * Makes scrollbar-color react to active / hover state, like on Windows. * Implements dark scrollbar support. Differential Revision: https://phabricator.services.mozilla.com/D103969
widget/gtk/nsNativeBasicThemeGTK.cpp
widget/gtk/nsNativeBasicThemeGTK.h
widget/nsNativeBasicTheme.cpp
widget/nsNativeBasicTheme.h
widget/windows/ScrollbarUtil.cpp
widget/windows/ScrollbarUtil.h
--- a/widget/gtk/nsNativeBasicThemeGTK.cpp
+++ b/widget/gtk/nsNativeBasicThemeGTK.cpp
@@ -5,16 +5,28 @@
 
 #include "nsNativeBasicThemeGTK.h"
 
 #include "nsLayoutUtils.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/StaticPrefs_widget.h"
 
 using namespace mozilla;
+using mozilla::gfx::sRGBColor;
+
+static bool ShouldUseDarkScrollbar(nsIFrame* aFrame,
+                                   const ComputedStyle& aStyle) {
+  if (StaticPrefs::widget_disable_dark_scrollbar()) {
+    return false;
+  }
+  if (aStyle.StyleUI()->mScrollbarColor.IsColors()) {
+    return false;
+  }
+  return nsNativeTheme::IsDarkBackground(aFrame);
+}
 
 already_AddRefed<nsITheme> do_GetBasicNativeThemeDoNotUseDirectly() {
   static StaticRefPtr<nsITheme> gInstance;
   if (MOZ_UNLIKELY(!gInstance)) {
     gInstance = new nsNativeBasicThemeGTK();
     ClearOnShutdown(&gInstance);
   }
   return do_AddRef(gInstance);
@@ -41,16 +53,38 @@ auto nsNativeBasicThemeGTK::GetScrollbar
   CSSCoord size =
       aWidth == StyleScrollbarWidth::Thin
           ? StaticPrefs::widget_gtk_non_native_scrollbar_thin_size()
           : StaticPrefs::widget_gtk_non_native_scrollbar_normal_size();
   LayoutDeviceIntCoord s = (size * dpiRatio).Truncated();
   return {s, s};
 }
 
+std::pair<sRGBColor, sRGBColor> nsNativeBasicThemeGTK::ComputeScrollbarColors(
+    nsIFrame* aFrame, const ComputedStyle& aStyle,
+    const EventStates& aDocumentState) {
+  if (ShouldUseDarkScrollbar(aFrame, aStyle)) {
+    auto color = sRGBColor::FromU8(20, 20, 25, 77);
+    return {color, color};
+  }
+  return nsNativeBasicTheme::ComputeScrollbarColors(aFrame, aStyle,
+                                                    aDocumentState);
+}
+
+sRGBColor nsNativeBasicThemeGTK::ComputeScrollbarThumbColor(
+    nsIFrame* aFrame, const ComputedStyle& aStyle,
+    const EventStates& aElementState, const EventStates& aDocumentState) {
+  if (ShouldUseDarkScrollbar(aFrame, aStyle)) {
+    return sRGBColor::FromABGR(AdjustUnthemedScrollbarThumbColor(
+        NS_RGBA(249, 249, 250, 102), aElementState));
+  }
+  return nsNativeBasicTheme::ComputeScrollbarThumbColor(
+      aFrame, aStyle, aElementState, aDocumentState);
+}
+
 NS_IMETHODIMP
 nsNativeBasicThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
                                             nsIFrame* aFrame,
                                             StyleAppearance aAppearance,
                                             LayoutDeviceIntSize* aResult,
                                             bool* aIsOverridable) {
   if (!IsWidgetScrollbarPart(aAppearance)) {
     return nsNativeBasicTheme::GetMinimumWidgetSize(
--- a/widget/gtk/nsNativeBasicThemeGTK.h
+++ b/widget/gtk/nsNativeBasicThemeGTK.h
@@ -31,16 +31,22 @@ class nsNativeBasicThemeGTK : public nsN
                       const ComputedStyle& aStyle,
                       const EventStates& aDocumentState,
                       DPIRatio aDpiRatio) override;
   void PaintScrollCorner(DrawTarget* aDrawTarget, const LayoutDeviceRect& aRect,
                          nsIFrame* aFrame, const ComputedStyle& aStyle,
                          const EventStates& aDocumentState,
                          DPIRatio aDpiRatio) override;
   bool ThemeSupportsScrollbarButtons() override { return false; }
+  sRGBColor ComputeScrollbarThumbColor(
+      nsIFrame*, const ComputedStyle&, const EventStates& aElementState,
+      const EventStates& aDocumentState) override;
+  std::pair<sRGBColor, sRGBColor> ComputeScrollbarColors(
+      nsIFrame*, const ComputedStyle&,
+      const EventStates& aDocumentState) override;
   ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
                                    Overlay) override;
 
  protected:
   virtual ~nsNativeBasicThemeGTK() = default;
 };
 
 #endif
--- a/widget/nsNativeBasicTheme.cpp
+++ b/widget/nsNativeBasicTheme.cpp
@@ -6,16 +6,17 @@
 #include "nsNativeBasicTheme.h"
 
 #include "gfxBlur.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/gfx/Filters.h"
+#include "mozilla/RelativeLuminanceUtils.h"
 #include "nsCSSColorUtils.h"
 #include "nsCSSRendering.h"
 #include "nsLayoutUtils.h"
 #include "PathHelpers.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 using namespace mozilla::gfx;
@@ -353,23 +354,57 @@ std::pair<sRGBColor, sRGBColor> nsNative
                                   sScrollbarColor.ToABGR());
   } else {
     color = LookAndFeel::GetColor(LookAndFeel::ColorID::ThemedScrollbar,
                                   sScrollbarColor.ToABGR());
   }
   return std::make_pair(gfx::sRGBColor::FromABGR(color), sScrollbarBorderColor);
 }
 
+nscolor nsNativeBasicTheme::AdjustUnthemedScrollbarThumbColor(
+    nscolor aFaceColor, EventStates aStates) {
+  // In Windows 10, scrollbar thumb has the following colors:
+  //
+  // State  | Color    | Luminance
+  // -------+----------+----------
+  // Normal | Gray 205 |     61.0%
+  // Hover  | Gray 166 |     38.1%
+  // Active | Gray 96  |     11.7%
+  //
+  // This function is written based on the ratios between the values.
+  bool isActive = aStates.HasState(NS_EVENT_STATE_ACTIVE);
+  bool isHover = aStates.HasState(NS_EVENT_STATE_HOVER);
+  if (!isActive && !isHover) {
+    return aFaceColor;
+  }
+  float luminance = RelativeLuminanceUtils::Compute(aFaceColor);
+  if (isActive) {
+    if (luminance >= 0.18f) {
+      luminance *= 0.192f;
+    } else {
+      luminance /= 0.192f;
+    }
+  } else {
+    if (luminance >= 0.18f) {
+      luminance *= 0.625f;
+    } else {
+      luminance /= 0.625f;
+    }
+  }
+  return RelativeLuminanceUtils::Adjust(aFaceColor, luminance);
+}
+
 sRGBColor nsNativeBasicTheme::ComputeScrollbarThumbColor(
     nsIFrame* aFrame, const ComputedStyle& aStyle,
     const EventStates& aElementState, const EventStates& aDocumentState) {
   const nsStyleUI* ui = aStyle.StyleUI();
   nscolor color;
   if (ui->mScrollbarColor.IsColors()) {
-    color = ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle);
+    color = AdjustUnthemedScrollbarThumbColor(
+        ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle), aElementState);
   } else if (aDocumentState.HasAllStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
     color = LookAndFeel::GetColor(
         LookAndFeel::ColorID::ThemedScrollbarThumbInactive,
         sScrollbarThumbColor.ToABGR());
   } else if (aElementState.HasAllStates(NS_EVENT_STATE_ACTIVE)) {
     color =
         LookAndFeel::GetColor(LookAndFeel::ColorID::ThemedScrollbarThumbActive,
                               sScrollbarThumbColorActive.ToABGR());
--- a/widget/nsNativeBasicTheme.h
+++ b/widget/nsNativeBasicTheme.h
@@ -184,16 +184,17 @@ class nsNativeBasicTheme : protected nsN
   bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
                            StyleAppearance aAppearance) override;
   bool WidgetIsContainer(StyleAppearance aAppearance) override;
   bool ThemeDrawsFocusForWidget(StyleAppearance aAppearance) override;
   bool ThemeNeedsComboboxDropmarker() override;
   ScrollbarSizes GetScrollbarSizes(nsPresContext*,
                                    StyleScrollbarWidth,
                                    Overlay) override;
+  static nscolor AdjustUnthemedScrollbarThumbColor(nscolor, EventStates);
 
  protected:
   nsNativeBasicTheme() = default;
   virtual ~nsNativeBasicTheme() = default;
 
   static DPIRatio GetDPIRatioForScrollbarPart(nsPresContext*);
   static DPIRatio GetDPIRatio(nsPresContext*, StyleAppearance);
   static DPIRatio GetDPIRatio(nsIFrame* aFrame, StyleAppearance);
--- a/widget/windows/ScrollbarUtil.cpp
+++ b/widget/windows/ScrollbarUtil.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScrollbarUtil.h"
 
 #include "mozilla/RelativeLuminanceUtils.h"
 #include "mozilla/StaticPrefs_widget.h"
 #include "nsNativeTheme.h"
+#include "nsNativeBasicTheme.h"
 
 /*static*/
 bool ScrollbarUtil::IsScrollbarWidthThin(ComputedStyle* aStyle) {
   auto scrollbarWidth = aStyle->StyleUIReset()->mScrollbarWidth;
   return scrollbarWidth == StyleScrollbarWidth::Thin;
 }
 
 /*static*/
@@ -98,51 +99,16 @@ nscolor ScrollbarUtil::GetScrollbarArrow
   // thus the value below. It's the lumanince of gray 118.
   if (luminance >= 0.18) {
     return NS_RGBA(0, 0, 0, NS_GET_A(aButtonColor));
   }
   return NS_RGBA(255, 255, 255, NS_GET_A(aButtonColor));
 }
 
 /*static*/
-nscolor ScrollbarUtil::AdjustScrollbarFaceColor(nscolor aFaceColor,
-                                                EventStates aStates) {
-  // In Windows 10, scrollbar thumb has the following colors:
-  //
-  // State  | Color    | Luminance
-  // -------+----------+----------
-  // Normal | Gray 205 |     61.0%
-  // Hover  | Gray 166 |     38.1%
-  // Active | Gray 96  |     11.7%
-  //
-  // This function is written based on the ratios between the values.
-
-  bool isActive = aStates.HasState(NS_EVENT_STATE_ACTIVE);
-  bool isHover = aStates.HasState(NS_EVENT_STATE_HOVER);
-  if (!isActive && !isHover) {
-    return aFaceColor;
-  }
-  float luminance = RelativeLuminanceUtils::Compute(aFaceColor);
-  if (isActive) {
-    if (luminance >= 0.18f) {
-      luminance *= 0.192f;
-    } else {
-      luminance /= 0.192f;
-    }
-  } else {
-    if (luminance >= 0.18f) {
-      luminance *= 0.625f;
-    } else {
-      luminance /= 0.625f;
-    }
-  }
-  return RelativeLuminanceUtils::Adjust(aFaceColor, luminance);
-}
-
-/*static*/
 nscolor ScrollbarUtil::GetScrollbarTrackColor(nsIFrame* aFrame) {
   bool darkScrollbar = false;
   ComputedStyle* style = GetCustomScrollbarStyle(aFrame, &darkScrollbar);
   if (style) {
     const nsStyleUI* ui = style->StyleUI();
     auto* customColors = ui->mScrollbarColor.IsAuto()
                              ? nullptr
                              : &ui->mScrollbarColor.AsColors();
@@ -153,29 +119,29 @@ nscolor ScrollbarUtil::GetScrollbarTrack
   return darkScrollbar ? NS_RGBA(20, 20, 25, 77) : NS_RGB(240, 240, 240);
 }
 
 /*static*/
 nscolor ScrollbarUtil::GetScrollbarThumbColor(nsIFrame* aFrame,
                                               EventStates aEventStates) {
   bool darkScrollbar = false;
   ComputedStyle* style = GetCustomScrollbarStyle(aFrame, &darkScrollbar);
+  nscolor color =
+      darkScrollbar ? NS_RGBA(249, 249, 250, 102) : NS_RGB(205, 205, 205);
   if (style) {
     const nsStyleUI* ui = style->StyleUI();
     auto* customColors = ui->mScrollbarColor.IsAuto()
                              ? nullptr
                              : &ui->mScrollbarColor.AsColors();
     if (customColors) {
-      nscolor faceColor = customColors->thumb.CalcColor(*style);
-      return AdjustScrollbarFaceColor(faceColor, aEventStates);
+      color = customColors->thumb.CalcColor(*style);
     }
   }
-  nscolor faceColor =
-      darkScrollbar ? NS_RGBA(249, 249, 250, 102) : NS_RGB(205, 205, 205);
-  return AdjustScrollbarFaceColor(faceColor, aEventStates);
+  return nsNativeBasicTheme::AdjustUnthemedScrollbarThumbColor(color,
+                                                               aEventStates);
 }
 
 /*static*/
 Maybe<nsITheme::Transparency> ScrollbarUtil::GetScrollbarPartTransparency(
     nsIFrame* aFrame, StyleAppearance aAppearance) {
   if (nsNativeTheme::IsWidgetScrollbarPart(aAppearance)) {
     if (ComputedStyle* style = ScrollbarUtil::GetCustomScrollbarStyle(aFrame)) {
       auto* ui = style->StyleUI();
--- a/widget/windows/ScrollbarUtil.h
+++ b/widget/windows/ScrollbarUtil.h
@@ -20,18 +20,16 @@ class ScrollbarUtil {
   // Optionally the caller can pass a pointer to aDarkScrollbar for whether
   // custom scrollbar may be drawn due to dark background.
   static ComputedStyle* GetCustomScrollbarStyle(nsIFrame* aFrame,
                                                 bool* aDarkScrollbar = nullptr);
 
   static nscolor GetScrollbarButtonColor(nscolor aTrackColor,
                                          EventStates aStates);
   static nscolor GetScrollbarArrowColor(nscolor aButtonColor);
-  static nscolor AdjustScrollbarFaceColor(nscolor aFaceColor,
-                                          EventStates aStates);
   static nscolor GetScrollbarTrackColor(nsIFrame* aFrame);
   static nscolor GetScrollbarThumbColor(nsIFrame* aFrame,
                                         EventStates aEventStates);
   static Maybe<nsITheme::Transparency> GetScrollbarPartTransparency(
       nsIFrame* aFrame, StyleAppearance aAppearance);
 
  protected:
   ScrollbarUtil() = default;