1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "gfxFeature.h"
9 #include "mozilla/Preferences.h"
10 #include "mozilla/Sprintf.h"
16 bool FeatureState::IsEnabled() const {
17 return IsInitialized() && IsFeatureStatusSuccess(GetValue());
20 FeatureStatus
FeatureState::GetValue() const {
21 if (!IsInitialized()) {
22 return FeatureStatus::Unused
;
25 if (mRuntime
.mStatus
!= FeatureStatus::Unused
) {
26 return mRuntime
.mStatus
;
28 if (mUser
.mStatus
== FeatureStatus::ForceEnabled
) {
29 return FeatureStatus::ForceEnabled
;
31 if (mEnvironment
.mStatus
!= FeatureStatus::Unused
) {
32 return mEnvironment
.mStatus
;
34 if (mUser
.mStatus
!= FeatureStatus::Unused
) {
37 return mDefault
.mStatus
;
40 bool FeatureState::SetDefault(bool aEnable
, FeatureStatus aDisableStatus
,
41 const char* aDisableMessage
) {
43 DisableByDefault(aDisableStatus
, aDisableMessage
,
44 "FEATURE_FAILURE_DISABLED"_ns
);
51 void FeatureState::SetDefaultFromPref(const char* aPrefName
, bool aIsEnablePref
,
53 Maybe
<bool> aUserValue
) {
55 Preferences::GetBool(aPrefName
, aDefaultValue
, PrefValueKind::Default
);
56 SetDefault(baseValue
== aIsEnablePref
, FeatureStatus::Disabled
,
57 "Disabled by default");
60 if (*aUserValue
== aIsEnablePref
) {
61 nsCString
message("Enabled via ");
62 message
.AppendASCII(aPrefName
);
63 UserEnable(message
.get());
65 nsCString
message("Disabled via ");
66 message
.AppendASCII(aPrefName
);
67 UserDisable(message
.get(), "FEATURE_FAILURE_PREF_OFF"_ns
);
72 void FeatureState::SetDefaultFromPref(const char* aPrefName
, bool aIsEnablePref
,
74 Maybe
<bool> userValue
;
75 if (Preferences::HasUserValue(aPrefName
)) {
76 userValue
.emplace(Preferences::GetBool(aPrefName
, aDefaultValue
));
79 SetDefaultFromPref(aPrefName
, aIsEnablePref
, aDefaultValue
, userValue
);
82 bool FeatureState::InitOrUpdate(bool aEnable
, FeatureStatus aDisableStatus
,
83 const char* aDisableMessage
) {
84 if (!IsInitialized()) {
85 return SetDefault(aEnable
, aDisableStatus
, aDisableMessage
);
87 return MaybeSetFailed(aEnable
, aDisableStatus
, aDisableMessage
, nsCString());
90 void FeatureState::UserEnable(const char* aMessage
) {
92 SetUser(FeatureStatus::Available
, aMessage
, nsCString());
95 void FeatureState::UserForceEnable(const char* aMessage
) {
97 SetUser(FeatureStatus::ForceEnabled
, aMessage
, nsCString());
100 void FeatureState::UserDisable(const char* aMessage
,
101 const nsACString
& aFailureId
) {
103 SetUser(FeatureStatus::Disabled
, aMessage
, aFailureId
);
106 void FeatureState::Disable(FeatureStatus aStatus
, const char* aMessage
,
107 const nsACString
& aFailureId
) {
110 // We should never bother setting an environment status to "enabled," since
111 // it could override an explicit user decision to disable it.
112 MOZ_ASSERT(IsFeatureStatusFailure(aStatus
));
114 SetEnvironment(aStatus
, aMessage
, aFailureId
);
117 void FeatureState::SetFailed(FeatureStatus aStatus
, const char* aMessage
,
118 const nsACString
& aFailureId
) {
121 // We should never bother setting a runtime status to "enabled," since it
122 // could override an explicit user decision to disable it.
123 MOZ_ASSERT(IsFeatureStatusFailure(aStatus
));
125 SetRuntime(aStatus
, aMessage
, aFailureId
);
128 bool FeatureState::MaybeSetFailed(bool aEnable
, FeatureStatus aStatus
,
129 const char* aMessage
,
130 const nsACString
& aFailureId
) {
132 SetFailed(aStatus
, aMessage
, aFailureId
);
138 bool FeatureState::MaybeSetFailed(FeatureStatus aStatus
, const char* aMessage
,
139 const nsACString
& aFailureId
) {
140 return MaybeSetFailed(IsFeatureStatusSuccess(aStatus
), aStatus
, aMessage
,
144 bool FeatureState::DisabledByDefault() const {
145 return mDefault
.mStatus
!= FeatureStatus::Available
;
148 bool FeatureState::IsForcedOnByUser() const {
150 return mUser
.mStatus
== FeatureStatus::ForceEnabled
;
153 void FeatureState::EnableByDefault() {
154 // User/runtime decisions should not have been made yet.
155 MOZ_ASSERT(!mUser
.IsInitialized());
156 MOZ_ASSERT(!mEnvironment
.IsInitialized());
157 MOZ_ASSERT(!mRuntime
.IsInitialized());
159 mDefault
.Set(FeatureStatus::Available
);
162 void FeatureState::DisableByDefault(FeatureStatus aStatus
, const char* aMessage
,
163 const nsACString
& aFailureId
) {
164 // User/runtime decisions should not have been made yet.
165 MOZ_ASSERT(!mUser
.IsInitialized());
166 MOZ_ASSERT(!mEnvironment
.IsInitialized());
167 MOZ_ASSERT(!mRuntime
.IsInitialized());
169 // Make sure that when disabling we actually use a failure status.
170 MOZ_ASSERT(IsFeatureStatusFailure(aStatus
));
172 mDefault
.Set(aStatus
, aMessage
, aFailureId
);
175 void FeatureState::SetUser(FeatureStatus aStatus
, const char* aMessage
,
176 const nsACString
& aFailureId
) {
177 // Default decision must have been made, but not runtime or environment.
178 MOZ_ASSERT(mDefault
.IsInitialized());
179 MOZ_ASSERT(!mEnvironment
.IsInitialized());
180 MOZ_ASSERT(!mRuntime
.IsInitialized());
182 mUser
.Set(aStatus
, aMessage
, aFailureId
);
185 void FeatureState::SetEnvironment(FeatureStatus aStatus
, const char* aMessage
,
186 const nsACString
& aFailureId
) {
187 // Default decision must have been made, but not runtime.
188 MOZ_ASSERT(mDefault
.IsInitialized());
189 MOZ_ASSERT(!mRuntime
.IsInitialized());
191 mEnvironment
.Set(aStatus
, aMessage
, aFailureId
);
194 void FeatureState::SetRuntime(FeatureStatus aStatus
, const char* aMessage
,
195 const nsACString
& aFailureId
) {
198 mRuntime
.Set(aStatus
, aMessage
, aFailureId
);
201 const char* FeatureState::GetRuntimeMessage() const {
202 MOZ_ASSERT(IsFeatureStatusFailure(mRuntime
.mStatus
));
203 return mRuntime
.mMessage
;
206 void FeatureState::ForEachStatusChange(
207 const StatusIterCallback
& aCallback
) const {
210 aCallback("default", mDefault
.mStatus
, mDefault
.MessageOrNull(),
211 mDefault
.FailureId());
212 if (mUser
.IsInitialized()) {
213 aCallback("user", mUser
.mStatus
, mUser
.Message(), mUser
.FailureId());
215 if (mEnvironment
.IsInitialized()) {
216 aCallback("env", mEnvironment
.mStatus
, mEnvironment
.Message(),
217 mEnvironment
.FailureId());
219 if (mRuntime
.IsInitialized()) {
220 aCallback("runtime", mRuntime
.mStatus
, mRuntime
.Message(),
221 mRuntime
.FailureId());
225 const char* FeatureState::GetFailureMessage() const {
227 MOZ_ASSERT(!IsEnabled());
229 if (mRuntime
.mStatus
!= FeatureStatus::Unused
&&
230 IsFeatureStatusFailure(mRuntime
.mStatus
)) {
231 return mRuntime
.mMessage
;
233 if (mEnvironment
.mStatus
!= FeatureStatus::Unused
&&
234 IsFeatureStatusFailure(mEnvironment
.mStatus
)) {
235 return mEnvironment
.mMessage
;
237 if (mUser
.mStatus
!= FeatureStatus::Unused
&&
238 IsFeatureStatusFailure(mUser
.mStatus
)) {
239 return mUser
.mMessage
;
242 MOZ_ASSERT(IsFeatureStatusFailure(mDefault
.mStatus
));
243 return mDefault
.mMessage
;
246 const nsCString
& FeatureState::GetFailureId() const {
247 MOZ_ASSERT(!IsEnabled());
249 if (mRuntime
.mStatus
!= FeatureStatus::Unused
) {
250 return mRuntime
.mFailureId
;
252 if (mEnvironment
.mStatus
!= FeatureStatus::Unused
) {
253 return mEnvironment
.mFailureId
;
255 if (mUser
.mStatus
!= FeatureStatus::Unused
) {
256 return mUser
.mFailureId
;
259 return mDefault
.mFailureId
;
262 nsCString
FeatureState::GetStatusAndFailureIdString() const {
264 auto value
= GetValue();
266 case FeatureStatus::Blocklisted
:
267 case FeatureStatus::Disabled
:
268 case FeatureStatus::Unavailable
:
269 case FeatureStatus::UnavailableNoAngle
:
270 case FeatureStatus::Blocked
:
271 status
.AppendPrintf("%s:%s", FeatureStatusToString(value
),
272 GetFailureId().get());
274 case FeatureStatus::Failed
:
275 status
.AppendPrintf("%s:%s", FeatureStatusToString(value
),
276 GetFailureMessage());
279 status
.Append(FeatureStatusToString(value
));
286 void FeatureState::Reset() {
287 mDefault
.Set(FeatureStatus::Unused
);
288 mUser
.Set(FeatureStatus::Unused
);
289 mEnvironment
.Set(FeatureStatus::Unused
);
290 mRuntime
.Set(FeatureStatus::Unused
);
293 void FeatureState::Instance::Set(FeatureStatus aStatus
) {
296 mFailureId
.Truncate();
299 void FeatureState::Instance::Set(FeatureStatus aStatus
, const char* aMessage
,
300 const nsACString
& aFailureId
) {
303 SprintfLiteral(mMessage
, "%s", aMessage
);
307 mFailureId
.Assign(aFailureId
);
311 } // namespace mozilla