Line data Source code
1 : /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set sts=2 ts=8 sw=2 tw=99 et: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "gfxFeature.h"
8 :
9 : #include "mozilla/Preferences.h"
10 : #include "mozilla/Sprintf.h"
11 : #include "nsString.h"
12 :
13 : namespace mozilla {
14 : namespace gfx {
15 :
16 : bool
17 10 : FeatureState::IsEnabled() const
18 : {
19 10 : return IsInitialized() && IsFeatureStatusSuccess(GetValue());
20 : }
21 :
22 : FeatureStatus
23 14 : FeatureState::GetValue() const
24 : {
25 14 : if (!IsInitialized()) {
26 4 : return FeatureStatus::Unused;
27 : }
28 :
29 10 : if (mRuntime.mStatus != FeatureStatus::Unused) {
30 0 : return mRuntime.mStatus;
31 : }
32 10 : if (mUser.mStatus == FeatureStatus::ForceEnabled) {
33 0 : return FeatureStatus::ForceEnabled;
34 : }
35 10 : if (mEnvironment.mStatus != FeatureStatus::Unused) {
36 0 : return mEnvironment.mStatus;
37 : }
38 10 : if (mUser.mStatus != FeatureStatus::Unused) {
39 0 : return mUser.mStatus;
40 : }
41 10 : return mDefault.mStatus;
42 : }
43 :
44 : bool
45 3 : FeatureState::SetDefault(bool aEnable,
46 : FeatureStatus aDisableStatus,
47 : const char* aDisableMessage)
48 : {
49 3 : if (!aEnable) {
50 3 : DisableByDefault(aDisableStatus, aDisableMessage,
51 6 : NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED"));
52 3 : return false;
53 : }
54 0 : EnableByDefault();
55 0 : return true;
56 : }
57 :
58 : void
59 0 : FeatureState::SetDefaultFromPref(const char* aPrefName,
60 : bool aIsEnablePref,
61 : bool aDefaultValue)
62 : {
63 0 : bool baseValue = Preferences::GetDefaultBool(aPrefName, aDefaultValue);
64 0 : SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled, "Disabled by default");
65 :
66 0 : if (Preferences::HasUserValue(aPrefName)) {
67 0 : bool userValue = Preferences::GetBool(aPrefName, aDefaultValue);
68 0 : if (userValue == aIsEnablePref) {
69 0 : nsCString message("Enabled via ");
70 0 : message.AppendASCII(aPrefName);
71 0 : UserEnable(message.get());
72 : } else {
73 0 : nsCString message("Disabled via ");
74 0 : message.AppendASCII(aPrefName);
75 0 : UserDisable(message.get(), NS_LITERAL_CSTRING("FEATURE_FAILURE_PREF_OFF"));
76 : }
77 : }
78 0 : }
79 :
80 : bool
81 0 : FeatureState::InitOrUpdate(bool aEnable,
82 : FeatureStatus aDisableStatus,
83 : const char* aDisableMessage)
84 : {
85 0 : if (!IsInitialized()) {
86 0 : return SetDefault(aEnable, aDisableStatus, aDisableMessage);
87 : }
88 0 : return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage, nsCString());
89 : }
90 :
91 : void
92 0 : FeatureState::UserEnable(const char* aMessage)
93 : {
94 0 : AssertInitialized();
95 0 : SetUser(FeatureStatus::Available, aMessage);
96 0 : }
97 :
98 : void
99 0 : FeatureState::UserForceEnable(const char* aMessage)
100 : {
101 0 : AssertInitialized();
102 0 : SetUser(FeatureStatus::ForceEnabled, aMessage);
103 0 : }
104 :
105 : void
106 0 : FeatureState::UserDisable(const char* aMessage, const nsACString& aFailureId)
107 : {
108 0 : AssertInitialized();
109 0 : SetUser(FeatureStatus::Disabled, aMessage);
110 0 : SetFailureId(aFailureId);
111 0 : }
112 :
113 : void
114 0 : FeatureState::Disable(FeatureStatus aStatus, const char* aMessage,
115 : const nsACString& aFailureId)
116 : {
117 0 : AssertInitialized();
118 :
119 : // We should never bother setting an environment status to "enabled," since
120 : // it could override an explicit user decision to disable it.
121 0 : MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
122 :
123 0 : SetEnvironment(aStatus, aMessage);
124 0 : SetFailureId(aFailureId);
125 0 : }
126 :
127 : void
128 0 : FeatureState::SetFailed(FeatureStatus aStatus, const char* aMessage,
129 : const nsACString& aFailureId)
130 : {
131 0 : AssertInitialized();
132 :
133 : // We should never bother setting a runtime status to "enabled," since it could
134 : // override an explicit user decision to disable it.
135 0 : MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
136 :
137 0 : SetRuntime(aStatus, aMessage);
138 0 : SetFailureId(aFailureId);
139 0 : }
140 :
141 : bool
142 0 : FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage,
143 : const nsACString& aFailureId)
144 : {
145 0 : if (!aEnable) {
146 0 : SetFailed(aStatus, aMessage, aFailureId);
147 0 : return false;
148 : }
149 0 : return true;
150 : }
151 :
152 : bool
153 0 : FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage,
154 : const nsACString& aFailureId)
155 : {
156 0 : return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage,
157 0 : aFailureId);
158 : }
159 :
160 : bool
161 0 : FeatureState::DisabledByDefault() const
162 : {
163 0 : return mDefault.mStatus != FeatureStatus::Available;
164 : }
165 :
166 : bool
167 0 : FeatureState::IsForcedOnByUser() const
168 : {
169 0 : AssertInitialized();
170 0 : return mUser.mStatus == FeatureStatus::ForceEnabled;
171 : }
172 :
173 : void
174 0 : FeatureState::EnableByDefault()
175 : {
176 : // User/runtime decisions should not have been made yet.
177 0 : MOZ_ASSERT(!mUser.IsInitialized());
178 0 : MOZ_ASSERT(!mEnvironment.IsInitialized());
179 0 : MOZ_ASSERT(!mRuntime.IsInitialized());
180 :
181 0 : mDefault.Set(FeatureStatus::Available);
182 0 : }
183 :
184 : void
185 7 : FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage,
186 : const nsACString& aFailureId)
187 : {
188 : // User/runtime decisions should not have been made yet.
189 7 : MOZ_ASSERT(!mUser.IsInitialized());
190 7 : MOZ_ASSERT(!mEnvironment.IsInitialized());
191 7 : MOZ_ASSERT(!mRuntime.IsInitialized());
192 :
193 : // Make sure that when disabling we actually use a failure status.
194 7 : MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
195 :
196 7 : mDefault.Set(aStatus, aMessage);
197 7 : SetFailureId(aFailureId);
198 7 : }
199 :
200 : void
201 0 : FeatureState::SetUser(FeatureStatus aStatus, const char* aMessage)
202 : {
203 : // Default decision must have been made, but not runtime or environment.
204 0 : MOZ_ASSERT(mDefault.IsInitialized());
205 0 : MOZ_ASSERT(!mEnvironment.IsInitialized());
206 0 : MOZ_ASSERT(!mRuntime.IsInitialized());
207 :
208 0 : mUser.Set(aStatus, aMessage);
209 0 : }
210 :
211 : void
212 0 : FeatureState::SetEnvironment(FeatureStatus aStatus, const char* aMessage)
213 : {
214 : // Default decision must have been made, but not runtime.
215 0 : MOZ_ASSERT(mDefault.IsInitialized());
216 0 : MOZ_ASSERT(!mRuntime.IsInitialized());
217 :
218 0 : mEnvironment.Set(aStatus, aMessage);
219 0 : }
220 :
221 : void
222 0 : FeatureState::SetRuntime(FeatureStatus aStatus, const char* aMessage)
223 : {
224 0 : AssertInitialized();
225 :
226 0 : mRuntime.Set(aStatus, aMessage);
227 0 : }
228 :
229 : const char*
230 0 : FeatureState::GetRuntimeMessage() const
231 : {
232 0 : MOZ_ASSERT(IsFeatureStatusFailure(mRuntime.mStatus));
233 0 : return mRuntime.mMessage;
234 : }
235 :
236 : void
237 0 : FeatureState::ForEachStatusChange(const StatusIterCallback& aCallback) const
238 : {
239 0 : AssertInitialized();
240 :
241 0 : aCallback("default", mDefault.mStatus, mDefault.MessageOrNull());
242 0 : if (mUser.IsInitialized()) {
243 0 : aCallback("user", mUser.mStatus, mUser.Message());
244 : }
245 0 : if (mEnvironment.IsInitialized()) {
246 0 : aCallback("env", mEnvironment.mStatus, mEnvironment.Message());
247 : }
248 0 : if (mRuntime.IsInitialized()) {
249 0 : aCallback("runtime", mRuntime.mStatus, mRuntime.Message());
250 : }
251 0 : }
252 :
253 : void
254 7 : FeatureState::SetFailureId(const nsACString& aFailureId)
255 : {
256 7 : if (mFailureId.IsEmpty()) {
257 7 : mFailureId = aFailureId;
258 : }
259 7 : }
260 :
261 : const char*
262 0 : FeatureState::GetFailureMessage() const
263 : {
264 0 : AssertInitialized();
265 0 : MOZ_ASSERT(!IsEnabled());
266 :
267 0 : if (mRuntime.mStatus != FeatureStatus::Unused &&
268 0 : IsFeatureStatusFailure(mRuntime.mStatus))
269 : {
270 0 : return mRuntime.mMessage;
271 : }
272 0 : if (mEnvironment.mStatus != FeatureStatus::Unused &&
273 0 : IsFeatureStatusFailure(mEnvironment.mStatus))
274 : {
275 0 : return mEnvironment.mMessage;
276 : }
277 0 : if (mUser.mStatus != FeatureStatus::Unused &&
278 0 : IsFeatureStatusFailure(mUser.mStatus))
279 : {
280 0 : return mUser.mMessage;
281 : }
282 :
283 0 : MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus));
284 0 : return mDefault.mMessage;
285 : }
286 :
287 : const nsCString&
288 0 : FeatureState::GetFailureId() const
289 : {
290 0 : MOZ_ASSERT(!IsEnabled());
291 0 : return mFailureId;
292 : }
293 :
294 : void
295 0 : FeatureState::Reset()
296 : {
297 0 : mDefault.Set(FeatureStatus::Unused);
298 0 : mUser.Set(FeatureStatus::Unused);
299 0 : mEnvironment.Set(FeatureStatus::Unused);
300 0 : mRuntime.Set(FeatureStatus::Unused);
301 0 : mFailureId = nsCString();
302 0 : }
303 :
304 : void
305 7 : FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage /* = nullptr */)
306 : {
307 7 : mStatus = aStatus;
308 7 : if (aMessage) {
309 7 : SprintfLiteral(mMessage, "%s", aMessage);
310 : } else {
311 0 : mMessage[0] = '\0';
312 : }
313 7 : }
314 :
315 : } // namespace gfx
316 : } // namespace mozilla
|