Commit 8ace3610 authored by criss's avatar criss
Browse files

Backed out 4 changesets (bug 1719427) for causing build bustages. CLOSED TREE

Backed out changeset d6948ef7f495 (bug 1719427)
Backed out changeset 4df7017f6bc9 (bug 1719427)
Backed out changeset 8c5bb08f80e9 (bug 1719427)
Backed out changeset e32004dd2014 (bug 1719427)
parent d516f7d6
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -10,7 +10,6 @@
#define nsITheme_h_

#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/dom/BrowsingContext.h"
#include "nsISupports.h"
#include "nsID.h"
#include "nscore.h"
@@ -256,7 +255,7 @@ class nsITheme : public nsISupports {
   */
  virtual bool ThemeNeedsComboboxDropmarker() = 0;

  virtual bool ThemeSupportsScrollbarButtons() = 0;
  virtual bool ThemeSupportsScrollbarButtons() { return true; }
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsITheme, NS_ITHEME_IID)
@@ -265,7 +264,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsITheme, NS_ITHEME_IID)
//
// Do not use directly, use nsPresContext::Theme instead.
extern already_AddRefed<nsITheme> do_GetNativeThemeDoNotUseDirectly();
extern already_AddRefed<nsITheme> do_GetAndroidNonNativeThemeDoNotUseDirectly();
extern already_AddRefed<nsITheme> do_GetBasicNativeThemeDoNotUseDirectly();
extern already_AddRefed<nsITheme> do_GetRDMThemeDoNotUseDirectly();

