Add change callbacks to gfxPrefs. (bug 1280822 part 2, r=milan)
☠☠ backed out by c6bb3db5e1b8 ☠ ☠
authorDavid Anderson <danderson@mozilla.com>
Fri, 24 Jun 2016 16:15:49 -0700
changeset 342657 91715d8e468fdaecf7f3f334527e8508d9d576c5
parent 342656 3db77f57cef49c606cb82f0ee28748bb7e1ca838
child 342658 93d483583ffa60face65bdd2ccd01bee0284b87e
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmilan
bugs1280822
milestone50.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
Add change callbacks to gfxPrefs. (bug 1280822 part 2, r=milan)
gfx/thebes/gfxPrefs.cpp
gfx/thebes/gfxPrefs.h
--- a/gfx/thebes/gfxPrefs.cpp
+++ b/gfx/thebes/gfxPrefs.cpp
@@ -75,25 +75,59 @@ gfxPrefs::~gfxPrefs()
   mMoz2DPrefAccess = nullptr;
 }
 
 void gfxPrefs::AssertMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread(), "this code must be run on the main thread");
 }
 
+void
+gfxPrefs::Pref::OnChange()
+{
+  if (mChangeCallback) {
+    mChangeCallback();
+  }
+}
+
+void
+gfxPrefs::Pref::SetChangeCallback(ChangeCallback aCallback)
+{
+  mChangeCallback = aCallback;
+
+  if (!IsParentProcess() && IsPrefsServiceAvailable()) {
+    // If we're in the parent process, we watch prefs by default so we can
+    // send changes over to the GPU process. Otherwise, we need to add or
+    // remove a watch for the pref now.
+    if (aCallback) {
+      WatchChanges(Name(), this);
+    } else {
+      UnwatchChanges(Name(), this);
+    }
+  }
+
+  // Fire the callback once to make initialization easier for the caller.
+  OnChange();
+}
+
 // On lightweight processes such as for GMP and GPU, XPCOM is not initialized,
 // and therefore we don't have access to Preferences. When XPCOM is not
 // available we rely on manual synchronization of gfxPrefs values over IPC.
 /* static */ bool
 gfxPrefs::IsPrefsServiceAvailable()
 {
   return Preferences::IsServiceAvailable();
 }
 
+/* static */ bool
+gfxPrefs::IsParentProcess()
+{
+  return XRE_IsParentProcess();
+}
+
 void gfxPrefs::PrefAddVarCache(bool* aVariable,
                                const char* aPref,
                                bool aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddBoolVarCache(aVariable, aPref, aDefault);
 }
 
@@ -164,8 +198,27 @@ void gfxPrefs::PrefSet(const char* aPref
 }
 
 void gfxPrefs::PrefSet(const char* aPref, float aValue)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::SetFloat(aPref, aValue);
 }
 
+static void
+OnGfxPrefChanged(const char* aPrefname, void* aClosure)
+{
+  reinterpret_cast<gfxPrefs::Pref*>(aClosure)->OnChange();
+}
+
+void gfxPrefs::WatchChanges(const char* aPrefname, Pref* aPref)
+{
+  MOZ_ASSERT(IsPrefsServiceAvailable());
+  Preferences::RegisterCallback(OnGfxPrefChanged, aPrefname, aPref, Preferences::ExactMatch);
+}
+
+void gfxPrefs::UnwatchChanges(const char* aPrefname, Pref* aPref)
+{
+  // The Preferences service can go offline before gfxPrefs is destroyed.
+  if (IsPrefsServiceAvailable()) {
+    Preferences::UnregisterCallback(OnGfxPrefChanged, aPrefname, aPref, Preferences::ExactMatch);
+  }
+}
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -50,24 +50,26 @@
 // in the first place, so be careful.  You need to be ready for the
 // values changing mid execution, and if you're using those preferences
 // in any setup and initialization, you may need to do extra work.
 
 // Note 2: Prefs can be set by using the corresponding Set method. For
 // example, if the accessor is Foo() then calling SetFoo(...) will update
 // the preference and also change the return value of subsequent Foo() calls.
 // This is true even for 'Once' prefs which otherwise do not change if the
-// pref is updated after initialization.
+// pref is updated after initialization. Changing gfxPrefs values in content
+// processes will not affect the result in other processes. Changing gfxPrefs
+// values in the GPU process is not supported at all.
 
