Bug 1315668 construct menuitem style contexts from paths r=stransky a=lizzard
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 15 Nov 2016 17:11:14 +1300
changeset 352471 b77fb8918a6d260b50eb27921b1b27096d382578
parent 352470 10c574e6c34375e071695a437ae6fd85c1c2157c
child 352472 04449274c3e1ec7f33a3256b6e9ce2e1e43e7c8c
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 construct menuitem style contexts from paths r=stransky a=lizzard instead of using the context belonging to a widget. Only the style context is cached, instead of the whole widget. Using the style context from a widget meant that rendering displayed the initial appearance of animations after state changes, but there was no invalidation to trigger the final rendering in the animations. Style contexts constructed from paths do not incorporate animations. (See gtk_css_path_node_update_style() in GTK.) Therefore they provide the appropriate rendering for Gecko's model, which is not expecting animations. There is no mechanism available to display animations when using style contexts constructed from paths, but the GtkWidget animation design is also not suitable for rendering potentially multiple elements each in a different state of their animation. This contexts-from-paths approach can be extended also to other widget types, but this is a smaller change intended for uplift to other branches to address a regression in menuitem rendering. MozReview-Commit-ID: EFV7swWQtm4
widget/gtk/WidgetStyleCache.cpp
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -20,16 +20,18 @@ static_assert(GTK_STATE_FLAG_DIR_LTR == 
 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()
 {
   GtkWidget *widget = gtk_window_new(GTK_WINDOW_POPUP);
   gtk_widget_realize(widget);
   gtk_widget_set_name(widget, "MozillaGtkWidget");
@@ -88,24 +90,16 @@ CreateMenuPopupWidget()
 {
   GtkWidget* widget = gtk_menu_new();
   gtk_menu_attach_to_widget(GTK_MENU(widget), GetWidget(MOZ_GTK_WINDOW),
                             nullptr);
   return widget;
 }
 
 static GtkWidget*
-CreateMenuItemWidget(WidgetNodeType aShellType)
-{
-  GtkWidget* widget = gtk_menu_item_new();
-  gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(aShellType)), widget);
-  return widget;
-}
-
-static GtkWidget*
 CreateProgressWidget()
 {
   GtkWidget* widget = gtk_progress_bar_new();
   AddToWindowContainer(widget);
   return widget;
 }
 
 static GtkWidget*
@@ -536,43 +530,16 @@ static GtkWidget*
 CreateVPanedWidget()
 {
   GtkWidget* widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
   AddToWindowContainer(widget);
   return widget;
 }
 
 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*
-CreateCheckMenuItemWidget()
-{
-  GtkWidget* widget = gtk_check_menu_item_new();
-  gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)), widget);
-  gtk_widget_realize(widget);
-  return widget;
-}
-
-static GtkWidget*
-CreateRadioMenuItemWidget()
-{
-  GtkWidget* widget = gtk_radio_menu_item_new(nullptr);
-  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);
   AddToWindowContainer(widget);
   return widget;
 }
 
 static GtkWidget*
@@ -602,20 +569,16 @@ CreateWidget(WidgetNodeType aWidgetType)
                                    GTK_ORIENTATION_HORIZONTAL);
     case MOZ_GTK_SCROLLBAR_VERTICAL:
       return CreateScrollbarWidget(aWidgetType,
                                    GTK_ORIENTATION_VERTICAL);
     case MOZ_GTK_MENUBAR:
       return CreateMenuBarWidget();
     case MOZ_GTK_MENUPOPUP:
       return CreateMenuPopupWidget();
-    case MOZ_GTK_MENUBARITEM:
-      return CreateMenuItemWidget(MOZ_GTK_MENUBAR);
-    case MOZ_GTK_MENUITEM:
-      return CreateMenuItemWidget(MOZ_GTK_MENUPOPUP);
     case MOZ_GTK_MENUSEPARATOR:
       return CreateMenuSeparatorWidget();
     case MOZ_GTK_EXPANDER:
       return CreateExpanderWidget();
     case MOZ_GTK_FRAME:
       return CreateFrameWidget();
     case MOZ_GTK_GRIPPER:
       return CreateGripperWidget();
@@ -644,22 +607,16 @@ CreateWidget(WidgetNodeType aWidgetType)
     case MOZ_GTK_TREE_HEADER_CELL:
       return CreateTreeHeaderCellWidget();
     case MOZ_GTK_TREE_HEADER_SORTARROW:
       return CreateTreeHeaderSortArrowWidget();
     case MOZ_GTK_SPLITTER_HORIZONTAL:
       return CreateHPanedWidget();
     case MOZ_GTK_SPLITTER_VERTICAL:
       return CreateVPanedWidget();
-    case MOZ_GTK_IMAGEMENUITEM:
-      return CreateImageMenuItemWidget();
-    case MOZ_GTK_CHECKMENUITEM_CONTAINER:
-      return CreateCheckMenuItemWidget();
-    case MOZ_GTK_RADIOMENUITEM_CONTAINER:
-      return CreateRadioMenuItemWidget();
     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();