#endif
+1 −1
Original line number Diff line number Diff line
@@ -1553,7 +1553,7 @@ nsITheme* nsPresContext::EnsureTheme() {
  if (Document()->ShouldAvoidNativeTheme()) {
    BrowsingContext* bc = Document()->GetBrowsingContext();
    if (bc && bc->Top()->InRDMPane()) {
      mTheme = do_GetRDMThemeDoNotUseDirectly();
      mTheme = do_GetAndroidNonNativeThemeDoNotUseDirectly();
    } else {
      mTheme = do_GetBasicNativeThemeDoNotUseDirectly();
    }
+1 −2
Original line number Diff line number Diff line
@@ -27,8 +27,7 @@ function init()
  downButton = SpecialPowers.unwrap(
    SpecialPowers.InspectorUtils.getChildrenForNode(scrollbar, true)[4]);
  if (!downButton) {
    ok(navigator.userAgent.indexOf("Linux") !== -1 ||
       navigator.userAgent.indexOf("Mac") !== -1, "Theme doesn't support scrollbar buttons");
    ok(navigator.userAgent.indexOf("Linux") !== -1, "Theme doesn't support scrollbar buttons");
    SimpleTest.finish();
    return;
  }
+9 −21
Original line number Diff line number Diff line
@@ -11991,28 +11991,16 @@
  value: false
  mirror: always

# The style of scrollbars to use. Here are the current options:
#
#   0: Default platform scrollbar style.
#   1: macOS scrollbars
#   2: GTK scrollbars
#   3: Android scrollbars
#   4: Windows 10 scrollbars
#
# Note that switching to non-default scrollbars is experimental and other
# scrollbar-related prefs may interfere with the experience. For example,
# setting the GTK thumb size may have no effect when using non-GTK scrollbars
# on GTK.
- name: widget.non-native-theme.scrollbar.style
  type: uint32_t
  value: 0
  mirror: always

# An override that allows to override the default platform size. The size in CSS
# pixels at full zoom of the minimum scrollbar width.
- name: widget.non-native-theme.scrollbar.size.override
# The size in CSS pixels at full zoom of the minimum scrollbar width.
- name: widget.non-native-theme.scrollbar.size
  type: uint32_t
  value: 0
#if defined(MOZ_WIDGET_GTK)
  value: 12
#elif defined(ANDROID)
  value: 6
#else
  value: 17
#endif
  mirror: always

# Whether the active thumb color should always use the themed colors, even if

widget/ScrollbarDrawing.cpp

deleted100644 → 0
+0 −448
Original line number Diff line number Diff line
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * 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 "ScrollbarDrawing.h"

#include "mozilla/RelativeLuminanceUtils.h"
#include "nsContainerFrame.h"
#include "nsDeviceContext.h"
#include "nsIFrame.h"
#include "nsLayoutUtils.h"
#include "nsLookAndFeel.h"
#include "nsNativeTheme.h"

using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::widget;

using ScrollbarParams = ScrollbarDrawing::ScrollbarParams;
using mozilla::RelativeLuminanceUtils;

/* static */
auto ScrollbarDrawing::GetDPIRatioForScrollbarPart(nsPresContext* aPc)
    -> DPIRatio {
  if (auto* rootPc = aPc->GetRootPresContext()) {
    if (nsCOMPtr<nsIWidget> widget = rootPc->GetRootWidget()) {
      return widget->GetDefaultScale();
    }
  }
  return DPIRatio(
      float(AppUnitsPerCSSPixel()) /
      float(aPc->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()));
}

/*static*/
nsIFrame* ScrollbarDrawing::GetParentScrollbarFrame(nsIFrame* aFrame) {
  // Walk our parents to find a scrollbar frame
  nsIFrame* scrollbarFrame = aFrame;
  do {
    if (scrollbarFrame->IsScrollbarFrame()) {
      break;
    }
  } while ((scrollbarFrame = scrollbarFrame->GetParent()));

  // We return null if we can't find a parent scrollbar frame
  return scrollbarFrame;
}

/*static*/
bool ScrollbarDrawing::IsParentScrollbarRolledOver(nsIFrame* aFrame) {
  nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
  return nsLookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) != 0
             ? nsNativeTheme::CheckBooleanAttr(scrollbarFrame, nsGkAtoms::hover)
             : nsNativeTheme::GetContentState(scrollbarFrame,
                                              StyleAppearance::None)
                   .HasState(NS_EVENT_STATE_HOVER);
}

/*static*/
bool ScrollbarDrawing::IsParentScrollbarHoveredOrActive(nsIFrame* aFrame) {
  nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
  return scrollbarFrame && scrollbarFrame->GetContent()
                               ->AsElement()
                               ->State()
                               .HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER |
                                                      NS_EVENT_STATE_ACTIVE);
}

/*static*/
bool ScrollbarDrawing::IsScrollbarWidthThin(const ComputedStyle& aStyle) {
  auto scrollbarWidth = aStyle.StyleUIReset()->mScrollbarWidth;
  return scrollbarWidth == StyleScrollbarWidth::Thin;
}

/*static*/
bool ScrollbarDrawing::IsScrollbarWidthThin(nsIFrame* aFrame) {
  ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
  return IsScrollbarWidthThin(*style);
}

auto ScrollbarDrawing::GetScrollbarSizes(nsPresContext* aPresContext,
                                         StyleScrollbarWidth aWidth, Overlay)
    -> ScrollbarSizes {
  uint32_t h = GetHorizontalScrollbarHeight();
  uint32_t w = GetVerticalScrollbarWidth();
  if (aWidth == StyleScrollbarWidth::Thin) {
    h /= 2;
    w /= 2;
  }
  auto dpi = GetDPIRatioForScrollbarPart(aPresContext);
  return {(CSSCoord(w) * dpi).Rounded(), (CSSCoord(h) * dpi).Rounded()};
}

/*static*/
bool ScrollbarDrawing::IsScrollbarTrackOpaque(nsIFrame* aFrame) {
  auto trackColor = ComputeScrollbarTrackColor(
      aFrame, *nsLayoutUtils::StyleForScrollbar(aFrame),
      aFrame->PresContext()->Document()->GetDocumentState(), Colors(aFrame));
  return trackColor.a == 1.0f;
}

