Blob Blame History Raw
diff -up firefox-50.0/widget/gtk/gtk3drawing.cpp.widget-rebase firefox-50.0/widget/gtk/gtk3drawing.cpp
--- firefox-50.0/widget/gtk/gtk3drawing.cpp.widget-rebase	2016-10-31 21:15:38.000000000 +0100
+++ firefox-50.0/widget/gtk/gtk3drawing.cpp	2016-11-24 11:57:52.033064782 +0100
@@ -18,27 +18,6 @@
 
 #include <math.h>
 
-static GtkWidget* gProtoLayout;
-static GtkWidget* gHScaleWidget;
-static GtkWidget* gVScaleWidget;
-static GtkWidget* gComboBoxWidget;
-static GtkWidget* gComboBoxButtonWidget;
-static GtkWidget* gComboBoxArrowWidget;
-static GtkWidget* gComboBoxSeparatorWidget;
-static GtkWidget* gComboBoxEntryWidget;
-static GtkWidget* gComboBoxEntryTextareaWidget;
-static GtkWidget* gComboBoxEntryButtonWidget;
-static GtkWidget* gComboBoxEntryArrowWidget;
-static GtkWidget* gTabWidget;
-static GtkWidget* gImageMenuItemWidget;
-static GtkWidget* gCheckMenuItemWidget;
-static GtkWidget* gTreeViewWidget;
-static GtkTreeViewColumn* gMiddleTreeViewColumn;
-static GtkWidget* gTreeHeaderCellWidget;
-static GtkWidget* gTreeHeaderSortArrowWidget;
-static GtkWidget* gHPanedWidget;
-static GtkWidget* gVPanedWidget;
-
 static style_prop_t style_prop_func;
 static gboolean have_arrow_scaling;
 static gboolean checkbox_check_state;
@@ -54,6 +33,13 @@ static gboolean is_initialized;
 #define GTK_STATE_FLAG_CHECKED (1 << 11)
 #endif
 
