summaryrefslogtreecommitdiff
path: root/libre-testing/iceweasel/iceweasel-gtk3-20.patch
diff options
context:
space:
mode:
Diffstat (limited to 'libre-testing/iceweasel/iceweasel-gtk3-20.patch')
-rw-r--r--libre-testing/iceweasel/iceweasel-gtk3-20.patch2333
1 files changed, 2333 insertions, 0 deletions
diff --git a/libre-testing/iceweasel/iceweasel-gtk3-20.patch b/libre-testing/iceweasel/iceweasel-gtk3-20.patch
new file mode 100644
index 000000000..eccbc5e8d
--- /dev/null
+++ b/libre-testing/iceweasel/iceweasel-gtk3-20.patch
@@ -0,0 +1,2333 @@
+diff -up firefox-48.0/widget/gtk/gtk3drawing.cpp.gtk3-20 firefox-48.0/widget/gtk/gtk3drawing.cpp
+--- firefox-48.0/widget/gtk/gtk3drawing.cpp.gtk3-20 2016-07-25 22:22:07.000000000 +0200
++++ firefox-48.0/widget/gtk/gtk3drawing.cpp 2016-07-29 09:15:11.822285857 +0200
+@@ -18,15 +18,9 @@
+
+ #include <math.h>
+
+-static GtkWidget* gProtoWindow;
+ static GtkWidget* gProtoLayout;
+-static GtkWidget* gButtonWidget;
+-static GtkWidget* gToggleButtonWidget;
+-static GtkWidget* gButtonArrowWidget;
+-static GtkWidget* gSpinWidget;
+ static GtkWidget* gHScaleWidget;
+ static GtkWidget* gVScaleWidget;
+-static GtkWidget* gEntryWidget;
+ static GtkWidget* gComboBoxWidget;
+ static GtkWidget* gComboBoxButtonWidget;
+ static GtkWidget* gComboBoxArrowWidget;
+@@ -35,30 +29,15 @@ static GtkWidget* gComboBoxEntryWidget;
+ static GtkWidget* gComboBoxEntryTextareaWidget;
+ static GtkWidget* gComboBoxEntryButtonWidget;
+ static GtkWidget* gComboBoxEntryArrowWidget;
+-static GtkWidget* gHandleBoxWidget;
+-static GtkWidget* gToolbarWidget;
+-static GtkWidget* gFrameWidget;
+-static GtkWidget* gProgressWidget;
+ static GtkWidget* gTabWidget;
+-static GtkWidget* gTextViewWidget;
+-static GtkWidget* gTooltipWidget;
+-static GtkWidget* gMenuBarWidget;
+-static GtkWidget* gMenuBarItemWidget;
+-static GtkWidget* gMenuPopupWidget;
+-static GtkWidget* gMenuItemWidget;
+ static GtkWidget* gImageMenuItemWidget;
+ static GtkWidget* gCheckMenuItemWidget;
+ static GtkWidget* gTreeViewWidget;
+ static GtkTreeViewColumn* gMiddleTreeViewColumn;
+ static GtkWidget* gTreeHeaderCellWidget;
+ static GtkWidget* gTreeHeaderSortArrowWidget;
+-static GtkWidget* gExpanderWidget;
+-static GtkWidget* gToolbarSeparatorWidget;
+-static GtkWidget* gMenuSeparatorWidget;
+ static GtkWidget* gHPanedWidget;
+ static GtkWidget* gVPanedWidget;
+-static GtkWidget* gScrolledWindowWidget;
+-static GtkWidget* gInfoBar;
+
+ static style_prop_t style_prop_func;
+ static gboolean have_arrow_scaling;
+@@ -94,15 +73,6 @@ GetStateFlagsFromGtkWidgetState(GtkWidge
+ return stateFlags;
+ }
+
+-/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
+- that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
+- things they may want to do. */
+-static void
+-moz_gtk_set_widget_name(GtkWidget* widget)
+-{
+- gtk_widget_set_name(widget, "MozillaGtkWidget");
+-}
+-
+ gint
+ moz_gtk_enable_style_props(style_prop_t styleGetProp)
+ {
+@@ -111,15 +81,6 @@ moz_gtk_enable_style_props(style_prop_t
+ }
+
+ static gint
+-ensure_window_widget()
+-{
+- if (!gProtoWindow) {
+- gProtoWindow = GetWidget(MOZ_GTK_WINDOW);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+ setup_widget_prototype(GtkWidget* widget)
+ {
+ if (!gProtoLayout) {
+@@ -130,16 +91,6 @@ setup_widget_prototype(GtkWidget* widget
+ }
+
+ static gint
+-ensure_button_widget()
+-{
+- if (!gButtonWidget) {
+- gButtonWidget = gtk_button_new_with_label("M");
+- setup_widget_prototype(gButtonWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+ ensure_hpaned_widget()
+ {
+ if (!gHPanedWidget) {
+@@ -160,40 +111,6 @@ ensure_vpaned_widget()
+ }
+
+ static gint
+-ensure_toggle_button_widget()
+-{
+- if (!gToggleButtonWidget) {
+- gToggleButtonWidget = gtk_toggle_button_new();
+- setup_widget_prototype(gToggleButtonWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_button_arrow_widget()
+-{
+- if (!gButtonArrowWidget) {
+- ensure_toggle_button_widget();
+-
+- gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+- gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget);
+- gtk_widget_realize(gButtonArrowWidget);
+- gtk_widget_show(gButtonArrowWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_spin_widget()
+-{
+- if (!gSpinWidget) {
+- gSpinWidget = gtk_spin_button_new(NULL, 1, 0);
+- setup_widget_prototype(gSpinWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+ ensure_scale_widget()
+ {
+ if (!gHScaleWidget) {
+@@ -207,16 +124,6 @@ ensure_scale_widget()
+ return MOZ_GTK_SUCCESS;
+ }
+
+-static gint
+-ensure_entry_widget()
+-{
+- if (!gEntryWidget) {
+- gEntryWidget = gtk_entry_new();
+- setup_widget_prototype(gEntryWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+ /* We need to have pointers to the inner widgets (button, separator, arrow)
+ * of the ComboBox to get the correct rendering from theme engines which
+ * special cases their look. Since the inner layout can change, we ask GTK
+@@ -225,7 +132,7 @@ ensure_entry_widget()
+ * g_object_add_weak_pointer().
+ * Note that if we don't find the inner widgets (which shouldn't happen), we
+ * fallback to use generic "non-inner" widgets, and they don't need that kind
+- * of weak pointer since they are explicit children of gProtoWindow and as
++ * of weak pointer since they are explicit children of gProtoLayout and as
+ * such GTK holds a strong reference to them. */
+ static void
+ moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
+@@ -297,16 +204,14 @@ ensure_combo_box_widgets()
+ /* Shouldn't be reached with current internal gtk implementation; we
+ * use a generic toggle button as last resort fallback to avoid
+ * crashing. */
+- ensure_toggle_button_widget();
+- gComboBoxButtonWidget = gToggleButtonWidget;
++ gComboBoxButtonWidget = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
+ }
+
+ if (!gComboBoxArrowWidget) {
+ /* Shouldn't be reached with current internal gtk implementation;
+ * we gButtonArrowWidget as last resort fallback to avoid
+ * crashing. */
+- ensure_button_arrow_widget();
+- gComboBoxArrowWidget = gButtonArrowWidget;
++ gComboBoxArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW);
+ }
+
+ /* We don't test the validity of gComboBoxSeparatorWidget since there
+@@ -316,15 +221,6 @@ ensure_combo_box_widgets()
+ return MOZ_GTK_SUCCESS;
+ }
+
+-static void
+-ensure_info_bar()
+-{
+- if (!gInfoBar) {
+- gInfoBar = gtk_info_bar_new();
+- setup_widget_prototype(gInfoBar);
+- }
+-}
+-
+ /* We need to have pointers to the inner widgets (entry, button, arrow) of
+ * the ComboBoxEntry to get the correct rendering from theme engines which
+ * special cases their look. Since the inner layout can change, we ask GTK
+@@ -333,7 +229,7 @@ ensure_info_bar()
+ * g_object_add_weak_pointer().
+ * Note that if we don't find the inner widgets (which shouldn't happen), we
+ * fallback to use generic "non-inner" widgets, and they don't need that kind
+- * of weak pointer since they are explicit children of gProtoWindow and as
++ * of weak pointer since they are explicit children of gProtoLayout and as
+ * such GTK holds a strong reference to them. */
+ static void
+ moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
+@@ -385,8 +281,7 @@ ensure_combo_box_entry_widgets()
+ NULL);
+
+ if (!gComboBoxEntryTextareaWidget) {
+- ensure_entry_widget();
+- gComboBoxEntryTextareaWidget = gEntryWidget;
++ gComboBoxEntryTextareaWidget = GetWidget(MOZ_GTK_ENTRY);
+ }
+
+ if (gComboBoxEntryButtonWidget) {
+@@ -412,68 +307,19 @@ ensure_combo_box_entry_widgets()
+ /* Shouldn't be reached with current internal gtk implementation;
+ * we use a generic toggle button as last resort fallback to avoid
+ * crashing. */
+- ensure_toggle_button_widget();
+- gComboBoxEntryButtonWidget = gToggleButtonWidget;
++ gComboBoxEntryButtonWidget = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
+ }
+
+ if (!gComboBoxEntryArrowWidget) {
+ /* Shouldn't be reached with current internal gtk implementation;
+ * we gButtonArrowWidget as last resort fallback to avoid
+ * crashing. */
+- ensure_button_arrow_widget();
+- gComboBoxEntryArrowWidget = gButtonArrowWidget;
++ gComboBoxEntryArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW);
+ }
+
+ return MOZ_GTK_SUCCESS;
+ }
+
+-
+-static gint
+-ensure_handlebox_widget()
+-{
+- if (!gHandleBoxWidget) {
+- gHandleBoxWidget = gtk_handle_box_new();
+- setup_widget_prototype(gHandleBoxWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_toolbar_widget()
+-{
+- if (!gToolbarWidget) {
+- ensure_handlebox_widget();
+- gToolbarWidget = gtk_toolbar_new();
+- gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget);
+- gtk_widget_realize(gToolbarWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_toolbar_separator_widget()
+-{
+- if (!gToolbarSeparatorWidget) {
+- ensure_toolbar_widget();
+- gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new());
+- setup_widget_prototype(gToolbarSeparatorWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_tooltip_widget()
+-{
+- if (!gTooltipWidget) {
+- gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP);
+- GtkStyleContext* style = gtk_widget_get_style_context(gTooltipWidget);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
+- gtk_widget_realize(gTooltipWidget);
+- moz_gtk_set_widget_name(gTooltipWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+ static gint
+ ensure_tab_widget()
+ {
+@@ -485,81 +331,11 @@ ensure_tab_widget()
+ }
+
+ static gint
+-ensure_progress_widget()
+-{
+- if (!gProgressWidget) {
+- gProgressWidget = gtk_progress_bar_new();
+- setup_widget_prototype(gProgressWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_frame_widget()
+-{
+- if (!gFrameWidget) {
+- gFrameWidget = gtk_frame_new(NULL);
+- setup_widget_prototype(gFrameWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_menu_bar_widget()
+-{
+- if (!gMenuBarWidget) {
+- gMenuBarWidget = gtk_menu_bar_new();
+- setup_widget_prototype(gMenuBarWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_menu_bar_item_widget()
+-{
+- if (!gMenuBarItemWidget) {
+- ensure_menu_bar_widget();
+- gMenuBarItemWidget = gtk_menu_item_new();
+- gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget),
+- gMenuBarItemWidget);
+- gtk_widget_realize(gMenuBarItemWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_menu_popup_widget()
+-{
+- if (!gMenuPopupWidget) {
+- ensure_window_widget();
+- gMenuPopupWidget = gtk_menu_new();
+- gtk_menu_attach_to_widget(GTK_MENU(gMenuPopupWidget), gProtoWindow,
+- NULL);
+- gtk_widget_realize(gMenuPopupWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_menu_item_widget()
+-{
+- if (!gMenuItemWidget) {
+- ensure_menu_popup_widget();
+- gMenuItemWidget = gtk_menu_item_new_with_label("M");
+- gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
+- gMenuItemWidget);
+- gtk_widget_realize(gMenuItemWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+ ensure_image_menu_item_widget()
+ {
+ if (!gImageMenuItemWidget) {
+- ensure_menu_popup_widget();
+ gImageMenuItemWidget = gtk_image_menu_item_new();
+- gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
++ gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
+ gImageMenuItemWidget);
+ gtk_widget_realize(gImageMenuItemWidget);
+ }
+@@ -567,25 +343,11 @@ ensure_image_menu_item_widget()
+ }
+
+ static gint
+-ensure_menu_separator_widget()
+-{
+- if (!gMenuSeparatorWidget) {
+- ensure_menu_popup_widget();
+- gMenuSeparatorWidget = gtk_separator_menu_item_new();
+- gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
+- gMenuSeparatorWidget);
+- gtk_widget_realize(gMenuSeparatorWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+ ensure_check_menu_item_widget()
+ {
+ if (!gCheckMenuItemWidget) {
+- ensure_menu_popup_widget();
+- gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M");
+- gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
++ gCheckMenuItemWidget = gtk_check_menu_item_new();
++ gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
+ gCheckMenuItemWidget);
+ gtk_widget_realize(gCheckMenuItemWidget);
+ }
+@@ -646,37 +408,6 @@ ensure_tree_header_cell_widget()
+ return MOZ_GTK_SUCCESS;
+ }
+
+-static gint
+-ensure_expander_widget()
+-{
+- if (!gExpanderWidget) {
+- gExpanderWidget = gtk_expander_new("M");
+- setup_widget_prototype(gExpanderWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static gint
+-ensure_scrolled_window_widget()
+-{
+- if (!gScrolledWindowWidget) {
+- gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
+- setup_widget_prototype(gScrolledWindowWidget);
+- }
+- return MOZ_GTK_SUCCESS;
+-}
+-
+-static void
+-ensure_text_view_widget()
+-{
+- if (gTextViewWidget)
+- return;
+-
+- gTextViewWidget = gtk_text_view_new();
+- ensure_scrolled_window_widget();
+- gtk_container_add(GTK_CONTAINER(gScrolledWindowWidget), gTextViewWidget);
+-}
+-
+ gint
+ moz_gtk_init()
+ {
+@@ -729,26 +460,21 @@ moz_gtk_get_focus_outline_size(gint* foc
+ {
+ GtkBorder border;
+ GtkBorder padding;
+- GtkStyleContext *style;
+-
+- ensure_entry_widget();
+- style = gtk_widget_get_style_context(gEntryWidget);
+-
++ GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_ENTRY);
+ gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
+ gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
+ *focus_h_width = border.left + padding.left;
+ *focus_v_width = border.top + padding.top;
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+ gint
+ moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding)
+ {
+- ensure_menu_item_widget();
+-
+- gtk_style_context_get_style(gtk_widget_get_style_context(gMenuItemWidget),
+- "horizontal-padding", horizontal_padding,
+- NULL);
++ gtk_widget_style_get(GetWidget(MOZ_GTK_MENUITEM),
++ "horizontal-padding", horizontal_padding,
++ nullptr);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -771,10 +497,11 @@ moz_gtk_button_get_default_overflow(gint
+ {
+ GtkBorder* default_outside_border;
+
+- ensure_button_widget();
+- gtk_style_context_get_style(gtk_widget_get_style_context(gButtonWidget),
++ GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
++ gtk_style_context_get_style(style,
+ "default-outside-border", &default_outside_border,
+ NULL);
++ ReleaseStyleContext(style);
+
+ if (default_outside_border) {
+ *border_top = default_outside_border->top;
+@@ -794,10 +521,11 @@ moz_gtk_button_get_default_border(gint*
+ {
+ GtkBorder* default_border;
+
+- ensure_button_widget();
+- gtk_style_context_get_style(gtk_widget_get_style_context(gButtonWidget),
++ GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
++ gtk_style_context_get_style(style,
+ "default-border", &default_border,
+ NULL);
++ ReleaseStyleContext(style);
+
+ if (default_border) {
+ *border_top = default_border->top;
+@@ -831,17 +559,15 @@ static gint
+ moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_window_widget();
+- gtk_widget_set_direction(gProtoWindow, direction);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW, direction);
+
+- style = gtk_widget_get_style_context(gProtoWindow);
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_style_context_restore(style);
+
++ ReleaseStyleContext(style);
++
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1118,6 +844,36 @@ moz_gtk_scrollbar_button_paint(cairo_t *
+ return MOZ_GTK_SUCCESS;
+ }
+
++static void
++moz_gtk_update_scrollbar_style(GtkStyleContext* style,
++ WidgetNodeType widget,
++ GtkTextDirection direction)
++{
++ if (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) {
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_BOTTOM);
++ } else {
++ if (direction == GTK_TEXT_DIR_LTR) {
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_RIGHT);
++ gtk_style_context_remove_class(style, GTK_STYLE_CLASS_LEFT);
++ } else {
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_LEFT);
++ gtk_style_context_remove_class(style, GTK_STYLE_CLASS_RIGHT);
++ }
++ }
++}
++
++static void
++moz_gtk_draw_styled_frame(GtkStyleContext* style, cairo_t *cr,
++ GdkRectangle* rect, bool drawFocus)
++{
++ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
++ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
++ if (drawFocus) {
++ gtk_render_focus(style, cr,
++ rect->x, rect->y, rect->width, rect->height);
++ }
++}
++
+ static gint
+ moz_gtk_scrollbar_trough_paint(WidgetNodeType widget,
+ cairo_t *cr, GdkRectangle* rect,
+@@ -1126,26 +882,34 @@ moz_gtk_scrollbar_trough_paint(WidgetNod
+ GtkTextDirection direction)
+ {
+ if (flags & MOZ_GTK_TRACK_OPAQUE) {
+- GtkStyleContext* style =
+- gtk_widget_get_style_context(GTK_WIDGET(gProtoWindow));
+- gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW, direction);
++ gtk_render_background(style, cr,
++ rect->x, rect->y, rect->width, rect->height);
++ ReleaseStyleContext(style);
+ }
+
+- GtkStyleContext* style =
+- ClaimStyleContext(widget == MOZ_GTK_SCROLLBAR_HORIZONTAL ?
+- MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL :
+- MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL,
+- direction);
+- // TODO - integate with ClaimStyleContext()?
+- gtk_style_context_set_direction(style, direction);
++ bool isHorizontal = (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL);
++ GtkStyleContext* style;
+
+- gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
++ // Draw all child CSS Nodes for Gtk >= 3.20
++ if (gtk_check_version(3, 20, 0) == nullptr) {
++ style = ClaimStyleContext(widget, direction);
++ moz_gtk_update_scrollbar_style(style, widget, direction);
++ moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
++ ReleaseStyleContext(style);
+
+- if (state->focused) {
+- gtk_render_focus(style, cr,
+- rect->x, rect->y, rect->width, rect->height);
++ style = ClaimStyleContext(isHorizontal ?
++ MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL :
++ MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL,
++ direction);
++ moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
++ ReleaseStyleContext(style);
+ }
++ style = ClaimStyleContext(isHorizontal ?
++ MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL :
++ MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL,
++ direction);
++ moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
+ ReleaseStyleContext(style);
+
+ return MOZ_GTK_SUCCESS;
+@@ -1160,12 +924,7 @@ moz_gtk_scrollbar_thumb_paint(WidgetNode
+ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+ GtkBorder margin;
+
+- GtkStyleContext* style = ClaimStyleContext(widget, direction);
+-
+- // TODO - integate those with ClaimStyleContext()?
+- gtk_style_context_set_state(style, state_flags);
+- gtk_style_context_set_direction(style, direction);
+-
++ GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags);
+ gtk_style_context_get_margin (style, state_flags, &margin);
+
+ gtk_render_slider(style, cr,
+@@ -1185,17 +944,10 @@ static gint
+ moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_spin_widget();
+- gtk_widget_set_direction(gSpinWidget, direction);
+- style = gtk_widget_get_style_context(gSpinWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
+-
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1204,21 +956,14 @@ moz_gtk_spin_updown_paint(cairo_t *cr, G
+ gboolean isDown, GtkWidgetState* state,
+ GtkTextDirection direction)
+ {
+- GdkRectangle arrow_rect;
+- GtkStyleContext* style;
+-
+- ensure_spin_widget();
+- style = gtk_widget_get_style_context(gSpinWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
+- gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+- gtk_widget_set_direction(gSpinWidget, direction);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction,
++ GetStateFlagsFromGtkWidgetState(state));
+
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+
+-
+ /* hard code these values */
++ GdkRectangle arrow_rect;
+ arrow_rect.width = 6;
+ arrow_rect.height = 6;
+ arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
+@@ -1229,7 +974,8 @@ moz_gtk_spin_updown_paint(cairo_t *cr, G
+ isDown ? ARROW_DOWN : ARROW_UP,
+ arrow_rect.x, arrow_rect.y,
+ arrow_rect.width);
+- gtk_style_context_restore(style);
++
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1295,8 +1041,8 @@ moz_gtk_scale_thumb_paint(cairo_t *cr, G
+ gtk_widget_set_direction(widget, direction);
+
+ style = gtk_widget_get_style_context(widget);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER);
+ gtk_style_context_save(style);
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER);
+ gtk_style_context_set_state(style, state_flags);
+ /* determine the thumb size, and position the thumb in the center in the opposite axis
+ */
+@@ -1321,20 +1067,12 @@ moz_gtk_gripper_paint(cairo_t *cr, GdkRe
+ GtkWidgetState* state,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_handlebox_widget();
+- gtk_widget_set_direction(gHandleBoxWidget, direction);
+-
+- style = gtk_widget_get_style_context(gHandleBoxWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
+- gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+-
++ GtkStyleContext* style =
++ ClaimStyleContext(MOZ_GTK_GRIPPER, direction,
++ GetStateFlagsFromGtkWidgetState(state));
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
+-
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1435,6 +1173,38 @@ moz_gtk_entry_paint(cairo_t *cr, GdkRect
+ return MOZ_GTK_SUCCESS;
+ }
+
++static gint
++moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* rect,
++ GtkWidgetState* state,
++ GtkTextDirection direction)
++{
++ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
++
++ GtkStyleContext* style_frame =
++ ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction, state_flags);
++ gtk_render_frame(style_frame, cr, rect->x, rect->y, rect->width, rect->height);
++
++ GtkBorder border, padding;
++ gtk_style_context_get_border(style_frame, state_flags, &border);
++ gtk_style_context_get_padding(style_frame, state_flags, &padding);
++ ReleaseStyleContext(style_frame);
++
++ GtkStyleContext* style =
++ ClaimStyleContext(MOZ_GTK_TEXT_VIEW, direction, state_flags);
++
++ gint xthickness = border.left + padding.left;
++ gint ythickness = border.top + padding.top;
++
++ gtk_render_background(style, cr,
++ rect->x + xthickness, rect->y + ythickness,
++ rect->width - 2 * xthickness,
++ rect->height - 2 * ythickness);
++
++ ReleaseStyleContext(style);
++
++ return MOZ_GTK_SUCCESS;
++}
++
+ static gint
+ moz_gtk_treeview_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+@@ -1447,18 +1217,13 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkR
+ GtkBorder border;
+
+ ensure_tree_view_widget();
+- ensure_scrolled_window_widget();
+-
+ gtk_widget_set_direction(gTreeViewWidget, direction);
+- gtk_widget_set_direction(gScrolledWindowWidget, direction);
+
+ /* only handle disabled and normal states, otherwise the whole background
+ * area will be painted differently with other states */
+ state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL;
+
+- style = gtk_widget_get_style_context(gScrolledWindowWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);
++ style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction);
+ gtk_style_context_get_border(style, state_flags, &border);
+ xthickness = border.left;
+ ythickness = border.top;
+@@ -1473,7 +1238,7 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkR
+ rect->height - 2 * ythickness);
+ gtk_render_frame(style, cr,
+ rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+ gtk_style_context_restore(style_tree);
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -1648,20 +1413,9 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRect
+ GtkWidgetState* state,
+ GtkArrowType arrow_type, GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+- GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+ GdkRectangle arrow_rect;
+ gdouble arrow_angle;
+
+- ensure_button_arrow_widget();
+- style = gtk_widget_get_style_context(gButtonArrowWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_set_state(style, state_flags);
+- gtk_widget_set_direction(gButtonArrowWidget, direction);
+-
+- calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect,
+- direction);
+-
+ if (direction == GTK_TEXT_DIR_RTL) {
+ arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
+ GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
+@@ -1680,10 +1434,17 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRect
+ arrow_angle = ARROW_UP;
+ break;
+ }
+- if (arrow_type != GTK_ARROW_NONE)
+- gtk_render_arrow(style, cr, arrow_angle,
+- arrow_rect.x, arrow_rect.y, arrow_rect.width);
+- gtk_style_context_restore(style);
++ if (arrow_type == GTK_ARROW_NONE)
++ return MOZ_GTK_SUCCESS;
++
++ calculate_arrow_rect(GetWidget(MOZ_GTK_BUTTON_ARROW), rect, &arrow_rect,
++ direction);
++ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_BUTTON_ARROW,
++ direction, state_flags);
++ gtk_render_arrow(style, cr, arrow_angle,
++ arrow_rect.x, arrow_rect.y, arrow_rect.width);
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1776,19 +1537,10 @@ static gint
+ moz_gtk_toolbar_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_toolbar_widget();
+- gtk_widget_set_direction(gToolbarWidget, direction);
+-
+- style = gtk_widget_get_style_context(gToolbarWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLBAR);
+-
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR, direction);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
+-
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1798,7 +1550,6 @@ static gint
+ moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+ gint separator_width;
+ gint paint_width;
+ gboolean wide_separators;
+@@ -1807,16 +1558,14 @@ moz_gtk_toolbar_separator_paint(cairo_t
+ const double start_fraction = 0.2;
+ const double end_fraction = 0.8;
+
+- ensure_toolbar_separator_widget();
+- gtk_widget_set_direction(gToolbarSeparatorWidget, direction);
+-
+- style = gtk_widget_get_style_context(gToolbarSeparatorWidget);
+-
+- gtk_style_context_get_style(gtk_widget_get_style_context(gToolbarWidget),
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR);
++ gtk_style_context_get_style(style,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
++ ReleaseStyleContext(style);
+
++ style = ClaimStyleContext(MOZ_GTK_TOOLBAR_SEPARATOR, direction);
+ if (wide_separators) {
+ if (separator_width > rect->width)
+ separator_width = rect->width;
+@@ -1840,7 +1589,7 @@ moz_gtk_toolbar_separator_paint(cairo_t
+ rect->x + (rect->width - paint_width) / 2,
+ rect->y + rect->height * end_fraction);
+ }
+-
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1848,14 +1597,10 @@ static gint
+ moz_gtk_tooltip_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_tooltip_widget();
+- gtk_widget_set_direction(gTooltipWidget, direction);
+-
+- style = gtk_widget_get_style_context(gTooltipWidget);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLTIP, direction);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1870,14 +1615,11 @@ moz_gtk_resizer_paint(cairo_t *cr, GdkRe
+ // GTK_STYLE_CLASS_VIEW to match the background with textarea elements.
+ // The resizer is drawn with shaded variants of the background color, and
+ // so a transparent background would lead to a transparent resizer.
+- ensure_text_view_widget();
+- gtk_widget_set_direction(gTextViewWidget, GTK_TEXT_DIR_LTR);
+-
+- style = gtk_widget_get_style_context(gTextViewWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_VIEW);
++ style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW, GTK_TEXT_DIR_LTR,
++ GetStateFlagsFromGtkWidgetState(state));
++ // TODO - we need to save/restore style when gtk 3.20 CSS node path
++ // is used
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
+- gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+
+ // Workaround unico not respecting the text direction for resizers.
+ // See bug 1174248.
+@@ -1891,7 +1633,7 @@ moz_gtk_resizer_paint(cairo_t *cr, GdkRe
+
+ gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height);
+ cairo_restore(cr);
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -1900,16 +1642,9 @@ static gint
+ moz_gtk_frame_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_frame_widget();
+- gtk_widget_set_direction(gFrameWidget, direction);
+- style = gtk_widget_get_style_context(gFrameWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);
+-
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_FRAME, direction);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1917,18 +1652,11 @@ static gint
+ moz_gtk_progressbar_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+- ensure_progress_widget();
+- gtk_widget_set_direction(gProgressWidget, direction);
+-
+- style = gtk_widget_get_style_context(gProgressWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
+-
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_PROGRESS_TROUGH,
++ direction);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -1940,13 +1668,15 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
+ {
+ GtkStyleContext* style;
+
+- ensure_progress_widget();
+- gtk_widget_set_direction(gProgressWidget, direction);
+-
+- style = gtk_widget_get_style_context(gProgressWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR);
++ if (gtk_check_version(3, 20, 0) != nullptr) {
++ /* Ask for MOZ_GTK_PROGRESS_TROUGH instead of MOZ_GTK_PROGRESSBAR
++ * because ClaimStyleContext() saves/restores that style */
++ style = ClaimStyleContext(MOZ_GTK_PROGRESS_TROUGH, direction);
++ gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR);
++ } else {
++ style = ClaimStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction);
++ }
+
+ if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
+ widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
+@@ -1990,7 +1720,7 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
+ } else {
+ gtk_render_activity(style, cr, rect->x, rect->y, rect->width, rect->height);
+ }
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -2324,10 +2054,10 @@ moz_gtk_menu_bar_paint(cairo_t *cr, GdkR
+ {
+ GtkStyleContext* style;
+
+- ensure_menu_bar_widget();
+- gtk_widget_set_direction(gMenuBarWidget, direction);
++ GtkWidget* widget = GetWidget(MOZ_GTK_MENUBAR);
++ gtk_widget_set_direction(widget, direction);
+
+- style = gtk_widget_get_style_context(gMenuBarWidget);
++ style = gtk_widget_get_style_context(widget);
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+@@ -2343,14 +2073,14 @@ moz_gtk_menu_popup_paint(cairo_t *cr, Gd
+ {
+ GtkStyleContext* style;
+
+- ensure_menu_popup_widget();
+- gtk_widget_set_direction(gMenuPopupWidget, direction);
++ GtkWidget* widget = GetWidget(MOZ_GTK_MENUPOPUP);
++ gtk_widget_set_direction(widget, direction);
+
+ // Draw a backing toplevel. This fixes themes that don't provide a menu
+ // background, and depend on the GtkMenu's implementation window to provide it.
+ moz_gtk_window_paint(cr, rect, direction);
+
+- style = gtk_widget_get_style_context(gMenuPopupWidget);
++ style = gtk_widget_get_style_context(widget);
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENU);
+
+@@ -2373,12 +2103,10 @@ moz_gtk_menu_separator_paint(cairo_t *cr
+ gint x, y, w;
+ GtkBorder padding;
+
+- ensure_menu_separator_widget();
+- gtk_widget_set_direction(gMenuSeparatorWidget, direction);
+-
+- border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget));
+-
+- style = gtk_widget_get_style_context(gMenuSeparatorWidget);
++ border_width =
++ gtk_container_get_border_width(GTK_CONTAINER(
++ GetWidget(MOZ_GTK_MENUSEPARATOR)));
++ style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR, direction);
+ gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
+
+ x = rect->x + border_width;
+@@ -2408,42 +2136,36 @@ moz_gtk_menu_separator_paint(cairo_t *cr
+ }
+
+ gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+
+ // See gtk_menu_item_draw() for reference.
+ static gint
+-moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
+- GtkWidgetState* state,
+- gint flags, GtkTextDirection direction)
++moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect,
++ GtkWidgetState* state, GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+- GtkWidget* item_widget;
+- guint border_width;
+ gint x, y, w, h;
+
+ if (state->inHover && !state->disabled) {
+- if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
+- ensure_menu_bar_item_widget();
+- item_widget = gMenuBarItemWidget;
+- } else {
+- ensure_menu_item_widget();
+- item_widget = gMenuItemWidget;
+- }
+- style = gtk_widget_get_style_context(item_widget);
+- gtk_style_context_save(style);
++ guint border_width =
++ gtk_container_get_border_width(GTK_CONTAINER(GetWidget(widget)));
++ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
++ GtkStyleContext* style =
++ ClaimStyleContext(widget, direction, state_flags);
+
+- if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
++ bool pre_3_6 = gtk_check_version(3, 6, 0) != nullptr;
++ if (pre_3_6) {
++ // GTK+ 3.4 saves the style context and adds the menubar class to
++ // menubar children, but does each of these only when drawing, not
++ // during layout.
++ gtk_style_context_save(style);
++ if (widget == MOZ_GTK_MENUBARITEM) {
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
++ }
+ }
+
+- gtk_widget_set_direction(item_widget, direction);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM);
+- gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+-
+- border_width = gtk_container_get_border_width(GTK_CONTAINER(item_widget));
+-
+ x = rect->x + border_width;
+ y = rect->y + border_width;
+ w = rect->width - border_width * 2;
+@@ -2451,7 +2173,11 @@ moz_gtk_menu_item_paint(cairo_t *cr, Gdk
+
+ gtk_render_background(style, cr, x, y, w, h);
+ gtk_render_frame(style, cr, x, y, w, h);
+- gtk_style_context_restore(style);
++
++ if (pre_3_6) {
++ gtk_style_context_restore(style);
++ }
++ ReleaseStyleContext(style);
+ }
+
+ return MOZ_GTK_SUCCESS;
+@@ -2462,21 +2188,13 @@ moz_gtk_menu_arrow_paint(cairo_t *cr, Gd
+ GtkWidgetState* state,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+-
+- ensure_menu_item_widget();
+- gtk_widget_set_direction(gMenuItemWidget, direction);
+-
+- style = gtk_widget_get_style_context(gMenuItemWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM);
+- gtk_style_context_set_state(style, state_flags);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_MENUITEM,
++ direction, state_flags);
+ gtk_render_arrow(style, cr,
+ (direction == GTK_TEXT_DIR_LTR) ? ARROW_RIGHT : ARROW_LEFT,
+ rect->x, rect->y, rect->width);
+- gtk_style_context_restore(style);
+-
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -2494,7 +2212,7 @@ moz_gtk_check_menu_item_paint(cairo_t *c
+ gint indicator_size, horizontal_padding;
+ gint x, y;
+
+- moz_gtk_menu_item_paint(cr, rect, state, FALSE, direction);
++ moz_gtk_menu_item_paint(MOZ_GTK_MENUITEM, cr, rect, state, direction);
+
+ ensure_check_menu_item_widget();
+ gtk_widget_set_direction(gCheckMenuItemWidget, direction);
+@@ -2545,21 +2263,13 @@ static gint
+ moz_gtk_info_bar_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkWidgetState* state)
+ {
+- GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+- GtkStyleContext *style;
+- ensure_info_bar();
+-
+- style = gtk_widget_get_style_context(gInfoBar);
+- gtk_style_context_save(style);
+-
+- gtk_style_context_set_state(style, state_flags);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO);
+-
++ GtkStyleContext *style =
++ ClaimStyleContext(MOZ_GTK_INFO_BAR, GTK_TEXT_DIR_LTR,
++ GetStateFlagsFromGtkWidgetState(state));
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width,
+ rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+-
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -2605,18 +2315,18 @@ moz_gtk_get_widget_border(WidgetNodeType
+ case MOZ_GTK_BUTTON:
+ case MOZ_GTK_TOOLBAR_BUTTON:
+ {
+- ensure_button_widget();
+- style = gtk_widget_get_style_context(gButtonWidget);
++ style = ClaimStyleContext(MOZ_GTK_BUTTON);
+
+- *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
++ *left = *top = *right = *bottom =
++ gtk_container_get_border_width(GTK_CONTAINER(GetWidget(MOZ_GTK_BUTTON)));
+
+ if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, "image-button");
+ }
+-
++
+ moz_gtk_add_style_padding(style, left, top, right, bottom);
+-
++
+ if (widget == MOZ_GTK_TOOLBAR_BUTTON)
+ gtk_style_context_restore(style);
+
+@@ -2624,12 +2334,13 @@ moz_gtk_get_widget_border(WidgetNodeType
+ // -moz-focus-inner border (Bug 1228281).
+ *left -= 1; *top -= 1; *right -= 1; *bottom -= 1;
+ moz_gtk_add_style_border(style, left, top, right, bottom);
++
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_ENTRY:
+ {
+- ensure_entry_widget();
+- style = gtk_widget_get_style_context(gEntryWidget);
++ style = ClaimStyleContext(MOZ_GTK_ENTRY);
+
+ // XXX: Subtract 1 pixel from the padding to account for the default
+ // padding in forms.css. See bug 1187385.
+@@ -2637,16 +2348,15 @@ moz_gtk_get_widget_border(WidgetNodeType
+ moz_gtk_add_style_padding(style, left, top, right, bottom);
+ moz_gtk_add_style_border(style, left, top, right, bottom);
+
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
++ case MOZ_GTK_TEXT_VIEW:
+ case MOZ_GTK_TREEVIEW:
+ {
+- ensure_scrolled_window_widget();
+- style = gtk_widget_get_style_context(gScrolledWindowWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);
++ style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW);
+ moz_gtk_add_style_border(style, left, top, right, bottom);
+- gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_TREE_HEADER_CELL:
+@@ -2726,14 +2436,12 @@ moz_gtk_get_widget_border(WidgetNodeType
+ w = gTabWidget;
+ break;
+ case MOZ_GTK_PROGRESSBAR:
+- ensure_progress_widget();
+- w = gProgressWidget;
++ w = GetWidget(MOZ_GTK_PROGRESSBAR);
+ break;
+ case MOZ_GTK_SPINBUTTON_ENTRY:
+ case MOZ_GTK_SPINBUTTON_UP:
+ case MOZ_GTK_SPINBUTTON_DOWN:
+- ensure_spin_widget();
+- w = gSpinWidget;
++ w = GetWidget(MOZ_GTK_SPINBUTTON);
+ break;
+ case MOZ_GTK_SCALE_HORIZONTAL:
+ ensure_scale_widget();
+@@ -2744,8 +2452,7 @@ moz_gtk_get_widget_border(WidgetNodeType
+ w = gVScaleWidget;
+ break;
+ case MOZ_GTK_FRAME:
+- ensure_frame_widget();
+- w = gFrameWidget;
++ w = GetWidget(MOZ_GTK_FRAME);
+ break;
+ case MOZ_GTK_CHECKBUTTON_CONTAINER:
+ case MOZ_GTK_RADIOBUTTON_CONTAINER:
+@@ -2761,19 +2468,17 @@ moz_gtk_get_widget_border(WidgetNodeType
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_MENUPOPUP:
+- ensure_menu_popup_widget();
+- w = gMenuPopupWidget;
++ w = GetWidget(MOZ_GTK_MENUPOPUP);
+ break;
++ case MOZ_GTK_MENUBARITEM:
+ case MOZ_GTK_MENUITEM:
+ case MOZ_GTK_CHECKMENUITEM:
+ case MOZ_GTK_RADIOMENUITEM:
+ {
+- if (widget == MOZ_GTK_MENUITEM) {
+- ensure_menu_item_widget();
+- ensure_menu_bar_item_widget();
+- w = gMenuItemWidget;
+- }
+- else {
++ if (widget == MOZ_GTK_MENUBARITEM || widget == MOZ_GTK_MENUITEM) {
++ // Bug 1274143 for MOZ_GTK_MENUBARITEM
++ w = GetWidget(MOZ_GTK_MENUITEM);
++ } else {
+ ensure_check_menu_item_widget();
+ w = gCheckMenuItemWidget;
+ }
+@@ -2784,9 +2489,16 @@ moz_gtk_get_widget_border(WidgetNodeType
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_INFO_BAR:
+- ensure_info_bar();
+- w = gInfoBar;
++ w = GetWidget(MOZ_GTK_INFO_BAR);
+ break;
++ case MOZ_GTK_TOOLTIP:
++ {
++ style = ClaimStyleContext(MOZ_GTK_TOOLTIP);
++ moz_gtk_add_style_border(style, left, top, right, bottom);
++ moz_gtk_add_style_padding(style, left, top, right, bottom);
++ ReleaseStyleContext(style);
++ return MOZ_GTK_SUCCESS;
++ }
+ /* These widgets have no borders, since they are not containers. */
+ case MOZ_GTK_CHECKBUTTON_LABEL:
+ case MOZ_GTK_RADIOBUTTON_LABEL:
+@@ -2810,7 +2522,6 @@ moz_gtk_get_widget_border(WidgetNodeType
+ case MOZ_GTK_MENUSEPARATOR:
+ /* These widgets have no borders.*/
+ case MOZ_GTK_SPINBUTTON:
+- case MOZ_GTK_TOOLTIP:
+ case MOZ_GTK_WINDOW:
+ case MOZ_GTK_RESIZER:
+ case MOZ_GTK_MENUARROW:
+@@ -2908,8 +2619,7 @@ moz_gtk_get_arrow_size(WidgetNodeType wi
+ widget = gComboBoxArrowWidget;
+ break;
+ default:
+- ensure_button_arrow_widget();
+- widget = gButtonArrowWidget;
++ widget = GetWidget(MOZ_GTK_BUTTON_ARROW);
+ break;
+ }
+
+@@ -2924,11 +2634,9 @@ moz_gtk_get_toolbar_separator_width(gint
+ {
+ gboolean wide_separators;
+ gint separator_width;
+- GtkStyleContext* style;
+ GtkBorder border;
+
+- ensure_toolbar_widget();
+- style = gtk_widget_get_style_context(gToolbarWidget);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR);
+ gtk_style_context_get_style(style,
+ "space-size", size,
+ "wide-separators", &wide_separators,
+@@ -2937,17 +2645,18 @@ moz_gtk_get_toolbar_separator_width(gint
+ /* Just in case... */
+ gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
+ *size = MAX(*size, (wide_separators ? separator_width : border.left));
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+ gint
+ moz_gtk_get_expander_size(gint* size)
+ {
+- ensure_expander_widget();
+- gtk_style_context_get_style(gtk_widget_get_style_context(gExpanderWidget),
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_EXPANDER);
++ gtk_style_context_get_style(style,
+ "expander-size", size,
+ NULL);
+-
++ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -2972,11 +2681,11 @@ moz_gtk_get_menu_separator_height(gint *
+ GtkStyleContext* style;
+ guint border_width;
+
+- ensure_menu_separator_widget();
+-
+- border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget));
++ border_width =
++ gtk_container_get_border_width(GTK_CONTAINER(
++ GetWidget(MOZ_GTK_MENUSEPARATOR)));
+
+- style = gtk_widget_get_style_context(gMenuSeparatorWidget);
++ style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR);
+ gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
+
+ gtk_style_context_save(style);
+@@ -2988,6 +2697,7 @@ moz_gtk_get_menu_separator_height(gint *
+ NULL);
+
+ gtk_style_context_restore(style);
++ ReleaseStyleContext(style);
+
+ *size = padding.top + padding.bottom + border_width*2;
+ *size += (wide_separators) ? separator_height : 1;
+@@ -2998,8 +2708,7 @@ moz_gtk_get_menu_separator_height(gint *
+ void
+ moz_gtk_get_entry_min_height(gint* height)
+ {
+- ensure_entry_widget();
+- GtkStyleContext* style = gtk_widget_get_style_context(gEntryWidget);
++ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_ENTRY);
+ if (!gtk_check_version(3, 20, 0)) {
+ gtk_style_context_get(style, gtk_style_context_get_state(style),
+ "min-height", height,
+@@ -3014,6 +2723,7 @@ moz_gtk_get_entry_min_height(gint* heigh
+ gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
+
+ *height += (border.top + border.bottom + padding.top + padding.bottom);
++ ReleaseStyleContext(style);
+ }
+
+ void
+@@ -3094,8 +2804,7 @@ moz_gtk_images_in_buttons()
+ gboolean result;
+ GtkSettings* settings;
+
+- ensure_button_widget();
+- settings = gtk_widget_get_settings(gButtonWidget);
++ settings = gtk_widget_get_settings(GetWidget(MOZ_GTK_BUTTON));
+
+ g_object_get(settings, "gtk-button-images", &result, NULL);
+ return result;
+@@ -3116,14 +2825,14 @@ moz_gtk_widget_paint(WidgetNodeType widg
+ case MOZ_GTK_BUTTON:
+ case MOZ_GTK_TOOLBAR_BUTTON:
+ if (state->depressed) {
+- ensure_toggle_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+ (GtkReliefStyle) flags,
+- gToggleButtonWidget, direction);
++ GetWidget(MOZ_GTK_TOGGLE_BUTTON),
++ direction);
+ }
+- ensure_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+- (GtkReliefStyle) flags, gButtonWidget,
++ (GtkReliefStyle) flags,
++ GetWidget(MOZ_GTK_BUTTON),
+ direction);
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+@@ -3171,9 +2880,9 @@ moz_gtk_widget_paint(WidgetNodeType widg
+ state, direction);
+ break;
+ case MOZ_GTK_SPINBUTTON_ENTRY:
+- ensure_spin_widget();
++ // TODO - use MOZ_GTK_SPINBUTTON_ENTRY style directly
+ return moz_gtk_entry_paint(cr, rect, state,
+- gSpinWidget, direction);
++ GetWidget(MOZ_GTK_SPINBUTTON), direction);
+ break;
+ case MOZ_GTK_GRIPPER:
+ return moz_gtk_gripper_paint(cr, rect, state,
+@@ -3198,9 +2907,11 @@ moz_gtk_widget_paint(WidgetNodeType widg
+ (GtkExpanderStyle) flags, direction);
+ break;
+ case MOZ_GTK_ENTRY:
+- ensure_entry_widget();
+- return moz_gtk_entry_paint(cr, rect, state,
+- gEntryWidget, direction);
++ return moz_gtk_entry_paint(cr, rect, state, GetWidget(MOZ_GTK_ENTRY),
++ direction);
++ break;
++ case MOZ_GTK_TEXT_VIEW:
++ return moz_gtk_text_view_paint(cr, rect, state, direction);
+ break;
+ case MOZ_GTK_DROPDOWN:
+ return moz_gtk_combo_box_paint(cr, rect, state, direction);
+@@ -3271,9 +2982,9 @@ moz_gtk_widget_paint(WidgetNodeType widg
+ return moz_gtk_menu_separator_paint(cr, rect,
+ direction);
+ break;
++ case MOZ_GTK_MENUBARITEM:
+ case MOZ_GTK_MENUITEM:
+- return moz_gtk_menu_item_paint(cr, rect, state, flags,
+- direction);
++ return moz_gtk_menu_item_paint(widget, cr, rect, state, direction);
+ break;
+ case MOZ_GTK_MENUARROW:
+ return moz_gtk_menu_arrow_paint(cr, rect, state,
+@@ -3333,25 +3044,16 @@ gboolean moz_gtk_has_scrollbar_buttons(v
+ gint
+ moz_gtk_shutdown()
+ {
+- if (gTooltipWidget)
+- gtk_widget_destroy(gTooltipWidget);
+ /* This will destroy all of our widgets */
+-
+ ResetWidgetCache();
+
+ /* TODO - replace it with appropriate widget */
+ if (gTreeHeaderSortArrowWidget)
+ gtk_widget_destroy(gTreeHeaderSortArrowWidget);
+
+- gProtoWindow = NULL;
+ gProtoLayout = NULL;
+- gButtonWidget = NULL;
+- gToggleButtonWidget = NULL;
+- gButtonArrowWidget = NULL;
+- gSpinWidget = NULL;
+ gHScaleWidget = NULL;
+ gVScaleWidget = NULL;
+- gEntryWidget = NULL;
+ gComboBoxWidget = NULL;
+ gComboBoxButtonWidget = NULL;
+ gComboBoxSeparatorWidget = NULL;
+@@ -3360,29 +3062,15 @@ moz_gtk_shutdown()
+ gComboBoxEntryButtonWidget = NULL;
+ gComboBoxEntryArrowWidget = NULL;
+ gComboBoxEntryTextareaWidget = NULL;
+- gHandleBoxWidget = NULL;
+- gToolbarWidget = NULL;
+- gFrameWidget = NULL;
+- gProgressWidget = NULL;
+ gTabWidget = NULL;
+- gTextViewWidget = nullptr;
+- gTooltipWidget = NULL;
+- gMenuBarWidget = NULL;
+- gMenuBarItemWidget = NULL;
+- gMenuPopupWidget = NULL;
+- gMenuItemWidget = NULL;
+ gImageMenuItemWidget = NULL;
+ gCheckMenuItemWidget = NULL;
+ gTreeViewWidget = NULL;
+ gMiddleTreeViewColumn = NULL;
+ gTreeHeaderCellWidget = NULL;
+ gTreeHeaderSortArrowWidget = NULL;
+- gExpanderWidget = NULL;
+- gToolbarSeparatorWidget = NULL;
+- gMenuSeparatorWidget = NULL;
+ gHPanedWidget = NULL;
+ gVPanedWidget = NULL;
+- gScrolledWindowWidget = NULL;
+
+ is_initialized = FALSE;
+
+diff -up firefox-48.0/widget/gtk/gtkdrawing.h.gtk3-20 firefox-48.0/widget/gtk/gtkdrawing.h
+--- firefox-48.0/widget/gtk/gtkdrawing.h.gtk3-20 2016-07-25 22:22:07.000000000 +0200
++++ firefox-48.0/widget/gtk/gtkdrawing.h 2016-07-29 09:15:11.822285857 +0200
+@@ -69,12 +69,6 @@ typedef enum {
+ MOZ_GTK_TAB_SELECTED = 1 << 10
+ } GtkTabFlags;
+
+-/** flags for menuitems **/
+-typedef enum {
+- /* menuitem is part of the menubar */
+- MOZ_TOPLEVEL_MENU_ITEM = 1 << 0
+-} GtkMenuItemFlags;
+-
+ /* function type for moz_gtk_enable_style_props */
+ typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint);
+
+@@ -93,6 +87,10 @@ typedef enum {
+ MOZ_GTK_BUTTON,
+ /* Paints a button with image and no text */
+ MOZ_GTK_TOOLBAR_BUTTON,
++ /* Paints a toggle button */
++ MOZ_GTK_TOGGLE_BUTTON,
++ /* Paints a button arrow */
++ MOZ_GTK_BUTTON_ARROW,
+
+ /* Paints the container part of a GtkCheckButton. */
+ MOZ_GTK_CHECKBUTTON_CONTAINER,
+@@ -115,6 +113,7 @@ typedef enum {
+
+ /* Horizontal GtkScrollbar counterparts */
+ MOZ_GTK_SCROLLBAR_HORIZONTAL,
++ MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL,
+ /* Paints the trough (track) of a GtkScrollbar. */
+ MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL,
+ /* Paints the slider (thumb) of a GtkScrollbar. */
+@@ -122,6 +121,7 @@ typedef enum {
+
+ /* Vertical GtkScrollbar counterparts */
+ MOZ_GTK_SCROLLBAR_VERTICAL,
++ MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL,
+ MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL,
+ MOZ_GTK_SCROLLBAR_THUMB_VERTICAL,
+
+@@ -140,6 +140,10 @@ typedef enum {
+ MOZ_GTK_GRIPPER,
+ /* Paints a GtkEntry. */
+ MOZ_GTK_ENTRY,
++ /* Paints a GtkExpander. */
++ MOZ_GTK_EXPANDER,
++ /* Paints a GtkTextView. */
++ MOZ_GTK_TEXT_VIEW,
+ /* Paints a GtkOptionMenu. */
+ MOZ_GTK_DROPDOWN,
+ /* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */
+@@ -159,6 +163,8 @@ typedef enum {
+ MOZ_GTK_RESIZER,
+ /* Paints a GtkProgressBar. */
+ MOZ_GTK_PROGRESSBAR,
++ /* Paints a trough (track) of a GtkProgressBar */
++ MOZ_GTK_PROGRESS_TROUGH,
+ /* Paints a progress chunk of a GtkProgressBar. */
+ MOZ_GTK_PROGRESS_CHUNK,
+ /* Paints a progress chunk of an indeterminated GtkProgressBar. */
+@@ -187,7 +193,9 @@ typedef enum {
+ MOZ_GTK_MENUARROW,
+ /* Paints an arrow in a toolbar button. flags is a GtkArrowType. */
+ MOZ_GTK_TOOLBARBUTTON_ARROW,
+- /* Paints items of menubar and popups. */
++ /* Paints items of menubar. */
++ MOZ_GTK_MENUBARITEM,
++ /* Paints items of popup menus. */
+ MOZ_GTK_MENUITEM,
+ MOZ_GTK_CHECKMENUITEM,
+ MOZ_GTK_RADIOMENUITEM,
+@@ -202,6 +210,8 @@ typedef enum {
+ MOZ_GTK_WINDOW_CONTAINER,
+ /* Paints a GtkInfoBar, for notifications. */
+ MOZ_GTK_INFO_BAR,
++ /* Used for scrolled window shell. */
++ MOZ_GTK_SCROLLED_WINDOW,
+
+ MOZ_GTK_WIDGET_NODE_COUNT
+ } WidgetNodeType;
+diff -up firefox-48.0/widget/gtk/mozgtk/mozgtk.c.gtk3-20 firefox-48.0/widget/gtk/mozgtk/mozgtk.c
+--- firefox-48.0/widget/gtk/mozgtk/mozgtk.c.gtk3-20 2016-07-25 22:22:07.000000000 +0200
++++ firefox-48.0/widget/gtk/mozgtk/mozgtk.c 2016-07-29 09:15:11.823285862 +0200
+@@ -517,6 +517,7 @@ STUB(gdk_event_get_source_device)
+ STUB(gdk_window_get_type)
+ STUB(gdk_x11_window_get_xid)
+ STUB(gdk_x11_display_get_type)
++STUB(gtk_box_new)
+ STUB(gtk_cairo_should_draw_window)
+ STUB(gtk_cairo_transform_to_window)
+ STUB(gtk_combo_box_text_append)
+@@ -570,6 +571,7 @@ STUB(gtk_tree_view_column_get_button)
+ STUB(gtk_widget_get_preferred_size)
+ STUB(gtk_widget_get_state_flags)
+ STUB(gtk_widget_get_style_context)
++STUB(gtk_widget_path_append_for_widget)
+ STUB(gtk_widget_path_append_type)
+ STUB(gtk_widget_path_copy)
+ STUB(gtk_widget_path_free)
+@@ -587,6 +589,10 @@ STUB(gtk_color_chooser_get_type)
+ STUB(gtk_color_chooser_set_rgba)
+ STUB(gtk_color_chooser_get_rgba)
+ STUB(gtk_color_chooser_set_use_alpha)
++STUB(gtk_check_menu_item_new)
++STUB(gtk_style_context_get_direction)
++STUB(gtk_style_context_invalidate)
++STUB(gtk_tooltip_get_type)
+ #endif
+
+ #ifdef GTK2_SYMBOLS
+diff -up firefox-48.0/widget/gtk/nsLookAndFeel.cpp.gtk3-20 firefox-48.0/widget/gtk/nsLookAndFeel.cpp
+--- firefox-48.0/widget/gtk/nsLookAndFeel.cpp.gtk3-20 2016-06-01 06:11:44.000000000 +0200
++++ firefox-48.0/widget/gtk/nsLookAndFeel.cpp 2016-07-29 09:15:54.943459700 +0200
+@@ -31,6 +31,7 @@
+
+ #if MOZ_WIDGET_GTK != 2
+ #include <cairo-gobject.h>
++#include "WidgetStyleCache.h"
+ #endif
+
+ using mozilla::LookAndFeel;
+@@ -1135,15 +1136,24 @@ nsLookAndFeel::Init()
+ gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
+ sMozWindowText = GDK_RGBA_TO_NS_RGBA(color);
+ gtk_style_context_restore(style);
++ g_object_unref(style);
+
+ // tooltip foreground and background
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
++ style = ClaimStyleContext(MOZ_GTK_TOOLTIP);
+ gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
+ sInfoBackground = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ {
++ GtkStyleContext* boxStyle =
++ CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0),
++ style);
++ GtkStyleContext* labelStyle =
++ CreateStyleForWidget(gtk_label_new(nullptr), boxStyle);
++ gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color);
++ g_object_unref(labelStyle);
++ g_object_unref(boxStyle);
++ }
+ sInfoText = GDK_RGBA_TO_NS_RGBA(color);
+- g_object_unref(style);
++ ReleaseStyleContext(style);
+
+ // menu foreground & menu background
+ GtkWidget *accel_label = gtk_accel_label_new("M");
+diff -up firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp.gtk3-20 firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp
+--- firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp.gtk3-20 2016-07-25 22:22:07.000000000 +0200
++++ firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp 2016-07-29 09:15:11.824285865 +0200
+@@ -354,10 +354,8 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
+
+ if (isTopLevel) {
+ aState->inHover = menuFrame->IsOpen();
+- *aWidgetFlags |= MOZ_TOPLEVEL_MENU_ITEM;
+ } else {
+ aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+- *aWidgetFlags &= ~MOZ_TOPLEVEL_MENU_ITEM;
+ }
+
+ aState->active = FALSE;
+@@ -510,8 +508,14 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
+ break;
+ case NS_THEME_NUMBER_INPUT:
+ case NS_THEME_TEXTFIELD:
++ aGtkWidgetType = MOZ_GTK_ENTRY;
++ break;
+ case NS_THEME_TEXTFIELD_MULTILINE:
++#if (MOZ_WIDGET_GTK == 3)
++ aGtkWidgetType = MOZ_GTK_TEXT_VIEW;
++#else
+ aGtkWidgetType = MOZ_GTK_ENTRY;
++#endif
+ break;
+ case NS_THEME_LISTBOX:
+ case NS_THEME_TREEVIEW:
+@@ -673,6 +677,13 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
+ aGtkWidgetType = MOZ_GTK_MENUPOPUP;
+ break;
+ case NS_THEME_MENUITEM:
++ {
++ nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
++ if (menuFrame && menuFrame->IsOnMenuBar()) {
++ aGtkWidgetType = MOZ_GTK_MENUBARITEM;
++ break;
++ }
++ }
+ aGtkWidgetType = MOZ_GTK_MENUITEM;
+ break;
+ case NS_THEME_MENUSEPARATOR:
+diff -up firefox-48.0/widget/gtk/WidgetStyleCache.cpp.gtk3-20 firefox-48.0/widget/gtk/WidgetStyleCache.cpp
+--- firefox-48.0/widget/gtk/WidgetStyleCache.cpp.gtk3-20 2016-07-25 22:22:07.000000000 +0200
++++ firefox-48.0/widget/gtk/WidgetStyleCache.cpp 2016-07-29 09:15:11.825285869 +0200
+@@ -22,7 +22,7 @@ static bool sStyleContextNeedsRestore;
+ static GtkStyleContext* sCurrentStyleContext;
+ #endif
+ static GtkStyleContext*
+-GetStyleInternal(WidgetNodeType aNodeType);
++GetCssNodeStyleInternal(WidgetNodeType aNodeType);
+
+ static GtkWidget*
+ CreateWindowWidget()
+@@ -67,12 +67,175 @@ CreateCheckboxWidget()
+ static GtkWidget*
+ CreateRadiobuttonWidget()
+ {
+- GtkWidget* widget = gtk_radio_button_new_with_label(NULL, "M");
++ GtkWidget* widget = gtk_radio_button_new_with_label(nullptr, "M");
+ AddToWindowContainer(widget);
+ return widget;
+ }
+
+ static GtkWidget*
++CreateMenuBarWidget()
++{
++ GtkWidget* widget = gtk_menu_bar_new();
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateMenuPopupWidget()
++{
++ GtkWidget* widget = gtk_menu_new();
++ gtk_menu_attach_to_widget(GTK_MENU(widget), GetWidget(MOZ_GTK_WINDOW),
++ nullptr);
++ return widget;
++}
++
++static GtkWidget*
++CreateMenuItemWidget(WidgetNodeType aShellType)
++{
++ GtkWidget* widget = gtk_menu_item_new();
++ gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(aShellType)), widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateProgressWidget()
++{
++ GtkWidget* widget = gtk_progress_bar_new();
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateTooltipWidget()
++{
++ MOZ_ASSERT(gtk_check_version(3, 20, 0) != nullptr,
++ "CreateTooltipWidget should be used for Gtk < 3.20 only.");
++ GtkWidget* widget = CreateWindowWidget();
++ GtkStyleContext* style = gtk_widget_get_style_context(widget);
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
++ return widget;
++}
++
++static GtkWidget*
++CreateExpanderWidget()
++{
++ GtkWidget* widget = gtk_expander_new("M");
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateFrameWidget()
++{
++ GtkWidget* widget = gtk_frame_new(nullptr);
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateGripperWidget()
++{
++ GtkWidget* widget = gtk_handle_box_new();
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateToolbarWidget()
++{
++ GtkWidget* widget = gtk_toolbar_new();
++ gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_GRIPPER)), widget);
++ gtk_widget_realize(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateToolbarSeparatorWidget()
++{
++ GtkWidget* widget = GTK_WIDGET(gtk_separator_tool_item_new());
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateInfoBarWidget()
++{
++ GtkWidget* widget = gtk_info_bar_new();
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateButtonWidget()
++{
++ GtkWidget* widget = gtk_button_new_with_label("M");
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateToggleButtonWidget()
++{
++ GtkWidget* widget = gtk_toggle_button_new();
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateButtonArrowWidget()
++{
++ GtkWidget* widget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
++ gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_TOGGLE_BUTTON)), widget);
++ gtk_widget_realize(widget);
++ gtk_widget_show(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateSpinWidget()
++{
++ GtkWidget* widget = gtk_spin_button_new(nullptr, 1, 0);
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateEntryWidget()
++{
++ GtkWidget* widget = gtk_entry_new();
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateScrolledWindowWidget()
++{
++ GtkWidget* widget = gtk_scrolled_window_new(nullptr, nullptr);
++ AddToWindowContainer(widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateTextViewWidget()
++{
++ GtkWidget* widget = gtk_text_view_new();
++ gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_SCROLLED_WINDOW)),
++ widget);
++ return widget;
++}
++
++static GtkWidget*
++CreateMenuSeparatorWidget()
++{
++ GtkWidget* widget = gtk_separator_menu_item_new();
++ gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
++ widget);
++ gtk_widget_realize(widget);
++ return widget;
++}
++
++
++static GtkWidget*
+ CreateWidget(WidgetNodeType aWidgetType)
+ {
+ switch (aWidgetType) {
+@@ -80,16 +243,54 @@ CreateWidget(WidgetNodeType aWidgetType)
+ return CreateWindowWidget();
+ case MOZ_GTK_WINDOW_CONTAINER:
+ return CreateWindowContainerWidget();
++ case MOZ_GTK_CHECKBUTTON_CONTAINER:
++ return CreateCheckboxWidget();
++ case MOZ_GTK_PROGRESSBAR:
++ return CreateProgressWidget();
++ case MOZ_GTK_RADIOBUTTON_CONTAINER:
++ return CreateRadiobuttonWidget();
+ case MOZ_GTK_SCROLLBAR_HORIZONTAL:
+ return CreateScrollbarWidget(aWidgetType,
+ GTK_ORIENTATION_HORIZONTAL);
+ case MOZ_GTK_SCROLLBAR_VERTICAL:
+ return CreateScrollbarWidget(aWidgetType,
+ GTK_ORIENTATION_VERTICAL);
+- case MOZ_GTK_CHECKBUTTON_CONTAINER:
+- return CreateCheckboxWidget();
+- case MOZ_GTK_RADIOBUTTON_CONTAINER:
+- return CreateRadiobuttonWidget();
++ case MOZ_GTK_MENUBAR:
++ return CreateMenuBarWidget();
++ case MOZ_GTK_MENUPOPUP:
++ return CreateMenuPopupWidget();
++ case MOZ_GTK_MENUBARITEM:
++ return CreateMenuItemWidget(MOZ_GTK_MENUBAR);
++ case MOZ_GTK_MENUITEM:
++ return CreateMenuItemWidget(MOZ_GTK_MENUPOPUP);
++ case MOZ_GTK_MENUSEPARATOR:
++ return CreateMenuSeparatorWidget();
++ case MOZ_GTK_EXPANDER:
++ return CreateExpanderWidget();
++ case MOZ_GTK_FRAME:
++ return CreateFrameWidget();
++ case MOZ_GTK_GRIPPER:
++ return CreateGripperWidget();
++ case MOZ_GTK_TOOLBAR:
++ return CreateToolbarWidget();
++ case MOZ_GTK_TOOLBAR_SEPARATOR:
++ return CreateToolbarSeparatorWidget();
++ case MOZ_GTK_INFO_BAR:
++ return CreateInfoBarWidget();
++ case MOZ_GTK_SPINBUTTON:
++ return CreateSpinWidget();
++ case MOZ_GTK_BUTTON:
++ return CreateButtonWidget();
++ case MOZ_GTK_TOGGLE_BUTTON:
++ return CreateToggleButtonWidget();
++ case MOZ_GTK_BUTTON_ARROW:
++ return CreateButtonArrowWidget();
++ case MOZ_GTK_ENTRY:
++ return CreateEntryWidget();
++ case MOZ_GTK_SCROLLED_WINDOW:
++ return CreateScrolledWindowWidget();
++ case MOZ_GTK_TEXT_VIEW:
++ return CreateTextViewWidget();
+ default:
+ /* Not implemented */
+ return nullptr;
+@@ -107,17 +308,42 @@ GetWidget(WidgetNodeType aWidgetType)
+ return widget;
+ }
+
+-static GtkStyleContext*
+-CreateCSSNode(const char* aName, GtkStyleContext *aParentStyle)
++GtkStyleContext*
++CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle)
++{
++ GtkWidgetPath* path = aParentStyle ?
++ gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) :
++ gtk_widget_path_new();
++
++ // Work around https://bugzilla.gnome.org/show_bug.cgi?id=767312
++ // which exists in GTK+ 3.20.
++ gtk_widget_get_style_context(aWidget);
++
++ gtk_widget_path_append_for_widget(path, aWidget);
++ // Release any floating reference on aWidget.
++ g_object_ref_sink(aWidget);
++ g_object_unref(aWidget);
++
++ GtkStyleContext *context = gtk_style_context_new();
++ gtk_style_context_set_path(context, path);
++ gtk_style_context_set_parent(context, aParentStyle);
++ gtk_widget_path_unref(path);
++
++ return context;
++}
++
++GtkStyleContext*
++CreateCSSNode(const char* aName, GtkStyleContext* aParentStyle, GType aType)
+ {
+ static auto sGtkWidgetPathIterSetObjectName =
+ reinterpret_cast<void (*)(GtkWidgetPath *, gint, const char *)>
+ (dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_set_object_name"));
+
+- GtkWidgetPath* path =
+- gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle));
++ GtkWidgetPath* path = aParentStyle ?
++ gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) :
++ gtk_widget_path_new();
+
+- gtk_widget_path_append_type(path, G_TYPE_NONE);
++ gtk_widget_path_append_type(path, aType);
+
+ (*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
+
+@@ -130,95 +356,168 @@ CreateCSSNode(const char* aName, GtkStyl
+ }
+
+ static GtkStyleContext*
+-GetChildNodeStyle(WidgetNodeType aStyleType,
+- WidgetNodeType aWidgetType,
+- const gchar* aStyleClass,
+- WidgetNodeType aParentNodeType)
++CreateChildCSSNode(const char* aName, WidgetNodeType aParentNodeType)
+ {
+- GtkStyleContext* style;
+-
+- if (gtk_check_version(3, 20, 0) != nullptr) {
+- style = gtk_widget_get_style_context(sWidgetStorage[aWidgetType]);
+-
+- gtk_style_context_save(style);
+- MOZ_ASSERT(!sStyleContextNeedsRestore);
+- sStyleContextNeedsRestore = true;
+-
+- gtk_style_context_add_class(style, aStyleClass);
+- }
+- else {
+- style = sStyleStorage[aStyleType];
+- if (!style) {
+- style = CreateCSSNode(aStyleClass, GetStyleInternal(aParentNodeType));
+- MOZ_ASSERT(!sStyleContextNeedsRestore);
+- sStyleStorage[aStyleType] = style;
+- }
+- }
++ return CreateCSSNode(aName, GetCssNodeStyleInternal(aParentNodeType));
++}
+
++static GtkStyleContext*
++GetWidgetStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass)
++{
++ GtkStyleContext* style = gtk_widget_get_style_context(GetWidget(aWidgetType));
++ gtk_style_context_save(style);
++ MOZ_ASSERT(!sStyleContextNeedsRestore);
++ sStyleContextNeedsRestore = true;
++ gtk_style_context_add_class(style, aStyleClass);
+ return style;
+ }
+
++/* GetCssNodeStyleInternal is used by Gtk >= 3.20 */
+ static GtkStyleContext*
+-GetStyleInternal(WidgetNodeType aNodeType)
++GetCssNodeStyleInternal(WidgetNodeType aNodeType)
+ {
++ GtkStyleContext* style = sStyleStorage[aNodeType];
++ if (style)
++ return style;
++
+ switch (aNodeType) {
+- case MOZ_GTK_SCROLLBAR_HORIZONTAL:
+- /* Root CSS node / widget for scrollbars */
++ case MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL:
++ style = CreateChildCSSNode("contents",
++ MOZ_GTK_SCROLLBAR_HORIZONTAL);
+ break;
+ case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
+- return GetChildNodeStyle(aNodeType,
+- MOZ_GTK_SCROLLBAR_HORIZONTAL,
+- GTK_STYLE_CLASS_TROUGH,
+- MOZ_GTK_SCROLLBAR_HORIZONTAL);
+-
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
++ MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL);
++ break;
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+- return GetChildNodeStyle(aNodeType,
+- MOZ_GTK_SCROLLBAR_HORIZONTAL,
+- GTK_STYLE_CLASS_SLIDER,
+- MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL);
+-
+- case MOZ_GTK_SCROLLBAR_VERTICAL:
+- /* Root CSS node / widget for scrollbars */
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
++ MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL);
++ break;
++ case MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL:
++ style = CreateChildCSSNode("contents",
++ MOZ_GTK_SCROLLBAR_VERTICAL);
+ break;
+ case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
+- return GetChildNodeStyle(aNodeType,
+- MOZ_GTK_SCROLLBAR_VERTICAL,
+- GTK_STYLE_CLASS_TROUGH,
+- MOZ_GTK_SCROLLBAR_VERTICAL);
+-
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
++ MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL);
++ break;
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+- return GetChildNodeStyle(aNodeType,
+- MOZ_GTK_SCROLLBAR_VERTICAL,
+- GTK_STYLE_CLASS_SLIDER,
+- MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL);
+-
+- case MOZ_GTK_RADIOBUTTON_CONTAINER:
+- /* Root CSS node / widget for checkboxes */
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
++ MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL);
+ break;
+ case MOZ_GTK_RADIOBUTTON:
+- return GetChildNodeStyle(aNodeType,
+- MOZ_GTK_RADIOBUTTON_CONTAINER,
+- GTK_STYLE_CLASS_RADIO,
+- MOZ_GTK_RADIOBUTTON_CONTAINER);
+- case MOZ_GTK_CHECKBUTTON_CONTAINER:
+- /* Root CSS node / widget for radiobuttons */
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
++ MOZ_GTK_RADIOBUTTON_CONTAINER);
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+- return GetChildNodeStyle(aNodeType,
+- MOZ_GTK_CHECKBUTTON_CONTAINER,
+- GTK_STYLE_CLASS_CHECK,
+- MOZ_GTK_CHECKBUTTON_CONTAINER);
+- default:
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
++ MOZ_GTK_CHECKBUTTON_CONTAINER);
++ break;
++ case MOZ_GTK_PROGRESS_TROUGH:
++ /* Progress bar background (trough) */
++ style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
++ MOZ_GTK_PROGRESSBAR);
++ break;
++ case MOZ_GTK_PROGRESS_CHUNK:
++ style = CreateChildCSSNode("progress",
++ MOZ_GTK_PROGRESS_TROUGH);
+ break;
++ case MOZ_GTK_TOOLTIP:
++ // We create this from the path because GtkTooltipWindow is not public.
++ style = CreateCSSNode("tooltip", nullptr, GTK_TYPE_TOOLTIP);
++ gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
++ break;
++ case MOZ_GTK_GRIPPER:
++ // TODO - create from CSS node
++ return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
++ GTK_STYLE_CLASS_GRIP);
++ case MOZ_GTK_INFO_BAR:
++ // TODO - create from CSS node
++ return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR,
++ GTK_STYLE_CLASS_INFO);
++ case MOZ_GTK_SPINBUTTON_ENTRY:
++ // TODO - create from CSS node
++ return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON,
++ GTK_STYLE_CLASS_ENTRY);
++ case MOZ_GTK_SCROLLED_WINDOW:
++ // TODO - create from CSS node
++ return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
++ GTK_STYLE_CLASS_FRAME);
++ case MOZ_GTK_TEXT_VIEW:
++ // TODO - create from CSS node
++ return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW,
++ GTK_STYLE_CLASS_VIEW);
++ default:
++ // TODO - create style from style path
++ GtkWidget* widget = GetWidget(aNodeType);
++ return gtk_widget_get_style_context(widget);
+ }
+
+- GtkWidget* widget = GetWidget(aNodeType);
+- if (widget) {
+- return gtk_widget_get_style_context(widget);
+- }
++ MOZ_ASSERT(style, "missing style context for node type");
++ sStyleStorage[aNodeType] = style;
++ return style;
++}
+
+- MOZ_ASSERT_UNREACHABLE("missing style context for node type");
+- return nullptr;
++/* GetWidgetStyleInternal is used by Gtk < 3.20 */
++static GtkStyleContext*
++GetWidgetStyleInternal(WidgetNodeType aNodeType)
++{
++ switch (aNodeType) {
++ case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
++ return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
++ GTK_STYLE_CLASS_TROUGH);
++ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
++ return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
++ GTK_STYLE_CLASS_SLIDER);
++ case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
++ return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
++ GTK_STYLE_CLASS_TROUGH);
++ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
++ return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
++ GTK_STYLE_CLASS_SLIDER);
++ case MOZ_GTK_RADIOBUTTON:
++ return GetWidgetStyleWithClass(MOZ_GTK_RADIOBUTTON_CONTAINER,
++ GTK_STYLE_CLASS_RADIO);
++ case MOZ_GTK_CHECKBUTTON:
++ return GetWidgetStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
++ GTK_STYLE_CLASS_CHECK);
++ case MOZ_GTK_PROGRESS_TROUGH:
++ return GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR,
++ GTK_STYLE_CLASS_TROUGH);
++ case MOZ_GTK_TOOLTIP: {
++ GtkStyleContext* style = sStyleStorage[aNodeType];
++ if (style)
++ return style;
++
++ // The tooltip style class is added first in CreateTooltipWidget() so
++ // that gtk_widget_path_append_for_widget() in CreateStyleForWidget()
++ // will find it.
++ GtkWidget* tooltipWindow = CreateTooltipWidget();
++ style = CreateStyleForWidget(tooltipWindow, nullptr);
++ gtk_widget_destroy(tooltipWindow); // Release GtkWindow self-reference.
++ sStyleStorage[aNodeType] = style;
++ return style;
++ }
++ case MOZ_GTK_GRIPPER:
++ return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
++ GTK_STYLE_CLASS_GRIP);
++ case MOZ_GTK_INFO_BAR:
++ return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR,
++ GTK_STYLE_CLASS_INFO);
++ case MOZ_GTK_SPINBUTTON_ENTRY:
++ return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON,
++ GTK_STYLE_CLASS_ENTRY);
++ case MOZ_GTK_SCROLLED_WINDOW:
++ return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
++ GTK_STYLE_CLASS_FRAME);
++ case MOZ_GTK_TEXT_VIEW:
++ return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW,
++ GTK_STYLE_CLASS_VIEW);
++ default:
++ GtkWidget* widget = GetWidget(aNodeType);
++ MOZ_ASSERT(widget);
++ return gtk_widget_get_style_context(widget);
++ }
+ }
+
+ void
+@@ -245,13 +544,39 @@ ResetWidgetCache(void)
+
+ GtkStyleContext*
+ ClaimStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection,
+- StyleFlags aFlags)
++ GtkStateFlags aStateFlags, StyleFlags aFlags)
+ {
+- GtkStyleContext* style = GetStyleInternal(aNodeType);
++ MOZ_ASSERT(!sStyleContextNeedsRestore);
++ GtkStyleContext* style;
++ if (gtk_check_version(3, 20, 0) != nullptr) {
++ style = GetWidgetStyleInternal(aNodeType);
++ } else {
++ style = GetCssNodeStyleInternal(aNodeType);
++ }
+ #ifdef DEBUG
+ MOZ_ASSERT(!sCurrentStyleContext);
+ sCurrentStyleContext = style;
+ #endif
++ GtkStateFlags oldState = gtk_style_context_get_state(style);
++ GtkTextDirection oldDirection = gtk_style_context_get_direction(style);
++ if (oldState != aStateFlags || oldDirection != aDirection) {
++ // From GTK 3.8, set_state() will overwrite the direction, so set
++ // direction after state.
++ gtk_style_context_set_state(style, aStateFlags);
++ gtk_style_context_set_direction(style, aDirection);
++
++ // This invalidate is necessary for unsaved style contexts from GtkWidgets
++ // in pre-3.18 GTK, because automatic invalidation of such contexts
++ // was delayed until a resize event runs.
++ //
++ // https://bugzilla.mozilla.org/show_bug.cgi?id=1272194#c7
++ //
++ // Avoid calling invalidate on saved contexts to avoid performing
++ // build_properties() (in 3.16 stylecontext.c) unnecessarily early.
++ if (!sStyleContextNeedsRestore) {
++ gtk_style_context_invalidate(style);
++ }
++ }
+ return style;
+ }
+
+diff -up firefox-48.0/widget/gtk/WidgetStyleCache.h.gtk3-20 firefox-48.0/widget/gtk/WidgetStyleCache.h
+--- firefox-48.0/widget/gtk/WidgetStyleCache.h.gtk3-20 2016-07-25 22:22:07.000000000 +0200
++++ firefox-48.0/widget/gtk/WidgetStyleCache.h 2016-07-29 09:15:11.825285869 +0200
+@@ -21,10 +21,24 @@ enum : StyleFlags {
+ GtkWidget*
+ GetWidget(WidgetNodeType aNodeType);
+
++/*
++ * Return a new style context based on aWidget, as a child of aParentStyle.
++ * If aWidget still has a floating reference, then it is sunk and released.
++ */
++GtkStyleContext*
++CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle);
++
++// CreateCSSNode is implemented for gtk >= 3.20 only.
++GtkStyleContext*
++CreateCSSNode(const char* aName,
++ GtkStyleContext* aParentStyle,
++ GType aType = G_TYPE_NONE);
++
+ // Callers must call ReleaseStyleContext() on the returned context.
+ GtkStyleContext*
+ ClaimStyleContext(WidgetNodeType aNodeType,
+ GtkTextDirection aDirection = GTK_TEXT_DIR_LTR,
++ GtkStateFlags aStateFlags = GTK_STATE_FLAG_NORMAL,
+ StyleFlags aFlags = NO_STYLE_FLAGS);
+ void
+ ReleaseStyleContext(GtkStyleContext* style);