/*static*/
sRGBColor ScrollbarDrawing::ComputeScrollbarTrackColor(
    nsIFrame* aFrame, const ComputedStyle& aStyle,
    const EventStates& aDocumentState, const Colors& aColors) {
  const nsStyleUI* ui = aStyle.StyleUI();
  if (aColors.HighContrast()) {
    return aColors.System(StyleSystemColor::Window);
  }
  if (ShouldUseDarkScrollbar(aFrame, aStyle)) {
    return sRGBColor::FromU8(20, 20, 25, 77);
  }
  if (ui->mScrollbarColor.IsColors()) {
    return sRGBColor::FromABGR(
        ui->mScrollbarColor.AsColors().track.CalcColor(aStyle));
  }
  if (aDocumentState.HasAllStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    return aColors.SystemOrElse(StyleSystemColor::ThemedScrollbarInactive,
                                [] { return sScrollbarColor; });
  }
  return aColors.SystemOrElse(StyleSystemColor::ThemedScrollbar,
                              [] { return sScrollbarColor; });
}

// Don't use the theme color for dark scrollbars if it's not a color (if it's
// grey-ish), as that'd either lack enough contrast, or be close to what we'd do
// by default anyways.
static bool ShouldUseColorForActiveDarkScrollbarThumb(nscolor aColor) {
  auto IsDifferentEnough = [](int32_t aChannel, int32_t aOtherChannel) {
    return std::abs(aChannel - aOtherChannel) > 10;
  };
  return IsDifferentEnough(NS_GET_R(aColor), NS_GET_G(aColor)) ||
         IsDifferentEnough(NS_GET_R(aColor), NS_GET_B(aColor));
}

/*static*/
sRGBColor ScrollbarDrawing::ComputeScrollbarThumbColor(
    nsIFrame* aFrame, const ComputedStyle& aStyle,
    const EventStates& aElementState, const EventStates& aDocumentState,
    const Colors& aColors) {
  if (!aColors.HighContrast() && ShouldUseDarkScrollbar(aFrame, aStyle)) {
    if (aElementState.HasState(NS_EVENT_STATE_ACTIVE) &&
        StaticPrefs::widget_non_native_theme_scrollbar_active_always_themed()) {
      auto color = LookAndFeel::GetColor(
          StyleSystemColor::ThemedScrollbarThumbActive,
          LookAndFeel::ColorScheme::Light, LookAndFeel::UseStandins::No);
      if (color && ShouldUseColorForActiveDarkScrollbarThumb(*color)) {
        return sRGBColor::FromABGR(*color);
      }
    }
    return sRGBColor::FromABGR(ThemeColors::AdjustUnthemedScrollbarThumbColor(
        NS_RGBA(249, 249, 250, 102), aElementState));
  }

  const nsStyleUI* ui = aStyle.StyleUI();
  if (ui->mScrollbarColor.IsColors()) {
    return sRGBColor::FromABGR(ThemeColors::AdjustUnthemedScrollbarThumbColor(
        ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle), aElementState));
  }

  auto systemColor = [&] {
    if (aDocumentState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
      return StyleSystemColor::ThemedScrollbarThumbInactive;
    }
    if (aElementState.HasState(NS_EVENT_STATE_ACTIVE)) {
      if (aColors.HighContrast()) {
        return StyleSystemColor::Selecteditem;
      }
      return StyleSystemColor::ThemedScrollbarThumbActive;
    }
    if (aElementState.HasState(NS_EVENT_STATE_HOVER)) {
      if (aColors.HighContrast()) {
        return StyleSystemColor::Selecteditem;
      }
      return StyleSystemColor::ThemedScrollbarThumbHover;
    }
    if (aColors.HighContrast()) {
      return StyleSystemColor::Windowtext;
    }
    return StyleSystemColor::ThemedScrollbarThumb;
  }();

  return aColors.SystemOrElse(systemColor, [&] {
    return sRGBColor::FromABGR(ThemeColors::AdjustUnthemedScrollbarThumbColor(
        sScrollbarThumbColor.ToABGR(), aElementState));
  });
}