+static gint
+moz_gtk_get_tab_thickness(GtkStyleContext *style);
+
+static gint
+moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect,
+                        GtkWidgetState* state, GtkTextDirection direction);
+
 static GtkStateFlags
 GetStateFlagsFromGtkWidgetState(GtkWidgetState* state)
 {
@@ -73,338 +59,17 @@ GetStateFlagsFromGtkWidgetState(GtkWidge
     return stateFlags;
 }
 
-gint
-moz_gtk_enable_style_props(style_prop_t styleGetProp)
-{
-    style_prop_func = styleGetProp;
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-setup_widget_prototype(GtkWidget* widget)
-{
-    if (!gProtoLayout) {
-        gProtoLayout = GetWidget(MOZ_GTK_WINDOW_CONTAINER);
-    }
-    gtk_container_add(GTK_CONTAINER(gProtoLayout), widget);
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_hpaned_widget()
-{
-    if (!gHPanedWidget) {
-        gHPanedWidget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
-        setup_widget_prototype(gHPanedWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_vpaned_widget()
-{
-    if (!gVPanedWidget) {
-        gVPanedWidget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
-        setup_widget_prototype(gVPanedWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_scale_widget()
-{
-  if (!gHScaleWidget) {
-    gHScaleWidget = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL);
-    setup_widget_prototype(gHScaleWidget);
-  }
-  if (!gVScaleWidget) {
-    gVScaleWidget = gtk_scale_new(GTK_ORIENTATION_VERTICAL, NULL);
-    setup_widget_prototype(gVScaleWidget);
-  }
-  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
- * to NULL our pointers when they are about to become invalid because the
- * corresponding widgets don't exist anymore. It's the role of
- * 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 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)
-{
-    if (GTK_IS_TOGGLE_BUTTON(widget)) {
-        gComboBoxButtonWidget = widget;
-        g_object_add_weak_pointer(G_OBJECT(widget),
-                                  (gpointer *) &gComboBoxButtonWidget);
-        gtk_widget_realize(widget);
-    }
-}
-
-static void
-moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
-                                           gpointer client_data)
-{
-    if (GTK_IS_SEPARATOR(widget)) {
-        gComboBoxSeparatorWidget = widget;
-        g_object_add_weak_pointer(G_OBJECT(widget),
-                                  (gpointer *) &gComboBoxSeparatorWidget);
-    } else if (GTK_IS_ARROW(widget)) {
-        gComboBoxArrowWidget = widget;
-        g_object_add_weak_pointer(G_OBJECT(widget),
-                                  (gpointer *) &gComboBoxArrowWidget);
-    } else
-        return;
-    gtk_widget_realize(widget);
-}
-
-static gint
-ensure_combo_box_widgets()
-{
-    GtkWidget* buttonChild;
-
-    if (gComboBoxButtonWidget && gComboBoxArrowWidget)
-        return MOZ_GTK_SUCCESS;
-
-    /* Create a ComboBox if needed */
-    if (!gComboBoxWidget) {
-        gComboBoxWidget = gtk_combo_box_new();
-        setup_widget_prototype(gComboBoxWidget);
-    }
-
-    /* Get its inner Button */
-    gtk_container_forall(GTK_CONTAINER(gComboBoxWidget),
-                         moz_gtk_get_combo_box_inner_button,
-                         NULL);
-
-    if (gComboBoxButtonWidget) {
-        /* Get the widgets inside the Button */
-        buttonChild = gtk_bin_get_child(GTK_BIN(gComboBoxButtonWidget));
-        if (GTK_IS_BOX(buttonChild)) {
-            /* appears-as-list = FALSE, cell-view = TRUE; the button
-             * contains an hbox. This hbox is there because the ComboBox
-             * needs to place a cell renderer, a separator, and an arrow in
-             * the button when appears-as-list is FALSE. */
-            gtk_container_forall(GTK_CONTAINER(buttonChild),
-                                 moz_gtk_get_combo_box_button_inner_widgets,
-                                 NULL);
-        } else if(GTK_IS_ARROW(buttonChild)) {
-            /* appears-as-list = TRUE, or cell-view = FALSE;
-             * the button only contains an arrow */
-            gComboBoxArrowWidget = buttonChild;
-            g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer *)
-                                      &gComboBoxArrowWidget);
-            gtk_widget_realize(gComboBoxArrowWidget);
-        }
-    } else {
-        /* Shouldn't be reached with current internal gtk implementation; we
-         * use a generic toggle button as last resort fallback to avoid
-         * crashing. */
-        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. */
-        gComboBoxArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW);
-    }
-
-    /* We don't test the validity of gComboBoxSeparatorWidget since there
-     * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
-     * is invalid we just won't paint it. */
-
-    return MOZ_GTK_SUCCESS;
-}
-
-/* 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
- * to NULL our pointers when they are about to become invalid because the
- * corresponding widgets don't exist anymore. It's the role of
- * 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 gProtoLayout and as
- * such GTK holds a strong reference to them. */
-static void
-moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
-                                          gpointer client_data)
-{
-    if (GTK_IS_TOGGLE_BUTTON(widget)) {
-        gComboBoxEntryButtonWidget = widget;
-        g_object_add_weak_pointer(G_OBJECT(widget),
-                                  (gpointer *) &gComboBoxEntryButtonWidget);
-    } else if (GTK_IS_ENTRY(widget)) {
-        gComboBoxEntryTextareaWidget = widget;
-        g_object_add_weak_pointer(G_OBJECT(widget),
-                                  (gpointer *) &gComboBoxEntryTextareaWidget);
-    } else
-        return;
-    gtk_widget_realize(widget);
-}
-
-static void
-moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data)
-{
-    if (GTK_IS_ARROW(widget)) {
-        gComboBoxEntryArrowWidget = widget;
-        g_object_add_weak_pointer(G_OBJECT(widget),
-                                  (gpointer *) &gComboBoxEntryArrowWidget);
-        gtk_widget_realize(widget);
-    }
-}
-
-static gint
-ensure_combo_box_entry_widgets()
-{
-    GtkWidget* buttonChild;
-
-    if (gComboBoxEntryTextareaWidget &&
-            gComboBoxEntryButtonWidget &&
-            gComboBoxEntryArrowWidget)
-        return MOZ_GTK_SUCCESS;
-
-    /* Create a ComboBoxEntry if needed */
-    if (!gComboBoxEntryWidget) {
-        gComboBoxEntryWidget = gtk_combo_box_new_with_entry();
-        setup_widget_prototype(gComboBoxEntryWidget);
-    }
-
-    /* Get its inner Entry and Button */
-    gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget),
-                         moz_gtk_get_combo_box_entry_inner_widgets,
-                         NULL);
-
-    if (!gComboBoxEntryTextareaWidget) {
-        gComboBoxEntryTextareaWidget = GetWidget(MOZ_GTK_ENTRY);
-    }
-
-    if (gComboBoxEntryButtonWidget) {
-        /* Get the Arrow inside the Button */
-        buttonChild = gtk_bin_get_child(GTK_BIN(gComboBoxEntryButtonWidget));
-        if (GTK_IS_BOX(buttonChild)) {
-           /* appears-as-list = FALSE, cell-view = TRUE; the button
-             * contains an hbox. This hbox is there because the ComboBox
-             * needs to place a cell renderer, a separator, and an arrow in
-             * the button when appears-as-list is FALSE. */
-            gtk_container_forall(GTK_CONTAINER(buttonChild),
-                                 moz_gtk_get_combo_box_entry_arrow,
-                                 NULL);
-        } else if(GTK_IS_ARROW(buttonChild)) {
-            /* appears-as-list = TRUE, or cell-view = FALSE;
-             * the button only contains an arrow */
-            gComboBoxEntryArrowWidget = buttonChild;
-            g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer *)
-                                      &gComboBoxEntryArrowWidget);
-            gtk_widget_realize(gComboBoxEntryArrowWidget);
-        }
-    } else {
-        /* Shouldn't be reached with current internal gtk implementation;
-         * we use a generic toggle button as last resort fallback to avoid
-         * crashing. */
-        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. */
-        gComboBoxEntryArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW);
-    }
-
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_tab_widget()
-{
-    if (!gTabWidget) {
-        gTabWidget = gtk_notebook_new();
-        setup_widget_prototype(gTabWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_image_menu_item_widget()
-{
-    if (!gImageMenuItemWidget) {
-        gImageMenuItemWidget = gtk_image_menu_item_new();
-        gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
-                              gImageMenuItemWidget);
-        gtk_widget_realize(gImageMenuItemWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_check_menu_item_widget()
-{
-    if (!gCheckMenuItemWidget) {
-        gCheckMenuItemWidget = gtk_check_menu_item_new();
-        gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
-                              gCheckMenuItemWidget);
-        gtk_widget_realize(gCheckMenuItemWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_tree_view_widget()
+static GtkStateFlags
+GetStateFlagsFromGtkTabFlags(GtkTabFlags flags)
 {
-    if (!gTreeViewWidget) {
-        gTreeViewWidget = gtk_tree_view_new();
-        setup_widget_prototype(gTreeViewWidget);
-    }
-    return MOZ_GTK_SUCCESS;
+    return ((flags & MOZ_GTK_TAB_SELECTED) == 0) ?
+            GTK_STATE_FLAG_NORMAL : GTK_STATE_FLAG_ACTIVE;
 }
 
-static gint
-ensure_tree_header_cell_widget()
+gint
+moz_gtk_enable_style_props(style_prop_t styleGetProp)
 {
-    if(!gTreeHeaderCellWidget) {
-        /*
-         * Some GTK engines paint the first and last cell
-         * of a TreeView header with a highlight.
-         * Since we do not know where our widget will be relative
-         * to the other buttons in the TreeView header, we must
-         * paint it as a button that is between two others,
-         * thus ensuring it is neither the first or last button
-         * in the header.
-         * GTK doesn't give us a way to do this explicitly,
-         * so we must paint with a button that is between two
-         * others.
-         */
-
-        GtkTreeViewColumn* firstTreeViewColumn;
-        GtkTreeViewColumn* lastTreeViewColumn;
-
-        ensure_tree_view_widget();
-
-        /* Create and append our three columns */
-        firstTreeViewColumn = gtk_tree_view_column_new();
-        gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
-        gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn);
-
-        gMiddleTreeViewColumn = gtk_tree_view_column_new();
-        gtk_tree_view_column_set_title(gMiddleTreeViewColumn, "M");
-        gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget),
-                                    gMiddleTreeViewColumn);
-
-        lastTreeViewColumn = gtk_tree_view_column_new();
-        gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
-        gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn);
-
-        /* Use the middle column's header for our button */
-        gTreeHeaderCellWidget = gtk_tree_view_column_get_button(gMiddleTreeViewColumn);
-        /* TODO, but it can't be NULL */
-        gTreeHeaderSortArrowWidget = gtk_button_new();
-    }
+    style_prop_func = styleGetProp;
     return MOZ_GTK_SUCCESS;
 }
 
@@ -423,13 +88,17 @@ moz_gtk_init()
     else
         checkbox_check_state = GTK_STATE_FLAG_ACTIVE;
 
-    if(!gtk_check_version(3, 12, 0)) {
-        ensure_tab_widget();
-        gtk_style_context_get_style(gtk_widget_get_style_context(gTabWidget),
+    if (gtk_check_version(3, 12, 0) == nullptr &&
+        gtk_check_version(3, 20, 0) != nullptr)
+    {
+        // Deprecated for Gtk >= 3.20+
+        GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_TAB_TOP);
+        gtk_style_context_get_style(style,
                                     "has-tab-gap", &notebook_has_tab_gap, NULL);
+        ReleaseStyleContext(style);
     }
     else {
-        notebook_has_tab_gap = TRUE;
+        notebook_has_tab_gap = true;
     }
 
     return MOZ_GTK_SUCCESS;
@@ -455,16 +124,24 @@ moz_gtk_radio_get_metrics(gint* indicato
     return MOZ_GTK_SUCCESS;
 }
 
-gint
-moz_gtk_get_focus_outline_size(gint* focus_h_width, gint* focus_v_width)
+static gint
+moz_gtk_get_focus_outline_size(GtkStyleContext* style,
+                               gint* focus_h_width, gint* focus_v_width)
 {
     GtkBorder border;
     GtkBorder padding;
-    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;
+    return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_focus_outline_size(gint* focus_h_width, gint* focus_v_width)
+{
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_ENTRY);
+    moz_gtk_get_focus_outline_size(style, focus_h_width, focus_v_width);
     ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
@@ -472,22 +149,22 @@ moz_gtk_get_focus_outline_size(gint* foc
 gint
 moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding)
 {
-    gtk_widget_style_get(GetWidget(MOZ_GTK_MENUITEM),
-                         "horizontal-padding", horizontal_padding,
-                         nullptr);
-
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_MENUITEM);
+    gtk_style_context_get_style(style,
+                                "horizontal-padding", horizontal_padding,
+                                nullptr);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
 gint
 moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding)
 {
-    ensure_check_menu_item_widget();
-
-    gtk_style_context_get_style(gtk_widget_get_style_context(gCheckMenuItemWidget),
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_CHECKMENUITEM);
+    gtk_style_context_get_style(style,
                                 "horizontal-padding", horizontal_padding,
-                                NULL);
-
+                                nullptr);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -543,15 +220,14 @@ moz_gtk_button_get_default_border(gint*
 gint
 moz_gtk_splitter_get_metrics(gint orientation, gint* size)
 {
+    GtkStyleContext *style;
     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
-        ensure_hpaned_widget();
-        gtk_style_context_get_style(gtk_widget_get_style_context(gHPanedWidget),
-                                    "handle_size", size, NULL);
+        style = ClaimStyleContext(MOZ_GTK_SPLITTER_HORIZONTAL);
     } else {
-        ensure_vpaned_widget();
-        gtk_style_context_get_style(gtk_widget_get_style_context(gVPanedWidget),
-                                    "handle_size", size, NULL);
+        style = ClaimStyleContext(MOZ_GTK_SPLITTER_VERTICAL);
     }
+    gtk_style_context_get_style(style, "handle_size", size, NULL);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -756,8 +432,66 @@ calculate_arrow_rect(GtkWidget* arrow, G
     return MOZ_GTK_SUCCESS;
 }
 
+void
+moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width,
+                            int* height)
+{
+  GtkStyleContext* style = ClaimStyleContext(aGtkWidgetType);
+  GtkStateFlags state_flags = gtk_style_context_get_state(style);
+  gtk_style_context_get(style, state_flags,
+                        "min-height", height,
+                        "min-width", width,
+                        nullptr);
+
+  GtkBorder border, padding, margin;
+  gtk_style_context_get_border(style, state_flags, &border);
+  gtk_style_context_get_padding(style, state_flags, &padding);
+  gtk_style_context_get_margin(style, state_flags,  &margin);
+  ReleaseStyleContext(style);
+
+  *width += border.left + border.right + margin.left + margin.right +
+            padding.left + padding.right;
+  *height += border.top + border.bottom + margin.top + margin.bottom +
+             padding.top + padding.bottom;
+}
+
+static void
+Inset(GdkRectangle* rect, GtkBorder& aBorder)
+{
+    MOZ_ASSERT(rect);
+    rect->x += aBorder.left;
+    rect->y += aBorder.top;
+    rect->width -= aBorder.left + aBorder.right;
+    rect->height -= aBorder.top + aBorder.bottom;
+}
+
+// Inset a rectangle by the margins specified in a style context.
+static void
+InsetByMargin(GdkRectangle* rect, GtkStyleContext* style)
+{
+    MOZ_ASSERT(rect);
+    GtkBorder margin;
+
+    gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
+                                 &margin);
+    Inset(rect, margin);
+}
+
+// Inset a rectangle by the border and padding specified in a style context.
+static void
+InsetByBorderPadding(GdkRectangle* rect, GtkStyleContext* style)
+{
+    GtkStateFlags state = gtk_style_context_get_state(style);
+    GtkBorder padding, border;
+
+    gtk_style_context_get_padding(style, state, &padding);
+    Inset(rect, padding);
+    gtk_style_context_get_border(style, state, &border);
+    Inset(rect, border);
+}
+
 static gint
-moz_gtk_scrollbar_button_paint(cairo_t *cr, GdkRectangle* rect,
+moz_gtk_scrollbar_button_paint(cairo_t *cr, const GdkRectangle* aRect,
                                GtkWidgetState* state,
                                GtkScrollbarButtonFlags flags,
                                GtkTextDirection direction)
@@ -795,32 +529,38 @@ moz_gtk_scrollbar_button_paint(cairo_t *
         gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOP);
     }
 
-    /* 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;
+    GdkRectangle rect = *aRect;
+    if (gtk_check_version(3,20,0) == nullptr) {
+      // The "trough-border" is not used since GTK 3.20.  The stepper margin
+      // box occupies the full width of the "contents" gadget content box.
+      InsetByMargin(&rect, style);
     } 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).
+      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;
+      }
     }
 
-    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_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);
 
-    arrow_rect.width = rect->width / 2;
-    arrow_rect.height = rect->height / 2;
+    arrow_rect.width = rect.width / 2;
+    arrow_rect.height = rect.height / 2;
     
     gfloat arrow_scaling;
     gtk_style_context_get_style(style, "arrow-scaling", &arrow_scaling, NULL);
 
-    gdouble arrow_size = MIN(rect->width, rect->height) * arrow_scaling;
-    arrow_rect.x = rect->x + (rect->width - arrow_size) / 2;
-    arrow_rect.y = rect->y + (rect->height - arrow_size) / 2;
+    gdouble arrow_size = MIN(rect.width, rect.height) * arrow_scaling;
+    arrow_rect.x = rect.x + (rect.width - arrow_size) / 2;
+    arrow_rect.y = rect.y + (rect.height - arrow_size) / 2;
 
     if (state_flags & GTK_STATE_FLAG_ACTIVE) {
         gtk_style_context_get_style(style,
@@ -862,19 +602,23 @@ moz_gtk_update_scrollbar_style(GtkStyleC
 
 static void
 moz_gtk_draw_styled_frame(GtkStyleContext* style, cairo_t *cr,
-                          GdkRectangle* rect, bool drawFocus)
+                          const GdkRectangle* aRect, 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);
+    GdkRectangle rect = *aRect;
+    if (gtk_check_version(3, 6, 0) == nullptr) {
+        InsetByMargin(&rect, 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);
     if (drawFocus) {
         gtk_render_focus(style, cr,
-                         rect->x, rect->y, rect->width, rect->height);
+                         rect.x, rect.y, rect.width, rect.height);
     }
 }
 
 static gint
 moz_gtk_scrollbar_trough_paint(WidgetNodeType widget,
-                               cairo_t *cr, GdkRectangle* rect,
+                               cairo_t *cr, const GdkRectangle* rect,
                                GtkWidgetState* state,
                                GtkScrollbarTrackFlags flags,
                                GtkTextDirection direction)
@@ -886,26 +630,28 @@ moz_gtk_scrollbar_trough_paint(WidgetNod
         ReleaseStyleContext(style);
     }
 
-    bool isHorizontal = (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL);
-    GtkStyleContext* style;
+    GtkStyleContext* style = ClaimStyleContext(widget, direction);
+    moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
+    ReleaseStyleContext(style);
 
-    // 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);
+    return MOZ_GTK_SUCCESS;
+}
 
-        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,
+static gint
+moz_gtk_scrollbar_paint(WidgetNodeType widget,
+                        cairo_t *cr, const GdkRectangle* rect,
+                        GtkWidgetState* state,
+                        GtkTextDirection direction)
+{
+    GtkStyleContext* style = ClaimStyleContext(widget, direction);
+    moz_gtk_update_scrollbar_style(style, widget, direction);
+
+    moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
+
+    ReleaseStyleContext(style);
+    style = ClaimStyleContext((widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) ?
+                              MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL :
+                              MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL,
                               direction);
     moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
     ReleaseStyleContext(style);
@@ -915,21 +661,21 @@ moz_gtk_scrollbar_trough_paint(WidgetNod
 
 static gint
 moz_gtk_scrollbar_thumb_paint(WidgetNodeType widget,
-                              cairo_t *cr, GdkRectangle* rect,
+                              cairo_t *cr, const GdkRectangle* aRect,
                               GtkWidgetState* state,
                               GtkTextDirection direction)
 {
     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
-    GtkBorder margin;
 
+    GdkRectangle rect = *aRect;
     GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags);
-    gtk_style_context_get_margin (style, state_flags, &margin);
+    InsetByMargin(&rect, style);
 
     gtk_render_slider(style, cr,
-                      rect->x + margin.left,
-                      rect->y + margin.top,
-                      rect->width - margin.left - margin.right,
-                      rect->height - margin.top - margin.bottom,
+                      rect.x,
+                      rect.y,
+                      rect.width,
+                      rect.height,
                      (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
                      GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
 
@@ -987,18 +733,15 @@ moz_gtk_scale_paint(cairo_t *cr, GdkRect
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
   gint x, y, width, height, min_width, min_height;
   GtkStyleContext* style;
-  GtkWidget* widget;
   GtkBorder margin;
 
-  ensure_scale_widget();
-  widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
-  gtk_widget_set_direction(widget, direction);
   moz_gtk_get_scale_metrics(flags, &min_width, &min_height);
 
-  style = gtk_widget_get_style_context(widget);
-  gtk_style_context_save(style);
-  gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
-  gtk_style_context_get_margin(style, state_flags, &margin); 
+  WidgetNodeType widget = (flags == GTK_ORIENTATION_HORIZONTAL) ?
+                          MOZ_GTK_SCALE_TROUGH_HORIZONTAL :
+                          MOZ_GTK_SCALE_TROUGH_VERTICAL;
+  style = ClaimStyleContext(widget, direction, state_flags);
+  gtk_style_context_get_margin(style, state_flags, &margin);
 
   // Clamp the dimension perpendicular to the direction that the slider crosses
   // to the minimum size.
@@ -1020,7 +763,8 @@ moz_gtk_scale_paint(cairo_t *cr, GdkRect
   if (state->focused)
     gtk_render_focus(style, cr, 
                     rect->x, rect->y, rect->width, rect->height);
-  gtk_style_context_restore(style);
+
+  ReleaseStyleContext(style);
   return MOZ_GTK_SUCCESS;
 }
 
@@ -1031,17 +775,8 @@ moz_gtk_scale_thumb_paint(cairo_t *cr, G
 {
   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
   GtkStyleContext* style;
-  GtkWidget* widget;
   gint thumb_width, thumb_height, x, y;
 
-  ensure_scale_widget();
-  widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
-  gtk_widget_set_direction(widget, direction);
-
-  style = gtk_widget_get_style_context(widget);
-  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 
   */
   if (flags == GTK_ORIENTATION_HORIZONTAL) {
@@ -1055,8 +790,13 @@ moz_gtk_scale_thumb_paint(cairo_t *cr, G
     y = rect->y;
   }
 
+  WidgetNodeType widget = (flags == GTK_ORIENTATION_HORIZONTAL) ?
+                          MOZ_GTK_SCALE_THUMB_HORIZONTAL :
+                          MOZ_GTK_SCALE_THUMB_VERTICAL;
+  style = ClaimStyleContext(widget, direction, state_flags);
   gtk_render_slider(style, cr, x, y, thumb_width, thumb_height, flags);
-  gtk_style_context_restore(style);
+  ReleaseStyleContext(style);
+
   return MOZ_GTK_SUCCESS;
 }
 
@@ -1078,17 +818,13 @@ static gint
 moz_gtk_hpaned_paint(cairo_t *cr, GdkRectangle* rect,
                      GtkWidgetState* state)
 {
-    GtkStyleContext* style;
-    
-    ensure_hpaned_widget();
-    style = gtk_widget_get_style_context(gHPanedWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_PANE_SEPARATOR);
-    gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+    GtkStyleContext* style =
+        ClaimStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL,
+                          GTK_TEXT_DIR_LTR,
+                          GetStateFlagsFromGtkWidgetState(state));
     gtk_render_handle(style, cr,
                       rect->x, rect->y, rect->width, rect->height);
-    gtk_style_context_restore(style);
-
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1096,17 +832,13 @@ static gint
 moz_gtk_vpaned_paint(cairo_t *cr, GdkRectangle* rect,
                      GtkWidgetState* state)
 {
-    GtkStyleContext* style;
-
-    ensure_vpaned_widget();
-    style = gtk_widget_get_style_context(gVPanedWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_PANE_SEPARATOR);
-    gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+    GtkStyleContext* style =
+        ClaimStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL,
+                          GTK_TEXT_DIR_LTR,
+                          GetStateFlagsFromGtkWidgetState(state));
     gtk_render_handle(style, cr,
                       rect->x, rect->y, rect->width, rect->height);                     
-    gtk_style_context_restore(style);
-
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1114,60 +846,26 @@ moz_gtk_vpaned_paint(cairo_t *cr, GdkRec
 static gint
 moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect,
                     GtkWidgetState* state,
-                    GtkWidget* widget, GtkTextDirection direction)
+                    GtkStyleContext* style)
 {
     gint x = rect->x, y = rect->y, width = rect->width, height = rect->height;
-    GtkStyleContext* style;
     int draw_focus_outline_only = state->depressed; // NS_THEME_FOCUS_OUTLINE
 
-    gtk_widget_set_direction(widget, direction);
-
-    style = gtk_widget_get_style_context(widget);
-
     if (draw_focus_outline_only) {
         // Inflate the given 'rect' with the focus outline size.
         gint h, v;
-        moz_gtk_get_focus_outline_size(&h, &v);
+        moz_gtk_get_focus_outline_size(style, &h, &v);
         rect->x -= h;
         rect->width += 2 * h;
         rect->y -= v;
         rect->height += 2 * v;
         width = rect->width;
         height = rect->height;
-    }
-
-    /* gtkentry.c uses two windows, one for the entire widget and one for the
-     * text area inside it. The background of both windows is set to the "base"
-     * color of the new state in gtk_entry_state_changed, but only the inner
-     * textarea window uses gtk_paint_flat_box when exposed */
-
-    /* This gets us a lovely greyish disabledish look */
-    gtk_widget_set_sensitive(widget, !state->disabled);
-
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_ENTRY);
-  
-    /* Now paint the shadow and focus border.
-     * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
-     * smaller when focused if the focus is not interior, then the focus. */
-
-    if (state->focused && !state->disabled) {
-        /* This will get us the lit borders that focused textboxes enjoy on
-         * some themes. */
-        gtk_style_context_set_state(style, GTK_STATE_FLAG_FOCUSED);
-    }
-
-    if (state->disabled) {
-        gtk_style_context_set_state(style, GTK_STATE_FLAG_INSENSITIVE);
-    }
-
-    if (!draw_focus_outline_only) {
+    } else {
         gtk_render_background(style, cr, x, y, width, height);
     }
     gtk_render_frame(style, cr, x, y, width, height);
 
-    gtk_style_context_restore(style);
-
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1214,9 +912,6 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkR
     GtkStateFlags state_flags;
     GtkBorder border;
 
-    ensure_tree_view_widget();
-    gtk_widget_set_direction(gTreeViewWidget, 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;
@@ -1225,19 +920,19 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkR
     gtk_style_context_get_border(style, state_flags, &border);
     xthickness = border.left;
     ythickness = border.top;    
+    ReleaseStyleContext(style);
 
-    style_tree = gtk_widget_get_style_context(gTreeViewWidget);
-    gtk_style_context_save(style_tree);
-    gtk_style_context_add_class(style_tree, GTK_STYLE_CLASS_VIEW);
-    
+    style_tree = ClaimStyleContext(MOZ_GTK_TREEVIEW_VIEW, direction);
     gtk_render_background(style_tree, cr,
                           rect->x + xthickness, rect->y + ythickness,
                           rect->width - 2 * xthickness,
                           rect->height - 2 * ythickness);
+    ReleaseStyleContext(style_tree);
+
+    style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction);
     gtk_render_frame(style, cr, 
                      rect->x, rect->y, rect->width, rect->height); 
     ReleaseStyleContext(style);
-    gtk_style_context_restore(style_tree);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1247,7 +942,7 @@ moz_gtk_tree_header_cell_paint(cairo_t *
                                gboolean isSorted, GtkTextDirection direction)
 {
     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
-                         gTreeHeaderCellWidget, direction);
+                         GetWidget(MOZ_GTK_TREE_HEADER_CELL), direction);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1260,18 +955,13 @@ moz_gtk_tree_header_sort_arrow_paint(cai
     gdouble arrow_angle;
     GtkStyleContext* style;
 
-    ensure_tree_header_cell_widget();
-    gtk_widget_set_direction(gTreeHeaderSortArrowWidget, direction);
-
     /* hard code these values */
     arrow_rect.width = 11;
     arrow_rect.height = 11;
     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
-    style = gtk_widget_get_style_context(gTreeHeaderSortArrowWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
-
+    style = ClaimStyleContext(MOZ_GTK_TREE_HEADER_SORTARROW, direction,
+                              GetStateFlagsFromGtkWidgetState(state));
     switch (arrow_type) {
     case GTK_ARROW_LEFT:
         arrow_angle = ARROW_LEFT;
@@ -1290,7 +980,7 @@ moz_gtk_tree_header_sort_arrow_paint(cai
         gtk_render_arrow(style, cr, arrow_angle,
                          arrow_rect.x, arrow_rect.y,
                          arrow_rect.width);
-    gtk_style_context_restore(style);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1302,37 +992,28 @@ moz_gtk_treeview_expander_paint(cairo_t
                                 GtkExpanderStyle expander_state,
                                 GtkTextDirection direction)
 {
-    GtkStyleContext *style;
-    GtkStateFlags    state_flags;
-
-    ensure_tree_view_widget();
-    gtk_widget_set_direction(gTreeViewWidget, direction);
-
-    style = gtk_widget_get_style_context(gTreeViewWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_EXPANDER);
-
     /* Because the frame we get is of the entire treeview, we can't get the precise
      * event state of one expander, thus rendering hover and active feedback useless. */
-    state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL;
+    GtkStateFlags state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE :
+                                                  GTK_STATE_FLAG_NORMAL;
 
     /* GTK_STATE_FLAG_ACTIVE controls expanded/colapsed state rendering
      * in gtk_render_expander()
      */
     if (expander_state == GTK_EXPANDER_EXPANDED)
-        state_flags = static_cast<GtkStateFlags>(state_flags|GTK_STATE_FLAG_ACTIVE);
+        state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
     else
-        state_flags = static_cast<GtkStateFlags>(state_flags&~(GTK_STATE_FLAG_ACTIVE));
-
-    gtk_style_context_set_state(style, state_flags);
+        state_flags = static_cast<GtkStateFlags>(state_flags&~(checkbox_check_state));
 
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_TREEVIEW_EXPANDER,
+                                               direction, state_flags);
     gtk_render_expander(style, cr,
                         rect->x,
                         rect->y,
                         rect->width,
                         rect->height);
 
-    gtk_style_context_restore(style);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1349,34 +1030,37 @@ moz_gtk_combo_box_paint(cairo_t *cr, Gdk
     GtkStyleContext* style;
     GtkRequisition arrow_req;
 
-    ensure_combo_box_widgets();
+    GtkWidget* comboBoxButton = GetWidget(MOZ_GTK_COMBOBOX_BUTTON);
+    GtkWidget* comboBoxArrow = GetWidget(MOZ_GTK_COMBOBOX_ARROW);
 
     /* Also sets the direction on gComboBoxButtonWidget, which is then
      * inherited by the separator and arrow */
     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
-                         gComboBoxButtonWidget, direction);
+                         comboBoxButton, direction);
 
-    calculate_button_inner_rect(gComboBoxButtonWidget,
-                                rect, &arrow_rect, direction);
+    calculate_button_inner_rect(comboBoxButton, rect, &arrow_rect, direction);
     /* Now arrow_rect contains the inner rect ; we want to correct the width
      * to what the arrow needs (see gtk_combo_box_size_allocate) */
-    gtk_widget_get_preferred_size(gComboBoxArrowWidget, NULL, &arrow_req);
+    gtk_widget_get_preferred_size(comboBoxArrow, NULL, &arrow_req);
+
     if (direction == GTK_TEXT_DIR_LTR)
         arrow_rect.x += arrow_rect.width - arrow_req.width;
     arrow_rect.width = arrow_req.width;
 
-    calculate_arrow_rect(gComboBoxArrowWidget,
+    calculate_arrow_rect(comboBoxArrow,
                          &arrow_rect, &real_arrow_rect, direction);
 
-    style = gtk_widget_get_style_context(gComboBoxArrowWidget);
+    style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ARROW);
     gtk_render_arrow(style, cr, ARROW_DOWN,
                      real_arrow_rect.x, real_arrow_rect.y,
                      real_arrow_rect.width);
+    ReleaseStyleContext(style);
 
     /* If there is no separator in the theme, there's nothing left to do. */
-    if (!gComboBoxSeparatorWidget)
+    GtkWidget* widget = GetWidget(MOZ_GTK_COMBOBOX_SEPARATOR);
+    if (!widget)
         return MOZ_GTK_SUCCESS;
-    style = gtk_widget_get_style_context(gComboBoxSeparatorWidget);
+    style = gtk_widget_get_style_context(widget);
     gtk_style_context_get_style(style,
                                 "wide-separators", &wide_separators,
                                 "separator-width", &separator_width,
@@ -1460,15 +1144,14 @@ moz_gtk_combo_box_entry_button_paint(cai
     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     GtkStyleContext* style;
 
-    ensure_combo_box_entry_widgets();
-
+    GtkWidget* comboBoxEntry = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
-                         gComboBoxEntryButtonWidget, direction);
+                         comboBoxEntry, direction);
+    calculate_button_inner_rect(comboBoxEntry, rect, &arrow_rect, direction);
 
-    calculate_button_inner_rect(gComboBoxEntryButtonWidget,
-                                rect, &arrow_rect, direction);
     if (state_flags & GTK_STATE_FLAG_ACTIVE) {
-        gtk_style_context_get_style(gtk_widget_get_style_context(gComboBoxEntryButtonWidget),
+        style = gtk_widget_get_style_context(comboBoxEntry);
+        gtk_style_context_get_style(style,
                                     "child-displacement-x", &x_displacement,
                                     "child-displacement-y", &y_displacement,
                                     NULL);
@@ -1476,15 +1159,14 @@ moz_gtk_combo_box_entry_button_paint(cai
         arrow_rect.y += y_displacement;
     }
 
-    calculate_arrow_rect(gComboBoxEntryArrowWidget,
+    calculate_arrow_rect(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_ARROW),
                          &arrow_rect, &real_arrow_rect, direction);
 
-    style = gtk_widget_get_style_context(gComboBoxEntryArrowWidget);
-
+    style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_ARROW);
     gtk_render_arrow(style, cr, ARROW_DOWN,
                     real_arrow_rect.x, real_arrow_rect.y,
                     real_arrow_rect.width);
-
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1504,7 +1186,6 @@ moz_gtk_container_paint(cairo_t *cr, Gdk
     }
 
     ReleaseStyleContext(style);
-
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1590,12 +1271,53 @@ moz_gtk_toolbar_separator_paint(cairo_t
 }
 
 static gint
-moz_gtk_tooltip_paint(cairo_t *cr, GdkRectangle* rect,
+moz_gtk_tooltip_paint(cairo_t *cr, const GdkRectangle* aRect,
                       GtkTextDirection direction)
 {
+    // Tooltip widget is made in GTK3 as following tree:
+    // Tooltip window
+    //   Horizontal Box
+    //     Icon (not supported by Firefox)
+    //     Label
+    // Each element can be fully styled by CSS of GTK theme.
+    // We have to draw all elements with appropriate offset and right dimensions.
+
+    // Tooltip drawing
     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);
+    GdkRectangle rect = *aRect;
+    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);
+
+    // Horizontal Box drawing
+    //
+    // The box element has hard-coded 6px margin-* GtkWidget properties, which
+    // are added between the window dimensions and the CSS margin box of the
+    // horizontal box.  The frame of the tooltip window is drawn in the
+    // 6px margin.
+    // For drawing Horizontal Box we have to inset drawing area by that 6px
+    // plus its CSS margin.
+    GtkStyleContext* boxStyle =
+        CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0), style);
+
+    rect.x += 6;
+    rect.y += 6;
+    rect.width -= 12;
+    rect.height -= 12;
+
+    InsetByMargin(&rect, boxStyle);
+    gtk_render_background(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
+    gtk_render_frame(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
+
+    // Label drawing
+    InsetByBorderPadding(&rect, boxStyle);
+
+    GtkStyleContext* labelStyle =
+        CreateStyleForWidget(gtk_label_new(nullptr), boxStyle);
+    moz_gtk_draw_styled_frame(labelStyle, cr, &rect, false);
+    g_object_unref(labelStyle);
+
+    g_object_unref(boxStyle);
+
     ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
@@ -1721,46 +1443,35 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
     return MOZ_GTK_SUCCESS;
 }
 
-gint
-moz_gtk_get_tab_thickness(void)
+static gint
+moz_gtk_get_tab_thickness(GtkStyleContext *style)
 {
-    GtkBorder border;
-    GtkStyleContext * style;
-
-    ensure_tab_widget();
     if (!notebook_has_tab_gap)
       return 0; /* tabs do not overdraw the tabpanel border with "no gap" style */
 
-    style = gtk_widget_get_style_context(gTabWidget);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK);
+    GtkBorder border;
     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
-
     if (border.top < 2)
         return 2; /* some themes don't set ythickness correctly */
 
     return border.top;
 }
 
-static void
-moz_gtk_tab_prepare_style_context(GtkStyleContext *style,
-                                  GtkTabFlags flags)
-{  
-  gtk_style_context_set_state(style, ((flags & MOZ_GTK_TAB_SELECTED) == 0) ? 
-                                        GTK_STATE_FLAG_NORMAL : 
-                                        GTK_STATE_FLAG_ACTIVE);
-  gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, 
-                                      (flags & MOZ_GTK_TAB_FIRST) ? 
-                                        GTK_REGION_FIRST : static_cast<GtkRegionFlags>(0));
-  gtk_style_context_add_class(style, (flags & MOZ_GTK_TAB_BOTTOM) ? 
-                                        GTK_STYLE_CLASS_BOTTOM : 
-                                        GTK_STYLE_CLASS_TOP);
+gint
+moz_gtk_get_tab_thickness(WidgetNodeType aNodeType)
+{
+    GtkStyleContext *style = ClaimStyleContext(aNodeType);
+    int thickness = moz_gtk_get_tab_thickness(style);
+    ReleaseStyleContext(style);
+    return thickness;
 }
 
 /* actual small tabs */
 static gint
 moz_gtk_tab_paint(cairo_t *cr, GdkRectangle* rect,
                   GtkWidgetState* state,
-                  GtkTabFlags flags, GtkTextDirection direction)
+                  GtkTabFlags flags, GtkTextDirection direction,
+                  WidgetNodeType widget)
 {
     /* When the tab isn't selected, we just draw a notebook extension.
      * When it is selected, we overwrite the adjacent border of the tabpanel
@@ -1772,14 +1483,10 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
     GdkRectangle focusRect;
     GdkRectangle backRect;
     int initial_gap = 0;
+    bool isBottomTab = (widget == MOZ_GTK_TAB_BOTTOM);
 
-    ensure_tab_widget();
-    gtk_widget_set_direction(gTabWidget, direction);
-
-    style = gtk_widget_get_style_context(gTabWidget);
-    gtk_style_context_save(style);
-    moz_gtk_tab_prepare_style_context(style, flags);
-
+    style = ClaimStyleContext(widget, direction,
+                              GetStateFlagsFromGtkTabFlags(flags));
     tabRect = *rect;
 
     if (flags & MOZ_GTK_TAB_FIRST) {
@@ -1798,8 +1505,7 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
             /* Only draw the tab */
             gtk_render_extension(style, cr,
                                  tabRect.x, tabRect.y, tabRect.width, tabRect.height,
-                                (flags & MOZ_GTK_TAB_BOTTOM) ?
-                                    GTK_POS_TOP : GTK_POS_BOTTOM );
+                                 isBottomTab ? GTK_POS_TOP : GTK_POS_BOTTOM );
         } else {
             /* Draw the tab and the gap
              * We want the gap to be positioned exactly on the tabpanel top
@@ -1840,7 +1546,7 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
             gint gap_loffset, gap_roffset, gap_voffset, gap_height;
 
             /* Get height needed by the gap */
-            gap_height = moz_gtk_get_tab_thickness();
+            gap_height = moz_gtk_get_tab_thickness(style);
 
             /* Extract gap_voffset from the first bits of flags */
             gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
@@ -1856,7 +1562,7 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
                     gap_loffset = initial_gap;
             }
 
-            if (flags & MOZ_GTK_TAB_BOTTOM) {
+            if (isBottomTab) {
                 /* Draw the tab on bottom */
                 focusRect.y += gap_voffset;
                 focusRect.height -= gap_voffset;
@@ -1920,15 +1626,9 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
         gtk_render_frame(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
     }
 
-    gtk_style_context_restore(style);
-
     if (state->focused) {
       /* Paint the focus ring */
       GtkBorder padding;
-
-      gtk_style_context_save(style);
-      moz_gtk_tab_prepare_style_context(style, flags);
-
       gtk_style_context_get_padding(style, GetStateFlagsFromGtkWidgetState(state), &padding);
 
       focusRect.x += padding.left;
@@ -1938,10 +1638,8 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
 
       gtk_render_focus(style, cr,
                       focusRect.x, focusRect.y, focusRect.width, focusRect.height);
-
-      gtk_style_context_restore(style);
     }
-
+    ReleaseStyleContext(style);
 
     return MOZ_GTK_SUCCESS;
 }
@@ -1951,14 +1649,7 @@ static gint
 moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
                         GtkTextDirection direction)
 {
-    GtkStyleContext* style;
-
-    ensure_tab_widget();
-    gtk_widget_set_direction(gTabWidget, direction);
-
-    style = gtk_widget_get_style_context(gTabWidget);
-    gtk_style_context_save(style);
-
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TABPANELS, direction);
     gtk_render_background(style, cr, rect->x, rect->y, 
                           rect->width, rect->height);
     /*
@@ -1982,7 +1673,7 @@ moz_gtk_tabpanels_paint(cairo_t *cr, Gdk
                          rect->width, rect->height,
                          GTK_POS_TOP, rect->width - 1, rect->width);
     cairo_restore(cr);
-    
+
     /* right side */
     cairo_save(cr);
     cairo_rectangle(cr, rect->x + rect->width / 2, rect->y,
@@ -1995,7 +1686,7 @@ moz_gtk_tabpanels_paint(cairo_t *cr, Gdk
                          GTK_POS_TOP, 0, 1);
     cairo_restore(cr);
 
-    gtk_style_context_restore(style);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -2005,17 +1696,12 @@ moz_gtk_tab_scroll_arrow_paint(cairo_t *
                                GtkArrowType arrow_type,
                                GtkTextDirection direction)
 {
-    GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     GtkStyleContext* style;
     gdouble arrow_angle;
     gint arrow_size = MIN(rect->width, rect->height);
     gint x = rect->x + (rect->width - arrow_size) / 2;
     gint y = rect->y + (rect->height - arrow_size) / 2;
 
-    ensure_tab_widget();
-
-    style = gtk_widget_get_style_context(gTabWidget);
-    gtk_style_context_save(style);
     if (direction == GTK_TEXT_DIR_RTL) {
         arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
                          GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
@@ -2035,12 +1721,12 @@ moz_gtk_tab_scroll_arrow_paint(cairo_t *
         break;      
     }
     if (arrow_type != GTK_ARROW_NONE)  {        
-        gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK); /* TODO TEST */
-        gtk_style_context_set_state(style, state_flags);
+        style = ClaimStyleContext(MOZ_GTK_TAB_SCROLLARROW, direction,
+                                  GetStateFlagsFromGtkWidgetState(state));
         gtk_render_arrow(style, cr, arrow_angle,
                          x, y, arrow_size);
+        ReleaseStyleContext(style);
     }
-    gtk_style_context_restore(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -2092,22 +1778,25 @@ static gint
 moz_gtk_menu_separator_paint(cairo_t *cr, GdkRectangle* rect,
                              GtkTextDirection direction)
 {
+    GtkWidgetState defaultState = { 0 };
+    moz_gtk_menu_item_paint(MOZ_GTK_MENUSEPARATOR, cr, rect,
+                            &defaultState, direction);
+
+    if (gtk_get_minor_version() >= 20)
+        return MOZ_GTK_SUCCESS;
+
     GtkStyleContext* style;
     gboolean wide_separators;
     gint separator_height;
-    guint border_width;
     gint x, y, w;
     GtkBorder padding;
 
-    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;
-    y = rect->y + border_width;
-    w = rect->width - border_width * 2;
+    x = rect->x;
+    y = rect->y;
+    w = rect->width;
 
     gtk_style_context_save(style);
     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SEPARATOR);
@@ -2144,37 +1833,32 @@ moz_gtk_menu_item_paint(WidgetNodeType w
 {
     gint x, y, w, h;
 
-    if (state->inHover && !state->disabled) {   
-        guint border_width =
-            gtk_container_get_border_width(GTK_CONTAINER(GetWidget(widget)));
-        GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
-        GtkStyleContext* style =
-            ClaimStyleContext(widget, direction, state_flags);
-
-        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);
-            }
+    GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+    GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags);
+
+    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);
         }
+    }
 
-        x = rect->x + border_width;
-        y = rect->y + border_width;
-        w = rect->width - border_width * 2;
-        h = rect->height - border_width * 2;
+    x = rect->x;
+    y = rect->y;
+    w = rect->width;
+    h = rect->height;
 
-        gtk_render_background(style, cr, x, y, w, h);
-        gtk_render_frame(style, cr, x, y, w, h);
+    gtk_render_background(style, cr, x, y, w, h);
+    gtk_render_frame(style, cr, x, y, w, h);
 
-        if (pre_3_6) {
-            gtk_style_context_restore(style);
-        }
-        ReleaseStyleContext(style);
+    if (pre_3_6) {
+        gtk_style_context_restore(style);
     }
+    ReleaseStyleContext(style);
 
     return MOZ_GTK_SUCCESS;
 }
