Bug 1367576 - Cache results of getting GTK widget borders. r=karlt
authorL. David Baron <dbaron@dbaron.org>
Tue, 06 Jun 2017 22:27:18 -0700
changeset 362646 b8e44a1cb4505c51d398db387c4c1d5c8afc462c
parent 362645 db68e1963b3974821cc065440f1b693a82721619
child 362647 33997d929fda5555b857ce1aa0f523c99bfc0434
push id31987
push userryanvm@gmail.com
push dateThu, 08 Jun 2017 02:55:14 +0000
treeherdermozilla-central@7efda263a842 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1367576
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1367576 - Cache results of getting GTK widget borders. r=karlt See comments in the header file. This also clears out mSafeWidgetStates in ThemeChanged since that seems like a good thing to do, and marks nsNativeThemeGTK as final. MozReview-Commit-ID: 5Zne4eGbGlh
widget/gtk/gtk3drawing.cpp
widget/gtk/gtkdrawing.h
widget/gtk/nsNativeThemeGTK.cpp
widget/gtk/nsNativeThemeGTK.h
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -2069,17 +2069,20 @@ GetMarginBorderPadding(GtkStyleContext* 
     result.right = right;
     result.top = top;
     result.bottom = bottom;
     return result;
 }
 
 gint
 moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
-                          gint* right, gint* bottom, GtkTextDirection direction)
+                          gint* right, gint* bottom,
+                          // NOTE: callers depend on direction being used
+                          // only for MOZ_GTK_DROPDOWN widgets.
+                          GtkTextDirection direction)
 {
     GtkWidget* w;
     GtkStyleContext* style;
     *left = *top = *right = *bottom = 0;
 
     switch (widget) {
     case MOZ_GTK_BUTTON:
     case MOZ_GTK_TOOLBAR_BUTTON:
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -351,17 +351,19 @@ moz_gtk_widget_paint(WidgetNodeType widg
 #endif
 
 
 /*** Widget metrics ***/
 /**
  * Get the border size of a widget
  * left/right:  [OUT] the widget's left/right border
  * top/bottom:  [OUT] the widget's top/bottom border
- * direction:   the text direction for the widget
+ * direction:   the text direction for the widget.  Callers depend on this
+ *              being used only for MOZ_GTK_DROPDOWN widgets, and cache
+ *              results for other widget types across direction values.
  *
  * returns:    MOZ_GTK_SUCCESS if there was no error, an error code otherwise
  */
 gint moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
                                gint* right, gint* bottom, GtkTextDirection direction);
 
 /**
  * Get the border size of a notebook tab
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -65,18 +65,17 @@ nsNativeThemeGTK::nsNativeThemeGTK()
     return;
   }
 
   // We have to call moz_gtk_shutdown before the event loop stops running.
   nsCOMPtr<nsIObserverService> obsServ =
     mozilla::services::GetObserverService();
   obsServ->AddObserver(this, "xpcom-shutdown", false);
 
-  memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
-  memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates));
+  ThemeChanged();
 }
 
 nsNativeThemeGTK::~nsNativeThemeGTK() {
 }
 
 NS_IMETHODIMP
 nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic,
                           const char16_t *aData)
@@ -1264,18 +1263,30 @@ nsNativeThemeGTK::GetCachedWidgetBorder(
                                         nsIntMargin* aResult)
 {
   aResult->SizeTo(0, 0, 0, 0);
 
   WidgetNodeType gtkWidgetType;
   gint unusedFlags;
   if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr,
                            &unusedFlags)) {
-    moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top,
-                              &aResult->right, &aResult->bottom, aDirection);
+    MOZ_ASSERT(0 <= gtkWidgetType && gtkWidgetType < MOZ_GTK_WIDGET_NODE_COUNT);
+    uint8_t cacheIndex = gtkWidgetType / 8;
+    uint8_t cacheBit = 1u << (gtkWidgetType % 8);
+
+    if (mBorderCacheValid[cacheIndex] & cacheBit) {
+      *aResult = mBorderCache[gtkWidgetType];
+    } else {
+      moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top,
+                                &aResult->right, &aResult->bottom, aDirection);
+      if (aWidgetType != MOZ_GTK_DROPDOWN) { // depends on aDirection
+        mBorderCacheValid[cacheIndex] |= cacheBit;
+        mBorderCache[gtkWidgetType] = *aResult;
+      }
+    }
   }
 }
 
 NS_IMETHODIMP
 nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
                                   uint8_t aWidgetType, nsIntMargin* aResult)
 {
   GtkTextDirection direction = GetTextDirection(aFrame);
@@ -1775,16 +1786,18 @@ nsNativeThemeGTK::WidgetStateChanged(nsI
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNativeThemeGTK::ThemeChanged()
 {
   memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
+  memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates));
+  memset(mBorderCacheValid, 0, sizeof(mBorderCacheValid));
   return NS_OK;
 }
 
 NS_IMETHODIMP_(bool)
 nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
                                       nsIFrame* aFrame,
                                       uint8_t aWidgetType)
 {
--- a/widget/gtk/nsNativeThemeGTK.h
+++ b/widget/gtk/nsNativeThemeGTK.h
@@ -10,19 +10,19 @@
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsIObserver.h"
 #include "nsNativeTheme.h"
 
 #include <gtk/gtk.h>
 #include "gtkdrawing.h"
 
-class nsNativeThemeGTK: private nsNativeTheme,
-                        public nsITheme,
-                        public nsIObserver {
+class nsNativeThemeGTK final : private nsNativeTheme,
+                               public nsITheme,
+                               public nsIObserver {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIOBSERVER
 
   // The nsITheme interface.
   NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
                                   nsIFrame* aFrame, uint8_t aWidgetType,
@@ -84,13 +84,18 @@ private:
 
   void RefreshWidgetWindow(nsIFrame* aFrame);
   WidgetNodeType NativeThemeToGtkTheme(uint8_t aWidgetType, nsIFrame* aFrame);
 
   uint8_t mDisabledWidgetTypes[32];
   uint8_t mSafeWidgetStates[1024];    // 256 widgets * 32 bits per widget
   static const char* sDisabledEngines[];
 
+  // Because moz_gtk_get_widget_border can be slow, we cache its results
+  // by widget type.  Each bit in mBorderCacheValid says whether the
+  // corresponding entry in mBorderCache is valid.
   void GetCachedWidgetBorder(nsIFrame* aFrame, uint8_t aWidgetType,
                              GtkTextDirection aDirection, nsIntMargin* aResult);
+  uint8_t mBorderCacheValid[(MOZ_GTK_WIDGET_NODE_COUNT + 7) / 8];
+  nsIntMargin mBorderCache[MOZ_GTK_WIDGET_NODE_COUNT];
 };
 
 #endif