blob: d9fb7c569402568499ce555a10928417b3b3dd09 [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]9486c1f2010-10-14 19:52:1251 IDS_FLAGS_TABPOSE_NAME,
52 IDS_FLAGS_TABPOSE_DESCRIPTION,
[email protected]ad2a3ded2010-08-27 13:19:0553 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.
[email protected]9486c1f2010-10-14 19:52:1263 IDS_FLAGS_SIDE_TABS_NAME,
64 IDS_FLAGS_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.
[email protected]9486c1f2010-10-14 19:52:1270 IDS_FLAGS_TABBED_OPTIONS_NAME,
71 IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION,
[email protected]654151872010-09-13 22:43:0572 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.
[email protected]9486c1f2010-10-14 19:52:1277 IDS_FLAGS_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.
[email protected]9486c1f2010-10-14 19:52:1280 IDS_FLAGS_REMOTING_HOST_DESCRIPTION,
[email protected]52fa2d52010-09-25 14:08:5681#elif defined(OS_LINUX)
82 // Linux only supports client functionality at the moment.
[email protected]9486c1f2010-10-14 19:52:1283 IDS_FLAGS_REMOTING_CLIENT_DESCRIPTION,
[email protected]52fa2d52010-09-25 14:08:5684#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.
[email protected]9486c1f2010-10-14 19:52:1293 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME,
94 IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
[email protected]57b66d02010-09-30 11:24:5195 kOsAll,
96 switches::kDisableOutdatedPlugins
97 },
[email protected]b3ce30ea2010-10-01 09:33:5398 {
99 "xss-auditor", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12100 IDS_FLAGS_XSS_AUDITOR_NAME,
101 IDS_FLAGS_XSS_AUDITOR_DESCRIPTION,
[email protected]b3ce30ea2010-10-01 09:33:53102 kOsAll,
103 switches::kEnableXSSAuditor
104 },
[email protected]aea2ff42010-10-04 18:04:19105 {
106 "background-webapps", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12107 IDS_FLAGS_BACKGROUND_WEBAPPS_NAME,
108 IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION,
[email protected]aea2ff42010-10-04 18:04:19109 kOsAll,
110 switches::kEnableBackgroundMode
[email protected]7bee0b22010-10-05 17:00:47111 },
112 {
113 "cloud-print-proxy", // Do not change; see above.
[email protected]9486c1f2010-10-14 19:52:12114 IDS_FLAGS_CLOUD_PRINT_PROXY_NAME,
115 IDS_FLAGS_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.
[email protected]9486c1f2010-10-14 19:52:12129 IDS_FLAGS_INSTANT_NAME,
130 IDS_FLAGS_INSTANT_DESCRIPTION,
[email protected]580939a2010-10-12 18:54:37131 kOsMac,
132 switches::kEnableMatchPreview
133 },
[email protected]8d260e52010-10-13 01:03:05134 // FIXME(scheib): Add Labs entry for accelerated Compositing,
[email protected]8b6588a2010-10-12 02:39:42135 // or pull it and the strings in generated_resources.grd by Dec 2010
136 //{
137 // "gpu-compositing", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12138 // IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
139 // IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42140 // kOsAll,
141 // switches::kDisableAcceleratedCompositing
142 //},
143 {
144 "gpu-canvas-2d", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12145 IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME,
146 IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42147 kOsWin | kOsLinux,
148 switches::kEnableAccelerated2dCanvas
[email protected]8d260e52010-10-13 01:03:05149 },
[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
[email protected]9486c1f2010-10-14 19:52:12154 // IDS_FLAGS_WEBGL_NAME,
155 // IDS_FLAGS_WEBGL_DESCRIPTION,
[email protected]8b6588a2010-10-12 02:39:42156 // kOsAll,
157 // switches::kDisableExperimentalWebGL
158 //}
[email protected]8d260e52010-10-13 01:03:05159 {
160 "print-preview", // Do not change; see above
[email protected]9486c1f2010-10-14 19:52:12161 IDS_FLAGS_PRINT_PREVIEW_NAME,
162 IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
[email protected]8d260e52010-10-13 01:03:05163 kOsAll,
164 switches::kEnablePrintPreview
165 }
[email protected]ad2a3ded2010-08-27 13:19:05166};
167
[email protected]c7b7800a2010-10-07 18:51:35168// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05169// in a set.
170void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) {
171 const ListValue* enabled_experiments = prefs->GetList(
172 prefs::kEnabledLabsExperiments);
173 if (!enabled_experiments)
174 return;
175
176 for (ListValue::const_iterator it = enabled_experiments->begin();
177 it != enabled_experiments->end();
178 ++it) {
179 std::string experiment_name;
180 if (!(*it)->GetAsString(&experiment_name)) {
181 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
182 continue;
183 }
184 result->insert(experiment_name);
185 }
186}
187
188// Takes a set of enabled lab experiments
189void SetEnabledLabs(
190 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
191 ListValue* experiments_list = prefs->GetMutableList(
192 prefs::kEnabledLabsExperiments);
193 if (!experiments_list)
194 return;
195
196 experiments_list->Clear();
197 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
198 it != enabled_experiments.end();
199 ++it) {
200 experiments_list->Append(new StringValue(*it));
201 }
202}
203
204// Removes all experiments from prefs::kEnabledLabsExperiments that are
205// unknown, to prevent this list to become very long as experiments are added
206// and removed.
207void SanitizeList(PrefService* prefs) {
208 std::set<std::string> known_experiments;
209 for (size_t i = 0; i < arraysize(kExperiments); ++i)
210 known_experiments.insert(kExperiments[i].internal_name);
211
212 std::set<std::string> enabled_experiments;
213 GetEnabledLabs(prefs, &enabled_experiments);
214
215 std::set<std::string> new_enabled_experiments;
216 std::set_intersection(
217 known_experiments.begin(), known_experiments.end(),
218 enabled_experiments.begin(), enabled_experiments.end(),
219 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
220
221 SetEnabledLabs(prefs, new_enabled_experiments);
222}
223
224void GetSanitizedEnabledLabs(
225 PrefService* prefs, std::set<std::string>* result) {
226 SanitizeList(prefs);
227 GetEnabledLabs(prefs, result);
228}
229
230int GetCurrentPlatform() {
231#if defined(OS_MACOSX)
232 return kOsMac;
233#elif defined(OS_WIN)
234 return kOsWin;
235#elif defined(OS_LINUX)
236 return kOsLinux;
237#else
238#error Unknown platform
239#endif
240}
241
242bool IsEnabled() {
243#if defined(OS_CHROMEOS)
244 // ChromeOS uses a different mechanism for about:labs; integrated with their
245 // dom ui options.
[email protected]9bbf9702010-10-02 00:25:38246 // TODO(thakis): Port about:labs to chromeos -- http://crbug.com/57634
[email protected]ad2a3ded2010-08-27 13:19:05247 return false;
[email protected]ad2a3ded2010-08-27 13:19:05248#else
249 return true;
250#endif
251}
252
[email protected]c7b7800a2010-10-07 18:51:35253void ConvertLabsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]ad2a3ded2010-08-27 13:19:05254 if (!IsEnabled())
255 return;
256
[email protected]f04f73a2010-10-13 00:54:58257 if (command_line->HasSwitch(switches::kNoLabs))
258 return;
259
[email protected]ad2a3ded2010-08-27 13:19:05260 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35261 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05262
263 std::map<std::string, const Experiment*> experiments;
264 for (size_t i = 0; i < arraysize(kExperiments); ++i)
265 experiments[kExperiments[i].internal_name] = &kExperiments[i];
266
267 for (std::set<std::string>::iterator it = enabled_experiments.begin();
268 it != enabled_experiments.end();
269 ++it) {
270 const std::string& experiment_name = *it;
271 std::map<std::string, const Experiment*>::iterator experiment =
272 experiments.find(experiment_name);
273 DCHECK(experiment != experiments.end());
274 if (experiment == experiments.end())
275 continue;
276
277 command_line->AppendSwitch(experiment->second->command_line);
278 }
279}
280
[email protected]c7b7800a2010-10-07 18:51:35281ListValue* GetLabsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05282 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35283 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05284
285 int current_platform = GetCurrentPlatform();
286
287 ListValue* experiments_data = new ListValue();
288 for (size_t i = 0; i < arraysize(kExperiments); ++i) {
289 const Experiment& experiment = kExperiments[i];
290 if (!(experiment.supported_platforms & current_platform))
291 continue;
292
293 DictionaryValue* data = new DictionaryValue();
294 data->SetString("internal_name", experiment.internal_name);
295 data->SetString("name",
296 l10n_util::GetStringUTF16(experiment.visible_name_id));
297 data->SetString("description",
298 l10n_util::GetStringUTF16(
299 experiment.visible_description_id));
300 data->SetBoolean("enabled",
301 enabled_experiments.count(experiment.internal_name) > 0);
302
303 experiments_data->Append(data);
304 }
305 return experiments_data;
306}
307
308static bool needs_restart_ = false;
309
310bool IsRestartNeededToCommitChanges() {
311 return needs_restart_;
312}
313
314void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35315 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05316 needs_restart_ = true;
317
318 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35319 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05320
321 if (enable)
322 enabled_experiments.insert(internal_name);
323 else
324 enabled_experiments.erase(internal_name);
325
[email protected]c7b7800a2010-10-07 18:51:35326 SetEnabledLabs(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05327}
328
329} // namespace Labs