bug 1315668 construct menuitem style contexts from paths r=stransky+263117
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 15 Nov 2016 17:11:14 +1300
changeset 439676 d09e8a3b7875af81f391fe46ae6da3febbb37363
parent 439675 1693f10ca33e6f46f5b0b20b7b0f3ac5171be0f7
child 439677 0c8359a83645538a6eb7ff7cc935a9115426e8ec
push id36064
push userrthijssen@mozilla.com
push dateWed, 16 Nov 2016 13:38:27 +0000
reviewersstransky
bugs1315668, 263117
milestone53.0a1
bug 1315668 construct menuitem style contexts from paths r=stransky+263117 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