-#define DECL_GFX_PREF(Update, Pref, Name, Type, Default)                     \
+#define DECL_GFX_PREF(Update, Prefname, Name, Type, Default)                  \
 public:                                                                       \
 static Type Name() { MOZ_ASSERT(SingletonExists()); return GetSingleton().mPref##Name.mValue; } \
-static void Set##Name(Type aVal) { MOZ_ASSERT(SingletonExists()); \
+static void Set##Name(Type aVal) { MOZ_ASSERT(SingletonExists());             \
     GetSingleton().mPref##Name.Set(UpdatePolicy::Update, Get##Name##PrefName(), aVal); } \
-static const char* Get##Name##PrefName() { return Pref; }                     \
+static const char* Get##Name##PrefName() { return Prefname; }                 \
 static Type Get##Name##PrefDefault() { return Default; }                      \
 private:                                                                      \
 PrefTemplate<UpdatePolicy::Update, Type, Get##Name##PrefDefault, Get##Name##PrefName> mPref##Name
 
 class PreferenceAccessImpl;
 class gfxPrefs;
 class gfxPrefs final
 {
@@ -78,29 +80,59 @@ private:
 private:
   // Enums for the update policy.
   enum class UpdatePolicy {
     Skip, // Set the value to default, skip any Preferences calls
     Once, // Evaluate the preference once, unchanged during the session
     Live  // Evaluate the preference and set callback so it stays current/live
   };
 
+public:
+  class Pref
+  {
+  public:
+    Pref() : mChangeCallback(nullptr)
+    {
+    }
+
+    void OnChange();
+
+    typedef void (*ChangeCallback)();
+    void SetChangeCallback(ChangeCallback aCallback);
+
+    virtual const char* Name() const = 0;
+
+  private:
+    ChangeCallback mChangeCallback;
+  };
+
+private:
   // Since we cannot use const char*, use a function that returns it.
   template <UpdatePolicy Update, class T, T Default(void), const char* Prefname(void)>
-  class PrefTemplate
+  class PrefTemplate : public Pref
   {
   public:
     PrefTemplate()
     : mValue(Default())
     {
       // If not using the Preferences service, values are synced over IPC, so
       // there's no need to register us as a Preferences observer.
       if (IsPrefsServiceAvailable()) {
         Register(Update, Prefname());
       }
+      // By default we only watch changes in the parent process, to communicate
+      // changes to the GPU process.
+      if (IsParentProcess() && Update == UpdatePolicy::Live) {
+        WatchChanges(Prefname(), this);
+      }
+    }
+    ~PrefTemplate() {
+      if (IsParentProcess() && Update == UpdatePolicy::Live) {
+        UnwatchChanges(Prefname(), this);
+      }
     }
     void Register(UpdatePolicy aUpdate, const char* aPreference)
     {
       AssertMainThread();
       switch (aUpdate) {
         case UpdatePolicy::Skip:
           break;
         case UpdatePolicy::Once:
@@ -123,16 +155,19 @@ private:
           break;
         case UpdatePolicy::Once:
           mValue = PrefGet(aPref, mValue);
           break;
         default:
           MOZ_CRASH("Incomplete switch");
       }
     }
+    const char *Name() const override {
+      return Prefname();
+    }
     T mValue;
   };
 
   // This is where DECL_GFX_PREF for each of the preferences should go.
   // We will keep these in an alphabetical order to make it easier to see if
   // a method accessing a pref already exists. Just add yours in the list.
 
   // The apz prefs are explained in AsyncPanZoomController.cpp
@@ -493,29 +528,32 @@ public:
   static bool SingletonExists();
 
 private:
   static gfxPrefs* sInstance;
   static bool sInstanceHasBeenDestroyed;
 
 private:
   static bool IsPrefsServiceAvailable();
+  static bool IsParentProcess();
   // Creating these to avoid having to include Preferences.h in the .h
   static void PrefAddVarCache(bool*, const char*, bool);
   static void PrefAddVarCache(int32_t*, const char*, int32_t);
   static void PrefAddVarCache(uint32_t*, const char*, uint32_t);
   static void PrefAddVarCache(float*, const char*, float);
   static bool PrefGet(const char*, bool);
   static int32_t PrefGet(const char*, int32_t);
   static uint32_t PrefGet(const char*, uint32_t);
   static float PrefGet(const char*, float);
   static void PrefSet(const char* aPref, bool aValue);
   static void PrefSet(const char* aPref, int32_t aValue);
   static void PrefSet(const char* aPref, uint32_t aValue);
   static void PrefSet(const char* aPref, float aValue);
+  static void WatchChanges(const char* aPrefname, Pref* aPref);
+  static void UnwatchChanges(const char* aPrefname, Pref* aPref);
 
   static void AssertMainThread();
 
   gfxPrefs();
   ~gfxPrefs();
   gfxPrefs(const gfxPrefs&) = delete;
   gfxPrefs& operator=(const gfxPrefs&) = delete;
 };