bug 1319650 mimic gtk_style_context_save() in WidgetStyleCache with a new context r=stransky draft
authorKarl Tomlinson <karlt+@karlt.net>
Fri, 02 Dec 2016 12:39:23 +1300
changeset 572872 a4056c61ef3a309859743b9cc03367dfd58c93fc
parent 572425 4a6a71f4aa22e4dc3961884ce505ce34bdd799a2
child 572873 4def9d426372d319575ad6a1b55f5723a20d9ac7
push id57209
push userktomlinson@mozilla.com
push dateThu, 04 May 2017 20:55:30 +0000
reviewersstransky
bugs1319650
milestone55.0a1
bug 1319650 mimic gtk_style_context_save() in WidgetStyleCache with a new context r=stransky This makes balancing with gtk_style_context_restore()/ReleaseStyleContext() unnecessary, and the style resolution cached in the style contexts is not invalidated so frequently. MozReview-Commit-ID: BKwyqoQsjv2
widget/gtk/WidgetStyleCache.cpp
widget/gtk/mozgtk/mozgtk.c
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -15,20 +15,16 @@
 static_assert(GTK_STATE_FLAG_DIR_LTR == STATE_FLAG_DIR_LTR &&
               GTK_STATE_FLAG_DIR_RTL == STATE_FLAG_DIR_RTL,
               "incorrect direction state flags");
 #endif
 
 static GtkWidget* sWidgetStorage[MOZ_GTK_WIDGET_NODE_COUNT];
 static GtkStyleContext* sStyleStorage[MOZ_GTK_WIDGET_NODE_COUNT];
 
-static bool sStyleContextNeedsRestore;
-#ifdef DEBUG
-static GtkStyleContext* sCurrentStyleContext;
-#endif
 static GtkStyleContext*
 GetWidgetRootStyle(WidgetNodeType aNodeType);
 static GtkStyleContext*
 GetCssNodeStyleInternal(WidgetNodeType aNodeType);
 
 static GtkWidget*
 CreateWindowWidget()
 {
@@ -626,16 +622,26 @@ GetWidget(WidgetNodeType aWidgetType)
   GtkWidget* widget = sWidgetStorage[aWidgetType];
   if (!widget) {
     widget = CreateWidget(aWidgetType);
     sWidgetStorage[aWidgetType] = widget;
   }
   return widget;
 }
 
