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/. */
5
6 #include "nsNativeBasicThemeGTK.h"
7
8 #include "nsLayoutUtils.h"
9 #include "nsIFrame.h"
10 #include "nsContainerFrame.h"
11 #include "mozilla/dom/Document.h"
12 #include "mozilla/ClearOnShutdown.h"
13 #include "mozilla/StaticPrefs_widget.h"
14
15 using namespace mozilla;
16
do_GetBasicNativeThemeDoNotUseDirectly()17 already_AddRefed<nsITheme> do_GetBasicNativeThemeDoNotUseDirectly() {
18 static StaticRefPtr<nsITheme> gInstance;
19 if (MOZ_UNLIKELY(!gInstance)) {
20 gInstance = new nsNativeBasicThemeGTK();
21 ClearOnShutdown(&gInstance);
22 }
23 return do_AddRef(gInstance);
24 }
25
GetWidgetTransparency(nsIFrame * aFrame,StyleAppearance aAppearance)26 nsITheme::Transparency nsNativeBasicThemeGTK::GetWidgetTransparency(
27 nsIFrame* aFrame, StyleAppearance aAppearance) {
28 if (!sOverlayScrollbars) {
29 if (aAppearance == StyleAppearance::ScrollbarVertical ||
30 aAppearance == StyleAppearance::ScrollbarHorizontal) {
31 nsPresContext* pc = aFrame->PresContext();
32 auto docState = pc->Document()->GetDocumentState();
33 const auto useSystemColors = ShouldUseSystemColors(*pc);
34 const auto* style = nsLayoutUtils::StyleForScrollbar(aFrame);
35 auto trackColor =
36 ComputeScrollbarTrackColor(aFrame, *style, docState, useSystemColors);
37 return trackColor.a == 1.0 ? eOpaque : eTransparent;
38 }
39 }
40 return nsNativeBasicTheme::GetWidgetTransparency(aFrame, aAppearance);
41 }
42
ThemeSupportsScrollbarButtons()43 bool nsNativeBasicThemeGTK::ThemeSupportsScrollbarButtons() {
44 return StaticPrefs::widget_non_native_theme_gtk_scrollbar_allow_buttons();
45 }
46
47 NS_IMETHODIMP
GetMinimumWidgetSize(nsPresContext * aPresContext,nsIFrame * aFrame,StyleAppearance aAppearance,LayoutDeviceIntSize * aResult,bool * aIsOverridable)48 nsNativeBasicThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
49 nsIFrame* aFrame,
50 StyleAppearance aAppearance,
51 LayoutDeviceIntSize* aResult,
52 bool* aIsOverridable) {
53 if (!IsWidgetScrollbarPart(aAppearance)) {
54 return nsNativeBasicTheme::GetMinimumWidgetSize(
55 aPresContext, aFrame, aAppearance, aResult, aIsOverridable);
56 }
57
58 DPIRatio dpiRatio = GetDPIRatioForScrollbarPart(aPresContext);
59 ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
60 auto sizes = GetScrollbarSizes(
61 aPresContext, style->StyleUIReset()->mScrollbarWidth, Overlay::No);
62 MOZ_ASSERT(sizes.mHorizontal == sizes.mVertical);
63 aResult->SizeTo(sizes.mHorizontal, sizes.mHorizontal);
64
65 if (aAppearance == StyleAppearance::ScrollbarHorizontal ||
66 aAppearance == StyleAppearance::ScrollbarVertical ||
67 aAppearance == StyleAppearance::ScrollbarthumbHorizontal ||
68 aAppearance == StyleAppearance::ScrollbarthumbVertical) {
69 CSSCoord thumbSize(
70 StaticPrefs::widget_non_native_theme_gtk_scrollbar_thumb_cross_size());
71 const bool isVertical =
72 aAppearance == StyleAppearance::ScrollbarVertical ||
73 aAppearance == StyleAppearance::ScrollbarthumbVertical;
74 if (isVertical) {
75 aResult->height = thumbSize * dpiRatio;
76 } else {
77 aResult->width = thumbSize * dpiRatio;
78 }
79 }
80
81 *aIsOverridable = true;
82 return NS_OK;
83 }
84
GetParentScrollbarFrame(nsIFrame * aFrame)85 static nsIFrame* GetParentScrollbarFrame(nsIFrame* aFrame) {
86 // Walk our parents to find a scrollbar frame
87 nsIFrame* scrollbarFrame = aFrame;
88 do {
89 if (scrollbarFrame->IsScrollbarFrame()) {
90 break;
91 }
92 } while ((scrollbarFrame = scrollbarFrame->GetParent()));
93
94 // We return null if we can't find a parent scrollbar frame
95 return scrollbarFrame;
96 }
97
IsParentScrollbarHoveredOrActive(nsIFrame * aFrame)98 static bool IsParentScrollbarHoveredOrActive(nsIFrame* aFrame) {
99 nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
100 return scrollbarFrame && scrollbarFrame->GetContent()
101 ->AsElement()
102 ->State()
103 .HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER |
104 NS_EVENT_STATE_ACTIVE);
105 }
106
107 template <typename PaintBackendData>
DoPaintScrollbarThumb(PaintBackendData & aPaintData,const LayoutDeviceRect & aRect,bool aHorizontal,nsIFrame * aFrame,const ComputedStyle & aStyle,const EventStates & aElementState,const EventStates & aDocumentState,UseSystemColors aUseSystemColors,DPIRatio aDpiRatio)108 bool nsNativeBasicThemeGTK::DoPaintScrollbarThumb(
109 PaintBackendData& aPaintData, const LayoutDeviceRect& aRect,
110 bool aHorizontal, nsIFrame* aFrame, const ComputedStyle& aStyle,
111 const EventStates& aElementState, const EventStates& aDocumentState,
112 UseSystemColors aUseSystemColors, DPIRatio aDpiRatio) {
113 sRGBColor thumbColor = ComputeScrollbarThumbColor(
114 aFrame, aStyle, aElementState, aDocumentState, aUseSystemColors);
115
116 LayoutDeviceRect thumbRect(aRect);
117
118 if (sOverlayScrollbars && !IsParentScrollbarHoveredOrActive(aFrame)) {
119 if (aHorizontal) {
120 thumbRect.height *= 0.5;
121 thumbRect.y += thumbRect.height;
122 } else {
123 thumbRect.width *= 0.5;
124 if (aFrame->GetWritingMode().IsPhysicalLTR()) {
125 thumbRect.x += thumbRect.width;
126 }
127 }
128 }
129
130 {
131 float factor = std::max(
132 0.0f,
133 1.0f - StaticPrefs::widget_non_native_theme_gtk_scrollbar_thumb_size());
134 thumbRect.Deflate((aHorizontal ? thumbRect.height : thumbRect.width) *
135 factor);
136 }
137
138 LayoutDeviceCoord radius =
139 StaticPrefs::widget_non_native_theme_gtk_scrollbar_round_thumb()
140 ? (aHorizontal ? thumbRect.height : thumbRect.width) / 2.0f
141 : 0.0f;
142
143 PaintRoundedRectWithRadius(aPaintData, thumbRect, thumbColor, sRGBColor(), 0,
144 radius / aDpiRatio, aDpiRatio);
145 return true;
146 }
147
PaintScrollbarThumb(DrawTarget & aDrawTarget,const LayoutDeviceRect & aRect,bool aHorizontal,nsIFrame * aFrame,const ComputedStyle & aStyle,const EventStates & aElementState,const EventStates & aDocumentState,UseSystemColors aUseSystemColors,DPIRatio aDpiRatio)148 bool nsNativeBasicThemeGTK::PaintScrollbarThumb(
149 DrawTarget& aDrawTarget, const LayoutDeviceRect& aRect, bool aHorizontal,
150 nsIFrame* aFrame, const ComputedStyle& aStyle,
151 const EventStates& aElementState, const EventStates& aDocumentState,
152 UseSystemColors aUseSystemColors, DPIRatio aDpiRatio) {
153 return DoPaintScrollbarThumb(aDrawTarget, aRect, aHorizontal, aFrame, aStyle,
154 aElementState, aDocumentState, aUseSystemColors,
155 aDpiRatio);
156 }
157
PaintScrollbarThumb(WebRenderBackendData & aWrData,const LayoutDeviceRect & aRect,bool aHorizontal,nsIFrame * aFrame,const ComputedStyle & aStyle,const EventStates & aElementState,const EventStates & aDocumentState,UseSystemColors aUseSystemColors,DPIRatio aDpiRatio)158 bool nsNativeBasicThemeGTK::PaintScrollbarThumb(
159 WebRenderBackendData& aWrData, const LayoutDeviceRect& aRect,
160 bool aHorizontal, nsIFrame* aFrame, const ComputedStyle& aStyle,
161 const EventStates& aElementState, const EventStates& aDocumentState,
162 UseSystemColors aUseSystemColors, DPIRatio aDpiRatio) {
163 return DoPaintScrollbarThumb(aWrData, aRect, aHorizontal, aFrame, aStyle,
164 aElementState, aDocumentState, aUseSystemColors,
165 aDpiRatio);
166 }
167