@@ -2194,63 +1878,68 @@ moz_gtk_menu_arrow_paint(cairo_t *cr, Gd
     return MOZ_GTK_SUCCESS;
 }
 
-// See gtk_real_check_menu_item_draw_indicator() for reference.
+// For reference, see gtk_check_menu_item_size_allocate() in GTK versions after
+// 3.20 and gtk_real_check_menu_item_draw_indicator() in earlier versions.
 static gint
-moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
+moz_gtk_check_menu_item_paint(WidgetNodeType widgetType,
+                              cairo_t *cr, GdkRectangle* rect,
                               GtkWidgetState* state,
-                              gboolean checked, gboolean isradio,
-                              GtkTextDirection direction)
+                              gboolean checked, GtkTextDirection direction)
 {
     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     GtkStyleContext* style;
-    GtkBorder padding;
-    gint offset;
     gint indicator_size, horizontal_padding;
     gint x, y;
 
     moz_gtk_menu_item_paint(MOZ_GTK_MENUITEM, cr, rect, state, direction);
 
-    ensure_check_menu_item_widget();
-    gtk_widget_set_direction(gCheckMenuItemWidget, direction);
-
-    style = gtk_widget_get_style_context(gCheckMenuItemWidget);
-    gtk_style_context_save(style);
+    if (checked) {
+      state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
+    }
 
+    bool pre_3_20 = gtk_get_minor_version() < 20;
+    gint offset;
+    style = ClaimStyleContext(widgetType, direction);
     gtk_style_context_get_style(style,
                                 "indicator-size", &indicator_size,
                                 "horizontal-padding", &horizontal_padding,
                                 NULL);
-
-    if (isradio) {
-      gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO);
+    if (pre_3_20) {
+        GtkBorder padding;
+        gtk_style_context_get_padding(style, state_flags, &padding);
+        offset = horizontal_padding + padding.left + 2;
     } else {
-      gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK);
-    }
-
-    if (checked) {
-      state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
+        GdkRectangle r = { 0 };
+        InsetByMargin(&r, style);
+        InsetByBorderPadding(&r, style);
+        offset = r.x;
     }
-    
-    gtk_style_context_set_state(style, state_flags);
-    gtk_style_context_get_padding(style, state_flags, &padding);
+    ReleaseStyleContext(style);
 
-    offset = gtk_container_get_border_width(GTK_CONTAINER(gCheckMenuItemWidget)) +
-                                            padding.left + 2;
+    bool isRadio = (widgetType == MOZ_GTK_RADIOMENUITEM);
+    WidgetNodeType indicatorType = isRadio ? MOZ_GTK_RADIOMENUITEM_INDICATOR
+                                           : MOZ_GTK_CHECKMENUITEM_INDICATOR;
+    style = ClaimStyleContext(indicatorType, direction, state_flags);
 
     if (direction == GTK_TEXT_DIR_RTL) {
-        x = rect->width - indicator_size - offset - horizontal_padding;
+        x = rect->width - indicator_size - offset;
     }
     else {
-        x = rect->x + offset + horizontal_padding;
+        x = rect->x + offset;
     }
     y = rect->y + (rect->height - indicator_size) / 2;
 
-    if (isradio) {
+    if (!pre_3_20) {
+        gtk_render_background(style, cr, x, y, indicator_size, indicator_size);
+        gtk_render_frame(style, cr, x, y, indicator_size, indicator_size);
+    }
+
+    if (isRadio) {
       gtk_render_option(style, cr, x, y, indicator_size, indicator_size);
     } else {
       gtk_render_check(style, cr, x, y, indicator_size, indicator_size);
     }
-    gtk_style_context_restore(style);
+    ReleaseStyleContext(style);
 
     return MOZ_GTK_SUCCESS;
 }
@@ -2271,6 +1960,20 @@ moz_gtk_info_bar_paint(cairo_t *cr, GdkR
 }
 
 static void
+moz_gtk_add_style_margin(GtkStyleContext* style,
+                         gint* left, gint* top, gint* right, gint* bottom)
+{
+    GtkBorder margin;
+
+    gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
+
+    *left += margin.left;
+    *right += margin.right;
+    *top += margin.top;
+    *bottom += margin.bottom;
+}
+
+static void
 moz_gtk_add_style_border(GtkStyleContext* style,
                          gint* left, gint* top, gint* right, gint* bottom)
 {
@@ -2298,6 +2001,15 @@ moz_gtk_add_style_padding(GtkStyleContex
     *bottom += padding.bottom;
 }
 
+static void moz_gtk_add_margin_border_padding(GtkStyleContext *style,
+                                              gint* left, gint* top,
+                                              gint* right, gint* bottom)
+{
+    moz_gtk_add_style_margin(style, left, top, right, bottom);
+    moz_gtk_add_style_border(style, left, top, right, bottom);
+    moz_gtk_add_style_padding(style, left, top, right, bottom);
+}
+
 gint
 moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
                           gint* right, gint* bottom, GtkTextDirection direction,
@@ -2362,26 +2074,24 @@ moz_gtk_get_widget_border(WidgetNodeType
              * assigned.
              * That is why the following code is the same as for MOZ_GTK_BUTTON.
              * */
-            ensure_tree_header_cell_widget();
-            *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gTreeHeaderCellWidget));
-
-            style = gtk_widget_get_style_context(gTreeHeaderCellWidget);
+            *left = *top = *right = *bottom =
+                gtk_container_get_border_width(GTK_CONTAINER(
+                                               GetWidget(MOZ_GTK_TREE_HEADER_CELL)));
 
+            style = ClaimStyleContext(MOZ_GTK_TREE_HEADER_CELL);
             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;
         }
     case MOZ_GTK_TREE_HEADER_SORTARROW:
-        ensure_tree_header_cell_widget();
-        w = gTreeHeaderSortArrowWidget;
+        w = GetWidget(MOZ_GTK_TREE_HEADER_SORTARROW);
         break;
     case MOZ_GTK_DROPDOWN_ENTRY:
-        ensure_combo_box_entry_widgets();
-        w = gComboBoxEntryTextareaWidget;
+        w = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA);
         break;
     case MOZ_GTK_DROPDOWN_ARROW:
