mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Bug 1454897 - Ubuntu/Ambiance - Render scrollbar thumb with different sizes in active/normal state, r=jhorak
This patch implements a workaround which alows us to emulate overlay scrollbars for some Gtk+ themes (Ubuntu/Ambiance), when an inactive scrollbar thumb is smaller than the active one. We calculate thumb margin as thumb class margin + difference margin between active and inactive scrollbars. Also remove boolean parameter from GetScrollbarMetrics() and implement GetActiveScrollbarMetrics() to get metrics for active scrollbar. MozReview-Commit-ID: 2zje5OZskYw --HG-- extra : rebase_source : dd50dc52d9d0942c9dcfbf72d217f3c6ee82c21a
This commit is contained in:
parent
681387a8ba
commit
659fc0cc75
@ -24,7 +24,7 @@ static gboolean checkbox_check_state;
|
||||
static gboolean notebook_has_tab_gap;
|
||||
|
||||
static ScrollbarGTKMetrics sScrollbarMetrics[2];
|
||||
static ScrollbarGTKMetrics sScrollbarMetricsActive[2];
|
||||
static ScrollbarGTKMetrics sActiveScrollbarMetrics[2];
|
||||
static ToggleGTKMetrics sCheckboxMetrics;
|
||||
static ToggleGTKMetrics sRadioMetrics;
|
||||
static ToolbarGTKMetrics sToolbarMetrics;
|
||||
@ -38,6 +38,28 @@ static ToolbarGTKMetrics sToolbarMetrics;
|
||||
#define GTK_STATE_FLAG_CHECKED (1 << 11)
|
||||
#endif
|
||||
|
||||
static GtkBorder
|
||||
operator-(const GtkBorder& first, const GtkBorder& second)
|
||||
{
|
||||
GtkBorder result;
|
||||
result.left = first.left - second.left;
|
||||
result.right = first.right - second.right;
|
||||
result.top = first.top - second.top;
|
||||
result.bottom = first.bottom - second.bottom;
|
||||
return result;
|
||||
}
|
||||
|
||||
static GtkBorder
|
||||
operator+(const GtkBorder& first, const GtkBorder& second)
|
||||
{
|
||||
GtkBorder result;
|
||||
result.left = first.left + second.left;
|
||||
result.right = first.right + second.right;
|
||||
result.top = first.top + second.top;
|
||||
result.bottom = first.bottom + second.bottom;
|
||||
return result;
|
||||
}
|
||||
|
||||
static GtkBorder
|
||||
operator+=(GtkBorder& first, const GtkBorder& second)
|
||||
{
|
||||
@ -193,8 +215,8 @@ moz_gtk_refresh()
|
||||
|
||||
sScrollbarMetrics[GTK_ORIENTATION_HORIZONTAL].initialized = false;
|
||||
sScrollbarMetrics[GTK_ORIENTATION_VERTICAL].initialized = false;
|
||||
sScrollbarMetricsActive[GTK_ORIENTATION_HORIZONTAL].initialized = false;
|
||||
sScrollbarMetricsActive[GTK_ORIENTATION_VERTICAL].initialized = false;
|
||||
sActiveScrollbarMetrics[GTK_ORIENTATION_HORIZONTAL].initialized = false;
|
||||
sActiveScrollbarMetrics[GTK_ORIENTATION_VERTICAL].initialized = false;
|
||||
sCheckboxMetrics.initialized = false;
|
||||
sRadioMetrics.initialized = false;
|
||||
sToolbarMetrics.initialized = false;
|
||||
@ -1010,19 +1032,21 @@ moz_gtk_scrollbar_thumb_paint(WidgetNodeType widget,
|
||||
GtkTextDirection direction)
|
||||
{
|
||||
GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
|
||||
GtkStyleContext* style = GetStyleContext(widget, direction, state_flags);
|
||||
|
||||
GtkOrientation orientation = (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
|
||||
GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
|
||||
|
||||
GdkRectangle rect = *aRect;
|
||||
GtkStyleContext* style = GetStyleContext(widget, direction, state_flags);
|
||||
InsetByMargin(&rect, style);
|
||||
|
||||
gtk_render_slider(style, cr,
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height,
|
||||
(widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
|
||||
GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
(state->depressed || state->active || state->inHover) ?
|
||||
GetActiveScrollbarMetrics(orientation) :
|
||||
GetScrollbarMetrics(orientation);
|
||||
Inset(&rect, metrics->margin.thumb);
|
||||
|
||||
gtk_render_slider(style, cr, rect.x, rect.y, rect.width, rect.height,
|
||||
orientation);
|
||||
|
||||
return MOZ_GTK_SUCCESS;
|
||||
}
|
||||
@ -2896,23 +2920,17 @@ GetToggleMetrics(bool isRadio)
|
||||
return metrics;
|
||||
}
|
||||
|
||||
const ScrollbarGTKMetrics*
|
||||
GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive)
|
||||
static void
|
||||
InitScrollbarMetrics(ScrollbarGTKMetrics* aMetrics,
|
||||
GtkOrientation aOrientation,
|
||||
GtkStateFlags aStateFlags)
|
||||
{
|
||||
auto metrics = aActive ? &sScrollbarMetricsActive[aOrientation] :
|
||||
&sScrollbarMetrics[aOrientation];
|
||||
if (metrics->initialized)
|
||||
return metrics;
|
||||
|
||||
metrics->initialized = true;
|
||||
|
||||
WidgetNodeType scrollbar = aOrientation == GTK_ORIENTATION_HORIZONTAL ?
|
||||
MOZ_GTK_SCROLLBAR_HORIZONTAL : MOZ_GTK_SCROLLBAR_VERTICAL;
|
||||
|
||||
gboolean backward, forward, secondary_backward, secondary_forward;
|
||||
GtkStyleContext* style = GetStyleContext(scrollbar, GTK_TEXT_DIR_NONE,
|
||||
aActive ? GTK_STATE_FLAG_PRELIGHT :
|
||||
GTK_STATE_FLAG_NORMAL);
|
||||
aStateFlags);
|
||||
gtk_style_context_get_style(style,
|
||||
"has-backward-stepper", &backward,
|
||||
"has-forward-stepper", &forward,
|
||||
@ -2933,15 +2951,15 @@ GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive)
|
||||
"min-slider-length", &min_slider_size,
|
||||
nullptr);
|
||||
|
||||
metrics->size.thumb =
|
||||
aMetrics->size.thumb =
|
||||
SizeFromLengthAndBreadth(aOrientation, min_slider_size, slider_width);
|
||||
metrics->size.button =
|
||||
aMetrics->size.button =
|
||||
SizeFromLengthAndBreadth(aOrientation, stepper_size, slider_width);
|
||||
// overall scrollbar
|
||||
gint breadth = slider_width + 2 * trough_border;
|
||||
// Require room for the slider in the track if we don't have buttons.
|
||||
gint length = hasButtons ? 0 : min_slider_size + 2 * trough_border;
|
||||
metrics->size.scrollbar =
|
||||
aMetrics->size.scrollbar =
|
||||
SizeFromLengthAndBreadth(aOrientation, length, breadth);
|
||||
|
||||
// Borders on the major axis are set on the outermost scrollbar
|
||||
@ -2951,23 +2969,24 @@ GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive)
|
||||
// receives mouse events, as in GTK.
|
||||
// Other borders have been zero-initialized.
|
||||
if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
|
||||
metrics->border.scrollbar.left =
|
||||
metrics->border.scrollbar.right =
|
||||
metrics->border.track.top =
|
||||
metrics->border.track.bottom = trough_border;
|
||||
aMetrics->border.scrollbar.left =
|
||||
aMetrics->border.scrollbar.right =
|
||||
aMetrics->border.track.top =
|
||||
aMetrics->border.track.bottom = trough_border;
|
||||
} else {
|
||||
metrics->border.scrollbar.top =
|
||||
metrics->border.scrollbar.bottom =
|
||||
metrics->border.track.left =
|
||||
metrics->border.track.right = trough_border;
|
||||
aMetrics->border.scrollbar.top =
|
||||
aMetrics->border.scrollbar.bottom =
|
||||
aMetrics->border.track.left =
|
||||
aMetrics->border.track.right = trough_border;
|
||||
}
|
||||
|
||||
return metrics;
|
||||
// We're done here for Gtk+ < 3.20...
|
||||
return;
|
||||
}
|
||||
|
||||
// GTK version > 3.20
|
||||
// scrollbar
|
||||
metrics->border.scrollbar = GetMarginBorderPadding(style);
|
||||
aMetrics->border.scrollbar = GetMarginBorderPadding(style);
|
||||
|
||||
WidgetNodeType contents, track, thumb;
|
||||
if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
|
||||
@ -2998,72 +3017,102 @@ GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive)
|
||||
*/
|
||||
|
||||
// thumb
|
||||
style = CreateStyleContextWithStates(thumb, GTK_TEXT_DIR_NONE,
|
||||
aActive ? GTK_STATE_FLAG_PRELIGHT :
|
||||
GTK_STATE_FLAG_NORMAL);
|
||||
metrics->size.thumb = GetMinMarginBox(style);
|
||||
style = CreateStyleContextWithStates(thumb, GTK_TEXT_DIR_NONE, aStateFlags);
|
||||
aMetrics->size.thumb = GetMinMarginBox(style);
|
||||
gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
|
||||
&aMetrics->margin.thumb);
|
||||
g_object_unref(style);
|
||||
|
||||
// track
|
||||
style = CreateStyleContextWithStates(track, GTK_TEXT_DIR_NONE,
|
||||
aActive ? GTK_STATE_FLAG_PRELIGHT :
|
||||
GTK_STATE_FLAG_NORMAL);
|
||||
metrics->border.track = GetMarginBorderPadding(style);
|
||||
MozGtkSize trackMinSize = GetMinContentBox(style) + metrics->border.track;
|
||||
MozGtkSize trackSizeForThumb = metrics->size.thumb + metrics->border.track;
|
||||
style = CreateStyleContextWithStates(track, GTK_TEXT_DIR_NONE, aStateFlags);
|
||||
aMetrics->border.track = GetMarginBorderPadding(style);
|
||||
MozGtkSize trackMinSize = GetMinContentBox(style) + aMetrics->border.track;
|
||||
MozGtkSize trackSizeForThumb = aMetrics->size.thumb + aMetrics->border.track;
|
||||
g_object_unref(style);
|
||||
|
||||
// button
|
||||
if (hasButtons) {
|
||||
style = CreateStyleContextWithStates(MOZ_GTK_SCROLLBAR_BUTTON,
|
||||
GTK_TEXT_DIR_NONE,
|
||||
aActive ? GTK_STATE_FLAG_PRELIGHT :
|
||||
GTK_STATE_FLAG_NORMAL);
|
||||
metrics->size.button = GetMinMarginBox(style);
|
||||
GTK_TEXT_DIR_NONE, aStateFlags);
|
||||
aMetrics->size.button = GetMinMarginBox(style);
|
||||
g_object_unref(style);
|
||||
} else {
|
||||
metrics->size.button = {0, 0};
|
||||
aMetrics->size.button = {0, 0};
|
||||
}
|
||||
if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
|
||||
metrics->size.button.Rotate();
|
||||
aMetrics->size.button.Rotate();
|
||||
// If the track is wider than necessary for the thumb, including when
|
||||
// the buttons will cause Gecko to expand the track to fill
|
||||
// available breadth, then add to the track border to prevent Gecko
|
||||
// from expanding the thumb to fill available breadth.
|
||||
gint extra =
|
||||
std::max(trackMinSize.height,
|
||||
metrics->size.button.height) - trackSizeForThumb.height;
|
||||
aMetrics->size.button.height) - trackSizeForThumb.height;
|
||||
if (extra > 0) {
|
||||
// If extra is odd, then the thumb is 0.5 pixels above
|
||||
// center as in gtk_range_compute_slider_position().
|
||||
metrics->border.track.top += extra / 2;
|
||||
metrics->border.track.bottom += extra - extra / 2;
|
||||
aMetrics->border.track.top += extra / 2;
|
||||
aMetrics->border.track.bottom += extra - extra / 2;
|
||||
// Update size for change in border.
|
||||
trackSizeForThumb.height += extra;
|
||||
}
|
||||
} else {
|
||||
gint extra =
|
||||
std::max(trackMinSize.width,
|
||||
metrics->size.button.width) - trackSizeForThumb.width;
|
||||
aMetrics->size.button.width) - trackSizeForThumb.width;
|
||||
if (extra > 0) {
|
||||
// If extra is odd, then the thumb is 0.5 pixels to the left
|
||||
// of center as in gtk_range_compute_slider_position().
|
||||
metrics->border.track.left += extra / 2;
|
||||
metrics->border.track.right += extra - extra / 2;
|
||||
aMetrics->border.track.left += extra / 2;
|
||||
aMetrics->border.track.right += extra - extra / 2;
|
||||
trackSizeForThumb.width += extra;
|
||||
}
|
||||
}
|
||||
|
||||
style = CreateStyleContextWithStates(contents, GTK_TEXT_DIR_NONE,
|
||||
aActive ? GTK_STATE_FLAG_PRELIGHT :
|
||||
GTK_STATE_FLAG_NORMAL);
|
||||
aStateFlags);
|
||||
GtkBorder contentsBorder = GetMarginBorderPadding(style);
|
||||
g_object_unref(style);
|
||||
|
||||
metrics->size.scrollbar =
|
||||
trackSizeForThumb + contentsBorder + metrics->border.scrollbar;
|
||||
aMetrics->size.scrollbar =
|
||||
trackSizeForThumb + contentsBorder + aMetrics->border.scrollbar;
|
||||
}
|
||||
|
||||
return metrics;
|
||||
const ScrollbarGTKMetrics*
|
||||
GetScrollbarMetrics(GtkOrientation aOrientation)
|
||||
{
|
||||
auto metrics = &sScrollbarMetrics[aOrientation];
|
||||
if (!metrics->initialized) {
|
||||
InitScrollbarMetrics(metrics, aOrientation, GTK_STATE_FLAG_NORMAL);
|
||||
|
||||
// We calculate thumb margin here because it's composited from
|
||||
// thumb class margin + difference margin between active and inactive
|
||||
// scrollbars. It's a workaround which alows us to emulate
|
||||
// overlay scrollbars for some Gtk+ themes (Ubuntu/Ambiance),
|
||||
// when an inactive scrollbar thumb is smaller than the active one.
|
||||
const ScrollbarGTKMetrics *metricsActive =
|
||||
GetActiveScrollbarMetrics(aOrientation);
|
||||
|
||||
if (metrics->size.thumb < metricsActive->size.thumb) {
|
||||
metrics->margin.thumb +=
|
||||
(metrics->border.scrollbar + metrics->border.track) -
|
||||
(metricsActive->border.scrollbar + metricsActive->border.track);
|
||||
}
|
||||
|
||||
metrics->initialized = true;
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
const ScrollbarGTKMetrics*
|
||||
GetActiveScrollbarMetrics(GtkOrientation aOrientation)
|
||||
{
|
||||
auto metrics = &sActiveScrollbarMetrics[aOrientation];
|
||||
if (!metrics->initialized) {
|
||||
InitScrollbarMetrics(metrics, aOrientation, GTK_STATE_FLAG_PRELIGHT);
|
||||
metrics->initialized = true;
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -82,6 +82,9 @@ typedef struct {
|
||||
GtkBorder scrollbar;
|
||||
GtkBorder track;
|
||||
} border;
|
||||
struct {
|
||||
GtkBorder thumb;
|
||||
} margin;
|
||||
} ScrollbarGTKMetrics;
|
||||
|
||||
typedef struct {
|
||||
@ -500,11 +503,17 @@ moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint*
|
||||
/**
|
||||
* Get the metrics in GTK pixels for a scrollbar.
|
||||
* aOrientation: [IN] the scrollbar orientation
|
||||
* aActive: [IN] Metricts for scrollbar with mouse pointer over it.
|
||||
*
|
||||
*/
|
||||
const ScrollbarGTKMetrics*
|
||||
GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive = false);
|
||||
GetScrollbarMetrics(GtkOrientation aOrientation);
|
||||
|
||||
/**
|
||||
* Get the metrics in GTK pixels for a scrollbar which is active
|
||||
* (selected by mouse pointer).
|
||||
* aOrientation: [IN] the scrollbar orientation
|
||||
*/
|
||||
const ScrollbarGTKMetrics*
|
||||
GetActiveScrollbarMetrics(GtkOrientation aOrientation);
|
||||
|
||||
/**
|
||||
* Get the desired size of a dropdown arrow button
|
||||
|
@ -1288,7 +1288,8 @@ nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
|
||||
GtkOrientation orientation =
|
||||
aWidgetType == NS_THEME_SCROLLBAR_HORIZONTAL ?
|
||||
GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
|
||||
const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation, true);
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
GetActiveScrollbarMetrics(orientation);
|
||||
|
||||
const GtkBorder& border = metrics->border.scrollbar;
|
||||
aResult->top = border.top;
|
||||
@ -1303,7 +1304,8 @@ nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
|
||||
GtkOrientation orientation =
|
||||
aWidgetType == NS_THEME_SCROLLBARTRACK_HORIZONTAL ?
|
||||
GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
|
||||
const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation, true);
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
GetActiveScrollbarMetrics(orientation);
|
||||
|
||||
const GtkBorder& border = metrics->border.track;
|
||||
aResult->top = border.top;
|
||||
@ -1458,7 +1460,7 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
case NS_THEME_SCROLLBARBUTTON_DOWN:
|
||||
{
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
GetScrollbarMetrics(GTK_ORIENTATION_VERTICAL, true);
|
||||
GetActiveScrollbarMetrics(GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
aResult->width = metrics->size.button.width;
|
||||
aResult->height = metrics->size.button.height;
|
||||
@ -1469,7 +1471,7 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
case NS_THEME_SCROLLBARBUTTON_RIGHT:
|
||||
{
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
GetScrollbarMetrics(GTK_ORIENTATION_HORIZONTAL, true);
|
||||
GetActiveScrollbarMetrics(GTK_ORIENTATION_HORIZONTAL);
|
||||
|
||||
aResult->width = metrics->size.button.width;
|
||||
aResult->height = metrics->size.button.height;
|
||||
@ -1502,7 +1504,8 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
GtkOrientation orientation =
|
||||
aWidgetType == NS_THEME_SCROLLBAR_HORIZONTAL ?
|
||||
GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
|
||||
const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation, true);
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
GetActiveScrollbarMetrics(orientation);
|
||||
|
||||
aResult->width = metrics->size.scrollbar.width;
|
||||
aResult->height = metrics->size.scrollbar.height;
|
||||
@ -1514,7 +1517,8 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
GtkOrientation orientation =
|
||||
aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL ?
|
||||
GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
|
||||
const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation, true);
|
||||
const ScrollbarGTKMetrics* metrics =
|
||||
GetActiveScrollbarMetrics(orientation);
|
||||
|
||||
aResult->width = metrics->size.thumb.width;
|
||||
aResult->height = metrics->size.thumb.height;
|
||||
|
Loading…
Reference in New Issue
Block a user