gecko-dev/gfx/config/gfxFeature.cpp
Kartikaya Gupta cf9ed9dbea Bug 1342520 - Make sure when setting the default feature state to disabled, it's set to an actual failure status. r=dvander
MozReview-Commit-ID: 3KxC5oQg1wL

--HG--
extra : rebase_source : a4ee0a3a50770de6a8dc1829d42a5e46da9b40ff
2017-02-24 15:43:33 -05:00

317 lines
7.8 KiB
C++

/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sts=2 ts=8 sw=2 tw=99 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxFeature.h"
#include "mozilla/Preferences.h"
#include "mozilla/Sprintf.h"
#include "nsString.h"
namespace mozilla {
namespace gfx {
bool
FeatureState::IsEnabled() const
{
return IsInitialized() && IsFeatureStatusSuccess(GetValue());
}
FeatureStatus
FeatureState::GetValue() const
{
if (!IsInitialized()) {
return FeatureStatus::Unused;
}
if (mRuntime.mStatus != FeatureStatus::Unused) {
return mRuntime.mStatus;
}
if (mUser.mStatus == FeatureStatus::ForceEnabled) {
return FeatureStatus::ForceEnabled;
}
if (mEnvironment.mStatus != FeatureStatus::Unused) {
return mEnvironment.mStatus;
}
if (mUser.mStatus != FeatureStatus::Unused) {
return mUser.mStatus;
}
return mDefault.mStatus;
}
bool
FeatureState::SetDefault(bool aEnable,
FeatureStatus aDisableStatus,
const char* aDisableMessage)
{
if (!aEnable) {
DisableByDefault(aDisableStatus, aDisableMessage,
NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED"));
return false;
}
EnableByDefault();
return true;
}
void
FeatureState::SetDefaultFromPref(const char* aPrefName,
bool aIsEnablePref,
bool aDefaultValue)
{
bool baseValue = Preferences::GetDefaultBool(aPrefName, aDefaultValue);
SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled, "Disabled by default");
if (Preferences::HasUserValue(aPrefName)) {
bool userValue = Preferences::GetBool(aPrefName, aDefaultValue);
if (userValue == aIsEnablePref) {
nsCString message("Enabled via ");
message.AppendASCII(aPrefName);
UserEnable(message.get());
} else {
nsCString message("Disabled via ");
message.AppendASCII(aPrefName);
UserDisable(message.get(), NS_LITERAL_CSTRING("FEATURE_FAILURE_PREF_OFF"));
}
}
}
bool
FeatureState::InitOrUpdate(bool aEnable,
FeatureStatus aDisableStatus,
const char* aDisableMessage)
{
if (!IsInitialized()) {
return SetDefault(aEnable, aDisableStatus, aDisableMessage);
}
return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage, nsCString());
}
void
FeatureState::UserEnable(const char* aMessage)
{
AssertInitialized();
SetUser(FeatureStatus::Available, aMessage);
}
void
FeatureState::UserForceEnable(const char* aMessage)
{
AssertInitialized();
SetUser(FeatureStatus::ForceEnabled, aMessage);
}
void
FeatureState::UserDisable(const char* aMessage, const nsACString& aFailureId)
{
AssertInitialized();
SetUser(FeatureStatus::Disabled, aMessage);
SetFailureId(aFailureId);
}
void
FeatureState::Disable(FeatureStatus aStatus, const char* aMessage,
const nsACString& aFailureId)
{
AssertInitialized();
// We should never bother setting an environment status to "enabled," since
// it could override an explicit user decision to disable it.
MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
SetEnvironment(aStatus, aMessage);
SetFailureId(aFailureId);
}
void
FeatureState::SetFailed(FeatureStatus aStatus, const char* aMessage,
const nsACString& aFailureId)
{
AssertInitialized();
// We should never bother setting a runtime status to "enabled," since it could
// override an explicit user decision to disable it.
MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
SetRuntime(aStatus, aMessage);
SetFailureId(aFailureId);
}
bool
FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage,
const nsACString& aFailureId)
{
if (!aEnable) {
SetFailed(aStatus, aMessage, aFailureId);
return false;
}
return true;
}
bool
FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage,
const nsACString& aFailureId)
{
return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage,
aFailureId);
}
bool
FeatureState::DisabledByDefault() const
{
return mDefault.mStatus != FeatureStatus::Available;
}
bool
FeatureState::IsForcedOnByUser() const
{
AssertInitialized();
return mUser.mStatus == FeatureStatus::ForceEnabled;
}
void
FeatureState::EnableByDefault()
{
// User/runtime decisions should not have been made yet.
MOZ_ASSERT(!mUser.IsInitialized());
MOZ_ASSERT(!mEnvironment.IsInitialized());
MOZ_ASSERT(!mRuntime.IsInitialized());
mDefault.Set(FeatureStatus::Available);
}
void
FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage,
const nsACString& aFailureId)
{
// User/runtime decisions should not have been made yet.
MOZ_ASSERT(!mUser.IsInitialized());
MOZ_ASSERT(!mEnvironment.IsInitialized());
MOZ_ASSERT(!mRuntime.IsInitialized());
// Make sure that when disabling we actually use a failure status.
MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
mDefault.Set(aStatus, aMessage);
SetFailureId(aFailureId);
}
void
FeatureState::SetUser(FeatureStatus aStatus, const char* aMessage)
{
// Default decision must have been made, but not runtime or environment.
MOZ_ASSERT(mDefault.IsInitialized());
MOZ_ASSERT(!mEnvironment.IsInitialized());
MOZ_ASSERT(!mRuntime.IsInitialized());
mUser.Set(aStatus, aMessage);
}
void
FeatureState::SetEnvironment(FeatureStatus aStatus, const char* aMessage)
{
// Default decision must have been made, but not runtime.
MOZ_ASSERT(mDefault.IsInitialized());
MOZ_ASSERT(!mRuntime.IsInitialized());
mEnvironment.Set(aStatus, aMessage);
}
void
FeatureState::SetRuntime(FeatureStatus aStatus, const char* aMessage)
{
AssertInitialized();
mRuntime.Set(aStatus, aMessage);
}
const char*
FeatureState::GetRuntimeMessage() const
{
MOZ_ASSERT(IsFeatureStatusFailure(mRuntime.mStatus));
return mRuntime.mMessage;
}
void
FeatureState::ForEachStatusChange(const StatusIterCallback& aCallback) const
{
AssertInitialized();
aCallback("default", mDefault.mStatus, mDefault.MessageOrNull());
if (mUser.IsInitialized()) {
aCallback("user", mUser.mStatus, mUser.Message());
}
if (mEnvironment.IsInitialized()) {
aCallback("env", mEnvironment.mStatus, mEnvironment.Message());
}
if (mRuntime.IsInitialized()) {
aCallback("runtime", mRuntime.mStatus, mRuntime.Message());
}
}
void
FeatureState::SetFailureId(const nsACString& aFailureId)
{
if (mFailureId.IsEmpty()) {
mFailureId = aFailureId;
}
}
const char*
FeatureState::GetFailureMessage() const
{
AssertInitialized();
MOZ_ASSERT(!IsEnabled());
if (mRuntime.mStatus != FeatureStatus::Unused &&
IsFeatureStatusFailure(mRuntime.mStatus))
{
return mRuntime.mMessage;
}
if (mEnvironment.mStatus != FeatureStatus::Unused &&
IsFeatureStatusFailure(mEnvironment.mStatus))
{
return mEnvironment.mMessage;
}
if (mUser.mStatus != FeatureStatus::Unused &&
IsFeatureStatusFailure(mUser.mStatus))
{
return mUser.mMessage;
}
MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus));
return mDefault.mMessage;
}
const nsCString&
FeatureState::GetFailureId() const
{
MOZ_ASSERT(!IsEnabled());
return mFailureId;
}
void
FeatureState::Reset()
{
mDefault.Set(FeatureStatus::Unused);
mUser.Set(FeatureStatus::Unused);
mEnvironment.Set(FeatureStatus::Unused);
mRuntime.Set(FeatureStatus::Unused);
mFailureId = nsCString();
}
void
FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage /* = nullptr */)
{
mStatus = aStatus;
if (aMessage) {
SprintfLiteral(mMessage, "%s", aMessage);
} else {
mMessage[0] = '\0';
}
}
} // namespace gfx
} // namespace mozilla