blob: 82ede785a82f34c1bb330395f946af2e9465556f [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
5#include "chrome/browser/labs.h"
6
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"
14#include "base/values.h"
[email protected]ad2a3ded2010-08-27 13:19:0515#include "chrome/browser/prefs/pref_service.h"
[email protected]ad2a3ded2010-08-27 13:19:0516#include "chrome/common/chrome_switches.h"
17#include "chrome/common/pref_names.h"
18#include "grit/generated_resources.h"
19
20namespace about_labs {
21
22enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 };
23
[email protected]654151872010-09-13 22:43:0524unsigned kOsAll = kOsMac | kOsWin | kOsLinux;
25
[email protected]ad2a3ded2010-08-27 13:19:0526struct Experiment {
27 // The internal name of the experiment. This is never shown to the user.
28 // It _is_ however stored in the prefs file, so you shouldn't change the
29 // name of existing labs.
30 const char* internal_name;
31
32 // String id of the message containing the experiment's name.
33 int visible_name_id;
34
35 // String id of the message containing the experiment's description.
36 int visible_description_id;
37
38 // The platforms the experiment is available on
39 // Needs to be more than a compile-time #ifdef because of profile sync.
40 unsigned supported_platforms; // bitmask
41
42 // The commandline parameter that's added when this lab is active. This is
43 // different from |internal_name| so that the commandline flag can be
44 // renamed without breaking the prefs file.
45 const char* command_line;
46};
47
48const Experiment kExperiments[] = {
49 {
[email protected]232448fb2010-08-27 18:48:2450 "expose-for-tabs", // Do not change; see above.
[email protected]ad2a3ded2010-08-27 13:19:0551 IDS_LABS_TABPOSE_NAME,
52 IDS_LABS_TABPOSE_DESCRIPTION,
53 kOsMac,
54#if defined(OS_MACOSX)
55 // The switch exists only on OS X.
56 switches::kEnableExposeForTabs
57#else
58 ""
59#endif
60 },
61 {
[email protected]232448fb2010-08-27 18:48:2462 "vertical-tabs", // Do not change; see above.
63 IDS_LABS_SIDE_TABS_NAME,
64 IDS_LABS_SIDE_TABS_DESCRIPTION,
[email protected]ad2a3ded2010-08-27 13:19:0565 kOsWin,
66 switches::kEnableVerticalTabs
[email protected]654151872010-09-13 22:43:0567 },
68 {
69 "tabbed-options", // Do not change; see above.
70 IDS_LABS_TABBED_OPTIONS_NAME,
71 IDS_LABS_TABBED_OPTIONS_DESCRIPTION,
72 kOsAll,
73 switches::kEnableTabbedOptions
74 },
[email protected]bcf91672010-09-16 15:40:2175 {
[email protected]52fa2d52010-09-25 14:08:5676 "remoting", // Do not change; see above.
77 IDS_LABS_REMOTING_NAME,
[email protected]4fb2f1192010-09-25 14:56:3178#if defined(OS_WIN)
[email protected]52fa2d52010-09-25 14:08:5679 // Windows only supports host functionality at the moment.
80 IDS_LABS_REMOTING_HOST_DESCRIPTION,
81#elif defined(OS_LINUX)
82 // Linux only supports client functionality at the moment.
83 IDS_LABS_REMOTING_CLIENT_DESCRIPTION,
84#else
[email protected]a6940852010-09-25 14:25:3285 // On other platforms, this lab isn't available at all.
86 0,
[email protected]52fa2d52010-09-25 14:08:5687#endif
88 kOsWin | kOsLinux,
89 switches::kEnableRemoting
90 },
[email protected]a6f03652010-09-28 15:59:0791 {
[email protected]57b66d02010-09-30 11:24:5192 "disable-outdated-plugins", // Do not change; see above.
93 IDS_LABS_DISABLE_OUTDATED_PLUGINS_NAME,
94 IDS_LABS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
95 kOsAll,
96 switches::kDisableOutdatedPlugins
97 },
[email protected]b3ce30ea2010-10-01 09:33:5398 {
99 "xss-auditor", // Do not change; see above.
100 IDS_LABS_XSS_AUDITOR_NAME,
101 IDS_LABS_XSS_AUDITOR_DESCRIPTION,
102 kOsAll,
103 switches::kEnableXSSAuditor
104 },
[email protected]aea2ff42010-10-04 18:04:19105 {
106 "background-webapps", // Do not change; see above
107 IDS_LABS_BACKGROUND_WEBAPPS_NAME,
108 IDS_LABS_BACKGROUND_WEBAPPS_DESCRIPTION,
109 kOsAll,
110 switches::kEnableBackgroundMode
[email protected]7bee0b22010-10-05 17:00:47111 },
112 {
113 "cloud-print-proxy", // Do not change; see above.
114 IDS_LABS_CLOUD_PRINT_PROXY_NAME,
115 IDS_LABS_CLOUD_PRINT_PROXY_DESCRIPTION,
[email protected]65736d42010-10-08 16:47:58116#if defined(GOOGLE_CHROME_BUILD)
117 // For a Chrome build, we know we have a PDF plug-in, and so we'll
118 // enable by platform as we get things working.
119 0,
120#else
121 // Otherwise, where we know it could be working if a viable PDF
122 // plug-in could be supplied, we'll keep the lab enabled.
[email protected]7bee0b22010-10-05 17:00:47123 kOsWin,
[email protected]65736d42010-10-08 16:47:58124#endif
[email protected]7bee0b22010-10-05 17:00:47125 switches::kEnableCloudPrintProxy
[email protected]8b6588a2010-10-12 02:39:42126 },
[email protected]580939a2010-10-12 18:54:37127 {
128 "match-preview", // Do not change; see above.
129 IDS_LABS_INSTANT_NAME,
130 IDS_LABS_INSTANT_DESCRIPTION,
131 kOsMac,
132 switches::kEnableMatchPreview
133 },
[email protected]8b6588a2010-10-12 02:39:42134 // FIXME(scheib): Add Labs entry for accelerated Compositing,
135 // or pull it and the strings in generated_resources.grd by Dec 2010
136 //{
137 // "gpu-compositing", // Do not change; see above
138 // IDS_LABS_ACCELERATED_COMPOSITING_NAME,
139 // IDS_LABS_ACCELERATED_COMPOSITING_DESCRIPTION,
140 // kOsAll,
141 // switches::kDisableAcceleratedCompositing
142 //},
143 {
144 "gpu-canvas-2d", // Do not change; see above
145 IDS_LABS_ACCELERATED_CANVAS_2D_NAME,
146 IDS_LABS_ACCELERATED_CANVAS_2D_DESCRIPTION,
147 kOsWin | kOsLinux,
148 switches::kEnableAccelerated2dCanvas
[email protected]aea2ff42010-10-04 18:04:19149 }
[email protected]8b6588a2010-10-12 02:39:42150 // FIXME(scheib): Add Labs entry for WebGL,
151 // or pull it and the strings in generated_resources.grd by Dec 2010
152 //{
153 // "webgl", // Do not change; see above
154 // IDS_LABS_WEBGL_NAME,
155 // IDS_LABS_WEBGL_DESCRIPTION,
156 // kOsAll,
157 // switches::kDisableExperimentalWebGL
158 //}
[email protected]ad2a3ded2010-08-27 13:19:05159};
160
[email protected]c7b7800a2010-10-07 18:51:35161// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05162// in a set.
163void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) {
164 const ListValue* enabled_experiments = prefs->GetList(
165 prefs::kEnabledLabsExperiments);
166 if (!enabled_experiments)
167 return;
168
169 for (ListValue::const_iterator it = enabled_experiments->begin();
170 it != enabled_experiments->end();
171 ++it) {
172 std::string experiment_name;
173 if (!(*it)->GetAsString(&experiment_name)) {
174 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
175 continue;
176 }
177 result->insert(experiment_name);
178 }
179}
180
181// Takes a set of enabled lab experiments
182void SetEnabledLabs(
183 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
184 ListValue* experiments_list = prefs->GetMutableList(
185 prefs::kEnabledLabsExperiments);
186 if (!experiments_list)
187 return;
188
189 experiments_list->Clear();
190 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
191 it != enabled_experiments.end();
192 ++it) {
193 experiments_list->Append(new StringValue(*it));
194 }
195}
196
197// Removes all experiments from prefs::kEnabledLabsExperiments that are
198// unknown, to prevent this list to become very long as experiments are added
199// and removed.
200void SanitizeList(PrefService* prefs) {
201 std::set<std::string> known_experiments;
202 for (size_t i = 0; i < arraysize(kExperiments); ++i)
203 known_experiments.insert(kExperiments[i].internal_name);
204
205 std::set<std::string> enabled_experiments;
206 GetEnabledLabs(prefs, &enabled_experiments);
207
208 std::set<std::string> new_enabled_experiments;
209 std::set_intersection(
210 known_experiments.begin(), known_experiments.end(),
211 enabled_experiments.begin(), enabled_experiments.end(),
212 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
213
214 SetEnabledLabs(prefs, new_enabled_experiments);
215}
216
217void GetSanitizedEnabledLabs(
218 PrefService* prefs, std::set<std::string>* result) {
219 SanitizeList(prefs);
220 GetEnabledLabs(prefs, result);
221}
222
223int GetCurrentPlatform() {
224#if defined(OS_MACOSX)
225 return kOsMac;
226#elif defined(OS_WIN)
227 return kOsWin;
228#elif defined(OS_LINUX)
229 return kOsLinux;
230#else
231#error Unknown platform
232#endif
233}
234
235bool IsEnabled() {
236#if defined(OS_CHROMEOS)
237 // ChromeOS uses a different mechanism for about:labs; integrated with their
238 // dom ui options.
[email protected]9bbf9702010-10-02 00:25:38239 // TODO(thakis): Port about:labs to chromeos -- http://crbug.com/57634
[email protected]ad2a3ded2010-08-27 13:19:05240 return false;
[email protected]ad2a3ded2010-08-27 13:19:05241#else
242 return true;
243#endif
244}
245
[email protected]c7b7800a2010-10-07 18:51:35246void ConvertLabsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]ad2a3ded2010-08-27 13:19:05247 if (!IsEnabled())
248 return;
249
250 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35251 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05252
253 std::map<std::string, const Experiment*> experiments;
254 for (size_t i = 0; i < arraysize(kExperiments); ++i)
255 experiments[kExperiments[i].internal_name] = &kExperiments[i];
256
257 for (std::set<std::string>::iterator it = enabled_experiments.begin();
258 it != enabled_experiments.end();
259 ++it) {
260 const std::string& experiment_name = *it;
261 std::map<std::string, const Experiment*>::iterator experiment =
262 experiments.find(experiment_name);
263 DCHECK(experiment != experiments.end());
264 if (experiment == experiments.end())
265 continue;
266
267 command_line->AppendSwitch(experiment->second->command_line);
268 }
269}
270
[email protected]c7b7800a2010-10-07 18:51:35271ListValue* GetLabsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05272 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35273 GetSanitizedEnabledLabs(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
298static bool needs_restart_ = false;
299
300bool IsRestartNeededToCommitChanges() {
301 return needs_restart_;
302}
303
304void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35305 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05306 needs_restart_ = true;
307
308 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35309 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05310
311 if (enable)
312 enabled_experiments.insert(internal_name);
313 else
314 enabled_experiments.erase(internal_name);
315
[email protected]c7b7800a2010-10-07 18:51:35316 SetEnabledLabs(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05317}
318
319} // namespace Labs