blob: 51671091f184308d2f182fd3a61036ef5e5894a9 [file] [log] [blame]
[email protected]ad2a3ded2010-08-27 13:19:051// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]1a47d7e2010-10-15 00:37:245#include "chrome/browser/about_flags.h"
[email protected]ad2a3ded2010-08-27 13:19:056
7#include <algorithm>
8#include <iterator>
9#include <map>
10#include <set>
11
12#include "app/l10n_util.h"
13#include "base/command_line.h"
[email protected]e2ddbc92010-10-15 20:02:0714#include "base/singleton.h"
[email protected]ad2a3ded2010-08-27 13:19:0515#include "base/values.h"
[email protected]ad2a3ded2010-08-27 13:19:0516#include "chrome/browser/prefs/pref_service.h"
[email protected]ad2a3ded2010-08-27 13:19:0517#include "chrome/common/chrome_switches.h"
18#include "chrome/common/pref_names.h"
19#include "grit/generated_resources.h"
20
[email protected]1a47d7e2010-10-15 00:37:2421namespace about_flags {
[email protected]ad2a3ded2010-08-27 13:19:0522
[email protected]e2ddbc92010-10-15 20:02:0723namespace {
24
[email protected]1af1dfe2010-10-19 23:49:1425enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 , kOsCrOS = 1 << 3 };
[email protected]ad2a3ded2010-08-27 13:19:0526
[email protected]1af1dfe2010-10-19 23:49:1427unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS;
[email protected]654151872010-09-13 22:43:0528
[email protected]ad2a3ded2010-08-27 13:19:0529struct Experiment {
30 // The internal name of the experiment. This is never shown to the user.
31 // It _is_ however stored in the prefs file, so you shouldn't change the
[email protected]1a47d7e2010-10-15 00:37:2432 // name of existing flags.
[email protected]ad2a3ded2010-08-27 13:19:0533 const char* internal_name;
34
35 // String id of the message containing the experiment's name.
36 int visible_name_id;
37
38 // String id of the message containing the experiment's description.
39 int visible_description_id;
40
41 // The platforms the experiment is available on
42 // Needs to be more than a compile-time #ifdef because of profile sync.
43 unsigned supported_platforms; // bitmask
44
45 // The commandline parameter that's added when this lab is active. This is
46 // different from |internal_name| so that the commandline flag can be
47 // renamed without breaking the prefs file.
48 const char* command_line;
49};
50
51const Experiment kExperiments[] = {
52 {
[email protected]232448fb2010-08-27 18:48:2453 "expose-for-tabs", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1254 IDS_FLAGS_TABPOSE_NAME,
55 IDS_FLAGS_TABPOSE_DESCRIPTION,
[email protected]ad2a3ded2010-08-27 13:19:0556 kOsMac,
57#if defined(OS_MACOSX)
58 // The switch exists only on OS X.
59 switches::kEnableExposeForTabs
60#else
61 ""
62#endif
63 },
64 {
[email protected]232448fb2010-08-27 18:48:2465 "vertical-tabs", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1266 IDS_FLAGS_SIDE_TABS_NAME,
67 IDS_FLAGS_SIDE_TABS_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1468 // TODO(thakis): Move sidetabs to about:flags on ChromeOS
69 // http://crbug.com/57634
[email protected]ad2a3ded2010-08-27 13:19:0570 kOsWin,
71 switches::kEnableVerticalTabs
[email protected]654151872010-09-13 22:43:0572 },
73 {
74 "tabbed-options", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1275 IDS_FLAGS_TABBED_OPTIONS_NAME,
76 IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1477 kOsWin | kOsLinux | kOsMac, // Enabled by default on CrOS.
[email protected]654151872010-09-13 22:43:0578 switches::kEnableTabbedOptions
79 },
[email protected]bcf91672010-09-16 15:40:2180 {
[email protected]52fa2d52010-09-25 14:08:5681 "remoting", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1282 IDS_FLAGS_REMOTING_NAME,
[email protected]4fb2f1192010-09-25 14:56:3183#if defined(OS_WIN)
[email protected]52fa2d52010-09-25 14:08:5684 // Windows only supports host functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1285 IDS_FLAGS_REMOTING_HOST_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:1486#elif defined(OS_LINUX) // Also true for CrOS.
[email protected]52fa2d52010-09-25 14:08:5687 // Linux only supports client functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1288 IDS_FLAGS_REMOTING_CLIENT_DESCRIPTION,
[email protected]52fa2d52010-09-25 14:08:5689#else
[email protected]a6940852010-09-25 14:25:3290 // On other platforms, this lab isn't available at all.
91 0,
[email protected]52fa2d52010-09-25 14:08:5692#endif
[email protected]1af1dfe2010-10-19 23:49:1493 kOsWin | kOsLinux | kOsCrOS,
[email protected]52fa2d52010-09-25 14:08:5694 switches::kEnableRemoting
95 },
[email protected]a6f03652010-09-28 15:59:0796 {
[email protected]57b66d02010-09-30 11:24:5197 "disable-outdated-plugins", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:1298 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME,
99 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
[email protected]57b66d02010-09-30 11:24:51100 kOsAll,
101 switches::kDisableOutdatedPlugins
102 },
[email protected]b3ce30ea2010-10-01 09:33:53103 {
104 "xss-auditor", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12105 IDS_FLAGS_XSS_AUDITOR_NAME,
106 IDS_FLAGS_XSS_AUDITOR_DESCRIPTION,
[email protected]b3ce30ea2010-10-01 09:33:53107 kOsAll,
108 switches::kEnableXSSAuditor
109 },
[email protected]aea2ff42010-10-04 18:04:19110 {
111 "background-webapps", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12112 IDS_FLAGS_BACKGROUND_WEBAPPS_NAME,
113 IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION,
[email protected]aea2ff42010-10-04 18:04:19114 kOsAll,
115 switches::kEnableBackgroundMode
[email protected]7bee0b22010-10-05 17:00:47116 },
117 {
118 "cloud-print-proxy", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12119 IDS_FLAGS_CLOUD_PRINT_PROXY_NAME,
120 IDS_FLAGS_CLOUD_PRINT_PROXY_DESCRIPTION,
[email protected]7bee0b22010-10-05 17:00:47121 kOsWin,
[email protected]7bee0b22010-10-05 17:00:47122 switches::kEnableCloudPrintProxy
[email protected]8b6588a2010-10-12 02:39:42123 },
[email protected]580939a2010-10-12 18:54:37124 {
125 "match-preview", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12126 IDS_FLAGS_INSTANT_NAME,
127 IDS_FLAGS_INSTANT_DESCRIPTION,
[email protected]580939a2010-10-12 18:54:37128 kOsMac,
129 switches::kEnableMatchPreview
130 },
[email protected]1a47d7e2010-10-15 00:37:24131 // FIXME(scheib): Add Flags entry for accelerated Compositing,
[email protected]8b6588a2010-10-12 02:39:42132 // or pull it and the strings in generated_resources.grd by Dec 2010
133 //{
134 // "gpu-compositing", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12135 // IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
136 // IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42137 // kOsAll,
138 // switches::kDisableAcceleratedCompositing
139 //},
140 {
141 "gpu-canvas-2d", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12142 IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME,
143 IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION,
[email protected]1af1dfe2010-10-19 23:49:14144 kOsWin | kOsLinux | kOsCrOS,
[email protected]8b6588a2010-10-12 02:39:42145 switches::kEnableAccelerated2dCanvas
[email protected]8d260e52010-10-13 01:03:05146 },
[email protected]1a47d7e2010-10-15 00:37:24147 // FIXME(scheib): Add Flags entry for WebGL,
[email protected]8b6588a2010-10-12 02:39:42148 // or pull it and the strings in generated_resources.grd by Dec 2010
149 //{
150 // "webgl", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12151 // IDS_FLAGS_WEBGL_NAME,
152 // IDS_FLAGS_WEBGL_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42153 // kOsAll,
154 // switches::kDisableExperimentalWebGL
155 //}
[email protected]8d260e52010-10-13 01:03:05156 {
157 "print-preview", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12158 IDS_FLAGS_PRINT_PREVIEW_NAME,
159 IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
[email protected]8d260e52010-10-13 01:03:05160 kOsAll,
161 switches::kEnablePrintPreview
162 }
[email protected]ad2a3ded2010-08-27 13:19:05163};
164
[email protected]e2ddbc92010-10-15 20:02:07165// Stores and encapsulates the little state that about:flags has.
166class FlagsState {
167 public:
168 FlagsState() : needs_restart_(false) {}
169 void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line);
170 bool IsRestartNeededToCommitChanges();
171 void SetExperimentEnabled(
172 PrefService* prefs, const std::string& internal_name, bool enable);
173 void RemoveFlagsSwitches(
174 std::map<std::string, CommandLine::StringType>* switch_list);
175 void reset();
176
177 // Returns the singleton instance of this class
178 static FlagsState* instance() {
179 return Singleton<FlagsState>::get();
180 }
181
182 private:
183 bool needs_restart_;
184 std::set<std::string> flags_switches_;
185
186 DISALLOW_COPY_AND_ASSIGN(FlagsState);
187};
188
[email protected]c7b7800a2010-10-07 18:51:35189// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05190// in a set.
[email protected]1a47d7e2010-10-15 00:37:24191void GetEnabledFlags(const PrefService* prefs, std::set<std::string>* result) {
[email protected]ad2a3ded2010-08-27 13:19:05192 const ListValue* enabled_experiments = prefs->GetList(
193 prefs::kEnabledLabsExperiments);
194 if (!enabled_experiments)
195 return;
196
197 for (ListValue::const_iterator it = enabled_experiments->begin();
198 it != enabled_experiments->end();
199 ++it) {
200 std::string experiment_name;
201 if (!(*it)->GetAsString(&experiment_name)) {
202 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
203 continue;
204 }
205 result->insert(experiment_name);
206 }
207}
208
209// Takes a set of enabled lab experiments
[email protected]1a47d7e2010-10-15 00:37:24210void SetEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05211 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
212 ListValue* experiments_list = prefs->GetMutableList(
213 prefs::kEnabledLabsExperiments);
214 if (!experiments_list)
215 return;
216
217 experiments_list->Clear();
218 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
219 it != enabled_experiments.end();
220 ++it) {
221 experiments_list->Append(new StringValue(*it));
222 }
223}
224
225// Removes all experiments from prefs::kEnabledLabsExperiments that are
226// unknown, to prevent this list to become very long as experiments are added
227// and removed.
228void SanitizeList(PrefService* prefs) {
229 std::set<std::string> known_experiments;
230 for (size_t i = 0; i < arraysize(kExperiments); ++i)
231 known_experiments.insert(kExperiments[i].internal_name);
232
233 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24234 GetEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05235
236 std::set<std::string> new_enabled_experiments;
237 std::set_intersection(
238 known_experiments.begin(), known_experiments.end(),
239 enabled_experiments.begin(), enabled_experiments.end(),
240 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
241
[email protected]1a47d7e2010-10-15 00:37:24242 SetEnabledFlags(prefs, new_enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05243}
244
[email protected]1a47d7e2010-10-15 00:37:24245void GetSanitizedEnabledFlags(
[email protected]ad2a3ded2010-08-27 13:19:05246 PrefService* prefs, std::set<std::string>* result) {
247 SanitizeList(prefs);
[email protected]1a47d7e2010-10-15 00:37:24248 GetEnabledFlags(prefs, result);
[email protected]ad2a3ded2010-08-27 13:19:05249}
250
251int GetCurrentPlatform() {
252#if defined(OS_MACOSX)
253 return kOsMac;
254#elif defined(OS_WIN)
255 return kOsWin;
[email protected]1af1dfe2010-10-19 23:49:14256#elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check.
257 return kOsCrOS;
[email protected]ad2a3ded2010-08-27 13:19:05258#elif defined(OS_LINUX)
259 return kOsLinux;
260#else
261#error Unknown platform
262#endif
263}
264
[email protected]e2ddbc92010-10-15 20:02:07265} // namespace
266
[email protected]1a47d7e2010-10-15 00:37:24267void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07268 FlagsState::instance()->ConvertFlagsToSwitches(prefs, command_line);
[email protected]ad2a3ded2010-08-27 13:19:05269}
270
[email protected]1a47d7e2010-10-15 00:37:24271ListValue* GetFlagsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05272 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24273 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05274
275 int current_platform = GetCurrentPlatform();
276
277 ListValue* experiments_data = new ListValue();
278 for (size_t i = 0; i < arraysize(kExperiments); ++i) {
279 const Experiment& experiment = kExperiments[i];
280 if (!(experiment.supported_platforms & current_platform))
281 continue;
282
283 DictionaryValue* data = new DictionaryValue();
284 data->SetString("internal_name", experiment.internal_name);
285 data->SetString("name",
286 l10n_util::GetStringUTF16(experiment.visible_name_id));
287 data->SetString("description",
288 l10n_util::GetStringUTF16(
289 experiment.visible_description_id));
290 data->SetBoolean("enabled",
291 enabled_experiments.count(experiment.internal_name) > 0);
292
293 experiments_data->Append(data);
294 }
295 return experiments_data;
296}
297
[email protected]ad2a3ded2010-08-27 13:19:05298bool IsRestartNeededToCommitChanges() {
[email protected]e2ddbc92010-10-15 20:02:07299 return FlagsState::instance()->IsRestartNeededToCommitChanges();
[email protected]ad2a3ded2010-08-27 13:19:05300}
301
302void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35303 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]e2ddbc92010-10-15 20:02:07304 FlagsState::instance()->SetExperimentEnabled(prefs, internal_name, enable);
305}
306
307void RemoveFlagsSwitches(
308 std::map<std::string, CommandLine::StringType>* switch_list) {
309 FlagsState::instance()->RemoveFlagsSwitches(switch_list);
310}
311
312//////////////////////////////////////////////////////////////////////////////
313// FlagsState implementation.
314
315namespace {
316
317void FlagsState::ConvertFlagsToSwitches(
318 PrefService* prefs, CommandLine* command_line) {
[email protected]e2ddbc92010-10-15 20:02:07319 if (command_line->HasSwitch(switches::kNoExperiments))
320 return;
321
322 std::set<std::string> enabled_experiments;
323 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
324
325 std::map<std::string, const Experiment*> experiments;
326 for (size_t i = 0; i < arraysize(kExperiments); ++i)
327 experiments[kExperiments[i].internal_name] = &kExperiments[i];
328
329 command_line->AppendSwitch(switches::kFlagSwitchesBegin);
330 flags_switches_.insert(switches::kFlagSwitchesBegin);
331 for (std::set<std::string>::iterator it = enabled_experiments.begin();
332 it != enabled_experiments.end();
333 ++it) {
334 const std::string& experiment_name = *it;
335 std::map<std::string, const Experiment*>::iterator experiment =
336 experiments.find(experiment_name);
337 DCHECK(experiment != experiments.end());
338 if (experiment == experiments.end())
339 continue;
340
341 command_line->AppendSwitch(experiment->second->command_line);
342 flags_switches_.insert(experiment->second->command_line);
343 }
344 command_line->AppendSwitch(switches::kFlagSwitchesEnd);
345 flags_switches_.insert(switches::kFlagSwitchesEnd);
346}
347
348bool FlagsState::IsRestartNeededToCommitChanges() {
349 return needs_restart_;
350}
351
352void FlagsState::SetExperimentEnabled(
353 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05354 needs_restart_ = true;
355
356 std::set<std::string> enabled_experiments;
[email protected]1a47d7e2010-10-15 00:37:24357 GetSanitizedEnabledFlags(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05358
359 if (enable)
360 enabled_experiments.insert(internal_name);
361 else
362 enabled_experiments.erase(internal_name);
363
[email protected]1a47d7e2010-10-15 00:37:24364 SetEnabledFlags(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05365}
366
[email protected]e2ddbc92010-10-15 20:02:07367void FlagsState::RemoveFlagsSwitches(
368 std::map<std::string, CommandLine::StringType>* switch_list) {
369 for (std::set<std::string>::const_iterator it = flags_switches_.begin();
370 it != flags_switches_.end();
371 ++it) {
372 switch_list->erase(*it);
373 }
374}
375
376void FlagsState::reset() {
377 needs_restart_ = false;
378 flags_switches_.clear();
379}
380
381} // namespace
382
383namespace testing {
384void ClearState() {
385 FlagsState::instance()->reset();
386}
387} // namespace testing
388
[email protected]1a47d7e2010-10-15 00:37:24389} // namespace about_flags