Blob Blame History Raw
diff -up firefox-51.0/widget/gtk/gtk3drawing.cpp.old firefox-51.0/widget/gtk/gtk3drawing.cpp
--- firefox-51.0/widget/gtk/gtk3drawing.cpp.old	2017-01-18 16:24:56.375732107 +0100
+++ firefox-51.0/widget/gtk/gtk3drawing.cpp	2017-01-10 11:28:15.000000000 +0100
@@ -18,16 +18,6 @@
 
 #include <math.h>
 
-static GtkWidget* gProtoLayout;
-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 style_prop_t style_prop_func;
 static gboolean have_arrow_scaling;
 static gboolean checkbox_check_state;
@@ -46,6 +36,10 @@ static gboolean is_initialized;
 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)
 {
@@ -79,212 +73,6 @@ moz_gtk_enable_style_props(style_prop_t
     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;
-}
-
-/* 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;
-}
-
 gint
 moz_gtk_init()
 {
@@ -336,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;
 }
@@ -364,7 +160,7 @@ moz_gtk_menuitem_get_horizontal_padding(
 gint
 moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding)
 {
-    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_CHECKMENUITEM_CONTAINER);
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_CHECKMENUITEM);
     gtk_style_context_get_style(style,
                                 "horizontal-padding", horizontal_padding,
                                 nullptr);
@@ -636,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)
@@ -675,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,
@@ -742,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)
@@ -766,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);
@@ -795,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);
 
@@ -980,65 +846,31 @@ 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;
 }
 
 static gint
-moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* rect,
+moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* aRect,
                         GtkWidgetState* state,
                         GtkTextDirection direction)
 {
@@ -1046,24 +878,29 @@ moz_gtk_text_view_paint(cairo_t *cr, Gdk
 
     GtkStyleContext* style_frame =
         ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction, state_flags);
-    gtk_render_frame(style_frame, cr, rect->x, rect->y, rect->width, rect->height);
+    gtk_render_frame(style_frame, cr,
+                     aRect->x, aRect->y, aRect->width, aRect->height);
+
+    GdkRectangle rect = *aRect;
+    InsetByBorderPadding(&rect, style_frame);
 
-    GtkBorder border, padding;
-    gtk_style_context_get_border(style_frame, state_flags, &border);
-    gtk_style_context_get_padding(style_frame, state_flags, &padding);
     ReleaseStyleContext(style_frame);
 
     GtkStyleContext* style =
         ClaimStyleContext(MOZ_GTK_TEXT_VIEW, direction, state_flags);
-
-    gint xthickness = border.left + padding.left;
-    gint ythickness = border.top + padding.top;
-
-    gtk_render_background(style, cr,
-                          rect->x + xthickness, rect->y + ythickness,
-                          rect->width - 2 * xthickness,
-                          rect->height - 2 * ythickness);
-
+    gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
+    ReleaseStyleContext(style);
+    // There is a separate "text" window, which usually provides the
+    // background behind the text.  However, this is transparent in Ambiance
+    // for GTK 3.20, in which case the MOZ_GTK_TEXT_VIEW background is
+    // visible.
+    // Workaround for Bug 1328899 - We don't want "selected" background color
+    // for active view class here which is set by Ambiance theme.
+    if (state->focused && !state->disabled) {
+        state_flags = static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED);
+    }
+    style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW_TEXT, direction, state_flags);
+    gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
     ReleaseStyleContext(style);
 
     return MOZ_GTK_SUCCESS;
@@ -1198,34 +1035,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,
@@ -1309,15 +1149,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);
@@ -1325,15 +1164,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;
 }
 
@@ -1353,7 +1191,6 @@ moz_gtk_container_paint(cairo_t *cr, Gdk
     }
 
     ReleaseStyleContext(style);
-
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1439,13 +1276,52 @@ 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);
-    ReleaseStyleContext(style);
+    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);
+    ReleaseStyleContext(style);
+
+    // 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 = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX, direction);
+
+    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);
+    ReleaseStyleContext(boxStyle);
+
+    GtkStyleContext* labelStyle =
+        ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL, direction);
+    moz_gtk_draw_styled_frame(labelStyle, cr, &rect, false);
+    ReleaseStyleContext(labelStyle);
+
     return MOZ_GTK_SUCCESS;
 }
 
@@ -1454,17 +1330,9 @@ moz_gtk_resizer_paint(cairo_t *cr, GdkRe
                       GtkWidgetState* state,
                       GtkTextDirection direction)
 {
-    GtkStyleContext* style;
-
-    // gtk_render_handle() draws a background, so use GtkTextView and its
-    // GTK_STYLE_CLASS_VIEW to match the background with textarea elements.
-    // The resizer is drawn with shaded variants of the background color, and
-    // so a transparent background would lead to a transparent resizer.
-    style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW, GTK_TEXT_DIR_LTR,
-                              GetStateFlagsFromGtkWidgetState(state));
-    // TODO - we need to save/restore style when gtk 3.20 CSS node path
-    // is used
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
+    GtkStyleContext* style =
+        ClaimStyleContext(MOZ_GTK_RESIZER, GTK_TEXT_DIR_LTR,
+                          GetStateFlagsFromGtkWidgetState(state));
 
     // Workaround unico not respecting the text direction for resizers.
     // See bug 1174248.
@@ -1511,17 +1379,8 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
                              GtkTextDirection direction,
                              WidgetNodeType widget)
 {
-    GtkStyleContext* style;
-
-    if (gtk_check_version(3, 20, 0) != nullptr) {
-      /* Ask for MOZ_GTK_PROGRESS_TROUGH instead of MOZ_GTK_PROGRESSBAR
-       * because ClaimStyleContext() saves/restores that style */
-      style = ClaimStyleContext(MOZ_GTK_PROGRESS_TROUGH, direction);
-      gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
-      gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR);
-    } else {
-      style = ClaimStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction);
-    }
+    GtkStyleContext* style =
+        ClaimStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction);
 
     if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
         widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
