1 /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsNativeBasicTheme.h"
9 #include "mozilla/MathAlgorithms.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/gfx/Rect.h"
12 #include "mozilla/gfx/Types.h"
13 #include "mozilla/gfx/Filters.h"
14 #include "mozilla/RelativeLuminanceUtils.h"
15 #include "mozilla/StaticPrefs_widget.h"
16 #include "mozilla/webrender/WebRenderAPI.h"
17 #include "nsCSSColorUtils.h"
18 #include "nsCSSRendering.h"
19 #include "nsLayoutUtils.h"
20 #include "PathHelpers.h"
22 #include "nsDeviceContext.h"
24 #include "nsColorControlFrame.h"
25 #include "nsDateTimeControlFrame.h"
26 #include "nsMeterFrame.h"
27 #include "nsProgressFrame.h"
28 #include "nsRangeFrame.h"
29 #include "mozilla/dom/HTMLMeterElement.h"
30 #include "mozilla/dom/HTMLProgressElement.h"
32 using namespace mozilla
;
33 using namespace mozilla::widget
;
34 using namespace mozilla::gfx
;
36 NS_IMPL_ISUPPORTS_INHERITED(nsNativeBasicTheme
, nsNativeTheme
, nsITheme
)
40 static constexpr sRGBColor sTransparent
= sRGBColor::White(0.0);
42 // This pushes and pops a clip rect to the draw target.
44 // This is done to reduce fuzz in places where we may have antialiasing,
45 // because skia is not clip-invariant: given different clips, it does not
46 // guarantee the same result, even if the painted content doesn't intersect
49 // This is a bit sad, overall, but...
50 struct MOZ_RAII AutoClipRect
{
51 AutoClipRect(DrawTarget
& aDt
, const LayoutDeviceRect
& aRect
) : mDt(aDt
) {
52 mDt
.PushClipRect(aRect
.ToUnknownRect());
55 ~AutoClipRect() { mDt
.PopClip(); }
61 static LayoutDeviceIntCoord
SnapBorderWidth(
62 CSSCoord aCssWidth
, nsNativeBasicTheme::DPIRatio aDpiRatio
) {
63 if (aCssWidth
== 0.0f
) {
66 return std::max(LayoutDeviceIntCoord(1), (aCssWidth
* aDpiRatio
).Truncated());
69 [[nodiscard
]] static float ScaleLuminanceBy(float aLuminance
, float aFactor
) {
70 return aLuminance
>= 0.18f
? aLuminance
* aFactor
: aLuminance
/ aFactor
;
73 static nscolor
ThemedAccentColor(bool aBackground
) {
74 MOZ_ASSERT(StaticPrefs::widget_non_native_theme_use_theme_accent());
75 // TODO(emilio): In the future we should probably add dark-color-scheme
76 // support for non-native form controls.
77 nscolor color
= LookAndFeel::Color(
78 aBackground
? LookAndFeel::ColorID::MozAccentColor
79 : LookAndFeel::ColorID::MozAccentColorForeground
,
80 LookAndFeel::ColorScheme::Light
, LookAndFeel::UseStandins::No
);
81 if (NS_GET_A(color
) != 0xff) {
82 // Blend with white, ensuring the color is opaque to avoid surprises if we
84 color
= NS_ComposeColors(NS_RGB(0xff, 0xff, 0xff), color
);
91 sRGBColor
nsNativeBasicTheme::sAccentColor
= sRGBColor::OpaqueWhite();
92 sRGBColor
nsNativeBasicTheme::sAccentColorForeground
= sRGBColor::OpaqueWhite();
93 sRGBColor
nsNativeBasicTheme::sAccentColorLight
= sRGBColor::OpaqueWhite();
94 sRGBColor
nsNativeBasicTheme::sAccentColorDark
= sRGBColor::OpaqueWhite();
95 sRGBColor
nsNativeBasicTheme::sAccentColorDarker
= sRGBColor::OpaqueWhite();
96 CSSIntCoord
nsNativeBasicTheme::sHorizontalScrollbarHeight
= CSSIntCoord(0);
97 CSSIntCoord
nsNativeBasicTheme::sVerticalScrollbarWidth
= CSSIntCoord(0);
98 bool nsNativeBasicTheme::sOverlayScrollbars
= false;
100 static constexpr nsLiteralCString kPrefs
[] = {
101 "widget.non-native-theme.use-theme-accent"_ns
,
102 "widget.non-native-theme.win.scrollbar.use-system-size"_ns
,
103 "widget.non-native-theme.scrollbar.size"_ns
,
106 void nsNativeBasicTheme::Init() {
107 for (const auto& pref
: kPrefs
) {
108 Preferences::RegisterCallback(PrefChangedCallback
, pref
);
110 LookAndFeelChanged();
113 void nsNativeBasicTheme::Shutdown() {
114 for (const auto& pref
: kPrefs
) {
115 Preferences::UnregisterCallback(PrefChangedCallback
, pref
);
119 void nsNativeBasicTheme::LookAndFeelChanged() {
120 RecomputeAccentColors();
121 RecomputeScrollbarParams();
124 void nsNativeBasicTheme::RecomputeAccentColors() {
125 MOZ_RELEASE_ASSERT(NS_IsMainThread());
127 if (!StaticPrefs::widget_non_native_theme_use_theme_accent()) {
128 sAccentColorForeground
= sColorWhite
;
130 sRGBColor::UnusualFromARGB(0xff0060df); // Luminance: 13.69346%
132 sRGBColor::UnusualFromARGB(0x4d008deb); // Luminance: 25.04791%
134 sRGBColor::UnusualFromARGB(0xff0250bb); // Luminance: 9.33808%
136 sRGBColor::UnusualFromARGB(0xff054096); // Luminance: 5.90106%
140 sAccentColorForeground
= sRGBColor::FromABGR(ThemedAccentColor(false));
141 const nscolor accent
= ThemedAccentColor(true);
142 const float luminance
= RelativeLuminanceUtils::Compute(accent
);
144 constexpr float kLightLuminanceScale
= 25.048f
/ 13.693f
;
145 constexpr float kDarkLuminanceScale
= 9.338f
/ 13.693f
;
146 constexpr float kDarkerLuminanceScale
= 5.901f
/ 13.693f
;
148 const float lightLuminanceAdjust
=
149 ScaleLuminanceBy(luminance
, kLightLuminanceScale
);
150 const float darkLuminanceAdjust
=
151 ScaleLuminanceBy(luminance
, kDarkLuminanceScale
);
152 const float darkerLuminanceAdjust
=
153 ScaleLuminanceBy(luminance
, kDarkerLuminanceScale
);
155 sAccentColor
= sRGBColor::FromABGR(accent
);
159 RelativeLuminanceUtils::Adjust(accent
, lightLuminanceAdjust
);
160 lightColor
= NS_RGBA(NS_GET_R(lightColor
), NS_GET_G(lightColor
),
161 NS_GET_B(lightColor
), 0x4d);
162 sAccentColorLight
= sRGBColor::FromABGR(lightColor
);
165 sAccentColorDark
= sRGBColor::FromABGR(
166 RelativeLuminanceUtils::Adjust(accent
, darkLuminanceAdjust
));
167 sAccentColorDarker
= sRGBColor::FromABGR(
168 RelativeLuminanceUtils::Adjust(accent
, darkerLuminanceAdjust
));
171 void nsNativeBasicTheme::RecomputeScrollbarParams() {
173 LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars
);
175 uint32_t defaultSize
= StaticPrefs::widget_non_native_theme_scrollbar_size();
176 if (StaticPrefs::widget_non_native_theme_win_scrollbar_use_system_size()) {
177 sHorizontalScrollbarHeight
= LookAndFeel::GetInt(
178 LookAndFeel::IntID::SystemHorizontalScrollbarHeight
, defaultSize
);
179 sVerticalScrollbarWidth
= LookAndFeel::GetInt(
180 LookAndFeel::IntID::SystemVerticalScrollbarWidth
, defaultSize
);
182 sHorizontalScrollbarHeight
= sVerticalScrollbarWidth
= defaultSize
;
184 // On GTK, widgets don't account for text scale factor, but that's included
185 // in the usual DPI computations, so we undo that here, just like
186 // GetMonitorScaleFactor does it in nsNativeThemeGTK.
188 LookAndFeel::GetFloat(LookAndFeel::FloatID::TextScaleFactor
, 1.0f
);
190 sVerticalScrollbarWidth
= float(sVerticalScrollbarWidth
) / scale
;
191 sHorizontalScrollbarHeight
= float(sHorizontalScrollbarHeight
) / scale
;
195 static bool IsScrollbarWidthThin(nsIFrame
* aFrame
) {
196 ComputedStyle
* style
= nsLayoutUtils::StyleForScrollbar(aFrame
);
197 auto scrollbarWidth
= style
->StyleUIReset()->mScrollbarWidth
;
198 return scrollbarWidth
== StyleScrollbarWidth::Thin
;
201 static sRGBColor
SystemColor(StyleSystemColor aColor
) {
202 // TODO(emilio): We could not hardcode light appearance here with a bit of
203 // work, but doesn't matter for now.
204 return sRGBColor::FromABGR(LookAndFeel::Color(
205 aColor
, LookAndFeel::ColorScheme::Light
, LookAndFeel::UseStandins::No
));
208 template <typename Compute
>
209 static sRGBColor
SystemColorOrElse(StyleSystemColor aColor
, Compute aCompute
) {
211 LookAndFeel::GetColor(aColor
, LookAndFeel::ColorScheme::Light
,
212 LookAndFeel::UseStandins::No
)) {
213 return sRGBColor::FromABGR(*color
);
218 static std::pair
<sRGBColor
, sRGBColor
> SystemColorPair(
219 StyleSystemColor aFirst
, StyleSystemColor aSecond
) {
220 return std::make_pair(SystemColor(aFirst
), SystemColor(aSecond
));
224 auto nsNativeBasicTheme::GetDPIRatioForScrollbarPart(nsPresContext
* aPc
)
226 return DPIRatio(float(AppUnitsPerCSSPixel()) /
227 aPc
->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
231 auto nsNativeBasicTheme::GetDPIRatio(nsPresContext
* aPc
,
232 StyleAppearance aAppearance
) -> DPIRatio
{
233 // Widgets react to zoom, except scrollbars.
234 if (IsWidgetScrollbarPart(aAppearance
)) {
235 return GetDPIRatioForScrollbarPart(aPc
);
237 return DPIRatio(float(AppUnitsPerCSSPixel()) / aPc
->AppUnitsPerDevPixel());
241 auto nsNativeBasicTheme::GetDPIRatio(nsIFrame
* aFrame
,
242 StyleAppearance aAppearance
) -> DPIRatio
{
243 return GetDPIRatio(aFrame
->PresContext(), aAppearance
);
247 bool nsNativeBasicTheme::IsDateTimeResetButton(nsIFrame
* aFrame
) {
252 nsIFrame
* parent
= aFrame
->GetParent();
253 if (parent
&& (parent
= parent
->GetParent()) &&
254 (parent
= parent
->GetParent())) {
255 nsDateTimeControlFrame
* dateTimeFrame
= do_QueryFrame(parent
);
264 bool nsNativeBasicTheme::IsColorPickerButton(nsIFrame
* aFrame
) {
265 nsColorControlFrame
* colorPickerButton
= do_QueryFrame(aFrame
);
266 return colorPickerButton
;
269 // Checkbox and radio need to preserve aspect-ratio for compat. We also snap the
270 // size to exact device pixels to avoid snapping disorting the circles.
271 static LayoutDeviceRect
CheckBoxRadioRect(const LayoutDeviceRect
& aRect
) {
272 // Place a square rect in the center of aRect.
273 auto size
= std::trunc(std::min(aRect
.width
, aRect
.height
));
274 auto position
= aRect
.Center() - LayoutDevicePoint(size
* 0.5, size
* 0.5);
275 return LayoutDeviceRect(position
, LayoutDeviceSize(size
, size
));
278 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeCheckboxColors(
279 const EventStates
& aState
, StyleAppearance aAppearance
,
280 UseSystemColors aUseSystemColors
) {
281 MOZ_ASSERT(aAppearance
== StyleAppearance::Checkbox
||
282 aAppearance
== StyleAppearance::Radio
);
283 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
285 aState
.HasAllStates(NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
);
286 bool isHovered
= aState
.HasState(NS_EVENT_STATE_HOVER
);
287 bool isChecked
= aState
.HasState(NS_EVENT_STATE_CHECKED
);
288 bool isIndeterminate
= aAppearance
== StyleAppearance::Checkbox
&&
289 aState
.HasState(NS_EVENT_STATE_INDETERMINATE
);
291 if (bool(aUseSystemColors
)) {
292 sRGBColor backgroundColor
= SystemColor(StyleSystemColor::Buttonface
);
293 sRGBColor borderColor
= SystemColor(StyleSystemColor::Buttontext
);
295 borderColor
= SystemColor(StyleSystemColor::Graytext
);
296 if (isChecked
|| isIndeterminate
) {
297 backgroundColor
= borderColor
;
299 } else if (isChecked
|| isIndeterminate
) {
300 backgroundColor
= borderColor
= SystemColor(StyleSystemColor::Highlight
);
302 return {backgroundColor
, borderColor
};
305 sRGBColor backgroundColor
= sColorWhite
;
306 sRGBColor borderColor
= sColorGrey40
;
308 backgroundColor
= sColorWhiteAlpha50
;
309 borderColor
= sColorGrey40Alpha50
;
310 if (isChecked
|| isIndeterminate
) {
311 backgroundColor
= borderColor
;
313 } else if (isChecked
|| isIndeterminate
) {
314 const auto& color
= isPressed
? sAccentColorDarker
315 : isHovered
? sAccentColorDark
317 backgroundColor
= borderColor
= color
;
318 } else if (isPressed
) {
319 backgroundColor
= sColorGrey20
;
320 borderColor
= sColorGrey60
;
321 } else if (isHovered
) {
322 backgroundColor
= sColorWhite
;
323 borderColor
= sColorGrey50
;
326 return std::make_pair(backgroundColor
, borderColor
);
329 sRGBColor
nsNativeBasicTheme::ComputeCheckmarkColor(
330 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
331 if (bool(aUseSystemColors
)) {
332 return SystemColor(StyleSystemColor::Highlighttext
);
334 if (aState
.HasState(NS_EVENT_STATE_DISABLED
)) {
335 return sColorWhiteAlpha80
;
337 return sAccentColorForeground
;
340 sRGBColor
nsNativeBasicTheme::ComputeBorderColor(
341 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
342 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
343 if (bool(aUseSystemColors
)) {
344 return SystemColor(isDisabled
? StyleSystemColor::Graytext
345 : StyleSystemColor::Buttontext
);
348 aState
.HasAllStates(NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
);
349 bool isHovered
= aState
.HasState(NS_EVENT_STATE_HOVER
);
350 bool isFocused
= aState
.HasState(NS_EVENT_STATE_FOCUSRING
);
352 return sColorGrey40Alpha50
;
355 // We draw the outline over the border for all controls that call into this,
356 // so to prevent issues where the border shows underneath if it snaps in the
357 // wrong direction, we use a transparent border. An alternative to this is
358 // ensuring that we snap the offset in PaintRoundedFocusRect the same was a
359 // we snap border widths, so that negative offsets are guaranteed to cover
360 // the border. But this looks harder to mess up.
372 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeButtonColors(
373 const EventStates
& aState
, UseSystemColors aUseSystemColors
,
376 aState
.HasAllStates(NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
);
377 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
378 bool isHovered
= aState
.HasState(NS_EVENT_STATE_HOVER
);
380 const sRGBColor backgroundColor
= [&] {
381 if (bool(aUseSystemColors
)) {
382 return SystemColor(StyleSystemColor::Buttonface
);
386 return sColorGrey10Alpha50
;
388 if (IsDateTimeResetButton(aFrame
)) {
400 const sRGBColor borderColor
= ComputeBorderColor(aState
, aUseSystemColors
);
401 return std::make_pair(backgroundColor
, borderColor
);
404 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeTextfieldColors(
405 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
406 const sRGBColor backgroundColor
= [&] {
407 if (bool(aUseSystemColors
)) {
408 return SystemColor(StyleSystemColor::TextBackground
);
410 if (aState
.HasState(NS_EVENT_STATE_DISABLED
)) {
411 return sColorWhiteAlpha50
;
415 const sRGBColor borderColor
= ComputeBorderColor(aState
, aUseSystemColors
);
416 return std::make_pair(backgroundColor
, borderColor
);
419 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeRangeProgressColors(
420 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
421 if (bool(aUseSystemColors
)) {
422 return SystemColorPair(StyleSystemColor::Highlight
,
423 StyleSystemColor::Buttontext
);
427 aState
.HasAllStates(NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
);
428 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
429 bool isHovered
= aState
.HasState(NS_EVENT_STATE_HOVER
);
432 return std::make_pair(sColorGrey40Alpha50
, sColorGrey40Alpha50
);
434 if (isActive
|| isHovered
) {
435 return std::make_pair(sAccentColorDark
, sAccentColorDarker
);
437 return std::make_pair(sAccentColor
, sAccentColorDark
);
440 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeRangeTrackColors(
441 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
442 if (bool(aUseSystemColors
)) {
443 return SystemColorPair(StyleSystemColor::TextBackground
,
444 StyleSystemColor::Buttontext
);
447 aState
.HasAllStates(NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
);
448 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
449 bool isHovered
= aState
.HasState(NS_EVENT_STATE_HOVER
);
452 return std::make_pair(sColorGrey10Alpha50
, sColorGrey40Alpha50
);
454 if (isActive
|| isHovered
) {
455 return std::make_pair(sColorGrey20
, sColorGrey50
);
457 return std::make_pair(sColorGrey10
, sColorGrey40
);
460 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeRangeThumbColors(
461 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
462 if (bool(aUseSystemColors
)) {
463 return SystemColorPair(StyleSystemColor::Highlighttext
,
464 StyleSystemColor::Highlight
);
468 aState
.HasAllStates(NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
);
469 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
470 bool isHovered
= aState
.HasState(NS_EVENT_STATE_HOVER
);
472 const sRGBColor
& backgroundColor
= [&] {
485 const sRGBColor borderColor
= sColorWhite
;
487 return std::make_pair(backgroundColor
, borderColor
);
490 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeProgressColors(
491 UseSystemColors aUseSystemColors
) {
492 if (bool(aUseSystemColors
)) {
493 return SystemColorPair(StyleSystemColor::Highlight
,
494 StyleSystemColor::Buttontext
);
496 return std::make_pair(sAccentColor
, sAccentColorDark
);
499 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeProgressTrackColors(
500 UseSystemColors aUseSystemColors
) {
501 if (bool(aUseSystemColors
)) {
502 return SystemColorPair(StyleSystemColor::Buttonface
,
503 StyleSystemColor::Buttontext
);
505 return std::make_pair(sColorGrey10
, sColorGrey40
);
508 std::pair
<sRGBColor
, sRGBColor
> nsNativeBasicTheme::ComputeMeterchunkColors(
509 const EventStates
& aMeterState
, UseSystemColors aUseSystemColors
) {
510 if (bool(aUseSystemColors
)) {
511 return ComputeProgressColors(aUseSystemColors
);
513 sRGBColor borderColor
= sColorMeterGreen20
;
514 sRGBColor chunkColor
= sColorMeterGreen10
;
516 if (aMeterState
.HasState(NS_EVENT_STATE_SUB_OPTIMUM
)) {
517 borderColor
= sColorMeterYellow20
;
518 chunkColor
= sColorMeterYellow10
;
519 } else if (aMeterState
.HasState(NS_EVENT_STATE_SUB_SUB_OPTIMUM
)) {
520 borderColor
= sColorMeterRed20
;
521 chunkColor
= sColorMeterRed10
;
524 return std::make_pair(chunkColor
, borderColor
);
527 sRGBColor
nsNativeBasicTheme::ComputeMenulistArrowButtonColor(
528 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
529 bool isDisabled
= aState
.HasState(NS_EVENT_STATE_DISABLED
);
530 if (bool(aUseSystemColors
)) {
531 return SystemColor(isDisabled
? StyleSystemColor::Graytext
532 : StyleSystemColor::TextForeground
);
534 return isDisabled
? sColorGrey60Alpha50
: sColorGrey60
;
537 std::array
<sRGBColor
, 3> nsNativeBasicTheme::ComputeFocusRectColors(
538 UseSystemColors aUseSystemColors
) {
539 if (bool(aUseSystemColors
)) {
540 return {SystemColor(StyleSystemColor::Highlight
),
541 SystemColor(StyleSystemColor::Buttontext
),
542 SystemColor(StyleSystemColor::TextBackground
)};
545 return {sAccentColor
, sColorWhiteAlpha80
, sAccentColorLight
};
548 sRGBColor
nsNativeBasicTheme::ComputeScrollbarTrackColor(
549 nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
550 const EventStates
& aDocumentState
, UseSystemColors aUseSystemColors
) {
551 const nsStyleUI
* ui
= aStyle
.StyleUI();
552 if (bool(aUseSystemColors
)) {
553 return SystemColor(StyleSystemColor::TextBackground
);
555 if (ShouldUseDarkScrollbar(aFrame
, aStyle
)) {
556 return sRGBColor::FromU8(20, 20, 25, 77);
558 if (ui
->mScrollbarColor
.IsColors()) {
559 return sRGBColor::FromABGR(
560 ui
->mScrollbarColor
.AsColors().track
.CalcColor(aStyle
));
562 if (aDocumentState
.HasAllStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE
)) {
563 return SystemColorOrElse(StyleSystemColor::ThemedScrollbarInactive
,
564 [] { return sScrollbarColor
; });
566 return SystemColorOrElse(StyleSystemColor::ThemedScrollbar
,
567 [] { return sScrollbarColor
; });
570 nscolor
nsNativeBasicTheme::AdjustUnthemedScrollbarThumbColor(
571 nscolor aFaceColor
, EventStates aStates
) {
572 // In Windows 10, scrollbar thumb has the following colors:
574 // State | Color | Luminance
575 // -------+----------+----------
576 // Normal | Gray 205 | 61.0%
577 // Hover | Gray 166 | 38.1%
578 // Active | Gray 96 | 11.7%
580 // This function is written based on the ratios between the values.
581 bool isActive
= aStates
.HasState(NS_EVENT_STATE_ACTIVE
);
582 bool isHover
= aStates
.HasState(NS_EVENT_STATE_HOVER
);
583 if (!isActive
&& !isHover
) {
586 float luminance
= RelativeLuminanceUtils::Compute(aFaceColor
);
589 luminance
= ScaleLuminanceBy(luminance
, 0.192f
);
592 luminance
= ScaleLuminanceBy(luminance
, 0.625f
);
594 return RelativeLuminanceUtils::Adjust(aFaceColor
, luminance
);
598 nscolor
nsNativeBasicTheme::GetScrollbarButtonColor(nscolor aTrackColor
,
599 EventStates aStates
) {
600 // See numbers in GetScrollbarArrowColor.
601 // This function is written based on ratios between values listed there.
603 bool isActive
= aStates
.HasState(NS_EVENT_STATE_ACTIVE
);
604 bool isHover
= aStates
.HasState(NS_EVENT_STATE_HOVER
);
605 if (!isActive
&& !isHover
) {
608 float luminance
= RelativeLuminanceUtils::Compute(aTrackColor
);
610 if (luminance
>= 0.18f
) {
614 luminance
= std::min(luminance
, 1.0f
);
617 if (luminance
>= 0.18f
) {
623 return RelativeLuminanceUtils::Adjust(aTrackColor
, luminance
);
627 Maybe
<nscolor
> nsNativeBasicTheme::GetScrollbarArrowColor(
628 nscolor aButtonColor
) {
629 // In Windows 10 scrollbar, there are several gray colors used:
631 // State | Background (lum) | Arrow | Contrast
632 // -------+------------------+---------+---------
633 // Normal | Gray 240 (87.1%) | Gray 96 | 5.5
634 // Hover | Gray 218 (70.1%) | Black | 15.0
635 // Active | Gray 96 (11.7%) | White | 6.3
637 // Contrast value is computed based on the definition in
638 // https://www.w3.org/TR/WCAG20/#contrast-ratiodef
640 // This function is written based on these values.
642 if (NS_GET_A(aButtonColor
) == 0) {
643 // If the button color is transparent, because of e.g.
644 // scrollbar-color: <something> transparent, then use
645 // the thumb color, which is expected to have enough
650 float luminance
= RelativeLuminanceUtils::Compute(aButtonColor
);
651 // Color with luminance larger than 0.72 has contrast ratio over 4.6
652 // to color with luminance of gray 96, so this value is chosen for
653 // this range. It is the luminance of gray 221.
654 if (luminance
>= 0.72) {
655 // ComputeRelativeLuminanceFromComponents(96). That function cannot
656 // be constexpr because of std::pow.
657 const float GRAY96_LUMINANCE
= 0.117f
;
658 return Some(RelativeLuminanceUtils::Adjust(aButtonColor
, GRAY96_LUMINANCE
));
660 // The contrast ratio of a color to black equals that to white when its
661 // luminance is around 0.18, with a contrast ratio ~4.6 to both sides,
662 // thus the value below. It's the lumanince of gray 118.
664 // TODO(emilio): Maybe the button alpha is not the best thing to use here and
665 // we should use the thumb alpha? It seems weird that the color of the arrow
666 // depends on the opacity of the scrollbar thumb...
667 if (luminance
>= 0.18) {
668 return Some(NS_RGBA(0, 0, 0, NS_GET_A(aButtonColor
)));
670 return Some(NS_RGBA(255, 255, 255, NS_GET_A(aButtonColor
)));
673 bool nsNativeBasicTheme::ShouldUseDarkScrollbar(nsIFrame
* aFrame
,
674 const ComputedStyle
& aStyle
) {
675 if (StaticPrefs::widget_disable_dark_scrollbar()) {
678 if (aStyle
.StyleUI()->mScrollbarColor
.IsColors()) {
681 return nsNativeTheme::IsDarkBackground(aFrame
);
684 sRGBColor
nsNativeBasicTheme::ComputeScrollbarThumbColor(
685 nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
686 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
687 UseSystemColors aUseSystemColors
) {
688 if (!bool(aUseSystemColors
) && ShouldUseDarkScrollbar(aFrame
, aStyle
)) {
689 const bool forceThemed
=
690 aElementState
.HasState(NS_EVENT_STATE_ACTIVE
) &&
691 StaticPrefs::widget_non_native_theme_scrollbar_active_always_themed();
693 return sRGBColor::FromABGR(AdjustUnthemedScrollbarThumbColor(
694 NS_RGBA(249, 249, 250, 102), aElementState
));
698 const nsStyleUI
* ui
= aStyle
.StyleUI();
699 if (ui
->mScrollbarColor
.IsColors()) {
700 return sRGBColor::FromABGR(AdjustUnthemedScrollbarThumbColor(
701 ui
->mScrollbarColor
.AsColors().thumb
.CalcColor(aStyle
), aElementState
));
704 auto systemColor
= [&] {
705 if (aDocumentState
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
)) {
706 return StyleSystemColor::ThemedScrollbarThumbInactive
;
708 if (aElementState
.HasState(NS_EVENT_STATE_ACTIVE
)) {
709 if (bool(aUseSystemColors
)) {
710 return StyleSystemColor::Highlight
;
712 return StyleSystemColor::ThemedScrollbarThumbActive
;
714 if (aElementState
.HasState(NS_EVENT_STATE_HOVER
)) {
715 if (bool(aUseSystemColors
)) {
716 return StyleSystemColor::Highlight
;
718 return StyleSystemColor::ThemedScrollbarThumbHover
;
720 if (bool(aUseSystemColors
)) {
721 return StyleSystemColor::TextForeground
;
723 return StyleSystemColor::ThemedScrollbarThumb
;
726 return SystemColorOrElse(systemColor
, [&] {
727 return sRGBColor::FromABGR(AdjustUnthemedScrollbarThumbColor(
728 sScrollbarThumbColor
.ToABGR(), aElementState
));
732 std::pair
<sRGBColor
, sRGBColor
>
733 nsNativeBasicTheme::ComputeScrollbarButtonColors(
734 nsIFrame
* aFrame
, StyleAppearance aAppearance
, const ComputedStyle
& aStyle
,
735 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
736 UseSystemColors aUseSystemColors
) {
737 if (bool(aUseSystemColors
)) {
738 if (aElementState
.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE
|
739 NS_EVENT_STATE_HOVER
)) {
740 return SystemColorPair(StyleSystemColor::Highlight
,
741 StyleSystemColor::Buttonface
);
743 return SystemColorPair(StyleSystemColor::TextBackground
,
744 StyleSystemColor::TextForeground
);
747 auto trackColor
= ComputeScrollbarTrackColor(aFrame
, aStyle
, aDocumentState
,
749 nscolor buttonColor
=
750 GetScrollbarButtonColor(trackColor
.ToABGR(), aElementState
);
752 GetScrollbarArrowColor(buttonColor
)
753 .map(sRGBColor::FromABGR
)
755 return ComputeScrollbarThumbColor(aFrame
, aStyle
, aElementState
,
756 aDocumentState
, aUseSystemColors
);
758 return {sRGBColor::FromABGR(buttonColor
), arrowColor
};
761 static const CSSCoord kInnerFocusOutlineWidth
= 2.0f
;
763 template <typename PaintBackendData
>
764 void nsNativeBasicTheme::PaintRoundedFocusRect(PaintBackendData
& aBackendData
,
765 const LayoutDeviceRect
& aRect
,
766 UseSystemColors aUseSystemColors
,
770 // NOTE(emilio): If the widths or offsets here change, make sure to tweak
771 // the GetWidgetOverflow path for FocusOutline.
772 auto [innerColor
, middleColor
, outerColor
] =
773 ComputeFocusRectColors(aUseSystemColors
);
775 LayoutDeviceRect
focusRect(aRect
);
777 // The focus rect is painted outside of the border area (aRect), see:
779 // data:text/html,<div style="border: 1px solid; outline: 2px solid
782 // But some controls might provide a negative offset to cover the border, if
784 CSSCoord strokeWidth
= kInnerFocusOutlineWidth
;
785 auto strokeWidthDevPx
=
786 LayoutDeviceCoord(SnapBorderWidth(strokeWidth
, aDpiRatio
));
787 CSSCoord strokeRadius
= aRadius
;
788 focusRect
.Inflate(aOffset
* aDpiRatio
+ strokeWidthDevPx
);
790 PaintRoundedRectWithRadius(aBackendData
, focusRect
, sTransparent
, innerColor
,
791 strokeWidth
, strokeRadius
, aDpiRatio
);
793 strokeWidth
= CSSCoord(1.0f
);
794 strokeWidthDevPx
= LayoutDeviceCoord(SnapBorderWidth(strokeWidth
, aDpiRatio
));
795 strokeRadius
+= strokeWidth
;
796 focusRect
.Inflate(strokeWidthDevPx
);
798 PaintRoundedRectWithRadius(aBackendData
, focusRect
, sTransparent
, middleColor
,
799 strokeWidth
, strokeRadius
, aDpiRatio
);
801 strokeWidth
= CSSCoord(2.0f
);
802 strokeWidthDevPx
= LayoutDeviceCoord(SnapBorderWidth(strokeWidth
, aDpiRatio
));
803 strokeRadius
+= strokeWidth
;
804 focusRect
.Inflate(strokeWidthDevPx
);
806 PaintRoundedRectWithRadius(aBackendData
, focusRect
, sTransparent
, outerColor
,
807 strokeWidth
, strokeRadius
, aDpiRatio
);
810 void nsNativeBasicTheme::PaintRoundedRectWithRadius(
811 WebRenderBackendData
& aWrData
, const LayoutDeviceRect
& aRect
,
812 const LayoutDeviceRect
& aClipRect
, const sRGBColor
& aBackgroundColor
,
813 const sRGBColor
& aBorderColor
, CSSCoord aBorderWidth
, CSSCoord aRadius
,
814 DPIRatio aDpiRatio
) {
815 const bool kBackfaceIsVisible
= true;
816 const LayoutDeviceCoord
borderWidth(SnapBorderWidth(aBorderWidth
, aDpiRatio
));
817 const LayoutDeviceCoord
radius(aRadius
* aDpiRatio
);
818 const wr::LayoutRect dest
= wr::ToLayoutRect(aRect
);
819 const wr::LayoutRect clip
= wr::ToLayoutRect(aClipRect
);
821 // Push the background.
822 if (aBackgroundColor
.a
) {
823 auto backgroundColor
= wr::ToColorF(ToDeviceColor(aBackgroundColor
));
824 wr::LayoutRect backgroundRect
= [&] {
825 LayoutDeviceRect bg
= aRect
;
826 bg
.Deflate(borderWidth
);
827 return wr::ToLayoutRect(bg
);
830 aWrData
.mBuilder
.PushRect(backgroundRect
, clip
, kBackfaceIsVisible
,
833 // NOTE(emilio): This follows DisplayListBuilder::PushRoundedRect and
834 // draws the rounded fill as an extra thick rounded border instead of a
835 // rectangle that's clipped to a rounded clip. Refer to that method for a
836 // justification. See bug 1694269.
837 LayoutDeviceCoord backgroundRadius
=
838 std::max(0.0f
, float(radius
) - float(borderWidth
));
839 wr::BorderSide side
= {backgroundColor
, wr::BorderStyle::Solid
};
840 const wr::BorderSide sides
[4] = {side
, side
, side
, side
};
841 float h
= backgroundRect
.size
.width
* 0.6f
;
842 float v
= backgroundRect
.size
.height
* 0.6f
;
843 wr::LayoutSideOffsets widths
= {v
, h
, v
, h
};
844 wr::BorderRadius radii
= {{backgroundRadius
, backgroundRadius
},
845 {backgroundRadius
, backgroundRadius
},
846 {backgroundRadius
, backgroundRadius
},
847 {backgroundRadius
, backgroundRadius
}};
848 aWrData
.mBuilder
.PushBorder(backgroundRect
, clip
, kBackfaceIsVisible
,
849 widths
, {sides
, 4}, radii
);
853 if (borderWidth
&& aBorderColor
.a
) {
855 const auto borderColor
= ToDeviceColor(aBorderColor
);
856 const auto side
= wr::ToBorderSide(borderColor
, StyleBorderStyle::Solid
);
857 const wr::BorderSide sides
[4] = {side
, side
, side
, side
};
858 const LayoutDeviceSize
sideRadius(radius
, radius
);
860 wr::ToBorderWidths(borderWidth
, borderWidth
, borderWidth
, borderWidth
);
861 const auto wrRadius
=
862 wr::ToBorderRadius(sideRadius
, sideRadius
, sideRadius
, sideRadius
);
863 aWrData
.mBuilder
.PushBorder(dest
, clip
, kBackfaceIsVisible
, widths
,
864 {sides
, 4}, wrRadius
);
868 void nsNativeBasicTheme::FillRect(DrawTarget
& aDt
,
869 const LayoutDeviceRect
& aRect
,
870 const sRGBColor
& aColor
) {
871 aDt
.FillRect(aRect
.ToUnknownRect(), ColorPattern(ToDeviceColor(aColor
)));
874 void nsNativeBasicTheme::FillRect(WebRenderBackendData
& aWrData
,
875 const LayoutDeviceRect
& aRect
,
876 const sRGBColor
& aColor
) {
877 const bool kBackfaceIsVisible
= true;
878 auto dest
= wr::ToLayoutRect(aRect
);
879 aWrData
.mBuilder
.PushRect(dest
, dest
, kBackfaceIsVisible
,
880 wr::ToColorF(ToDeviceColor(aColor
)));
883 void nsNativeBasicTheme::PaintRoundedRectWithRadius(
884 DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
,
885 const LayoutDeviceRect
& aClipRect
, const sRGBColor
& aBackgroundColor
,
886 const sRGBColor
& aBorderColor
, CSSCoord aBorderWidth
, CSSCoord aRadius
,
887 DPIRatio aDpiRatio
) {
888 const LayoutDeviceCoord
borderWidth(SnapBorderWidth(aBorderWidth
, aDpiRatio
));
889 const bool needsClip
= !(aRect
== aClipRect
);
891 aDrawTarget
.PushClipRect(aClipRect
.ToUnknownRect());
894 LayoutDeviceRect
rect(aRect
);
895 // Deflate the rect by half the border width, so that the middle of the
896 // stroke fills exactly the area we want to fill and not more.
897 rect
.Deflate(borderWidth
* 0.5f
);
899 LayoutDeviceCoord
radius(aRadius
* aDpiRatio
- borderWidth
* 0.5f
);
900 // Fix up the radius if it's too large with the rect we're going to paint.
902 LayoutDeviceCoord min
= std::min(rect
.width
, rect
.height
);
903 if (radius
* 2.0f
> min
) {
908 Maybe
<ColorPattern
> backgroundPattern
;
909 if (aBackgroundColor
.a
) {
910 backgroundPattern
.emplace(ToDeviceColor(aBackgroundColor
));
912 Maybe
<ColorPattern
> borderPattern
;
913 if (borderWidth
&& aBorderColor
.a
) {
914 borderPattern
.emplace(ToDeviceColor(aBorderColor
));
917 if (borderPattern
|| backgroundPattern
) {
919 RectCornerRadii
radii(radius
, radius
, radius
, radius
);
920 RefPtr
<Path
> roundedRect
=
921 MakePathForRoundedRect(aDrawTarget
, rect
.ToUnknownRect(), radii
);
923 if (backgroundPattern
) {
924 aDrawTarget
.Fill(roundedRect
, *backgroundPattern
);
927 aDrawTarget
.Stroke(roundedRect
, *borderPattern
,
928 StrokeOptions(borderWidth
));
931 if (backgroundPattern
) {
932 aDrawTarget
.FillRect(rect
.ToUnknownRect(), *backgroundPattern
);
935 aDrawTarget
.StrokeRect(rect
.ToUnknownRect(), *borderPattern
,
936 StrokeOptions(borderWidth
));
942 aDrawTarget
.PopClip();
946 void nsNativeBasicTheme::PaintCheckboxControl(DrawTarget
& aDrawTarget
,
947 const LayoutDeviceRect
& aRect
,
948 const EventStates
& aState
,
949 UseSystemColors aUseSystemColors
,
950 DPIRatio aDpiRatio
) {
951 auto [backgroundColor
, borderColor
] = ComputeCheckboxColors(
952 aState
, StyleAppearance::Checkbox
, aUseSystemColors
);
954 const CSSCoord radius
= 2.0f
;
955 CSSCoord borderWidth
= kCheckboxRadioBorderWidth
;
956 if (backgroundColor
== borderColor
) {
959 PaintRoundedRectWithRadius(aDrawTarget
, aRect
, backgroundColor
, borderColor
,
960 borderWidth
, radius
, aDpiRatio
);
963 if (aState
.HasState(NS_EVENT_STATE_INDETERMINATE
)) {
964 PaintIndeterminateMark(aDrawTarget
, aRect
, aState
, aUseSystemColors
);
965 } else if (aState
.HasState(NS_EVENT_STATE_CHECKED
)) {
966 PaintCheckMark(aDrawTarget
, aRect
, aState
, aUseSystemColors
);
969 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
970 PaintRoundedFocusRect(aDrawTarget
, aRect
, aUseSystemColors
, aDpiRatio
, 5.0f
,
975 constexpr CSSCoord kCheckboxRadioContentBoxSize
= 10.0f
;
976 constexpr CSSCoord kCheckboxRadioBorderBoxSize
=
977 kCheckboxRadioContentBoxSize
+ kCheckboxRadioBorderWidth
* 2.0f
;
979 // Returns the right scale for points in a aSize x aSize sized box, centered at
980 // 0x0 to fill aRect in the smaller dimension.
981 static float ScaleToFillRect(const LayoutDeviceRect
& aRect
, const float aSize
) {
982 return std::min(aRect
.width
, aRect
.height
) / aSize
;
985 void nsNativeBasicTheme::PaintCheckMark(DrawTarget
& aDrawTarget
,
986 const LayoutDeviceRect
& aRect
,
987 const EventStates
& aState
,
988 UseSystemColors aUseSystemColors
) {
989 // Points come from the coordinates on a 14X14 (kCheckboxRadioBorderBoxSize)
990 // unit box centered at 0,0
991 const float checkPolygonX
[] = {-4.5f
, -1.5f
, -0.5f
, 5.0f
, 4.75f
,
992 3.5f
, -0.5f
, -1.5f
, -3.5f
};
993 const float checkPolygonY
[] = {0.5f
, 4.0f
, 4.0f
, -2.5f
, -4.0f
,
994 -4.0f
, 1.0f
, 1.25f
, -1.0f
};
995 const int32_t checkNumPoints
= sizeof(checkPolygonX
) / sizeof(float);
996 const float scale
= ScaleToFillRect(aRect
, kCheckboxRadioBorderBoxSize
);
997 auto center
= aRect
.Center().ToUnknownPoint();
999 RefPtr
<PathBuilder
> builder
= aDrawTarget
.CreatePathBuilder();
1000 Point p
= center
+ Point(checkPolygonX
[0] * scale
, checkPolygonY
[0] * scale
);
1002 for (int32_t i
= 1; i
< checkNumPoints
; i
++) {
1003 p
= center
+ Point(checkPolygonX
[i
] * scale
, checkPolygonY
[i
] * scale
);
1006 RefPtr
<Path
> path
= builder
->Finish();
1008 sRGBColor fillColor
= ComputeCheckmarkColor(aState
, aUseSystemColors
);
1009 aDrawTarget
.Fill(path
, ColorPattern(ToDeviceColor(fillColor
)));
1012 void nsNativeBasicTheme::PaintIndeterminateMark(
1013 DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
,
1014 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
1015 const CSSCoord borderWidth
= 2.0f
;
1016 const float scale
= ScaleToFillRect(aRect
, kCheckboxRadioBorderBoxSize
);
1018 Rect rect
= aRect
.ToUnknownRect();
1019 rect
.y
+= (rect
.height
/ 2) - (borderWidth
* scale
/ 2);
1020 rect
.height
= borderWidth
* scale
;
1021 rect
.x
+= (borderWidth
* scale
) + (borderWidth
* scale
/ 8);
1022 rect
.width
-= ((borderWidth
* scale
) + (borderWidth
* scale
/ 8)) * 2;
1024 sRGBColor fillColor
= ComputeCheckmarkColor(aState
, aUseSystemColors
);
1025 aDrawTarget
.FillRect(rect
, ColorPattern(ToDeviceColor(fillColor
)));
1028 template <typename PaintBackendData
>
1029 void nsNativeBasicTheme::PaintStrokedCircle(PaintBackendData
& aPaintData
,
1030 const LayoutDeviceRect
& aRect
,
1031 const sRGBColor
& aBackgroundColor
,
1032 const sRGBColor
& aBorderColor
,
1033 const CSSCoord aBorderWidth
,
1034 DPIRatio aDpiRatio
) {
1035 auto radius
= LayoutDeviceCoord(aRect
.Size().width
) / aDpiRatio
;
1036 PaintRoundedRectWithRadius(aPaintData
, aRect
, aBackgroundColor
, aBorderColor
,
1037 aBorderWidth
, radius
, aDpiRatio
);
1040 void nsNativeBasicTheme::PaintCircleShadow(WebRenderBackendData
& aWrData
,
1041 const LayoutDeviceRect
& aBoxRect
,
1042 const LayoutDeviceRect
& aClipRect
,
1044 const CSSPoint
& aShadowOffset
,
1045 CSSCoord aShadowBlurStdDev
,
1046 DPIRatio aDpiRatio
) {
1047 const bool kBackfaceIsVisible
= true;
1048 const LayoutDeviceCoord stdDev
= aShadowBlurStdDev
* aDpiRatio
;
1049 const LayoutDevicePoint shadowOffset
= aShadowOffset
* aDpiRatio
;
1050 const IntSize inflation
=
1051 gfxAlphaBoxBlur::CalculateBlurRadius(gfxPoint(stdDev
, stdDev
));
1052 LayoutDeviceRect shadowRect
= aBoxRect
;
1053 shadowRect
.MoveBy(shadowOffset
);
1054 shadowRect
.Inflate(inflation
.width
, inflation
.height
);
1055 const auto boxRect
= wr::ToLayoutRect(aBoxRect
);
1056 aWrData
.mBuilder
.PushBoxShadow(
1057 wr::ToLayoutRect(shadowRect
), wr::ToLayoutRect(aClipRect
),
1058 kBackfaceIsVisible
, boxRect
,
1059 wr::ToLayoutVector2D(aShadowOffset
* aDpiRatio
),
1060 wr::ToColorF(DeviceColor(0.0f
, 0.0f
, 0.0f
, aShadowAlpha
)), stdDev
,
1061 /* aSpread = */ 0.0f
,
1062 wr::ToBorderRadius(gfx::RectCornerRadii(aBoxRect
.Size().width
)),
1063 wr::BoxShadowClipMode::Outset
);
1066 void nsNativeBasicTheme::PaintCircleShadow(DrawTarget
& aDrawTarget
,
1067 const LayoutDeviceRect
& aBoxRect
,
1068 const LayoutDeviceRect
& aClipRect
,
1070 const CSSPoint
& aShadowOffset
,
1071 CSSCoord aShadowBlurStdDev
,
1072 DPIRatio aDpiRatio
) {
1073 Float stdDev
= aShadowBlurStdDev
* aDpiRatio
;
1074 Point offset
= (aShadowOffset
* aDpiRatio
).ToUnknownPoint();
1076 RefPtr
<FilterNode
> blurFilter
=
1077 aDrawTarget
.CreateFilter(FilterType::GAUSSIAN_BLUR
);
1082 blurFilter
->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION
, stdDev
);
1085 gfxAlphaBoxBlur::CalculateBlurRadius(gfxPoint(stdDev
, stdDev
));
1086 Rect inflatedRect
= aBoxRect
.ToUnknownRect();
1087 inflatedRect
.Inflate(inflation
.width
, inflation
.height
);
1088 Rect sourceRectInFilterSpace
=
1089 inflatedRect
- aBoxRect
.TopLeft().ToUnknownPoint();
1090 Point destinationPointOfSourceRect
= inflatedRect
.TopLeft() + offset
;
1092 IntSize dtSize
= RoundedToInt(aBoxRect
.Size().ToUnknownSize());
1093 RefPtr
<DrawTarget
> ellipseDT
= aDrawTarget
.CreateSimilarDrawTargetForFilter(
1094 dtSize
, SurfaceFormat::A8
, blurFilter
, blurFilter
,
1095 sourceRectInFilterSpace
, destinationPointOfSourceRect
);
1100 AutoClipRect
clipRect(aDrawTarget
, aClipRect
);
1102 RefPtr
<Path
> ellipse
= MakePathForEllipse(
1103 *ellipseDT
, (aBoxRect
- aBoxRect
.TopLeft()).Center().ToUnknownPoint(),
1104 aBoxRect
.Size().ToUnknownSize());
1105 ellipseDT
->Fill(ellipse
,
1106 ColorPattern(DeviceColor(0.0f
, 0.0f
, 0.0f
, aShadowAlpha
)));
1107 RefPtr
<SourceSurface
> ellipseSurface
= ellipseDT
->Snapshot();
1109 blurFilter
->SetInput(IN_GAUSSIAN_BLUR_IN
, ellipseSurface
);
1110 aDrawTarget
.DrawFilter(blurFilter
, sourceRectInFilterSpace
,
1111 destinationPointOfSourceRect
);
1114 template <typename PaintBackendData
>
1115 void nsNativeBasicTheme::PaintRadioControl(PaintBackendData
& aPaintData
,
1116 const LayoutDeviceRect
& aRect
,
1117 const EventStates
& aState
,
1118 UseSystemColors aUseSystemColors
,
1119 DPIRatio aDpiRatio
) {
1120 auto [backgroundColor
, borderColor
] =
1121 ComputeCheckboxColors(aState
, StyleAppearance::Radio
, aUseSystemColors
);
1123 CSSCoord borderWidth
= kCheckboxRadioBorderWidth
;
1124 if (backgroundColor
== borderColor
) {
1127 PaintStrokedCircle(aPaintData
, aRect
, backgroundColor
, borderColor
,
1128 borderWidth
, aDpiRatio
);
1131 if (aState
.HasState(NS_EVENT_STATE_CHECKED
)) {
1132 LayoutDeviceRect
rect(aRect
);
1133 rect
.Deflate(SnapBorderWidth(kCheckboxRadioBorderWidth
, aDpiRatio
));
1135 auto checkColor
= ComputeCheckmarkColor(aState
, aUseSystemColors
);
1136 PaintStrokedCircle(aPaintData
, rect
, backgroundColor
, checkColor
,
1137 kCheckboxRadioBorderWidth
, aDpiRatio
);
1140 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1141 PaintRoundedFocusRect(aPaintData
, aRect
, aUseSystemColors
, aDpiRatio
, 5.0f
,
1146 template <typename PaintBackendData
>
1147 void nsNativeBasicTheme::PaintTextField(PaintBackendData
& aPaintData
,
1148 const LayoutDeviceRect
& aRect
,
1149 const EventStates
& aState
,
1150 UseSystemColors aUseSystemColors
,
1151 DPIRatio aDpiRatio
) {
1152 auto [backgroundColor
, borderColor
] =
1153 ComputeTextfieldColors(aState
, aUseSystemColors
);
1155 const CSSCoord radius
= 2.0f
;
1157 PaintRoundedRectWithRadius(aPaintData
, aRect
, backgroundColor
, borderColor
,
1158 kTextFieldBorderWidth
, radius
, aDpiRatio
);
1160 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1161 PaintRoundedFocusRect(aPaintData
, aRect
, aUseSystemColors
, aDpiRatio
,
1162 radius
+ kTextFieldBorderWidth
,
1163 -kTextFieldBorderWidth
);
1167 template <typename PaintBackendData
>
1168 void nsNativeBasicTheme::PaintListbox(PaintBackendData
& aPaintData
,
1169 const LayoutDeviceRect
& aRect
,
1170 const EventStates
& aState
,
1171 UseSystemColors aUseSystemColors
,
1172 DPIRatio aDpiRatio
) {
1173 const CSSCoord radius
= 2.0f
;
1174 auto [backgroundColor
, borderColor
] =
1175 ComputeTextfieldColors(aState
, aUseSystemColors
);
1177 PaintRoundedRectWithRadius(aPaintData
, aRect
, backgroundColor
, borderColor
,
1178 kMenulistBorderWidth
, radius
, aDpiRatio
);
1180 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1181 PaintRoundedFocusRect(aPaintData
, aRect
, aUseSystemColors
, aDpiRatio
,
1182 radius
+ kMenulistBorderWidth
, -kMenulistBorderWidth
);
1186 template <typename PaintBackendData
>
1187 void nsNativeBasicTheme::PaintMenulist(PaintBackendData
& aDrawTarget
,
1188 const LayoutDeviceRect
& aRect
,
1189 const EventStates
& aState
,
1190 UseSystemColors aUseSystemColors
,
1191 DPIRatio aDpiRatio
) {
1192 const CSSCoord radius
= 4.0f
;
1193 auto [backgroundColor
, borderColor
] =
1194 ComputeButtonColors(aState
, aUseSystemColors
);
1196 PaintRoundedRectWithRadius(aDrawTarget
, aRect
, backgroundColor
, borderColor
,
1197 kMenulistBorderWidth
, radius
, aDpiRatio
);
1199 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1200 PaintRoundedFocusRect(aDrawTarget
, aRect
, aUseSystemColors
, aDpiRatio
,
1201 radius
+ kMenulistBorderWidth
, -kMenulistBorderWidth
);
1205 void nsNativeBasicTheme::PaintArrow(DrawTarget
& aDrawTarget
,
1206 const LayoutDeviceRect
& aRect
,
1207 const float aArrowPolygonX
[],
1208 const float aArrowPolygonY
[],
1209 const float aArrowPolygonSize
,
1210 const int32_t aArrowNumPoints
,
1211 const sRGBColor aFillColor
) {
1212 const float scale
= ScaleToFillRect(aRect
, aArrowPolygonSize
);
1214 auto center
= aRect
.Center().ToUnknownPoint();
1216 RefPtr
<PathBuilder
> builder
= aDrawTarget
.CreatePathBuilder();
1218 center
+ Point(aArrowPolygonX
[0] * scale
, aArrowPolygonY
[0] * scale
);
1220 for (int32_t i
= 1; i
< aArrowNumPoints
; i
++) {
1221 p
= center
+ Point(aArrowPolygonX
[i
] * scale
, aArrowPolygonY
[i
] * scale
);
1224 RefPtr
<Path
> path
= builder
->Finish();
1226 aDrawTarget
.Fill(path
, ColorPattern(ToDeviceColor(aFillColor
)));
1229 void nsNativeBasicTheme::PaintMenulistArrowButton(
1230 nsIFrame
* aFrame
, DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
,
1231 const EventStates
& aState
, UseSystemColors aUseSystemColors
) {
1232 const float kPolygonX
[] = {-4.0f
, -0.5f
, 0.5f
, 4.0f
, 4.0f
,
1233 3.0f
, 0.0f
, 0.0f
, -3.0f
, -4.0f
};
1234 const float kPolygonY
[] = {-1, 3.0f
, 3.0f
, -1.0f
, -2.0f
,
1235 -2.0f
, 1.5f
, 1.5f
, -2.0f
, -2.0f
};
1237 const float kPolygonSize
= kMinimumDropdownArrowButtonWidth
;
1239 sRGBColor arrowColor
=
1240 ComputeMenulistArrowButtonColor(aState
, aUseSystemColors
);
1241 PaintArrow(aDrawTarget
, aRect
, kPolygonX
, kPolygonY
, kPolygonSize
,
1242 ArrayLength(kPolygonX
), arrowColor
);
1245 void nsNativeBasicTheme::PaintSpinnerButton(
1246 nsIFrame
* aFrame
, DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
,
1247 const EventStates
& aState
, StyleAppearance aAppearance
,
1248 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1249 auto [backgroundColor
, borderColor
] =
1250 ComputeButtonColors(aState
, aUseSystemColors
);
1252 aDrawTarget
.FillRect(aRect
.ToUnknownRect(),
1253 ColorPattern(ToDeviceColor(backgroundColor
)));
1255 const float kPolygonX
[] = {-3.5f
, -0.5f
, 0.5f
, 3.5f
, 3.5f
,
1256 2.5f
, 0.0f
, 0.0f
, -2.5f
, -3.5f
};
1257 float polygonY
[] = {-1.5f
, 1.5f
, 1.5f
, -1.5f
, -2.5f
,
1258 -2.5f
, 0.0f
, 0.0f
, -2.5f
, -2.5f
};
1260 const float kPolygonSize
= kMinimumSpinnerButtonHeight
;
1261 if (aAppearance
== StyleAppearance::SpinnerUpbutton
) {
1262 for (auto& coord
: polygonY
) {
1267 PaintArrow(aDrawTarget
, aRect
, kPolygonX
, polygonY
, kPolygonSize
,
1268 ArrayLength(kPolygonX
), borderColor
);
1271 template <typename PaintBackendData
>
1272 void nsNativeBasicTheme::PaintRange(nsIFrame
* aFrame
,
1273 PaintBackendData
& aPaintData
,
1274 const LayoutDeviceRect
& aRect
,
1275 const EventStates
& aState
,
1276 UseSystemColors aUseSystemColors
,
1277 DPIRatio aDpiRatio
, bool aHorizontal
) {
1278 nsRangeFrame
* rangeFrame
= do_QueryFrame(aFrame
);
1283 double progress
= rangeFrame
->GetValueAsFractionOfRange();
1285 LayoutDeviceRect
thumbRect(0, 0, kMinimumRangeThumbSize
* aDpiRatio
,
1286 kMinimumRangeThumbSize
* aDpiRatio
);
1287 LayoutDeviceRect
progressClipRect(aRect
);
1288 LayoutDeviceRect
trackClipRect(aRect
);
1289 const LayoutDeviceCoord verticalSize
= kRangeHeight
* aDpiRatio
;
1291 rect
.height
= verticalSize
;
1292 rect
.y
= aRect
.y
+ (aRect
.height
- rect
.height
) / 2;
1293 thumbRect
.y
= aRect
.y
+ (aRect
.height
- thumbRect
.height
) / 2;
1295 if (IsFrameRTL(aFrame
)) {
1297 aRect
.x
+ (aRect
.width
- thumbRect
.width
) * (1.0 - progress
);
1298 float midPoint
= thumbRect
.Center().X();
1299 trackClipRect
.SetBoxX(aRect
.X(), midPoint
);
1300 progressClipRect
.SetBoxX(midPoint
, aRect
.XMost());
1302 thumbRect
.x
= aRect
.x
+ (aRect
.width
- thumbRect
.width
) * progress
;
1303 float midPoint
= thumbRect
.Center().X();
1304 progressClipRect
.SetBoxX(aRect
.X(), midPoint
);
1305 trackClipRect
.SetBoxX(midPoint
, aRect
.XMost());
1308 rect
.width
= verticalSize
;
1309 rect
.x
= aRect
.x
+ (aRect
.width
- rect
.width
) / 2;
1310 thumbRect
.x
= aRect
.x
+ (aRect
.width
- thumbRect
.width
) / 2;
1313 aRect
.y
+ (aRect
.height
- thumbRect
.height
) * (1.0 - progress
);
1314 float midPoint
= thumbRect
.Center().Y();
1315 trackClipRect
.SetBoxY(aRect
.Y(), midPoint
);
1316 progressClipRect
.SetBoxY(midPoint
, aRect
.YMost());
1319 const CSSCoord borderWidth
= 1.0f
;
1320 const CSSCoord radius
= 3.0f
;
1322 auto [progressColor
, progressBorderColor
] =
1323 ComputeRangeProgressColors(aState
, aUseSystemColors
);
1324 auto [trackColor
, trackBorderColor
] =
1325 ComputeRangeTrackColors(aState
, aUseSystemColors
);
1327 PaintRoundedRectWithRadius(aPaintData
, rect
, progressClipRect
, progressColor
,
1328 progressBorderColor
, borderWidth
, radius
,
1331 PaintRoundedRectWithRadius(aPaintData
, rect
, trackClipRect
, trackColor
,
1332 trackBorderColor
, borderWidth
, radius
, aDpiRatio
);
1334 if (!aState
.HasState(NS_EVENT_STATE_DISABLED
)) {
1335 // Ensure the shadow doesn't expand outside of our overflow rect declared in
1336 // GetWidgetOverflow().
1337 auto overflowRect
= aRect
;
1338 overflowRect
.Inflate(CSSCoord(6.0f
) * aDpiRatio
);
1340 PaintCircleShadow(aPaintData
, thumbRect
, overflowRect
, 0.3f
,
1341 CSSPoint(0.0f
, 2.0f
), 2.0f
, aDpiRatio
);
1344 // Draw the thumb on top.
1345 const CSSCoord thumbBorderWidth
= 2.0f
;
1346 auto [thumbColor
, thumbBorderColor
] =
1347 ComputeRangeThumbColors(aState
, aUseSystemColors
);
1349 PaintStrokedCircle(aPaintData
, thumbRect
, thumbColor
, thumbBorderColor
,
1350 thumbBorderWidth
, aDpiRatio
);
1352 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1353 PaintRoundedFocusRect(aPaintData
, aRect
, aUseSystemColors
, aDpiRatio
,
1358 template <typename PaintBackendData
>
1359 void nsNativeBasicTheme::PaintProgress(nsIFrame
* aFrame
,
1360 PaintBackendData
& aPaintData
,
1361 const LayoutDeviceRect
& aRect
,
1362 const EventStates
& aState
,
1363 UseSystemColors aUseSystemColors
,
1364 DPIRatio aDpiRatio
, bool aIsMeter
) {
1365 const CSSCoord borderWidth
= 1.0f
;
1366 const CSSCoord radius
= aIsMeter
? 6.0f
: 3.0f
;
1368 LayoutDeviceRect
rect(aRect
);
1369 const LayoutDeviceCoord thickness
=
1370 (aIsMeter
? kMeterHeight
: kProgressbarHeight
) * aDpiRatio
;
1372 const bool isHorizontal
= !nsNativeTheme::IsVerticalProgress(aFrame
);
1374 // Center it vertically.
1375 rect
.y
+= (rect
.height
- thickness
) / 2;
1376 rect
.height
= thickness
;
1378 // Center it horizontally.
1379 rect
.x
+= (rect
.width
- thickness
) / 2;
1380 rect
.width
= thickness
;
1384 // Paint the track, unclipped.
1385 auto [backgroundColor
, borderColor
] =
1386 ComputeProgressTrackColors(aUseSystemColors
);
1387 PaintRoundedRectWithRadius(aPaintData
, rect
, rect
, backgroundColor
,
1388 borderColor
, borderWidth
, radius
, aDpiRatio
);
1391 // Now paint the chunk, clipped as needed.
1392 LayoutDeviceRect clipRect
= rect
;
1393 if (aState
.HasState(NS_EVENT_STATE_INDETERMINATE
)) {
1394 // For indeterminate progress, we paint an animated chunk of 1/3 of the
1397 // Animation speed and math borrowed from GTK.
1398 const LayoutDeviceCoord size
= isHorizontal
? rect
.width
: rect
.height
;
1399 const LayoutDeviceCoord barSize
= size
* 0.3333f
;
1400 const LayoutDeviceCoord travel
= 2.0f
* (size
- barSize
);
1402 // Period equals to travel / pixelsPerMillisecond where pixelsPerMillisecond
1403 // equals progressSize / 1000.0. This is equivalent to 1600.
1404 const unsigned kPeriod
= 1600;
1406 const int t
= PR_IntervalToMilliseconds(PR_IntervalNow()) % kPeriod
;
1407 const LayoutDeviceCoord dx
= travel
* float(t
) / float(kPeriod
);
1409 rect
.width
= barSize
;
1410 rect
.x
+= (dx
< travel
* .5f
) ? dx
: travel
- dx
;
1412 rect
.height
= barSize
;
1413 rect
.y
+= (dx
< travel
* .5f
) ? dx
: travel
- dx
;
1416 // Queue the next frame if needed.
1417 if (!QueueAnimatedContentForRefresh(aFrame
->GetContent(), 60)) {
1418 NS_WARNING("Couldn't refresh indeterminate <progress>");
1421 // This is the progress chunk, clip it to the right amount.
1422 double position
= [&] {
1424 auto* meter
= dom::HTMLMeterElement::FromNode(aFrame
->GetContent());
1428 return meter
->Value() / meter
->Max();
1430 auto* progress
= dom::HTMLProgressElement::FromNode(aFrame
->GetContent());
1434 return progress
->Value() / progress
->Max();
1437 double clipWidth
= rect
.width
* position
;
1438 clipRect
.width
= clipWidth
;
1439 if (IsFrameRTL(aFrame
)) {
1440 clipRect
.x
+= rect
.width
- clipWidth
;
1443 double clipHeight
= rect
.height
* position
;
1444 clipRect
.height
= clipHeight
;
1445 clipRect
.y
+= rect
.height
- clipHeight
;
1449 auto [backgroundColor
, borderColor
] =
1450 aIsMeter
? ComputeMeterchunkColors(aState
, aUseSystemColors
)
1451 : ComputeProgressColors(aUseSystemColors
);
1452 PaintRoundedRectWithRadius(aPaintData
, rect
, clipRect
, backgroundColor
,
1453 borderColor
, borderWidth
, radius
, aDpiRatio
);
1456 template <typename PaintBackendData
>
1457 void nsNativeBasicTheme::PaintButton(nsIFrame
* aFrame
,
1458 PaintBackendData
& aPaintData
,
1459 const LayoutDeviceRect
& aRect
,
1460 const EventStates
& aState
,
1461 UseSystemColors aUseSystemColors
,
1462 DPIRatio aDpiRatio
) {
1463 const CSSCoord radius
= 4.0f
;
1464 auto [backgroundColor
, borderColor
] =
1465 ComputeButtonColors(aState
, aUseSystemColors
, aFrame
);
1467 PaintRoundedRectWithRadius(aPaintData
, aRect
, backgroundColor
, borderColor
,
1468 kButtonBorderWidth
, radius
, aDpiRatio
);
1470 if (aState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1471 PaintRoundedFocusRect(aPaintData
, aRect
, aUseSystemColors
, aDpiRatio
,
1472 radius
+ kButtonBorderWidth
, -kButtonBorderWidth
);
1476 template <typename PaintBackendData
>
1477 bool nsNativeBasicTheme::DoPaintDefaultScrollbarThumb(
1478 PaintBackendData
& aPaintData
, const LayoutDeviceRect
& aRect
,
1479 bool aHorizontal
, nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1480 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
1481 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1482 sRGBColor thumbColor
= ComputeScrollbarThumbColor(
1483 aFrame
, aStyle
, aElementState
, aDocumentState
, aUseSystemColors
);
1484 FillRect(aPaintData
, aRect
, thumbColor
);
1488 bool nsNativeBasicTheme::PaintScrollbarThumb(
1489 DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
, bool aHorizontal
,
1490 nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1491 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
1492 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1493 return DoPaintDefaultScrollbarThumb(aDrawTarget
, aRect
, aHorizontal
, aFrame
,
1494 aStyle
, aElementState
, aDocumentState
,
1495 aUseSystemColors
, aDpiRatio
);
1498 bool nsNativeBasicTheme::PaintScrollbarThumb(
1499 WebRenderBackendData
& aWrData
, const LayoutDeviceRect
& aRect
,
1500 bool aHorizontal
, nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1501 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
1502 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1503 return DoPaintDefaultScrollbarThumb(aWrData
, aRect
, aHorizontal
, aFrame
,
1504 aStyle
, aElementState
, aDocumentState
,
1505 aUseSystemColors
, aDpiRatio
);
1508 template <typename PaintBackendData
>
1509 bool nsNativeBasicTheme::DoPaintDefaultScrollbar(
1510 PaintBackendData
& aPaintData
, const LayoutDeviceRect
& aRect
,
1511 bool aHorizontal
, nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1512 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
1513 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1514 if (sOverlayScrollbars
&& !aElementState
.HasAtLeastOneOfStates(
1515 NS_EVENT_STATE_HOVER
| NS_EVENT_STATE_ACTIVE
)) {
1518 auto scrollbarColor
= ComputeScrollbarTrackColor(
1519 aFrame
, aStyle
, aDocumentState
, aUseSystemColors
);
1520 FillRect(aPaintData
, aRect
, scrollbarColor
);
1524 bool nsNativeBasicTheme::PaintScrollbar(
1525 DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
, bool aHorizontal
,
1526 nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1527 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
1528 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1529 return DoPaintDefaultScrollbar(aDrawTarget
, aRect
, aHorizontal
, aFrame
,
1530 aStyle
, aElementState
, aDocumentState
,
1531 aUseSystemColors
, aDpiRatio
);
1534 bool nsNativeBasicTheme::PaintScrollbar(
1535 WebRenderBackendData
& aWrData
, const LayoutDeviceRect
& aRect
,
1536 bool aHorizontal
, nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1537 const EventStates
& aElementState
, const EventStates
& aDocumentState
,
1538 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1539 return DoPaintDefaultScrollbar(aWrData
, aRect
, aHorizontal
, aFrame
, aStyle
,
1540 aElementState
, aDocumentState
,
1541 aUseSystemColors
, aDpiRatio
);
1544 template <typename PaintBackendData
>
1545 bool nsNativeBasicTheme::DoPaintDefaultScrollCorner(
1546 PaintBackendData
& aPaintData
, const LayoutDeviceRect
& aRect
,
1547 nsIFrame
* aFrame
, const ComputedStyle
& aStyle
,
1548 const EventStates
& aDocumentState
, UseSystemColors aUseSystemColors
,
1549 DPIRatio aDpiRatio
) {
1550 auto scrollbarColor
= ComputeScrollbarTrackColor(
1551 aFrame
, aStyle
, aDocumentState
, aUseSystemColors
);
1552 FillRect(aPaintData
, aRect
, scrollbarColor
);
1556 bool nsNativeBasicTheme::PaintScrollCorner(
1557 DrawTarget
& aDrawTarget
, const LayoutDeviceRect
& aRect
, nsIFrame
* aFrame
,
1558 const ComputedStyle
& aStyle
, const EventStates
& aDocumentState
,
1559 UseSystemColors aUseSystemColors
, DPIRatio aDpiRatio
) {
1560 return DoPaintDefaultScrollCorner(aDrawTarget
, aRect
, aFrame
, aStyle
,
1561 aDocumentState
, aUseSystemColors
,
1565 bool nsNativeBasicTheme::PaintScrollCorner(WebRenderBackendData
& aWrData
,
1566 const LayoutDeviceRect
& aRect
,
1568 const ComputedStyle
& aStyle
,
1569 const EventStates
& aDocumentState
,
1570 UseSystemColors aUseSystemColors
,
1571 DPIRatio aDpiRatio
) {
1572 return DoPaintDefaultScrollCorner(aWrData
, aRect
, aFrame
, aStyle
,
1573 aDocumentState
, aUseSystemColors
,
1577 void nsNativeBasicTheme::PaintScrollbarButton(
1578 DrawTarget
& aDrawTarget
, StyleAppearance aAppearance
,
1579 const LayoutDeviceRect
& aRect
, nsIFrame
* aFrame
,
1580 const ComputedStyle
& aStyle
, const EventStates
& aElementState
,
1581 const EventStates
& aDocumentState
, UseSystemColors aUseSystemColors
,
1582 DPIRatio aDpiRatio
) {
1583 auto [buttonColor
, arrowColor
] =
1584 ComputeScrollbarButtonColors(aFrame
, aAppearance
, aStyle
, aElementState
,
1585 aDocumentState
, aUseSystemColors
);
1586 aDrawTarget
.FillRect(aRect
.ToUnknownRect(),
1587 ColorPattern(ToDeviceColor(buttonColor
)));
1589 // Start with Up arrow.
1590 float arrowPolygonX
[] = {-4.0f
, 0.0f
, 4.0f
, 4.0f
, 0.0f
, -4.0f
};
1591 float arrowPolygonY
[] = {0.0f
, -4.0f
, 0.0f
, 3.0f
, -1.0f
, 3.0f
};
1593 const float kPolygonSize
= 17;
1595 const int32_t arrowNumPoints
= ArrayLength(arrowPolygonX
);
1596 switch (aAppearance
) {
1597 case StyleAppearance::ScrollbarbuttonUp
:
1599 case StyleAppearance::ScrollbarbuttonDown
:
1600 for (int32_t i
= 0; i
< arrowNumPoints
; i
++) {
1601 arrowPolygonY
[i
] *= -1;
1604 case StyleAppearance::ScrollbarbuttonLeft
:
1605 for (int32_t i
= 0; i
< arrowNumPoints
; i
++) {
1606 int32_t temp
= arrowPolygonX
[i
];
1607 arrowPolygonX
[i
] = arrowPolygonY
[i
];
1608 arrowPolygonY
[i
] = temp
;
1611 case StyleAppearance::ScrollbarbuttonRight
:
1612 for (int32_t i
= 0; i
< arrowNumPoints
; i
++) {
1613 int32_t temp
= arrowPolygonX
[i
];
1614 arrowPolygonX
[i
] = arrowPolygonY
[i
] * -1;
1615 arrowPolygonY
[i
] = temp
;
1621 PaintArrow(aDrawTarget
, aRect
, arrowPolygonX
, arrowPolygonY
, kPolygonSize
,
1622 arrowNumPoints
, arrowColor
);
1626 nsNativeBasicTheme::DrawWidgetBackground(gfxContext
* aContext
, nsIFrame
* aFrame
,
1627 StyleAppearance aAppearance
,
1628 const nsRect
& aRect
,
1629 const nsRect
& /* aDirtyRect */,
1630 DrawOverflow aDrawOverflow
) {
1631 if (!DoDrawWidgetBackground(*aContext
->GetDrawTarget(), aFrame
, aAppearance
,
1632 aRect
, aDrawOverflow
)) {
1633 return NS_ERROR_NOT_IMPLEMENTED
;
1638 bool nsNativeBasicTheme::CreateWebRenderCommandsForWidget(
1639 mozilla::wr::DisplayListBuilder
& aBuilder
,
1640 mozilla::wr::IpcResourceUpdateQueue
& aResources
,
1641 const mozilla::layers::StackingContextHelper
& aSc
,
1642 mozilla::layers::RenderRootStateManager
* aManager
, nsIFrame
* aFrame
,
1643 StyleAppearance aAppearance
, const nsRect
& aRect
) {
1644 if (!StaticPrefs::widget_non_native_theme_webrender()) {
1647 WebRenderBackendData data
{aBuilder
, aResources
, aSc
, aManager
};
1648 return DoDrawWidgetBackground(data
, aFrame
, aAppearance
, aRect
,
1652 static LayoutDeviceRect
ToSnappedRect(const nsRect
& aRect
,
1653 nscoord aTwipsPerPixel
, DrawTarget
& aDt
) {
1654 return LayoutDeviceRect::FromUnknownRect(
1655 NSRectToSnappedRect(aRect
, aTwipsPerPixel
, aDt
));
1658 static LayoutDeviceRect
ToSnappedRect(
1659 const nsRect
& aRect
, nscoord aTwipsPerPixel
,
1660 nsNativeBasicTheme::WebRenderBackendData
& aDt
) {
1661 // TODO: Do we need to do any more snapping here?
1662 return LayoutDeviceRect::FromAppUnits(aRect
, aTwipsPerPixel
);
1665 auto nsNativeBasicTheme::ShouldUseSystemColors(const dom::Document
& aDoc
)
1666 -> UseSystemColors
{
1667 // TODO: Do we really want to use system colors even when the page can
1668 // override the high contrast theme? (mUseDocumentColors = true?).
1669 return UseSystemColors(
1670 PreferenceSheet::PrefsFor(aDoc
).NonNativeThemeShouldUseSystemColors());
1673 template <typename PaintBackendData
>
1674 bool nsNativeBasicTheme::DoDrawWidgetBackground(PaintBackendData
& aPaintData
,
1676 StyleAppearance aAppearance
,
1677 const nsRect
& aRect
,
1678 DrawOverflow aDrawOverflow
) {
1679 static_assert(std::is_same_v
<PaintBackendData
, DrawTarget
> ||
1680 std::is_same_v
<PaintBackendData
, WebRenderBackendData
>);
1682 const nsPresContext
* pc
= aFrame
->PresContext();
1683 const nscoord twipsPerPixel
= pc
->AppUnitsPerDevPixel();
1684 const auto devPxRect
= ToSnappedRect(aRect
, twipsPerPixel
, aPaintData
);
1686 const EventStates docState
= pc
->Document()->GetDocumentState();
1687 const auto useSystemColors
= ShouldUseSystemColors(*pc
->Document());
1688 EventStates eventState
= GetContentState(aFrame
, aAppearance
);
1689 if (aAppearance
== StyleAppearance::MozMenulistArrowButton
) {
1690 bool isHTML
= IsHTMLContent(aFrame
);
1691 nsIFrame
* parentFrame
= aFrame
->GetParent();
1692 bool isMenulist
= !isHTML
&& parentFrame
->IsMenuFrame();
1693 // HTML select and XUL menulist dropdown buttons get state from the
1695 if (isHTML
|| isMenulist
) {
1696 aFrame
= parentFrame
;
1697 eventState
= GetContentState(parentFrame
, aAppearance
);
1701 if (aDrawOverflow
== DrawOverflow::No
) {
1702 eventState
&= ~NS_EVENT_STATE_FOCUSRING
;
1705 // Hack to avoid skia fuzziness: Add a dummy clip if the widget doesn't
1706 // overflow devPxRect.
1707 Maybe
<AutoClipRect
> maybeClipRect
;
1708 if constexpr (std::is_same_v
<PaintBackendData
, DrawTarget
>) {
1709 if (aAppearance
!= StyleAppearance::FocusOutline
&&
1710 aAppearance
!= StyleAppearance::Range
&&
1711 !eventState
.HasState(NS_EVENT_STATE_FOCUSRING
)) {
1712 maybeClipRect
.emplace(aPaintData
, devPxRect
);
1716 DPIRatio dpiRatio
= GetDPIRatio(aFrame
, aAppearance
);
1718 switch (aAppearance
) {
1719 case StyleAppearance::Radio
: {
1720 auto rect
= CheckBoxRadioRect(devPxRect
);
1721 PaintRadioControl(aPaintData
, rect
, eventState
, useSystemColors
,
1725 case StyleAppearance::Checkbox
: {
1726 if constexpr (std::is_same_v
<PaintBackendData
, WebRenderBackendData
>) {
1727 // TODO: Need to figure out how to best draw this using WR.
1730 auto rect
= CheckBoxRadioRect(devPxRect
);
1731 PaintCheckboxControl(aPaintData
, rect
, eventState
, useSystemColors
,
1736 case StyleAppearance::Textarea
:
1737 case StyleAppearance::Textfield
:
1738 case StyleAppearance::NumberInput
:
1739 PaintTextField(aPaintData
, devPxRect
, eventState
, useSystemColors
,
1742 case StyleAppearance::Listbox
:
1743 PaintListbox(aPaintData
, devPxRect
, eventState
, useSystemColors
,
1746 case StyleAppearance::MenulistButton
:
1747 case StyleAppearance::Menulist
:
1748 PaintMenulist(aPaintData
, devPxRect
, eventState
, useSystemColors
,
1751 case StyleAppearance::MozMenulistArrowButton
:
1752 if constexpr (std::is_same_v
<PaintBackendData
, WebRenderBackendData
>) {
1753 // TODO: Need to figure out how to best draw this using WR.
1756 PaintMenulistArrowButton(aFrame
, aPaintData
, devPxRect
, eventState
,
1760 case StyleAppearance::SpinnerUpbutton
:
1761 case StyleAppearance::SpinnerDownbutton
:
1762 if constexpr (std::is_same_v
<PaintBackendData
, WebRenderBackendData
>) {
1763 // TODO: Need to figure out how to best draw this using WR.
1766 PaintSpinnerButton(aFrame
, aPaintData
, devPxRect
, eventState
,
1767 aAppearance
, useSystemColors
, dpiRatio
);
1770 case StyleAppearance::Range
:
1771 PaintRange(aFrame
, aPaintData
, devPxRect
, eventState
, useSystemColors
,
1772 dpiRatio
, IsRangeHorizontal(aFrame
));
1774 case StyleAppearance::RangeThumb
:
1775 // Painted as part of StyleAppearance::Range.
1777 case StyleAppearance::ProgressBar
:
1778 PaintProgress(aFrame
, aPaintData
, devPxRect
, eventState
, useSystemColors
,
1780 /* aIsMeter = */ false);
1782 case StyleAppearance::Progresschunk
:
1783 /* Painted as part of the progress bar */
1785 case StyleAppearance::Meter
:
1786 PaintProgress(aFrame
, aPaintData
, devPxRect
, eventState
, useSystemColors
,
1787 dpiRatio
, /* aIsMeter = */ true);
1789 case StyleAppearance::Meterchunk
:
1790 /* Painted as part of the meter bar */
1792 case StyleAppearance::ScrollbarthumbHorizontal
:
1793 case StyleAppearance::ScrollbarthumbVertical
: {
1795 aAppearance
== StyleAppearance::ScrollbarthumbHorizontal
;
1796 return PaintScrollbarThumb(aPaintData
, devPxRect
, isHorizontal
, aFrame
,
1797 *nsLayoutUtils::StyleForScrollbar(aFrame
),
1798 eventState
, docState
, useSystemColors
,
1801 case StyleAppearance::ScrollbartrackHorizontal
:
1802 case StyleAppearance::ScrollbartrackVertical
: {
1804 aAppearance
== StyleAppearance::ScrollbartrackHorizontal
;
1805 return PaintScrollbarTrack(aPaintData
, devPxRect
, isHorizontal
, aFrame
,
1806 *nsLayoutUtils::StyleForScrollbar(aFrame
),
1807 docState
, useSystemColors
, dpiRatio
);
1809 case StyleAppearance::ScrollbarHorizontal
:
1810 case StyleAppearance::ScrollbarVertical
: {
1811 bool isHorizontal
= aAppearance
== StyleAppearance::ScrollbarHorizontal
;
1812 return PaintScrollbar(aPaintData
, devPxRect
, isHorizontal
, aFrame
,
1813 *nsLayoutUtils::StyleForScrollbar(aFrame
),
1814 eventState
, docState
, useSystemColors
, dpiRatio
);
1816 case StyleAppearance::Scrollcorner
:
1817 return PaintScrollCorner(aPaintData
, devPxRect
, aFrame
,
1818 *nsLayoutUtils::StyleForScrollbar(aFrame
),
1819 docState
, useSystemColors
, dpiRatio
);
1820 case StyleAppearance::ScrollbarbuttonUp
:
1821 case StyleAppearance::ScrollbarbuttonDown
:
1822 case StyleAppearance::ScrollbarbuttonLeft
:
1823 case StyleAppearance::ScrollbarbuttonRight
:
1824 // For scrollbar-width:thin, we don't display the buttons.
1825 if (!IsScrollbarWidthThin(aFrame
)) {
1826 if constexpr (std::is_same_v
<PaintBackendData
, WebRenderBackendData
>) {
1827 // TODO: Need to figure out how to best draw this using WR.
1830 PaintScrollbarButton(aPaintData
, aAppearance
, devPxRect
, aFrame
,
1831 *nsLayoutUtils::StyleForScrollbar(aFrame
),
1832 eventState
, docState
, useSystemColors
, dpiRatio
);
1836 case StyleAppearance::Button
:
1837 PaintButton(aFrame
, aPaintData
, devPxRect
, eventState
, useSystemColors
,
1840 case StyleAppearance::FocusOutline
:
1841 PaintAutoStyleOutline(aFrame
, aPaintData
, devPxRect
, useSystemColors
,
1845 // Various appearance values are used for XUL elements. Normally these
1846 // will not be available in content documents (and thus in the content
1847 // processes where the native basic theme can be used), but tests are
1848 // run with the remote XUL pref enabled and so we can get in here. So
1849 // we just return an error rather than assert.
1856 template <typename PaintBackendData
>
1857 void nsNativeBasicTheme::PaintAutoStyleOutline(nsIFrame
* aFrame
,
1858 PaintBackendData
& aPaintData
,
1859 const LayoutDeviceRect
& aRect
,
1860 UseSystemColors aUseSystemColors
,
1861 DPIRatio aDpiRatio
) {
1862 auto [innerColor
, middleColor
, outerColor
] =
1863 ComputeFocusRectColors(aUseSystemColors
);
1864 Unused
<< middleColor
;
1865 Unused
<< outerColor
;
1867 LayoutDeviceRect
rect(aRect
);
1869 LayoutDeviceCoord(SnapBorderWidth(kInnerFocusOutlineWidth
, aDpiRatio
));
1870 rect
.Inflate(width
);
1872 const nscoord offset
= aFrame
->StyleOutline()->mOutlineOffset
.ToAppUnits();
1873 nscoord cssRadii
[8];
1874 if (!aFrame
->GetBorderRadii(cssRadii
)) {
1875 const CSSCoord cssOffset
= CSSCoord::FromAppUnits(offset
);
1876 const CSSCoord radius
=
1878 ? kInnerFocusOutlineWidth
1879 : std::max(kInnerFocusOutlineWidth
+ cssOffset
, CSSCoord(0.0f
));
1880 return PaintRoundedRectWithRadius(aPaintData
, rect
, sRGBColor::White(0.0f
),
1881 innerColor
, kInnerFocusOutlineWidth
,
1885 nsPresContext
* pc
= aFrame
->PresContext();
1886 const Float devPixelOffset
= pc
->AppUnitsToFloatDevPixels(offset
);
1888 RectCornerRadii innerRadii
;
1889 nsCSSRendering::ComputePixelRadii(cssRadii
, pc
->AppUnitsPerDevPixel(),
1892 const auto borderColor
= ToDeviceColor(innerColor
);
1893 // NOTE(emilio): This doesn't use PaintRoundedRectWithRadius because we need
1894 // to support arbitrary radii.
1895 RectCornerRadii outerRadii
;
1896 if constexpr (std::is_same_v
<PaintBackendData
, WebRenderBackendData
>) {
1897 const Float widths
[4] = {width
+ devPixelOffset
, width
+ devPixelOffset
,
1898 width
+ devPixelOffset
, width
+ devPixelOffset
};
1899 nsCSSBorderRenderer::ComputeOuterRadii(innerRadii
, widths
, &outerRadii
);
1901 const auto dest
= wr::ToLayoutRect(rect
);
1902 const auto side
= wr::ToBorderSide(borderColor
, StyleBorderStyle::Solid
);
1903 const wr::BorderSide sides
[4] = {side
, side
, side
, side
};
1904 const bool kBackfaceIsVisible
= true;
1905 const auto wrWidths
= wr::ToBorderWidths(width
, width
, width
, width
);
1906 const auto wrRadius
= wr::ToBorderRadius(outerRadii
);
1907 aPaintData
.mBuilder
.PushBorder(dest
, dest
, kBackfaceIsVisible
, wrWidths
,
1908 {sides
, 4}, wrRadius
);
1910 const LayoutDeviceCoord halfWidth
= width
* 0.5f
;
1911 rect
.Deflate(halfWidth
);
1912 const Float widths
[4] = {
1913 halfWidth
+ devPixelOffset
, halfWidth
+ devPixelOffset
,
1914 halfWidth
+ devPixelOffset
, halfWidth
+ devPixelOffset
};
1915 nsCSSBorderRenderer::ComputeOuterRadii(innerRadii
, widths
, &outerRadii
);
1917 MakePathForRoundedRect(aPaintData
, rect
.ToUnknownRect(), outerRadii
);
1918 aPaintData
.Stroke(path
, ColorPattern(borderColor
), StrokeOptions(width
));
1922 LayoutDeviceIntMargin
nsNativeBasicTheme::GetWidgetBorder(
1923 nsDeviceContext
* aContext
, nsIFrame
* aFrame
, StyleAppearance aAppearance
) {
1924 switch (aAppearance
) {
1925 case StyleAppearance::Textfield
:
1926 case StyleAppearance::Textarea
:
1927 case StyleAppearance::NumberInput
:
1928 case StyleAppearance::Listbox
:
1929 case StyleAppearance::Menulist
:
1930 case StyleAppearance::MenulistButton
:
1931 case StyleAppearance::Button
:
1932 // Return the border size from the UA sheet, even though what we paint
1933 // doesn't actually match that. We know this is the UA sheet border
1934 // because we disable native theming when different border widths are
1935 // specified by authors, see nsNativeBasicTheme::IsWidgetStyled.
1937 // The Rounded() bit is technically redundant, but needed to appease the
1938 // type system, we should always end up with full device pixels due to
1939 // round_border_to_device_pixels at style time.
1940 return LayoutDeviceIntMargin::FromAppUnits(
1941 aFrame
->StyleBorder()->GetComputedBorder(),
1942 aFrame
->PresContext()->AppUnitsPerDevPixel())
1944 case StyleAppearance::Checkbox
:
1945 case StyleAppearance::Radio
: {
1946 DPIRatio dpiRatio
= GetDPIRatio(aFrame
, aAppearance
);
1947 LayoutDeviceIntCoord w
=
1948 SnapBorderWidth(kCheckboxRadioBorderWidth
, dpiRatio
);
1949 return LayoutDeviceIntMargin(w
, w
, w
, w
);
1952 return LayoutDeviceIntMargin();
1956 bool nsNativeBasicTheme::GetWidgetPadding(nsDeviceContext
* aContext
,
1958 StyleAppearance aAppearance
,
1959 LayoutDeviceIntMargin
* aResult
) {
1960 switch (aAppearance
) {
1961 // Radios and checkboxes return a fixed size in GetMinimumWidgetSize
1962 // and have a meaningful baseline, so they can't have
1963 // author-specified padding.
1964 case StyleAppearance::Radio
:
1965 case StyleAppearance::Checkbox
:
1966 aResult
->SizeTo(0, 0, 0, 0);
1974 bool nsNativeBasicTheme::GetWidgetOverflow(nsDeviceContext
* aContext
,
1976 StyleAppearance aAppearance
,
1977 nsRect
* aOverflowRect
) {
1978 nsIntMargin overflow
;
1979 switch (aAppearance
) {
1980 case StyleAppearance::FocusOutline
:
1981 // 2px * one segment
1982 overflow
.SizeTo(2, 2, 2, 2);
1984 case StyleAppearance::Radio
:
1985 case StyleAppearance::Checkbox
:
1986 case StyleAppearance::Range
:
1987 // 2px for each outline segment, plus 1px separation, plus we paint with a
1988 // 1px extra offset, so 6px.
1989 overflow
.SizeTo(6, 6, 6, 6);
1991 case StyleAppearance::Textarea
:
1992 case StyleAppearance::Textfield
:
1993 case StyleAppearance::NumberInput
:
1994 case StyleAppearance::Listbox
:
1995 case StyleAppearance::MenulistButton
:
1996 case StyleAppearance::Menulist
:
1997 case StyleAppearance::Button
:
1998 // 2px for each segment, plus 1px separation, but we paint 1px inside
1999 // the border area so 4px overflow.
2000 overflow
.SizeTo(4, 4, 4, 4);
2006 // TODO: This should convert from device pixels to app units, not from CSS
2007 // pixels. And it should take the dpi ratio into account.
2008 // Using CSS pixels can cause the overflow to be too small if the page is
2010 aOverflowRect
->Inflate(nsMargin(CSSPixel::ToAppUnits(overflow
.top
),
2011 CSSPixel::ToAppUnits(overflow
.right
),
2012 CSSPixel::ToAppUnits(overflow
.bottom
),
2013 CSSPixel::ToAppUnits(overflow
.left
)));
2018 auto nsNativeBasicTheme::GetScrollbarSizes(nsPresContext
* aPresContext
,
2019 StyleScrollbarWidth aWidth
, Overlay
)
2021 CSSIntCoord h
= sHorizontalScrollbarHeight
;
2022 CSSIntCoord w
= sVerticalScrollbarWidth
;
2023 if (aWidth
== StyleScrollbarWidth::Thin
) {
2027 auto dpi
= GetDPIRatioForScrollbarPart(aPresContext
);
2028 return {(CSSCoord(w
) * dpi
).Rounded(), (CSSCoord(h
) * dpi
).Rounded()};
2031 nscoord
nsNativeBasicTheme::GetCheckboxRadioPrefSize() {
2032 return CSSPixel::ToAppUnits(kCheckboxRadioContentBoxSize
);
2036 nsNativeBasicTheme::GetMinimumWidgetSize(nsPresContext
* aPresContext
,
2038 StyleAppearance aAppearance
,
2039 LayoutDeviceIntSize
* aResult
,
2040 bool* aIsOverridable
) {
2041 DPIRatio dpiRatio
= GetDPIRatio(aFrame
, aAppearance
);
2043 aResult
->width
= aResult
->height
= 0;
2044 *aIsOverridable
= true;
2046 switch (aAppearance
) {
2047 case StyleAppearance::Button
:
2048 if (IsColorPickerButton(aFrame
)) {
2049 aResult
->height
= (kMinimumColorPickerHeight
* dpiRatio
).Rounded();
2052 case StyleAppearance::RangeThumb
:
2053 aResult
->SizeTo((kMinimumRangeThumbSize
* dpiRatio
).Rounded(),
2054 (kMinimumRangeThumbSize
* dpiRatio
).Rounded());
2056 case StyleAppearance::MozMenulistArrowButton
:
2057 aResult
->width
= (kMinimumDropdownArrowButtonWidth
* dpiRatio
).Rounded();
2059 case StyleAppearance::SpinnerUpbutton
:
2060 case StyleAppearance::SpinnerDownbutton
:
2061 aResult
->width
= (kMinimumSpinnerButtonWidth
* dpiRatio
).Rounded();
2062 aResult
->height
= (kMinimumSpinnerButtonHeight
* dpiRatio
).Rounded();
2064 case StyleAppearance::ScrollbarbuttonUp
:
2065 case StyleAppearance::ScrollbarbuttonDown
:
2066 case StyleAppearance::ScrollbarbuttonLeft
:
2067 case StyleAppearance::ScrollbarbuttonRight
:
2068 // For scrollbar-width:thin, we don't display the buttons.
2069 if (IsScrollbarWidthThin(aFrame
)) {
2070 aResult
->SizeTo(0, 0);
2074 case StyleAppearance::ScrollbarthumbVertical
:
2075 case StyleAppearance::ScrollbarthumbHorizontal
: {
2076 auto* style
= nsLayoutUtils::StyleForScrollbar(aFrame
);
2077 auto width
= style
->StyleUIReset()->mScrollbarWidth
;
2078 auto sizes
= GetScrollbarSizes(aPresContext
, width
, Overlay::No
);
2079 // TODO: for short scrollbars it could be nice if the thumb could shrink
2081 const bool isHorizontal
=
2082 aAppearance
== StyleAppearance::ScrollbarthumbHorizontal
||
2083 aAppearance
== StyleAppearance::ScrollbarbuttonLeft
||
2084 aAppearance
== StyleAppearance::ScrollbarbuttonRight
;
2085 const auto size
= isHorizontal
? sizes
.mHorizontal
: sizes
.mVertical
;
2086 aResult
->SizeTo(size
, size
);
2096 nsITheme::Transparency
nsNativeBasicTheme::GetWidgetTransparency(
2097 nsIFrame
* aFrame
, StyleAppearance aAppearance
) {
2098 return eUnknownTransparency
;
2102 nsNativeBasicTheme::WidgetStateChanged(nsIFrame
* aFrame
,
2103 StyleAppearance aAppearance
,
2104 nsAtom
* aAttribute
, bool* aShouldRepaint
,
2105 const nsAttrValue
* aOldValue
) {
2107 // Hover/focus/active changed. Always repaint.
2108 *aShouldRepaint
= true;
2110 // Check the attribute to see if it's relevant.
2111 // disabled, checked, dlgtype, default, etc.
2112 *aShouldRepaint
= false;
2113 if ((aAttribute
== nsGkAtoms::disabled
) ||
2114 (aAttribute
== nsGkAtoms::checked
) ||
2115 (aAttribute
== nsGkAtoms::selected
) ||
2116 (aAttribute
== nsGkAtoms::visuallyselected
) ||
2117 (aAttribute
== nsGkAtoms::menuactive
) ||
2118 (aAttribute
== nsGkAtoms::sortDirection
) ||
2119 (aAttribute
== nsGkAtoms::focused
) ||
2120 (aAttribute
== nsGkAtoms::_default
) ||
2121 (aAttribute
== nsGkAtoms::open
) || (aAttribute
== nsGkAtoms::hover
)) {
2122 *aShouldRepaint
= true;
2130 nsNativeBasicTheme::ThemeChanged() { return NS_OK
; }
2132 bool nsNativeBasicTheme::WidgetAppearanceDependsOnWindowFocus(
2133 StyleAppearance aAppearance
) {
2134 return IsWidgetScrollbarPart(aAppearance
);
2137 nsITheme::ThemeGeometryType
nsNativeBasicTheme::ThemeGeometryTypeForWidget(
2138 nsIFrame
* aFrame
, StyleAppearance aAppearance
) {
2139 return eThemeGeometryTypeUnknown
;
2142 bool nsNativeBasicTheme::ThemeSupportsWidget(nsPresContext
* aPresContext
,
2144 StyleAppearance aAppearance
) {
2145 switch (aAppearance
) {
2146 case StyleAppearance::Radio
:
2147 case StyleAppearance::Checkbox
:
2148 case StyleAppearance::FocusOutline
:
2149 case StyleAppearance::Textarea
:
2150 case StyleAppearance::Textfield
:
2151 case StyleAppearance::Range
:
2152 case StyleAppearance::RangeThumb
:
2153 case StyleAppearance::ProgressBar
:
2154 case StyleAppearance::Progresschunk
:
2155 case StyleAppearance::Meter
:
2156 case StyleAppearance::Meterchunk
:
2157 case StyleAppearance::ScrollbarbuttonUp
:
2158 case StyleAppearance::ScrollbarbuttonDown
:
2159 case StyleAppearance::ScrollbarbuttonLeft
:
2160 case StyleAppearance::ScrollbarbuttonRight
:
2161 case StyleAppearance::ScrollbarthumbHorizontal
:
2162 case StyleAppearance::ScrollbarthumbVertical
:
2163 case StyleAppearance::ScrollbartrackHorizontal
:
2164 case StyleAppearance::ScrollbartrackVertical
:
2165 case StyleAppearance::ScrollbarHorizontal
:
2166 case StyleAppearance::ScrollbarVertical
:
2167 case StyleAppearance::Scrollcorner
:
2168 case StyleAppearance::Button
:
2169 case StyleAppearance::Listbox
:
2170 case StyleAppearance::Menulist
:
2171 case StyleAppearance::MenulistButton
:
2172 case StyleAppearance::NumberInput
:
2173 case StyleAppearance::MozMenulistArrowButton
:
2174 case StyleAppearance::SpinnerUpbutton
:
2175 case StyleAppearance::SpinnerDownbutton
:
2176 return !IsWidgetStyled(aPresContext
, aFrame
, aAppearance
);
2182 bool nsNativeBasicTheme::WidgetIsContainer(StyleAppearance aAppearance
) {
2183 switch (aAppearance
) {
2184 case StyleAppearance::MozMenulistArrowButton
:
2185 case StyleAppearance::Radio
:
2186 case StyleAppearance::Checkbox
:
2193 bool nsNativeBasicTheme::ThemeDrawsFocusForWidget(StyleAppearance aAppearance
) {
2197 bool nsNativeBasicTheme::ThemeNeedsComboboxDropmarker() { return true; }