/*static*/
ScrollbarParams ScrollbarDrawing::ComputeScrollbarParams(
    nsIFrame* aFrame, const ComputedStyle& aStyle, bool aIsHorizontal) {
  ScrollbarParams params;
  params.overlay =
      nsLookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) != 0;
  params.rolledOver = IsParentScrollbarRolledOver(aFrame);
  params.small =
      aStyle.StyleUIReset()->mScrollbarWidth == StyleScrollbarWidth::Thin;
  params.rtl = nsNativeTheme::IsFrameRTL(aFrame);
  params.horizontal = aIsHorizontal;
  params.onDarkBackground = !StaticPrefs::widget_disable_dark_scrollbar() &&
                            nsNativeTheme::IsDarkBackground(aFrame);
  // Don't use custom scrollbars for overlay scrollbars since they are
  // generally good enough for use cases of custom scrollbars.
  if (!params.overlay) {
    const nsStyleUI* ui = aStyle.StyleUI();
    if (ui->HasCustomScrollbars()) {
      const auto& colors = ui->mScrollbarColor.AsColors();
      params.custom = true;
      params.trackColor = colors.track.CalcColor(aStyle);
      params.faceColor = colors.thumb.CalcColor(aStyle);
    }
  }

  return params;
}

template <typename PaintBackendData>
bool ScrollbarDrawing::DoPaintDefaultScrollbar(
    PaintBackendData& aPaintData, const LayoutDeviceRect& aRect,
    bool aHorizontal, nsIFrame* aFrame, const ComputedStyle& aStyle,
    const EventStates& aElementState, const EventStates& aDocumentState,
    const Colors& aColors, const DPIRatio& aDpiRatio) {
  if (aFrame->PresContext()->UseOverlayScrollbars() &&
      !aElementState.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER |
                                           NS_EVENT_STATE_ACTIVE)) {
    return true;
  }
  auto scrollbarColor =
      ComputeScrollbarTrackColor(aFrame, aStyle, aDocumentState, aColors);
  ThemeDrawing::FillRect(aPaintData, aRect, scrollbarColor);
  return true;
}

bool ScrollbarDrawing::PaintScrollbar(
    DrawTarget& aDrawTarget, const LayoutDeviceRect& aRect, bool aHorizontal,
    nsIFrame* aFrame, const ComputedStyle& aStyle,
    const EventStates& aElementState, const EventStates& aDocumentState,
    const Colors& aColors, const DPIRatio& aDpiRatio) {
  return DoPaintDefaultScrollbar(aDrawTarget, aRect, aHorizontal, aFrame,
                                 aStyle, aElementState, aDocumentState, aColors,
                                 aDpiRatio);
}

bool ScrollbarDrawing::PaintScrollbar(
    WebRenderBackendData& aWrData, const LayoutDeviceRect& aRect,
    bool aHorizontal, nsIFrame* aFrame, const ComputedStyle& aStyle,
    const EventStates& aElementState, const EventStates& aDocumentState,
    const Colors& aColors, const DPIRatio& aDpiRatio) {
  return DoPaintDefaultScrollbar(aWrData, aRect, aHorizontal, aFrame, aStyle,
                                 aElementState, aDocumentState, aColors,
                                 aDpiRatio);
}

template <typename PaintBackendData>
bool ScrollbarDrawing::DoPaintDefaultScrollCorner(
    PaintBackendData& aPaintData, const LayoutDeviceRect& aRect,
    nsIFrame* aFrame, const ComputedStyle& aStyle,
    const EventStates& aDocumentState, const Colors& aColors,
    const DPIRatio& aDpiRatio) {
  auto scrollbarColor =
      ComputeScrollbarTrackColor(aFrame, aStyle, aDocumentState, aColors);
  ThemeDrawing::FillRect(aPaintData, aRect, scrollbarColor);
  return true;
}