@@ -1905,6 +1764,13 @@ 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;
@@ -1952,36 +1818,39 @@ moz_gtk_menu_item_paint(WidgetNodeType w
                         GtkWidgetState* state, GtkTextDirection direction)
 {
     gint x, y, w, h;
+    guint minorVersion = gtk_get_minor_version();
+    GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
 
-    if (state->inHover && !state->disabled) {   
-        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);
-            }
+    // GTK versions prior to 3.8 render the background and frame only when not
+    // a separator and in hover prelight.
+    if (minorVersion < 8 && (widget == MOZ_GTK_MENUSEPARATOR ||
+                             !(state_flags & GTK_STATE_FLAG_PRELIGHT)))
+        return MOZ_GTK_SUCCESS;
+
+    GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags);
+
+    if (minorVersion < 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;
-        y = rect->y;
-        w = rect->width;
-        h = rect->height;
+    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 (minorVersion < 6) {
+        gtk_style_context_restore(style);
     }
+    ReleaseStyleContext(style);
 
     return MOZ_GTK_SUCCESS;
 }
@@ -2001,16 +1870,16 @@ 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 indicator_size, horizontal_padding;
     gint x, y;
 
@@ -2020,35 +1889,44 @@ moz_gtk_check_menu_item_paint(cairo_t *c
       state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
     }
 
-    style = ClaimStyleContext(isradio ? MOZ_GTK_RADIOMENUITEM_CONTAINER :
-                                        MOZ_GTK_CHECKMENUITEM_CONTAINER,
-                              direction);
+    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 (pre_3_20) {
+        GtkBorder padding;
+        gtk_style_context_get_padding(style, state_flags, &padding);
+        offset = horizontal_padding + padding.left + 2;
+    } else {
+        GdkRectangle r = { 0 };
+        InsetByMargin(&r, style);
+        InsetByBorderPadding(&r, style);
+        offset = r.x;
+    }
     ReleaseStyleContext(style);
 
