Bug 1282753 - move button and entry widgets from gtk3drawing to WidgetCache, r=andrew@comminos
authorMartin Stransky <stransky@redhat.com>
Wed, 20 Jul 2016 01:57:00 +0200
changeset 331747 0d7f83477045aedfd34ba896c17dac918e24cb35
parent 331746 6e23273bf3508403aeacdb301d278c281528756c
child 331748 da083c6367526ab8d30d1b07b94b2c56b77d7831
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersandrew
bugs1282753
milestone50.0a1
Bug 1282753 - move button and entry widgets from gtk3drawing to WidgetCache, r=andrew@comminos
widget/gtk/WidgetStyleCache.cpp
widget/gtk/gtk3drawing.cpp
widget/gtk/gtkdrawing.h
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -62,17 +62,17 @@ CreateCheckboxWidget()
   GtkWidget* widget = gtk_check_button_new_with_label("M");
   AddToWindowContainer(widget);
   return widget;
 }
 
 static GtkWidget*
 CreateRadiobuttonWidget()
 {
-  GtkWidget* widget = gtk_radio_button_new_with_label(NULL, "M");
+  GtkWidget* widget = gtk_radio_button_new_with_label(nullptr, "M");
   AddToWindowContainer(widget);
   return widget;
 }
 
 static GtkWidget*
 CreateMenuBarWidget()
 {
   GtkWidget* widget = gtk_menu_bar_new();
@@ -161,16 +161,58 @@ static GtkWidget*
 CreateInfoBarWidget()
 {
   GtkWidget* widget = gtk_info_bar_new();
   AddToWindowContainer(widget);
   return widget;
 }
 
 static GtkWidget*
+CreateButtonWidget()
+{
+  GtkWidget* widget = gtk_button_new_with_label("M");
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateToggleButtonWidget()
+{
+  GtkWidget* widget = gtk_toggle_button_new();
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateButtonArrowWidget()
+{
+  GtkWidget* widget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+  gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_TOGGLE_BUTTON)), widget);
+  gtk_widget_realize(widget);
+  gtk_widget_show(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateSpinWidget()
+{
+  GtkWidget* widget = gtk_spin_button_new(nullptr, 1, 0);
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
+CreateEntryWidget()
+{
+  GtkWidget* widget = gtk_entry_new();
+  AddToWindowContainer(widget);
+  return widget;
+}
+
+static GtkWidget*
 CreateWidget(WidgetNodeType aWidgetType)
 {
   switch (aWidgetType) {
     case MOZ_GTK_WINDOW:
       return CreateWindowWidget();
     case MOZ_GTK_WINDOW_CONTAINER:
       return CreateWindowContainerWidget();
     case MOZ_GTK_CHECKBUTTON_CONTAINER:
@@ -200,16 +242,26 @@ CreateWidget(WidgetNodeType aWidgetType)
     case MOZ_GTK_GRIPPER:
       return CreateGripperWidget();
     case MOZ_GTK_TOOLBAR:
       return CreateToolbarWidget();
     case MOZ_GTK_TOOLBAR_SEPARATOR:
       return CreateToolbarSeparatorWidget();
     case MOZ_GTK_INFO_BAR:
       return CreateInfoBarWidget();
+    case MOZ_GTK_SPINBUTTON:
+      return CreateSpinWidget();
+    case MOZ_GTK_BUTTON:
+      return CreateButtonWidget();
+    case MOZ_GTK_TOGGLE_BUTTON:
+      return CreateToggleButtonWidget();
+    case MOZ_GTK_BUTTON_ARROW:
+      return CreateButtonArrowWidget();
+    case MOZ_GTK_ENTRY:
+      return CreateEntryWidget();
     default:
       /* Not implemented */
       return nullptr;
   }
 }
 
 GtkWidget*
 GetWidget(WidgetNodeType aWidgetType)
@@ -344,16 +396,20 @@ GetCssNodeStyleInternal(WidgetNodeType a
     case MOZ_GTK_GRIPPER:
       // TODO - create from CSS node
       return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
                                      GTK_STYLE_CLASS_GRIP);
     case MOZ_GTK_INFO_BAR:
       // TODO - create from CSS node
       return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR,
                                      GTK_STYLE_CLASS_INFO);
+    case MOZ_GTK_SPINBUTTON_ENTRY:
+      // TODO - create from CSS node
+      return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON,
+                                     GTK_STYLE_CLASS_ENTRY);
     default:
       // TODO - create style from style path
       GtkWidget* widget = GetWidget(aNodeType);
       return gtk_widget_get_style_context(widget);
   }
 
   MOZ_ASSERT(style, "missing style context for node type");
   sStyleStorage[aNodeType] = style;