bool ScrollbarDrawing::PaintScrollCorner(
    DrawTarget& aDrawTarget, const LayoutDeviceRect& aRect, nsIFrame* aFrame,
    const ComputedStyle& aStyle, const EventStates& aDocumentState,
    const Colors& aColors, const DPIRatio& aDpiRatio) {
  return DoPaintDefaultScrollCorner(aDrawTarget, aRect, aFrame, aStyle,
                                    aDocumentState, aColors, aDpiRatio);
}

bool ScrollbarDrawing::PaintScrollCorner(WebRenderBackendData& aWrData,
                                         const LayoutDeviceRect& aRect,
                                         nsIFrame* aFrame,
                                         const ComputedStyle& aStyle,
                                         const EventStates& aDocumentState,
                                         const Colors& aColors,
                                         const DPIRatio& aDpiRatio) {
  return DoPaintDefaultScrollCorner(aWrData, aRect, aFrame, aStyle,
                                    aDocumentState, aColors, aDpiRatio);
}

/*static*/
bool ScrollbarDrawing::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);
}

/*static*/
nscolor ScrollbarDrawing::GetScrollbarButtonColor(nscolor aTrackColor,
                                                  EventStates aStates) {
  // See numbers in GetScrollbarArrowColor.
  // This function is written based on ratios between values listed there.

  bool isActive = aStates.HasState(NS_EVENT_STATE_ACTIVE);
  bool isHover = aStates.HasState(NS_EVENT_STATE_HOVER);
  if (!isActive && !isHover) {
    return aTrackColor;
  }
  float luminance = RelativeLuminanceUtils::Compute(aTrackColor);
  if (isActive) {
    if (luminance >= 0.18f) {
      luminance *= 0.134f;
    } else {
      luminance /= 0.134f;
      luminance = std::min(luminance, 1.0f);
    }
  } else {
    if (luminance >= 0.18f) {
      luminance *= 0.805f;
    } else {
      luminance /= 0.805f;
    }
  }
  return RelativeLuminanceUtils::Adjust(aTrackColor, luminance);
}

/*static*/
Maybe<nscolor> ScrollbarDrawing::GetScrollbarArrowColor(nscolor aButtonColor) {
  // In Windows 10 scrollbar, there are several gray colors used:
  //
  // State  | Background (lum) | Arrow   | Contrast
  // -------+------------------+---------+---------
  // Normal | Gray 240 (87.1%) | Gray 96 |     5.5
  // Hover  | Gray 218 (70.1%) | Black   |    15.0
  // Active | Gray 96  (11.7%) | White   |     6.3
  //
  // Contrast value is computed based on the definition in
  // https://www.w3.org/TR/WCAG20/#contrast-ratiodef
  //
  // This function is written based on these values.

  if (NS_GET_A(aButtonColor) == 0) {
    // If the button color is transparent, because of e.g.
    // scrollbar-color: <something> transparent, then use
    // the thumb color, which is expected to have enough
    // contrast.
    return Nothing();
  }

  float luminance = RelativeLuminanceUtils::Compute(aButtonColor);
  // Color with luminance larger than 0.72 has contrast ratio over 4.6
  // to color with luminance of gray 96, so this value is chosen for
  // this range. It is the luminance of gray 221.
  if (luminance >= 0.72) {
    // ComputeRelativeLuminanceFromComponents(96). That function cannot
    // be constexpr because of std::pow.
    const float GRAY96_LUMINANCE = 0.117f;
    return Some(RelativeLuminanceUtils::Adjust(aButtonColor, GRAY96_LUMINANCE));
  }
  // The contrast ratio of a color to black equals that to white when its
  // luminance is around 0.18, with a contrast ratio ~4.6 to both sides,
  // thus the value below. It's the lumanince of gray 118.
  //
  // TODO(emilio): Maybe the button alpha is not the best thing to use here and
  // we should use the thumb alpha? It seems weird that the color of the arrow
  // depends on the opacity of the scrollbar thumb...
  if (luminance >= 0.18) {
    return Some(NS_RGBA(0, 0, 0, NS_GET_A(aButtonColor)));
  }
  return Some(NS_RGBA(255, 255, 255, NS_GET_A(aButtonColor)));
}