-    style = ClaimStyleContext(isradio ? MOZ_GTK_RADIOMENUITEM :
-                                        MOZ_GTK_CHECKMENUITEM,
-                              direction, state_flags);
-    gtk_style_context_get_padding(style, state_flags, &padding);
-    gint offset = 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 (gtk_check_version(3, 20, 0) == nullptr) {
+    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) {
+    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);
@@ -2074,6 +1952,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)
 {
@@ -2101,6 +1993,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,
@@ -2129,9 +2030,6 @@ moz_gtk_get_widget_border(WidgetNodeType
             if (widget == MOZ_GTK_TOOLBAR_BUTTON)
                 gtk_style_context_restore(style);
 
-            // XXX: Subtract 1 pixel from the border to account for the added
-            // -moz-focus-inner border (Bug 1228281).
-            *left -= 1; *top -= 1; *right -= 1; *bottom -= 1;
             moz_gtk_add_style_border(style, left, top, right, bottom);
 
             ReleaseStyleContext(style);
@@ -2179,12 +2077,10 @@ moz_gtk_get_widget_border(WidgetNodeType
         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:
         {
@@ -2196,32 +2092,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;
@@ -2271,12 +2168,15 @@ moz_gtk_get_widget_border(WidgetNodeType
         {
             // Bug 1274143 for MOZ_GTK_MENUBARITEM
             WidgetNodeType type =
-                widget == MOZ_GTK_MENUBARITEM || widget == MOZ_GTK_MENUITEM ?
-                MOZ_GTK_MENUITEM : MOZ_GTK_CHECKMENUITEM_CONTAINER;
+                widget == MOZ_GTK_MENUBARITEM ? MOZ_GTK_MENUITEM : widget;
             style = ClaimStyleContext(type);
 
-            moz_gtk_add_style_padding(style, left, top, right, bottom);
-
+            if (gtk_get_minor_version() < 20) {
+                moz_gtk_add_style_padding(style, left, top, right, bottom);
+            } else {
+                moz_gtk_add_margin_border_padding(style,
+                                                  left, top, right, bottom);
+            }
             ReleaseStyleContext(style);
             return MOZ_GTK_SUCCESS;
         }
@@ -2285,12 +2185,81 @@ moz_gtk_get_widget_border(WidgetNodeType
         break;
     case MOZ_GTK_TOOLTIP:
         {
-            style = ClaimStyleContext(MOZ_GTK_TOOLTIP);
-            moz_gtk_add_style_border(style, left, top, right, bottom);
-            moz_gtk_add_style_padding(style, left, top, right, bottom);
-            ReleaseStyleContext(style);
+            // 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 = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX);
+            moz_gtk_add_margin_border_padding(boxStyle,
+                                              left, top, right, bottom);
+            ReleaseStyleContext(boxStyle);
+
+            GtkStyleContext* labelStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL);
+            moz_gtk_add_margin_border_padding(labelStyle,
+                                              left, top, right, bottom);
+            ReleaseStyleContext(labelStyle);
+
             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:
@@ -2299,10 +2268,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:
@@ -2390,9 +2355,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;
 
@@ -2421,8 +2386,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);
@@ -2588,6 +2552,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,
@@ -2598,40 +2565,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;
-
-    settings = gtk_widget_get_settings(GetWidget(MOZ_GTK_IMAGEMENUITEM));
-
-    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,
@@ -2672,10 +2608,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:
@@ -2702,9 +2653,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,
@@ -2729,9 +2684,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;
@@ -2743,9 +2702,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:
@@ -2819,10 +2782,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);
@@ -2870,16 +2831,6 @@ moz_gtk_shutdown()
     /* This will destroy all of our widgets */
     ResetWidgetCache();
 
-    gProtoLayout = NULL;
-    gComboBoxWidget = NULL;
-    gComboBoxButtonWidget = NULL;
-    gComboBoxSeparatorWidget = NULL;
-    gComboBoxArrowWidget = NULL;
-    gComboBoxEntryWidget = NULL;
-    gComboBoxEntryButtonWidget = NULL;
-    gComboBoxEntryArrowWidget = NULL;
-    gComboBoxEntryTextareaWidget = NULL;
-
     is_initialized = FALSE;
 
     return MOZ_GTK_SUCCESS;
diff -up firefox-51.0/widget/gtk/gtkdrawing.h.old firefox-51.0/widget/gtk/gtkdrawing.h
--- firefox-51.0/widget/gtk/gtkdrawing.h.old	2017-01-16 17:16:53.000000000 +0100
+++ firefox-51.0/widget/gtk/gtkdrawing.h	2017-01-06 10:20:43.000000000 +0100
@@ -145,8 +145,11 @@ typedef enum {
   MOZ_GTK_ENTRY,
   /* Paints a GtkExpander. */
   MOZ_GTK_EXPANDER,
-  /* Paints a GtkTextView. */
+  /* Paints a GtkTextView or gets the style context corresponding to the
+     root node of a GtkTextView. */
   MOZ_GTK_TEXT_VIEW,
+  /* The "text" window or node of a GtkTextView */
+  MOZ_GTK_TEXT_VIEW_TEXT,
   /* Paints a GtkOptionMenu. */
   MOZ_GTK_DROPDOWN,
   /* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */
@@ -160,11 +163,15 @@ typedef enum {
   MOZ_GTK_TOOLBAR_SEPARATOR,
   /* Paints a GtkToolTip */
   MOZ_GTK_TOOLTIP,
+  /* Paints a GtkBox from GtkToolTip  */
+  MOZ_GTK_TOOLTIP_BOX,
+  /* Paints a GtkLabel of GtkToolTip */
+  MOZ_GTK_TOOLTIP_BOX_LABEL,
   /* Paints a GtkFrame (e.g. a status bar panel). */
   MOZ_GTK_FRAME,
   /* Paints the border of a GtkFrame */
   MOZ_GTK_FRAME_BORDER,
-  /* Paints a resize grip for a GtkWindow */
+  /* Paints a resize grip for a GtkTextView */
   MOZ_GTK_RESIZER,
   /* Paints a GtkProgressBar. */
   MOZ_GTK_PROGRESSBAR,
@@ -210,11 +217,13 @@ typedef enum {
   MOZ_GTK_MENUBARITEM,
   /* Paints items of popup menus. */
   MOZ_GTK_MENUITEM,
-  MOZ_GTK_IMAGEMENUITEM,
-  MOZ_GTK_CHECKMENUITEM_CONTAINER,
-  MOZ_GTK_RADIOMENUITEM_CONTAINER,
+  /* 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,
   /* GtkVPaned base class */
   MOZ_GTK_SPLITTER_HORIZONTAL,
@@ -230,6 +239,22 @@ typedef enum {
   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,
 
@@ -505,23 +530,18 @@ gint
 moz_gtk_get_tab_thickness(WidgetNodeType aNodeType);
 
 /**
- * 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);
-
-/**
  * Get a boolean which indicates whether the theme draws scrollbar buttons.
  * If TRUE, draw scrollbar buttons.
  */
 gboolean moz_gtk_has_scrollbar_buttons(void);
 
+/**
+ * Get minimum widget size as sum of margin, padding, border and min-width,
+ * min-height.
+ */
+void moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width,
+                                 int* height);
+
 #if (MOZ_WIDGET_GTK == 2)
 #ifdef __cplusplus
 }
diff -up firefox-51.0/widget/gtk/mozgtk/mozgtk.c.old firefox-51.0/widget/gtk/mozgtk/mozgtk.c
--- firefox-51.0/widget/gtk/mozgtk/mozgtk.c.old	2017-01-18 16:26:11.416376760 +0100
+++ firefox-51.0/widget/gtk/mozgtk/mozgtk.c	2016-12-21 13:10:28.000000000 +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)
@@ -577,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)
@@ -612,6 +612,9 @@ STUB(gdkx_visual_get)
 STUB(gtk_object_get_type)
 #endif
 
+#ifndef GTK3_SYMBOLS
+// Only define the following workaround when using GTK3, which we detect
+// by checking if GTK3 stubs are not provided.
 #include <X11/Xlib.h>
 // Bug 1271100
 // We need to trick system Cairo into not using the XShm extension due to
@@ -625,4 +628,5 @@ XShmQueryExtension(Display* aDisplay)
 {
   return False;
 }
+#endif
 
diff -up firefox-51.0/widget/gtk/nsLookAndFeel.cpp.old firefox-51.0/widget/gtk/nsLookAndFeel.cpp
--- firefox-51.0/widget/gtk/nsLookAndFeel.cpp.old	2017-01-18 16:25:23.072605687 +0100
+++ firefox-51.0/widget/gtk/nsLookAndFeel.cpp	2017-01-06 10:20:43.000000000 +0100
@@ -47,9 +47,6 @@ nsLookAndFeel::nsLookAndFeel()
     : nsXPLookAndFeel(),
 #if (MOZ_WIDGET_GTK == 2)
       mStyle(nullptr),
-#else
-      mBackgroundStyle(nullptr),
-      mButtonStyle(nullptr),
 #endif
       mDefaultFontCached(false), mButtonFontCached(false),
       mFieldFontCached(false), mMenuFontCached(false)
@@ -61,13 +58,27 @@ nsLookAndFeel::~nsLookAndFeel()
 {
 #if (MOZ_WIDGET_GTK == 2)
     g_object_unref(mStyle);
-#else
-    g_object_unref(mBackgroundStyle);
-    g_object_unref(mButtonStyle);
 #endif
 }
 
 #if MOZ_WIDGET_GTK != 2
+// Modifies color |*aDest| as if a pattern of color |aSource| was painted with
+// CAIRO_OPERATOR_OVER to a surface with color |*aDest|.
+static void
+ApplyColorOver(const GdkRGBA& aSource, GdkRGBA* aDest) {
+    gdouble sourceCoef = aSource.alpha;
+    gdouble destCoef = aDest->alpha * (1.0 - sourceCoef);
+    gdouble resultAlpha = sourceCoef + destCoef;
+    if (resultAlpha != 0.0) { // don't divide by zero
+        destCoef /= resultAlpha;
+        sourceCoef /= resultAlpha;
+        aDest->red = sourceCoef * aSource.red + destCoef * aDest->red;
+        aDest->green = sourceCoef * aSource.green + destCoef * aDest->green;
+        aDest->blue = sourceCoef * aSource.blue + destCoef * aDest->blue;
+        aDest->alpha = resultAlpha;
+    }
+}
+
 static void
 GetLightAndDarkness(const GdkRGBA& aColor,
                     double* aLightness, double* aDarkness)
@@ -157,30 +168,55 @@ GetUnicoBorderGradientColors(GtkStyleCon
     return result;
 }
 
-
-static void
+// Sets |aLightColor| and |aDarkColor| to colors from |aContext|.  Returns
+// true if |aContext| uses these colors to render a visible border.
+// If returning false, then the colors returned are a fallback from the
+// border-color value even though |aContext| does not use these colors to
+// render a border.
+static bool
 GetBorderColors(GtkStyleContext* aContext,
                 GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
 {
-    if (GetUnicoBorderGradientColors(aContext, aLightColor, aDarkColor))
-        return;
-
+    // Determine whether the border on this style context is visible.
     GtkStateFlags state = gtk_style_context_get_state(aContext);
+    GtkBorderStyle borderStyle;
+    gtk_style_context_get(aContext, state, GTK_STYLE_PROPERTY_BORDER_STYLE,
+                          &borderStyle, nullptr);
+    bool visible = borderStyle != GTK_BORDER_STYLE_NONE &&
+        borderStyle != GTK_BORDER_STYLE_HIDDEN;
+    if (visible) {
+        // GTK has an initial value of zero for border-widths, and so themes
+        // need to explicitly set border-widths to make borders visible.
+        GtkBorder border;
+        gtk_style_context_get_border(aContext, GTK_STATE_FLAG_NORMAL, &border);
+        visible = border.top != 0 || border.right != 0 ||
+            border.bottom != 0 || border.left != 0;
+    }
+
+    if (visible &&
+        GetUnicoBorderGradientColors(aContext, aLightColor, aDarkColor))
+        return true;
+
+    // The initial value for the border-color is the foreground color, and so
+    // this will usually return a color distinct from the background even if
+    // there is no visible border detected.
     gtk_style_context_get_border_color(aContext, state, aDarkColor);
     // TODO GTK3 - update aLightColor
     // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles.
     // https://bugzilla.mozilla.org/show_bug.cgi?id=978172#c25
     *aLightColor = *aDarkColor;
+    return visible;
 }
 
-static void
+static bool
 GetBorderColors(GtkStyleContext* aContext,
                 nscolor* aLightColor, nscolor* aDarkColor)
 {
     GdkRGBA lightColor, darkColor;
-    GetBorderColors(aContext, &lightColor, &darkColor);
+    bool ret = GetBorderColors(aContext, &lightColor, &darkColor);
     *aLightColor = GDK_RGBA_TO_NS_RGBA(lightColor);
     *aDarkColor = GDK_RGBA_TO_NS_RGBA(darkColor);
+    return ret;
 }
 #endif
 
@@ -352,30 +388,39 @@ nsLookAndFeel::NativeGetColor(ColorID aI
         break;
 #else
         // css2  http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
-    case eColorID_activeborder:
+    case eColorID_activeborder: {
         // active window border
-        gtk_style_context_get_border_color(mBackgroundStyle, 
+        GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW);
+        gtk_style_context_get_border_color(style,
                                            GTK_STATE_FLAG_NORMAL, &gdk_color);
         aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+        ReleaseStyleContext(style);
         break;
-    case eColorID_inactiveborder:
+    }
+    case eColorID_inactiveborder: {
         // inactive window border
-        gtk_style_context_get_border_color(mBackgroundStyle, 
-                                           GTK_STATE_FLAG_INSENSITIVE, 
+        GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW);
+        gtk_style_context_get_border_color(style,
+                                           GTK_STATE_FLAG_INSENSITIVE,
                                            &gdk_color);
         aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+        ReleaseStyleContext(style);
         break;
+    }
     case eColorID_graytext: // disabled text in windows, menus, etc.
     case eColorID_inactivecaptiontext: // text in inactive window caption
         aColor = sMenuTextInactive;
         break;
-    case eColorID_inactivecaption:
+    case eColorID_inactivecaption: {
         // inactive window caption
-        gtk_style_context_get_background_color(mBackgroundStyle, 
+        GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW);
+        gtk_style_context_get_background_color(style,
                                                GTK_STATE_FLAG_INSENSITIVE, 
                                                &gdk_color);
         aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+        ReleaseStyleContext(style);
         break;
+    }
 #endif
     case eColorID_infobackground:
         // tooltip background color
@@ -496,18 +541,24 @@ nsLookAndFeel::NativeGetColor(ColorID aI
     case eColorID__moz_fieldtext:
         aColor = sMozFieldText;
         break;
-    case eColorID__moz_buttondefault:
-      // default button border color
-        gtk_style_context_get_border_color(mButtonStyle, 
+    case eColorID__moz_buttondefault: {
+        // default button border color
+        GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
+        gtk_style_context_get_border_color(style,
                                            GTK_STATE_FLAG_NORMAL, &gdk_color);
         aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+        ReleaseStyleContext(style);
         break;
-    case eColorID__moz_buttonhoverface:
-        gtk_style_context_get_background_color(mButtonStyle, 
+    }
+    case eColorID__moz_buttonhoverface: {
+        GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
+        gtk_style_context_get_background_color(style,
                                                GTK_STATE_FLAG_PRELIGHT, 
                                                &gdk_color);
         aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+        ReleaseStyleContext(style);
         break;
+    }
     case eColorID__moz_buttonhovertext:
         aColor = sButtonHoverText;
         break;
@@ -784,12 +835,6 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
     case eIntID_SpellCheckerUnderlineStyle:
         aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
         break;
-    case eIntID_ImagesInMenus:
-        aResult = moz_gtk_images_in_menus();
-        break;
-    case eIntID_ImagesInButtons:
-        aResult = moz_gtk_images_in_buttons();
-        break;
     case eIntID_MenuBarDrag:
         aResult = sMenuSupportsDrag;
         break;
@@ -1010,16 +1055,6 @@ nsLookAndFeel::GetFontImpl(FontID aID, n
   return true;
 }
 
-#if (MOZ_WIDGET_GTK == 3)
-static GtkStyleContext*
-create_context(GtkWidgetPath *path)
-{
-    GtkStyleContext *style = gtk_style_context_new();
-    gtk_style_context_set_path(style, path);
-    return(style);
-}
-#endif
-
 void
 nsLookAndFeel::Init()
 {
@@ -1110,78 +1145,54 @@ nsLookAndFeel::Init()
         g_object_set(settings, dark_setting, FALSE, nullptr);
     }
 
-    GtkWidgetPath *path = gtk_widget_path_new();
-    gtk_widget_path_append_type(path, GTK_TYPE_WINDOW);
-
-    mBackgroundStyle = create_context(path);
-    gtk_style_context_add_class(mBackgroundStyle, GTK_STYLE_CLASS_BACKGROUND);
-
-    mButtonStyle = create_context(path);
-    gtk_style_context_add_class(mButtonStyle, GTK_STYLE_CLASS_BUTTON); 
-
     // Scrollbar colors
-    style = create_context(path);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCROLLBAR);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
+    style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sMozScrollbar = GDK_RGBA_TO_NS_RGBA(color);
-    g_object_unref(style);
+    ReleaseStyleContext(style);
 
     // Window colors
-    style = create_context(path);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
+    style = ClaimStyleContext(MOZ_GTK_WINDOW);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sMozWindowBackground = GDK_RGBA_TO_NS_RGBA(color);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sMozWindowText = GDK_RGBA_TO_NS_RGBA(color);
-    gtk_style_context_restore(style);
-    g_object_unref(style);
+    ReleaseStyleContext(style);
 
     // tooltip foreground and background
     style = ClaimStyleContext(MOZ_GTK_TOOLTIP);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sInfoBackground = GDK_RGBA_TO_NS_RGBA(color);
-    {
-        GtkStyleContext* boxStyle =
-            CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0),
-                                 style);
-        GtkStyleContext* labelStyle =
-            CreateStyleForWidget(gtk_label_new(nullptr), boxStyle);
-        gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color);
-        g_object_unref(labelStyle);
-        g_object_unref(boxStyle);
-    }
-    sInfoText = GDK_RGBA_TO_NS_RGBA(color);
     ReleaseStyleContext(style);
 
-    // menu foreground & menu background
-    GtkWidget *accel_label = gtk_accel_label_new("M");
-    GtkWidget *menuitem = gtk_menu_item_new();
-    GtkWidget *menu = gtk_menu_new();
-
-    g_object_ref_sink(menu);
-
-    gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-    style = gtk_widget_get_style_context(accel_label);
+    style = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
-    sMenuText = GDK_RGBA_TO_NS_RGBA(color);
-    gtk_style_context_get_color(style, GTK_STATE_FLAG_INSENSITIVE, &color);
-    sMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color);
+    sInfoText = GDK_RGBA_TO_NS_RGBA(color);
+    ReleaseStyleContext(style);
 
-    style = gtk_widget_get_style_context(menu);
+    style = ClaimStyleContext(MOZ_GTK_MENUITEM);
+    {
+        GtkStyleContext* accelStyle =
+            CreateStyleForWidget(gtk_accel_label_new("M"), style);
+        gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_NORMAL, &color);
+        sMenuText = GDK_RGBA_TO_NS_RGBA(color);
+        gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_INSENSITIVE, &color);
+        sMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color);
+        g_object_unref(accelStyle);
+    }
+    ReleaseStyleContext(style);
+
+    style = ClaimStyleContext(MOZ_GTK_MENUPOPUP);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sMenuBackground = GDK_RGBA_TO_NS_RGBA(color);
+    ReleaseStyleContext(style);
 
-    style = gtk_widget_get_style_context(menuitem);
+    style = ClaimStyleContext(MOZ_GTK_MENUITEM);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
     sMenuHover = GDK_RGBA_TO_NS_RGBA(color);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
     sMenuHoverText = GDK_RGBA_TO_NS_RGBA(color);
-
-    g_object_unref(menu);
+    ReleaseStyleContext(style);
 #endif
 
     // button styles
@@ -1192,9 +1203,6 @@ nsLookAndFeel::Init()
     GtkWidget *combobox = gtk_combo_box_new();
     GtkWidget *comboboxLabel = gtk_label_new("M");
     gtk_container_add(GTK_CONTAINER(combobox), comboboxLabel);
-#else
-    GtkWidget *combobox = gtk_combo_box_new_with_entry();
-    GtkWidget *comboboxLabel = gtk_bin_get_child(GTK_BIN(combobox));
 #endif
     GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
     GtkWidget *treeView = gtk_tree_view_new();
@@ -1208,7 +1216,9 @@ nsLookAndFeel::Init()
     gtk_container_add(GTK_CONTAINER(parent), button);
     gtk_container_add(GTK_CONTAINER(parent), treeView);
     gtk_container_add(GTK_CONTAINER(parent), linkButton);
+#if (MOZ_WIDGET_GTK == 2)
     gtk_container_add(GTK_CONTAINER(parent), combobox);
+#endif
     gtk_container_add(GTK_CONTAINER(parent), menuBar);
     gtk_menu_shell_append(GTK_MENU_SHELL(menuBar), menuBarItem);
     gtk_container_add(GTK_CONTAINER(window), parent);
@@ -1291,11 +1301,19 @@ nsLookAndFeel::Init()
     }
 #else
     // Text colors