@@ -733,16 +690,22 @@ CreateStyleForWidget(GtkWidget* aWidget,
 
   // Release any floating reference on aWidget.
   g_object_ref_sink(aWidget);
   g_object_unref(aWidget);
 
   return context;
 }
 
+static GtkStyleContext*
+CreateStyleForWidget(GtkWidget* aWidget, WidgetNodeType aParentType)
+{
+  return CreateStyleForWidget(aWidget, GetWidgetRootStyle(aParentType));
+}
+
 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 ?
@@ -758,26 +721,63 @@ CreateCSSNode(const char* aName, GtkStyl
   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;
 }
 
+// Return a style context matching that of the root CSS node of a widget.
+// This is used by all GTK versions.
+static GtkStyleContext*
+GetWidgetRootStyle(WidgetNodeType aNodeType)
+{
+  GtkStyleContext* style = sStyleStorage[aNodeType];
+  if (style)
+    return style;
+
+  switch (aNodeType) {
+    case MOZ_GTK_MENUBARITEM:
+      style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUBAR);
+      break;
+    case MOZ_GTK_MENUITEM:
+      style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUPOPUP);
+      break;
+    case MOZ_GTK_IMAGEMENUITEM:
+      style = CreateStyleForWidget(gtk_image_menu_item_new(), MOZ_GTK_MENUPOPUP);
+      break;
+    case MOZ_GTK_CHECKMENUITEM_CONTAINER:
+      style = CreateStyleForWidget(gtk_check_menu_item_new(), MOZ_GTK_MENUPOPUP);
+      break;
+    case MOZ_GTK_RADIOMENUITEM_CONTAINER:
+      style = CreateStyleForWidget(gtk_radio_menu_item_new(nullptr),
+                                   MOZ_GTK_MENUPOPUP);
+      break;
+    default:
+      GtkWidget* widget = GetWidget(aNodeType);
+      MOZ_ASSERT(widget);
+      return gtk_widget_get_style_context(widget);
+  }
+
+  MOZ_ASSERT(style);
+  sStyleStorage[aNodeType] = style;
+  return style;
+}
+
 static GtkStyleContext*
 CreateChildCSSNode(const char* aName, WidgetNodeType aParentNodeType)
 {
   return CreateCSSNode(aName, GetCssNodeStyleInternal(aParentNodeType));
 }
 
 static GtkStyleContext*
 GetWidgetStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass)
 {
-  GtkStyleContext* style = gtk_widget_get_style_context(GetWidget(aWidgetType));
+  GtkStyleContext* style = GetWidgetRootStyle(aWidgetType);
   gtk_style_context_save(style);
   MOZ_ASSERT(!sStyleContextNeedsRestore);
   sStyleContextNeedsRestore = true;
   gtk_style_context_add_class(style, aStyleClass);
   return style;
 }
 
 /* GetCssNodeStyleInternal is used by Gtk >= 3.20 */
@@ -933,19 +933,17 @@ GetCssNodeStyleInternal(WidgetNodeType a
     case MOZ_GTK_TABPANELS:
     case MOZ_GTK_TAB_SCROLLARROW:
     { 
       // TODO - create from CSS node
       GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
       return gtk_widget_get_style_context(widget);
     }
     default:
-      // TODO - create style from style path
-      GtkWidget* widget = GetWidget(aNodeType);
-      return gtk_widget_get_style_context(widget);
+      return GetWidgetRootStyle(aNodeType);
   }
 
   MOZ_ASSERT(style, "missing style context for node type");
   sStyleStorage[aNodeType] = style;
   return style;
 }
 
 /* GetWidgetStyleInternal is used by Gtk < 3.20 */
@@ -1005,17 +1003,17 @@ GetWidgetStyleInternal(WidgetNodeType aN
                                      GTK_STYLE_CLASS_ENTRY);
     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_FRAME_BORDER:
-      return GetWidgetStyleInternal(MOZ_GTK_FRAME);
+      return GetWidgetRootStyle(MOZ_GTK_FRAME);
     case MOZ_GTK_TREEVIEW_VIEW:
       return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
                                      GTK_STYLE_CLASS_VIEW);
     case MOZ_GTK_TREEVIEW_EXPANDER:
       return GetWidgetStyleWithClass(MOZ_GTK_TREEVIEW,
                                      GTK_STYLE_CLASS_EXPANDER);
     case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
       return GetWidgetStyleWithClass(MOZ_GTK_SPLITTER_HORIZONTAL,
@@ -1055,19 +1053,17 @@ GetWidgetStyleInternal(WidgetNodeType aN
     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:
-      GtkWidget* widget = GetWidget(aNodeType);
-      MOZ_ASSERT(widget);
-      return gtk_widget_get_style_context(widget);
+      return GetWidgetRootStyle(aNodeType);
   }
 }
 
 void
 ResetWidgetCache(void)
 {
   MOZ_ASSERT(!sStyleContextNeedsRestore);
 #ifdef DEBUG