bug 1315668 construct menuitem style contexts from paths r?stransky draft
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 15 Nov 2016 17:11:14 +1300
changeset 438829 eda1e700ee3c8ffb4b9673854b611a927918ec2f
parent 438827 a1c80bc8f5e6320236a1890b8addfd76e90da9b0
child 439462 65b2a0df24fe06582350b93614a9ffa62147da11
push id35826
push userktomlinson@mozilla.com
push dateTue, 15 Nov 2016 04:18:03 +0000
reviewersstransky
bugs1315668
milestone53.0a1
bug 1315668 construct menuitem style contexts from paths r?stransky 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