-    style = gtk_widget_get_style_context(textView);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_VIEW);
-    gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
-    sMozFieldBackground = GDK_RGBA_TO_NS_RGBA(color);
+    GdkRGBA bgColor;
+    // If the text window background is translucent, then the background of
+    // the textview root node is visible.
+    style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW);
+    gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL,
+                                           &bgColor);
+    ReleaseStyleContext(style);
+
+    style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW_TEXT);
+    gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL,
+                                           &color);
+    ApplyColorOver(color, &bgColor);
+    sMozFieldBackground = GDK_RGBA_TO_NS_RGBA(bgColor);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sMozFieldText = GDK_RGBA_TO_NS_RGBA(color);
 
@@ -1308,26 +1326,34 @@ nsLookAndFeel::Init()
         static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED),
         &color);
     sTextSelectedText = GDK_RGBA_TO_NS_RGBA(color);
-    gtk_style_context_restore(style);
+    ReleaseStyleContext(style);
 
-    // Button text, background, border
-    style = gtk_widget_get_style_context(label);
-    gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
-    sButtonText = GDK_RGBA_TO_NS_RGBA(color);
-    gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
-    sButtonHoverText = GDK_RGBA_TO_NS_RGBA(color);
+    // Button text color
+    style = ClaimStyleContext(MOZ_GTK_BUTTON);
+    {
+        GtkStyleContext* labelStyle =
+            CreateStyleForWidget(gtk_label_new("M"), style);
+        gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color);
+        sButtonText = GDK_RGBA_TO_NS_RGBA(color);
+        gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_PRELIGHT, &color);
+        sButtonHoverText = GDK_RGBA_TO_NS_RGBA(color);
+        g_object_unref(labelStyle);
+    }
+    ReleaseStyleContext(style);
 
     // Combobox text color
