gfxFeature.cpp (9694B)
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/. */ 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 FeatureState::IsEnabled() const { 17 return IsInitialized() && IsFeatureStatusSuccess(GetValue()); 18 } 19 20 FeatureStatus FeatureState::GetValue() const { 21 if (!IsInitialized()) { 22 return FeatureStatus::Unused; 23 } 24 25 if (mRuntime.mStatus != FeatureStatus::Unused) { 26 return mRuntime.mStatus; 27 } 28 if (mUser.mStatus == FeatureStatus::ForceEnabled) { 29 return FeatureStatus::ForceEnabled; 30 } 31 if (mEnvironment.mStatus != FeatureStatus::Unused) { 32 return mEnvironment.mStatus; 33 } 34 if (mUser.mStatus != FeatureStatus::Unused) { 35 return mUser.mStatus; 36 } 37 return mDefault.mStatus; 38 } 39 40 bool FeatureState::SetDefault(bool aEnable, FeatureStatus aDisableStatus, 41 const char* aDisableMessage) { 42 if (!aEnable) { 43 DisableByDefault(aDisableStatus, aDisableMessage, 44 "FEATURE_FAILURE_DISABLED"_ns); 45 return false; 46 } 47 EnableByDefault(); 48 return true; 49 } 50 51 void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref, 52 bool aDefaultValue, 53 Maybe<bool> aUserValue) { 54 bool baseValue = 55 Preferences::GetBool(aPrefName, aDefaultValue, PrefValueKind::Default); 56 SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled, 57 "Disabled by default"); 58 59 if (aUserValue) { 60 if (*aUserValue == aIsEnablePref) { 61 nsCString message("Enabled via "); 62 message.AppendASCII(aPrefName); 63 UserEnable(message.get()); 64 } else { 65 nsCString message("Disabled via "); 66 message.AppendASCII(aPrefName); 67 UserDisable(message.get(), "FEATURE_FAILURE_PREF_OFF"_ns); 68 } 69 } 70 } 71 72 void FeatureState::SetDefaultFromPref(const char* aPrefName, bool aIsEnablePref, 73 bool aDefaultValue) { 74 Maybe<bool> userValue; 75 if (Preferences::HasUserValue(aPrefName)) { 76 userValue.emplace(Preferences::GetBool(aPrefName, aDefaultValue)); 77 } 78 79 SetDefaultFromPref(aPrefName, aIsEnablePref, aDefaultValue, userValue); 80 } 81 82 bool FeatureState::InitOrUpdate(bool aEnable, FeatureStatus aDisableStatus, 83 const char* aDisableMessage) { 84 if (!IsInitialized()) { 85 return SetDefault(aEnable, aDisableStatus, aDisableMessage); 86 } 87 return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage, nsCString()); 88 } 89 90 void FeatureState::UserEnable(const char* aMessage) { 91 AssertInitialized(); 92 SetUser(FeatureStatus::Available, aMessage, nsCString()); 93 } 94 95 void FeatureState::UserForceEnable(const char* aMessage) { 96 AssertInitialized(); 97 SetUser(FeatureStatus::ForceEnabled, aMessage, nsCString()); 98 } 99 100 void FeatureState::UserDisable(const char* aMessage, 101 const nsACString& aFailureId) { 102 AssertInitialized(); 103 SetUser(FeatureStatus::Disabled, aMessage, aFailureId); 104 } 105 106 void FeatureState::Disable(FeatureStatus aStatus, const char* aMessage, 107 const nsACString& aFailureId) { 108 AssertInitialized(); 109 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)); 113 114 SetEnvironment(aStatus, aMessage, aFailureId); 115 } 116 117 void FeatureState::SetFailed(FeatureStatus aStatus, const char* aMessage, 118 const nsACString& aFailureId) { 119 AssertInitialized(); 120 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)); 124 125 SetRuntime(aStatus, aMessage, aFailureId); 126 } 127 128 bool FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus, 129 const char* aMessage, 130 const nsACString& aFailureId) { 131 if (!aEnable) { 132 SetFailed(aStatus, aMessage, aFailureId); 133 return false; 134 } 135 return true; 136 } 137 138 bool FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage, 139 const nsACString& aFailureId) { 140 return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage, 141 aFailureId); 142 } 143 144 bool FeatureState::DisabledByDefault() const { 145 return mDefault.mStatus != FeatureStatus::Available; 146 } 147 148 bool FeatureState::IsForcedOnByUser() const { 149 AssertInitialized(); 150 return mUser.mStatus == FeatureStatus::ForceEnabled; 151 } 152 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()); 158 159 mDefault.Set(FeatureStatus::Available); 160 } 161 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()); 168 169 // Make sure that when disabling we actually use a failure status. 170 MOZ_ASSERT(IsFeatureStatusFailure(aStatus)); 171 172 mDefault.Set(aStatus, aMessage, aFailureId); 173 } 174 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()); 181 182 mUser.Set(aStatus, aMessage, aFailureId); 183 } 184 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()); 190 191 mEnvironment.Set(aStatus, aMessage, aFailureId); 192 } 193 194 void FeatureState::SetRuntime(FeatureStatus aStatus, const char* aMessage, 195 const nsACString& aFailureId) { 196 AssertInitialized(); 197 198 mRuntime.Set(aStatus, aMessage, aFailureId); 199 } 200 201 const char* FeatureState::GetRuntimeMessage() const { 202 MOZ_ASSERT(IsFeatureStatusFailure(mRuntime.mStatus)); 203 return mRuntime.mMessage; 204 } 205 206 void FeatureState::ForEachStatusChange( 207 const StatusIterCallback& aCallback) const { 208 AssertInitialized(); 209 210 aCallback("default", mDefault.mStatus, mDefault.MessageOrNull(), 211 mDefault.FailureId()); 212 if (mUser.IsInitialized()) { 213 aCallback("user", mUser.mStatus, mUser.Message(), mUser.FailureId()); 214 } 215 if (mEnvironment.IsInitialized()) { 216 aCallback("env", mEnvironment.mStatus, mEnvironment.Message(), 217 mEnvironment.FailureId()); 218 } 219 if (mRuntime.IsInitialized()) { 220 aCallback("runtime", mRuntime.mStatus, mRuntime.Message(), 221 mRuntime.FailureId()); 222 } 223 } 224 225 const char* FeatureState::GetFailureMessage() const { 226 AssertInitialized(); 227 MOZ_ASSERT(!IsEnabled()); 228 229 if (mRuntime.mStatus != FeatureStatus::Unused && 230 IsFeatureStatusFailure(mRuntime.mStatus)) { 231 return mRuntime.mMessage; 232 } 233 if (mEnvironment.mStatus != FeatureStatus::Unused && 234 IsFeatureStatusFailure(mEnvironment.mStatus)) { 235 return mEnvironment.mMessage; 236 } 237 if (mUser.mStatus != FeatureStatus::Unused && 238 IsFeatureStatusFailure(mUser.mStatus)) { 239 return mUser.mMessage; 240 } 241 242 MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus)); 243 return mDefault.mMessage; 244 } 245 246 const nsCString& FeatureState::GetFailureId() const { 247 MOZ_ASSERT(!IsEnabled()); 248 249 if (mRuntime.mStatus != FeatureStatus::Unused) { 250 return mRuntime.mFailureId; 251 } 252 if (mEnvironment.mStatus != FeatureStatus::Unused) { 253 return mEnvironment.mFailureId; 254 } 255 if (mUser.mStatus != FeatureStatus::Unused) { 256 return mUser.mFailureId; 257 } 258 259 return mDefault.mFailureId; 260 } 261 262 nsCString FeatureState::GetStatusAndFailureIdString() const { 263 nsCString status; 264 auto value = GetValue(); 265 switch (value) { 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()); 273 break; 274 case FeatureStatus::Failed: 275 status.AppendPrintf("%s:%s", FeatureStatusToString(value), 276 GetFailureMessage()); 277 break; 278 default: 279 status.Append(FeatureStatusToString(value)); 280 break; 281 } 282 283 return status; 284 } 285 286 void FeatureState::Reset() { 287 mDefault.Set(FeatureStatus::Unused); 288 mUser.Set(FeatureStatus::Unused); 289 mEnvironment.Set(FeatureStatus::Unused); 290 mRuntime.Set(FeatureStatus::Unused); 291 } 292 293 void FeatureState::Instance::Set(FeatureStatus aStatus) { 294 mStatus = aStatus; 295 mMessage[0] = '\0'; 296 mFailureId.Truncate(); 297 } 298 299 void FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage, 300 const nsACString& aFailureId) { 301 mStatus = aStatus; 302 if (aMessage) { 303 SprintfLiteral(mMessage, "%s", aMessage); 304 } else { 305 mMessage[0] = '\0'; 306 } 307 mFailureId.Assign(aFailureId); 308 } 309 310 } // namespace gfx 311 } // namespace mozilla