Bug 1315668 CreateStyleForWidget: store classes on context instead of path r=stransky a=lizzard
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 15 Nov 2016 15:29:06 +1300
changeset 352470 10c574e6c34375e071695a437ae6fd85c1c2157c
parent 352469 333f3821396e342c267309a84ce5cf405737a37a
child 352471 b77fb8918a6d260b50eb27921b1b27096d382578
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstransky, lizzard
bugs1315668
milestone52.0a2
Bug 1315668 CreateStyleForWidget: store classes on context instead of path r=stransky a=lizzard CreateStyleForWidget() then provides the same behavior with g_style_context_save() as contexts from widget root style nodes. MozReview-Commit-ID: 6lRCp3XOoRr
widget/gtk/WidgetStyleCache.cpp
widget/gtk/WidgetStyleCache.h
widget/gtk/mozgtk/mozgtk.c
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -692,51 +692,73 @@ GetWidget(WidgetNodeType aWidgetType)
     sWidgetStorage[aWidgetType] = widget;
   }
   return widget;
 }
 
 GtkStyleContext*
 CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle)
 {
-  GtkWidgetPath* path = aParentStyle ?
-    gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) :
-    gtk_widget_path_new();
+  static auto sGtkWidgetClassGetCSSName =
+    reinterpret_cast<const char* (*)(GtkWidgetClass*)>
+    (dlsym(RTLD_DEFAULT, "gtk_widget_class_get_css_name"));
+
+  GtkWidgetClass *widgetClass = GTK_WIDGET_GET_CLASS(aWidget);
+  const gchar* name = sGtkWidgetClassGetCSSName ?
+    sGtkWidgetClassGetCSSName(widgetClass) : nullptr;
+
+  GtkStyleContext *context =
+    CreateCSSNode(name, aParentStyle, G_TYPE_FROM_CLASS(widgetClass));
 
-  // Work around https://bugzilla.gnome.org/show_bug.cgi?id=767312
-  // which exists in GTK+ 3.20.
-  gtk_widget_get_style_context(aWidget);
+  // Classes are stored on the style context instead of the path so that any
+  // future gtk_style_context_save() will inherit classes on the head CSS
+  // node, in the same way as happens when called on a style context owned by
+  // a widget.
+  //
+  // Classes can be stored on a GtkCssNodeDeclaration and/or the path.
+  // gtk_style_context_save() reuses the GtkCssNodeDeclaration, and appends a
+  // new object to the path, without copying the classes from the old path
+  // head.  The new head picks up classes from the GtkCssNodeDeclaration, but
+  // not the path.  GtkWidgets store their classes on the
+  // GtkCssNodeDeclaration, so make sure to add classes there.
+  //
+  // Picking up classes from the style context also means that
+  // https://bugzilla.gnome.org/show_bug.cgi?id=767312, which can stop
+  // gtk_widget_path_append_for_widget() from finding classes in GTK 3.20,
+  // is not a problem.
+  GtkStyleContext* widgetStyle = gtk_widget_get_style_context(aWidget);
+  GList* classes = gtk_style_context_list_classes(widgetStyle);
+  for (GList* link = classes; link; link = link->next) {
+    gtk_style_context_add_class(context, static_cast<gchar*>(link->data));
+  }
+  g_list_free(classes);
 
-  gtk_widget_path_append_for_widget(path, aWidget);
   // Release any floating reference on aWidget.
   g_object_ref_sink(aWidget);
   g_object_unref(aWidget);
 
-  GtkStyleContext *context = gtk_style_context_new();
-  gtk_style_context_set_path(context, path);
-  gtk_style_context_set_parent(context, aParentStyle);
-  gtk_widget_path_unref(path);
-
   return context;
 }
 
 GtkStyleContext*
 CreateCSSNode(const char* aName, GtkStyleContext* aParentStyle, GType aType)
 {
   static auto sGtkWidgetPathIterSetObjectName =
     reinterpret_cast<void (*)(GtkWidgetPath *, gint, const char *)>
     (dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_set_object_name"));
 
   GtkWidgetPath* path = aParentStyle ?
     gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) :
     gtk_widget_path_new();
 
   gtk_widget_path_append_type(path, aType);
 
-  (*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
+  if (sGtkWidgetPathIterSetObjectName) {
+    (*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
+  }
 
   GtkStyleContext *context = gtk_style_context_new();
   gtk_style_context_set_path(context, path);
   gtk_style_context_set_parent(context, aParentStyle);
   gtk_widget_path_unref(path);
 
   return context;
 }
--- a/widget/gtk/WidgetStyleCache.h
+++ b/widget/gtk/WidgetStyleCache.h
@@ -23,17 +23,16 @@ GetWidget(WidgetNodeType aNodeType);
 
 /*
  * Return a new style context based on aWidget, as a child of aParentStyle.
  * If aWidget still has a floating reference, then it is sunk and released.
  */
 GtkStyleContext*
 CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle);
 
-// CreateCSSNode is implemented for gtk >= 3.20 only.
 GtkStyleContext*
 CreateCSSNode(const char*      aName,
               GtkStyleContext* aParentStyle,
               GType            aType = G_TYPE_NONE);
 
 // Callers must call ReleaseStyleContext() on the returned context.
 GtkStyleContext*
 ClaimStyleContext(WidgetNodeType aNodeType,
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -558,16 +558,17 @@ STUB(gtk_style_context_get_direction)
 STUB(gtk_style_context_get_margin)
 STUB(gtk_style_context_get_padding)
 STUB(gtk_style_context_get_path)
 STUB(gtk_style_context_get_property)
 STUB(gtk_style_context_get_state)
 STUB(gtk_style_context_get_style)
 STUB(gtk_style_context_has_class)
 STUB(gtk_style_context_invalidate)
+STUB(gtk_style_context_list_classes)
 STUB(gtk_style_context_new)
 STUB(gtk_style_context_remove_class)
 STUB(gtk_style_context_remove_region)
 STUB(gtk_style_context_restore)
 STUB(gtk_style_context_save)
 STUB(gtk_style_context_set_direction)
 STUB(gtk_style_context_set_path)
 STUB(gtk_style_context_set_parent)