/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * 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/. */ #ifndef nsNativeBasicTheme_h #define nsNativeBasicTheme_h #include "Units.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Rect.h" #include "mozilla/gfx/Types.h" #include "nsITheme.h" #include "nsNativeTheme.h" namespace mozilla { enum class StyleSystemColor : uint8_t; namespace widget { static const gfx::sRGBColor sColorWhite(gfx::sRGBColor::OpaqueWhite()); static const gfx::sRGBColor sColorWhiteAlpha50(gfx::sRGBColor::White(0.5f)); static const gfx::sRGBColor sColorWhiteAlpha80(gfx::sRGBColor::White(0.8f)); static const gfx::sRGBColor sColorBlack(gfx::sRGBColor::OpaqueBlack()); static const gfx::sRGBColor sColorGrey10( gfx::sRGBColor::UnusualFromARGB(0xffe9e9ed)); static const gfx::sRGBColor sColorGrey10Alpha50( gfx::sRGBColor::UnusualFromARGB(0x7fe9e9ed)); static const gfx::sRGBColor sColorGrey20( gfx::sRGBColor::UnusualFromARGB(0xffd0d0d7)); static const gfx::sRGBColor sColorGrey30( gfx::sRGBColor::UnusualFromARGB(0xffb1b1b9)); static const gfx::sRGBColor sColorGrey40( gfx::sRGBColor::UnusualFromARGB(0xff8f8f9d)); static const gfx::sRGBColor sColorGrey40Alpha50( gfx::sRGBColor::UnusualFromARGB(0x7f8f8f9d)); static const gfx::sRGBColor sColorGrey50( gfx::sRGBColor::UnusualFromARGB(0xff676774)); static const gfx::sRGBColor sColorGrey50Alpha50( gfx::sRGBColor::UnusualFromARGB(0x7f676774)); static const gfx::sRGBColor sColorGrey60( gfx::sRGBColor::UnusualFromARGB(0xff484851)); static const gfx::sRGBColor sColorGrey60Alpha50( gfx::sRGBColor::UnusualFromARGB(0x7f484851)); static const gfx::sRGBColor sColorMeterGreen10( gfx::sRGBColor::UnusualFromARGB(0xff00ab60)); static const gfx::sRGBColor sColorMeterGreen20( gfx::sRGBColor::UnusualFromARGB(0xff056139)); static const gfx::sRGBColor sColorMeterYellow10( gfx::sRGBColor::UnusualFromARGB(0xffffbd4f)); static const gfx::sRGBColor sColorMeterYellow20( gfx::sRGBColor::UnusualFromARGB(0xffd2811e)); static const gfx::sRGBColor sColorMeterRed10( gfx::sRGBColor::UnusualFromARGB(0xffe22850)); static const gfx::sRGBColor sColorMeterRed20( gfx::sRGBColor::UnusualFromARGB(0xff810220)); static const gfx::sRGBColor sScrollbarColor( gfx::sRGBColor::UnusualFromARGB(0xfff0f0f0)); static const gfx::sRGBColor sScrollbarBorderColor(gfx::sRGBColor(1.0f, 1.0f, 1.0f)); static const gfx::sRGBColor sScrollbarThumbColor( gfx::sRGBColor::UnusualFromARGB(0xffcdcdcd)); static const CSSCoord kMinimumColorPickerHeight = 32.0f; static const CSSCoord kMinimumRangeThumbSize = 20.0f; static const CSSCoord kMinimumDropdownArrowButtonWidth = 18.0f; static const CSSCoord kMinimumSpinnerButtonWidth = 18.0f; static const CSSCoord kMinimumSpinnerButtonHeight = 9.0f; static const CSSCoord kButtonBorderWidth = 1.0f; static const CSSCoord kMenulistBorderWidth = 1.0f; static const CSSCoord kTextFieldBorderWidth = 1.0f; static const CSSCoord kRangeHeight = 6.0f; static const CSSCoord kProgressbarHeight = 6.0f; static const CSSCoord kMeterHeight = 12.0f; // nsCheckboxRadioFrame takes the bottom of the content box as the baseline. // This border-width makes its baseline 2px under the bottom, which is nice. static constexpr CSSCoord kCheckboxRadioBorderWidth = 2.0f; } // namespace widget } // namespace mozilla class nsNativeBasicTheme : protected nsNativeTheme, public nsITheme { protected: using sRGBColor = mozilla::gfx::sRGBColor; using CSSCoord = mozilla::CSSCoord; using CSSPoint = mozilla::CSSPoint; using CSSIntCoord = mozilla::CSSIntCoord; using ComputedStyle = mozilla::ComputedStyle; using EventStates = mozilla::EventStates; using DrawTarget = mozilla::gfx::DrawTarget; using Path = mozilla::gfx::Path; using Rect = mozilla::gfx::Rect; using Point = mozilla::gfx::Point; using RectCornerRadii = mozilla::gfx::RectCornerRadii; using LayoutDeviceCoord = mozilla::LayoutDeviceCoord; using LayoutDeviceRect = mozilla::LayoutDeviceRect; public: static void Init(); static void Shutdown(); static void LookAndFeelChanged(); using DPIRatio = mozilla::CSSToLayoutDeviceScale; NS_DECL_ISUPPORTS_INHERITED // The nsITheme interface. NS_IMETHOD DrawWidgetBackground(gfxContext* aContext, nsIFrame*, StyleAppearance, const nsRect& aRect, const nsRect& aDirtyRect, DrawOverflow) override; struct WebRenderBackendData { mozilla::wr::DisplayListBuilder& mBuilder; mozilla::wr::IpcResourceUpdateQueue& mResources; const mozilla::layers::StackingContextHelper& mSc; mozilla::layers::RenderRootStateManager* mManager; }; bool CreateWebRenderCommandsForWidget( mozilla::wr::DisplayListBuilder& aBuilder, mozilla::wr::IpcResourceUpdateQueue& aResources, const mozilla::layers::StackingContextHelper& aSc, mozilla::layers::RenderRootStateManager* aManager, nsIFrame*, StyleAppearance, const nsRect& aRect) override; // PaintBackendData will be either a DrawTarget, or a WebRenderBackendData. // // The return value represents whether the widget could be painted with the // given back-end. template bool DoDrawWidgetBackground(PaintBackendData&, nsIFrame*, StyleAppearance, const nsRect&, DrawOverflow); [[nodiscard]] LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, nsIFrame*, StyleAppearance) override; bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame*, StyleAppearance, LayoutDeviceIntMargin* aResult) override; bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame*, StyleAppearance, nsRect* aOverflowRect) override; NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame*, StyleAppearance, mozilla::LayoutDeviceIntSize* aResult, bool* aIsOverridable) override; Transparency GetWidgetTransparency(nsIFrame*, StyleAppearance) override; NS_IMETHOD WidgetStateChanged(nsIFrame*, StyleAppearance, nsAtom* aAttribute, bool* aShouldRepaint, const nsAttrValue* aOldValue) override; NS_IMETHOD ThemeChanged() override; bool WidgetAppearanceDependsOnWindowFocus(StyleAppearance) override; /*bool NeedToClearBackgroundBehindWidget( nsIFrame*, StyleAppearance) override;*/ ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame*, StyleAppearance) override; bool ThemeSupportsWidget(nsPresContext*, nsIFrame*, StyleAppearance) override; bool WidgetIsContainer(StyleAppearance) override; bool ThemeDrawsFocusForWidget(StyleAppearance) override; bool ThemeNeedsComboboxDropmarker() override; ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth, Overlay) override; static nscolor AdjustUnthemedScrollbarThumbColor(nscolor, EventStates); static nscolor GetScrollbarButtonColor(nscolor aTrackColor, EventStates); static nscolor GetScrollbarArrowColor(nscolor aButtonColor); nscoord GetCheckboxRadioPrefSize() override; protected: nsNativeBasicTheme() = default; virtual ~nsNativeBasicTheme() = default; static DPIRatio GetDPIRatioForScrollbarPart(nsPresContext*); static DPIRatio GetDPIRatio(nsPresContext*, StyleAppearance); static DPIRatio GetDPIRatio(nsIFrame*, StyleAppearance); static bool IsDateTimeResetButton(nsIFrame*); static bool IsColorPickerButton(nsIFrame*); // Whether we should use system colors (for high contrast mode). enum class UseSystemColors : bool { No, Yes }; static UseSystemColors ShouldUseSystemColors(const mozilla::dom::Document&); std::pair ComputeCheckboxColors(const EventStates&, StyleAppearance, UseSystemColors); sRGBColor ComputeCheckmarkColor(const EventStates&, UseSystemColors); sRGBColor ComputeBorderColor(const EventStates&, UseSystemColors); std::pair ComputeButtonColors(const EventStates&, UseSystemColors, nsIFrame* = nullptr); std::pair ComputeTextfieldColors(const EventStates&, UseSystemColors); std::pair ComputeRangeProgressColors(const EventStates&, UseSystemColors); std::pair ComputeRangeTrackColors(const EventStates&, UseSystemColors); std::pair ComputeRangeThumbColors(const EventStates&, UseSystemColors); std::pair ComputeProgressColors(UseSystemColors); std::pair ComputeProgressTrackColors(UseSystemColors); std::pair ComputeMeterchunkColors( const EventStates& aMeterState, UseSystemColors); sRGBColor ComputeMenulistArrowButtonColor(const EventStates&, UseSystemColors); std::array ComputeFocusRectColors(UseSystemColors); static bool ShouldUseDarkScrollbar(nsIFrame*, const ComputedStyle&); virtual sRGBColor ComputeScrollbarColor(nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors); virtual sRGBColor ComputeScrollbarThumbColor( nsIFrame*, const ComputedStyle&, const EventStates& aElementState, const EventStates& aDocumentState, UseSystemColors); // Returned colors are button, arrow. std::pair ComputeScrollbarButtonColors( nsIFrame*, StyleAppearance, const ComputedStyle&, const EventStates& aElementState, const EventStates& aDocumentState, UseSystemColors); template void PaintRoundedFocusRect(PaintBackendData&, const LayoutDeviceRect&, UseSystemColors, DPIRatio, CSSCoord aRadius, CSSCoord aOffset); template void PaintAutoStyleOutline(nsIFrame*, PaintBackendData&, const LayoutDeviceRect&, UseSystemColors, DPIRatio); static void PaintRoundedRectWithRadius(DrawTarget&, const LayoutDeviceRect& aRect, const LayoutDeviceRect& aClipRect, const sRGBColor& aBackgroundColor, const sRGBColor& aBorderColor, CSSCoord aBorderWidth, CSSCoord aRadius, DPIRatio); static void PaintRoundedRectWithRadius(WebRenderBackendData&, const LayoutDeviceRect& aRect, const LayoutDeviceRect& aClipRect, const sRGBColor& aBackgroundColor, const sRGBColor& aBorderColor, CSSCoord aBorderWidth, CSSCoord aRadius, DPIRatio); template static void PaintRoundedRectWithRadius(PaintBackendData& aData, const LayoutDeviceRect& aRect, const sRGBColor& aBackgroundColor, const sRGBColor& aBorderColor, CSSCoord aBorderWidth, CSSCoord aRadius, DPIRatio aDpiRatio) { PaintRoundedRectWithRadius(aData, aRect, aRect, aBackgroundColor, aBorderColor, aBorderWidth, aRadius, aDpiRatio); } static void FillRect(DrawTarget&, const LayoutDeviceRect&, const sRGBColor&); static void FillRect(WebRenderBackendData&, const LayoutDeviceRect&, const sRGBColor&); void PaintCheckboxControl(DrawTarget& aDrawTarget, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio); void PaintCheckMark(DrawTarget&, const LayoutDeviceRect&, const EventStates&, UseSystemColors); void PaintIndeterminateMark(DrawTarget&, const LayoutDeviceRect&, const EventStates&, UseSystemColors); template void PaintStrokedCircle(PaintBackendData&, const LayoutDeviceRect&, const sRGBColor& aBackgroundColor, const sRGBColor& aBorderColor, const CSSCoord aBorderWidth, DPIRatio); void PaintCircleShadow(DrawTarget&, const LayoutDeviceRect& aBoxRect, const LayoutDeviceRect& aClipRect, float aShadowAlpha, const CSSPoint& aShadowOffset, CSSCoord aShadowBlurStdDev, DPIRatio); void PaintCircleShadow(WebRenderBackendData&, const LayoutDeviceRect& aBoxRect, const LayoutDeviceRect& aClipRect, float aShadowAlpha, const CSSPoint& aShadowOffset, CSSCoord aShadowBlurStdDev, DPIRatio); template void PaintRadioControl(PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio); template void PaintRadioCheckmark(PaintBackendData&, const LayoutDeviceRect&, const EventStates&, DPIRatio); template void PaintTextField(PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio); template void PaintListbox(PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio); template void PaintMenulist(PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio); void PaintArrow(DrawTarget&, const LayoutDeviceRect&, const float aArrowPolygonX[], const float aArrowPolygonY[], const float aArrowPolygonSize, const int32_t aArrowNumPoints, const sRGBColor aFillColor); void PaintMenulistArrowButton(nsIFrame*, DrawTarget&, const LayoutDeviceRect&, const EventStates&, UseSystemColors); void PaintSpinnerButton(nsIFrame*, DrawTarget&, const LayoutDeviceRect&, const EventStates&, StyleAppearance, UseSystemColors, DPIRatio); template void PaintRange(nsIFrame*, PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio, bool aHorizontal); template void PaintProgress(nsIFrame*, PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio, bool aIsMeter); template void PaintButton(nsIFrame*, PaintBackendData&, const LayoutDeviceRect&, const EventStates&, UseSystemColors, DPIRatio); void PaintScrollbarButton(DrawTarget&, StyleAppearance, const LayoutDeviceRect&, nsIFrame*, const ComputedStyle&, const EventStates& aElementState, const EventStates& aDocumentState, UseSystemColors, DPIRatio); virtual bool PaintScrollbarThumb(DrawTarget&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aElementState, const EventStates& aDocumentState, UseSystemColors, DPIRatio); virtual bool PaintScrollbarThumb(WebRenderBackendData&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aElementState, const EventStates& aDocumentState, UseSystemColors, DPIRatio); template bool DoPaintDefaultScrollbarThumb(PaintBackendData&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aElementState, const EventStates& aDocumentState, UseSystemColors aUseSystemColors, DPIRatio); virtual bool PaintScrollbar(DrawTarget&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio); virtual bool PaintScrollbar(WebRenderBackendData&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio); template bool DoPaintDefaultScrollbar(PaintBackendData&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors aUseSystemColors, DPIRatio); virtual bool PaintScrollbarTrack(DrawTarget&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio) { // Draw nothing by default. Subclasses can override this. return true; } virtual bool PaintScrollbarTrack(WebRenderBackendData&, const LayoutDeviceRect&, bool aHorizontal, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio) { // Draw nothing by default. Subclasses can override this. return true; } virtual bool PaintScrollCorner(DrawTarget&, const LayoutDeviceRect&, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio); virtual bool PaintScrollCorner(WebRenderBackendData&, const LayoutDeviceRect&, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio); template bool DoPaintDefaultScrollCorner(PaintBackendData&, const LayoutDeviceRect&, nsIFrame*, const ComputedStyle&, const EventStates& aDocumentState, UseSystemColors, DPIRatio); static sRGBColor sAccentColor; static sRGBColor sAccentColorForeground; // Note that depending on the exact accent color, lighter/darker might really // be inverted. static sRGBColor sAccentColorLight; static sRGBColor sAccentColorDark; static sRGBColor sAccentColorDarker; static CSSIntCoord sHorizontalScrollbarHeight; static CSSIntCoord sVerticalScrollbarWidth; static void PrefChangedCallback(const char*, void*) { LookAndFeelChanged(); } static void RecomputeAccentColors(); static void RecomputeScrollbarSizes(); }; #endif