-    style = gtk_widget_get_style_context(comboboxLabel);
+    style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sComboBoxText = GDK_RGBA_TO_NS_RGBA(color);
+    ReleaseStyleContext(style);
 
     // Menubar text and hover text colors    
-    style = gtk_widget_get_style_context(menuBarItem);
+    style = ClaimStyleContext(MOZ_GTK_MENUBARITEM);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sMenuBarText = GDK_RGBA_TO_NS_RGBA(color);
     gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
     sMenuBarHoverText = GDK_RGBA_TO_NS_RGBA(color);
+    ReleaseStyleContext(style);
 
     // GTK's guide to fancy odd row background colors:
     // 1) Check if a theme explicitly defines an odd row color
@@ -1335,7 +1361,7 @@ nsLookAndFeel::Init()
     //    slightly by a hardcoded value (gtkstyle.c)
     // 3) If neither are defined, take the base background color and
     //    darken that by a hardcoded value
-    style = gtk_widget_get_style_context(treeView);
+    style = ClaimStyleContext(MOZ_GTK_TREEVIEW);
 
     // Get odd row background color
     gtk_style_context_save(style);
@@ -1343,12 +1369,21 @@ nsLookAndFeel::Init()
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
     gtk_style_context_restore(style);
+    ReleaseStyleContext(style);
 
