Bug 1689253 - Add a more sensible scrollbar size API to nsITheme, and use it to replace ScrollbarNonDisappearing. r=spohl

There's no reason we should need an scrollbar box to query the size of a
scrollbar. I plan to use this in the following patch to make the size of a
resizer not vary depending on whether the container has scrollbars or not,
which is what ultimately causes the reftest failure.

Differential Revision: https://phabricator.services.mozilla.com/D103302
This commit is contained in:
Emilio Cobos Álvarez 2021-01-28 22:11:54 +00:00
Родитель 5d69f38941
Коммит 4b4ff83478
24 изменённых файлов: 298 добавлений и 181 удалений

Просмотреть файл

@ -27,6 +27,7 @@ class nsIWidget;
namespace mozilla {
class ComputedStyle;
enum class StyleAppearance : uint8_t;
enum class StyleScrollbarWidth : uint8_t;
namespace layers {
class StackingContextHelper;
class RenderRootStateManager;
@ -59,7 +60,11 @@ class IpcResourceUpdateQueue;
class nsITheme : public nsISupports {
protected:
using LayoutDeviceIntMargin = mozilla::LayoutDeviceIntMargin;
using LayoutDeviceIntSize = mozilla::LayoutDeviceIntSize;
using LayoutDeviceIntCoord = mozilla::LayoutDeviceIntCoord;
using StyleAppearance = mozilla::StyleAppearance;
using StyleScrollbarWidth = mozilla::StyleScrollbarWidth;
using ComputedStyle = mozilla::ComputedStyle;
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITHEME_IID)
@ -92,6 +97,19 @@ class nsITheme : public nsISupports {
return false;
}
/**
* Returns the minimum widths of a scrollbar for a given style, that is, the
* minimum width for a vertical scrollbar, and the minimum height of a
* horizontal scrollbar.
*/
enum class Overlay { No, Yes };
struct ScrollbarSizes {
LayoutDeviceIntCoord mVertical;
LayoutDeviceIntCoord mHorizontal;
};
virtual ScrollbarSizes GetScrollbarSizes(
nsPresContext*, StyleScrollbarWidth, Overlay) = 0;
/**
* Return the border for the widget, in device pixels.
*/

Просмотреть файл

@ -933,6 +933,18 @@ nsIFrame* nsLayoutUtils::GetStyleFrame(const nsIContent* aContent) {
return nsLayoutUtils::GetStyleFrame(frame);
}
CSSIntCoord nsLayoutUtils::UnthemedScrollbarSize(StyleScrollbarWidth aWidth) {
switch (aWidth) {
case StyleScrollbarWidth::Auto:
return 12;
case StyleScrollbarWidth::Thin:
return 6;
case StyleScrollbarWidth::None:
return 0;
}
return 0;
}
/* static */
nsIFrame* nsLayoutUtils::GetPrimaryFrameFromStyleFrame(nsIFrame* aStyleFrame) {
nsIFrame* parent = aStyleFrame->GetParent();

Просмотреть файл

@ -83,6 +83,7 @@ class EffectSet;
struct ActiveScrolledRoot;
enum class ScrollOrigin : uint8_t;
enum class StyleImageOrientation : uint8_t;
enum class StyleScrollbarWidth : uint8_t;
struct OverflowAreas;
namespace dom {
class CanvasRenderingContext2D;
@ -312,6 +313,11 @@ class nsLayoutUtils {
*/
static nsIFrame* GetStyleFrame(const nsIContent* aContent);
/**
* Returns the placeholder size for when the scrollbar is unthemed.
*/
static mozilla::CSSIntCoord UnthemedScrollbarSize(mozilla::StyleScrollbarWidth);
/**
* The inverse of GetStyleFrame. Returns |aStyleFrame| unless it is an inner
* table frame, in which case the table wrapper frame is returned.

Просмотреть файл

@ -1501,17 +1501,12 @@ nscoord ScrollFrameHelper::GetNondisappearingScrollbarWidth(
// we're using e.g. scrollbar-width: thin, or overlay scrollbars. That's why
// we use ScrollbarNonDisappearing.
nsIFrame* box = verticalWM ? mHScrollbarBox : mVScrollbarBox;
nsITheme* theme = aState->PresContext()->Theme();
if (box &&
theme->ThemeSupportsWidget(aState->PresContext(), box,
StyleAppearance::ScrollbarNonDisappearing)) {
LayoutDeviceIntSize size;
bool canOverride = true;
theme->GetMinimumWidgetSize(aState->PresContext(), box,
StyleAppearance::ScrollbarNonDisappearing,
&size, &canOverride);
return aState->PresContext()->DevPixelsToAppUnits(verticalWM ? size.height
: size.width);
if (box) {
auto sizes = aState->PresContext()->Theme()->GetScrollbarSizes(
aState->PresContext(), StyleScrollbarWidth::Auto,
nsITheme::Overlay::No);
return aState->PresContext()->DevPixelsToAppUnits(
verticalWM ? sizes.mHorizontal : sizes.mVertical);
}
nsMargin sizes(GetDesiredScrollbarSizes(aState));

Просмотреть файл

@ -374,22 +374,6 @@ bool nsIFrame::AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidthSet,
return (aWidthSet && aHeightSet);
}
// This returns the scrollbar width we want to use when either native
// theme is disabled, or the native theme claims that it doesn't support
// scrollbar.
static nscoord GetScrollbarWidthNoTheme(nsIFrame* aBox) {
ComputedStyle* scrollbarStyle = nsLayoutUtils::StyleForScrollbar(aBox);
switch (scrollbarStyle->StyleUIReset()->mScrollbarWidth) {
default:
case StyleScrollbarWidth::Auto:
return 12 * AppUnitsPerCSSPixel();
case StyleScrollbarWidth::Thin:
return 6 * AppUnitsPerCSSPixel();
case StyleScrollbarWidth::None:
return 0;
}
}
bool nsIFrame::AddXULMinSize(nsIFrame* aBox, nsSize& aSize, bool& aWidthSet,
bool& aHeightSet) {
aWidthSet = false;
@ -418,13 +402,20 @@ bool nsIFrame::AddXULMinSize(nsIFrame* aBox, nsSize& aSize, bool& aWidthSet,
} else {
switch (appearance) {
case StyleAppearance::ScrollbarVertical:
aSize.width = GetScrollbarWidthNoTheme(aBox);
aWidthSet = true;
break;
case StyleAppearance::ScrollbarHorizontal:
aSize.height = GetScrollbarWidthNoTheme(aBox);
aHeightSet = true;
case StyleAppearance::ScrollbarHorizontal: {
ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aBox);
auto sizes = theme->GetScrollbarSizes(
pc, style->StyleUIReset()->mScrollbarWidth,
nsITheme::Overlay::No);
if (appearance == StyleAppearance::ScrollbarVertical) {
aSize.width = sizes.mVertical;
aWidthSet = true;
} else {
aSize.height = sizes.mHorizontal;
aHeightSet = true;
}
break;
}
default:
break;
}

Просмотреть файл

@ -1835,10 +1835,6 @@ pub enum Appearance {
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
MozMacVibrantTitlebarLight,
/// A non-disappearing scrollbar.
#[css(skip)]
ScrollbarNonDisappearing,
/// A themed focus outline (for outline:auto).
///
/// This isn't exposed to CSS at all, just here for convenience.

Просмотреть файл

@ -42,9 +42,27 @@ static bool IsParentScrollbarRolledOver(nsIFrame* aFrame) {
.HasState(NS_EVENT_STATE_HOVER);
}
CSSIntCoord ScrollbarDrawingMac::GetScrollbarSize(StyleScrollbarWidth aWidth,
bool aOverlay) {
bool isSmall = aWidth == StyleScrollbarWidth::Thin;
if (aOverlay) {
return isSmall ? 14 : 16;
}
return isSmall ? 11 : 15;
}
LayoutDeviceIntCoord ScrollbarDrawingMac::GetScrollbarSize(
StyleScrollbarWidth aWidth, bool aOverlay, float aDpiRatio) {
CSSIntCoord size = GetScrollbarSize(aWidth, aOverlay);
if (aDpiRatio >= 2.0f) {
return int32_t(size) * 2;
}
return int32_t(size);
}
LayoutDeviceIntSize ScrollbarDrawingMac::GetMinimumWidgetSize(
StyleAppearance aAppearance, nsIFrame* aFrame, float aDpiRatio) {
auto fn = [](StyleAppearance aAppearance, nsIFrame* aFrame) -> IntSize {
auto minSize = [&] {
switch (aAppearance) {
case StyleAppearance::ScrollbarthumbHorizontal:
return IntSize{26, 0};
@ -55,23 +73,17 @@ LayoutDeviceIntSize ScrollbarDrawingMac::GetMinimumWidgetSize(
case StyleAppearance::ScrollbartrackVertical:
case StyleAppearance::ScrollbartrackHorizontal: {
ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
bool isSmall =
style->StyleUIReset()->mScrollbarWidth == StyleScrollbarWidth::Thin;
if (nsLookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) !=
0) {
if (isSmall) {
return IntSize{14, 14};
}
return IntSize{16, 16};
}
if (isSmall) {
return IntSize{11, 11};
}
return IntSize{15, 15};
auto scrollbarWidth = style->StyleUIReset()->mScrollbarWidth;
auto size = GetScrollbarSize(
scrollbarWidth,
LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars));
return IntSize{size, size};
}
case StyleAppearance::MozMenulistArrowButton: {
auto size =
GetScrollbarSize(StyleScrollbarWidth::Auto, /* aOverlay = */ false);
return IntSize{size, size};
}
case StyleAppearance::MozMenulistArrowButton:
case StyleAppearance::ScrollbarNonDisappearing:
return IntSize{15, 15};
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
return IntSize{15, 16};
@ -81,9 +93,8 @@ LayoutDeviceIntSize ScrollbarDrawingMac::GetMinimumWidgetSize(
default:
return IntSize{};
}
};
}();
IntSize minSize = fn(aAppearance, aFrame);
if (aDpiRatio >= 2.0f) {
return LayoutDeviceIntSize{minSize.width * 2, minSize.height * 2};
}

Просмотреть файл

@ -33,6 +33,10 @@ struct ScrollbarParams {
class ScrollbarDrawingMac final {
public:
static CSSIntCoord GetScrollbarSize(StyleScrollbarWidth, bool aOverlay);
static LayoutDeviceIntCoord GetScrollbarSize(StyleScrollbarWidth,
bool aOverlay, float aDpiRatio);
static LayoutDeviceIntSize GetMinimumWidgetSize(StyleAppearance aAppearance,
nsIFrame* aFrame,
float aDpiRatio);

Просмотреть файл

@ -59,10 +59,13 @@ static const CSSIntCoord kMinimumAndroidWidgetSize = 17;
NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeAndroid, nsNativeTheme, nsITheme)
static uint32_t GetDPIRatio(nsPresContext* aPresContext) {
return AppUnitsPerCSSPixel() /
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
}
static uint32_t GetDPIRatio(nsIFrame* aFrame) {
return AppUnitsPerCSSPixel() / aFrame->PresContext()
->DeviceContext()
->AppUnitsPerDevPixelAtUnitFullZoom();
return GetDPIRatio(aFrame->PresContext());
}
static bool IsDateTimeResetButton(nsIFrame* aFrame) {
@ -798,6 +801,12 @@ nsNativeThemeAndroid::GetMinimumWidgetSize(nsPresContext* aPresContext,
return NS_OK;
}
auto nsNativeThemeAndroid::GetScrollbarSizes(
nsPresContext* aPresContext, StyleScrollbarWidth aWidth, Overlay aOverlay) -> ScrollbarSizes {
int32_t size = kMinimumAndroidWidgetSize * int32_t(GetDPIRatio(aPresContext));
return {size, size};
}
nsITheme::Transparency nsNativeThemeAndroid::GetWidgetTransparency(
nsIFrame* aFrame, StyleAppearance aAppearance) {
return eUnknownTransparency;
@ -872,7 +881,6 @@ bool nsNativeThemeAndroid::ThemeSupportsWidget(nsPresContext* aPresContext,
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarNonDisappearing:
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::Scrollcorner:
case StyleAppearance::Button:

Просмотреть файл

@ -58,6 +58,8 @@ class nsNativeThemeAndroid : private nsNativeTheme, public nsITheme {
bool WidgetIsContainer(StyleAppearance aAppearance) override;
bool ThemeDrawsFocusForWidget(StyleAppearance aAppearance) override;
bool ThemeNeedsComboboxDropmarker() override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) override;
protected:
virtual ~nsNativeThemeAndroid() = default;

Просмотреть файл

@ -5,6 +5,7 @@
#include "nsNativeBasicThemeCocoa.h"
#include "mozilla/gfx/Helpers.h"
#include "mozilla/LookAndFeel.h"
already_AddRefed<nsITheme> do_GetBasicNativeThemeDoNotUseDirectly() {
static mozilla::StaticRefPtr<nsITheme> gInstance;
@ -19,33 +20,28 @@ NS_IMETHODIMP
nsNativeBasicThemeCocoa::GetMinimumWidgetSize(
nsPresContext* aPresContext, nsIFrame* aFrame, StyleAppearance aAppearance,
mozilla::LayoutDeviceIntSize* aResult, bool* aIsOverridable) {
DPIRatio dpiRatio = GetDPIRatio(aFrame, aAppearance);
switch (aAppearance) {
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbartrackVertical:
case StyleAppearance::ScrollbartrackHorizontal:
case StyleAppearance::ScrollbarbuttonUp:
case StyleAppearance::ScrollbarbuttonDown:
case StyleAppearance::ScrollbarbuttonLeft:
case StyleAppearance::ScrollbarbuttonRight: {
*aIsOverridable = false;
*aResult = ScrollbarDrawingMac::GetMinimumWidgetSize(aAppearance, aFrame,
dpiRatio.scale);
break;
}
default:
return nsNativeBasicTheme::GetMinimumWidgetSize(
aPresContext, aFrame, aAppearance, aResult, aIsOverridable);
if (!IsWidgetScrollbarPart(aAppearance)) {
return nsNativeBasicTheme::GetMinimumWidgetSize(
aPresContext, aFrame, aAppearance, aResult, aIsOverridable);
}
DPIRatio dpiRatio = GetDPIRatioForScrollbarPart(aPresContext);
*aIsOverridable = false;
*aResult = ScrollbarDrawingMac::GetMinimumWidgetSize(aAppearance, aFrame,
dpiRatio.scale);
return NS_OK;
}
auto nsNativeBasicThemeCocoa::GetScrollbarSizes(nsPresContext* aPresContext,
StyleScrollbarWidth aWidth,
Overlay aOverlay)
-> ScrollbarSizes {
auto size = ScrollbarDrawingMac::GetScrollbarSize(
aWidth, aOverlay == Overlay::Yes,
GetDPIRatioForScrollbarPart(aPresContext).scale);
return {size, size};
}
void nsNativeBasicThemeCocoa::PaintScrollbarThumb(
DrawTarget* aDrawTarget, const LayoutDeviceRect& aRect, bool aHorizontal,
nsIFrame* aFrame, const ComputedStyle& aStyle,

Просмотреть файл

@ -23,6 +23,9 @@ class nsNativeBasicThemeCocoa : public nsNativeBasicTheme {
mozilla::LayoutDeviceIntSize* aResult,
bool* aIsOverridable) override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) override;
void PaintScrollbarThumb(DrawTarget* aDrawTarget,
const LayoutDeviceRect& aRect, bool aHorizontal,
nsIFrame* aFrame, const ComputedStyle& aStyle,

Просмотреть файл

@ -371,6 +371,7 @@ class nsNativeThemeCocoa : private nsNativeTheme, public nsITheme {
virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance, nsRect* aOverflowRect) override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth, Overlay) override;
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
mozilla::LayoutDeviceIntSize* aResult,

Просмотреть файл

@ -3388,6 +3388,14 @@ bool nsNativeThemeCocoa::GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame*
return false;
}
auto nsNativeThemeCocoa::GetScrollbarSizes(nsPresContext* aPresContext, StyleScrollbarWidth aWidth, Overlay aOverlay) -> ScrollbarSizes {
auto size = ScrollbarDrawingMac::GetScrollbarSize(aWidth, aOverlay == Overlay::Yes);
if (IsHiDPIContext(aPresContext->DeviceContext())) {
size *= 2;
}
return {int32_t(size), int32_t(size)};
}
NS_IMETHODIMP
nsNativeThemeCocoa::GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame,
StyleAppearance aAppearance, LayoutDeviceIntSize* aResult,
@ -3548,10 +3556,8 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame*
}
case StyleAppearance::MozMenulistArrowButton:
case StyleAppearance::ScrollbarNonDisappearing: {
*aResult = ScrollbarDrawingMac::GetMinimumWidgetSize(aAppearance, aFrame, 1.0f);
break;
}
case StyleAppearance::Resizer: {
HIThemeGrowBoxDrawInfo drawInfo;
@ -3728,7 +3734,6 @@ bool nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFra
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbartrackVertical:
case StyleAppearance::ScrollbartrackHorizontal:
case StyleAppearance::ScrollbarNonDisappearing:
return !IsWidgetStyled(aPresContext, aFrame, aAppearance);
case StyleAppearance::Scrollcorner:

Просмотреть файл

@ -35,41 +35,35 @@ nsITheme::Transparency nsNativeBasicThemeGTK::GetWidgetTransparency(
}
}
auto nsNativeBasicThemeGTK::GetScrollbarSizes(nsPresContext* aPresContext,
StyleScrollbarWidth aWidth,
Overlay) -> ScrollbarSizes {
DPIRatio dpiRatio = GetDPIRatioForScrollbarPart(aPresContext);
CSSCoord size = aWidth == StyleScrollbarWidth::Thin
? kGtkMinimumThinScrollbarSize
: kGtkMinimumScrollbarSize;
LayoutDeviceIntCoord s = (size * dpiRatio).Truncated();
return {s, s};
}
NS_IMETHODIMP
nsNativeBasicThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
nsIFrame* aFrame,
StyleAppearance aAppearance,
LayoutDeviceIntSize* aResult,
bool* aIsOverridable) {
DPIRatio dpiRatio = GetDPIRatio(aFrame, aAppearance);
switch (aAppearance) {
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::ScrollbartrackHorizontal:
case StyleAppearance::ScrollbartrackVertical:
case StyleAppearance::Scrollcorner: {
ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
if (style->StyleUIReset()->mScrollbarWidth == StyleScrollbarWidth::Thin) {
aResult->SizeTo(kGtkMinimumThinScrollbarSize * dpiRatio,
kGtkMinimumThinScrollbarSize * dpiRatio);
} else {
aResult->SizeTo(kGtkMinimumScrollbarSize * dpiRatio,
kGtkMinimumScrollbarSize * dpiRatio);
}
break;
}
default:
return nsNativeBasicTheme::GetMinimumWidgetSize(
aPresContext, aFrame, aAppearance, aResult, aIsOverridable);
if (!IsWidgetScrollbarPart(aAppearance)) {
return nsNativeBasicTheme::GetMinimumWidgetSize(
aPresContext, aFrame, aAppearance, aResult, aIsOverridable);
}
DPIRatio dpiRatio = GetDPIRatioForScrollbarPart(aPresContext);
ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
auto sizes = GetScrollbarSizes(
aPresContext, style->StyleUIReset()->mScrollbarWidth, Overlay::No);
MOZ_ASSERT(sizes.mHorizontal == sizes.mVertical);
aResult->SizeTo(sizes.mHorizontal, sizes.mHorizontal);
switch (aAppearance) {
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarthumbHorizontal:

Просмотреть файл

@ -36,6 +36,8 @@ class nsNativeBasicThemeGTK : public nsNativeBasicTheme {
const EventStates& aDocumentState, DPIRatio aDpiRatio,
bool aIsRoot) override;
bool ThemeSupportsScrollbarButtons() override { return false; }
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) override;
protected:
virtual ~nsNativeBasicThemeGTK() = default;

Просмотреть файл

@ -70,13 +70,12 @@ static int gLastGdkError;
// Return scale factor of the monitor where the window is located
// by the most part or layout.css.devPixelsPerPx pref if set to > 0.
static inline gint GetMonitorScaleFactor(nsIFrame* aFrame) {
static inline gint GetMonitorScaleFactor(nsPresContext* aPresContext) {
// When the layout.css.devPixelsPerPx is set the scale can be < 1,
// the real monitor scale cannot go under 1.
double scale = StaticPrefs::layout_css_devPixelsPerPx();
if (scale <= 0) {
nsIWidget* rootWidget = aFrame->PresContext()->GetRootWidget();
if (rootWidget) {
if (nsIWidget* rootWidget = aPresContext->GetRootWidget()) {
// We need to use GetDefaultScale() despite it returns monitor scale
// factor multiplied by font scale factor because it is the only scale
// updated in nsPuppetWidget.
@ -99,6 +98,10 @@ static inline gint GetMonitorScaleFactor(nsIFrame* aFrame) {
return ScreenHelperGTK::GetGTKMonitorScaleFactor();
}
static inline gint GetMonitorScaleFactor(nsIFrame* aFrame) {
return GetMonitorScaleFactor(aFrame->PresContext());
}
nsNativeThemeGTK::nsNativeThemeGTK() {
if (moz_gtk_init() != MOZ_GTK_SUCCESS) {
memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes));
@ -1487,14 +1490,6 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
}
*aIsOverridable = false;
} break;
case StyleAppearance::ScrollbarNonDisappearing: {
const ScrollbarGTKMetrics* verticalMetrics =
GetActiveScrollbarMetrics(GTK_ORIENTATION_VERTICAL);
const ScrollbarGTKMetrics* horizontalMetrics =
GetActiveScrollbarMetrics(GTK_ORIENTATION_HORIZONTAL);
aResult->width = verticalMetrics->size.scrollbar.width;
aResult->height = horizontalMetrics->size.scrollbar.height;
} break;
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarVertical: {
/* While we enforce a minimum size for the thumb, this is ignored
@ -1797,6 +1792,11 @@ nsNativeThemeGTK::ThemeChanged() {
return NS_OK;
}
static bool CanHandleScrollbar(const ComputedStyle& aStyle) {
return !aStyle.StyleUI()->HasCustomScrollbars() &&
aStyle.StyleUIReset()->mScrollbarWidth != StyleScrollbarWidth::Thin;
}
NS_IMETHODIMP_(bool)
nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
nsIFrame* aFrame,
@ -1807,9 +1807,7 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
if (IsWidgetScrollbarPart(aAppearance)) {
ComputedStyle* cs = nsLayoutUtils::StyleForScrollbar(aFrame);
if (cs->StyleUI()->HasCustomScrollbars() ||
// We cannot handle thin scrollbar on GTK+ widget directly as well.
cs->StyleUIReset()->mScrollbarWidth == StyleScrollbarWidth::Thin) {
if (!CanHandleScrollbar(*cs)) {
return false;
}
}
@ -1874,7 +1872,6 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
case StyleAppearance::ScrollbartrackVertical:
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarthumbVertical:
case StyleAppearance::ScrollbarNonDisappearing:
case StyleAppearance::NumberInput:
case StyleAppearance::Textfield:
case StyleAppearance::Textarea:
@ -2003,6 +2000,26 @@ bool nsNativeThemeGTK::WidgetAppearanceDependsOnWindowFocus(
}
}
auto nsNativeThemeGTK::GetScrollbarSizes(nsPresContext* aPresContext,
StyleScrollbarWidth aWidth, Overlay)
-> ScrollbarSizes {
CSSIntCoord vertical;
CSSIntCoord horizontal;
if (aWidth != StyleScrollbarWidth::Thin) {
const ScrollbarGTKMetrics* verticalMetrics =
GetActiveScrollbarMetrics(GTK_ORIENTATION_VERTICAL);
const ScrollbarGTKMetrics* horizontalMetrics =
GetActiveScrollbarMetrics(GTK_ORIENTATION_HORIZONTAL);
vertical = verticalMetrics->size.scrollbar.width;
horizontal = horizontalMetrics->size.scrollbar.height;
} else {
auto unthemed = nsLayoutUtils::UnthemedScrollbarSize(aWidth);
vertical = horizontal = unthemed;
}
auto scale = GetMonitorScaleFactor(aPresContext);
return {int32_t(vertical) * scale, int32_t(horizontal) * scale};
}
already_AddRefed<nsITheme> do_GetNativeThemeDoNotUseDirectly() {
static nsCOMPtr<nsITheme> inst;

Просмотреть файл

@ -45,9 +45,9 @@ class nsNativeThemeGTK final : private nsNativeTheme,
StyleAppearance aAppearance,
LayoutDeviceIntMargin* aResult) override;
virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
nsRect* aOverflowRect) override;
bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
nsRect* aOverflowRect) override;
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
@ -69,13 +69,11 @@ class nsNativeThemeGTK final : private nsNativeTheme,
NS_IMETHOD_(bool)
ThemeDrawsFocusForWidget(StyleAppearance aAppearance) override;
virtual bool ThemeNeedsComboboxDropmarker() override;
virtual Transparency GetWidgetTransparency(
nsIFrame* aFrame, StyleAppearance aAppearance) override;
virtual bool WidgetAppearanceDependsOnWindowFocus(
StyleAppearance aAppearance) override;
bool ThemeNeedsComboboxDropmarker() override;
Transparency GetWidgetTransparency(nsIFrame*, StyleAppearance) override;
bool WidgetAppearanceDependsOnWindowFocus(StyleAppearance) override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) override;
nsNativeThemeGTK();

Просмотреть файл

@ -149,6 +149,14 @@ bool HeadlessThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,
return false;
}
static const int32_t kMinimumScrollbarSize = 10;
// TODO: Should probably deal with scrollbar-width somehow.
auto HeadlessThemeGTK::GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) -> ScrollbarSizes {
return {kMinimumScrollbarSize, kMinimumScrollbarSize};
}
NS_IMETHODIMP
HeadlessThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
nsIFrame* aFrame,
@ -227,10 +235,10 @@ HeadlessThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
break;
case StyleAppearance::ScrollbarHorizontal:
aResult->width = 31;
aResult->height = 10;
aResult->height = kMinimumScrollbarSize;
break;
case StyleAppearance::ScrollbarVertical:
aResult->width = 10;
aResult->width = kMinimumScrollbarSize;
aResult->height = 31;
break;
case StyleAppearance::ScrollbarbuttonUp:

Просмотреть файл

@ -49,7 +49,10 @@ class HeadlessThemeGTK final : private nsNativeTheme, public nsITheme {
NS_IMETHOD_(bool)
ThemeDrawsFocusForWidget(StyleAppearance aAppearance) override;
virtual bool ThemeNeedsComboboxDropmarker() override;
bool ThemeNeedsComboboxDropmarker() override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) override;
protected:
virtual ~HeadlessThemeGTK() = default;

Просмотреть файл

@ -59,16 +59,27 @@ static bool IsScrollbarWidthThin(nsIFrame* aFrame) {
return scrollbarWidth == StyleScrollbarWidth::Thin;
}
/* static */
auto nsNativeBasicTheme::GetDPIRatioForScrollbarPart(nsPresContext* aPc)
-> DPIRatio {
return DPIRatio(float(AppUnitsPerCSSPixel()) /
aPc->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
}
/* static */
auto nsNativeBasicTheme::GetDPIRatio(nsPresContext* aPc,
StyleAppearance aAppearance) -> DPIRatio {
// Widgets react to zoom, except scrollbars.
if (IsWidgetScrollbarPart(aAppearance)) {
return GetDPIRatioForScrollbarPart(aPc);
}
return DPIRatio(float(AppUnitsPerCSSPixel()) / aPc->AppUnitsPerDevPixel());
}
/* static */
auto nsNativeBasicTheme::GetDPIRatio(nsIFrame* aFrame,
StyleAppearance aAppearance) -> DPIRatio {
nsPresContext* pc = aFrame->PresContext();
// Widgets react to zoom, except scrollbars.
nscoord auPerPx =
IsWidgetScrollbarPart(aAppearance)
? pc->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()
: pc->AppUnitsPerDevPixel();
return DPIRatio(float(AppUnitsPerCSSPixel()) / auPerPx);
return GetDPIRatio(aFrame->PresContext(), aAppearance);
}
/* static */
@ -432,8 +443,8 @@ static already_AddRefed<Path> GetFocusStrokePath(
aFocusRect.Inflate(aOffset);
LayoutDeviceRect focusRect(aFocusRect);
// Deflate the rect by half the border width, so that the middle of the stroke
// fills exactly the area we want to fill and not more.
// Deflate the rect by half the border width, so that the middle of the
// stroke fills exactly the area we want to fill and not more.
focusRect.Deflate(aFocusWidth * 0.5f);
return MakePathForRoundedRect(*aDrawTarget, focusRect.ToUnknownRect(), radii);
@ -444,8 +455,8 @@ void nsNativeBasicTheme::PaintRoundedFocusRect(DrawTarget* aDrawTarget,
DPIRatio aDpiRatio,
CSSCoord aRadius,
CSSCoord aOffset) {
// NOTE(emilio): If the widths or offsets here change, make sure to tweak the
// GetWidgetOverflow path for FocusOutline.
// NOTE(emilio): If the widths or offsets here change, make sure to tweak
// the GetWidgetOverflow path for FocusOutline.
auto [innerColor, middleColor, outerColor] = ComputeFocusRectColors();
LayoutDeviceRect focusRect(aRect);
@ -491,8 +502,8 @@ void nsNativeBasicTheme::PaintRoundedRectWithRadius(
const LayoutDeviceCoord borderWidth(SnapBorderWidth(aBorderWidth, aDpiRatio));
LayoutDeviceRect rect(aRect);
// Deflate the rect by half the border width, so that the middle of the stroke
// fills exactly the area we want to fill and not more.
// Deflate the rect by half the border width, so that the middle of the
// stroke fills exactly the area we want to fill and not more.
rect.Deflate(borderWidth * 0.5f);
LayoutDeviceCoord radius(aRadius * aDpiRatio);
@ -505,8 +516,8 @@ void nsNativeBasicTheme::PaintRoundedRectWithRadius(
}
RectCornerRadii radii(radius, radius, radius, radius);
RefPtr<Path> roundedRect = MakePathForRoundedRect(
*aDrawTarget, rect.ToUnknownRect(), radii);
RefPtr<Path> roundedRect =
MakePathForRoundedRect(*aDrawTarget, rect.ToUnknownRect(), radii);
aDrawTarget->Fill(roundedRect, ColorPattern(ToDeviceColor(aBackgroundColor)));
aDrawTarget->Stroke(roundedRect, ColorPattern(ToDeviceColor(aBorderColor)),
@ -779,7 +790,8 @@ void nsNativeBasicTheme::PaintSpinnerButton(nsIFrame* aFrame,
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
auto center = aRect.Center().ToUnknownPoint();
Point p = center + Point(arrowPolygonX[0] * scaleX, arrowPolygonY[0] * scaleY);
Point p =
center + Point(arrowPolygonX[0] * scaleX, arrowPolygonY[0] * scaleY);
builder->MoveTo(p);
for (int32_t i = 1; i < arrowNumPoints; i++) {
p = center + Point(arrowPolygonX[i] * scaleX, arrowPolygonY[i] * scaleY);
@ -1245,9 +1257,9 @@ nsNativeBasicTheme::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
default:
// Various appearance values are used for XUL elements. Normally these
// will not be available in content documents (and thus in the content
// processes where the native basic theme can be used), but tests are run
// with the remote XUL pref enabled and so we can get in here. So we
// just return an error rather than assert.
// processes where the native basic theme can be used), but tests are
// run with the remote XUL pref enabled and so we can get in here. So
// we just return an error rather than assert.
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -1259,7 +1271,8 @@ nsNativeBasicTheme::CreateWebRenderCommandsForWidget(mozilla::wr::DisplayListBui
aBuilder, mozilla::wr::IpcResourceUpdateQueue& aResources, const
mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager*
aManager, nsIFrame* aFrame, StyleAppearance aAppearance, const nsRect& aRect) {
aManager, nsIFrame* aFrame, StyleAppearance aAppearance, const nsRect& aRect)
{
}*/
LayoutDeviceIntMargin nsNativeBasicTheme::GetWidgetBorder(
@ -1338,8 +1351,8 @@ bool nsNativeBasicTheme::GetWidgetOverflow(nsDeviceContext* aContext,
case StyleAppearance::MenulistButton:
case StyleAppearance::Menulist:
case StyleAppearance::Button:
// 2px for each segment, plus 1px separation, but we paint 1px inside the
// border area so 4px overflow.
// 2px for each segment, plus 1px separation, but we paint 1px inside
// the border area so 4px overflow.
overflow.SizeTo(4, 4, 4, 4);
break;
default:
@ -1358,6 +1371,17 @@ bool nsNativeBasicTheme::GetWidgetOverflow(nsDeviceContext* aContext,
return true;
}
auto nsNativeBasicTheme::GetScrollbarSizes(nsPresContext* aPresContext,
StyleScrollbarWidth aWidth, Overlay)
-> ScrollbarSizes {
CSSCoord size = aWidth == StyleScrollbarWidth::Thin
? kMinimumThinScrollbarSize
: kMinimumScrollbarSize;
LayoutDeviceIntCoord s =
(size * GetDPIRatioForScrollbarPart(aPresContext)).Rounded();
return {s, s};
}
NS_IMETHODIMP
nsNativeBasicTheme::GetMinimumWidgetSize(nsPresContext* aPresContext,
nsIFrame* aFrame,
@ -1403,13 +1427,12 @@ nsNativeBasicTheme::GetMinimumWidgetSize(nsPresContext* aPresContext,
case StyleAppearance::ScrollbartrackHorizontal:
case StyleAppearance::ScrollbartrackVertical:
case StyleAppearance::Scrollcorner: {
if (IsScrollbarWidthThin(aFrame)) {
aResult->SizeTo((kMinimumThinScrollbarSize * dpiRatio).Rounded(),
(kMinimumThinScrollbarSize * dpiRatio).Rounded());
} else {
aResult->SizeTo((kMinimumScrollbarSize * dpiRatio).Rounded(),
(kMinimumScrollbarSize * dpiRatio).Rounded());
auto* style = nsLayoutUtils::StyleForScrollbar(aFrame);
auto width = style->StyleUIReset()->mScrollbarWidth;
auto sizes = GetScrollbarSizes(aPresContext, width, Overlay::No);
MOZ_ASSERT(sizes.mHorizontal == sizes.mVertical);
aResult->SizeTo(sizes.mHorizontal, sizes.mHorizontal);
if (width != StyleScrollbarWidth::Thin) {
// If the scrollbar has any buttons, then we increase the minimum
// size so that they fit too.
//

Просмотреть файл

@ -186,11 +186,16 @@ class nsNativeBasicTheme : protected nsNativeTheme, public nsITheme {
bool WidgetIsContainer(StyleAppearance aAppearance) override;
bool ThemeDrawsFocusForWidget(StyleAppearance aAppearance) override;
bool ThemeNeedsComboboxDropmarker() override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*,
StyleScrollbarWidth,
Overlay) override;
protected:
nsNativeBasicTheme() = default;
virtual ~nsNativeBasicTheme() = default;
static DPIRatio GetDPIRatioForScrollbarPart(nsPresContext*);
static DPIRatio GetDPIRatio(nsPresContext*, StyleAppearance);
static DPIRatio GetDPIRatio(nsIFrame* aFrame, StyleAppearance);
static bool IsDateTimeResetButton(nsIFrame* aFrame);
static bool IsColorPickerButton(nsIFrame* aFrame);

Просмотреть файл

@ -1459,10 +1459,10 @@ static bool AssumeThemePartAndStateAreTransparent(int32_t aPart,
// with a different DPI setting from the system's default scaling, we need to
// apply scaling to native-themed elements as the Windows theme APIs assume
// the system default resolution.
static inline double GetThemeDpiScaleFactor(nsIFrame* aFrame) {
static inline double GetThemeDpiScaleFactor(nsPresContext* aPresContext) {
if (WinUtils::IsPerMonitorDPIAware() ||
StaticPrefs::layout_css_devPixelsPerPx() > 0.0) {
nsIWidget* rootWidget = aFrame->PresContext()->GetRootWidget();
nsIWidget* rootWidget = aPresContext->GetRootWidget();
if (rootWidget) {
double systemScale = WinUtils::SystemScaleFactor();
return rootWidget->GetDefaultScale().scale / systemScale;
@ -1471,6 +1471,10 @@ static inline double GetThemeDpiScaleFactor(nsIFrame* aFrame) {
return 1.0;
}
static inline double GetThemeDpiScaleFactor(nsIFrame* aFrame) {
return GetThemeDpiScaleFactor(aFrame->PresContext());
}
NS_IMETHODIMP
nsNativeThemeWin::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
@ -2634,7 +2638,6 @@ bool nsNativeThemeWin::ClassicThemeSupportsWidget(nsIFrame* aFrame,
case StyleAppearance::ScrollbarthumbHorizontal:
case StyleAppearance::ScrollbarVertical:
case StyleAppearance::ScrollbarHorizontal:
case StyleAppearance::ScrollbarNonDisappearing:
case StyleAppearance::Scrollcorner:
case StyleAppearance::Menulist:
case StyleAppearance::MenulistButton:
@ -2813,11 +2816,6 @@ nsresult nsNativeThemeWin::ClassicGetMinimumWidgetSize(
// (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB) << 1;
break;
case StyleAppearance::ScrollbarNonDisappearing: {
aResult->SizeTo(::GetSystemMetrics(SM_CXVSCROLL),
::GetSystemMetrics(SM_CYHSCROLL));
break;
}
case StyleAppearance::RangeThumb: {
if (IsRangeHorizontal(aFrame)) {
(*aResult).width = 12;
@ -2945,6 +2943,25 @@ nsresult nsNativeThemeWin::ClassicGetMinimumWidgetSize(
return NS_OK;
}
auto nsNativeThemeWin::GetScrollbarSizes(nsPresContext* aPresContext,
StyleScrollbarWidth aWidth, Overlay)
-> ScrollbarSizes {
ScrollbarSizes sizes{::GetSystemMetrics(SM_CXVSCROLL),
::GetSystemMetrics(SM_CYHSCROLL)};
if (aWidth == StyleScrollbarWidth::Thin) {
sizes.mVertical = sizes.mVertical >> 1;
sizes.mHorizontal = sizes.mHorizontal >> 1;
}
double themeScale = GetThemeDpiScaleFactor(aPresContext);
if (themeScale != 1.0) {
sizes.mVertical = NSToIntRound(sizes.mVertical * themeScale);
sizes.mHorizontal = NSToIntRound(sizes.mHorizontal * themeScale);
}
return sizes;
}
nsresult nsNativeThemeWin::ClassicGetThemePartAndState(
nsIFrame* aFrame, StyleAppearance aAppearance, int32_t& aPart,
int32_t& aState, bool& aFocused) {

Просмотреть файл

@ -72,12 +72,14 @@ class nsNativeThemeWin : private nsNativeTheme, public nsITheme {
bool ThemeNeedsComboboxDropmarker() override;
virtual bool WidgetAppearanceDependsOnWindowFocus(
StyleAppearance aAppearance) override;
bool WidgetAppearanceDependsOnWindowFocus(StyleAppearance) override;
enum { eThemeGeometryTypeWindowButtons = eThemeGeometryTypeUnknown + 1 };
virtual ThemeGeometryType ThemeGeometryTypeForWidget(
nsIFrame* aFrame, StyleAppearance aAppearance) override;
ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame*,
StyleAppearance) override;
ScrollbarSizes GetScrollbarSizes(nsPresContext*, StyleScrollbarWidth,
Overlay) override;
nsNativeThemeWin();