std::pair<sRGBColor, sRGBColor> ScrollbarDrawing::ComputeScrollbarButtonColors(
    nsIFrame* aFrame, StyleAppearance aAppearance, const ComputedStyle& aStyle,
    const EventStates& aElementState, const EventStates& aDocumentState,
    const Colors& aColors) {
  if (aColors.HighContrast()) {
    if (aElementState.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE |
                                            NS_EVENT_STATE_HOVER)) {
      return aColors.SystemPair(StyleSystemColor::Selecteditem,
                                StyleSystemColor::Buttonface);
    }
    return aColors.SystemPair(StyleSystemColor::Window,
                              StyleSystemColor::Windowtext);
  }

  auto trackColor =
      ComputeScrollbarTrackColor(aFrame, aStyle, aDocumentState, aColors);
  nscolor buttonColor =
      GetScrollbarButtonColor(trackColor.ToABGR(), aElementState);
  auto arrowColor =
      GetScrollbarArrowColor(buttonColor)
          .map(sRGBColor::FromABGR)
          .valueOrFrom([&] {
            return ComputeScrollbarThumbColor(aFrame, aStyle, aElementState,
                                              aDocumentState, aColors);
          });
  return {sRGBColor::FromABGR(buttonColor), arrowColor};
}

bool ScrollbarDrawing::PaintScrollbarButton(
    DrawTarget& aDrawTarget, StyleAppearance aAppearance,
    const LayoutDeviceRect& aRect, nsIFrame* aFrame,
    const ComputedStyle& aStyle, const EventStates& aElementState,
    const EventStates& aDocumentState, const Colors& aColors,
    const DPIRatio& aDpiRatio) {
  auto [buttonColor, arrowColor] = ComputeScrollbarButtonColors(
      aFrame, aAppearance, aStyle, aElementState, aDocumentState, aColors);
  aDrawTarget.FillRect(aRect.ToUnknownRect(),
                       ColorPattern(ToDeviceColor(buttonColor)));

  // Start with Up arrow.
  float arrowPolygonX[] = {-4.0f, 0.0f, 4.0f, 4.0f, 0.0f, -4.0f};
  float arrowPolygonY[] = {0.0f, -4.0f, 0.0f, 3.0f, -1.0f, 3.0f};

  const float kPolygonSize = 17;

  const int32_t arrowNumPoints = ArrayLength(arrowPolygonX);
  switch (aAppearance) {
    case StyleAppearance::ScrollbarbuttonUp:
      break;
    case StyleAppearance::ScrollbarbuttonDown:
      for (int32_t i = 0; i < arrowNumPoints; i++) {
        arrowPolygonY[i] *= -1;
      }
      break;
    case StyleAppearance::ScrollbarbuttonLeft:
      for (int32_t i = 0; i < arrowNumPoints; i++) {
        float temp = arrowPolygonX[i];
        arrowPolygonX[i] = arrowPolygonY[i];
        arrowPolygonY[i] = temp;
      }
      break;
    case StyleAppearance::ScrollbarbuttonRight:
      for (int32_t i = 0; i < arrowNumPoints; i++) {
        float temp = arrowPolygonX[i];
        arrowPolygonX[i] = arrowPolygonY[i] * -1;
        arrowPolygonY[i] = temp;
      }
      break;
    default:
      return false;
  }
  ThemeDrawing::PaintArrow(aDrawTarget, aRect, arrowPolygonX, arrowPolygonY,
                           kPolygonSize, arrowNumPoints, arrowColor);
  return true;
}
Loading