-    gtk_widget_path_free(path);
-
+    // GtkFrame has a "border" subnode on which Adwaita draws the border.
+    // Some themes do not draw on this node but draw a border on the widget
+    // root node, so check the root node if no border is found on the border
+    // node.
     style = ClaimStyleContext(MOZ_GTK_FRAME_BORDER);
-    GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder);
+    bool themeUsesColors =
+        GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder);
     ReleaseStyleContext(style);
+    if (!themeUsesColors) {
+        style = ClaimStyleContext(MOZ_GTK_FRAME);
+        GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder);
+        ReleaseStyleContext(style);
+    }
 
     // GtkInfoBar
     // TODO - Use WidgetCache for it?
@@ -1419,12 +1454,6 @@ nsLookAndFeel::RefreshImpl()
 #if (MOZ_WIDGET_GTK == 2)
     g_object_unref(mStyle);
     mStyle = nullptr;
-#else
-    g_object_unref(mBackgroundStyle);
-    g_object_unref(mButtonStyle);
-
-    mBackgroundStyle = nullptr;
-    mButtonStyle = nullptr;
 #endif
 
     Init();
diff -up firefox-51.0/widget/gtk/nsNativeThemeGTK.cpp.old firefox-51.0/widget/gtk/nsNativeThemeGTK.cpp
--- firefox-51.0/widget/gtk/nsNativeThemeGTK.cpp.old	2017-01-16 17:16:53.000000000 +0100
+++ firefox-51.0/widget/gtk/nsNativeThemeGTK.cpp	2016-10-31 11:52:13.000000000 +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).
@@ -429,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;
@@ -1105,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))
@@ -1248,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)
@@ -1255,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,
@@ -1312,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));
@@ -1426,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;
@@ -1468,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-51.0/widget/gtk/nsNativeThemeGTK.h.old firefox-51.0/widget/gtk/nsNativeThemeGTK.h
--- firefox-51.0/widget/gtk/nsNativeThemeGTK.h.old	2016-07-25 22:22:07.000000000 +0200
+++ firefox-51.0/widget/gtk/nsNativeThemeGTK.h	2016-10-27 16:22:27.000000000 +0200
@@ -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-51.0/widget/gtk/WidgetStyleCache.cpp.old firefox-51.0/widget/gtk/WidgetStyleCache.cpp
--- firefox-51.0/widget/gtk/WidgetStyleCache.cpp.old	2017-01-16 17:16:53.000000000 +0100
+++ firefox-51.0/widget/gtk/WidgetStyleCache.cpp	2017-01-06 10:20:43.000000000 +0100
@@ -33,7 +33,6 @@ static GtkWidget*
 CreateWindowWidget()
 {
   GtkWidget *widget = gtk_window_new(GTK_WINDOW_POPUP);
-  gtk_widget_realize(widget);
   gtk_widget_set_name(widget, "MozillaGtkWidget");
   return widget;
 }