+static void
+AddStyleClassesFromStyle(GtkStyleContext* aDest, GtkStyleContext* aSrc)
+{
+  GList* classes = gtk_style_context_list_classes(aSrc);
+  for (GList* link = classes; link; link = link->next) {
+    gtk_style_context_add_class(aDest, static_cast<gchar*>(link->data));
+  }
+  g_list_free(classes);
+}
+
 GtkStyleContext*
 CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle)
 {
   static auto sGtkWidgetClassGetCSSName =
     reinterpret_cast<const char* (*)(GtkWidgetClass*)>
     (dlsym(RTLD_DEFAULT, "gtk_widget_class_get_css_name"));
 
   GtkWidgetClass *widgetClass = GTK_WIDGET_GET_CLASS(aWidget);
@@ -657,21 +663,17 @@ CreateStyleForWidget(GtkWidget* aWidget,
   // not the path.  GtkWidgets store their classes on the
   // GtkCssNodeDeclaration, so make sure to add classes there.
   //
   // Picking up classes from the style context also means that
   // https://bugzilla.gnome.org/show_bug.cgi?id=767312, which can stop
   // gtk_widget_path_append_for_widget() from finding classes in GTK 3.20,
   // is not a problem.
   GtkStyleContext* widgetStyle = gtk_widget_get_style_context(aWidget);
-  GList* classes = gtk_style_context_list_classes(widgetStyle);
-  for (GList* link = classes; link; link = link->next) {
-    gtk_style_context_add_class(context, static_cast<gchar*>(link->data));
-  }
-  g_list_free(classes);
+  AddStyleClassesFromStyle(context, widgetStyle);
 
   // Release any floating reference on aWidget.
   g_object_ref_sink(aWidget);
   g_object_unref(aWidget);
 
   return context;
 }
 
@@ -777,23 +779,68 @@ GetWidgetRootStyle(WidgetNodeType aNodeT
 }
 
 static GtkStyleContext*
 CreateChildCSSNode(const char* aName, WidgetNodeType aParentNodeType)
 {
   return CreateCSSNode(aName, GetCssNodeStyleInternal(aParentNodeType));
 }
 
+// Create a style context equivalent to a saved root style context of
+// |aWidgetType| with |aStyleClass| as an additional class.  This is used to
+// produce a context equivalent to what GTK versions < 3.20 use for many
+// internal parts of widgets.
 static GtkStyleContext*
-GetWidgetStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass)
+CreateSubStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass)
 {
-  GtkStyleContext* style = GetWidgetRootStyle(aWidgetType);
-  gtk_style_context_save(style);
-  MOZ_ASSERT(!sStyleContextNeedsRestore);
-  sStyleContextNeedsRestore = true;
+  static auto sGtkWidgetPathIterGetObjectName =
+    reinterpret_cast<const char* (*)(const GtkWidgetPath*, gint)>
+    (dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_get_object_name"));
+
+  GtkStyleContext* parentStyle = GetWidgetRootStyle(aWidgetType);
+
+  // Create a new context that behaves like |parentStyle| would after
+  // gtk_style_context_save(parentStyle).
+  //
+  // Avoiding gtk_style_context_save() avoids the need to manage the
+  // restore, and a new context permits caching style resolution.
+  //
+  // gtk_style_context_save(context) changes the node hierarchy of |context|
+  // to add a new GtkCssNodeDeclaration that is a copy of its original node.
+  // The new node is a child of the original node, and so the new heirarchy is
+  // one level deeper.  The new node receives the same classes as the
+  // original, but any changes to the classes on |context| will change only
+  // the new node.  The new node inherits properties from the original node
+  // (which retains the original heirarchy and classes) and matches CSS rules
+  // with the new heirarchy and any changes to the classes.
+  //
+  // The change in hierarchy can produce some surprises in matching theme CSS
+  // rules (e.g. https://bugzilla.gnome.org/show_bug.cgi?id=761870#c2), but it
+  // is important here to produce the same behavior so that rules match the
+  // same widget parts in Gecko as they do in GTK.
+  //
+  // When using public GTK API to construct style contexts, a widget path is
+  // required.  CSS rules are not matched against the style context heirarchy
+  // but according to the heirarchy in the widget path.  The path that matches
+  // the same CSS rules as a saved context is like the path of |parentStyle|
+  // but with an extra copy of the head (last) object appended.  Setting
+  // |parentStyle| as the parent context provides the same inheritance of
+  // properties from the widget root node.
+  const GtkWidgetPath* parentPath = gtk_style_context_get_path(parentStyle);
+  const gchar* name = sGtkWidgetPathIterGetObjectName ?
+    sGtkWidgetPathIterGetObjectName(parentPath, -1) : nullptr;
+  GType objectType = gtk_widget_path_get_object_type(parentPath);
+
+  GtkStyleContext* style = CreateCSSNode(name, parentStyle, objectType);
+
+  // Start with the same classes on the new node as were on |parentStyle|.
+  // GTK puts no regions or junction_sides on widget root nodes, and so there
+  // is no need to copy these.
+  AddStyleClassesFromStyle(style, parentStyle);
+
   gtk_style_context_add_class(style, aStyleClass);
   return style;
 }
 
 /* GetCssNodeStyleInternal is used by Gtk >= 3.20 */
 static GtkStyleContext*
 GetCssNodeStyleInternal(WidgetNodeType aNodeType)
 {
@@ -852,30 +899,34 @@ GetCssNodeStyleInternal(WidgetNodeType a
                                  MOZ_GTK_PROGRESSBAR);
       break;
     case MOZ_GTK_PROGRESS_CHUNK:
       style = CreateChildCSSNode("progress",
                                  MOZ_GTK_PROGRESS_TROUGH);
       break;
     case MOZ_GTK_GRIPPER:
       // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
-                                     GTK_STYLE_CLASS_GRIP);
+      style = CreateSubStyleWithClass(MOZ_GTK_GRIPPER,
+                                      GTK_STYLE_CLASS_GRIP);
+      break;
     case MOZ_GTK_INFO_BAR:
       // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR,
-                                     GTK_STYLE_CLASS_INFO);
+      style = CreateSubStyleWithClass(MOZ_GTK_INFO_BAR,
+                                      GTK_STYLE_CLASS_INFO);
+      break;
     case MOZ_GTK_SPINBUTTON_ENTRY:
       // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON,
-                                     GTK_STYLE_CLASS_ENTRY);
+      style = CreateSubStyleWithClass(MOZ_GTK_SPINBUTTON,
+                                      GTK_STYLE_CLASS_ENTRY);
+      break;
     case MOZ_GTK_SCROLLED_WINDOW:
       // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
-                                     GTK_STYLE_CLASS_FRAME);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
+                                      GTK_STYLE_CLASS_FRAME);
+      break;
     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