@@ -401,16 +457,19 @@ GetWidgetStyleInternal(WidgetNodeType aN
       return style;
     }
     case MOZ_GTK_GRIPPER:
       return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
                                      GTK_STYLE_CLASS_GRIP);
     case MOZ_GTK_INFO_BAR:
       return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR,
                                      GTK_STYLE_CLASS_INFO);
+    case MOZ_GTK_SPINBUTTON_ENTRY:
+      return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON,
+                                     GTK_STYLE_CLASS_ENTRY);
     default:
       GtkWidget* widget = GetWidget(aNodeType);
       MOZ_ASSERT(widget);
       return gtk_widget_get_style_context(widget);
   }
 }
 
 void
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -14,23 +14,18 @@
 #include "gtkdrawing.h"
 #include "mozilla/Assertions.h"
 #include "prinrval.h"
 #include "WidgetStyleCache.h"
 
 #include <math.h>
 
 static GtkWidget* gProtoLayout;
-static GtkWidget* gButtonWidget;
-static GtkWidget* gToggleButtonWidget;
-static GtkWidget* gButtonArrowWidget;
-static GtkWidget* gSpinWidget;
 static GtkWidget* gHScaleWidget;
 static GtkWidget* gVScaleWidget;
-static GtkWidget* gEntryWidget;
 static GtkWidget* gComboBoxWidget;
 static GtkWidget* gComboBoxButtonWidget;
 static GtkWidget* gComboBoxArrowWidget;
 static GtkWidget* gComboBoxSeparatorWidget;
 static GtkWidget* gComboBoxEntryWidget;
 static GtkWidget* gComboBoxEntryTextareaWidget;
 static GtkWidget* gComboBoxEntryButtonWidget;
 static GtkWidget* gComboBoxEntryArrowWidget;