@@ -50,7 +49,6 @@ static void
 AddToWindowContainer(GtkWidget* widget)
 {
   gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_WINDOW_CONTAINER)), widget);
-  gtk_widget_realize(widget);
 }
 
 static GtkWidget*
@@ -142,7 +140,6 @@ CreateToolbarWidget()
 {
   GtkWidget* widget = gtk_toolbar_new();
   gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_GRIPPER)), widget);
-  gtk_widget_realize(widget);
   return widget;
 }
 
@@ -183,7 +180,6 @@ CreateButtonArrowWidget()
 {
   GtkWidget* widget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
   gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_TOGGLE_BUTTON)), widget);
-  gtk_widget_realize(widget);
   gtk_widget_show(widget);
   return widget;
 }
@@ -205,19 +201,235 @@ CreateEntryWidget()
 }
 
 static GtkWidget*
-CreateScrolledWindowWidget()
+CreateComboBoxWidget()
 {
-  GtkWidget* widget = gtk_scrolled_window_new(nullptr, nullptr);
+  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;
+  }
+}
+
+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;
+  }
+
+  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*
-CreateTextViewWidget()
+CreateComboBoxEntryArrowWidget()
 {
-  GtkWidget* widget = gtk_text_view_new();
-  gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_SCROLLED_WINDOW)),
-                    widget);
+  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;
+  }
+
+  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);
+  AddToWindowContainer(widget);
   return widget;
 }
 
@@ -227,7 +439,6 @@ CreateMenuSeparatorWidget()
   GtkWidget* widget = gtk_separator_menu_item_new();
   gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
                         widget);
-  gtk_widget_realize(widget);
   return widget;
 }
 
@@ -306,15 +517,6 @@ CreateVPanedWidget()
 }
 
 static GtkWidget*
-CreateImageMenuItemWidget()
-{
-  GtkWidget* widget = gtk_image_menu_item_new();
-  gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)), widget);
-  gtk_widget_realize(widget);
-  return widget;
-}
-
-static GtkWidget*
 CreateScaleWidget(GtkOrientation aOrientation)
 {
   GtkWidget* widget = gtk_scale_new(aOrientation, nullptr);
@@ -380,8 +582,6 @@ CreateWidget(WidgetNodeType aWidgetType)
       return CreateEntryWidget();
     case MOZ_GTK_SCROLLED_WINDOW: 
       return CreateScrolledWindowWidget();
-    case MOZ_GTK_TEXT_VIEW:
-      return CreateTextViewWidget();
     case MOZ_GTK_TREEVIEW:
       return CreateTreeViewWidget();
     case MOZ_GTK_TREE_HEADER_CELL:
@@ -392,14 +592,28 @@ CreateWidget(WidgetNodeType aWidgetType)
       return CreateHPanedWidget();
     case MOZ_GTK_SPLITTER_VERTICAL:
       return CreateVPanedWidget();
-    case MOZ_GTK_IMAGEMENUITEM:
-      return CreateImageMenuItemWidget();
     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;
@@ -474,9 +688,20 @@ 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);
 
@@ -508,13 +733,38 @@ GetWidgetRootStyle(WidgetNodeType aNodeT
     case MOZ_GTK_MENUITEM:
       style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUPOPUP);
       break;
-    case MOZ_GTK_CHECKMENUITEM_CONTAINER:
+    case MOZ_GTK_CHECKMENUITEM:
       style = CreateStyleForWidget(gtk_check_menu_item_new(), MOZ_GTK_MENUPOPUP);
       break;
-    case MOZ_GTK_RADIOMENUITEM_CONTAINER:
+    case MOZ_GTK_RADIOMENUITEM:
       style = CreateStyleForWidget(gtk_radio_menu_item_new(nullptr),
                                    MOZ_GTK_MENUPOPUP);
       break;
+    case MOZ_GTK_TEXT_VIEW:
+      style = CreateStyleForWidget(gtk_text_view_new(),
+                                   MOZ_GTK_SCROLLED_WINDOW);
+      break;
+    case MOZ_GTK_TOOLTIP:
+      if (gtk_check_version(3, 20, 0) != nullptr) {
+          // The tooltip style class is added first in CreateTooltipWidget()
+          // and transfered to style in CreateStyleForWidget().
+          GtkWidget* tooltipWindow = CreateTooltipWidget();
+          style = CreateStyleForWidget(tooltipWindow, nullptr);
+          gtk_widget_destroy(tooltipWindow); // Release GtkWindow self-reference.
+      } else {
+          // We create this from the path because GtkTooltipWindow is not public.
+          style = CreateCSSNode("tooltip", nullptr, GTK_TYPE_TOOLTIP);
+          gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
+      }
+      break;
+    case MOZ_GTK_TOOLTIP_BOX:
+      style = CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0),
+                                   MOZ_GTK_TOOLTIP);
+      break;
+    case MOZ_GTK_TOOLTIP_BOX_LABEL:
+      style = CreateStyleForWidget(gtk_label_new(nullptr),
+                                   MOZ_GTK_TOOLTIP_BOX);
+      break;
     default:
       GtkWidget* widget = GetWidget(aNodeType);
       MOZ_ASSERT(widget);
@@ -576,6 +826,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);
@@ -584,13 +838,13 @@ GetCssNodeStyleInternal(WidgetNodeType a
       style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
                                  MOZ_GTK_CHECKBUTTON_CONTAINER);
       break;