@@ -893,22 +944,24 @@ GetCssNodeStyleInternal(WidgetNodeType a
         gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
       }
       break;
     case MOZ_GTK_FRAME_BORDER:
       style = CreateChildCSSNode("border", MOZ_GTK_FRAME);
       break;
     case MOZ_GTK_TREEVIEW_VIEW:
       // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
-                                     GTK_STYLE_CLASS_VIEW);
+      style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
+                                      GTK_STYLE_CLASS_VIEW);
+      break;
     case MOZ_GTK_TREEVIEW_EXPANDER:
       // TODO - create from CSS node
-      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
-                                     GTK_STYLE_CLASS_EXPANDER);
+      style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
+                                      GTK_STYLE_CLASS_EXPANDER);
+      break;
     case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
       style = CreateChildCSSNode("separator",
                                  MOZ_GTK_SPLITTER_HORIZONTAL);
       break;
     case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
       style = CreateChildCSSNode("separator",
                                  MOZ_GTK_SPLITTER_VERTICAL);
       break;
@@ -934,30 +987,30 @@ GetCssNodeStyleInternal(WidgetNodeType a
       break;
     case MOZ_GTK_SCALE_THUMB_VERTICAL:
       style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
                                  MOZ_GTK_SCALE_TROUGH_VERTICAL);
       break;
     case MOZ_GTK_TAB_TOP:
     {
       // TODO - create from CSS node
-      style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
+      style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK,
                                       GTK_STYLE_CLASS_TOP);
       gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
                                    static_cast<GtkRegionFlags>(0));
-      return style;
+      break;
     }
     case MOZ_GTK_TAB_BOTTOM:
     {
       // TODO - create from CSS node
-      style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
+      style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK,
                                       GTK_STYLE_CLASS_BOTTOM);
       gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
                                    static_cast<GtkRegionFlags>(0));
-      return style;
+      break;
     }
     case MOZ_GTK_NOTEBOOK:
     case MOZ_GTK_NOTEBOOK_HEADER:
     case MOZ_GTK_TABPANELS:
     case MOZ_GTK_TAB_SCROLLARROW:
     { 
       // TODO - create from CSS node
       GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
@@ -971,145 +1024,159 @@ GetCssNodeStyleInternal(WidgetNodeType a
   sStyleStorage[aNodeType] = style;
   return style;
 }
 
 /* GetWidgetStyleInternal is used by Gtk < 3.20 */
 static GtkStyleContext*
 GetWidgetStyleInternal(WidgetNodeType aNodeType)
 {
+  GtkStyleContext* style = sStyleStorage[aNodeType];
+  if (style)
+    return style;
+
   switch (aNodeType) {
     case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
-                                     GTK_STYLE_CLASS_TROUGH);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
+                                      GTK_STYLE_CLASS_TROUGH);
+      break;
     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
-                                     GTK_STYLE_CLASS_SLIDER);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
+                                      GTK_STYLE_CLASS_SLIDER);
+      break;
     case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
-                                     GTK_STYLE_CLASS_TROUGH);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
+                                      GTK_STYLE_CLASS_TROUGH);
+      break;
     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
-                                     GTK_STYLE_CLASS_SLIDER);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
+                                      GTK_STYLE_CLASS_SLIDER);
+      break;
     case MOZ_GTK_RADIOBUTTON:
-      return GetWidgetStyleWithClass(MOZ_GTK_RADIOBUTTON_CONTAINER,
-                                     GTK_STYLE_CLASS_RADIO);
+      style = CreateSubStyleWithClass(MOZ_GTK_RADIOBUTTON_CONTAINER,
+                                      GTK_STYLE_CLASS_RADIO);
+      break;
     case MOZ_GTK_CHECKBUTTON:
-      return GetWidgetStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
-                                     GTK_STYLE_CLASS_CHECK);
+      style = CreateSubStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
+                                      GTK_STYLE_CLASS_CHECK);
+      break;
     case MOZ_GTK_RADIOMENUITEM_INDICATOR:
-      return GetWidgetStyleWithClass(MOZ_GTK_RADIOMENUITEM,
-                                     GTK_STYLE_CLASS_RADIO);
+      style = CreateSubStyleWithClass(MOZ_GTK_RADIOMENUITEM,
+                                      GTK_STYLE_CLASS_RADIO);
+      break;
     case MOZ_GTK_CHECKMENUITEM_INDICATOR:
-      return GetWidgetStyleWithClass(MOZ_GTK_CHECKMENUITEM,
-                                     GTK_STYLE_CLASS_CHECK);
+      style = CreateSubStyleWithClass(MOZ_GTK_CHECKMENUITEM,
+                                      GTK_STYLE_CLASS_CHECK);
+      break;
     case MOZ_GTK_PROGRESS_TROUGH:
-      return GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR,
-                                     GTK_STYLE_CLASS_TROUGH);
-    case MOZ_GTK_PROGRESS_CHUNK: {
-      GtkStyleContext* style =
-        GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR,
-                                GTK_STYLE_CLASS_PROGRESSBAR);
+      style = CreateSubStyleWithClass(MOZ_GTK_PROGRESSBAR,
+                                      GTK_STYLE_CLASS_TROUGH);
+      break;
+    case MOZ_GTK_PROGRESS_CHUNK:
+      style = CreateSubStyleWithClass(MOZ_GTK_PROGRESSBAR,
+                                      GTK_STYLE_CLASS_PROGRESSBAR);
       gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
-      return style;
-    }
+      break;
     case MOZ_GTK_GRIPPER:
-      return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER,
-                                     GTK_STYLE_CLASS_GRIP);
+      style = CreateSubStyleWithClass(MOZ_GTK_GRIPPER,
+                                      GTK_STYLE_CLASS_GRIP);
+      break;
     case MOZ_GTK_INFO_BAR:
-      return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR,
-                                     GTK_STYLE_CLASS_INFO);
+      style = CreateSubStyleWithClass(MOZ_GTK_INFO_BAR,
+                                      GTK_STYLE_CLASS_INFO);
+      break;
     case MOZ_GTK_SPINBUTTON_ENTRY:
-      return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON,
-                                     GTK_STYLE_CLASS_ENTRY);
+      style = CreateSubStyleWithClass(MOZ_GTK_SPINBUTTON,
+                                      GTK_STYLE_CLASS_ENTRY);
+      break;
     case MOZ_GTK_SCROLLED_WINDOW:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
-                                     GTK_STYLE_CLASS_FRAME);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
+                                      GTK_STYLE_CLASS_FRAME);
+      break;
     case MOZ_GTK_TEXT_VIEW_TEXT:
-    case MOZ_GTK_RESIZER: {
+    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);
+      style = CreateSubStyleWithClass(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;
-    }
+      break;
     case MOZ_GTK_FRAME_BORDER:
       return GetWidgetRootStyle(MOZ_GTK_FRAME);
     case MOZ_GTK_TREEVIEW_VIEW:
-      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
-                                     GTK_STYLE_CLASS_VIEW);
+      style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
+                                      GTK_STYLE_CLASS_VIEW);
+      break;
     case MOZ_GTK_TREEVIEW_EXPANDER:
-      return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
-                                     GTK_STYLE_CLASS_EXPANDER);
+      style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
+                                      GTK_STYLE_CLASS_EXPANDER);
+      break;
     case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SPLITTER_HORIZONTAL,
-                                     GTK_STYLE_CLASS_PANE_SEPARATOR);
+      style = CreateSubStyleWithClass(MOZ_GTK_SPLITTER_HORIZONTAL,
+                                      GTK_STYLE_CLASS_PANE_SEPARATOR);
+      break;
     case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SPLITTER_VERTICAL,
-                                     GTK_STYLE_CLASS_PANE_SEPARATOR);
+      style = CreateSubStyleWithClass(MOZ_GTK_SPLITTER_VERTICAL,
+                                      GTK_STYLE_CLASS_PANE_SEPARATOR);
+      break;
     case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
-                                     GTK_STYLE_CLASS_TROUGH);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
+                                      GTK_STYLE_CLASS_TROUGH);
+      break;
     case MOZ_GTK_SCALE_TROUGH_VERTICAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
-                                     GTK_STYLE_CLASS_TROUGH);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
+                                      GTK_STYLE_CLASS_TROUGH);
+      break;
     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
-                                     GTK_STYLE_CLASS_SLIDER);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
+                                      GTK_STYLE_CLASS_SLIDER);
+      break;
     case MOZ_GTK_SCALE_THUMB_VERTICAL:
-      return GetWidgetStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
-                                     GTK_STYLE_CLASS_SLIDER);
+      style = CreateSubStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
+                                      GTK_STYLE_CLASS_SLIDER);
+      break;
     case MOZ_GTK_TAB_TOP:
-    {
-      GtkStyleContext* style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
-                                                       GTK_STYLE_CLASS_TOP);
+      style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_TOP);
       gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
                                    static_cast<GtkRegionFlags>(0));
-      return style;
-    }
+      break;
     case MOZ_GTK_TAB_BOTTOM:
-    {
-      GtkStyleContext* style = GetWidgetStyleWithClass(MOZ_GTK_NOTEBOOK,
-                                                       GTK_STYLE_CLASS_BOTTOM);
+      style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_BOTTOM);
       gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
                                    static_cast<GtkRegionFlags>(0));