@@ -94,26 +89,16 @@ setup_widget_prototype(GtkWidget* widget
     if (!gProtoLayout) {
         gProtoLayout = GetWidget(MOZ_GTK_WINDOW_CONTAINER);
     }
     gtk_container_add(GTK_CONTAINER(gProtoLayout), widget);
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
-ensure_button_widget()
-{
-    if (!gButtonWidget) {
-        gButtonWidget = gtk_button_new_with_label("M");
-        setup_widget_prototype(gButtonWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
 ensure_hpaned_widget()
 {
     if (!gHPanedWidget) {
         gHPanedWidget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
         setup_widget_prototype(gHPanedWidget);
     }
     return MOZ_GTK_SUCCESS;
 }
@@ -124,73 +109,29 @@ ensure_vpaned_widget()
     if (!gVPanedWidget) {
         gVPanedWidget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
         setup_widget_prototype(gVPanedWidget);
     }
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
-ensure_toggle_button_widget()
-{
-    if (!gToggleButtonWidget) {
-        gToggleButtonWidget = gtk_toggle_button_new();
-        setup_widget_prototype(gToggleButtonWidget);
-  }
-  return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_button_arrow_widget()
-{
-    if (!gButtonArrowWidget) {
-        ensure_toggle_button_widget();
-
-        gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
-        gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget);
-        gtk_widget_realize(gButtonArrowWidget);
-        gtk_widget_show(gButtonArrowWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
-static gint
-ensure_spin_widget()
-{
-  if (!gSpinWidget) {
-    gSpinWidget = gtk_spin_button_new(NULL, 1, 0);
-    setup_widget_prototype(gSpinWidget);
-  }
-  return MOZ_GTK_SUCCESS;
-}
-
-static gint
 ensure_scale_widget()
 {
   if (!gHScaleWidget) {
     gHScaleWidget = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL);
     setup_widget_prototype(gHScaleWidget);
   }
   if (!gVScaleWidget) {
     gVScaleWidget = gtk_scale_new(GTK_ORIENTATION_VERTICAL, NULL);
     setup_widget_prototype(gVScaleWidget);
   }
   return MOZ_GTK_SUCCESS;
 }
 
-static gint
-ensure_entry_widget()
-{
-    if (!gEntryWidget) {
-        gEntryWidget = gtk_entry_new();
-        setup_widget_prototype(gEntryWidget);
-    }
-    return MOZ_GTK_SUCCESS;
-}
-
 /* We need to have pointers to the inner widgets (button, separator, arrow)
  * of the ComboBox to get the correct rendering from theme engines which
  * special cases their look. Since the inner layout can change, we ask GTK
  * 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
@@ -261,26 +202,24 @@ ensure_combo_box_widgets()
             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. */
-        ensure_toggle_button_widget();
-        gComboBoxButtonWidget = gToggleButtonWidget;
+        gComboBoxButtonWidget = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
     }
 
     if (!gComboBoxArrowWidget) {
         /* Shouldn't be reached with current internal gtk implementation;
          * we gButtonArrowWidget as last resort fallback to avoid
          * crashing. */
-        ensure_button_arrow_widget();
-        gComboBoxArrowWidget = gButtonArrowWidget;
+        gComboBoxArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW);
     }
 
     /* We don't test the validity of gComboBoxSeparatorWidget since there
      * 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;
 }
@@ -340,18 +279,17 @@ ensure_combo_box_entry_widgets()
     }
 
     /* Get its inner Entry and Button */
     gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget),
                          moz_gtk_get_combo_box_entry_inner_widgets,
                          NULL);
 
     if (!gComboBoxEntryTextareaWidget) {
-        ensure_entry_widget();
-        gComboBoxEntryTextareaWidget = gEntryWidget;
+        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
@@ -367,26 +305,24 @@ ensure_combo_box_entry_widgets()
             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. */
-        ensure_toggle_button_widget();
-        gComboBoxEntryButtonWidget = gToggleButtonWidget;
+        gComboBoxEntryButtonWidget = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
     }
 
     if (!gComboBoxEntryArrowWidget) {
         /* Shouldn't be reached with current internal gtk implementation;
          * we gButtonArrowWidget as last resort fallback to avoid
          * crashing. */
-        ensure_button_arrow_widget();
-        gComboBoxEntryArrowWidget = gButtonArrowWidget;
+        gComboBoxEntryArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW);
     }
 
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 ensure_tab_widget()
 {
@@ -555,25 +491,22 @@ 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)
 {
     GtkBorder border;
     GtkBorder padding;
-    GtkStyleContext *style;
-
-    ensure_entry_widget();
-    style = gtk_widget_get_style_context(gEntryWidget);
-
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_ENTRY);
     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
     *focus_h_width = border.left + padding.left;
     *focus_v_width = border.top + padding.top;
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
 gint
 moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding)
 {
     gtk_widget_style_get(GetWidget(MOZ_GTK_MENUITEM),
                          "horizontal-padding", horizontal_padding,
@@ -595,20 +528,21 @@ moz_gtk_checkmenuitem_get_horizontal_pad
 }
 
 gint
 moz_gtk_button_get_default_overflow(gint* border_top, gint* border_left,
                                     gint* border_bottom, gint* border_right)
 {
     GtkBorder* default_outside_border;
 
-    ensure_button_widget();
-    gtk_style_context_get_style(gtk_widget_get_style_context(gButtonWidget),
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
+    gtk_style_context_get_style(style,
                                 "default-outside-border", &default_outside_border,
                                 NULL);
+    ReleaseStyleContext(style);
 
     if (default_outside_border) {
         *border_top = default_outside_border->top;
         *border_left = default_outside_border->left;
         *border_bottom = default_outside_border->bottom;
         *border_right = default_outside_border->right;
         gtk_border_free(default_outside_border);
     } else {
@@ -618,20 +552,21 @@ moz_gtk_button_get_default_overflow(gint
 }
 
 static gint
 moz_gtk_button_get_default_border(gint* border_top, gint* border_left,
                                   gint* border_bottom, gint* border_right)
 {
     GtkBorder* default_border;
 
-    ensure_button_widget();
-    gtk_style_context_get_style(gtk_widget_get_style_context(gButtonWidget),
+    GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
+    gtk_style_context_get_style(style,
                                 "default-border", &default_border,
                                 NULL);
+    ReleaseStyleContext(style);
 
     if (default_border) {
         *border_top = default_border->top;
         *border_left = default_border->left;
         *border_bottom = default_border->bottom;
         *border_right = default_border->right;
         gtk_border_free(default_border);
     } else {
@@ -1040,61 +975,48 @@ moz_gtk_scrollbar_thumb_paint(WidgetNode
 
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect,
                    GtkTextDirection direction)
 {
-    GtkStyleContext* style;
-
-    ensure_spin_widget();
-    gtk_widget_set_direction(gSpinWidget, direction);
-    style = gtk_widget_get_style_context(gSpinWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction);
     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
-    gtk_style_context_restore(style);
-
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 moz_gtk_spin_updown_paint(cairo_t *cr, GdkRectangle* rect,
                           gboolean isDown, GtkWidgetState* state,
                           GtkTextDirection direction)
 {
-    GdkRectangle arrow_rect;
-    GtkStyleContext* style;
-
-    ensure_spin_widget();
-    style = gtk_widget_get_style_context(gSpinWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
-    gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
-    gtk_widget_set_direction(gSpinWidget, direction);
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction,
+                                 GetStateFlagsFromGtkWidgetState(state));
 
     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
 
-
     /* hard code these values */
+    GdkRectangle arrow_rect;
     arrow_rect.width = 6;
     arrow_rect.height = 6;
     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
     arrow_rect.y += isDown ? -1 : 1;
 
     gtk_render_arrow(style, cr, 
                     isDown ? ARROW_DOWN : ARROW_UP,
                     arrow_rect.x, arrow_rect.y,
                     arrow_rect.width);
-    gtk_style_context_restore(style);
+
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
 /* See gtk_range_draw() for reference.
 */
 static gint
 moz_gtk_scale_paint(cairo_t *cr, GdkRectangle* rect,
                     GtkWidgetState* state,
@@ -1543,30 +1465,19 @@ moz_gtk_combo_box_paint(cairo_t *cr, Gdk
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 moz_gtk_arrow_paint(cairo_t *cr, GdkRectangle* rect,
                     GtkWidgetState* state,
                     GtkArrowType arrow_type, GtkTextDirection direction)
 {
-    GtkStyleContext* style;
-    GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     GdkRectangle arrow_rect;
     gdouble arrow_angle;
 
-    ensure_button_arrow_widget();
-    style = gtk_widget_get_style_context(gButtonArrowWidget);
-    gtk_style_context_save(style);
-    gtk_style_context_set_state(style, state_flags);
-    gtk_widget_set_direction(gButtonArrowWidget, direction);
-
-    calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect,
-                         direction);
-
     if (direction == GTK_TEXT_DIR_RTL) {
         arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
                          GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
     }
     switch (arrow_type) {
     case GTK_ARROW_LEFT:
         arrow_angle = ARROW_LEFT;
         break;
@@ -1575,20 +1486,27 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRect
         break;
     case GTK_ARROW_DOWN:
         arrow_angle = ARROW_DOWN;
         break;
     default:
         arrow_angle = ARROW_UP;
         break;
     }
-    if (arrow_type != GTK_ARROW_NONE)
-        gtk_render_arrow(style, cr, arrow_angle,
-                         arrow_rect.x, arrow_rect.y, arrow_rect.width);                    
-    gtk_style_context_restore(style);
+    if (arrow_type == GTK_ARROW_NONE)
+        return MOZ_GTK_SUCCESS;
+
+    calculate_arrow_rect(GetWidget(MOZ_GTK_BUTTON_ARROW), rect, &arrow_rect,
+                         direction);
+    GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_BUTTON_ARROW,
+                                               direction, state_flags);
+    gtk_render_arrow(style, cr, arrow_angle,
+                     arrow_rect.x, arrow_rect.y, arrow_rect.width);
+    ReleaseStyleContext(style);
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 moz_gtk_combo_box_entry_button_paint(cairo_t *cr, GdkRectangle* rect,
                                      GtkWidgetState* state,
                                      gboolean input_focus,
                                      GtkTextDirection direction)
@@ -2453,48 +2371,50 @@ moz_gtk_get_widget_border(WidgetNodeType
     GtkWidget* w;
     GtkStyleContext* style;
     *left = *top = *right = *bottom = 0;
 
     switch (widget) {
     case MOZ_GTK_BUTTON:
     case MOZ_GTK_TOOLBAR_BUTTON:
         {
-            ensure_button_widget();
-            style = gtk_widget_get_style_context(gButtonWidget);
-
-            *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
+            style = ClaimStyleContext(MOZ_GTK_BUTTON);
+
+            *left = *top = *right = *bottom =
+                gtk_container_get_border_width(GTK_CONTAINER(GetWidget(MOZ_GTK_BUTTON)));
 
             if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
                 gtk_style_context_save(style);
                 gtk_style_context_add_class(style, "image-button");
             }
-              
+
             moz_gtk_add_style_padding(style, left, top, right, bottom);
-                
+
             if (widget == MOZ_GTK_TOOLBAR_BUTTON)
                 gtk_style_context_restore(style);
 
             // 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);
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_ENTRY:
         {
-            ensure_entry_widget();
-            style = gtk_widget_get_style_context(gEntryWidget);
+            style = ClaimStyleContext(MOZ_GTK_ENTRY);
 
             // XXX: Subtract 1 pixel from the padding to account for the default
             // padding in forms.css. See bug 1187385.
             *left = *top = *right = *bottom = -1;
             moz_gtk_add_style_padding(style, left, top, right, bottom);
             moz_gtk_add_style_border(style, left, top, right, bottom);
 
+            ReleaseStyleContext(style);
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_TEXT_VIEW:
     case MOZ_GTK_TREEVIEW:
         {
             ensure_scrolled_window_widget();
             style = gtk_widget_get_style_context(gScrolledWindowWidget);
             gtk_style_context_save(style);
@@ -2580,18 +2500,17 @@ moz_gtk_get_widget_border(WidgetNodeType
         w = gTabWidget;
         break;
     case MOZ_GTK_PROGRESSBAR:
         w = GetWidget(MOZ_GTK_PROGRESSBAR);
         break;
     case MOZ_GTK_SPINBUTTON_ENTRY:
     case MOZ_GTK_SPINBUTTON_UP:
     case MOZ_GTK_SPINBUTTON_DOWN:
-        ensure_spin_widget();
-        w = gSpinWidget;
+        w = GetWidget(MOZ_GTK_SPINBUTTON);
         break;
     case MOZ_GTK_SCALE_HORIZONTAL:
         ensure_scale_widget();
         w = gHScaleWidget;
         break;
     case MOZ_GTK_SCALE_VERTICAL:
         ensure_scale_widget();
         w = gVScaleWidget;
@@ -2759,18 +2678,17 @@ moz_gtk_get_arrow_size(WidgetNodeType wi
 {
     GtkWidget* widget;
     switch (widgetType) {
         case MOZ_GTK_DROPDOWN:
             ensure_combo_box_widgets();
             widget = gComboBoxArrowWidget;
             break;
         default:
-            ensure_button_arrow_widget();
-            widget = gButtonArrowWidget;
+            widget = GetWidget(MOZ_GTK_BUTTON_ARROW);
             break;
     }
 
     GtkRequisition requisition;
     gtk_widget_get_preferred_size(widget, NULL, &requisition);
     *width = requisition.width;
     *height = requisition.height;
 }
@@ -2848,32 +2766,32 @@ moz_gtk_get_menu_separator_height(gint *
     *size += (wide_separators) ? separator_height : 1;
 
     return MOZ_GTK_SUCCESS;
 }
 
 void
 moz_gtk_get_entry_min_height(gint* height)
 {
-    ensure_entry_widget();
-    GtkStyleContext* style = gtk_widget_get_style_context(gEntryWidget);
+    GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_ENTRY);
     if (!gtk_check_version(3, 20, 0)) {
         gtk_style_context_get(style, gtk_style_context_get_state(style),
                               "min-height", height,
                               nullptr);
     } else {
         *height = 0;
     }
 
     GtkBorder border;
     GtkBorder padding;
     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
 
     *height += (border.top + border.bottom + padding.top + padding.bottom);
+    ReleaseStyleContext(style);
 }
 
 void
 moz_gtk_get_scale_metrics(GtkOrientation orient, gint* scale_width,
                           gint* scale_height)
 {
   gint thumb_length, thumb_height, trough_border;
   GtkWidget* widget = orient == GTK_ORIENTATION_HORIZONTAL ?
@@ -2944,18 +2862,17 @@ moz_gtk_images_in_menus()
 }
 
 gboolean
 moz_gtk_images_in_buttons()
 {
     gboolean result;
     GtkSettings* settings;
 
-    ensure_button_widget();
-    settings = gtk_widget_get_settings(gButtonWidget);
+    settings = gtk_widget_get_settings(GetWidget(MOZ_GTK_BUTTON));
 
     g_object_get(settings, "gtk-button-images", &result, NULL);
     return result;
 }
 
 /* cairo_t *cr argument has to be a system-cairo. */
 gint
 moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr,
@@ -2966,24 +2883,24 @@ moz_gtk_widget_paint(WidgetNodeType widg
     /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=694086
      */
     cairo_new_path(cr);
 
     switch (widget) {
     case MOZ_GTK_BUTTON:
     case MOZ_GTK_TOOLBAR_BUTTON:
         if (state->depressed) {
-            ensure_toggle_button_widget();
             return moz_gtk_button_paint(cr, rect, state,
                                         (GtkReliefStyle) flags,
-                                        gToggleButtonWidget, direction);
+                                        GetWidget(MOZ_GTK_TOGGLE_BUTTON),
+                                        direction);
         }
-        ensure_button_widget();
         return moz_gtk_button_paint(cr, rect, state,
-                                    (GtkReliefStyle) flags, gButtonWidget,
+                                    (GtkReliefStyle) flags,
+                                    GetWidget(MOZ_GTK_BUTTON),
                                     direction);
         break;
     case MOZ_GTK_CHECKBUTTON:
     case MOZ_GTK_RADIOBUTTON:
         return moz_gtk_toggle_paint(cr, rect, state,
                                     !!(flags & MOZ_GTK_WIDGET_CHECKED),
                                     !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
                                     (widget == MOZ_GTK_RADIOBUTTON),
@@ -3021,19 +2938,19 @@ moz_gtk_widget_paint(WidgetNodeType widg
         break;
     case MOZ_GTK_SPINBUTTON_UP:
     case MOZ_GTK_SPINBUTTON_DOWN:
         return moz_gtk_spin_updown_paint(cr, rect,
                                          (widget == MOZ_GTK_SPINBUTTON_DOWN),
                                          state, direction);
         break;
     case MOZ_GTK_SPINBUTTON_ENTRY:
-        ensure_spin_widget();
+        // TODO - use MOZ_GTK_SPINBUTTON_ENTRY style directly
         return moz_gtk_entry_paint(cr, rect, state,
-                                   gSpinWidget, direction);
+                                   GetWidget(MOZ_GTK_SPINBUTTON), direction);
         break;
     case MOZ_GTK_GRIPPER:
         return moz_gtk_gripper_paint(cr, rect, state,
                                      direction);
         break;
     case MOZ_GTK_TREEVIEW:
         return moz_gtk_treeview_paint(cr, rect, state,
                                       direction);
@@ -3048,19 +2965,18 @@ moz_gtk_widget_paint(WidgetNodeType widg
                                                     (GtkArrowType) flags,
                                                     direction);
         break;
     case MOZ_GTK_TREEVIEW_EXPANDER:
         return moz_gtk_treeview_expander_paint(cr, rect, state,
                                                (GtkExpanderStyle) flags, direction);
         break;
     case MOZ_GTK_ENTRY:
-        ensure_entry_widget();
-        return moz_gtk_entry_paint(cr, rect, state,
-                                   gEntryWidget, direction);
+        return moz_gtk_entry_paint(cr, rect, state, GetWidget(MOZ_GTK_ENTRY),
+                                   direction);
         break;
     case MOZ_GTK_TEXT_VIEW:
         return moz_gtk_text_view_paint(cr, rect, state, direction);
         break;
     case MOZ_GTK_DROPDOWN:
         return moz_gtk_combo_box_paint(cr, rect, state, direction);
         break;
     case MOZ_GTK_DROPDOWN_ARROW:
@@ -3194,23 +3110,18 @@ moz_gtk_shutdown()
     /* This will destroy all of our widgets */
     ResetWidgetCache();
 
     /* TODO - replace it with appropriate widget */
     if (gTreeHeaderSortArrowWidget)
         gtk_widget_destroy(gTreeHeaderSortArrowWidget);
 
     gProtoLayout = NULL;
-    gButtonWidget = NULL;
-    gToggleButtonWidget = NULL;
-    gButtonArrowWidget = NULL;
-    gSpinWidget = NULL;
     gHScaleWidget = NULL;
     gVScaleWidget = NULL;
-    gEntryWidget = NULL;
     gComboBoxWidget = NULL;
     gComboBoxButtonWidget = NULL;
     gComboBoxSeparatorWidget = NULL;
     gComboBoxArrowWidget = NULL;
     gComboBoxEntryWidget = NULL;
     gComboBoxEntryButtonWidget = NULL;
     gComboBoxEntryArrowWidget = NULL;
     gComboBoxEntryTextareaWidget = NULL;
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -82,16 +82,20 @@ typedef gint (*style_prop_t)(GtkStyle*, 
 #define MOZ_GTK_WIDGET_INCONSISTENT (1 << 1)
 
 /*** widget type constants ***/
 typedef enum {
   /* Paints a GtkButton. flags is a GtkReliefStyle. */
   MOZ_GTK_BUTTON,
   /* Paints a button with image and no text */
   MOZ_GTK_TOOLBAR_BUTTON,
+  /* Paints a toggle button */
+  MOZ_GTK_TOGGLE_BUTTON,
+  /* Paints a button arrow */
+  MOZ_GTK_BUTTON_ARROW,
 
   /* Paints the container part of a GtkCheckButton. */
   MOZ_GTK_CHECKBUTTON_CONTAINER,
   /* Paints a GtkCheckButton. flags is a boolean, 1=checked, 0=not checked. */
   MOZ_GTK_CHECKBUTTON,
   /* Paints the label of a GtkCheckButton (focus outline) */
   MOZ_GTK_CHECKBUTTON_LABEL,