-        ensure_combo_box_entry_widgets();
-        w = gComboBoxEntryButtonWidget;
+        w = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
         break;
     case MOZ_GTK_DROPDOWN:
         {
@@ -2393,32 +2103,33 @@ moz_gtk_get_widget_border(WidgetNodeType
             GtkRequisition arrow_req;
             GtkBorder border;
 
-            ensure_combo_box_widgets();
-
-            *left = *top = *right = *bottom = 
-                gtk_container_get_border_width(GTK_CONTAINER(gComboBoxButtonWidget));
-
-            style = gtk_widget_get_style_context(gComboBoxButtonWidget);
-
+            *left = *top = *right = *bottom =
+                gtk_container_get_border_width(GTK_CONTAINER(
+                                               GetWidget(MOZ_GTK_COMBOBOX_BUTTON)));
+            style = ClaimStyleContext(MOZ_GTK_COMBOBOX_BUTTON);
             moz_gtk_add_style_padding(style, left, top, right, bottom);
             moz_gtk_add_style_border(style, left, top, right, bottom);
+            ReleaseStyleContext(style);
 
             /* If there is no separator, don't try to count its width. */
             separator_width = 0;
-            if (gComboBoxSeparatorWidget) {
-                style = gtk_widget_get_style_context(gComboBoxSeparatorWidget);
+            GtkWidget* comboBoxSeparator = GetWidget(MOZ_GTK_COMBOBOX_SEPARATOR);
+            if (comboBoxSeparator) {
+                style = gtk_widget_get_style_context(comboBoxSeparator);
                 gtk_style_context_get_style(style,
                                             "wide-separators", &wide_separators,
                                             "separator-width", &separator_width,
                                             NULL);
 
                 if (!wide_separators) {
-                    gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
+                    gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL,
+                                                 &border);
                     separator_width = border.left;
                 }
             }
 
-            gtk_widget_get_preferred_size(gComboBoxArrowWidget, NULL, &arrow_req);
+            gtk_widget_get_preferred_size(GetWidget(MOZ_GTK_COMBOBOX_ARROW),
+                                          NULL, &arrow_req);
 
             if (direction == GTK_TEXT_DIR_RTL)
                 *left += separator_width + arrow_req.width;
@@ -2428,8 +2139,7 @@ moz_gtk_get_widget_border(WidgetNodeType
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_TABPANELS:
-        ensure_tab_widget();
-        w = gTabWidget;
+        w = GetWidget(MOZ_GTK_TABPANELS);
         break;
     case MOZ_GTK_PROGRESSBAR:
         w = GetWidget(MOZ_GTK_PROGRESSBAR);
@@ -2440,12 +2150,8 @@ moz_gtk_get_widget_border(WidgetNodeType
         w = GetWidget(MOZ_GTK_SPINBUTTON);
         break;
     case MOZ_GTK_SCALE_HORIZONTAL:
-        ensure_scale_widget();
-        w = gHScaleWidget;
-        break;
     case MOZ_GTK_SCALE_VERTICAL:
-        ensure_scale_widget();
-        w = gVScaleWidget;
+        w = GetWidget(widget);
         break;
     case MOZ_GTK_FRAME:
         w = GetWidget(MOZ_GTK_FRAME);
@@ -2471,17 +2177,18 @@ moz_gtk_get_widget_border(WidgetNodeType
     case MOZ_GTK_CHECKMENUITEM:
     case MOZ_GTK_RADIOMENUITEM:
         {
-            if (widget == MOZ_GTK_MENUBARITEM || widget == MOZ_GTK_MENUITEM) {
-                // Bug 1274143 for MOZ_GTK_MENUBARITEM
-                w = GetWidget(MOZ_GTK_MENUITEM);
+            // Bug 1274143 for MOZ_GTK_MENUBARITEM
+            WidgetNodeType type =
+                widget == MOZ_GTK_MENUBARITEM ? MOZ_GTK_MENUITEM : widget;
+            style = ClaimStyleContext(type);
+
+            if (gtk_get_minor_version() < 20) {
+                moz_gtk_add_style_padding(style, left, top, right, bottom);
             } else {
-                ensure_check_menu_item_widget();
-                w = gCheckMenuItemWidget;
+                moz_gtk_add_margin_border_padding(style,
+                                                  left, top, right, bottom);
             }
-
-            *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
-            moz_gtk_add_style_padding(gtk_widget_get_style_context(w),
-                                      left, top, right, bottom);
+            ReleaseStyleContext(style);
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_INFO_BAR:
@@ -2490,11 +2197,86 @@ moz_gtk_get_widget_border(WidgetNodeType
     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);
+            // In GTK 3 there are 6 pixels of additional margin around the box.
+            // See details there:
+            // https://github.com/GNOME/gtk/blob/5ea69a136bd7e4970b3a800390e20314665aaed2/gtk/ui/gtktooltipwindow.ui#L11
+            *left = *right = *top = *bottom = 6;
+
+            // We also need to add margin/padding/borders from Tooltip content.
+            // Tooltip contains horizontal box, where icon and label is put.
+            // We ignore icon as long as we don't have support for it.
+            GtkStyleContext* boxStyle =
+                CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0),
+                                     style);
+            moz_gtk_add_margin_border_padding(boxStyle,
+                                              left, top, right, bottom);
+
+            GtkStyleContext* labelStyle =
+                CreateStyleForWidget(gtk_label_new(nullptr), boxStyle);
+            moz_gtk_add_margin_border_padding(labelStyle,
+                                              left, top, right, bottom);
+
+            g_object_unref(labelStyle);
+            g_object_unref(boxStyle);
+
             ReleaseStyleContext(style);
             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:
@@ -2503,10 +2285,6 @@ moz_gtk_get_widget_border(WidgetNodeType
     case MOZ_GTK_CHECKBUTTON:
     case MOZ_GTK_RADIOBUTTON:
     case MOZ_GTK_SCROLLBAR_BUTTON:
-    case MOZ_GTK_SCROLLBAR_HORIZONTAL:
-    case MOZ_GTK_SCROLLBAR_VERTICAL:
-    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:
@@ -2540,35 +2318,48 @@ moz_gtk_get_widget_border(WidgetNodeType
 
 gint
 moz_gtk_get_tab_border(gint* left, gint* top, gint* right, gint* bottom, 
-                       GtkTextDirection direction, GtkTabFlags flags)
+                       GtkTextDirection direction, GtkTabFlags flags, 
+                       WidgetNodeType widget)
 {
-    GtkStyleContext* style;    
-    int tab_curvature;
-
-    ensure_tab_widget();
-
-    style = gtk_widget_get_style_context(gTabWidget);
-    gtk_style_context_save(style);
-    moz_gtk_tab_prepare_style_context(style, flags);
+    GtkStyleContext* style = ClaimStyleContext(widget, direction,
+                              GetStateFlagsFromGtkTabFlags(flags));
 
     *left = *top = *right = *bottom = 0;
     moz_gtk_add_style_padding(style, left, top, right, bottom);
 
-    gtk_style_context_get_style(style, "tab-curvature", &tab_curvature, NULL);
-    *left += tab_curvature;
-    *right += tab_curvature;
+    // Gtk >= 3.20 does not use those styles
+    if (gtk_check_version(3, 20, 0) != nullptr) {
+        int tab_curvature;
 
-    if (flags & MOZ_GTK_TAB_FIRST) {
-      int initial_gap;
-      gtk_style_context_get_style(style, "initial-gap", &initial_gap, NULL);
-      if (direction == GTK_TEXT_DIR_RTL)
-        *right += initial_gap;
-      else
-        *left += initial_gap;
-    }
+        gtk_style_context_get_style(style, "tab-curvature", &tab_curvature, NULL);
+        *left += tab_curvature;
+        *right += tab_curvature;
+
+        if (flags & MOZ_GTK_TAB_FIRST) {
+            int initial_gap = 0;
+            gtk_style_context_get_style(style, "initial-gap", &initial_gap, NULL);
+            if (direction == GTK_TEXT_DIR_RTL)
+                *right += initial_gap;
+            else
+                *left += initial_gap;
+        }
+    } else {
+        GtkBorder margin;
 
-    gtk_style_context_restore(style);
+        gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
+        *left += margin.left;
+        *right += margin.right;
 
+        if (flags & MOZ_GTK_TAB_FIRST) {
+            ReleaseStyleContext(style);
+            style = ClaimStyleContext(MOZ_GTK_NOTEBOOK_HEADER, direction);
+            gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
+            *left += margin.left;
+            *right += margin.right;
+        }
+    }
+
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -2581,9 +2372,9 @@ moz_gtk_get_combo_box_entry_button_size(
      * as well as the minimum arrow size and its padding
      * */
     GtkRequisition requisition;
-    ensure_combo_box_entry_widgets();
 
-    gtk_widget_get_preferred_size(gComboBoxEntryButtonWidget, NULL, &requisition);
+    gtk_widget_get_preferred_size(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON),
+                                  NULL, &requisition);
     *width = requisition.width;
     *height = requisition.height;
 
@@ -2595,10 +2386,11 @@ moz_gtk_get_tab_scroll_arrow_size(gint*
 {
     gint arrow_size;
 
-    ensure_tab_widget();
-    gtk_style_context_get_style(gtk_widget_get_style_context(gTabWidget),
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_TABPANELS);
+    gtk_style_context_get_style(style,
                                 "scroll-arrow-hlength", &arrow_size,
                                 NULL);
+    ReleaseStyleContext(style);
 
     *height = *width = arrow_size;
 
@@ -2611,8 +2403,7 @@ moz_gtk_get_arrow_size(WidgetNodeType wi
     GtkWidget* widget;
     switch (widgetType) {
         case MOZ_GTK_DROPDOWN:
-            ensure_combo_box_widgets();
-            widget = gComboBoxArrowWidget;
+            widget = GetWidget(MOZ_GTK_COMBOBOX_ARROW);
             break;
         default:
             widget = GetWidget(MOZ_GTK_BUTTON_ARROW);
@@ -2659,11 +2450,9 @@ moz_gtk_get_expander_size(gint* size)
 gint
 moz_gtk_get_treeview_expander_size(gint* size)
 {
-    ensure_tree_view_widget();
-    gtk_style_context_get_style(gtk_widget_get_style_context(gTreeViewWidget),
-                                "expander-size", size,
-                                NULL);
-
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TREEVIEW);
+    gtk_style_context_get_style(style, "expander-size", size, NULL);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
@@ -2674,14 +2463,7 @@ moz_gtk_get_menu_separator_height(gint *
     gboolean  wide_separators;
     gint      separator_height;
     GtkBorder padding;
-    GtkStyleContext* style;
-    guint border_width;
-
-    border_width =
-        gtk_container_get_border_width(GTK_CONTAINER(
-                                       GetWidget(MOZ_GTK_MENUSEPARATOR)));
-
-    style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR);
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR);
     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
 
     gtk_style_context_save(style);
@@ -2695,7 +2477,7 @@ moz_gtk_get_menu_separator_height(gint *
     gtk_style_context_restore(style);
     ReleaseStyleContext(style);
 
-    *size = padding.top + padding.bottom + border_width*2;
+    *size = padding.top + padding.bottom;
     *size += (wide_separators) ? separator_height : 1;
 
     return MOZ_GTK_SUCCESS;
@@ -2726,34 +2508,60 @@ void
 moz_gtk_get_scale_metrics(GtkOrientation orient, gint* scale_width,
                           gint* scale_height)
 {
-  gint thumb_length, thumb_height, trough_border;
-  GtkWidget* widget = orient == GTK_ORIENTATION_HORIZONTAL ?
-                      gHScaleWidget : gVScaleWidget;
-  moz_gtk_get_scalethumb_metrics(orient, &thumb_length, &thumb_height);
-  gtk_style_context_get_style(gtk_widget_get_style_context(widget),
-                              "trough-border", &trough_border, NULL);
-
-  if (orient == GTK_ORIENTATION_HORIZONTAL) {
-      *scale_width = thumb_length + trough_border * 2;
-      *scale_height = thumb_height + trough_border * 2;
+  WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
+                           MOZ_GTK_SCALE_HORIZONTAL :
+                           MOZ_GTK_SCALE_VERTICAL;
+
+  if (gtk_check_version(3, 20, 0) != nullptr) {
+      gint thumb_length, thumb_height, trough_border;
+      moz_gtk_get_scalethumb_metrics(orient, &thumb_length, &thumb_height);
+
+      GtkStyleContext* style = ClaimStyleContext(widget);
+      gtk_style_context_get_style(style, "trough-border", &trough_border, NULL);
+
+      if (orient == GTK_ORIENTATION_HORIZONTAL) {
+          *scale_width = thumb_length + trough_border * 2;
+          *scale_height = thumb_height + trough_border * 2;
+      } else {
+          *scale_width = thumb_height + trough_border * 2;
+          *scale_height = thumb_length + trough_border * 2;
+      }
+      ReleaseStyleContext(style);
   } else {
-      *scale_width = thumb_height + trough_border * 2;
-      *scale_height = thumb_length + trough_border * 2;
+      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);
   }
 }
 
 gint
 moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
 {
-  GtkWidget* widget;
 
-  ensure_scale_widget();
-  widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
-
-  gtk_style_context_get_style(gtk_widget_get_style_context(widget),
-                              "slider_length", thumb_length,
-                              "slider_width", thumb_height,
-                              NULL);
+  if (gtk_check_version(3, 20, 0) != nullptr) {
+      WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
+                               MOZ_GTK_SCALE_HORIZONTAL:
+                               MOZ_GTK_SCALE_VERTICAL;
+      GtkStyleContext* style = ClaimStyleContext(widget);
+      gtk_style_context_get_style(style,
+                                  "slider_length", thumb_length,
+                                  "slider_width", thumb_height,
+                                  NULL);
+      ReleaseStyleContext(style);
+  } else {
+      WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
+                               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,
+                             nullptr);
+      ReleaseStyleContext(style);
+  }
 
   return MOZ_GTK_SUCCESS;
 }
@@ -2761,6 +2569,9 @@ moz_gtk_get_scalethumb_metrics(GtkOrient
 gint
 moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
 {
+    // For Gtk >= 3.20 scrollbar metrics are ignored
+    MOZ_ASSERT(gtk_check_version(3, 20, 0) != nullptr);
+
     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_VERTICAL);
     gtk_style_context_get_style(style,
                                 "slider_width", &metrics->slider_width,
@@ -2771,41 +2582,9 @@ moz_gtk_get_scrollbar_metrics(MozGtkScro
                                 nullptr);
     ReleaseStyleContext(style);
 
-    if(!gtk_check_version(3, 20, 0)) {
-        style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_THUMB_VERTICAL);
-        gtk_style_context_get(style, gtk_style_context_get_state(style),
-                              "min-height", &metrics->min_slider_size, nullptr);
-        ReleaseStyleContext(style);
-    }
-
     return MOZ_GTK_SUCCESS;
 }
 
-gboolean
-moz_gtk_images_in_menus()
-{
-    gboolean result;
-    GtkSettings* settings;
-
-    ensure_image_menu_item_widget();
-    settings = gtk_widget_get_settings(gImageMenuItemWidget);
-
-    g_object_get(settings, "gtk-menu-images", &result, NULL);
-    return result;
-}
-
-gboolean
-moz_gtk_images_in_buttons()
-{
-    gboolean result;
-    GtkSettings* settings;
-
-    settings = gtk_widget_get_settings(GetWidget(MOZ_GTK_BUTTON));
-
-    g_object_get(settings, "gtk-button-images", &result, NULL);
-    return result;
-}
-
 /* cairo_t *cr argument has to be a system-cairo. */
 gint
 moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr,
@@ -2846,10 +2625,25 @@ moz_gtk_widget_paint(WidgetNodeType widg
         break;
     case MOZ_GTK_SCROLLBAR_HORIZONTAL:
     case MOZ_GTK_SCROLLBAR_VERTICAL:
-        return moz_gtk_scrollbar_trough_paint(widget, cr, rect,
-                                              state,
-                                              (GtkScrollbarTrackFlags) flags,
-                                              direction);
+        if (gtk_check_version(3,20,0) == nullptr) {
+          return moz_gtk_scrollbar_paint(widget, cr, rect, state, direction);
+        } else {
+          WidgetNodeType trough_widget = (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) ?
+              MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL : MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
+          return moz_gtk_scrollbar_trough_paint(trough_widget, cr, rect,
+                                                state,
+                                                (GtkScrollbarTrackFlags) flags,
+                                                direction);
+        }
+        break;
+    case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
+    case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
+        if (gtk_check_version(3,20,0) == nullptr) {
+          return moz_gtk_scrollbar_trough_paint(widget, cr, rect,
+                                                state,
+                                                (GtkScrollbarTrackFlags) flags,
+                                                direction);
+        }
         break;
     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
@@ -2876,9 +2670,13 @@ moz_gtk_widget_paint(WidgetNodeType widg
                                          state, direction);
         break;
     case MOZ_GTK_SPINBUTTON_ENTRY:
-        // TODO - use MOZ_GTK_SPINBUTTON_ENTRY style directly
-        return moz_gtk_entry_paint(cr, rect, state,
-                                   GetWidget(MOZ_GTK_SPINBUTTON), direction);
+        {
+            GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON_ENTRY,
+                                     direction, GetStateFlagsFromGtkWidgetState(state));
+            gint ret = moz_gtk_entry_paint(cr, rect, state, style);
+            ReleaseStyleContext(style);
+            return ret;
+        }
         break;
     case MOZ_GTK_GRIPPER:
         return moz_gtk_gripper_paint(cr, rect, state,
@@ -2903,9 +2701,13 @@ moz_gtk_widget_paint(WidgetNodeType widg
                                                (GtkExpanderStyle) flags, direction);
         break;
     case MOZ_GTK_ENTRY:
-        return moz_gtk_entry_paint(cr, rect, state, GetWidget(MOZ_GTK_ENTRY),
-                                   direction);
-        break;
+        {
+            GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_ENTRY,
+                                     direction, GetStateFlagsFromGtkWidgetState(state));
+            gint ret = moz_gtk_entry_paint(cr, rect, state, style);
+            ReleaseStyleContext(style);
+            return ret;
+        }
     case MOZ_GTK_TEXT_VIEW:
         return moz_gtk_text_view_paint(cr, rect, state, direction);
         break;
@@ -2917,9 +2719,13 @@ moz_gtk_widget_paint(WidgetNodeType widg
                                                     state, flags, direction);
         break;
     case MOZ_GTK_DROPDOWN_ENTRY:
-        ensure_combo_box_entry_widgets();
-        return moz_gtk_entry_paint(cr, rect, state,
-                                   gComboBoxEntryTextareaWidget, direction);
+        {
+            GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA,
+                                     direction, GetStateFlagsFromGtkWidgetState(state));
+            gint ret = moz_gtk_entry_paint(cr, rect, state, style);
+            ReleaseStyleContext(style);
+            return ret;
+        }
         break;
     case MOZ_GTK_CHECKBUTTON_CONTAINER:
     case MOZ_GTK_RADIOBUTTON_CONTAINER:
@@ -2957,9 +2763,10 @@ moz_gtk_widget_paint(WidgetNodeType widg
         return moz_gtk_progress_chunk_paint(cr, rect,
                                             direction, widget);
         break;
-    case MOZ_GTK_TAB:
+    case MOZ_GTK_TAB_TOP:
+    case MOZ_GTK_TAB_BOTTOM:
         return moz_gtk_tab_paint(cr, rect, state,
-                                 (GtkTabFlags) flags, direction);
+                                 (GtkTabFlags) flags, direction, widget);
         break;
     case MOZ_GTK_TABPANELS:
         return moz_gtk_tabpanels_paint(cr, rect, direction);
@@ -2992,10 +2799,8 @@ moz_gtk_widget_paint(WidgetNodeType widg
         break;
     case MOZ_GTK_CHECKMENUITEM:
     case MOZ_GTK_RADIOMENUITEM:
-        return moz_gtk_check_menu_item_paint(cr, rect, state,
-                                             (gboolean) flags,
-                                             (widget == MOZ_GTK_RADIOMENUITEM),
-                                             direction);
+        return moz_gtk_check_menu_item_paint(widget, cr, rect, state,
+                                             (gboolean) flags, direction);
         break;
     case MOZ_GTK_SPLITTER_HORIZONTAL:
         return moz_gtk_vpaned_paint(cr, rect, state);
@@ -3043,31 +2848,6 @@ moz_gtk_shutdown()
     /* This will destroy all of our widgets */
     ResetWidgetCache();
 
-    /* TODO - replace it with appropriate widget */
-    if (gTreeHeaderSortArrowWidget)
-        gtk_widget_destroy(gTreeHeaderSortArrowWidget);
-
-    gProtoLayout = NULL;
-    gHScaleWidget = NULL;
-    gVScaleWidget = NULL;
-    gComboBoxWidget = NULL;
-    gComboBoxButtonWidget = NULL;
-    gComboBoxSeparatorWidget = NULL;
-    gComboBoxArrowWidget = NULL;
-    gComboBoxEntryWidget = NULL;
-    gComboBoxEntryButtonWidget = NULL;
-    gComboBoxEntryArrowWidget = NULL;
-    gComboBoxEntryTextareaWidget = NULL;
-    gTabWidget = NULL;
-    gImageMenuItemWidget = NULL;
-    gCheckMenuItemWidget = NULL;
-    gTreeViewWidget = NULL;
-    gMiddleTreeViewColumn = NULL;
-    gTreeHeaderCellWidget = NULL;
-    gTreeHeaderSortArrowWidget = NULL;
-    gHPanedWidget = NULL;
-    gVPanedWidget = NULL;
-
     is_initialized = FALSE;
 
     return MOZ_GTK_SUCCESS;
diff -up firefox-50.0/widget/gtk/gtkdrawing.h.widget-rebase firefox-50.0/widget/gtk/gtkdrawing.h
--- firefox-50.0/widget/gtk/gtkdrawing.h.widget-rebase	2016-10-31 21:15:38.000000000 +0100
+++ firefox-50.0/widget/gtk/gtkdrawing.h	2016-11-24 11:57:52.034064779 +0100
@@ -61,8 +61,6 @@ typedef enum {
 typedef enum {
   /* first eight bits are used to pass a margin */
   MOZ_GTK_TAB_MARGIN_MASK     = 0xFF,
-  /* bottom tabs */
-  MOZ_GTK_TAB_BOTTOM          = 1 << 8,
   /* the first tab in the group */
   MOZ_GTK_TAB_FIRST           = 1 << 9,
   /* the selected tab */
@@ -128,6 +126,11 @@ typedef enum {
   /* Paints a GtkScale. */
   MOZ_GTK_SCALE_HORIZONTAL,
   MOZ_GTK_SCALE_VERTICAL,
+  /* Paints a GtkScale trough. */
+  MOZ_GTK_SCALE_CONTENTS_HORIZONTAL,
+  MOZ_GTK_SCALE_CONTENTS_VERTICAL,
+  MOZ_GTK_SCALE_TROUGH_HORIZONTAL,
+  MOZ_GTK_SCALE_TROUGH_VERTICAL,
   /* Paints a GtkScale thumb. */
   MOZ_GTK_SCALE_THUMB_HORIZONTAL,
   MOZ_GTK_SCALE_THUMB_VERTICAL,
@@ -173,14 +176,22 @@ typedef enum {
   MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE,
   /* Paints a progress chunk of a vertical indeterminated GtkProgressBar. */
   MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE,
+  /* Used as root style of whole GtkNotebook widget */
+  MOZ_GTK_NOTEBOOK,
+  /* Used as root style of active GtkNotebook area which contains tabs and arrows. */
+  MOZ_GTK_NOTEBOOK_HEADER,
   /* Paints a tab of a GtkNotebook. flags is a GtkTabFlags, defined above. */
-  MOZ_GTK_TAB,
+  MOZ_GTK_TAB_TOP,
+  /* Paints a tab of a GtkNotebook. flags is a GtkTabFlags, defined above. */
+  MOZ_GTK_TAB_BOTTOM,
   /* Paints the background and border of a GtkNotebook. */
   MOZ_GTK_TABPANELS,
   /* Paints a GtkArrow for a GtkNotebook. flags is a GtkArrowType. */
   MOZ_GTK_TAB_SCROLLARROW,
-  /* Paints the background and border of a GtkTreeView */
+  /* Paints the expander and border of a GtkTreeView */
   MOZ_GTK_TREEVIEW,
+  /* Paints the border of a GtkTreeView */
+  MOZ_GTK_TREEVIEW_VIEW,
   /* Paints treeheader cells */
   MOZ_GTK_TREE_HEADER_CELL,
   /* Paints sort arrows in treeheader cells */
@@ -199,19 +210,44 @@ typedef enum {
   MOZ_GTK_MENUBARITEM,
   /* Paints items of popup menus. */
   MOZ_GTK_MENUITEM,
+  /* Paints a menuitem with check indicator, or the gets the style context for
+     a menuitem that contains a checkbox. */
   MOZ_GTK_CHECKMENUITEM,
+  /* Gets the style context for a checkbox in a check menuitem. */
+  MOZ_GTK_CHECKMENUITEM_INDICATOR,
   MOZ_GTK_RADIOMENUITEM,
+  MOZ_GTK_RADIOMENUITEM_INDICATOR,
   MOZ_GTK_MENUSEPARATOR,
-  /* Paints a GtkVPaned separator */
+  /* GtkVPaned base class */
   MOZ_GTK_SPLITTER_HORIZONTAL,
-  /* Paints a GtkHPaned separator */
+  /* GtkHPaned base class */
   MOZ_GTK_SPLITTER_VERTICAL,
+  /* Paints a GtkVPaned separator */
+  MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL,
+  /* Paints a GtkHPaned separator */
+  MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL,
   /* Paints the background of a window, dialog or page. */
   MOZ_GTK_WINDOW,
   /* Window container for all widgets */
   MOZ_GTK_WINDOW_CONTAINER,
   /* Paints a GtkInfoBar, for notifications. */
   MOZ_GTK_INFO_BAR,
+  /* Used for widget tree construction. */
+  MOZ_GTK_COMBOBOX,
+  /* Paints a GtkComboBox button widget. */
+  MOZ_GTK_COMBOBOX_BUTTON,
+  /* Paints a GtkComboBox arrow widget. */
+  MOZ_GTK_COMBOBOX_ARROW,
+  /* Paints a GtkComboBox separator widget. */
+  MOZ_GTK_COMBOBOX_SEPARATOR,
+  /* Used for widget tree construction. */
+  MOZ_GTK_COMBOBOX_ENTRY,
+  /* Paints a GtkComboBox entry widget. */
+  MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA,
+  /* Paints a GtkComboBox entry button widget. */
+  MOZ_GTK_COMBOBOX_ENTRY_BUTTON,
+  /* Paints a GtkComboBox entry arrow widget. */
+  MOZ_GTK_COMBOBOX_ENTRY_ARROW,
   /* Used for scrolled window shell. */
   MOZ_GTK_SCROLLED_WINDOW,
 
@@ -300,12 +336,14 @@ gint moz_gtk_get_widget_border(WidgetNod
  * top/bottom:  [OUT] the tab's top/bottom border
  * direction:   the text direction for the widget
  * flags:       tab-dependant flags; see the GtkTabFlags definition.
+ * widget:      tab widget
  *
  * returns:    MOZ_GTK_SUCCESS if there was no error, an error code otherwise
  */
 gint
 moz_gtk_get_tab_border(gint* left, gint* top, gint* right, gint* bottom, 
-                       GtkTextDirection direction, GtkTabFlags flags);
+                       GtkTextDirection direction, GtkTabFlags flags,
+                       WidgetNodeType widget);
 
 /**
  * Get the desired size of a GtkCheckButton
@@ -481,19 +519,8 @@ GtkWidget* moz_gtk_get_scrollbar_widget(
 /**
  * Get the YTHICKNESS of a tab (notebook extension).
  */
-gint moz_gtk_get_tab_thickness(void);
-
-/**
- * Get a boolean which indicates whether or not to use images in menus.
- * If TRUE, use images in menus.
- */
-gboolean moz_gtk_images_in_menus(void);
-
-/**
- * Get a boolean which indicates whether or not to use images in buttons.
- * If TRUE, use images in buttons.
- */
-gboolean moz_gtk_images_in_buttons(void);
+gint
+moz_gtk_get_tab_thickness(WidgetNodeType aNodeType);
 
 /**
  * Get a boolean which indicates whether the theme draws scrollbar buttons.
@@ -501,6 +528,13 @@ gboolean moz_gtk_images_in_buttons(void)
  */
 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-50.0/widget/gtk/mozgtk/mozgtk.c.widget-rebase firefox-50.0/widget/gtk/mozgtk/mozgtk.c
--- firefox-50.0/widget/gtk/mozgtk/mozgtk.c.widget-rebase	2016-10-31 21:15:38.000000000 +0100
+++ firefox-50.0/widget/gtk/mozgtk/mozgtk.c	2016-11-24 11:57:52.034064779 +0100
@@ -9,6 +9,7 @@ STUB(gdk_atom_name)
 STUB(gdk_beep)
 STUB(gdk_cairo_create)
 STUB(gdk_color_free)
+STUB(gdk_color_parse)
 STUB(gdk_cursor_new_for_display)
 STUB(gdk_cursor_new_from_name)
 STUB(gdk_cursor_new_from_pixbuf)
@@ -244,7 +245,6 @@ STUB(gtk_icon_theme_get_icon_sizes)
 STUB(gtk_icon_theme_lookup_by_gicon)
 STUB(gtk_icon_theme_lookup_icon)
 STUB(gtk_image_get_type)
-STUB(gtk_image_menu_item_new)
 STUB(gtk_image_new)
 STUB(gtk_image_new_from_stock)
 STUB(gtk_image_set_from_pixbuf)
@@ -530,6 +530,7 @@ STUB(gtk_get_minor_version)
 STUB(gtk_menu_button_new)
 STUB(gtk_offscreen_window_new)
 STUB(gtk_paned_new)
+STUB(gtk_radio_menu_item_new)
 STUB(gtk_render_activity)
 STUB(gtk_render_arrow)
 STUB(gtk_render_background)
@@ -561,6 +562,7 @@ STUB(gtk_style_context_get_state)
 STUB(gtk_style_context_get_style)
 STUB(gtk_style_context_has_class)
 STUB(gtk_style_context_invalidate)
+STUB(gtk_style_context_list_classes)
 STUB(gtk_style_context_new)
 STUB(gtk_style_context_remove_class)
 STUB(gtk_style_context_remove_region)
@@ -575,10 +577,10 @@ 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)
+STUB(gtk_widget_path_iter_add_class)
 STUB(gtk_widget_path_new)
 STUB(gtk_widget_path_unref)
 STUB(gtk_widget_set_visual)
diff -up firefox-50.0/widget/gtk/nsLookAndFeel.cpp.widget-rebase firefox-50.0/widget/gtk/nsLookAndFeel.cpp
--- firefox-50.0/widget/gtk/nsLookAndFeel.cpp.widget-rebase	2016-11-24 12:00:04.563704500 +0100
+++ firefox-50.0/widget/gtk/nsLookAndFeel.cpp	2016-11-24 12:00:47.316588277 +0100
@@ -786,10 +786,10 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
         aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
         break;
     case eIntID_ImagesInMenus:
-        aResult = moz_gtk_images_in_menus();
+        aResult = 0;
         break;
     case eIntID_ImagesInButtons:
-        aResult = moz_gtk_images_in_buttons();
+        aResult = 0;
         break;
     case eIntID_MenuBarDrag:
         aResult = sMenuSupportsDrag;
diff -up firefox-50.0/widget/gtk/nsNativeThemeGTK.cpp.widget-rebase firefox-50.0/widget/gtk/nsNativeThemeGTK.cpp
--- firefox-50.0/widget/gtk/nsNativeThemeGTK.cpp.widget-rebase	2016-10-31 21:15:38.000000000 +0100
+++ firefox-50.0/widget/gtk/nsNativeThemeGTK.cpp	2016-11-24 11:57:52.034064779 +0100
@@ -149,19 +149,15 @@ static void SetWidgetStateSafe(uint8_t *
   aSafeVector[key >> 3] |= (1 << (key & 7));
 }
 
-static GtkTextDirection GetTextDirection(nsIFrame* aFrame)
+/* static */ GtkTextDirection
+nsNativeThemeGTK::GetTextDirection(nsIFrame* aFrame)
 {
-  if (!aFrame)
-    return GTK_TEXT_DIR_NONE;
-
-  switch (aFrame->StyleVisibility()->mDirection) {
-    case NS_STYLE_DIRECTION_RTL:
-      return GTK_TEXT_DIR_RTL;
-    case NS_STYLE_DIRECTION_LTR:
-      return GTK_TEXT_DIR_LTR;
-  }
-
-  return GTK_TEXT_DIR_NONE;
+  // IsFrameRTL() treats vertical-rl modes as right-to-left (in addition to
+  // horizontal text with direction=RTL), rather than just considering the
+  // text direction.  GtkTextDirection does not have distinct values for
+  // vertical writing modes, but considering the block flow direction is
+  // important for resizers and scrollbar elements, at least.
+  return IsFrameRTL(aFrame) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
 }
 
 // Returns positive for negative margins (otherwise 0).
@@ -193,205 +189,199 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
                                        gint* aWidgetFlags)
 {
   if (aState) {
-    if (!aFrame) {
-      // reset the entire struct to zero
-      memset(aState, 0, sizeof(GtkWidgetState));
-    } else {
+    // For XUL checkboxes and radio buttons, the state of the parent
+    // determines our state.
+    nsIFrame *stateFrame = aFrame;
+    if (aFrame && ((aWidgetFlags && (aWidgetType == NS_THEME_CHECKBOX ||
+                                     aWidgetType == NS_THEME_RADIO)) ||
+                   aWidgetType == NS_THEME_CHECKBOX_LABEL ||
+                   aWidgetType == NS_THEME_RADIO_LABEL)) {
 
-      // For XUL checkboxes and radio buttons, the state of the parent
-      // determines our state.
-      nsIFrame *stateFrame = aFrame;
-      if (aFrame && ((aWidgetFlags && (aWidgetType == NS_THEME_CHECKBOX ||
-                                       aWidgetType == NS_THEME_RADIO)) ||
-                     aWidgetType == NS_THEME_CHECKBOX_LABEL ||
-                     aWidgetType == NS_THEME_RADIO_LABEL)) {
-
-        nsIAtom* atom = nullptr;
-        if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
-          if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
-              aWidgetType == NS_THEME_RADIO_LABEL) {
-            // Adjust stateFrame so GetContentState finds the correct state.
-            stateFrame = aFrame = aFrame->GetParent()->GetParent();
-          } else {
-            // GetContentState knows to look one frame up for radio/checkbox
-            // widgets, so don't adjust stateFrame here.
-            aFrame = aFrame->GetParent();
+      nsIAtom* atom = nullptr;
+      if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
+        if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
+            aWidgetType == NS_THEME_RADIO_LABEL) {
+          // Adjust stateFrame so GetContentState finds the correct state.
+          stateFrame = aFrame = aFrame->GetParent()->GetParent();
+        } else {
+          // GetContentState knows to look one frame up for radio/checkbox
+          // widgets, so don't adjust stateFrame here.
+          aFrame = aFrame->GetParent();
+        }
+        if (aWidgetFlags) {
+          if (!atom) {
+            atom = (aWidgetType == NS_THEME_CHECKBOX ||
+                    aWidgetType == NS_THEME_CHECKBOX_LABEL) ? nsGkAtoms::checked
+                                                            : nsGkAtoms::selected;
           }
-          if (aWidgetFlags) {
-            if (!atom) {
-              atom = (aWidgetType == NS_THEME_CHECKBOX ||
-                      aWidgetType == NS_THEME_CHECKBOX_LABEL) ? nsGkAtoms::checked
-                                                              : nsGkAtoms::selected;
-            }
-            *aWidgetFlags = CheckBooleanAttr(aFrame, atom);
+          *aWidgetFlags = CheckBooleanAttr(aFrame, atom);
+        }
+      } else {
+        if (aWidgetFlags) {
+          nsCOMPtr<nsIDOMHTMLInputElement> inputElt(do_QueryInterface(aFrame->GetContent()));
+          *aWidgetFlags = 0;
+          if (inputElt) {
+            bool isHTMLChecked;
+            inputElt->GetChecked(&isHTMLChecked);
+            if (isHTMLChecked)
+              *aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED;
           }
-        } else {
-          if (aWidgetFlags) {
-            nsCOMPtr<nsIDOMHTMLInputElement> inputElt(do_QueryInterface(aFrame->GetContent()));
-            *aWidgetFlags = 0;
-            if (inputElt) {
-              bool isHTMLChecked;
-              inputElt->GetChecked(&isHTMLChecked);
-              if (isHTMLChecked)
-                *aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED;
-            }
 
-            if (GetIndeterminate(aFrame))
-              *aWidgetFlags |= MOZ_GTK_WIDGET_INCONSISTENT;
-          }
+          if (GetIndeterminate(aFrame))
+            *aWidgetFlags |= MOZ_GTK_WIDGET_INCONSISTENT;
         }
-      } else if (aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
-                 aWidgetType == NS_THEME_TREEHEADERSORTARROW ||
-                 aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS ||
-                 aWidgetType == NS_THEME_BUTTON_ARROW_NEXT ||
-                 aWidgetType == NS_THEME_BUTTON_ARROW_UP ||
-                 aWidgetType == NS_THEME_BUTTON_ARROW_DOWN) {
-        // The state of an arrow comes from its parent.
-        stateFrame = aFrame = aFrame->GetParent();
-      }
-
-      EventStates eventState = GetContentState(stateFrame, aWidgetType);
-
-      aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame);
-      aState->active  = eventState.HasState(NS_EVENT_STATE_ACTIVE);
-      aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS);
-      aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER);
-      aState->isDefault = IsDefaultButton(aFrame);
-      aState->canDefault = FALSE; // XXX fix me
-      aState->depressed = FALSE;
-
-      if (aWidgetType == NS_THEME_FOCUS_OUTLINE) {
-        aState->disabled = FALSE;
-        aState->active  = FALSE;
-        aState->inHover = FALSE;
-        aState->isDefault = FALSE;
-        aState->canDefault = FALSE;
-
-        aState->focused = TRUE;
-        aState->depressed = TRUE; // see moz_gtk_entry_paint()
-      } else if (aWidgetType == NS_THEME_BUTTON ||
-                 aWidgetType == NS_THEME_TOOLBARBUTTON ||
-                 aWidgetType == NS_THEME_DUALBUTTON ||
-                 aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
-                 aWidgetType == NS_THEME_MENULIST ||
-                 aWidgetType == NS_THEME_MENULIST_BUTTON) {
-        aState->active &= aState->inHover;
       }
-
-      if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
-        // For these widget types, some element (either a child or parent)
-        // actually has element focus, so we check the focused attribute
-        // to see whether to draw in the focused state.
-        if (aWidgetType == NS_THEME_NUMBER_INPUT ||
-            aWidgetType == NS_THEME_TEXTFIELD ||
-            aWidgetType == NS_THEME_TEXTFIELD_MULTILINE ||
-            aWidgetType == NS_THEME_MENULIST_TEXTFIELD ||
-            aWidgetType == NS_THEME_SPINNER_TEXTFIELD ||
-            aWidgetType == NS_THEME_RADIO_CONTAINER ||
-            aWidgetType == NS_THEME_RADIO_LABEL) {
-          aState->focused = IsFocused(aFrame);
-        } else if (aWidgetType == NS_THEME_RADIO ||
-                   aWidgetType == NS_THEME_CHECKBOX) {
-          // In XUL, checkboxes and radios shouldn't have focus rings, their labels do
-          aState->focused = FALSE;
+    } else if (aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
+               aWidgetType == NS_THEME_TREEHEADERSORTARROW ||
+               aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS ||
+               aWidgetType == NS_THEME_BUTTON_ARROW_NEXT ||
+               aWidgetType == NS_THEME_BUTTON_ARROW_UP ||
+               aWidgetType == NS_THEME_BUTTON_ARROW_DOWN) {
+      // The state of an arrow comes from its parent.
+      stateFrame = aFrame = aFrame->GetParent();
+    }
+
+    EventStates eventState = GetContentState(stateFrame, aWidgetType);
+
+    aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame);
+    aState->active  = eventState.HasState(NS_EVENT_STATE_ACTIVE);
+    aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS);
+    aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER);
+    aState->isDefault = IsDefaultButton(aFrame);
+    aState->canDefault = FALSE; // XXX fix me
+    aState->depressed = FALSE;
+
+    if (aWidgetType == NS_THEME_FOCUS_OUTLINE) {
+      aState->disabled = FALSE;
+      aState->active  = FALSE;
+      aState->inHover = FALSE;
+      aState->isDefault = FALSE;
+      aState->canDefault = FALSE;
+
+      aState->focused = TRUE;
+      aState->depressed = TRUE; // see moz_gtk_entry_paint()
+    } else if (aWidgetType == NS_THEME_BUTTON ||
+               aWidgetType == NS_THEME_TOOLBARBUTTON ||
+               aWidgetType == NS_THEME_DUALBUTTON ||
+               aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
+               aWidgetType == NS_THEME_MENULIST ||
+               aWidgetType == NS_THEME_MENULIST_BUTTON) {
+      aState->active &= aState->inHover;
+    }
+
+    if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
+      // For these widget types, some element (either a child or parent)
+      // actually has element focus, so we check the focused attribute
+      // to see whether to draw in the focused state.
+      if (aWidgetType == NS_THEME_NUMBER_INPUT ||
+          aWidgetType == NS_THEME_TEXTFIELD ||
+          aWidgetType == NS_THEME_TEXTFIELD_MULTILINE ||
+          aWidgetType == NS_THEME_MENULIST_TEXTFIELD ||
+          aWidgetType == NS_THEME_SPINNER_TEXTFIELD ||
+          aWidgetType == NS_THEME_RADIO_CONTAINER ||
+          aWidgetType == NS_THEME_RADIO_LABEL) {
+        aState->focused = IsFocused(aFrame);
+      } else if (aWidgetType == NS_THEME_RADIO ||
+                 aWidgetType == NS_THEME_CHECKBOX) {
+        // In XUL, checkboxes and radios shouldn't have focus rings, their labels do
+        aState->focused = FALSE;
+      }
+
+      if (aWidgetType == NS_THEME_SCROLLBARTHUMB_VERTICAL ||
+          aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL) {
+        // for scrollbars we need to go up two to go from the thumb to
+        // the slider to the actual scrollbar object
+        nsIFrame *tmpFrame = aFrame->GetParent()->GetParent();
+
+        aState->curpos = CheckIntAttr(tmpFrame, nsGkAtoms::curpos, 0);
+        aState->maxpos = CheckIntAttr(tmpFrame, nsGkAtoms::maxpos, 100);
+
+        if (CheckBooleanAttr(aFrame, nsGkAtoms::active)) {
+          aState->active = TRUE;
+          // Set hover state to emulate Gtk style of active scrollbar thumb
+          aState->inHover = TRUE;
         }
+      }
 
-        if (aWidgetType == NS_THEME_SCROLLBARTHUMB_VERTICAL ||
-            aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL) {
-          // for scrollbars we need to go up two to go from the thumb to
-          // the slider to the actual scrollbar object
-          nsIFrame *tmpFrame = aFrame->GetParent()->GetParent();
-
-          aState->curpos = CheckIntAttr(tmpFrame, nsGkAtoms::curpos, 0);
-          aState->maxpos = CheckIntAttr(tmpFrame, nsGkAtoms::maxpos, 100);
-
-          if (CheckBooleanAttr(aFrame, nsGkAtoms::active)) {
-            aState->active = TRUE;
-            // Set hover state to emulate Gtk style of active scrollbar thumb 
-            aState->inHover = TRUE;
-          }
+      if (aWidgetType == NS_THEME_SCROLLBARBUTTON_UP ||
+          aWidgetType == NS_THEME_SCROLLBARBUTTON_DOWN ||
+          aWidgetType == NS_THEME_SCROLLBARBUTTON_LEFT ||
+          aWidgetType == NS_THEME_SCROLLBARBUTTON_RIGHT) {
+        // set the state to disabled when the scrollbar is scrolled to
+        // the beginning or the end, depending on the button type.
+        int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
+        int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
+        if (ShouldScrollbarButtonBeDisabled(curpos, maxpos, aWidgetType)) {
+          aState->disabled = true;
         }
 
-        if (aWidgetType == NS_THEME_SCROLLBARBUTTON_UP ||
-            aWidgetType == NS_THEME_SCROLLBARBUTTON_DOWN ||
-            aWidgetType == NS_THEME_SCROLLBARBUTTON_LEFT ||
-            aWidgetType == NS_THEME_SCROLLBARBUTTON_RIGHT) {
-          // set the state to disabled when the scrollbar is scrolled to
-          // the beginning or the end, depending on the button type.
-          int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
-          int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
-          if (ShouldScrollbarButtonBeDisabled(curpos, maxpos, aWidgetType)) {
-            aState->disabled = true;
-          }
+        // In order to simulate native GTK scrollbar click behavior,
+        // we set the active attribute on the element to true if it's
+        // pressed with any mouse button.
+        // This allows us to show that it's active without setting :active
+        else if (CheckBooleanAttr(aFrame, nsGkAtoms::active))
+          aState->active = true;
+
+        if (aWidgetFlags) {
+          *aWidgetFlags = GetScrollbarButtonType(aFrame);
+          if (aWidgetType - NS_THEME_SCROLLBARBUTTON_UP < 2)
+            *aWidgetFlags |= MOZ_GTK_STEPPER_VERTICAL;
+        }
+      }
 
-          // In order to simulate native GTK scrollbar click behavior,
-          // we set the active attribute on the element to true if it's
-          // pressed with any mouse button.
-          // This allows us to show that it's active without setting :active
-          else if (CheckBooleanAttr(aFrame, nsGkAtoms::active))
-            aState->active = true;
-
-          if (aWidgetFlags) {
-            *aWidgetFlags = GetScrollbarButtonType(aFrame);
-            if (aWidgetType - NS_THEME_SCROLLBARBUTTON_UP < 2)
-              *aWidgetFlags |= MOZ_GTK_STEPPER_VERTICAL;
-          }
+      // menu item state is determined by the attribute "_moz-menuactive",
+      // and not by the mouse hovering (accessibility).  as a special case,
+      // menus which are children of a menu bar are only marked as prelight
+      // if they are open, not on normal hover.
+
+      if (aWidgetType == NS_THEME_MENUITEM ||
+          aWidgetType == NS_THEME_CHECKMENUITEM ||
+          aWidgetType == NS_THEME_RADIOMENUITEM ||
+          aWidgetType == NS_THEME_MENUSEPARATOR ||
+          aWidgetType == NS_THEME_MENUARROW) {
+        bool isTopLevel = false;
+        nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
+        if (menuFrame) {
+          isTopLevel = menuFrame->IsOnMenuBar();
         }
 
-        // menu item state is determined by the attribute "_moz-menuactive",
-        // and not by the mouse hovering (accessibility).  as a special case,
-        // menus which are children of a menu bar are only marked as prelight
-        // if they are open, not on normal hover.
-
-        if (aWidgetType == NS_THEME_MENUITEM ||
-            aWidgetType == NS_THEME_CHECKMENUITEM ||
-            aWidgetType == NS_THEME_RADIOMENUITEM ||
-            aWidgetType == NS_THEME_MENUSEPARATOR ||
-            aWidgetType == NS_THEME_MENUARROW) {
-          bool isTopLevel = false;
-          nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
-          if (menuFrame) {
-            isTopLevel = menuFrame->IsOnMenuBar();
-          }
+        if (isTopLevel) {
+          aState->inHover = menuFrame->IsOpen();
+        } else {
+          aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+        }
 
-          if (isTopLevel) {
-            aState->inHover = menuFrame->IsOpen();
-          } else {
-            aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
-          }
+        aState->active = FALSE;
 
-          aState->active = FALSE;
-        
-          if (aWidgetType == NS_THEME_CHECKMENUITEM ||
-              aWidgetType == NS_THEME_RADIOMENUITEM) {
-            *aWidgetFlags = 0;
-            if (aFrame && aFrame->GetContent()) {
-              *aWidgetFlags = aFrame->GetContent()->
-                AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
-                            nsGkAtoms::_true, eIgnoreCase);
-            }
+        if (aWidgetType == NS_THEME_CHECKMENUITEM ||
+            aWidgetType == NS_THEME_RADIOMENUITEM) {
+          *aWidgetFlags = 0;
+          if (aFrame && aFrame->GetContent()) {
+            *aWidgetFlags = aFrame->GetContent()->
+              AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
+                          nsGkAtoms::_true, eIgnoreCase);
           }
         }
+      }
 
-        // A button with drop down menu open or an activated toggle button
-        // should always appear depressed.
-        if (aWidgetType == NS_THEME_BUTTON ||
-            aWidgetType == NS_THEME_TOOLBARBUTTON ||
-            aWidgetType == NS_THEME_DUALBUTTON ||
-            aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
-            aWidgetType == NS_THEME_MENULIST ||
-            aWidgetType == NS_THEME_MENULIST_BUTTON) {
-          bool menuOpen = IsOpenButton(aFrame);
-          aState->depressed = IsCheckedButton(aFrame) || menuOpen;
-          // we must not highlight buttons with open drop down menus on hover.
-          aState->inHover = aState->inHover && !menuOpen;
-        }
-
-        // When the input field of the drop down button has focus, some themes
-        // should draw focus for the drop down button as well.
-        if (aWidgetType == NS_THEME_MENULIST_BUTTON && aWidgetFlags) {
-          *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused);
-        }
+      // A button with drop down menu open or an activated toggle button
+      // should always appear depressed.
+      if (aWidgetType == NS_THEME_BUTTON ||
+          aWidgetType == NS_THEME_TOOLBARBUTTON ||
+          aWidgetType == NS_THEME_DUALBUTTON ||
+          aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
+          aWidgetType == NS_THEME_MENULIST ||
+          aWidgetType == NS_THEME_MENULIST_BUTTON) {
+        bool menuOpen = IsOpenButton(aFrame);
+        aState->depressed = IsCheckedButton(aFrame) || menuOpen;
+        // we must not highlight buttons with open drop down menus on hover.
+        aState->inHover = aState->inHover && !menuOpen;
+      }
+
+      // When the input field of the drop down button has focus, some themes
+      // should draw focus for the drop down button as well.
+      if (aWidgetType == NS_THEME_MENULIST_BUTTON && aWidgetFlags) {
+        *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused);
       }
     }
   }
@@ -435,6 +425,20 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
     else
         *aWidgetFlags = 0;
     break;
+  case NS_THEME_SCROLLBARTRACK_HORIZONTAL:
+    if (gtk_check_version(3,20,0) == nullptr) {
+      aGtkWidgetType = MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL;
+    } else {
+      return false;
+    }
+    break;
+  case NS_THEME_SCROLLBARTRACK_VERTICAL:
+    if (gtk_check_version(3,20,0) == nullptr) {
+      aGtkWidgetType = MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
+    } else {
+      return false;
+    }
+    break;
   case NS_THEME_SCROLLBARTHUMB_VERTICAL:
     aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
     break;
@@ -644,17 +648,17 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
     break;
   case NS_THEME_TAB:
     {
+      if (IsBottomTab(aFrame)) {
+        aGtkWidgetType = MOZ_GTK_TAB_BOTTOM;
+      } else {
+        aGtkWidgetType = MOZ_GTK_TAB_TOP;
+      }
+
       if (aWidgetFlags) {
         /* First bits will be used to store max(0,-bmargin) where bmargin
          * is the bottom margin of the tab in pixels  (resp. top margin,
          * for bottom tabs). */
-        if (IsBottomTab(aFrame)) {
-            *aWidgetFlags = MOZ_GTK_TAB_BOTTOM;
-        } else {
-            *aWidgetFlags = 0;
-        }
-
-        *aWidgetFlags |= GetTabMarginPixels(aFrame);
+        *aWidgetFlags = GetTabMarginPixels(aFrame);
 
         if (IsSelectedTab(aFrame))
           *aWidgetFlags |= MOZ_GTK_TAB_SELECTED;
@@ -662,8 +666,6 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
         if (IsFirstTab(aFrame))
           *aWidgetFlags |= MOZ_GTK_TAB_FIRST;
       }
-
-      aGtkWidgetType = MOZ_GTK_TAB;
     }
     break;
   case NS_THEME_SPLITTER:
@@ -862,12 +864,19 @@ DrawThemeWithCairo(gfxContext* aContext,
   cairo_matrix_t mat;
   GfxMatrixToCairoMatrix(transform, mat);
 
+  nsIntSize clipSize((aDrawSize.width + aScaleFactor - 1) / aScaleFactor,
+                     (aDrawSize.height + aScaleFactor - 1) / aScaleFactor);
+
 #ifndef MOZ_TREE_CAIRO
   // Directly use the Cairo draw target to render the widget if using system Cairo everywhere.
   BorrowedCairoContext borrowCairo(aDrawTarget);
   if (borrowCairo.mCairo) {
     cairo_set_matrix(borrowCairo.mCairo, &mat);
 
+    cairo_new_path(borrowCairo.mCairo);
+    cairo_rectangle(borrowCairo.mCairo, 0, 0, clipSize.width, clipSize.height);
+    cairo_clip(borrowCairo.mCairo);
+
     moz_gtk_widget_paint(aGTKWidgetType, borrowCairo.mCairo, &aGDKRect, &aState, aFlags, aDirection);
 
     borrowCairo.Finish();
@@ -908,6 +917,10 @@ DrawThemeWithCairo(gfxContext* aContext,
 
           cairo_set_matrix(cr, &mat);
 
+          cairo_new_path(cr);
+          cairo_rectangle(cr, 0, 0, clipSize.width, clipSize.height);
+          cairo_clip(cr);
+
           moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
 
           cairo_destroy(cr);
@@ -942,6 +955,10 @@ DrawThemeWithCairo(gfxContext* aContext,
 
         cairo_set_matrix(cr, &mat);
 
+        cairo_new_path(cr);
+        cairo_rectangle(cr, 0, 0, clipSize.width, clipSize.height);
+        cairo_clip(cr);
+
         moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
 
         cairo_destroy(cr);
@@ -1062,7 +1079,8 @@ nsNativeThemeGTK::GetExtraSizeForWidget(
       if (!IsSelectedTab(aFrame))
         return false;
 
-      gint gap_height = moz_gtk_get_tab_thickness();
+      gint gap_height = moz_gtk_get_tab_thickness(IsBottomTab(aFrame) ?
+                            MOZ_GTK_TAB_BOTTOM : MOZ_GTK_TAB_TOP);
       if (!gap_height)
         return false;
 
@@ -1097,14 +1115,7 @@ nsNativeThemeGTK::DrawWidgetBackground(n
 {
   GtkWidgetState state;
   WidgetNodeType gtkWidgetType;
-  // For resizer drawing, we want IsFrameRTL, which treats vertical-rl modes
-  // as right-to-left (in addition to horizontal text with direction=RTL),
-  // rather than just considering the text direction.
-  // This will make resizers on vertically-oriented elements render properly.
-  GtkTextDirection direction =
-    aWidgetType == NS_THEME_RESIZER
-    ? (IsFrameRTL(aFrame) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR)
-    : GetTextDirection(aFrame);
+  GtkTextDirection direction = GetTextDirection(aFrame);
   gint flags;
   if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state,
                             &flags))
@@ -1240,6 +1251,21 @@ nsNativeThemeGTK::DrawWidgetBackground(n
   return NS_OK;
 }
 
+WidgetNodeType
+nsNativeThemeGTK::NativeThemeToGtkTheme(uint8_t aWidgetType, nsIFrame* aFrame)
+{
+  WidgetNodeType gtkWidgetType;
+  gint unusedFlags;
+
+  if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr,
+                            &unusedFlags))
+  {
+    MOZ_ASSERT_UNREACHABLE("Unknown native widget to gtk widget mapping");
+    return MOZ_GTK_WINDOW;
+  }
+  return gtkWidgetType;
+}
+
 NS_IMETHODIMP
 nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
                                   uint8_t aWidgetType, nsIntMargin* aResult)
@@ -1247,24 +1273,6 @@ nsNativeThemeGTK::GetWidgetBorder(nsDevi
   GtkTextDirection direction = GetTextDirection(aFrame);
   aResult->top = aResult->left = aResult->right = aResult->bottom = 0;
   switch (aWidgetType) {
-  case NS_THEME_SCROLLBAR_VERTICAL:
-  case NS_THEME_SCROLLBARTRACK_HORIZONTAL:
-    {
-      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 */
-      aResult->top = aResult->bottom = metrics.trough_border;
-    }
-    break;
-  case NS_THEME_SCROLLBAR_HORIZONTAL:
-  case NS_THEME_SCROLLBARTRACK_VERTICAL:
-    {
-      MozGtkScrollbarMetrics metrics;
-      moz_gtk_get_scrollbar_metrics(&metrics);
-      aResult->left = aResult->right = metrics.trough_border;
-    }
-    break;
   case NS_THEME_TOOLBOX:
     // gtk has no toolbox equivalent.  So, although we map toolbox to
     // gtk's 'toolbar' for purposes of painting the widget background,
@@ -1289,7 +1297,7 @@ nsNativeThemeGTK::GetWidgetBorder(nsDevi
 
       moz_gtk_get_tab_border(&aResult->left, &aResult->top,
                              &aResult->right, &aResult->bottom, direction,
-                             (GtkTabFlags)flags);
+                             (GtkTabFlags)flags, gtkWidgetType);
     }
     break;
   case NS_THEME_MENUITEM:
@@ -1304,8 +1312,9 @@ nsNativeThemeGTK::GetWidgetBorder(nsDevi
   default:
     {
       WidgetNodeType gtkWidgetType;
+      gint unusedFlags;
       if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr,
-                               nullptr)) {
+                               &unusedFlags)) {
         moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top,
                                   &aResult->right, &aResult->bottom, direction,
                                   IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML));
@@ -1418,22 +1427,33 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
     case NS_THEME_SCROLLBARBUTTON_UP:
     case NS_THEME_SCROLLBARBUTTON_DOWN:
       {
-        MozGtkScrollbarMetrics metrics;
-        moz_gtk_get_scrollbar_metrics(&metrics);
+        if (gtk_check_version(3,20,0) == nullptr) {
+          moz_gtk_get_widget_min_size(MOZ_GTK_SCROLLBAR_BUTTON,
+                                      &(aResult->width), &(aResult->height));
+        } else {
+          MozGtkScrollbarMetrics metrics;
+          moz_gtk_get_scrollbar_metrics(&metrics);
+
+          aResult->width = metrics.slider_width;
+          aResult->height = metrics.stepper_size;
+        }
 
-        aResult->width = metrics.slider_width;
-        aResult->height = metrics.stepper_size;
         *aIsOverridable = false;
       }
       break;
     case NS_THEME_SCROLLBARBUTTON_LEFT:
     case NS_THEME_SCROLLBARBUTTON_RIGHT:
       {
-        MozGtkScrollbarMetrics metrics;
-        moz_gtk_get_scrollbar_metrics(&metrics);
+        if (gtk_check_version(3,20,0) == nullptr) {
+          moz_gtk_get_widget_min_size(MOZ_GTK_SCROLLBAR_BUTTON,
+                                      &(aResult->width), &(aResult->height));
+        } else {
+          MozGtkScrollbarMetrics metrics;
+          moz_gtk_get_scrollbar_metrics(&metrics);
 
-        aResult->width = metrics.stepper_size;
-        aResult->height = metrics.slider_width;
+          aResult->width = metrics.stepper_size;
+          aResult->height = metrics.slider_width;
+        }
         *aIsOverridable = false;
       }
       break;
@@ -1460,39 +1480,65 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
        * the thumb isn't a direct child of the scrollbar, unlike the buttons
        * or track. So add a minimum size to the track as well to prevent a
        * 0-width scrollbar. */
-      MozGtkScrollbarMetrics metrics;
-      moz_gtk_get_scrollbar_metrics(&metrics);
+      if (gtk_check_version(3,20,0) == nullptr) {
+        // Thumb min dimensions to start with
+        WidgetNodeType thumbType = aWidgetType == NS_THEME_SCROLLBAR_VERTICAL ?
+          MOZ_GTK_SCROLLBAR_THUMB_VERTICAL : MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
+        moz_gtk_get_widget_min_size(thumbType, &(aResult->width), &(aResult->height));
+
+        // Add scrollbar's borders
+        nsIntMargin border;
+        nsNativeThemeGTK::GetWidgetBorder(aFrame->PresContext()->DeviceContext(),
+                                          aFrame, aWidgetType, &border);
+        aResult->width += border.left + border.right;
+        aResult->height += border.top + border.bottom;
+
+        // Add track's borders
+        uint8_t trackType = aWidgetType == NS_THEME_SCROLLBAR_VERTICAL ?
+          NS_THEME_SCROLLBARTRACK_VERTICAL : NS_THEME_SCROLLBARTRACK_HORIZONTAL;
+        nsNativeThemeGTK::GetWidgetBorder(aFrame->PresContext()->DeviceContext(),
+                                          aFrame, trackType, &border);
+        aResult->width += border.left + border.right;
+        aResult->height += border.top + border.bottom;
+      } else {
+        MozGtkScrollbarMetrics metrics;
+        moz_gtk_get_scrollbar_metrics(&metrics);
 
-      // Require room for the slider in the track if we don't have buttons.
-      bool hasScrollbarButtons = moz_gtk_has_scrollbar_buttons();
+        // Require room for the slider in the track if we don't have buttons.
+        bool hasScrollbarButtons = moz_gtk_has_scrollbar_buttons();
 
-      if (aWidgetType == NS_THEME_SCROLLBAR_VERTICAL) {
-        aResult->width = metrics.slider_width + 2 * metrics.trough_border;
-        if (!hasScrollbarButtons)
-          aResult->height = metrics.min_slider_size + 2 * metrics.trough_border;
-      } else {
-        aResult->height = metrics.slider_width + 2 * metrics.trough_border;
-        if (!hasScrollbarButtons)
-          aResult->width = metrics.min_slider_size + 2 * metrics.trough_border;
+        if (aWidgetType == NS_THEME_SCROLLBAR_VERTICAL) {
+          aResult->width = metrics.slider_width + 2 * metrics.trough_border;
+          if (!hasScrollbarButtons)
+            aResult->height = metrics.min_slider_size + 2 * metrics.trough_border;
+        } else {
+          aResult->height = metrics.slider_width + 2 * metrics.trough_border;
+          if (!hasScrollbarButtons)
+            aResult->width = metrics.min_slider_size + 2 * metrics.trough_border;
+        }
+        *aIsOverridable = false;
       }
 
-      *aIsOverridable = false;
     }
     break;
     case NS_THEME_SCROLLBARTHUMB_VERTICAL:
     case NS_THEME_SCROLLBARTHUMB_HORIZONTAL:
       {
-        MozGtkScrollbarMetrics metrics;
-        moz_gtk_get_scrollbar_metrics(&metrics);
-
-        if (aWidgetType == NS_THEME_SCROLLBARTHUMB_VERTICAL) {
-          aResult->width = metrics.slider_width;
-          aResult->height = metrics.min_slider_size;
+        if (gtk_check_version(3,20,0) == nullptr) {
+          moz_gtk_get_widget_min_size(NativeThemeToGtkTheme(aWidgetType, aFrame),
+                                      &(aResult->width), &(aResult->height));
         } else {
-          aResult->height = metrics.slider_width;
-          aResult->width = metrics.min_slider_size;
-        }
+          MozGtkScrollbarMetrics metrics;
+          moz_gtk_get_scrollbar_metrics(&metrics);
 
+          if (aWidgetType == NS_THEME_SCROLLBARTHUMB_VERTICAL) {
+            aResult->width = metrics.slider_width;
+            aResult->height = metrics.min_slider_size;
+          } else {
+            aResult->height = metrics.slider_width;
+            aResult->width = metrics.min_slider_size;
+          }
+        }
         *aIsOverridable = false;
       }
       break;
diff -up firefox-50.0/widget/gtk/nsNativeThemeGTK.h.widget-rebase firefox-50.0/widget/gtk/nsNativeThemeGTK.h
--- firefox-50.0/widget/gtk/nsNativeThemeGTK.h.widget-rebase	2016-07-25 22:22:07.000000000 +0200
+++ firefox-50.0/widget/gtk/nsNativeThemeGTK.h	2016-11-24 11:57:52.035064777 +0100
@@ -74,6 +74,7 @@ protected:
   virtual ~nsNativeThemeGTK();
 
 private:
+  GtkTextDirection GetTextDirection(nsIFrame* aFrame);
   gint GetTabMarginPixels(nsIFrame* aFrame);
   bool GetGtkWidgetAndState(uint8_t aWidgetType, nsIFrame* aFrame,
                             WidgetNodeType& aGtkWidgetType,
@@ -82,6 +83,7 @@ private:
                                nsIntMargin* aExtra);
 
   void RefreshWidgetWindow(nsIFrame* aFrame);
+  WidgetNodeType NativeThemeToGtkTheme(uint8_t aWidgetType, nsIFrame* aFrame);
 
   uint8_t mDisabledWidgetTypes[32];
   uint8_t mSafeWidgetStates[1024];    // 256 widgets * 32 bits per widget
diff -up firefox-50.0/widget/gtk/WidgetStyleCache.cpp.widget-rebase firefox-50.0/widget/gtk/WidgetStyleCache.cpp
--- firefox-50.0/widget/gtk/WidgetStyleCache.cpp.widget-rebase	2016-10-31 21:15:38.000000000 +0100
+++ firefox-50.0/widget/gtk/WidgetStyleCache.cpp	2016-11-24 11:57:52.035064777 +0100
@@ -25,6 +25,8 @@ static bool sStyleContextNeedsRestore;
 static GtkStyleContext* sCurrentStyleContext;
 #endif
 static GtkStyleContext*
+GetWidgetRootStyle(WidgetNodeType aNodeType);
+static GtkStyleContext*
 GetCssNodeStyleInternal(WidgetNodeType aNodeType);
 
 static GtkWidget*
@@ -93,14 +95,6 @@ CreateMenuPopupWidget()
 }
 
 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();
@@ -211,6 +205,235 @@ CreateEntryWidget()
 }
 
 static GtkWidget*
+CreateComboBoxWidget()
+{
+  GtkWidget* widget = gtk_combo_box_new();
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+typedef struct
+{
+  GType       type;
+  GtkWidget** widget;
+} GtkInnerWidgetInfo;
+
+static void
+GetInnerWidget(GtkWidget* widget, gpointer client_data)
+{
+  auto info = static_cast<GtkInnerWidgetInfo*>(client_data);
+
+  if (G_TYPE_CHECK_INSTANCE_TYPE(widget, info->type)) {
+    *info->widget = widget;
+  }
+
+  gtk_widget_realize(widget);
+}
+
+static GtkWidget*
+CreateComboBoxButtonWidget()
+{
+  GtkWidget* comboBox = GetWidget(MOZ_GTK_COMBOBOX);
+  GtkWidget* comboBoxButton = nullptr;
+
+  /* Get its inner Button */
+  GtkInnerWidgetInfo info = { GTK_TYPE_TOGGLE_BUTTON,
+                              &comboBoxButton };
+  gtk_container_forall(GTK_CONTAINER(comboBox),
+                       GetInnerWidget, &info);
+
+  if (!comboBoxButton) {
+    /* Shouldn't be reached with current internal gtk implementation; we
+     * use a generic toggle button as last resort fallback to avoid
+     * crashing. */
+    comboBoxButton = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
+  } else {
+    /* 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
+     * to NULL our pointers when they are about to become invalid because the
+     * corresponding widgets don't exist anymore. It's the role of
+     * 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 gProtoLayout and as
+     * such GTK holds a strong reference to them. */
+    g_object_add_weak_pointer(G_OBJECT(comboBoxButton),
+                              reinterpret_cast<gpointer *>(sWidgetStorage) +
+                              MOZ_GTK_COMBOBOX_BUTTON);
+  }
+
+  return comboBoxButton;
+}
+
+static GtkWidget*
+CreateComboBoxArrowWidget()
+{
+  GtkWidget* comboBoxButton = GetWidget(MOZ_GTK_COMBOBOX_BUTTON);
+  GtkWidget* comboBoxArrow = nullptr;
+
+  /* Get the widgets inside the Button */
+  GtkWidget* buttonChild = gtk_bin_get_child(GTK_BIN(comboBoxButton));
+  if (GTK_IS_BOX(buttonChild)) {
+    /* appears-as-list = FALSE, cell-view = TRUE; the button
+     * contains an hbox. This hbox is there because the ComboBox
+     * needs to place a cell renderer, a separator, and an arrow in
+     * the button when appears-as-list is FALSE. */
+    GtkInnerWidgetInfo info = { GTK_TYPE_ARROW,
+                                &comboBoxArrow };
+    gtk_container_forall(GTK_CONTAINER(buttonChild),
+                         GetInnerWidget, &info);
+  } else if (GTK_IS_ARROW(buttonChild)) {
+    /* appears-as-list = TRUE, or cell-view = FALSE;
+     * the button only contains an arrow */
+    comboBoxArrow = buttonChild;
+    gtk_widget_realize(comboBoxArrow);
+  }
+
+  if (!comboBoxArrow) {
+    /* Shouldn't be reached with current internal gtk implementation;
+     * we gButtonArrowWidget as last resort fallback to avoid
+     * crashing. */
+    comboBoxArrow = GetWidget(MOZ_GTK_BUTTON_ARROW);
+  } else {
+    g_object_add_weak_pointer(G_OBJECT(comboBoxArrow),
+                              reinterpret_cast<gpointer *>(sWidgetStorage) +
+                              MOZ_GTK_COMBOBOX_ARROW);
+  }
+
+  return comboBoxArrow;
+}
+
+static GtkWidget*
+CreateComboBoxSeparatorWidget()
+{
+  // Ensure to search for separator only once as it can fail
+  // TODO - it won't initialize after ResetWidgetCache() call
+  static bool isMissingSeparator = false;
+  if (isMissingSeparator)
+    return nullptr;
+
+  /* Get the widgets inside the Button */
+  GtkWidget* comboBoxSeparator = nullptr;
+  GtkWidget* buttonChild =
+    gtk_bin_get_child(GTK_BIN(GetWidget(MOZ_GTK_COMBOBOX_BUTTON)));
+  if (GTK_IS_BOX(buttonChild)) {
+    /* appears-as-list = FALSE, cell-view = TRUE; the button
+     * contains an hbox. This hbox is there because the ComboBox
+     * needs to place a cell renderer, a separator, and an arrow in
+     * the button when appears-as-list is FALSE. */
+    GtkInnerWidgetInfo info = { GTK_TYPE_SEPARATOR,
+                                &comboBoxSeparator };
+    gtk_container_forall(GTK_CONTAINER(buttonChild),
+                         GetInnerWidget, &info);
+  }
+
+  if (comboBoxSeparator) {
+    g_object_add_weak_pointer(G_OBJECT(comboBoxSeparator),
+                              reinterpret_cast<gpointer *>(sWidgetStorage) +
+                              MOZ_GTK_COMBOBOX_SEPARATOR);
+  } else {
+    /* comboBoxSeparator may be NULL
+     * when "appears-as-list" = TRUE or "cell-view" = FALSE;
+     * if there is no separator, then we just won't paint it. */
+    isMissingSeparator = true;
+  }
+
+  return comboBoxSeparator;
+}
+
+static GtkWidget*
+CreateComboBoxEntryWidget()
+{
+  GtkWidget* widget = gtk_combo_box_new_with_entry();
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateComboBoxEntryTextareaWidget()
+{
+  GtkWidget* comboBoxTextarea = nullptr;
+
+  /* Get its inner Entry and Button */
+  GtkInnerWidgetInfo info = { GTK_TYPE_ENTRY,
+                              &comboBoxTextarea };
+  gtk_container_forall(GTK_CONTAINER(GetWidget(MOZ_GTK_COMBOBOX_ENTRY)),
+                       GetInnerWidget, &info);
+
+  if (!comboBoxTextarea) {
+    comboBoxTextarea = GetWidget(MOZ_GTK_ENTRY);
+  } else {
+    g_object_add_weak_pointer(G_OBJECT(comboBoxTextarea),
+                              reinterpret_cast<gpointer *>(sWidgetStorage) +
+                              MOZ_GTK_COMBOBOX_ENTRY);
+  }
+
+  return comboBoxTextarea;
+}
+
+static GtkWidget*
+CreateComboBoxEntryButtonWidget()
+{
+  GtkWidget* comboBoxButton = nullptr;
+
+  /* Get its inner Entry and Button */
+  GtkInnerWidgetInfo info = { GTK_TYPE_TOGGLE_BUTTON,
+                              &comboBoxButton };
+  gtk_container_forall(GTK_CONTAINER(GetWidget(MOZ_GTK_COMBOBOX_ENTRY)),
+                       GetInnerWidget, &info);
+
+  if (!comboBoxButton) {
+    comboBoxButton = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
+  } else {
+    g_object_add_weak_pointer(G_OBJECT(comboBoxButton),
+                              reinterpret_cast<gpointer *>(sWidgetStorage) +
+                              MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
+  }
+
+  return comboBoxButton;
+}
+
+static GtkWidget*
+CreateComboBoxEntryArrowWidget()
+{
+  GtkWidget* comboBoxArrow = nullptr;
+
+  /* Get the Arrow inside the Button */
+  GtkWidget* buttonChild =
+    gtk_bin_get_child(GTK_BIN(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON)));
+
+  if (GTK_IS_BOX(buttonChild)) {
+   /* appears-as-list = FALSE, cell-view = TRUE; the button
+     * contains an hbox. This hbox is there because the ComboBox
+     * needs to place a cell renderer, a separator, and an arrow in
+     * the button when appears-as-list is FALSE. */
+    GtkInnerWidgetInfo info = { GTK_TYPE_ARROW,
+                                &comboBoxArrow };
+    gtk_container_forall(GTK_CONTAINER(buttonChild),
+                         GetInnerWidget, &info);
+  } else if (GTK_IS_ARROW(buttonChild)) {
+    /* appears-as-list = TRUE, or cell-view = FALSE;
+     * the button only contains an arrow */
+    comboBoxArrow = buttonChild;
+    gtk_widget_realize(comboBoxArrow);
+  }
+
+  if (!comboBoxArrow) {
+    /* Shouldn't be reached with current internal gtk implementation;
+     * we gButtonArrowWidget as last resort fallback to avoid
+     * crashing. */
+    comboBoxArrow = GetWidget(MOZ_GTK_BUTTON_ARROW);
+  } else {
+    g_object_add_weak_pointer(G_OBJECT(comboBoxArrow),
+                              reinterpret_cast<gpointer *>(sWidgetStorage) +
+                              MOZ_GTK_COMBOBOX_ENTRY_ARROW);
+  }
+
+  return comboBoxArrow;
+}
+
+static GtkWidget*
 CreateScrolledWindowWidget()
 {
   GtkWidget* widget = gtk_scrolled_window_new(nullptr, nullptr);
@@ -237,6 +460,95 @@ CreateMenuSeparatorWidget()
   return widget;
 }
 
+static GtkWidget*
+CreateTreeViewWidget()
+{
+  GtkWidget* widget = gtk_tree_view_new();
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateTreeHeaderCellWidget()
+{
+  /*
+   * Some GTK engines paint the first and last cell
+   * of a TreeView header with a highlight.
+   * Since we do not know where our widget will be relative
+   * to the other buttons in the TreeView header, we must
+   * paint it as a button that is between two others,
+   * thus ensuring it is neither the first or last button
+   * in the header.
+   * GTK doesn't give us a way to do this explicitly,
+   * so we must paint with a button that is between two
+   * others.
+   */
+  GtkTreeViewColumn* firstTreeViewColumn;
+  GtkTreeViewColumn* middleTreeViewColumn;
+  GtkTreeViewColumn* lastTreeViewColumn;
+
+  GtkWidget *treeView = GetWidget(MOZ_GTK_TREEVIEW);
+
+  /* Create and append our three columns */
+  firstTreeViewColumn = gtk_tree_view_column_new();
+  gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
+  gtk_tree_view_append_column(GTK_TREE_VIEW(treeView),
+                              firstTreeViewColumn);
+
+  middleTreeViewColumn = gtk_tree_view_column_new();
+  gtk_tree_view_column_set_title(middleTreeViewColumn, "M");
+  gtk_tree_view_append_column(GTK_TREE_VIEW(treeView),
+                              middleTreeViewColumn);
+
+  lastTreeViewColumn = gtk_tree_view_column_new();
+  gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
+  gtk_tree_view_append_column(GTK_TREE_VIEW(treeView),
+                              lastTreeViewColumn);
+
+  /* Use the middle column's header for our button */
+  return gtk_tree_view_column_get_button(middleTreeViewColumn);
+}
+
+static GtkWidget*
+CreateTreeHeaderSortArrowWidget()
+{
+  /* TODO, but it can't be NULL */
+  GtkWidget* widget = gtk_button_new();
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateHPanedWidget()
+{
+  GtkWidget* widget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateVPanedWidget()
+{
+  GtkWidget* widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateScaleWidget(GtkOrientation aOrientation)
+{
+  GtkWidget* widget = gtk_scale_new(aOrientation, nullptr);
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateNotebookWidget()
+{
+  GtkWidget* widget = gtk_notebook_new();
+  AddToWindowContainer(widget);
+  return widget;
+}
 
 static GtkWidget*
 CreateWidget(WidgetNodeType aWidgetType)
@@ -262,10 +574,6 @@ CreateWidget(WidgetNodeType aWidgetType)
       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:
@@ -294,6 +602,38 @@ CreateWidget(WidgetNodeType aWidgetType)
       return CreateScrolledWindowWidget();
     case MOZ_GTK_TEXT_VIEW:
       return CreateTextViewWidget();
+    case MOZ_GTK_TREEVIEW:
+      return CreateTreeViewWidget();
+    case MOZ_GTK_TREE_HEADER_CELL:
+      return CreateTreeHeaderCellWidget();
+    case MOZ_GTK_TREE_HEADER_SORTARROW:
+      return CreateTreeHeaderSortArrowWidget();
+    case MOZ_GTK_SPLITTER_HORIZONTAL:
+      return CreateHPanedWidget();
+    case MOZ_GTK_SPLITTER_VERTICAL:
+      return CreateVPanedWidget();
+    case MOZ_GTK_SCALE_HORIZONTAL:
+      return CreateScaleWidget(GTK_ORIENTATION_HORIZONTAL);
+    case MOZ_GTK_SCALE_VERTICAL:
+      return CreateScaleWidget(GTK_ORIENTATION_VERTICAL);
+    case MOZ_GTK_NOTEBOOK:
+      return CreateNotebookWidget();
+    case MOZ_GTK_COMBOBOX:
+      return CreateComboBoxWidget();
+    case MOZ_GTK_COMBOBOX_BUTTON:
+      return CreateComboBoxButtonWidget();
+    case MOZ_GTK_COMBOBOX_ARROW:
+      return CreateComboBoxArrowWidget();
+    case MOZ_GTK_COMBOBOX_SEPARATOR:
+      return CreateComboBoxSeparatorWidget();
+    case MOZ_GTK_COMBOBOX_ENTRY:
+      return CreateComboBoxEntryWidget();
+    case MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA:
+      return CreateComboBoxEntryTextareaWidget();
+    case MOZ_GTK_COMBOBOX_ENTRY_BUTTON:
+      return CreateComboBoxEntryButtonWidget();
+    case MOZ_GTK_COMBOBOX_ENTRY_ARROW:
+      return CreateComboBoxEntryArrowWidget();
     default:
       /* Not implemented */
       return nullptr;
@@ -314,27 +654,53 @@ GetWidget(WidgetNodeType aWidgetType)
 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);
+  static auto sGtkWidgetClassGetCSSName =
+    reinterpret_cast<const char* (*)(GtkWidgetClass*)>
+    (dlsym(RTLD_DEFAULT, "gtk_widget_class_get_css_name"));
+
+  GtkWidgetClass *widgetClass = GTK_WIDGET_GET_CLASS(aWidget);
+  const gchar* name = sGtkWidgetClassGetCSSName ?
+    sGtkWidgetClassGetCSSName(widgetClass) : nullptr;
+
+  GtkStyleContext *context =
+    CreateCSSNode(name, aParentStyle, G_TYPE_FROM_CLASS(widgetClass));
+
+  // Classes are stored on the style context instead of the path so that any
+  // future gtk_style_context_save() will inherit classes on the head CSS
+  // node, in the same way as happens when called on a style context owned by
+  // a widget.
+  //
+  // Classes can be stored on a GtkCssNodeDeclaration and/or the path.
+  // gtk_style_context_save() reuses the GtkCssNodeDeclaration, and appends a
+  // new object to the path, without copying the classes from the old path
+  // head.  The new head picks up classes from the GtkCssNodeDeclaration, but
+  // not the path.  GtkWidgets store their classes on the
+  // GtkCssNodeDeclaration, so make sure to add classes there.
+  //
+  // Picking up classes from the style context also means that
+  // https://bugzilla.gnome.org/show_bug.cgi?id=767312, which can stop
+  // gtk_widget_path_append_for_widget() from finding classes in GTK 3.20,
+  // is not a problem.
+  GtkStyleContext* widgetStyle = gtk_widget_get_style_context(aWidget);
+  GList* classes = gtk_style_context_list_classes(widgetStyle);
+  for (GList* link = classes; link; link = link->next) {
+    gtk_style_context_add_class(context, static_cast<gchar*>(link->data));
+  }
+  g_list_free(classes);
 
-  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;
 }
 
+static GtkStyleContext*
+CreateStyleForWidget(GtkWidget* aWidget, WidgetNodeType aParentType)
+{
+  return CreateStyleForWidget(aWidget, GetWidgetRootStyle(aParentType));
+}
+
 GtkStyleContext*
 CreateCSSNode(const char* aName, GtkStyleContext* aParentStyle, GType aType)
 {
@@ -342,13 +708,26 @@ CreateCSSNode(const char* aName, GtkStyl
     reinterpret_cast<void (*)(GtkWidgetPath *, gint, const char *)>
     (dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_set_object_name"));
 
-  GtkWidgetPath* path = aParentStyle ?
-    gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) :
-    gtk_widget_path_new();
+  GtkWidgetPath* path;
+  if (aParentStyle) {
+    path = gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle));
+    // Copy classes from the parent style context to its corresponding node in
+    // the path, because GTK will only match against ancestor classes if they
+    // are on the path.
+    GList* classes = gtk_style_context_list_classes(aParentStyle);
+    for (GList* link = classes; link; link = link->next) {
+      gtk_widget_path_iter_add_class(path, -1, static_cast<gchar*>(link->data));
+    }
+    g_list_free(classes);
+  } else {
+    path = gtk_widget_path_new();
+  }
 
   gtk_widget_path_append_type(path, aType);
 
-  (*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
+  if (sGtkWidgetPathIterSetObjectName) {
+    (*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
+  }
 
   GtkStyleContext *context = gtk_style_context_new();
   gtk_style_context_set_path(context, path);
@@ -358,6 +737,40 @@ CreateCSSNode(const char* aName, GtkStyl
   return context;
 }
 
+// Return a style context matching that of the root CSS node of a widget.
+// This is used by all GTK versions.
+static GtkStyleContext*
+GetWidgetRootStyle(WidgetNodeType aNodeType)
+{
+  GtkStyleContext* style = sStyleStorage[aNodeType];
+  if (style)
+    return style;
+
+  switch (aNodeType) {
+    case MOZ_GTK_MENUBARITEM:
+      style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUBAR);
+      break;
+    case MOZ_GTK_MENUITEM:
+      style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUPOPUP);
+      break;
+    case MOZ_GTK_CHECKMENUITEM:
+      style = CreateStyleForWidget(gtk_check_menu_item_new(), MOZ_GTK_MENUPOPUP);
+      break;
+    case MOZ_GTK_RADIOMENUITEM:
+      style = CreateStyleForWidget(gtk_radio_menu_item_new(nullptr),
+                                   MOZ_GTK_MENUPOPUP);
+      break;
+    default:
+      GtkWidget* widget = GetWidget(aNodeType);
+      MOZ_ASSERT(widget);
+      return gtk_widget_get_style_context(widget);
+  }
+
+  MOZ_ASSERT(style);
+  sStyleStorage[aNodeType] = style;
+  return style;
+}
+
 static GtkStyleContext*
 CreateChildCSSNode(const char* aName, WidgetNodeType aParentNodeType)
 {
@@ -367,7 +780,7 @@ CreateChildCSSNode(const char* aName, Wi
 static GtkStyleContext*
 GetWidgetStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass)
 {
-  GtkStyleContext* style = gtk_widget_get_style_context(GetWidget(aWidgetType));
+  GtkStyleContext* style = GetWidgetRootStyle(aWidgetType);
   gtk_style_context_save(style);
   MOZ_ASSERT(!sStyleContextNeedsRestore);
   sStyleContextNeedsRestore = true;
@@ -408,6 +821,10 @@ GetCssNodeStyleInternal(WidgetNodeType a
       style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
                                  MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL);
       break;
+    case MOZ_GTK_SCROLLBAR_BUTTON:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_BUTTON,
+                                 MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL);
+      break;
     case MOZ_GTK_RADIOBUTTON:
       style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
                                  MOZ_GTK_RADIOBUTTON_CONTAINER);
@@ -416,6 +833,14 @@ GetCssNodeStyleInternal(WidgetNodeType a
       style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
                                  MOZ_GTK_CHECKBUTTON_CONTAINER);
       break;
+    case MOZ_GTK_RADIOMENUITEM_INDICATOR:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
+                                 MOZ_GTK_RADIOMENUITEM);
+      break;
+    case MOZ_GTK_CHECKMENUITEM_INDICATOR:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
+                                 MOZ_GTK_CHECKMENUITEM);
+      break;
     case MOZ_GTK_PROGRESS_TROUGH:
       /* Progress bar background (trough) */
       style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
@@ -451,11 +876,77 @@ GetCssNodeStyleInternal(WidgetNodeType a
       return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW,
                                      GTK_STYLE_CLASS_VIEW);
     case MOZ_GTK_FRAME_BORDER:
-      return CreateChildCSSNode("border", MOZ_GTK_FRAME);
-    default:
-      // TODO - create style from style path
-      GtkWidget* widget = GetWidget(aNodeType);
+      style = CreateChildCSSNode("border", MOZ_GTK_FRAME);
+      break;
+    case MOZ_GTK_TREEVIEW_VIEW:
+      // TODO - create from CSS node
+      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
+                                     GTK_STYLE_CLASS_VIEW);
+    case MOZ_GTK_TREEVIEW_EXPANDER:
+      // TODO - create from CSS node
+      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
+                                     GTK_STYLE_CLASS_EXPANDER);
+    case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
+      style = CreateChildCSSNode("separator",
+                                 MOZ_GTK_SPLITTER_HORIZONTAL);
+      break;
+    case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
+      style = CreateChildCSSNode("separator",
+                                 MOZ_GTK_SPLITTER_VERTICAL);
+      break;
+    case MOZ_GTK_SCALE_CONTENTS_HORIZONTAL:
+      style = CreateChildCSSNode("contents",
+                                 MOZ_GTK_SCALE_HORIZONTAL);
+      break;
+    case MOZ_GTK_SCALE_CONTENTS_VERTICAL:
+      style = CreateChildCSSNode("contents",
+                                 MOZ_GTK_SCALE_VERTICAL);
+      break; 
+    case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
+                                 MOZ_GTK_SCALE_CONTENTS_HORIZONTAL);
+      break; 
+    case MOZ_GTK_SCALE_TROUGH_VERTICAL:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
+                                 MOZ_GTK_SCALE_CONTENTS_VERTICAL);
+      break;
+    case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
+                                 MOZ_GTK_SCALE_TROUGH_HORIZONTAL);
+      break;
+    case MOZ_GTK_SCALE_THUMB_VERTICAL:
+      style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
+                                 MOZ_GTK_SCALE_TROUGH_VERTICAL);
+      break;
+    case MOZ_GTK_TAB_TOP:
+    {
+      // TODO - create from CSS node
+      style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
+                                      GTK_STYLE_CLASS_TOP);
+      gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
+                                   static_cast<GtkRegionFlags>(0));
+      return style;
+    }
+    case MOZ_GTK_TAB_BOTTOM:
+    {
+      // TODO - create from CSS node
+      style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
+                                      GTK_STYLE_CLASS_BOTTOM);
+      gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
+                                   static_cast<GtkRegionFlags>(0));
+      return style;
+    }
+    case MOZ_GTK_NOTEBOOK:
+    case MOZ_GTK_NOTEBOOK_HEADER:
+    case MOZ_GTK_TABPANELS:
+    case MOZ_GTK_TAB_SCROLLARROW:
+    { 
+      // TODO - create from CSS node
+      GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
       return gtk_widget_get_style_context(widget);
+    }
+    default:
+      return GetWidgetRootStyle(aNodeType);
   }
 
   MOZ_ASSERT(style, "missing style context for node type");
