diff -up firefox-53.0/widget/gtk/gtk3drawing.cpp.widget-rebase firefox-53.0/widget/gtk/gtk3drawing.cpp --- firefox-53.0/widget/gtk/gtk3drawing.cpp.widget-rebase 2017-04-11 06:15:20.000000000 +0200 +++ firefox-53.0/widget/gtk/gtk3drawing.cpp 2017-04-18 10:22:45.332920938 +0200 @@ -18,11 +18,10 @@ #include -static style_prop_t style_prop_func; -static gboolean have_arrow_scaling; static gboolean checkbox_check_state; static gboolean notebook_has_tab_gap; -static gboolean is_initialized; + +static ScrollbarGTKMetrics sScrollbarMetrics[2]; #define ARROW_UP 0 #define ARROW_DOWN G_PI @@ -40,6 +39,9 @@ static gint moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state, GtkTextDirection direction); +static GtkBorder +GetMarginBorderPadding(GtkStyleContext* aStyle); + // GetStateFlagsFromGtkWidgetState() can be safely used for the specific // GtkWidgets that set both prelight and active flags. For other widgets, // either the GtkStateFlags or Gecko's GtkWidgetState need to be carefully @@ -78,27 +80,22 @@ GetStateFlagsFromGtkTabFlags(GtkTabFlags } gint -moz_gtk_enable_style_props(style_prop_t styleGetProp) -{ - style_prop_func = styleGetProp; - return MOZ_GTK_SUCCESS; -} - -gint moz_gtk_init() { - if (is_initialized) - return MOZ_GTK_SUCCESS; - - is_initialized = TRUE; - have_arrow_scaling = (gtk_major_version > 2 || - (gtk_major_version == 2 && gtk_minor_version >= 12)); if (gtk_major_version > 3 || (gtk_major_version == 3 && gtk_minor_version >= 14)) checkbox_check_state = GTK_STATE_FLAG_CHECKED; else checkbox_check_state = GTK_STATE_FLAG_ACTIVE; + moz_gtk_refresh(); + + return MOZ_GTK_SUCCESS; +} + +void +moz_gtk_refresh() +{ if (gtk_check_version(3, 12, 0) == nullptr && gtk_check_version(3, 20, 0) != nullptr) { @@ -112,7 +109,8 @@ moz_gtk_init() notebook_has_tab_gap = true; } - return MOZ_GTK_SUCCESS; + sScrollbarMetrics[GTK_ORIENTATION_HORIZONTAL].initialized = false; + sScrollbarMetrics[GTK_ORIENTATION_VERTICAL].initialized = false; } gint @@ -420,9 +418,8 @@ calculate_arrow_rect(GtkWidget* arrow, G gfloat mxalign, myalign; GtkMisc* misc = GTK_MISC(arrow); - if (have_arrow_scaling) - gtk_style_context_get_style(gtk_widget_get_style_context(arrow), - "arrow_scaling", &arrow_scaling, NULL); + gtk_style_context_get_style(gtk_widget_get_style_context(arrow), + "arrow_scaling", &arrow_scaling, NULL); gtk_misc_get_padding(misc, &mxpad, &mypad); extent = MIN((rect->width - mxpad * 2), @@ -443,7 +440,23 @@ calculate_arrow_rect(GtkWidget* arrow, G return MOZ_GTK_SUCCESS; } -void +static MozGtkSize +GetMinContentBox(GtkStyleContext* style) +{ + GtkStateFlags state_flags = gtk_style_context_get_state(style); + gint width, height; + gtk_style_context_get(style, state_flags, + "min-width", &width, + "min-height", &height, + nullptr); + return {width, height}; +} + +/** + * Get minimum widget size as sum of margin, padding, border and + * min-width/min-height. + */ +static void moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width, int* height) { @@ -466,6 +479,14 @@ moz_gtk_get_widget_min_size(WidgetNodeTy padding.top + padding.bottom; } +static MozGtkSize +GetMinMarginBox(WidgetNodeType aNodeType) +{ + gint width, height; + moz_gtk_get_widget_min_size(aNodeType, &width, &height); + return {width, height}; +} + static void Inset(GdkRectangle* rect, GtkBorder& aBorder) { @@ -546,18 +567,22 @@ moz_gtk_scrollbar_button_paint(cairo_t * // box occupies the full width of the "contents" gadget content box. InsetByMargin(&rect, style); } else { - // Scrollbar button has to be inset by trough_border because its DOM - // element is filling width of vertical scrollbar's track (or height - // in case of horizontal scrollbars). - MozGtkScrollbarMetrics metrics; - moz_gtk_get_scrollbar_metrics(&metrics); - if (flags & MOZ_GTK_STEPPER_VERTICAL) { - rect.x += metrics.trough_border; - rect.width = metrics.slider_width; - } else { - rect.y += metrics.trough_border; - rect.height = metrics.slider_width; - } + // Scrollbar button has to be inset by trough_border because its DOM + // element is filling width of vertical scrollbar's track (or height + // in case of horizontal scrollbars). + GtkOrientation orientation = flags & MOZ_GTK_STEPPER_VERTICAL ? + GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL; + const auto& metrics = sScrollbarMetrics[orientation]; + if (!metrics.initialized) { + NS_WARNING("Didn't measure before drawing?"); + } + if (flags & MOZ_GTK_STEPPER_VERTICAL) { + rect.x += metrics.border.track.left; + rect.width = metrics.size.thumb.width; + } else { + rect.y += metrics.border.track.top; + rect.height = metrics.size.thumb.height; + } } gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height); @@ -629,12 +654,37 @@ moz_gtk_draw_styled_frame(GtkStyleContex static gint moz_gtk_scrollbar_trough_paint(WidgetNodeType widget, - cairo_t *cr, const GdkRectangle* rect, + cairo_t *cr, const GdkRectangle* aRect, GtkWidgetState* state, GtkTextDirection direction) { - GtkStyleContext* style = ClaimStyleContext(widget, direction); - moz_gtk_draw_styled_frame(style, cr, rect, state->focused); + GdkRectangle rect = *aRect; + GtkStyleContext* style; + + if (gtk_get_minor_version() >= 20) { + WidgetNodeType thumb = widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL ? + MOZ_GTK_SCROLLBAR_THUMB_VERTICAL : + MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL; + MozGtkSize thumbSize = GetMinMarginBox(thumb); + style = ClaimStyleContext(widget, direction); + MozGtkSize trackSize = GetMinContentBox(style); + trackSize.Include(thumbSize); + trackSize += GetMarginBorderPadding(style); + // Gecko's trough |aRect| fills available breadth, but GTK's trough is + // centered in the contents_gadget. The centering here round left + // and up, like gtk_box_gadget_allocate_child(). + if (widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL) { + rect.x += (rect.width - trackSize.width)/2; + rect.width = trackSize.width; + } else { + rect.y += (rect.height - trackSize.height)/2; + rect.height = trackSize.height; + } + } else { + style = ClaimStyleContext(widget, direction); + } + + moz_gtk_draw_styled_frame(style, cr, &rect, state->focused); ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; @@ -2009,6 +2059,20 @@ static void moz_gtk_add_margin_border_pa moz_gtk_add_style_padding(style, left, top, right, bottom); } +static GtkBorder +GetMarginBorderPadding(GtkStyleContext* aStyle) +{ + gint left = 0, top = 0, right = 0, bottom = 0; + moz_gtk_add_margin_border_padding(aStyle, &left, &top, &right, &bottom); + // narrowing conversions to gint16: + GtkBorder result; + result.left = left; + result.right = right; + result.top = top; + result.bottom = bottom; + return result; +} + gint moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top, gint* right, gint* bottom, GtkTextDirection direction, @@ -2212,61 +2276,7 @@ moz_gtk_get_widget_border(WidgetNodeType return MOZ_GTK_SUCCESS; } - case MOZ_GTK_SCROLLBAR_VERTICAL: - case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL: - { - if (gtk_check_version(3,20,0) == nullptr) { - style = ClaimStyleContext(widget); - moz_gtk_add_margin_border_padding(style, left, top, right, bottom); - ReleaseStyleContext(style); - if (widget == MOZ_GTK_SCROLLBAR_VERTICAL) { - style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL); - moz_gtk_add_margin_border_padding(style, left, top, right, bottom); - ReleaseStyleContext(style); - } - } else { - MozGtkScrollbarMetrics metrics; - moz_gtk_get_scrollbar_metrics(&metrics); - /* Top and bottom border for whole vertical scrollbar, top and bottom - * border for horizontal track - to correctly position thumb element */ - *top = *bottom = metrics.trough_border; - } - return MOZ_GTK_SUCCESS; - } - break; - case MOZ_GTK_SCROLLBAR_HORIZONTAL: - case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL: - { - if (gtk_check_version(3,20,0) == nullptr) { - style = ClaimStyleContext(widget); - moz_gtk_add_margin_border_padding(style, left, top, right, bottom); - ReleaseStyleContext(style); - if (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) { - style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL); - moz_gtk_add_margin_border_padding(style, left, top, right, bottom); - ReleaseStyleContext(style); - } - } else { - MozGtkScrollbarMetrics metrics; - moz_gtk_get_scrollbar_metrics(&metrics); - *left = *right = metrics.trough_border; - } - return MOZ_GTK_SUCCESS; - } - break; - - case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: - case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: - { - if (gtk_check_version(3,20,0) == nullptr) { - style = ClaimStyleContext(widget); - moz_gtk_add_margin_border_padding(style, left, top, right, bottom); - ReleaseStyleContext(style); - } - return MOZ_GTK_SUCCESS; - } - break; /* These widgets have no borders, since they are not containers. */ case MOZ_GTK_CHECKBUTTON_LABEL: case MOZ_GTK_RADIOBUTTON_LABEL: @@ -2275,6 +2285,8 @@ moz_gtk_get_widget_border(WidgetNodeType case MOZ_GTK_CHECKBUTTON: case MOZ_GTK_RADIOBUTTON: case MOZ_GTK_SCROLLBAR_BUTTON: + case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: case MOZ_GTK_SCALE_THUMB_HORIZONTAL: case MOZ_GTK_SCALE_THUMB_VERTICAL: case MOZ_GTK_GRIPPER: @@ -2498,11 +2510,11 @@ void moz_gtk_get_scale_metrics(GtkOrientation orient, gint* scale_width, gint* scale_height) { - WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ? - MOZ_GTK_SCALE_HORIZONTAL : - MOZ_GTK_SCALE_VERTICAL; - if (gtk_check_version(3, 20, 0) != nullptr) { + WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ? + MOZ_GTK_SCALE_HORIZONTAL : + MOZ_GTK_SCALE_VERTICAL; + gint thumb_length, thumb_height, trough_border; moz_gtk_get_scalethumb_metrics(orient, &thumb_length, &thumb_height); @@ -2518,12 +2530,10 @@ moz_gtk_get_scale_metrics(GtkOrientation } ReleaseStyleContext(style); } else { - GtkStyleContext* style = ClaimStyleContext(widget); - gtk_style_context_get(style, gtk_style_context_get_state(style), - "min-width", scale_width, - "min-height", scale_height, - nullptr); - ReleaseStyleContext(style); + WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ? + MOZ_GTK_SCALE_TROUGH_HORIZONTAL : + MOZ_GTK_SCALE_TROUGH_VERTICAL; + moz_gtk_get_widget_min_size(widget, scale_width, scale_height); } } @@ -2546,33 +2556,176 @@ moz_gtk_get_scalethumb_metrics(GtkOrient MOZ_GTK_SCALE_THUMB_HORIZONTAL: MOZ_GTK_SCALE_THUMB_VERTICAL; GtkStyleContext* style = ClaimStyleContext(widget); - gtk_style_context_get(style, gtk_style_context_get_state(style), - "min-width", thumb_length, - "min-height", thumb_height, + + gint min_width, min_height; + GtkStateFlags state = gtk_style_context_get_state(style); + gtk_style_context_get(style, state, + "min-width", &min_width, + "min-height", &min_height, nullptr); + GtkBorder margin; + gtk_style_context_get_margin(style, state, &margin); + gint margin_width = margin.left + margin.right; + gint margin_height = margin.top + margin.bottom; + + // Negative margin of slider element also determines its minimal size + // so use bigger of those two values. + if (min_width < -margin_width) + min_width = -margin_width; + if (min_height < -margin_height) + min_height = -margin_height; + + *thumb_length = min_width; + *thumb_height = min_height; + ReleaseStyleContext(style); } return MOZ_GTK_SUCCESS; } -gint -moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) +static MozGtkSize +SizeFromLengthAndBreadth(GtkOrientation aOrientation, + gint aLength, gint aBreadth) { - // For Gtk >= 3.20 scrollbar metrics are ignored - MOZ_ASSERT(gtk_check_version(3, 20, 0) != nullptr); + return aOrientation == GTK_ORIENTATION_HORIZONTAL ? + MozGtkSize({aLength, aBreadth}) : MozGtkSize({aBreadth, aLength}); +} + +const ScrollbarGTKMetrics* +GetScrollbarMetrics(GtkOrientation aOrientation) +{ + auto metrics = &sScrollbarMetrics[aOrientation]; + if (metrics->initialized) + return metrics; + + metrics->initialized = true; - GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_VERTICAL); + WidgetNodeType scrollbar = aOrientation == GTK_ORIENTATION_HORIZONTAL ? + MOZ_GTK_SCROLLBAR_HORIZONTAL : MOZ_GTK_SCROLLBAR_VERTICAL; + + gboolean backward, forward, secondary_backward, secondary_forward; + GtkStyleContext* style = ClaimStyleContext(scrollbar); gtk_style_context_get_style(style, - "slider_width", &metrics->slider_width, - "trough_border", &metrics->trough_border, - "stepper_size", &metrics->stepper_size, - "stepper_spacing", &metrics->stepper_spacing, - "min-slider-length", &metrics->min_slider_size, - nullptr); + "has-backward-stepper", &backward, + "has-forward-stepper", &forward, + "has-secondary-backward-stepper", + &secondary_backward, + "has-secondary-forward-stepper", + &secondary_forward, nullptr); + bool hasButtons = + backward || forward || secondary_backward || secondary_forward; + + if (gtk_get_minor_version() < 20) { + gint slider_width, trough_border, stepper_size, min_slider_size; + + gtk_style_context_get_style(style, + "slider-width", &slider_width, + "trough-border", &trough_border, + "stepper-size", &stepper_size, + "min-slider-length", &min_slider_size, + nullptr); + ReleaseStyleContext(style); + + metrics->size.thumb = + SizeFromLengthAndBreadth(aOrientation, min_slider_size, slider_width); + metrics->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 = + SizeFromLengthAndBreadth(aOrientation, length, breadth); + + // Borders on the major axis are set on the outermost scrollbar + // element to correctly position the buttons when + // trough-under-steppers is true. + // Borders on the minor axis are set on the track element so that it + // 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; + } else { + metrics->border.scrollbar.top = + metrics->border.scrollbar.bottom = + metrics->border.track.left = + metrics->border.track.right = trough_border; + } + + return metrics; + } + + // GTK version > 3.20 + // scrollbar + metrics->border.scrollbar = GetMarginBorderPadding(style); ReleaseStyleContext(style); - return MOZ_GTK_SUCCESS; + WidgetNodeType contents, track, thumb; + if (aOrientation == GTK_ORIENTATION_HORIZONTAL) { + contents = MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL; + track = MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL; + thumb = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL; + } else { + contents = MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL; + track = MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL; + thumb = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL; + } + // thumb + metrics->size.thumb = GetMinMarginBox(thumb); + // track + style = ClaimStyleContext(track); + metrics->border.track = GetMarginBorderPadding(style); + MozGtkSize trackMinSize = GetMinContentBox(style) + metrics->border.track; + ReleaseStyleContext(style); + MozGtkSize trackSizeForThumb = metrics->size.thumb + metrics->border.track; + // button + if (hasButtons) { + metrics->size.button = GetMinMarginBox(MOZ_GTK_SCROLLBAR_BUTTON); + } else { + metrics->size.button = {0, 0}; + } + if (aOrientation == GTK_ORIENTATION_HORIZONTAL) { + metrics->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; + 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; + // Update size for change in border. + trackSizeForThumb.height += extra; + } + } else { + gint extra = + std::max(trackMinSize.width, + metrics->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; + trackSizeForThumb.width += extra; + } + } + + style = ClaimStyleContext(contents); + GtkBorder contentsBorder = GetMarginBorderPadding(style); + ReleaseStyleContext(style); + + metrics->size.scrollbar = + trackSizeForThumb + contentsBorder + metrics->border.scrollbar; + + return metrics; } /* cairo_t *cr argument has to be a system-cairo. */ @@ -2814,34 +2967,11 @@ moz_gtk_widget_paint(WidgetNodeType widg return MOZ_GTK_UNKNOWN_WIDGET; } -GtkWidget* moz_gtk_get_scrollbar_widget(void) -{ - return GetWidget(MOZ_GTK_SCROLLBAR_HORIZONTAL); -} - -gboolean moz_gtk_has_scrollbar_buttons(void) -{ - gboolean backward, forward, secondary_backward, secondary_forward; - MOZ_ASSERT(is_initialized, "Forgot to call moz_gtk_init()"); - GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_VERTICAL); - gtk_style_context_get_style(style, - "has-backward-stepper", &backward, - "has-forward-stepper", &forward, - "has-secondary-backward-stepper", &secondary_backward, - "has-secondary-forward-stepper", &secondary_forward, - NULL); - ReleaseStyleContext(style); - - return backward | forward | secondary_forward | secondary_forward; -} - gint moz_gtk_shutdown() { /* This will destroy all of our widgets */ ResetWidgetCache(); - is_initialized = FALSE; - return MOZ_GTK_SUCCESS; } diff -up firefox-53.0/widget/gtk/gtkdrawing.h.widget-rebase firefox-53.0/widget/gtk/gtkdrawing.h --- firefox-53.0/widget/gtk/gtkdrawing.h.widget-rebase 2017-04-18 10:24:37.950508591 +0200 +++ firefox-53.0/widget/gtk/gtkdrawing.h 2017-04-18 10:22:45.412920645 +0200 @@ -39,13 +39,49 @@ typedef struct { gint32 maxpos; } GtkWidgetState; +/** + * A size in the same GTK pixel units as GtkBorder and GdkRectangle. + */ +struct MozGtkSize { + gint width; + gint height; + + MozGtkSize& operator+=(const GtkBorder& aBorder) + { + width += aBorder.left + aBorder.right; + height += aBorder.top + aBorder.bottom; + return *this; + } + MozGtkSize operator+(const GtkBorder& aBorder) const + { + MozGtkSize result = *this; + return result += aBorder; + } + void Include(MozGtkSize aOther) + { + width = std::max(width, aOther.width); + height = std::max(height, aOther.height); + } + void Rotate() + { + gint tmp = width; + width = height; + height = tmp; + } +}; + typedef struct { - gint slider_width; - gint trough_border; - gint stepper_size; - gint stepper_spacing; - gint min_slider_size; -} MozGtkScrollbarMetrics; + bool initialized; + struct { + MozGtkSize scrollbar; + MozGtkSize thumb; + MozGtkSize button; + } size; + struct { + GtkBorder scrollbar; + GtkBorder track; + } border; +} ScrollbarGTKMetrics; typedef enum { MOZ_GTK_STEPPER_DOWN = 1 << 0, @@ -67,9 +103,6 @@ typedef enum { MOZ_GTK_TAB_SELECTED = 1 << 10 } GtkTabFlags; -/* function type for moz_gtk_enable_style_props */ -typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint); - /*** result/error codes ***/ #define MOZ_GTK_SUCCESS 0 #define MOZ_GTK_UNKNOWN_WIDGET -1 @@ -272,13 +305,9 @@ typedef enum { gint moz_gtk_init(); /** - * Enable GTK+ 1.2.9+ theme enhancements. You must provide a pointer - * to the GTK+ 1.2.9+ function "gtk_style_get_prop_experimental". - * styleGetProp: pointer to gtk_style_get_prop_experimental - * - * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + * Updates the drawing library when the theme changes. */ -gint moz_gtk_enable_style_props(style_prop_t styleGetProp); +void moz_gtk_refresh(); /** * Perform cleanup of the drawing library. You should call this function @@ -432,13 +461,10 @@ gint moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height); /** - * Get the desired metrics for a GtkScrollbar - * metrics: [IN] struct which will contain the metrics - * - * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + * Get the metrics in GTK pixels for a scrollbar. */ -gint -moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics* metrics); +const ScrollbarGTKMetrics* +GetScrollbarMetrics(GtkOrientation aOrientation); /** * Get the desired size of a dropdown arrow button @@ -518,30 +544,11 @@ gint moz_gtk_get_menu_separator_height(g gint moz_gtk_splitter_get_metrics(gint orientation, gint* size); /** - * Retrieve an actual GTK scrollbar widget for style analysis. It will not - * be modified. - */ -GtkWidget* moz_gtk_get_scrollbar_widget(void); - -/** * Get the YTHICKNESS of a tab (notebook extension). */ gint moz_gtk_get_tab_thickness(WidgetNodeType aNodeType); -/** - * Get a boolean which indicates whether the theme draws scrollbar buttons. - * If TRUE, draw scrollbar buttons. - */ -gboolean moz_gtk_has_scrollbar_buttons(void); - -/** - * Get minimum widget size as sum of margin, padding, border and min-width, - * min-height. - */ -void moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width, - int* height); - #if (MOZ_WIDGET_GTK == 2) #ifdef __cplusplus } diff -up firefox-53.0/widget/gtk/mozgtk/mozgtk.c.widget-rebase firefox-53.0/widget/gtk/mozgtk/mozgtk.c diff -up firefox-53.0/widget/gtk/nsLookAndFeel.cpp.widget-rebase firefox-53.0/widget/gtk/nsLookAndFeel.cpp --- firefox-53.0/widget/gtk/nsLookAndFeel.cpp.widget-rebase 2017-04-11 06:15:20.000000000 +0200 +++ firefox-53.0/widget/gtk/nsLookAndFeel.cpp 2017-04-18 10:22:45.333920935 +0200 @@ -18,7 +18,7 @@ #include #include "gfxPlatformGtk.h" -#include "nsScreenGtk.h" +#include "ScreenHelperGTK.h" #include "gtkdrawing.h" #include "nsStyleConsts.h" @@ -49,9 +49,9 @@ nsLookAndFeel::nsLookAndFeel() mStyle(nullptr), #endif mDefaultFontCached(false), mButtonFontCached(false), - mFieldFontCached(false), mMenuFontCached(false) + mFieldFontCached(false), mMenuFontCached(false), + mInitialized(false) { - Init(); } nsLookAndFeel::~nsLookAndFeel() @@ -223,6 +223,8 @@ GetBorderColors(GtkStyleContext* aContex nsresult nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) { + EnsureInit(); + #if (MOZ_WIDGET_GTK == 3) GdkRGBA gdk_color; #endif @@ -674,6 +676,11 @@ nsLookAndFeel::GetIntImpl(IntID aID, int return res; res = NS_OK; + // We use delayed initialization by EnsureInit() here + // to make sure mozilla::Preferences is available (Bug 115807). + // eIntID_UseAccessibilityTheme is requested before user preferences + // are read, and so EnsureInit(), which depends on preference values, + // is deliberately delayed until required. switch (aID) { case eIntID_CaretBlinkTime: { @@ -777,11 +784,11 @@ nsLookAndFeel::GetIntImpl(IntID aID, int aResult = threshold; } break; - case eIntID_ScrollArrowStyle: - moz_gtk_init(); - aResult = - ConvertGTKStepperStyleToMozillaScrollArrowStyle(moz_gtk_get_scrollbar_widget()); + case eIntID_ScrollArrowStyle: { + GtkWidget* scrollbar = GetWidget(MOZ_GTK_SCROLLBAR_HORIZONTAL); + aResult = ConvertGTKStepperStyleToMozillaScrollArrowStyle(scrollbar); break; + } case eIntID_ScrollSliderStyle: aResult = eScrollThumbStyle_Proportional; break; @@ -836,6 +843,7 @@ nsLookAndFeel::GetIntImpl(IntID aID, int aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY; break; case eIntID_MenuBarDrag: + EnsureInit(); aResult = sMenuSupportsDrag; break; case eIntID_ScrollbarButtonAutoRepeatBehavior: @@ -876,6 +884,7 @@ nsLookAndFeel::GetFloatImpl(FloatID aID, aResult = 1.0f; break; case eFloatID_CaretAspectRatio: + EnsureInit(); aResult = sCaretRatio; break; default: @@ -925,7 +934,7 @@ GetSystemFontInfo(GtkWidget *aWidget, // Scale fonts up on HiDPI displays. // This would be done automatically with cairo, but we manually manage // the display scale for platform consistency. - size *= nsScreenGtk::GetGtkMonitorScaleFactor(); + size *= ScreenHelperGTK::GetGTKMonitorScaleFactor(); // |size| is now pixels @@ -1056,11 +1065,15 @@ nsLookAndFeel::GetFontImpl(FontID aID, n } void -nsLookAndFeel::Init() +nsLookAndFeel::EnsureInit() { GdkColor colorValue; GdkColor *colorValuePtr; + if (mInitialized) + return; + mInitialized = true; + #if (MOZ_WIDGET_GTK == 2) NS_ASSERTION(!mStyle, "already initialized"); // GtkInvisibles come with a refcount that is not floating @@ -1133,16 +1146,39 @@ nsLookAndFeel::Init() // with wrong color theme, see Bug 972382 GtkSettings *settings = gtk_settings_get_for_screen(gdk_screen_get_default()); - // Disable dark theme because it interacts poorly with widget styling in - // web content (see bug 1216658). + // Dark themes interacts poorly with widget styling (see bug 1216658). + // We disable dark themes by default for all processes (chrome, web content) + // but allow user to overide it by prefs. + const gchar* dark_setting = "gtk-application-prefer-dark-theme"; + gboolean darkThemeDefault; + g_object_get(settings, dark_setting, &darkThemeDefault, nullptr); + // To avoid triggering reload of theme settings unnecessarily, only set the // setting when necessary. - const gchar* dark_setting = "gtk-application-prefer-dark-theme"; - gboolean dark; - g_object_get(settings, dark_setting, &dark, nullptr); + if (darkThemeDefault) { + bool allowDarkTheme; + if (XRE_IsContentProcess()) { + allowDarkTheme = + mozilla::Preferences::GetBool("widget.content.allow-gtk-dark-theme", + false); + } else { + allowDarkTheme = (PR_GetEnv("MOZ_ALLOW_GTK_DARK_THEME") != nullptr) || + mozilla::Preferences::GetBool("widget.chrome.allow-gtk-dark-theme", + false); + } + if (!allowDarkTheme) { + g_object_set(settings, dark_setting, FALSE, nullptr); + } + } - if (dark && !PR_GetEnv("MOZ_ALLOW_GTK_DARK_THEME")) { - g_object_set(settings, dark_setting, FALSE, nullptr); + // Allow content Gtk theme override by pref, it's useful when styled Gtk+ + // widgets break web content. + if (XRE_IsContentProcess()) { + auto contentThemeName = + mozilla::Preferences::GetCString("widget.content.gtk-theme-override"); + if (!contentThemeName.IsEmpty()) { + g_object_set(settings, "gtk-theme-name", contentThemeName.get(), nullptr); + } } // Scrollbar colors @@ -1438,6 +1474,7 @@ nsLookAndFeel::Init() char16_t nsLookAndFeel::GetPasswordCharacterImpl() { + EnsureInit(); return sInvisibleCharacter; } @@ -1445,6 +1482,7 @@ void nsLookAndFeel::RefreshImpl() { nsXPLookAndFeel::RefreshImpl(); + moz_gtk_refresh(); mDefaultFontCached = false; mButtonFontCached = false; @@ -1456,7 +1494,7 @@ nsLookAndFeel::RefreshImpl() mStyle = nullptr; #endif - Init(); + mInitialized = false; } bool