-    case MOZ_GTK_RADIOMENUITEM:
+    case MOZ_GTK_RADIOMENUITEM_INDICATOR:
       style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
-                                 MOZ_GTK_RADIOMENUITEM_CONTAINER);
+                                 MOZ_GTK_RADIOMENUITEM);
       break;
-    case MOZ_GTK_CHECKMENUITEM:
+    case MOZ_GTK_CHECKMENUITEM_INDICATOR:
       style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
-                                 MOZ_GTK_CHECKMENUITEM_CONTAINER);
+                                 MOZ_GTK_CHECKMENUITEM);
       break;
     case MOZ_GTK_PROGRESS_TROUGH:
       /* Progress bar background (trough) */
@@ -601,11 +855,6 @@ GetCssNodeStyleInternal(WidgetNodeType a
       style = CreateChildCSSNode("progress",
                                  MOZ_GTK_PROGRESS_TROUGH);
       break;
-    case MOZ_GTK_TOOLTIP:
-      // We create this from the path because GtkTooltipWindow is not public.
-      style = CreateCSSNode("tooltip", nullptr, GTK_TYPE_TOOLTIP);
-      gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
-      break; 
     case MOZ_GTK_GRIPPER:
       // TODO - create from CSS node
       return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
@@ -622,10 +871,28 @@ GetCssNodeStyleInternal(WidgetNodeType a
       // TODO - create from CSS node
       return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
                                      GTK_STYLE_CLASS_FRAME);
-    case MOZ_GTK_TEXT_VIEW:
-      // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW,
-                                     GTK_STYLE_CLASS_VIEW);
+    case MOZ_GTK_TEXT_VIEW_TEXT:
+    case MOZ_GTK_RESIZER:
+      style = CreateChildCSSNode("text", MOZ_GTK_TEXT_VIEW);
+      if (aNodeType == MOZ_GTK_RESIZER) {
+        // The "grip" class provides the correct builtin icon from
+        // gtk_render_handle().  The icon is drawn with shaded variants of
+        // the background color, and so a transparent background would lead to
+        // a transparent resizer.  gtk_render_handle() also uses the
+        // background color to draw a background, and so this style otherwise
+        // matches what is used in GtkTextView to match the background with
+        // textarea elements.
+        GdkRGBA color;
+        gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL,
+                                               &color);
+        if (color.alpha == 0.0) {
+          g_object_unref(style);
+          style = CreateStyleForWidget(gtk_text_view_new(),
+                                       MOZ_GTK_SCROLLED_WINDOW);
+        }
+        gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
+      }
+      break;
     case MOZ_GTK_FRAME_BORDER:
       style = CreateChildCSSNode("border", MOZ_GTK_FRAME);
       break;
@@ -728,27 +995,20 @@ GetWidgetStyleInternal(WidgetNodeType aN
     case MOZ_GTK_CHECKBUTTON:
       return GetWidgetStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
                                      GTK_STYLE_CLASS_CHECK);
-    case MOZ_GTK_RADIOMENUITEM:
-      return GetWidgetStyleWithClass(MOZ_GTK_RADIOMENUITEM_CONTAINER,
+    case MOZ_GTK_RADIOMENUITEM_INDICATOR:
+      return GetWidgetStyleWithClass(MOZ_GTK_RADIOMENUITEM,
                                      GTK_STYLE_CLASS_RADIO);
-    case MOZ_GTK_CHECKMENUITEM:
-      return GetWidgetStyleWithClass(MOZ_GTK_CHECKMENUITEM_CONTAINER,
+    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);
-    case MOZ_GTK_TOOLTIP: {
-      GtkStyleContext* style = sStyleStorage[aNodeType];
-      if (style)
-        return style;
-
-      // The tooltip style class is added first in CreateTooltipWidget() so
-      // that gtk_widget_path_append_for_widget() in CreateStyleForWidget()
-      // will find it.
-      GtkWidget* tooltipWindow = CreateTooltipWidget();
-      style = CreateStyleForWidget(tooltipWindow, nullptr);
-      gtk_widget_destroy(tooltipWindow); // Release GtkWindow self-reference.
-      sStyleStorage[aNodeType] = style;
+    case MOZ_GTK_PROGRESS_CHUNK: {
+      GtkStyleContext* style =
+        GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR,
+                                GTK_STYLE_CLASS_PROGRESSBAR);
+      gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
       return style;
     }
     case MOZ_GTK_GRIPPER:
@@ -763,9 +1023,25 @@ GetWidgetStyleInternal(WidgetNodeType aN
     case MOZ_GTK_SCROLLED_WINDOW:
       return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
                                      GTK_STYLE_CLASS_FRAME);
-    case MOZ_GTK_TEXT_VIEW:
-      return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW,
-                                     GTK_STYLE_CLASS_VIEW);
+    case MOZ_GTK_TEXT_VIEW_TEXT:
+    case MOZ_GTK_RESIZER: {
+      // GTK versions prior to 3.20 do not have the view class on the root
+      // node, but add this to determine the background for the text window.
+      GtkStyleContext* style =
+        GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW, GTK_STYLE_CLASS_VIEW);
+      if (aNodeType == MOZ_GTK_RESIZER) {
+        // The "grip" class provides the correct builtin icon from
+        // gtk_render_handle().  The icon is drawn with shaded variants of
+        // the background color, and so a transparent background would lead to
+        // a transparent resizer.  gtk_render_handle() also uses the
+        // background color to draw a background, and so this style otherwise
+        // matches MOZ_GTK_TEXT_VIEW_TEXT to match the background with
+        // textarea elements.  GtkTextView creates a separate text window and
+        // so the background should not be transparent.
+        gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
+      }
+      return style;
+    }
     case MOZ_GTK_FRAME_BORDER:
       return GetWidgetRootStyle(MOZ_GTK_FRAME);
     case MOZ_GTK_TREEVIEW_VIEW: