bug 1315668 CreateStyleForWidget: store classes on context instead of path r?stransky draft
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 15 Nov 2016 15:29:06 +1300
changeset 438827 a1c80bc8f5e6320236a1890b8addfd76e90da9b0
parent 438826 c80f440a7152d0e0c91671c0343b85a1b74628e1
child 438828 ebaba2a5914226a08dee99e2bd36bb675b9f2c93
child 438829 eda1e700ee3c8ffb4b9673854b611a927918ec2f
push id35825
push userktomlinson@mozilla.com
push dateTue, 15 Nov 2016 04:01:18 +0000
reviewersstransky
bugs1315668
milestone53.0a1
bug 1315668 CreateStyleForWidget: store classes on context instead of path r?stransky 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)