-      return style;
-    }
+      break;
     case MOZ_GTK_NOTEBOOK:
     case MOZ_GTK_NOTEBOOK_HEADER:
     case MOZ_GTK_TABPANELS:
     case MOZ_GTK_TAB_SCROLLARROW:
     { 
       GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
       return gtk_widget_get_style_context(widget);
     }
     default:
       return GetWidgetRootStyle(aNodeType);
   }
+
+  MOZ_ASSERT(style);
+  sStyleStorage[aNodeType] = style;
+  return style;
 }
 
 void
 ResetWidgetCache(void)
 {
-  MOZ_ASSERT(!sStyleContextNeedsRestore);
-#ifdef DEBUG
-  MOZ_ASSERT(!sCurrentStyleContext);
-#endif
-
   for (int i = 0; i < MOZ_GTK_WIDGET_NODE_COUNT; i++) {
     if (sStyleStorage[i])
       g_object_unref(sStyleStorage[i]);
   }
   mozilla::PodArrayZero(sStyleStorage);
 
   /* This will destroy all of our widgets */
   if (sWidgetStorage[MOZ_GTK_WINDOW])
@@ -1118,27 +1185,22 @@ ResetWidgetCache(void)
   /* Clear already freed arrays */
   mozilla::PodArrayZero(sWidgetStorage);
 }
 
 GtkStyleContext*
 ClaimStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection,
                   GtkStateFlags aStateFlags, StyleFlags aFlags)
 {
-  MOZ_ASSERT(!sStyleContextNeedsRestore);
   GtkStyleContext* style;
   if (gtk_check_version(3, 20, 0) != nullptr) {
     style = GetWidgetStyleInternal(aNodeType);
   } else {
     style = GetCssNodeStyleInternal(aNodeType);
   }
-#ifdef DEBUG
-  MOZ_ASSERT(!sCurrentStyleContext);
-  sCurrentStyleContext = style;
-#endif
   bool stateChanged = false;
   bool stateHasDirection = gtk_get_minor_version() >= 8;
   GtkStateFlags oldState = gtk_style_context_get_state(style);
   MOZ_ASSERT(!(aStateFlags & (STATE_FLAG_DIR_LTR|STATE_FLAG_DIR_RTL)));
   unsigned newState = aStateFlags;
   if (stateHasDirection) {
     switch (aDirection) {
       case GTK_TEXT_DIR_LTR:
@@ -1168,28 +1230,21 @@ ClaimStyleContext(WidgetNodeType aNodeTy
     stateChanged = true;
   }
   // This invalidate is necessary for unsaved style contexts from GtkWidgets
   // in pre-3.18 GTK, because automatic invalidation of such contexts
   // was delayed until a resize event runs.
   //
   // https://bugzilla.mozilla.org/show_bug.cgi?id=1272194#c7
   //
-  // Avoid calling invalidate on saved contexts to avoid performing
-  // build_properties() (in 3.16 stylecontext.c) unnecessarily early.
-  if (stateChanged && !sStyleContextNeedsRestore) {
+  // Avoid calling invalidate on contexts that are not owned and constructed
+  // by widgets to avoid performing build_properties() (in 3.16 stylecontext.c)
+  // unnecessarily early.
+  if (stateChanged && sWidgetStorage[aNodeType]) {
     gtk_style_context_invalidate(style);
   }
   return style;
 }
 
 void
 ReleaseStyleContext(GtkStyleContext* aStyleContext)
 {
-  if (sStyleContextNeedsRestore) {
-    gtk_style_context_restore(aStyleContext);
-  }
-  sStyleContextNeedsRestore = false;
-#ifdef DEBUG
-  MOZ_ASSERT(sCurrentStyleContext == aStyleContext);
-  sCurrentStyleContext = nullptr;
-#endif
 }
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -576,16 +576,17 @@ STUB(gtk_style_properties_lookup_propert
 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_type)
 STUB(gtk_widget_path_copy)
 STUB(gtk_widget_path_free)
 STUB(gtk_widget_path_iter_add_class)
+STUB(gtk_widget_path_get_object_type)
 STUB(gtk_widget_path_new)
 STUB(gtk_widget_path_unref)
 STUB(gtk_widget_set_visual)
 STUB(gtk_app_chooser_dialog_new_for_content_type)
 STUB(gtk_app_chooser_get_type)
 STUB(gtk_app_chooser_get_app_info)
 STUB(gtk_app_chooser_dialog_get_type)
 STUB(gtk_app_chooser_dialog_set_heading)