Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Restore support for native styled scrollbars. (external patch) #3294

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 264 additions & 3 deletions widget/windows/nsNativeThemeWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "nsWindow.h"
#include "prinrval.h"
#include "WinUtils.h"
#include "ScrollbarDrawingWin.h"

using namespace mozilla;
using namespace mozilla::gfx;
Expand Down Expand Up @@ -68,8 +69,11 @@ nsNativeThemeWin::~nsNativeThemeWin() { nsUXThemeData::Invalidate(); }
auto nsNativeThemeWin::IsWidgetNonNative(nsIFrame* aFrame,
StyleAppearance aAppearance)
-> NonNative {
if (IsWidgetScrollbarPart(aAppearance) ||
aAppearance == StyleAppearance::FocusOutline) {
if (IsWidgetScrollbarPart(aAppearance)) {
return NonNative::No;
}

if (aAppearance == StyleAppearance::FocusOutline) {
return NonNative::Always;
}

Expand Down Expand Up @@ -718,6 +722,16 @@ mozilla::Maybe<nsUXThemeClass> nsNativeThemeWin::GetThemeClass(
case StyleAppearance::Tabpanel:
case StyleAppearance::Tabpanels:
return Some(eUXTab);
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::Scrollcorner:
return Some(eUXScrollbar);
case StyleAppearance::Range:
case StyleAppearance::RangeThumb:
return Some(eUXTrackbar);
Expand Down Expand Up @@ -967,6 +981,66 @@ nsresult nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame,
aState = TS_NORMAL;
return NS_OK;
}
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight: {
aPart = SP_BUTTON;
aState = (int(aAppearance) - int(StyleAppearance::ScrollbarbuttonUp)) * 4;
ElementState eventState = GetContentState(aFrame, aAppearance);
if (!aFrame)
aState += TS_NORMAL;
else if (eventState.HasState(ElementState::DISABLED))
aState += TS_DISABLED;
else {
nsIFrame* parent = aFrame->GetParent();
ElementState parentState = GetContentState(
parent, parent->StyleDisplay()->EffectiveAppearance());
if (eventState.HasAllStates(ElementState::HOVER | ElementState::ACTIVE))
aState += TS_ACTIVE;
else if (eventState.HasState(ElementState::HOVER))
aState += TS_HOVER;
else if (parentState.HasState(ElementState::HOVER))
aState =
(int(aAppearance) - int(StyleAppearance::ScrollbarbuttonUp)) +
SP_BUTTON_IMPLICIT_HOVER_BASE;
else
aState += TS_NORMAL;
}
return NS_OK;
}
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarVertical: {
aPart = (aAppearance == StyleAppearance::ScrollbarHorizontal)
? SP_TRACKSTARTHOR
: SP_TRACKSTARTVERT;
aState = TS_NORMAL;
return NS_OK;
}
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarthumbVertical: {
aPart = (aAppearance == StyleAppearance::ScrollbarthumbHorizontal)
? SP_THUMBHOR
: SP_THUMBVERT;
ElementState eventState = GetContentState(aFrame, aAppearance);
if (!aFrame)
aState = TS_NORMAL;
else if (eventState.HasState(ElementState::DISABLED))
aState = TS_DISABLED;
else {
if (eventState.HasState(
ElementState::ACTIVE)) // Hover is not also a requirement for
// the thumb, since the drag is not
// canceled when you move outside the
// thumb.
aState = TS_ACTIVE;
else if (eventState.HasState(ElementState::HOVER))
aState = TS_HOVER;
else
aState = TS_NORMAL;
}
return NS_OK;
}
case StyleAppearance::Range: {
if (IsRangeHorizontal(aFrame)) {
aPart = TKP_TRACK;
Expand Down Expand Up @@ -1004,6 +1078,11 @@ nsresult nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame,
}
return NS_OK;
}
case StyleAppearance::Scrollcorner: {
aState = 0;
aPart = RP_BACKGROUND;
return NS_OK;
}
case StyleAppearance::SpinnerUpbutton:
case StyleAppearance::SpinnerDownbutton: {
aPart = (aAppearance == StyleAppearance::SpinnerUpbutton) ? SPNP_UP
Expand Down Expand Up @@ -1696,6 +1775,26 @@ nsNativeThemeWin::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
widgetRect.bottom = widgetRect.top + TB_SEPARATOR_HEIGHT;
DrawThemeEdge(theme, hdc, RP_BAND, 0, &widgetRect, EDGE_ETCHED, BF_TOP,
nullptr);
} else if (aAppearance == StyleAppearance::ScrollbarthumbHorizontal ||
aAppearance == StyleAppearance::ScrollbarthumbVertical) {
// Draw the decorative gripper for the scrollbar thumb button, if it fits

SIZE gripSize;
MARGINS thumbMgns;
int gripPart = (aAppearance == StyleAppearance::ScrollbarthumbHorizontal)
? SP_GRIPPERHOR
: SP_GRIPPERVERT;

if (GetThemePartSize(theme, hdc, gripPart, state, nullptr, TS_TRUE,
&gripSize) == S_OK &&
GetThemeMargins(theme, hdc, part, state, TMT_CONTENTMARGINS, nullptr,
&thumbMgns) == S_OK &&
gripSize.cx + thumbMgns.cxLeftWidth + thumbMgns.cxRightWidth <=
widgetRect.right - widgetRect.left &&
gripSize.cy + thumbMgns.cyTopHeight + thumbMgns.cyBottomHeight <=
widgetRect.bottom - widgetRect.top) {
DrawThemeBackground(theme, hdc, gripPart, state, &widgetRect, &clipRect);
}
}

nativeDrawing.EndNativeDrawing();
Expand Down Expand Up @@ -1745,7 +1844,11 @@ LayoutDeviceIntMargin nsNativeThemeWin::GetWidgetBorder(
if (!themeClass.isNothing()) {
theme = nsUXThemeData::GetTheme(themeClass.value());
}
if (!theme) {

// Classic scrollbar thumbs require classic borders. The theme procedure will
// break horizontal scrollbar thumbs otherwise.
if (aAppearance == StyleAppearance::ScrollbarthumbVertical ||
aAppearance == StyleAppearance::ScrollbarthumbHorizontal || !theme) {
result = ClassicGetWidgetBorder(aContext, aFrame, aAppearance);
ScaleForFrameDPI(&result, aFrame);
return result;
Expand All @@ -1757,6 +1860,9 @@ LayoutDeviceIntMargin nsNativeThemeWin::GetWidgetBorder(
aAppearance == StyleAppearance::MozWinCommunicationsToolbox ||
aAppearance == StyleAppearance::MozWinBrowsertabbarToolbox ||
aAppearance == StyleAppearance::Tabpanel ||
aAppearance == StyleAppearance::ScrollbarHorizontal ||
aAppearance == StyleAppearance::ScrollbarVertical ||
aAppearance == StyleAppearance::Scrollcorner ||
aAppearance == StyleAppearance::Menuitem ||
aAppearance == StyleAppearance::Checkmenuitem ||
aAppearance == StyleAppearance::Radiomenuitem ||
Expand Down Expand Up @@ -2051,6 +2157,14 @@ LayoutDeviceIntSize nsNativeThemeWin::GetMinimumWidgetSize(
// Windows appears to always use metrics when drawing standard scrollbars)
THEMESIZE sizeReq = TS_TRUE; // Best-fit size
switch (aAppearance) {
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::MozMenulistArrowButton: {
auto result = ClassicGetMinimumWidgetSize(aFrame, aAppearance);
ScaleForFrameDPI(&result, aFrame);
Expand Down Expand Up @@ -2095,6 +2209,17 @@ LayoutDeviceIntSize nsNativeThemeWin::GetMinimumWidgetSize(
return result;
}

case StyleAppearance::Scrollcorner: {
if (nsLookAndFeel::GetInt(nsLookAndFeel::IntID::UseOverlayScrollbars) !=
0) {
LayoutDeviceIntSize result(::GetSystemMetrics(SM_CXHSCROLL),
::GetSystemMetrics(SM_CYVSCROLL));
ScaleForFrameDPI(&result, aFrame);
return result;
}
break;
}

case StyleAppearance::Separator: {
// that's 2px left margin, 2px right margin and 2px separator
// (the margin is drawn as part of the separator, though)
Expand Down Expand Up @@ -2400,6 +2525,15 @@ bool nsNativeThemeWin::ClassicThemeSupportsWidget(nsIFrame* aFrame,
case StyleAppearance::Range:
case StyleAppearance::RangeThumb:
case StyleAppearance::Groupbox:
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::Scrollcorner:
case StyleAppearance::Menulist:
case StyleAppearance::MenulistButton:
case StyleAppearance::MozMenulistArrowButton:
Expand Down Expand Up @@ -2526,6 +2660,25 @@ LayoutDeviceIntSize nsNativeThemeWin::ClassicGetMinimumWidgetSize(
result.width = ::GetSystemMetrics(SM_CXVSCROLL);
result.height = 8; // No good metrics available for this
break;
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
result.width = ::GetSystemMetrics(SM_CXVSCROLL);
result.height = ::GetSystemMetrics(SM_CYVSCROLL);
break;
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight:
// For scrollbar-width:thin, we don't display the buttons.
if (!ScrollbarDrawing::IsScrollbarWidthThin(aFrame)) {
result.width = ::GetSystemMetrics(SM_CXHSCROLL);
result.height = ::GetSystemMetrics(SM_CYHSCROLL);
}
break;
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbarHorizontal:
// Sizing code needed after removal of XUL layout (around ESR 115)
result.width = ::GetSystemMetrics(SM_CYHSCROLL);
result.height = ::GetSystemMetrics(SM_CYHSCROLL);
break;
case StyleAppearance::RangeThumb: {
if (IsRangeHorizontal(aFrame)) {
result.width = 12;
Expand All @@ -2536,6 +2689,35 @@ LayoutDeviceIntSize nsNativeThemeWin::ClassicGetMinimumWidgetSize(
}
break;
}
case StyleAppearance::ScrollbarthumbVertical:
result.width = ::GetSystemMetrics(SM_CXVSCROLL);
result.height = ::GetSystemMetrics(SM_CYVTHUMB);
// Without theming, divide the thumb size by two in order to look more
// native
if (!GetTheme(aAppearance)) {
result.height >>= 1;
}
// If scrollbar-width is thin, divide the thickness by two to make
// it look more compact.
if (ScrollbarDrawing::IsScrollbarWidthThin(aFrame)) {
result.width >>= 1;
}
break;
case StyleAppearance::ScrollbarthumbHorizontal:
result.width = ::GetSystemMetrics(SM_CXHTHUMB);
result.height = ::GetSystemMetrics(SM_CYHSCROLL);
// Without theming, divide the thumb size by two in order to look more
// native
if (TRUE || !GetTheme(aAppearance)) {
result.width >>= 1;
}
// If scrollbar-width is thin, divide the thickness by two to make
// it look more compact.
if (ScrollbarDrawing::IsScrollbarWidthThin(aFrame)) {
result.height >>= 1;
}

break;
case StyleAppearance::MozMenulistArrowButton:
result.width = ::GetSystemMetrics(SM_CXVSCROLL);
break;
Expand Down Expand Up @@ -2732,6 +2914,11 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(
case StyleAppearance::MenulistButton:
case StyleAppearance::Range:
case StyleAppearance::RangeThumb:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::Scrollcorner:
case StyleAppearance::Progresschunk:
case StyleAppearance::ProgressBar:
case StyleAppearance::Tab:
Expand Down Expand Up @@ -2777,6 +2964,39 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(

return NS_OK;
}
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight: {
ElementState contentState = GetContentState(aFrame, aAppearance);

aPart = DFC_SCROLL;
switch (aAppearance) {
case StyleAppearance::ScrollbarbuttonUp:
aState = DFCS_SCROLLUP;
break;
case StyleAppearance::ScrollbarbuttonDown:
aState = DFCS_SCROLLDOWN;
break;
case StyleAppearance::ScrollbarbuttonLeft:
aState = DFCS_SCROLLLEFT;
break;
case StyleAppearance::ScrollbarbuttonRight:
aState = DFCS_SCROLLRIGHT;
break;
default:
break;
}

if (contentState.HasState(ElementState::DISABLED)) {
aState |= DFCS_INACTIVE;
} else if (contentState.HasAllStates(ElementState::HOVER |
ElementState::ACTIVE)) {
aState |= DFCS_PUSHED | DFCS_FLAT;
}

return NS_OK;
}
case StyleAppearance::SpinnerUpbutton:
case StyleAppearance::SpinnerDownbutton: {
ElementState contentState = GetContentState(aFrame, aAppearance);
Expand Down Expand Up @@ -3055,6 +3275,10 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(
// Draw controls supported by DrawFrameControl
case StyleAppearance::Checkbox:
case StyleAppearance::Radio:
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight:
case StyleAppearance::SpinnerUpbutton:
case StyleAppearance::SpinnerDownbutton:
case StyleAppearance::MozMenulistArrowButton: {
Expand Down Expand Up @@ -3110,6 +3334,12 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(
::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_BTNFACE + 1));
break;
}
// Draw scrollbar thumb
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarthumbHorizontal:
::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);

break;
case StyleAppearance::RangeThumb: {
ElementState elementState = GetContentState(aFrame, aAppearance);

Expand Down Expand Up @@ -3147,6 +3377,37 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(

break;
}
// Draw scrollbar track background
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbarHorizontal: {
// Windows fills in the scrollbar track differently
// depending on whether these are equal
DWORD color3D, colorScrollbar, colorWindow;

color3D = ::GetSysColor(COLOR_3DFACE);
colorWindow = ::GetSysColor(COLOR_WINDOW);
colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);

if ((color3D != colorScrollbar) && (colorWindow != colorScrollbar))
// Use solid brush
::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_SCROLLBAR + 1));
else {
DrawCheckedRect(hdc, widgetRect, COLOR_3DHILIGHT, COLOR_3DFACE,
(HBRUSH)COLOR_SCROLLBAR + 1);
}
// XXX should invert the part of the track being clicked here
// but the track is never :active

break;
}
case StyleAppearance::Scrollcorner: {
::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_SCROLLBAR + 1));

// Mozilla added this in 2018
// (https://github.com/mozilla/gecko-dev/blob/7038d5f94456dcb558f7c7f6fe66d913070001c5/widget/windows/nsNativeThemeWin.cpp#L3793-L3795)
// and never fixed this fallthrough.
break;
}
case StyleAppearance::Progresschunk: {
nsIFrame* stateFrame = aFrame->GetParent();
ElementState elementState = GetContentState(stateFrame, aAppearance);
Expand Down
Loading