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