1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "gfxPrefs.h"
7 
8 #include "MainThreadUtils.h"
9 #include "nsXULAppAPI.h"
10 #include "mozilla/Preferences.h"
11 #include "mozilla/Unused.h"
12 #include "mozilla/gfx/Logging.h"
13 #include "mozilla/gfx/GPUChild.h"
14 #include "mozilla/gfx/GPUProcessManager.h"
15 
16 using namespace mozilla;
17 
18 nsTArray<gfxPrefs::Pref*>* gfxPrefs::sGfxPrefList = nullptr;
19 gfxPrefs* gfxPrefs::sInstance = nullptr;
20 bool gfxPrefs::sInstanceHasBeenDestroyed = false;
21 
22 void
DestroySingleton()23 gfxPrefs::DestroySingleton()
24 {
25   if (sInstance) {
26     delete sInstance;
27     sInstance = nullptr;
28     sInstanceHasBeenDestroyed = true;
29   }
30   MOZ_ASSERT(!SingletonExists());
31 }
32 
33 bool
SingletonExists()34 gfxPrefs::SingletonExists()
35 {
36   return sInstance != nullptr;
37 }
38 
gfxPrefs()39 gfxPrefs::gfxPrefs()
40 {
41   // UI, content, and plugin processes use XPCOM and should have prefs
42   // ready by the time we initialize gfxPrefs.
43   MOZ_ASSERT_IF(XRE_IsContentProcess() ||
44                 XRE_IsParentProcess() ||
45                 XRE_GetProcessType() == GeckoProcessType_Plugin,
46                 Preferences::IsServiceAvailable());
47 
48   gfxPrefs::AssertMainThread();
49 }
50 
51 void
Init()52 gfxPrefs::Init()
53 {
54   // Set up Moz2D prefs.
55   mPrefGfxLoggingLevel.SetChangeCallback([]() -> void {
56     mozilla::gfx::LoggingPrefs::sGfxLogLevel = GetSingleton().mPrefGfxLoggingLevel.GetLiveValue();
57   });
58 }
59 
~gfxPrefs()60 gfxPrefs::~gfxPrefs()
61 {
62   gfxPrefs::AssertMainThread();
63   mPrefGfxLoggingLevel.SetChangeCallback(nullptr);
64   delete sGfxPrefList;
65   sGfxPrefList = nullptr;
66 }
67 
AssertMainThread()68 void gfxPrefs::AssertMainThread()
69 {
70   MOZ_ASSERT(NS_IsMainThread(), "this code must be run on the main thread");
71 }
72 
73 void
OnChange()74 gfxPrefs::Pref::OnChange()
75 {
76   if (auto gpm = gfx::GPUProcessManager::Get()) {
77     if (gfx::GPUChild* gpu = gpm->GetGPUChild()) {
78       GfxPrefValue value;
79       GetLiveValue(&value);
80       Unused << gpu->SendUpdatePref(gfx::GfxPrefSetting(mIndex, value));
81     }
82   }
83   FireChangeCallback();
84 }
85 
86 void
FireChangeCallback()87 gfxPrefs::Pref::FireChangeCallback()
88 {
89   if (mChangeCallback) {
90     mChangeCallback();
91   }
92 }
93 
94 void
SetChangeCallback(ChangeCallback aCallback)95 gfxPrefs::Pref::SetChangeCallback(ChangeCallback aCallback)
96 {
97   mChangeCallback = aCallback;
98 
99   if (!IsParentProcess() && IsPrefsServiceAvailable()) {
100     // If we're in the parent process, we watch prefs by default so we can
101     // send changes over to the GPU process. Otherwise, we need to add or
102     // remove a watch for the pref now.
103     if (aCallback) {
104       WatchChanges(Name(), this);
105     } else {
106       UnwatchChanges(Name(), this);
107     }
108   }
109 
110   // Fire the callback once to make initialization easier for the caller.
111   FireChangeCallback();
112 }
113 
114 // On lightweight processes such as for GMP and GPU, XPCOM is not initialized,
115 // and therefore we don't have access to Preferences. When XPCOM is not
116 // available we rely on manual synchronization of gfxPrefs values over IPC.
117 /* static */ bool
IsPrefsServiceAvailable()118 gfxPrefs::IsPrefsServiceAvailable()
119 {
120   return Preferences::IsServiceAvailable();
121 }
122 
123 /* static */ bool
IsParentProcess()124 gfxPrefs::IsParentProcess()
125 {
126   return XRE_IsParentProcess();
127 }
128 
PrefAddVarCache(bool * aVariable,const char * aPref,bool aDefault)129 void gfxPrefs::PrefAddVarCache(bool* aVariable,
130                                const char* aPref,
131                                bool aDefault)
132 {
133   MOZ_ASSERT(IsPrefsServiceAvailable());
134   Preferences::AddBoolVarCache(aVariable, aPref, aDefault);
135 }
136 
PrefAddVarCache(int32_t * aVariable,const char * aPref,int32_t aDefault)137 void gfxPrefs::PrefAddVarCache(int32_t* aVariable,
138                                const char* aPref,
139                                int32_t aDefault)
140 {
141   MOZ_ASSERT(IsPrefsServiceAvailable());
142   Preferences::AddIntVarCache(aVariable, aPref, aDefault);
143 }
144 
PrefAddVarCache(uint32_t * aVariable,const char * aPref,uint32_t aDefault)145 void gfxPrefs::PrefAddVarCache(uint32_t* aVariable,
146                                const char* aPref,
147                                uint32_t aDefault)
148 {
149   MOZ_ASSERT(IsPrefsServiceAvailable());
150   Preferences::AddUintVarCache(aVariable, aPref, aDefault);
151 }
152 
PrefAddVarCache(float * aVariable,const char * aPref,float aDefault)153 void gfxPrefs::PrefAddVarCache(float* aVariable,
154                                const char* aPref,
155                                float aDefault)
156 {
157   MOZ_ASSERT(IsPrefsServiceAvailable());
158   Preferences::AddFloatVarCache(aVariable, aPref, aDefault);
159 }
160 
PrefGet(const char * aPref,bool aDefault)161 bool gfxPrefs::PrefGet(const char* aPref, bool aDefault)
162 {
163   MOZ_ASSERT(IsPrefsServiceAvailable());
164   return Preferences::GetBool(aPref, aDefault);
165 }
166 
PrefGet(const char * aPref,int32_t aDefault)167 int32_t gfxPrefs::PrefGet(const char* aPref, int32_t aDefault)
168 {
169   MOZ_ASSERT(IsPrefsServiceAvailable());
170   return Preferences::GetInt(aPref, aDefault);
171 }
172 
PrefGet(const char * aPref,uint32_t aDefault)173 uint32_t gfxPrefs::PrefGet(const char* aPref, uint32_t aDefault)
174 {
175   MOZ_ASSERT(IsPrefsServiceAvailable());
176   return Preferences::GetUint(aPref, aDefault);
177 }
178 
PrefGet(const char * aPref,float aDefault)179 float gfxPrefs::PrefGet(const char* aPref, float aDefault)
180 {
181   MOZ_ASSERT(IsPrefsServiceAvailable());
182   return Preferences::GetFloat(aPref, aDefault);
183 }
184 
PrefSet(const char * aPref,bool aValue)185 void gfxPrefs::PrefSet(const char* aPref, bool aValue)
186 {
187   MOZ_ASSERT(IsPrefsServiceAvailable());
188   Preferences::SetBool(aPref, aValue);
189 }
190 
PrefSet(const char * aPref,int32_t aValue)191 void gfxPrefs::PrefSet(const char* aPref, int32_t aValue)
192 {
193   MOZ_ASSERT(IsPrefsServiceAvailable());
194   Preferences::SetInt(aPref, aValue);
195 }
196 
PrefSet(const char * aPref,uint32_t aValue)197 void gfxPrefs::PrefSet(const char* aPref, uint32_t aValue)
198 {
199   MOZ_ASSERT(IsPrefsServiceAvailable());
200   Preferences::SetUint(aPref, aValue);
201 }
202 
PrefSet(const char * aPref,float aValue)203 void gfxPrefs::PrefSet(const char* aPref, float aValue)
204 {
205   MOZ_ASSERT(IsPrefsServiceAvailable());
206   Preferences::SetFloat(aPref, aValue);
207 }
208 
209 static void
OnGfxPrefChanged(const char * aPrefname,void * aClosure)210 OnGfxPrefChanged(const char* aPrefname, void* aClosure)
211 {
212   reinterpret_cast<gfxPrefs::Pref*>(aClosure)->OnChange();
213 }
214 
WatchChanges(const char * aPrefname,Pref * aPref)215 void gfxPrefs::WatchChanges(const char* aPrefname, Pref* aPref)
216 {
217   MOZ_ASSERT(IsPrefsServiceAvailable());
218   Preferences::RegisterCallback(OnGfxPrefChanged, aPrefname, aPref, Preferences::ExactMatch);
219 }
220 
UnwatchChanges(const char * aPrefname,Pref * aPref)221 void gfxPrefs::UnwatchChanges(const char* aPrefname, Pref* aPref)
222 {
223   // The Preferences service can go offline before gfxPrefs is destroyed.
224   if (IsPrefsServiceAvailable()) {
225     Preferences::UnregisterCallback(OnGfxPrefChanged, aPrefname, aPref, Preferences::ExactMatch);
226   }
227 }
228 
CopyPrefValue(const bool * aValue,GfxPrefValue * aOutValue)229 void gfxPrefs::CopyPrefValue(const bool* aValue, GfxPrefValue* aOutValue)
230 {
231   *aOutValue = *aValue;
232 }
233 
CopyPrefValue(const int32_t * aValue,GfxPrefValue * aOutValue)234 void gfxPrefs::CopyPrefValue(const int32_t* aValue, GfxPrefValue* aOutValue)
235 {
236   *aOutValue = *aValue;
237 }
238 
CopyPrefValue(const uint32_t * aValue,GfxPrefValue * aOutValue)239 void gfxPrefs::CopyPrefValue(const uint32_t* aValue, GfxPrefValue* aOutValue)
240 {
241   *aOutValue = *aValue;
242 }
243 
CopyPrefValue(const float * aValue,GfxPrefValue * aOutValue)244 void gfxPrefs::CopyPrefValue(const float* aValue, GfxPrefValue* aOutValue)
245 {
246   *aOutValue = *aValue;
247 }
248 
CopyPrefValue(const GfxPrefValue * aValue,bool * aOutValue)249 void gfxPrefs::CopyPrefValue(const GfxPrefValue* aValue, bool* aOutValue)
250 {
251   *aOutValue = aValue->get_bool();
252 }
253 
CopyPrefValue(const GfxPrefValue * aValue,int32_t * aOutValue)254 void gfxPrefs::CopyPrefValue(const GfxPrefValue* aValue, int32_t* aOutValue)
255 {
256   *aOutValue = aValue->get_int32_t();
257 }
258 
CopyPrefValue(const GfxPrefValue * aValue,uint32_t * aOutValue)259 void gfxPrefs::CopyPrefValue(const GfxPrefValue* aValue, uint32_t* aOutValue)
260 {
261   *aOutValue = aValue->get_uint32_t();
262 }
263 
CopyPrefValue(const GfxPrefValue * aValue,float * aOutValue)264 void gfxPrefs::CopyPrefValue(const GfxPrefValue* aValue, float* aOutValue)
265 {
266   *aOutValue = aValue->get_float();
267 }
268