Rename about:labs to about:flags, part 3/3

This renames the cc and h files, and renames the --no-labs switch to --no-experiments

BUG=59139
TEST=about:flags still works

Review URL: http://codereview.chromium.org/3777005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62682 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
new file mode 100644
index 0000000..7824dee
--- /dev/null
+++ b/chrome/browser/about_flags.cc
@@ -0,0 +1,327 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/about_flags.h"
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <set>
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/values.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+
+namespace about_flags {
+
+enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 };
+
+unsigned kOsAll = kOsMac | kOsWin | kOsLinux;
+
+struct Experiment {
+  // The internal name of the experiment. This is never shown to the user.
+  // It _is_ however stored in the prefs file, so you shouldn't change the
+  // name of existing flags.
+  const char* internal_name;
+
+  // String id of the message containing the experiment's name.
+  int visible_name_id;
+
+  // String id of the message containing the experiment's description.
+  int visible_description_id;
+
+  // The platforms the experiment is available on
+  // Needs to be more than a compile-time #ifdef because of profile sync.
+  unsigned supported_platforms;  // bitmask
+
+  // The commandline parameter that's added when this lab is active. This is
+  // different from |internal_name| so that the commandline flag can be
+  // renamed without breaking the prefs file.
+  const char* command_line;
+};
+
+const Experiment kExperiments[] = {
+  {
+    "expose-for-tabs",  // Do not change; see above.
+    IDS_FLAGS_TABPOSE_NAME,
+    IDS_FLAGS_TABPOSE_DESCRIPTION,
+    kOsMac,
+#if defined(OS_MACOSX)
+    // The switch exists only on OS X.
+    switches::kEnableExposeForTabs
+#else
+    ""
+#endif
+  },
+  {
+    "vertical-tabs",  // Do not change; see above.
+    IDS_FLAGS_SIDE_TABS_NAME,
+    IDS_FLAGS_SIDE_TABS_DESCRIPTION,
+    kOsWin,
+    switches::kEnableVerticalTabs
+  },
+  {
+    "tabbed-options",  // Do not change; see above.
+    IDS_FLAGS_TABBED_OPTIONS_NAME,
+    IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION,
+    kOsAll,
+    switches::kEnableTabbedOptions
+  },
+  {
+    "remoting",  // Do not change; see above.
+    IDS_FLAGS_REMOTING_NAME,
+#if defined(OS_WIN)
+    // Windows only supports host functionality at the moment.
+    IDS_FLAGS_REMOTING_HOST_DESCRIPTION,
+#elif defined(OS_LINUX)
+    // Linux only supports client functionality at the moment.
+    IDS_FLAGS_REMOTING_CLIENT_DESCRIPTION,
+#else
+    // On other platforms, this lab isn't available at all.
+    0,
+#endif
+    kOsWin | kOsLinux,
+    switches::kEnableRemoting
+  },
+  {
+    "disable-outdated-plugins",  // Do not change; see above.
+    IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME,
+    IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
+    kOsAll,
+    switches::kDisableOutdatedPlugins
+  },
+  {
+    "xss-auditor",  // Do not change; see above.
+    IDS_FLAGS_XSS_AUDITOR_NAME,
+    IDS_FLAGS_XSS_AUDITOR_DESCRIPTION,
+    kOsAll,
+    switches::kEnableXSSAuditor
+  },
+  {
+    "background-webapps", // Do not change; see above
+    IDS_FLAGS_BACKGROUND_WEBAPPS_NAME,
+    IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION,
+    kOsAll,
+    switches::kEnableBackgroundMode
+  },
+  {
+    "cloud-print-proxy", // Do not change; see above.
+    IDS_FLAGS_CLOUD_PRINT_PROXY_NAME,
+    IDS_FLAGS_CLOUD_PRINT_PROXY_DESCRIPTION,
+#if defined(GOOGLE_CHROME_BUILD)
+    // For a Chrome build, we know we have a PDF plug-in, and so we'll
+    // enable by platform as we get things working.
+    0,
+#else
+    // Otherwise, where we know it could be working if a viable PDF
+    // plug-in could be supplied, we'll keep the lab enabled.
+    kOsWin,
+#endif
+    switches::kEnableCloudPrintProxy
+  },
+  {
+    "match-preview",  // Do not change; see above.
+    IDS_FLAGS_INSTANT_NAME,
+    IDS_FLAGS_INSTANT_DESCRIPTION,
+    kOsMac,
+    switches::kEnableMatchPreview
+  },
+  // FIXME(scheib): Add Flags entry for accelerated Compositing,
+  // or pull it and the strings in generated_resources.grd by Dec 2010
+  //{
+  //  "gpu-compositing", // Do not change; see above
+  //  IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
+  //  IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
+  //  kOsAll,
+  //  switches::kDisableAcceleratedCompositing
+  //},
+  {
+    "gpu-canvas-2d", // Do not change; see above
+    IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME,
+    IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION,
+    kOsWin | kOsLinux,
+    switches::kEnableAccelerated2dCanvas
+  },
+  // FIXME(scheib): Add Flags entry for WebGL,
+  // or pull it and the strings in generated_resources.grd by Dec 2010
+  //{
+  //  "webgl", // Do not change; see above
+  //  IDS_FLAGS_WEBGL_NAME,
+  //  IDS_FLAGS_WEBGL_DESCRIPTION,
+  //  kOsAll,
+  //  switches::kDisableExperimentalWebGL
+  //}
+  {
+    "print-preview",  // Do not change; see above
+    IDS_FLAGS_PRINT_PREVIEW_NAME,
+    IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
+    kOsAll,
+    switches::kEnablePrintPreview
+  }
+};
+
+// Extracts the list of enabled lab experiments from preferences and stores them
+// in a set.
+void GetEnabledFlags(const PrefService* prefs, std::set<std::string>* result) {
+  const ListValue* enabled_experiments = prefs->GetList(
+      prefs::kEnabledLabsExperiments);
+  if (!enabled_experiments)
+    return;
+
+  for (ListValue::const_iterator it = enabled_experiments->begin();
+       it != enabled_experiments->end();
+       ++it) {
+    std::string experiment_name;
+    if (!(*it)->GetAsString(&experiment_name)) {
+      LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
+      continue;
+    }
+    result->insert(experiment_name);
+  }
+}
+
+// Takes a set of enabled lab experiments
+void SetEnabledFlags(
+    PrefService* prefs, const std::set<std::string>& enabled_experiments) {
+  ListValue* experiments_list = prefs->GetMutableList(
+      prefs::kEnabledLabsExperiments);
+  if (!experiments_list)
+    return;
+
+  experiments_list->Clear();
+  for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
+       it != enabled_experiments.end();
+       ++it) {
+    experiments_list->Append(new StringValue(*it));
+  }
+}
+
+// Removes all experiments from prefs::kEnabledLabsExperiments that are
+// unknown, to prevent this list to become very long as experiments are added
+// and removed.
+void SanitizeList(PrefService* prefs) {
+  std::set<std::string> known_experiments;
+  for (size_t i = 0; i < arraysize(kExperiments); ++i)
+    known_experiments.insert(kExperiments[i].internal_name);
+
+  std::set<std::string> enabled_experiments;
+  GetEnabledFlags(prefs, &enabled_experiments);
+
+  std::set<std::string> new_enabled_experiments;
+  std::set_intersection(
+      known_experiments.begin(), known_experiments.end(),
+      enabled_experiments.begin(), enabled_experiments.end(),
+      std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
+
+  SetEnabledFlags(prefs, new_enabled_experiments);
+}
+
+void GetSanitizedEnabledFlags(
+    PrefService* prefs, std::set<std::string>* result) {
+  SanitizeList(prefs);
+  GetEnabledFlags(prefs, result);
+}
+
+int GetCurrentPlatform() {
+#if defined(OS_MACOSX)
+  return kOsMac;
+#elif defined(OS_WIN)
+  return kOsWin;
+#elif defined(OS_LINUX)
+  return kOsLinux;
+#else
+#error Unknown platform
+#endif
+}
+
+bool IsEnabled() {
+#if defined(OS_CHROMEOS)
+  // TODO(thakis): Port about:flags to chromeos -- http://crbug.com/57634
+  return false;
+#else
+  return true;
+#endif
+}
+
+void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
+  if (!IsEnabled())
+    return;
+
+  if (command_line->HasSwitch(switches::kNoExperiments))
+    return;
+
+  std::set<std::string> enabled_experiments;
+  GetSanitizedEnabledFlags(prefs, &enabled_experiments);
+
+  std::map<std::string, const Experiment*> experiments;
+  for (size_t i = 0; i < arraysize(kExperiments); ++i)
+    experiments[kExperiments[i].internal_name] = &kExperiments[i];
+
+  for (std::set<std::string>::iterator it = enabled_experiments.begin();
+       it != enabled_experiments.end();
+       ++it) {
+    const std::string& experiment_name = *it;
+    std::map<std::string, const Experiment*>::iterator experiment =
+        experiments.find(experiment_name);
+    DCHECK(experiment != experiments.end());
+    if (experiment == experiments.end())
+      continue;
+
+    command_line->AppendSwitch(experiment->second->command_line);
+  }
+}
+
+ListValue* GetFlagsExperimentsData(PrefService* prefs) {
+  std::set<std::string> enabled_experiments;
+  GetSanitizedEnabledFlags(prefs, &enabled_experiments);
+
+  int current_platform = GetCurrentPlatform();
+
+  ListValue* experiments_data = new ListValue();
+  for (size_t i = 0; i < arraysize(kExperiments); ++i) {
+    const Experiment& experiment = kExperiments[i];
+    if (!(experiment.supported_platforms & current_platform))
+      continue;
+
+    DictionaryValue* data = new DictionaryValue();
+    data->SetString("internal_name", experiment.internal_name);
+    data->SetString("name",
+                    l10n_util::GetStringUTF16(experiment.visible_name_id));
+    data->SetString("description",
+                    l10n_util::GetStringUTF16(
+                        experiment.visible_description_id));
+    data->SetBoolean("enabled",
+                      enabled_experiments.count(experiment.internal_name) > 0);
+
+    experiments_data->Append(data);
+  }
+  return experiments_data;
+}
+
+static bool needs_restart_ = false;
+
+bool IsRestartNeededToCommitChanges() {
+  return needs_restart_;
+}
+
+void SetExperimentEnabled(
+    PrefService* prefs, const std::string& internal_name, bool enable) {
+  needs_restart_ = true;
+
+  std::set<std::string> enabled_experiments;
+  GetSanitizedEnabledFlags(prefs, &enabled_experiments);
+
+  if (enable)
+    enabled_experiments.insert(internal_name);
+  else
+    enabled_experiments.erase(internal_name);
+
+  SetEnabledFlags(prefs, enabled_experiments);
+}
+
+}  // namespace about_flags