@@ -486,6 +977,12 @@ GetWidgetStyleInternal(WidgetNodeType aN
     case MOZ_GTK_CHECKBUTTON:
       return GetWidgetStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
                                      GTK_STYLE_CLASS_CHECK);
+    case MOZ_GTK_RADIOMENUITEM_INDICATOR:
+      return GetWidgetStyleWithClass(MOZ_GTK_RADIOMENUITEM,
+                                     GTK_STYLE_CLASS_RADIO);
+    case MOZ_GTK_CHECKMENUITEM_INDICATOR:
+      return GetWidgetStyleWithClass(MOZ_GTK_CHECKMENUITEM,
+                                     GTK_STYLE_CLASS_CHECK);
     case MOZ_GTK_PROGRESS_TROUGH:
       return GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR,
                                      GTK_STYLE_CLASS_TROUGH);
@@ -519,11 +1016,57 @@ GetWidgetStyleInternal(WidgetNodeType aN
       return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW,
                                      GTK_STYLE_CLASS_VIEW);
     case MOZ_GTK_FRAME_BORDER:
-      return GetWidgetStyleInternal(MOZ_GTK_FRAME);
-    default:
-      GtkWidget* widget = GetWidget(aNodeType);
-      MOZ_ASSERT(widget);
+      return GetWidgetRootStyle(MOZ_GTK_FRAME);
+    case MOZ_GTK_TREEVIEW_VIEW:
+      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
+                                     GTK_STYLE_CLASS_VIEW);
+    case MOZ_GTK_TREEVIEW_EXPANDER:
+      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
+                                     GTK_STYLE_CLASS_EXPANDER);
+    case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
+      return GetWidgetStyleWithClass(MOZ_GTK_SPLITTER_HORIZONTAL,
+                                     GTK_STYLE_CLASS_PANE_SEPARATOR);
+    case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
+      return GetWidgetStyleWithClass(MOZ_GTK_SPLITTER_VERTICAL,
+                                     GTK_STYLE_CLASS_PANE_SEPARATOR);
+    case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
+      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
+                                     GTK_STYLE_CLASS_TROUGH);
+    case MOZ_GTK_SCALE_TROUGH_VERTICAL:
+      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
+                                     GTK_STYLE_CLASS_TROUGH);
+    case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
+      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
+                                     GTK_STYLE_CLASS_SLIDER);
+    case MOZ_GTK_SCALE_THUMB_VERTICAL:
+      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
+                                     GTK_STYLE_CLASS_SLIDER);
+    case MOZ_GTK_TAB_TOP:
+    {
+      GtkStyleContext* style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
+                                                       GTK_STYLE_CLASS_TOP);
+      gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
+                                   static_cast<GtkRegionFlags>(0));
+      return style;
+    }
+    case MOZ_GTK_TAB_BOTTOM:
+    {
+      GtkStyleContext* style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
+                                                       GTK_STYLE_CLASS_BOTTOM);
+      gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
+                                   static_cast<GtkRegionFlags>(0));
+      return style;
+    }
+    case MOZ_GTK_NOTEBOOK:
+    case MOZ_GTK_NOTEBOOK_HEADER:
+    case MOZ_GTK_TABPANELS:
+    case MOZ_GTK_TAB_SCROLLARROW:
+    { 
+      GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
       return gtk_widget_get_style_context(widget);
+    }
+    default:
+      return GetWidgetRootStyle(aNodeType);
   }
 }
 
diff -up firefox-50.0/widget/gtk/WidgetStyleCache.h.widget-rebase firefox-50.0/widget/gtk/WidgetStyleCache.h
--- firefox-50.0/widget/gtk/WidgetStyleCache.h.widget-rebase	2016-10-31 21:15:38.000000000 +0100
+++ firefox-50.0/widget/gtk/WidgetStyleCache.h	2016-11-24 11:57:52.035064777 +0100
@@ -28,7 +28,6 @@ GetWidget(WidgetNodeType aNodeType);
 GtkStyleContext*
 CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle);
 
-// CreateCSSNode is implemented for gtk >= 3.20 only.
 GtkStyleContext*
 CreateCSSNode(const char*      aName,
               GtkStyleContext* aParentStyle,