about_flags.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1// Copyright (c) 2012 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/about_flags.h"
6
7#include <algorithm>
8#include <iterator>
9#include <map>
10#include <set>
11#include <utility>
12
13#include "ash/ash_switches.h"
14#include "base/command_line.h"
15#include "base/memory/singleton.h"
16#include "base/strings/string_number_conversions.h"
17#include "base/strings/utf_string_conversions.h"
18#include "base/values.h"
19#include "cc/base/switches.h"
20#include "chrome/browser/flags_storage.h"
21#include "chrome/common/chrome_content_client.h"
22#include "chrome/common/chrome_switches.h"
23#include "components/nacl/common/nacl_switches.h"
24#include "content/public/browser/user_metrics.h"
25#include "extensions/common/switches.h"
26#include "grit/chromium_strings.h"
27#include "grit/generated_resources.h"
28#include "grit/google_chrome_strings.h"
29#include "media/base/media_switches.h"
30#include "ui/base/l10n/l10n_util.h"
31#include "ui/base/ui_base_switches.h"
32#include "ui/compositor/compositor_switches.h"
33#include "ui/events/event_switches.h"
34#include "ui/gfx/switches.h"
35#include "ui/gl/gl_switches.h"
36#include "ui/keyboard/keyboard_switches.h"
37#include "ui/message_center/message_center_switches.h"
38#include "ui/surface/surface_switches.h"
39
40#if defined(USE_ASH)
41#include "ash/ash_switches.h"
42#endif
43
44#if defined(OS_CHROMEOS)
45#include "chromeos/chromeos_switches.h"
46#include "third_party/cros_system_api/switches/chrome_switches.h"
47#endif
48
49using content::UserMetricsAction;
50
51namespace about_flags {
52
53// Macros to simplify specifying the type.
54#define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \
55    Experiment::SINGLE_VALUE, \
56    command_line_switch, switch_value, NULL, NULL, NULL, 0
57#define SINGLE_VALUE_TYPE(command_line_switch) \
58    SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
59#define ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, enable_value, \
60                                            disable_switch, disable_value) \
61    Experiment::ENABLE_DISABLE_VALUE, enable_switch, enable_value, \
62    disable_switch, disable_value, NULL, 3
63#define ENABLE_DISABLE_VALUE_TYPE(enable_switch, disable_switch) \
64    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, "", disable_switch, "")
65#define MULTI_VALUE_TYPE(choices) \
66    Experiment::MULTI_VALUE, NULL, NULL, NULL, NULL, choices, arraysize(choices)
67
68namespace {
69
70const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid;
71const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS;
72
73// Adds a |StringValue| to |list| for each platform where |bitmask| indicates
74// whether the experiment is available on that platform.
75void AddOsStrings(unsigned bitmask, ListValue* list) {
76  struct {
77    unsigned bit;
78    const char* const name;
79  } kBitsToOs[] = {
80    {kOsMac, "Mac"},
81    {kOsWin, "Windows"},
82    {kOsLinux, "Linux"},
83    {kOsCrOS, "Chrome OS"},
84    {kOsAndroid, "Android"},
85    {kOsCrOSOwnerOnly, "Chrome OS (owner only)"},
86  };
87  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kBitsToOs); ++i)
88    if (bitmask & kBitsToOs[i].bit)
89      list->Append(new StringValue(kBitsToOs[i].name));
90}
91
92// Convert switch constants to proper CommandLine::StringType strings.
93CommandLine::StringType GetSwitchString(const std::string& flag) {
94  CommandLine cmd_line(CommandLine::NO_PROGRAM);
95  cmd_line.AppendSwitch(flag);
96  DCHECK(cmd_line.argv().size() == 2);
97  return cmd_line.argv()[1];
98}
99
100// Scoops flags from a command line.
101std::set<CommandLine::StringType> ExtractFlagsFromCommandLine(
102    const CommandLine& cmdline) {
103  std::set<CommandLine::StringType> flags;
104  // First do the ones between --flag-switches-begin and --flag-switches-end.
105  CommandLine::StringVector::const_iterator first =
106      std::find(cmdline.argv().begin(), cmdline.argv().end(),
107                GetSwitchString(switches::kFlagSwitchesBegin));
108  CommandLine::StringVector::const_iterator last =
109      std::find(cmdline.argv().begin(), cmdline.argv().end(),
110                GetSwitchString(switches::kFlagSwitchesEnd));
111  if (first != cmdline.argv().end() && last != cmdline.argv().end())
112    flags.insert(first + 1, last);
113#if defined(OS_CHROMEOS)
114  // Then add those between --policy-switches-begin and --policy-switches-end.
115  first = std::find(cmdline.argv().begin(), cmdline.argv().end(),
116                    GetSwitchString(chromeos::switches::kPolicySwitchesBegin));
117  last = std::find(cmdline.argv().begin(), cmdline.argv().end(),
118                   GetSwitchString(chromeos::switches::kPolicySwitchesEnd));
119  if (first != cmdline.argv().end() && last != cmdline.argv().end())
120    flags.insert(first + 1, last);
121#endif
122  return flags;
123}
124
125const Experiment::Choice kEnableCompositingForFixedPositionChoices[] = {
126  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
127  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
128    switches::kEnableCompositingForFixedPosition, ""},
129  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
130    switches::kDisableCompositingForFixedPosition, ""},
131  { IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_HIGH_DPI,
132    switches::kEnableHighDpiCompositingForFixedPosition, ""}
133};
134
135const Experiment::Choice kEnableCompositingForTransitionChoices[] = {
136  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
137  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
138    switches::kEnableCompositingForTransition, ""},
139  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
140    switches::kDisableCompositingForTransition, ""},
141};
142
143const Experiment::Choice kEnableAcceleratedFixedRootBackgroundChoices[] = {
144  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
145  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
146    switches::kEnableAcceleratedFixedRootBackground, ""},
147  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
148    switches::kDisableAcceleratedFixedRootBackground, ""},
149};
150
151const Experiment::Choice kGDIPresentChoices[] = {
152  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
153  { IDS_FLAGS_PRESENT_WITH_GDI_FIRST_SHOW,
154    switches::kDoFirstShowPresentWithGDI, ""},
155  { IDS_FLAGS_PRESENT_WITH_GDI_ALL_SHOW,
156    switches::kDoAllShowPresentWithGDI, ""}
157};
158
159const Experiment::Choice kTouchEventsChoices[] = {
160  { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" },
161  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
162    switches::kTouchEvents,
163    switches::kTouchEventsEnabled },
164  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
165    switches::kTouchEvents,
166    switches::kTouchEventsDisabled }
167};
168
169const Experiment::Choice kTouchOptimizedUIChoices[] = {
170  { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" },
171  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
172    switches::kTouchOptimizedUI,
173    switches::kTouchOptimizedUIEnabled },
174  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
175    switches::kTouchOptimizedUI,
176    switches::kTouchOptimizedUIDisabled }
177};
178
179const Experiment::Choice kNaClDebugMaskChoices[] = {
180  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
181  // Secure shell can be used on ChromeOS for forwarding the TCP port opened by
182  // debug stub to a remote machine. Since secure shell uses NaCl, we provide
183  // an option to switch off its debugging.
184  { IDS_NACL_DEBUG_MASK_CHOICE_EXCLUDE_UTILS,
185      switches::kNaClDebugMask, "!*://*/*ssh_client.nmf" },
186  { IDS_NACL_DEBUG_MASK_CHOICE_INCLUDE_DEBUG,
187      switches::kNaClDebugMask, "*://*/*debug.nmf" }
188};
189
190#if defined(OS_CHROMEOS)
191
192const Experiment::Choice kChromeCaptivePortalDetectionChoices[] = {
193  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
194  { IDS_FLAGS_CHROME_CAPTIVE_PORTAL_DETECTOR,
195    chromeos::switches::kEnableChromeCaptivePortalDetector, "" },
196  { IDS_FLAGS_SHILL_CAPTIVE_PORTAL_DETECTOR,
197    chromeos::switches::kDisableChromeCaptivePortalDetector, "" }
198};
199
200#endif
201
202const Experiment::Choice kImplSidePaintingChoices[] = {
203  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
204  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
205    cc::switches::kEnableImplSidePainting, ""},
206  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
207    cc::switches::kDisableImplSidePainting, ""}
208};
209
210const Experiment::Choice kDeadlineSchedulingChoices[] = {
211  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
212  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
213    switches::kEnableDeadlineScheduling, ""},
214  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
215    switches::kDisableDeadlineScheduling, ""}
216};
217
218const Experiment::Choice kUIDeadlineSchedulingChoices[] = {
219  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
220  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
221    switches::kUIEnableDeadlineScheduling, ""},
222  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
223    switches::kUIDisableDeadlineScheduling, ""}
224};
225
226const Experiment::Choice kLCDTextChoices[] = {
227  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
228  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, cc::switches::kEnableLCDText, ""},
229  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, cc::switches::kDisableLCDText, ""}
230};
231
232const Experiment::Choice kDelegatedRendererChoices[] = {
233  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
234  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
235    switches::kEnableDelegatedRenderer, ""},
236  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
237    switches::kDisableDelegatedRenderer, ""}
238};
239
240const Experiment::Choice kMaxTilesForInterestAreaChoices[] = {
241  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
242  { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_SHORT,
243    cc::switches::kMaxTilesForInterestArea, "64"},
244  { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_TALL,
245    cc::switches::kMaxTilesForInterestArea, "128"},
246  { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_GRANDE,
247    cc::switches::kMaxTilesForInterestArea, "256"},
248  { IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_VENTI,
249    cc::switches::kMaxTilesForInterestArea, "512"}
250};
251
252const Experiment::Choice kDefaultTileWidthChoices[] = {
253  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
254  { IDS_FLAGS_DEFAULT_TILE_WIDTH_SHORT,
255    switches::kDefaultTileWidth, "128"},
256  { IDS_FLAGS_DEFAULT_TILE_WIDTH_TALL,
257    switches::kDefaultTileWidth, "256"},
258  { IDS_FLAGS_DEFAULT_TILE_WIDTH_GRANDE,
259    switches::kDefaultTileWidth, "512"},
260  { IDS_FLAGS_DEFAULT_TILE_WIDTH_VENTI,
261    switches::kDefaultTileWidth, "1024"}
262};
263
264#if defined(USE_ASH)
265const Experiment::Choice kAshOverviewDelayChoices[] = {
266  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
267  { IDS_FLAGS_OVERVIEW_DELAY_INSTANT,
268    ash::switches::kAshOverviewDelayOnAltTab, "0" },
269  { IDS_FLAGS_OVERVIEW_DELAY_SHORT,
270    ash::switches::kAshOverviewDelayOnAltTab, "100" },
271  { IDS_FLAGS_OVERVIEW_DELAY_LONG,
272    ash::switches::kAshOverviewDelayOnAltTab, "500" },
273  { IDS_FLAGS_OVERVIEW_DELAY_NEVER,
274    ash::switches::kAshOverviewDelayOnAltTab, "10000" },
275};
276#endif
277
278const Experiment::Choice kDefaultTileHeightChoices[] = {
279  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
280  { IDS_FLAGS_DEFAULT_TILE_HEIGHT_SHORT,
281    switches::kDefaultTileHeight, "128"},
282  { IDS_FLAGS_DEFAULT_TILE_HEIGHT_TALL,
283    switches::kDefaultTileHeight, "256"},
284  { IDS_FLAGS_DEFAULT_TILE_HEIGHT_GRANDE,
285    switches::kDefaultTileHeight, "512"},
286  { IDS_FLAGS_DEFAULT_TILE_HEIGHT_VENTI,
287    switches::kDefaultTileHeight, "1024"}
288};
289
290const Experiment::Choice kSimpleCacheBackendChoices[] = {
291  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
292  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
293    switches::kUseSimpleCacheBackend, "off" },
294  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
295    switches::kUseSimpleCacheBackend, "on"}
296};
297
298#if defined(USE_AURA)
299const Experiment::Choice kTabCaptureUpscaleQualityChoices[] = {
300  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
301  { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_FAST,
302    switches::kTabCaptureUpscaleQuality, "fast" },
303  { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_GOOD,
304    switches::kTabCaptureUpscaleQuality, "good" },
305  { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_BEST,
306    switches::kTabCaptureUpscaleQuality, "best" },
307};
308
309const Experiment::Choice kTabCaptureDownscaleQualityChoices[] = {
310  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
311  { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_FAST,
312    switches::kTabCaptureDownscaleQuality, "fast" },
313  { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_GOOD,
314    switches::kTabCaptureDownscaleQuality, "good" },
315  { IDS_FLAGS_TAB_CAPTURE_SCALE_QUALITY_BEST,
316    switches::kTabCaptureDownscaleQuality, "best" },
317};
318#endif
319
320const Experiment::Choice kMapImageChoices[] = {
321  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
322  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
323    cc::switches::kEnableMapImage, ""},
324  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
325    cc::switches::kDisableMapImage, ""}
326};
327
328// RECORDING USER METRICS FOR FLAGS:
329// -----------------------------------------------------------------------------
330// The first line of the experiment is the internal name. If you'd like to
331// gather statistics about the usage of your flag, you should append a marker
332// comment to the end of the feature name, like so:
333//   "my-special-feature",  // FLAGS:RECORD_UMA
334//
335// After doing that, run //chrome/tools/extract_actions.py (see instructions at
336// the top of that file for details) to update the chromeactions.txt file, which
337// will enable UMA to record your feature flag.
338//
339// After your feature has shipped under a flag, you can locate the metrics under
340// the action name AboutFlags_internal-action-name. Actions are recorded once
341// per startup, so you should divide this number by AboutFlags_StartupTick to
342// get a sense of usage. Note that this will not be the same as number of users
343// with a given feature enabled because users can quit and relaunch the
344// application multiple times over a given time interval. The dashboard also
345// shows you how many (metrics reporting) users have enabled the flag over the
346// last seven days. However, note that this is not the same as the number of
347// users who have the flag enabled, since enabling the flag happens once,
348// whereas running with the flag enabled happens until the user flips the flag
349// again.
350
351// To add a new experiment add to the end of kExperiments. There are two
352// distinct types of experiments:
353// . SINGLE_VALUE: experiment is either on or off. Use the SINGLE_VALUE_TYPE
354//   macro for this type supplying the command line to the macro.
355// . MULTI_VALUE: a list of choices, the first of which should correspond to a
356//   deactivated state for this lab (i.e. no command line option).  To specify
357//   this type of experiment use the macro MULTI_VALUE_TYPE supplying it the
358//   array of choices.
359// See the documentation of Experiment for details on the fields.
360//
361// When adding a new choice, add it to the end of the list.
362const Experiment kExperiments[] = {
363  {
364    "expose-for-tabs",  // FLAGS:RECORD_UMA
365    IDS_FLAGS_TABPOSE_NAME,
366    IDS_FLAGS_TABPOSE_DESCRIPTION,
367    kOsMac,
368#if defined(OS_MACOSX)
369    // The switch exists only on OS X.
370    SINGLE_VALUE_TYPE(switches::kEnableExposeForTabs)
371#else
372    SINGLE_VALUE_TYPE("")
373#endif
374  },
375  {
376    "conflicting-modules-check",  // FLAGS:RECORD_UMA
377    IDS_FLAGS_CONFLICTS_CHECK_NAME,
378    IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION,
379    kOsWin,
380    SINGLE_VALUE_TYPE(switches::kConflictingModulesCheck)
381  },
382  {
383    "ignore-gpu-blacklist",
384    IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME,
385    IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION,
386    kOsAll,
387    SINGLE_VALUE_TYPE(switches::kIgnoreGpuBlacklist)
388  },
389  {
390    "force-compositing-mode-2",
391    IDS_FLAGS_FORCE_COMPOSITING_MODE_NAME,
392    IDS_FLAGS_FORCE_COMPOSITING_MODE_DESCRIPTION,
393    kOsMac | kOsWin | kOsLinux,
394    ENABLE_DISABLE_VALUE_TYPE(switches::kForceCompositingMode,
395                              switches::kDisableForceCompositingMode)
396  },
397  {
398    "threaded-compositing-mode",
399    IDS_FLAGS_THREADED_COMPOSITING_MODE_NAME,
400    IDS_FLAGS_THREADED_COMPOSITING_MODE_DESCRIPTION,
401    kOsMac | kOsWin | kOsLinux,
402    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableThreadedCompositing,
403                              switches::kDisableThreadedCompositing)
404  },
405  {
406    "force-accelerated-composited-scrolling",
407     IDS_FLAGS_FORCE_ACCELERATED_OVERFLOW_SCROLL_MODE_NAME,
408     IDS_FLAGS_FORCE_ACCELERATED_OVERFLOW_SCROLL_MODE_DESCRIPTION,
409     kOsAll,
410     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAcceleratedOverflowScroll,
411                               switches::kDisableAcceleratedOverflowScroll)
412  },
413  {
414    "force-universal-accelerated-composited-scrolling",
415     IDS_FLAGS_FORCE_UNIVERSAL_ACCELERATED_OVERFLOW_SCROLL_MODE_NAME,
416     IDS_FLAGS_FORCE_UNIVERSAL_ACCELERATED_OVERFLOW_SCROLL_MODE_DESCRIPTION,
417     kOsAll,
418     ENABLE_DISABLE_VALUE_TYPE(
419         switches::kEnableUniversalAcceleratedOverflowScroll,
420         switches::kDisableUniversalAcceleratedOverflowScroll)
421  },
422  {
423    "present-with-GDI",
424    IDS_FLAGS_PRESENT_WITH_GDI_NAME,
425    IDS_FLAGS_PRESENT_WITH_GDI_DESCRIPTION,
426    kOsWin,
427    MULTI_VALUE_TYPE(kGDIPresentChoices)
428  },
429  {
430    "enable-experimental-canvas-features",
431    IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_NAME,
432    IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_DESCRIPTION,
433    kOsAll,
434    SINGLE_VALUE_TYPE(switches::kEnableExperimentalCanvasFeatures)
435  },
436  {
437    "disable-accelerated-2d-canvas",
438    IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_NAME,
439    IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_DESCRIPTION,
440    kOsAll,
441    SINGLE_VALUE_TYPE(switches::kDisableAccelerated2dCanvas)
442  },
443  {
444    "disable-threaded-animation",
445    IDS_FLAGS_DISABLE_THREADED_ANIMATION_NAME,
446    IDS_FLAGS_DISABLE_THREADED_ANIMATION_DESCRIPTION,
447    kOsAll,
448    SINGLE_VALUE_TYPE(cc::switches::kDisableThreadedAnimation)
449  },
450  {
451    "composited-layer-borders",
452    IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
453    IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION,
454    kOsAll,
455    SINGLE_VALUE_TYPE(cc::switches::kShowCompositedLayerBorders)
456  },
457  {
458    "show-fps-counter",
459    IDS_FLAGS_SHOW_FPS_COUNTER,
460    IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION,
461    kOsAll,
462    SINGLE_VALUE_TYPE(cc::switches::kShowFPSCounter)
463  },
464  {
465    "accelerated-filters",
466    IDS_FLAGS_ACCELERATED_FILTERS,
467    IDS_FLAGS_ACCELERATED_FILTERS_DESCRIPTION,
468    kOsAll,
469    SINGLE_VALUE_TYPE(switches::kEnableAcceleratedFilters)
470  },
471  {
472    "disable-webgl",
473    IDS_FLAGS_DISABLE_WEBGL_NAME,
474    IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION,
475    kOsAll,
476    SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)
477  },
478  {
479    "enable-d3d11",
480    IDS_FLAGS_ENABLE_D3D11_NAME,
481    IDS_FLAGS_ENABLE_D3D11_DESCRIPTION,
482    kOsWin,
483    SINGLE_VALUE_TYPE(switches::kEnableD3D11)
484  },
485  {
486    "disable-webrtc",
487    IDS_FLAGS_DISABLE_WEBRTC_NAME,
488    IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION,
489    kOsAndroid,
490#if defined(OS_ANDROID)
491    SINGLE_VALUE_TYPE(switches::kDisableWebRTC)
492#else
493    SINGLE_VALUE_TYPE("")
494#endif
495  },
496#if defined(ENABLE_WEBRTC)
497  {
498    "disable-device-enumeration",
499    IDS_FLAGS_DISABLE_DEVICE_ENUMERATION_NAME,
500    IDS_FLAGS_DISABLE_DEVICE_ENUMERATION_DESCRIPTION,
501    kOsAll,
502    SINGLE_VALUE_TYPE(switches::kDisableDeviceEnumeration)
503  },
504  {
505    "disable-sctp-data-channels",
506    IDS_FLAGS_DISABLE_SCTP_DATA_CHANNELS_NAME,
507    IDS_FLAGS_DISABLE_SCTP_DATA_CHANNELS_DESCRIPTION,
508    kOsAll,
509    SINGLE_VALUE_TYPE(switches::kDisableSCTPDataChannels)
510  },
511  {
512    "disable-webrtc-hw-decoding",
513    IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_NAME,
514    IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_DESCRIPTION,
515    kOsCrOS,
516    SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWDecoding)
517  },
518  {
519    "disable-webrtc-hw-encoding",
520    IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_NAME,
521    IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_DESCRIPTION,
522    kOsCrOS,
523    SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWEncoding)
524  },
525#endif
526#if defined(OS_ANDROID)
527  {
528    "disable-webaudio",
529    IDS_FLAGS_DISABLE_WEBAUDIO_NAME,
530    IDS_FLAGS_DISABLE_WEBAUDIO_DESCRIPTION,
531    kOsAndroid,
532    SINGLE_VALUE_TYPE(switches::kDisableWebAudio)
533  },
534#endif
535  {
536    "fixed-position-creates-stacking-context",
537    IDS_FLAGS_FIXED_POSITION_CREATES_STACKING_CONTEXT_NAME,
538    IDS_FLAGS_FIXED_POSITION_CREATES_STACKING_CONTEXT_DESCRIPTION,
539    kOsAll,
540    ENABLE_DISABLE_VALUE_TYPE(
541        switches::kEnableFixedPositionCreatesStackingContext,
542        switches::kDisableFixedPositionCreatesStackingContext)
543  },
544  {
545    "enable-compositing-for-fixed-position",
546    IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_NAME,
547    IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_DESCRIPTION,
548    kOsAll,
549    MULTI_VALUE_TYPE(kEnableCompositingForFixedPositionChoices)
550  },
551  {
552    "enable-compositing-for-transition",
553    IDS_FLAGS_COMPOSITING_FOR_TRANSITION_NAME,
554    IDS_FLAGS_COMPOSITING_FOR_TRANSITION_DESCRIPTION,
555    kOsAll,
556    MULTI_VALUE_TYPE(kEnableCompositingForTransitionChoices)
557  },
558  {
559    "enable-accelerated-fixed-root-background",
560    IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_NAME,
561    IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_DESCRIPTION,
562    kOsAll,
563    MULTI_VALUE_TYPE(kEnableAcceleratedFixedRootBackgroundChoices)
564  },
565  // TODO(bbudge): When NaCl is on by default, remove this flag entry.
566  {
567    "enable-nacl",  // FLAGS:RECORD_UMA
568    IDS_FLAGS_ENABLE_NACL_NAME,
569    IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
570    kOsDesktop,
571    SINGLE_VALUE_TYPE(switches::kEnableNaCl)
572  },
573  {
574    "enable-nacl-debug",  // FLAGS:RECORD_UMA
575    IDS_FLAGS_ENABLE_NACL_DEBUG_NAME,
576    IDS_FLAGS_ENABLE_NACL_DEBUG_DESCRIPTION,
577    kOsDesktop,
578    SINGLE_VALUE_TYPE(switches::kEnableNaClDebug)
579  },
580  {
581    "disable-pnacl",  // FLAGS:RECORD_UMA
582    IDS_FLAGS_DISABLE_PNACL_NAME,
583    IDS_FLAGS_DISABLE_PNACL_DESCRIPTION,
584    kOsDesktop,
585    SINGLE_VALUE_TYPE(switches::kDisablePnacl)
586  },
587  {
588    "nacl-debug-mask",  // FLAGS:RECORD_UMA
589    IDS_FLAGS_NACL_DEBUG_MASK_NAME,
590    IDS_FLAGS_NACL_DEBUG_MASK_DESCRIPTION,
591    kOsDesktop,
592    MULTI_VALUE_TYPE(kNaClDebugMaskChoices)
593  },
594  {
595    "extension-apis",  // FLAGS:RECORD_UMA
596    IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
597    IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
598    kOsDesktop,
599    SINGLE_VALUE_TYPE(extensions::switches::kEnableExperimentalExtensionApis)
600  },
601  {
602    "extensions-on-chrome-urls",
603    IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME,
604    IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION,
605    kOsAll,
606    SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)
607  },
608  {
609    "enable-fast-unload",
610    IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME,
611    IDS_FLAGS_ENABLE_FAST_UNLOAD_DESCRIPTION,
612    kOsAll,
613    SINGLE_VALUE_TYPE(switches::kEnableFastUnload)
614  },
615  {
616    "enable-adview",
617    IDS_FLAGS_ENABLE_ADVIEW_NAME,
618    IDS_FLAGS_ENABLE_ADVIEW_DESCRIPTION,
619    kOsDesktop,
620    SINGLE_VALUE_TYPE(switches::kEnableAdview)
621  },
622  {
623    "enable-adview-src-attribute",
624    IDS_FLAGS_ENABLE_ADVIEW_SRC_ATTRIBUTE_NAME,
625    IDS_FLAGS_ENABLE_ADVIEW_SRC_ATTRIBUTE_DESCRIPTION,
626    kOsDesktop,
627    SINGLE_VALUE_TYPE(switches::kEnableAdviewSrcAttribute)
628  },
629  {
630    "enable-app-window-controls",
631    IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME,
632    IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION,
633    kOsDesktop,
634    SINGLE_VALUE_TYPE(switches::kEnableAppWindowControls)
635  },
636  {
637    "script-badges",
638    IDS_FLAGS_SCRIPT_BADGES_NAME,
639    IDS_FLAGS_SCRIPT_BADGES_DESCRIPTION,
640    kOsDesktop,
641    SINGLE_VALUE_TYPE(switches::kScriptBadges)
642  },
643  {
644    "script-bubble",
645    IDS_FLAGS_SCRIPT_BUBBLE_NAME,
646    IDS_FLAGS_SCRIPT_BUBBLE_DESCRIPTION,
647    kOsDesktop,
648    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kScriptBubble, "1",
649                                        switches::kScriptBubble, "0")
650  },
651  {
652    "apps-new-install-bubble",
653    IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_NAME,
654    IDS_FLAGS_APPS_NEW_INSTALL_BUBBLE_DESCRIPTION,
655    kOsDesktop,
656    SINGLE_VALUE_TYPE(switches::kAppsNewInstallBubble)
657  },
658  {
659    "disable-hyperlink-auditing",
660    IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
661    IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
662    kOsAll,
663    SINGLE_VALUE_TYPE(switches::kNoPings)
664  },
665  {
666    "tab-groups-context-menu",
667    IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_NAME,
668    IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_DESCRIPTION,
669    kOsWin,
670    SINGLE_VALUE_TYPE(switches::kEnableTabGroupsContextMenu)
671  },
672  {
673    "enable-instant-extended-api",
674    IDS_FLAGS_ENABLE_INSTANT_EXTENDED_API,
675    IDS_FLAGS_ENABLE_INSTANT_EXTENDED_API_DESCRIPTION,
676    kOsMac | kOsWin | kOsCrOS,
677    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableInstantExtendedAPI,
678                              switches::kDisableInstantExtendedAPI)
679  },
680  {
681    "use-cacheable-new-tab-page",
682    IDS_FLAGS_ENABLE_INSTANT_EXTENDED_CACHEABLE_NTP,
683    IDS_FLAGS_ENABLE_INSTANT_EXTENDED_CACHEABLE_NTP_DESCRIPTION,
684    kOsMac | kOsWin | kOsCrOS,
685    SINGLE_VALUE_TYPE(switches::kUseCacheableNewTabPage)
686  },
687  {
688    "enable-local-first-load-ntp",
689    IDS_FLAGS_ENABLE_LOCAL_FIRST_LOAD_NTP,
690    IDS_FLAGS_ENABLE_LOCAL_FIRST_LOAD_NTP_DESCRIPTION,
691    kOsMac | kOsWin | kOsCrOS,
692    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLocalFirstLoadNTP,
693                              switches::kDisableLocalFirstLoadNTP)
694  },
695#if defined(OS_ANDROID)
696  {
697    "enable-new-ntp",
698    IDS_FLAGS_ENABLE_NEW_NTP,
699    IDS_FLAGS_ENABLE_NEW_NTP_DESCRIPTION,
700    kOsAndroid,
701    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewNTP,
702                              switches::kDisableNewNTP)
703  },
704#endif
705  {
706    "show-autofill-type-predictions",
707    IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME,
708    IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION,
709    kOsAll,
710    SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillTypePredictions)
711  },
712  {
713    "enable-gesture-tap-highlight",
714    IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_NAME,
715    IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_DESCRIPTION,
716    kOsLinux | kOsCrOS,
717    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableGestureTapHighlight,
718                              switches::kDisableGestureTapHighlight)
719  },
720  {
721    "enable-smooth-scrolling",  // FLAGS:RECORD_UMA
722    IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME,
723    IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION,
724    // Can't expose the switch unless the code is compiled in.
725    // On by default for the Mac (different implementation in WebKit).
726    kOsWin | kOsLinux,
727    SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)
728  },
729  {
730    "enable-overlay-scrollbars",
731    IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_NAME,
732    IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_DESCRIPTION,
733    // Uses the system preference on Mac (a different implementation).
734    // On Android, this is always enabled.
735    kOsCrOS,
736    SINGLE_VALUE_TYPE(switches::kEnableOverlayScrollbars)
737  },
738  {
739    "enable-panels",
740    IDS_FLAGS_ENABLE_PANELS_NAME,
741    IDS_FLAGS_ENABLE_PANELS_DESCRIPTION,
742    kOsDesktop,
743    SINGLE_VALUE_TYPE(switches::kEnablePanels)
744  },
745  {
746    // See http://crbug.com/120416 for how to remove this flag.
747    "save-page-as-mhtml",  // FLAGS:RECORD_UMA
748    IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME,
749    IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION,
750    kOsMac | kOsWin | kOsLinux,
751    SINGLE_VALUE_TYPE(switches::kSavePageAsMHTML)
752  },
753  {
754    "enable-autologin",
755    IDS_FLAGS_ENABLE_AUTOLOGIN_NAME,
756    IDS_FLAGS_ENABLE_AUTOLOGIN_DESCRIPTION,
757    kOsMac | kOsWin | kOsLinux,
758    SINGLE_VALUE_TYPE(switches::kEnableAutologin)
759  },
760  {
761    "enable-quic",
762    IDS_FLAGS_ENABLE_QUIC_NAME,
763    IDS_FLAGS_ENABLE_QUIC_DESCRIPTION,
764    kOsAll,
765    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuic,
766                              switches::kDisableQuic)
767  },
768  {
769    "enable-quic-https",
770    IDS_FLAGS_ENABLE_QUIC_HTTPS_NAME,
771    IDS_FLAGS_ENABLE_QUIC_HTTPS_DESCRIPTION,
772    kOsAll,
773    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuicHttps,
774                              switches::kDisableQuicHttps)
775  },
776  {
777    "enable-spdy4a2",
778    IDS_FLAGS_ENABLE_SPDY4A2_NAME,
779    IDS_FLAGS_ENABLE_SPDY4A2_DESCRIPTION,
780    kOsAll,
781    SINGLE_VALUE_TYPE(switches::kEnableSpdy4a2)
782  },
783  {
784    "enable-http2-draft-04",
785    IDS_FLAGS_ENABLE_HTTP2_DRAFT_04_NAME,
786    IDS_FLAGS_ENABLE_HTTP2_DRAFT_04_DESCRIPTION,
787    kOsAll,
788    SINGLE_VALUE_TYPE(switches::kEnableHttp2Draft04)
789  },
790  {
791    "enable-async-dns",
792    IDS_FLAGS_ENABLE_ASYNC_DNS_NAME,
793    IDS_FLAGS_ENABLE_ASYNC_DNS_DESCRIPTION,
794    kOsWin | kOsMac | kOsLinux | kOsCrOS,
795    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAsyncDns,
796                              switches::kDisableAsyncDns)
797  },
798  {
799    "disable-webkit-media-source",
800    IDS_FLAGS_DISABLE_WEBKIT_MEDIA_SOURCE_NAME,
801    IDS_FLAGS_DISABLE_WEBKIT_MEDIA_SOURCE_DESCRIPTION,
802    kOsAll,
803    SINGLE_VALUE_TYPE(switches::kDisableWebKitMediaSource)
804  },
805  {
806    "disable-unprefixed-media-source",
807    IDS_FLAGS_DISABLE_UNPREFIXED_MEDIA_SOURCE_NAME,
808    IDS_FLAGS_DISABLE_UNPREFIXED_MEDIA_SOURCE_DESCRIPTION,
809    kOsAll,
810    SINGLE_VALUE_TYPE(switches::kDisableUnprefixedMediaSource)
811  },
812  {
813    "enable-encrypted-media",
814    IDS_FLAGS_ENABLE_ENCRYPTED_MEDIA_NAME,
815    IDS_FLAGS_ENABLE_ENCRYPTED_MEDIA_DESCRIPTION,
816    kOsAll,
817    SINGLE_VALUE_TYPE(switches::kEnableEncryptedMedia)
818  },
819  {
820    "disable-prefixed-encrypted-media",
821    IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_NAME,
822    IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_DESCRIPTION,
823    kOsAll,
824    SINGLE_VALUE_TYPE(switches::kDisablePrefixedEncryptedMedia)
825  },
826#if defined(OS_ANDROID)
827  {
828    "disable-infobar-for-protected-media-identifier",
829    IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_NAME,
830    IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_DESCRIPTION,
831    kOsAndroid,
832    SINGLE_VALUE_TYPE(switches::kDisableInfobarForProtectedMediaIdentifier)
833  },
834  {
835    "mediadrm-enable-non-compositing",
836    IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_NAME,
837    IDS_FLAGS_MEDIADRM_ENABLE_NON_COMPOSITING_DESCRIPTION,
838    kOsAndroid,
839    SINGLE_VALUE_TYPE(switches::kMediaDrmEnableNonCompositing)
840  },
841#endif  // defined(OS_ANDROID)
842  {
843    "enable-opus-playback",
844    IDS_FLAGS_ENABLE_OPUS_PLAYBACK_NAME,
845    IDS_FLAGS_ENABLE_OPUS_PLAYBACK_DESCRIPTION,
846    kOsDesktop,
847    SINGLE_VALUE_TYPE(switches::kEnableOpusPlayback)
848  },
849 {
850    "disable-vp8-alpha-playback",
851    IDS_FLAGS_DISABLE_VP8_ALPHA_PLAYBACK_NAME,
852    IDS_FLAGS_DISABLE_VP8_ALPHA_PLAYBACK_DESCRIPTION,
853    kOsDesktop,
854    SINGLE_VALUE_TYPE(switches::kDisableVp8AlphaPlayback)
855  },
856  {
857    "enable-managed-users",
858    IDS_FLAGS_ENABLE_LOCALLY_MANAGED_USERS_NAME,
859    IDS_FLAGS_ENABLE_LOCALLY_MANAGED_USERS_DESCRIPTION,
860    kOsMac | kOsWin | kOsLinux | kOsCrOSOwnerOnly,
861    SINGLE_VALUE_TYPE(switches::kEnableManagedUsers)
862  },
863  {
864    "per-tile-painting",
865    IDS_FLAGS_PER_TILE_PAINTING_NAME,
866    IDS_FLAGS_PER_TILE_PAINTING_DESCRIPTION,
867    kOsMac | kOsLinux | kOsCrOS,
868    SINGLE_VALUE_TYPE(cc::switches::kEnablePerTilePainting)
869  },
870  {
871    "enable-javascript-harmony",
872    IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME,
873    IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION,
874    kOsAll,
875    SINGLE_VALUE_TYPE_AND_VALUE(switches::kJavaScriptFlags, "--harmony")
876  },
877  {
878    "enable-tab-browser-dragging",
879    IDS_FLAGS_ENABLE_TAB_BROWSER_DRAGGING_NAME,
880    IDS_FLAGS_ENABLE_TAB_BROWSER_DRAGGING_DESCRIPTION,
881    kOsWin,
882    SINGLE_VALUE_TYPE(switches::kTabBrowserDragging)
883  },
884  {
885    "disable-restore-session-state",
886    IDS_FLAGS_DISABLE_RESTORE_SESSION_STATE_NAME,
887    IDS_FLAGS_DISABLE_RESTORE_SESSION_STATE_DESCRIPTION,
888    kOsAll,
889    SINGLE_VALUE_TYPE(switches::kDisableRestoreSessionState)
890  },
891  {
892    "disable-software-rasterizer",
893    IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME,
894    IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION,
895#if defined(ENABLE_SWIFTSHADER)
896    kOsAll,
897#else
898    0,
899#endif
900    SINGLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)
901  },
902  {
903    "enable-experimental-web-platform-features",
904    IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME,
905    IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION,
906    kOsAll,
907    SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebPlatformFeatures)
908  },
909  {
910    "disable-ntp-other-sessions-menu",
911    IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_NAME,
912    IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_DESCRIPTION,
913    kOsDesktop,
914    SINGLE_VALUE_TYPE(switches::kDisableNTPOtherSessionsMenu)
915  },
916#if defined(USE_ASH)
917  {
918    "enable-ash-oak",
919    IDS_FLAGS_ENABLE_ASH_OAK_NAME,
920    IDS_FLAGS_ENABLE_ASH_OAK_DESCRIPTION,
921    kOsAll,
922    SINGLE_VALUE_TYPE(ash::switches::kAshEnableOak),
923  },
924#endif
925  {
926    "enable-devtools-experiments",
927    IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME,
928    IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION,
929    kOsDesktop,
930    SINGLE_VALUE_TYPE(switches::kEnableDevToolsExperiments)
931  },
932  {
933    "silent-debugger-extension-api",
934    IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_NAME,
935    IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_DESCRIPTION,
936    kOsDesktop,
937    SINGLE_VALUE_TYPE(switches::kSilentDebuggerExtensionAPI)
938  },
939  {
940    "enable-suggestions-ntp",
941    IDS_FLAGS_NTP_SUGGESTIONS_PAGE_NAME,
942    IDS_FLAGS_NTP_SUGGESTIONS_PAGE_DESCRIPTION,
943    kOsDesktop,
944    SINGLE_VALUE_TYPE(switches::kEnableSuggestionsTabPage)
945  },
946  {
947    "spellcheck-autocorrect",
948    IDS_FLAGS_SPELLCHECK_AUTOCORRECT,
949    IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION,
950    kOsWin | kOsLinux | kOsCrOS,
951    SINGLE_VALUE_TYPE(switches::kEnableSpellingAutoCorrect)
952  },
953  {
954    "enable-scroll-prediction",
955    IDS_FLAGS_ENABLE_SCROLL_PREDICTION_NAME,
956    IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION,
957    kOsDesktop,
958    SINGLE_VALUE_TYPE(switches::kEnableScrollPrediction)
959  },
960  {
961    "touch-events",
962    IDS_TOUCH_EVENTS_NAME,
963    IDS_TOUCH_EVENTS_DESCRIPTION,
964    kOsDesktop,
965    MULTI_VALUE_TYPE(kTouchEventsChoices)
966  },
967  {
968    "touch-optimized-ui",
969    IDS_FLAGS_TOUCH_OPTIMIZED_UI_NAME,
970    IDS_FLAGS_TOUCH_OPTIMIZED_UI_DESCRIPTION,
971    kOsWin,
972    MULTI_VALUE_TYPE(kTouchOptimizedUIChoices)
973  },
974  {
975    "disable-touch-adjustment",
976    IDS_DISABLE_TOUCH_ADJUSTMENT_NAME,
977    IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION,
978    kOsWin | kOsLinux | kOsCrOS,
979    SINGLE_VALUE_TYPE(switches::kDisableTouchAdjustment)
980  },
981#if defined(OS_CHROMEOS)
982  {
983      "ash-use-alternate-shelf",
984      IDS_FLAGS_ALTERNATE_SHELF_LAYOUT_NAME,
985      IDS_FLAGS_ALTERNATE_SHELF_LAYOUT_DESCRIPTION,
986      kOsCrOS,
987      ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshUseAlternateShelfLayout,
988                                ash::switches::kAshDisableAlternateShelfLayout)
989  },
990  {
991      "ash-disable-drag-off-shelf",
992      IDS_FLAGS_DRAG_OFF_SHELF_NAME,
993      IDS_FLAGS_DRAG_OFF_SHELF_DESCRIPTION,
994      kOsCrOS,
995      SINGLE_VALUE_TYPE(ash::switches::kAshDisableDragOffShelf)
996  },
997  {
998    "enable-background-loader",
999    IDS_ENABLE_BACKLOADER_NAME,
1000    IDS_ENABLE_BACKLOADER_DESCRIPTION,
1001    kOsCrOS,
1002    SINGLE_VALUE_TYPE(chromeos::switches::kEnableBackgroundLoader)
1003  },
1004  {
1005    "ash-enable-docked-windows",
1006    IDS_FLAGS_DOCKED_WINDOWS_NAME,
1007    IDS_FLAGS_DOCKED_WINDOWS_DESCRIPTION,
1008    kOsCrOS,
1009    SINGLE_VALUE_TYPE(ash::switches::kAshEnableDockedWindows)
1010  },
1011#endif
1012  {
1013    "enable-download-resumption",
1014    IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_NAME,
1015    IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION,
1016    kOsDesktop,
1017    SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption)
1018  },
1019  {
1020    "allow-nacl-socket-api",
1021    IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME,
1022    IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION,
1023    kOsDesktop,
1024    SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")
1025  },
1026  {
1027    "stacked-tab-strip",
1028    IDS_FLAGS_STACKED_TAB_STRIP_NAME,
1029    IDS_FLAGS_STACKED_TAB_STRIP_DESCRIPTION,
1030    kOsWin,
1031    SINGLE_VALUE_TYPE(switches::kEnableStackedTabStrip)
1032  },
1033  {
1034    "force-device-scale-factor",
1035    IDS_FLAGS_FORCE_HIGH_DPI_NAME,
1036    IDS_FLAGS_FORCE_HIGH_DPI_DESCRIPTION,
1037    kOsCrOS,
1038    SINGLE_VALUE_TYPE_AND_VALUE(switches::kForceDeviceScaleFactor, "2")
1039  },
1040#if defined(OS_CHROMEOS)
1041  {
1042    "allow-touchpad-three-finger-click",
1043    IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_NAME,
1044    IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_DESCRIPTION,
1045    kOsCrOS,
1046    SINGLE_VALUE_TYPE(chromeos::switches::kEnableTouchpadThreeFingerClick)
1047  },
1048#endif
1049#if defined(USE_ASH)
1050  {
1051    "show-launcher-alignment-menu",
1052    IDS_FLAGS_SHOW_SHELF_ALIGNMENT_MENU_NAME,
1053    IDS_FLAGS_SHOW_SHELF_ALIGNMENT_MENU_DESCRIPTION,
1054    kOsAll,
1055    ENABLE_DISABLE_VALUE_TYPE(
1056        ash::switches::kShowShelfAlignmentMenu,
1057        ash::switches::kHideShelfAlignmentMenu)
1058  },
1059  {
1060    "disable-minimize-on-second-launcher-item-click",
1061    IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_NAME,
1062    IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_DESCRIPTION,
1063    kOsAll,
1064    SINGLE_VALUE_TYPE(switches::kDisableMinimizeOnSecondLauncherItemClick)
1065  },
1066  {
1067    "disable-overview-mode",
1068    IDS_FLAGS_DISABLE_OVERVIEW_MODE_NAME,
1069    IDS_FLAGS_DISABLE_OVERVIEW_MODE_DESCRIPTION,
1070    kOsCrOS,
1071    SINGLE_VALUE_TYPE(ash::switches::kAshDisableOverviewMode)
1072  },
1073  {
1074    "overview-delay-on-alt-tab",
1075    IDS_FLAGS_OVERVIEW_DELAY_NAME,
1076    IDS_FLAGS_OVERVIEW_DELAY_DESCRIPTION,
1077    kOsCrOS,
1078    MULTI_VALUE_TYPE(kAshOverviewDelayChoices)
1079  },
1080  {
1081    "show-touch-hud",
1082    IDS_FLAGS_SHOW_TOUCH_HUD_NAME,
1083    IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION,
1084    kOsAll,
1085    SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)
1086  },
1087  {
1088    "enable-pinch",
1089    IDS_FLAGS_ENABLE_PINCH_SCALE_NAME,
1090    IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION,
1091    kOsLinux | kOsWin | kOsCrOS,
1092    ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePinch, switches::kDisablePinch),
1093  },
1094  {
1095    "enable-pinch-virtual-viewport",
1096    IDS_FLAGS_ENABLE_PINCH_VIRTUAL_VIEWPORT_NAME,
1097    IDS_FLAGS_ENABLE_PINCH_VIRTUAL_VIEWPORT_DESCRIPTION,
1098    kOsLinux | kOsWin | kOsCrOS,
1099    SINGLE_VALUE_TYPE(cc::switches::kEnablePinchVirtualViewport),
1100  },
1101#endif  // defined(USE_ASH)
1102#if defined(OS_CHROMEOS)
1103  {
1104    "disable-boot-animation",
1105    IDS_FLAGS_DISABLE_BOOT_ANIMATION,
1106    IDS_FLAGS_DISABLE_BOOT_ANIMATION_DESCRIPTION,
1107    kOsCrOSOwnerOnly,
1108    SINGLE_VALUE_TYPE(chromeos::switches::kDisableBootAnimation),
1109  },
1110  {
1111    "captive-portal-detector",
1112    IDS_FLAGS_CAPTIVE_PORTAL_DETECTOR_NAME,
1113    IDS_FLAGS_CAPTIVE_PORTAL_DETECTOR_DESCRIPTION,
1114    kOsCrOSOwnerOnly,
1115    MULTI_VALUE_TYPE(kChromeCaptivePortalDetectionChoices),
1116  },
1117  {
1118    "file-manager-show-checkboxes",
1119    IDS_FLAGS_FILE_MANAGER_SHOW_CHECKBOXES_NAME,
1120    IDS_FLAGS_FILE_MANAGER_SHOW_CHECKBOXES_DESCRIPTION,
1121    kOsCrOS,
1122    SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerShowCheckboxes)
1123  },
1124  {
1125    "file-manager-enable-webstore-integration",
1126    IDS_FLAGS_FILE_MANAGER_ENABLE_WEBSTORE_INTEGRATION,
1127    IDS_FLAGS_FILE_MANAGER_ENABLE_WEBSTORE_INTEGRATION_DESCRIPTION,
1128    kOsCrOS,
1129    SINGLE_VALUE_TYPE(chromeos::switches::kFileManagerEnableWebstoreIntegration)
1130  },
1131  {
1132    "disable-quickoffice-component-app",
1133    IDS_FLAGS_DISABLE_QUICKOFFICE_COMPONENT_APP_NAME,
1134    IDS_FLAGS_DISABLE_QUICKOFFICE_COMPONENT_APP_DESCRIPTION,
1135    kOsCrOS,
1136    SINGLE_VALUE_TYPE(chromeos::switches::kDisableQuickofficeComponentApp),
1137  },
1138  {
1139    "enable-saml-signin",
1140    IDS_FLAGS_ENABLE_SAML_SIGNIN_NAME,
1141    IDS_FLAGS_ENABLE_SAML_SIGNIN_DESCRIPTION,
1142    kOsCrOS,
1143    SINGLE_VALUE_TYPE(chromeos::switches::kEnableSamlSignin),
1144  },
1145  {
1146    "enable-multi-profiles",
1147    IDS_FLAGS_ENABLE_MULTI_PROFILES_NAME,
1148    IDS_FLAGS_ENABLE_MULTI_PROFILES_DESCRIPTION,
1149    kOsCrOS,
1150    SINGLE_VALUE_TYPE(switches::kMultiProfiles),
1151  },
1152#endif  // defined(OS_CHROMEOS)
1153  {
1154    "views-textfield",
1155    IDS_FLAGS_VIEWS_TEXTFIELD_NAME,
1156    IDS_FLAGS_VIEWS_TEXTFIELD_DESCRIPTION,
1157    kOsWin,
1158    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableViewsTextfield,
1159                              switches::kDisableViewsTextfield),
1160  },
1161  { "disable-accelerated-video-decode",
1162    IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME,
1163    IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION,
1164    kOsWin | kOsCrOS,
1165    SINGLE_VALUE_TYPE(switches::kDisableAcceleratedVideoDecode),
1166  },
1167  {
1168    "enable-contacts",
1169    IDS_FLAGS_ENABLE_CONTACTS_NAME,
1170    IDS_FLAGS_ENABLE_CONTACTS_DESCRIPTION,
1171    kOsCrOS,
1172    SINGLE_VALUE_TYPE(switches::kEnableContacts)
1173  },
1174#if defined(USE_ASH)
1175  {
1176    "ash-debug-shortcuts",
1177    IDS_FLAGS_DEBUG_SHORTCUTS_NAME,
1178    IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION,
1179    kOsAll,
1180    SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts),
1181  },
1182  { "ash-enable-advanced-gestures",
1183    IDS_FLAGS_ENABLE_ADVANCED_GESTURES_NAME,
1184    IDS_FLAGS_ENABLE_ADVANCED_GESTURES_DESCRIPTION,
1185    kOsCrOS,
1186    SINGLE_VALUE_TYPE(ash::switches::kAshEnableAdvancedGestures),
1187  },
1188  { "ash-alternate-caption-button",
1189    IDS_FLAGS_ASH_FRAME_CAPTION_BUTTON_STYLE_NAME,
1190    IDS_FLAGS_ASH_FRAME_CAPTION_BUTTON_STYLE_DESCRIPTION,
1191    kOsCrOS,
1192    ENABLE_DISABLE_VALUE_TYPE(
1193        ash::switches::kAshEnableAlternateFrameCaptionButtonStyle,
1194        ash::switches::kAshDisableAlternateFrameCaptionButtonStyle),
1195  },
1196  {
1197    "ash-disable-auto-maximizing",
1198    IDS_FLAGS_ASH_AUTO_MAXIMIZING_NAME,
1199    IDS_FLAGS_ASH_AUTO_MAXIMIZING_DESCRIPTION,
1200    kOsWin | kOsLinux | kOsCrOS,
1201    SINGLE_VALUE_TYPE(ash::switches::kAshDisableAutoMaximizing)
1202  },
1203  { "ash-disable-drag-and-drop-applist-to-launcher",
1204    IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_NAME,
1205    IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_DESCRIPTION,
1206    kOsCrOS,
1207    SINGLE_VALUE_TYPE(ash::switches::kAshDisableDragAndDropAppListToLauncher),
1208  },
1209#if defined(OS_LINUX)
1210  { "ash-enable-memory-monitor",
1211      IDS_FLAGS_ENABLE_MEMORY_MONITOR_NAME,
1212      IDS_FLAGS_ENABLE_MEMORY_MONITOR_DESCRIPTION,
1213      kOsCrOS,
1214      SINGLE_VALUE_TYPE(ash::switches::kAshEnableMemoryMonitor),
1215  },
1216#endif
1217#if defined(OS_CHROMEOS)
1218  { "ash-enable-full-multi-profile-mode",
1219      IDS_FLAGS_ENABLE_FULL_MULTI_PROFILE_MODE,
1220      IDS_FLAGS_ENABLE_FULL_MULTI_PROFILE_MODE_DESCRIPTION,
1221      kOsCrOS,
1222      SINGLE_VALUE_TYPE(ash::switches::kAshEnableFullMultiProfileMode),
1223  },
1224#endif
1225#endif
1226#if defined(OS_CHROMEOS)
1227  {
1228    "ash-audio-device-menu",
1229    IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_NAME,
1230    IDS_FLAGS_ASH_AUDIO_DEVICE_MENU_DESCRIPTION,
1231    kOsCrOS,
1232    ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableAudioDeviceMenu,
1233                              ash::switches::kAshDisableAudioDeviceMenu)
1234  },
1235  {
1236    "enable-carrier-switching",
1237    IDS_FLAGS_ENABLE_CARRIER_SWITCHING,
1238    IDS_FLAGS_ENABLE_CARRIER_SWITCHING_DESCRIPTION,
1239    kOsCrOS,
1240    SINGLE_VALUE_TYPE(chromeos::switches::kEnableCarrierSwitching)
1241  },
1242  {
1243    "enable-request-tablet-site",
1244    IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME,
1245    IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION,
1246    kOsCrOS,
1247    SINGLE_VALUE_TYPE(chromeos::switches::kEnableRequestTabletSite)
1248  },
1249#endif
1250  {
1251    "debug-packed-apps",
1252    IDS_FLAGS_DEBUG_PACKED_APP_NAME,
1253    IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION,
1254    kOsDesktop,
1255    SINGLE_VALUE_TYPE(switches::kDebugPackedApps)
1256  },
1257  {
1258    "enable-password-generation",
1259    IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME,
1260    IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION,
1261    kOsDesktop,
1262    ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnablePasswordGeneration,
1263                              autofill::switches::kDisablePasswordGeneration)
1264  },
1265  {
1266    "enable-password-manager-reauthentication",
1267    IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_NAME,
1268    IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_DESCRIPTION,
1269    kOsMac,
1270    SINGLE_VALUE_TYPE(switches::kEnablePasswordManagerReauthentication)
1271  },
1272  {
1273    "password-autofill-public-suffix-domain-matching",
1274    IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_NAME,
1275    IDS_FLAGS_PASSWORD_AUTOFILL_PUBLIC_SUFFIX_DOMAIN_MATCHING_DESCRIPTION,
1276    kOsAndroid,
1277    ENABLE_DISABLE_VALUE_TYPE(
1278        switches::kEnablePasswordAutofillPublicSuffixDomainMatching,
1279        switches::kDisablePasswordAutofillPublicSuffixDomainMatching)
1280  },
1281  {
1282    "enable-deferred-image-decoding",
1283    IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME,
1284    IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION,
1285    kOsMac | kOsLinux | kOsCrOS,
1286    SINGLE_VALUE_TYPE(switches::kEnableDeferredImageDecoding)
1287  },
1288  {
1289    "performance-monitor-gathering",
1290    IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_NAME,
1291    IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_DESCRIPTION,
1292    kOsAll,
1293    SINGLE_VALUE_TYPE(switches::kPerformanceMonitorGathering)
1294  },
1295  {
1296    "enable-experimental-form-filling",
1297    IDS_FLAGS_ENABLE_EXPERIMENTAL_FORM_FILLING_NAME,
1298    IDS_FLAGS_ENABLE_EXPERIMENTAL_FORM_FILLING_DESCRIPTION,
1299    kOsWin | kOsCrOS,
1300    SINGLE_VALUE_TYPE(autofill::switches::kEnableExperimentalFormFilling)
1301  },
1302  {
1303    "wallet-service-use-sandbox",
1304    IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_NAME,
1305    IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_DESCRIPTION,
1306    kOsCrOS | kOsWin | kOsMac,
1307    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1308        autofill::switches::kWalletServiceUseSandbox, "1",
1309        autofill::switches::kWalletServiceUseSandbox, "0")
1310  },
1311  {
1312    "enable-interactive-autocomplete",
1313    IDS_FLAGS_ENABLE_INTERACTIVE_AUTOCOMPLETE_NAME,
1314    IDS_FLAGS_ENABLE_INTERACTIVE_AUTOCOMPLETE_DESCRIPTION,
1315    kOsWin | kOsCrOS | kOsAndroid | kOsMac,
1316    ENABLE_DISABLE_VALUE_TYPE(
1317        autofill::switches::kEnableInteractiveAutocomplete,
1318        autofill::switches::kDisableInteractiveAutocomplete)
1319  },
1320#if defined(USE_AURA)
1321  {
1322    "overscroll-history-navigation",
1323    IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_NAME,
1324    IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION,
1325    kOsAll,
1326    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1327        switches::kOverscrollHistoryNavigation, "1",
1328        switches::kOverscrollHistoryNavigation, "0")
1329  },
1330#endif
1331  {
1332    "scroll-end-effect",
1333    IDS_FLAGS_SCROLL_END_EFFECT_NAME,
1334    IDS_FLAGS_SCROLL_END_EFFECT_DESCRIPTION,
1335    kOsCrOS,
1336    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1337        switches::kScrollEndEffect, "1",
1338        switches::kScrollEndEffect, "0")
1339  },
1340  {
1341    "enable-touch-side-bezels",
1342    IDS_FLAGS_ENABLE_TOUCH_SIDE_BEZELS_NAME,
1343    IDS_FLAGS_ENABLE_TOUCH_SIDE_BEZELS_DESCRIPTION,
1344    kOsCrOS,
1345    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
1346        switches::kTouchSideBezels, "1",
1347        switches::kTouchSideBezels, "0")
1348  },
1349  {
1350    "enable-touch-drag-drop",
1351    IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME,
1352    IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION,
1353    kOsWin | kOsCrOS,
1354    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchDragDrop,
1355                              switches::kDisableTouchDragDrop)
1356  },
1357  {
1358    "enable-touch-editing",
1359    IDS_FLAGS_ENABLE_TOUCH_EDITING_NAME,
1360    IDS_FLAGS_ENABLE_TOUCH_EDITING_DESCRIPTION,
1361    kOsCrOS,
1362    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchEditing,
1363                              switches::kDisableTouchEditing)
1364  },
1365  {
1366    "enable-rich-notifications",
1367    IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_NAME,
1368    IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_DESCRIPTION,
1369    kOsWin | kOsMac,
1370    ENABLE_DISABLE_VALUE_TYPE(
1371        message_center::switches::kEnableRichNotifications,
1372        message_center::switches::kDisableRichNotifications)
1373  },
1374  {
1375    "enable-sync-synced-notifications",
1376    IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_NAME,
1377    IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_DESCRIPTION,
1378    kOsDesktop,
1379    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSyncSyncedNotifications,
1380                              switches::kDisableSyncSyncedNotifications)
1381  },
1382  {
1383    "disable-full-history-sync",
1384    IDS_FLAGS_FULL_HISTORY_SYNC_NAME,
1385    IDS_FLAGS_FULL_HISTORY_SYNC_DESCRIPTION,
1386    kOsAll,
1387    SINGLE_VALUE_TYPE(switches::kHistoryDisableFullHistorySync)
1388  },
1389  {
1390    "enable-usermedia-screen-capture",
1391    IDS_FLAGS_ENABLE_SCREEN_CAPTURE_NAME,
1392    IDS_FLAGS_ENABLE_SCREEN_CAPTURE_DESCRIPTION,
1393    kOsDesktop,
1394    SINGLE_VALUE_TYPE(switches::kEnableUserMediaScreenCapturing)
1395  },
1396  {
1397    "enable-apps-devtool-app",
1398    IDS_FLAGS_ENABLE_APPS_DEVTOOL_APP_NAME,
1399    IDS_FLAGS_ENABLE_APPS_DEVTOOL_APP_DESCRIPTION,
1400    kOsDesktop,
1401    SINGLE_VALUE_TYPE(switches::kAppsDevtool)
1402  },
1403  {
1404    "impl-side-painting",
1405    IDS_FLAGS_IMPL_SIDE_PAINTING_NAME,
1406    IDS_FLAGS_IMPL_SIDE_PAINTING_DESCRIPTION,
1407    kOsAndroid | kOsLinux | kOsCrOS,
1408    MULTI_VALUE_TYPE(kImplSidePaintingChoices)
1409  },
1410  {
1411    "deadline-scheduling",
1412    IDS_FLAGS_DEADLINE_SCHEDULING_NAME,
1413    IDS_FLAGS_DEADLINE_SCHEDULING_DESCRIPTION,
1414    kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
1415    MULTI_VALUE_TYPE(kDeadlineSchedulingChoices)
1416  },
1417  {
1418    "ui-deadline-scheduling",
1419    IDS_FLAGS_UI_DEADLINE_SCHEDULING_NAME,
1420    IDS_FLAGS_UI_DEADLINE_SCHEDULING_DESCRIPTION,
1421#ifdef USE_AURA
1422    kOsWin | kOsLinux |
1423#endif
1424    kOsCrOS,
1425    MULTI_VALUE_TYPE(kUIDeadlineSchedulingChoices)
1426  },
1427  {
1428    "lcd-text-aa",
1429    IDS_FLAGS_LCD_TEXT_NAME,
1430    IDS_FLAGS_LCD_TEXT_DESCRIPTION,
1431    kOsDesktop,
1432    MULTI_VALUE_TYPE(kLCDTextChoices)
1433  },
1434  {
1435    "delegated-renderer",
1436    IDS_FLAGS_DELEGATED_RENDERER_NAME,
1437    IDS_FLAGS_DELEGATED_RENDERER_DESCRIPTION,
1438#ifdef USE_AURA
1439    kOsWin | kOsLinux |
1440#endif
1441    kOsAndroid | kOsCrOS,
1442    MULTI_VALUE_TYPE(kDelegatedRendererChoices)
1443  },
1444  {
1445    "enable-websocket-experimental-implementation",
1446    IDS_FLAGS_ENABLE_EXPERIMENTAL_WEBSOCKET_NAME,
1447    IDS_FLAGS_ENABLE_EXPERIMENTAL_WEBSOCKET_DESCRIPTION,
1448    kOsAll,
1449    SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebSocket)
1450  },
1451  {
1452    "max-tiles-for-interest-area",
1453    IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_NAME,
1454    IDS_FLAGS_MAX_TILES_FOR_INTEREST_AREA_DESCRIPTION,
1455    kOsAndroid | kOsLinux | kOsCrOS,
1456    MULTI_VALUE_TYPE(kMaxTilesForInterestAreaChoices)
1457  },
1458  {
1459    "enable-offline-mode",
1460    IDS_FLAGS_ENABLE_OFFLINE_MODE_NAME,
1461    IDS_FLAGS_ENABLE_OFFLINE_MODE_DESCRIPTION,
1462    kOsAll,
1463    SINGLE_VALUE_TYPE(switches::kEnableOfflineCacheAccess)
1464  },
1465  {
1466    "default-tile-width",
1467    IDS_FLAGS_DEFAULT_TILE_WIDTH_NAME,
1468    IDS_FLAGS_DEFAULT_TILE_WIDTH_DESCRIPTION,
1469    kOsAll,
1470    MULTI_VALUE_TYPE(kDefaultTileWidthChoices)
1471  },
1472  {
1473    "default-tile-height",
1474    IDS_FLAGS_DEFAULT_TILE_HEIGHT_NAME,
1475    IDS_FLAGS_DEFAULT_TILE_HEIGHT_DESCRIPTION,
1476    kOsAll,
1477    MULTI_VALUE_TYPE(kDefaultTileHeightChoices)
1478  },
1479  // TODO(sky): ifdef needed until focus sorted out in DesktopNativeWidgetAura.
1480#if !defined(USE_AURA)
1481  {
1482    "track-active-visit-time",
1483    IDS_FLAGS_TRACK_ACTIVE_VISIT_TIME_NAME,
1484    IDS_FLAGS_TRACK_ACTIVE_VISIT_TIME_DESCRIPTION,
1485    kOsWin,
1486    SINGLE_VALUE_TYPE(switches::kTrackActiveVisitTime)
1487  },
1488#endif
1489#if defined(OS_ANDROID)
1490  {
1491    "disable-gesture-requirement-for-media-playback",
1492    IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME,
1493    IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION,
1494    kOsAndroid,
1495    SINGLE_VALUE_TYPE(switches::kDisableGestureRequirementForMediaPlayback)
1496  },
1497#endif
1498#if defined(ENABLE_GOOGLE_NOW)
1499  {
1500    "enable-google-now",
1501    IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_NAME,
1502    IDS_FLAGS_ENABLE_GOOGLE_NOW_INTEGRATION_DESCRIPTION,
1503    kOsWin | kOsCrOS | kOsMac,
1504    ENABLE_DISABLE_VALUE_TYPE(
1505        switches::kEnableGoogleNowIntegration,
1506        switches::kDisableGoogleNowIntegration)
1507  },
1508#endif
1509#if defined(OS_CHROMEOS)
1510  {
1511    "enable-virtual-keyboard",
1512    IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_NAME,
1513    IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_DESCRIPTION,
1514    kOsCrOS,
1515    SINGLE_VALUE_TYPE(keyboard::switches::kEnableVirtualKeyboard)
1516  },
1517  {
1518    "enable-swipe-selection",
1519    IDS_FLAGS_ENABLE_SWIPE_SELECTION_NAME,
1520    IDS_FLAGS_ENABLE_SWIPE_SELECTION_DESCRIPTION,
1521    kOsCrOS,
1522    SINGLE_VALUE_TYPE(keyboard::switches::kEnableSwipeSelection)
1523  },
1524#endif
1525  {
1526    "enable-simple-cache-backend",
1527    IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME,
1528    IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_DESCRIPTION,
1529    kOsAll,
1530    MULTI_VALUE_TYPE(kSimpleCacheBackendChoices)
1531  },
1532  {
1533    "enable-tcp-fast-open",
1534    IDS_FLAGS_ENABLE_TCP_FAST_OPEN_NAME,
1535    IDS_FLAGS_ENABLE_TCP_FAST_OPEN_DESCRIPTION,
1536    kOsLinux | kOsCrOS | kOsAndroid,
1537    SINGLE_VALUE_TYPE(switches::kEnableTcpFastOpen)
1538  },
1539  {
1540    "apps-use-native-frame",
1541    IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_NAME,
1542    IDS_FLAGS_ENABLE_NATIVE_FRAMES_FOR_APPS_DESCRIPTION,
1543    kOsMac | kOsWin,
1544    SINGLE_VALUE_TYPE(switches::kAppsUseNativeFrame)
1545  },
1546  {
1547    "enable-syncfs-directory-operation",
1548    IDS_FLAGS_ENABLE_SYNC_DIRECTORY_OPERATION_NAME,
1549    IDS_FLAGS_ENABLE_SYNC_DIRECTORY_OPERATION_DESCRIPTION,
1550    kOsAll,
1551    SINGLE_VALUE_TYPE(switches::kSyncfsEnableDirectoryOperation),
1552  },
1553#if defined(ENABLE_MDNS)
1554  {
1555    "disable-device-discovery",
1556    IDS_FLAGS_DISABLE_DEVICE_DISCOVERY_NAME,
1557    IDS_FLAGS_DISABLE_DEVICE_DISCOVERY_DESCRIPTION,
1558    kOsWin | kOsLinux | kOsCrOS,
1559    SINGLE_VALUE_TYPE(switches::kDisableDeviceDiscovery)
1560  },
1561  {
1562    "device-discovery-notifications",
1563    IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_NAME,
1564    IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_DESCRIPTION,
1565    kOsWin | kOsLinux | kOsCrOS,
1566    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDeviceDiscoveryNotifications,
1567                              switches::kDisableDeviceDiscoveryNotifications)
1568  },
1569  {
1570    "enable-privet-local-printing",
1571    IDS_FLAGS_ENABLE_PRIVET_LOCAL_PRINTING_NAME,
1572    IDS_FLAGS_ENABLE_PRIVET_LOCAL_PRINTING_DESCRIPTION,
1573    kOsWin | kOsLinux | kOsCrOS,
1574    SINGLE_VALUE_TYPE(switches::kEnablePrivetLocalPrinting)
1575  },
1576#endif  // ENABLE_MDNS
1577#if defined(OS_MACOSX)
1578  {
1579    "enable-app-shims",
1580    IDS_FLAGS_ENABLE_APP_SHIMS_NAME,
1581    IDS_FLAGS_ENABLE_APP_SHIMS_DESCRIPTION,
1582    kOsMac,
1583    SINGLE_VALUE_TYPE(switches::kEnableAppShims)
1584  },
1585  {
1586    "enable-simplified-fullscreen",
1587    IDS_FLAGS_ENABLE_SIMPLIFIED_FULLSCREEN_NAME,
1588    IDS_FLAGS_ENABLE_SIMPLIFIED_FULLSCREEN_DESCRIPTION,
1589    kOsMac,
1590    SINGLE_VALUE_TYPE(switches::kEnableSimplifiedFullscreen)
1591  },
1592#endif
1593#if defined(OS_CHROMEOS) || defined(OS_WIN)
1594  {
1595    "omnibox-auto-completion-for-ime",
1596    IDS_FLAGS_ENABLE_OMNIBOX_AUTO_COMPLETION_FOR_IME_NAME,
1597    IDS_FLAGS_ENABLE_OMNIBOX_AUTO_COMPLETION_FOR_IME_DESCRIPTION,
1598    kOsCrOS | kOsWin,
1599    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOmniboxAutoCompletionForIme,
1600                              switches::kDisableOmniboxAutoCompletionForIme)
1601  },
1602#endif
1603#if defined(USE_AURA)
1604  {
1605    "tab-capture-upscale-quality",
1606    IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_NAME,
1607    IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_DESCRIPTION,
1608    kOsAll,
1609    MULTI_VALUE_TYPE(kTabCaptureUpscaleQualityChoices)
1610  },
1611  {
1612    "tab-capture-downscale-quality",
1613    IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_NAME,
1614    IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_DESCRIPTION,
1615    kOsAll,
1616    MULTI_VALUE_TYPE(kTabCaptureDownscaleQualityChoices)
1617  },
1618#endif
1619  {
1620    "enable-spelling-service-feedback",
1621    IDS_FLAGS_ENABLE_SPELLING_SERVICE_FEEDBACK_NAME,
1622    IDS_FLAGS_ENABLE_SPELLING_SERVICE_FEEDBACK_DESCRIPTION,
1623    kOsAll,
1624    SINGLE_VALUE_TYPE(switches::kEnableSpellingServiceFeedback)
1625  },
1626  {
1627    "enable-webgl-draft-extensions",
1628    IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_NAME,
1629    IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_DESCRIPTION,
1630    kOsAll,
1631    SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)
1632  },
1633  {
1634    "enable-html-imports",
1635    IDS_FLAGS_ENABLE_HTML_IMPORTS_NAME,
1636    IDS_FLAGS_ENABLE_HTML_IMPORTS_DESCRIPTION,
1637    kOsAll,
1638    SINGLE_VALUE_TYPE(switches::kEnableHTMLImports)
1639  },
1640  {
1641    "high-dpi-support",
1642    IDS_FLAGS_HIDPI_NAME,
1643    IDS_FLAGS_HIDPI_DESCRIPTION,
1644    kOsWin,
1645    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kHighDPISupport, "1",
1646                                        switches::kHighDPISupport, "0")
1647  },
1648#if defined(OS_CHROMEOS)
1649  {
1650    "enable-quickoffice-viewing",
1651    IDS_FLAGS_ENABLE_QUICKOFFICE_DESKTOP_VIEWING_NAME,
1652    IDS_FLAGS_ENABLE_QUICKOFFICE_DESKTOP_VIEWING_DESCRIPTION,
1653    kOsCrOS,
1654    SINGLE_VALUE_TYPE(switches::kEnableQuickofficeViewing),
1655  },
1656  {
1657    "enable-sticky-keys",
1658    IDS_FLAGS_ENABLE_STICKY_KEYS_NAME,
1659    IDS_FLAGS_ENABLE_STICKY_KEYS_DESCRIPTION,
1660    kOsCrOS,
1661    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableStickyKeys,
1662                              switches::kDisableStickyKeys)
1663  },
1664#endif
1665  {
1666    "enable-web-midi",
1667    IDS_FLAGS_ENABLE_WEB_MIDI_NAME,
1668    IDS_FLAGS_ENABLE_WEB_MIDI_DESCRIPTION,
1669    kOsMac,
1670    SINGLE_VALUE_TYPE(switches::kEnableWebMIDI)
1671  },
1672  {
1673    "enable-new-profile-management",
1674    IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_NAME,
1675    IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_DESCRIPTION,
1676    kOsWin,
1677    SINGLE_VALUE_TYPE(switches::kNewProfileManagement)
1678  },
1679  {
1680    "enable-inline-signin",
1681    IDS_FLAGS_ENABLE_INLINE_SIGNIN_NAME,
1682    IDS_FLAGS_ENABLE_INLINE_SIGNIN_DESCRIPTION,
1683    kOsMac | kOsWin | kOsLinux,
1684    SINGLE_VALUE_TYPE(switches::kEnableInlineSignin)
1685  },
1686  {
1687    "enable-google-profile-info",
1688    IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_NAME,
1689    IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_DESCRIPTION,
1690    kOsMac | kOsWin | kOsLinux,
1691    SINGLE_VALUE_TYPE(switches::kGoogleProfileInfo)
1692  },
1693  {
1694    "disable-app-launcher",
1695    IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_NAME,
1696    IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_DESCRIPTION,
1697    kOsMac | kOsWin,
1698    SINGLE_VALUE_TYPE(switches::kResetAppListInstallState)
1699  },
1700#if defined(ENABLE_APP_LIST)
1701  {
1702    "enable-app-launcher-start-page",
1703    IDS_FLAGS_ENABLE_APP_LIST_START_PAGE_NAME,
1704    IDS_FLAGS_ENABLE_APP_LIST_START_PAGE_DESCRIPTION,
1705    kOsWin | kOsCrOS,
1706    SINGLE_VALUE_TYPE(switches::kShowAppListStartPage)
1707  },
1708#endif
1709#if defined(OS_CHROMEOS)
1710  {
1711    "disable-user-image-sync",
1712    IDS_FLAGS_DISABLE_USER_IMAGE_SYNC_NAME,
1713    IDS_FLAGS_DISABLE_USER_IMAGE_SYNC_DESCRIPTION,
1714    kOsCrOS,
1715    SINGLE_VALUE_TYPE(chromeos::switches::kDisableUserImageSync)
1716  },
1717#endif
1718#if defined(OS_ANDROID)
1719  {
1720    "enable-accessibility-tab-switcher",
1721    IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_NAME,
1722    IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION,
1723    kOsAndroid,
1724    SINGLE_VALUE_TYPE(switches::kEnableAccessibilityTabSwitcher)
1725  },
1726#endif
1727  {
1728    "disable-batched-shutdown",
1729    IDS_FLAGS_DISABLE_BATCHED_SHUTDOWN_NAME,
1730    IDS_FLAGS_DISABLE_BATCHED_SHUTDOWN_DESCRIPTION,
1731    kOsDesktop,
1732    SINGLE_VALUE_TYPE(switches::kDisableBatchedShutdown)
1733  },
1734  {
1735    "map-image",
1736    IDS_FLAGS_MAP_IMAGE_NAME,
1737    IDS_FLAGS_MAP_IMAGE_DESCRIPTION,
1738    kOsAll,
1739    MULTI_VALUE_TYPE(kMapImageChoices)
1740  },
1741  {
1742    "enable-add-to-homescreen",
1743    IDS_FLAGS_ENABLE_ADD_TO_HOMESCREEN_NAME,
1744    IDS_FLAGS_ENABLE_ADD_TO_HOMESCREEN_DESCRIPTION,
1745    kOsAndroid,
1746#if defined(OS_ANDROID)
1747    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAddToHomescreen,
1748                              switches::kDisableAddToHomescreen),
1749#else
1750    SINGLE_VALUE_TYPE("")
1751#endif
1752  },
1753#if defined(OS_CHROMEOS)
1754  {
1755    "enable-first-run-ui",
1756    IDS_FLAGS_ENABLE_FIRST_RUN_UI_NAME,
1757    IDS_FLAGS_ENABLE_FIRST_RUN_UI_DESCRIPTION,
1758    kOsCrOS,
1759    SINGLE_VALUE_TYPE(chromeos::switches::kEnableFirstRunUI)
1760  },
1761#endif
1762  {
1763    "disable-compositor-touch-hit-testing",
1764    IDS_FLAGS_DISABLE_COMPOSITOR_TOUCH_HIT_TESTING_NAME,
1765    IDS_FLAGS_DISABLE_COMPOSITOR_TOUCH_HIT_TESTING_DESCRIPTION,
1766    kOsAll,
1767    SINGLE_VALUE_TYPE(cc::switches::kDisableCompositorTouchHitTesting),
1768  },
1769  {
1770    "enable-accelerated-scrollable-frames",
1771     IDS_FLAGS_ENABLE_ACCELERATED_SCROLLABLE_FRAMES_NAME,
1772     IDS_FLAGS_ENABLE_ACCELERATED_SCROLLABLE_FRAMES_DESCRIPTION,
1773     kOsAll,
1774     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAcceleratedScrollableFrames,
1775                               switches::kDisableAcceleratedScrollableFrames)
1776  },
1777  {
1778    "enable-composited-scrolling-for-frames",
1779     IDS_FLAGS_ENABLE_COMPOSITED_SCROLLING_FOR_FRAMES_NAME,
1780     IDS_FLAGS_ENABLE_COMPOSITED_SCROLLING_FOR_FRAMES_DESCRIPTION,
1781     kOsAll,
1782     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableCompositedScrollingForFrames,
1783                               switches::kDisableCompositedScrollingForFrames)
1784  },
1785  {
1786    "enable-streamlined-hosted-apps",
1787    IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_NAME,
1788    IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_DESCRIPTION,
1789    kOsWin | kOsCrOS,
1790    SINGLE_VALUE_TYPE(switches::kEnableStreamlinedHostedApps)
1791  },
1792  {
1793    "enable-ephemeral-apps",
1794    IDS_FLAGS_ENABLE_EPHEMERAL_APPS_NAME,
1795    IDS_FLAGS_ENABLE_EPHEMERAL_APPS_DESCRIPTION,
1796    kOsWin | kOsCrOS,
1797    SINGLE_VALUE_TYPE(switches::kEnableEphemeralApps)
1798  },
1799  {
1800    "enable-service-worker",
1801    IDS_FLAGS_ENABLE_SERVICE_WORKER_NAME,
1802    IDS_FLAGS_ENABLE_SERVICE_WORKER_DESCRIPTION,
1803    kOsAll,
1804    SINGLE_VALUE_TYPE(switches::kEnableServiceWorker)
1805  },
1806#if defined(OS_ANDROID)
1807  {
1808    "disable-click-delay",
1809    IDS_FLAGS_DISABLE_CLICK_DELAY_NAME,
1810    IDS_FLAGS_DISABLE_CLICK_DELAY_DESCRIPTION,
1811    kOsAndroid,
1812    // Java-only switch: CommandLine.DISABLE_CLICK_DELAY
1813    SINGLE_VALUE_TYPE("disable-click-delay")
1814  },
1815#endif
1816#if defined(OS_CHROMEOS)
1817  {
1818    "enable-ime-mode-indicator",
1819    IDS_FLAGS_ENABLE_IME_MODE_INDICATOR,
1820    IDS_FLAGS_ENABLE_IME_MODE_INDICATOR_DESCRIPTION,
1821    kOsCrOS,
1822    SINGLE_VALUE_TYPE(chromeos::switches::kEnableIMEModeIndicator)
1823  },
1824#endif
1825  {
1826    "enable-translate-new-ux",
1827    IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME,
1828    IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION,
1829    kOsDesktop,
1830    SINGLE_VALUE_TYPE(switches::kEnableTranslateNewUX)
1831  },
1832};
1833
1834const Experiment* experiments = kExperiments;
1835size_t num_experiments = arraysize(kExperiments);
1836
1837// Stores and encapsulates the little state that about:flags has.
1838class FlagsState {
1839 public:
1840  FlagsState() : needs_restart_(false) {}
1841  void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
1842                              CommandLine* command_line,
1843                              SentinelsMode sentinels);
1844  bool IsRestartNeededToCommitChanges();
1845  void SetExperimentEnabled(
1846      FlagsStorage* flags_storage,
1847      const std::string& internal_name,
1848      bool enable);
1849  void RemoveFlagsSwitches(
1850      std::map<std::string, CommandLine::StringType>* switch_list);
1851  void ResetAllFlags(FlagsStorage* flags_storage);
1852  void reset();
1853
1854  // Returns the singleton instance of this class
1855  static FlagsState* GetInstance() {
1856    return Singleton<FlagsState>::get();
1857  }
1858
1859 private:
1860  bool needs_restart_;
1861  std::map<std::string, std::string> flags_switches_;
1862
1863  DISALLOW_COPY_AND_ASSIGN(FlagsState);
1864};
1865
1866// Adds the internal names for the specified experiment to |names|.
1867void AddInternalName(const Experiment& e, std::set<std::string>* names) {
1868  if (e.type == Experiment::SINGLE_VALUE) {
1869    names->insert(e.internal_name);
1870  } else {
1871    DCHECK(e.type == Experiment::MULTI_VALUE ||
1872           e.type == Experiment::ENABLE_DISABLE_VALUE);
1873    for (int i = 0; i < e.num_choices; ++i)
1874      names->insert(e.NameForChoice(i));
1875  }
1876}
1877
1878// Confirms that an experiment is valid, used in a DCHECK in
1879// SanitizeList below.
1880bool ValidateExperiment(const Experiment& e) {
1881  switch (e.type) {
1882    case Experiment::SINGLE_VALUE:
1883      DCHECK_EQ(0, e.num_choices);
1884      DCHECK(!e.choices);
1885      break;
1886    case Experiment::MULTI_VALUE:
1887      DCHECK_GT(e.num_choices, 0);
1888      DCHECK(e.choices);
1889      DCHECK(e.choices[0].command_line_switch);
1890      DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
1891      break;
1892    case Experiment::ENABLE_DISABLE_VALUE:
1893      DCHECK_EQ(3, e.num_choices);
1894      DCHECK(!e.choices);
1895      DCHECK(e.command_line_switch);
1896      DCHECK(e.command_line_value);
1897      DCHECK(e.disable_command_line_switch);
1898      DCHECK(e.disable_command_line_value);
1899      break;
1900    default:
1901      NOTREACHED();
1902  }
1903  return true;
1904}
1905
1906// Removes all experiments from prefs::kEnabledLabsExperiments that are
1907// unknown, to prevent this list to become very long as experiments are added
1908// and removed.
1909void SanitizeList(FlagsStorage* flags_storage) {
1910  std::set<std::string> known_experiments;
1911  for (size_t i = 0; i < num_experiments; ++i) {
1912    DCHECK(ValidateExperiment(experiments[i]));
1913    AddInternalName(experiments[i], &known_experiments);
1914  }
1915
1916  std::set<std::string> enabled_experiments = flags_storage->GetFlags();
1917
1918  std::set<std::string> new_enabled_experiments;
1919  std::set_intersection(
1920      known_experiments.begin(), known_experiments.end(),
1921      enabled_experiments.begin(), enabled_experiments.end(),
1922      std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
1923
1924  if (new_enabled_experiments != enabled_experiments)
1925    flags_storage->SetFlags(new_enabled_experiments);
1926}
1927
1928void GetSanitizedEnabledFlags(
1929    FlagsStorage* flags_storage, std::set<std::string>* result) {
1930  SanitizeList(flags_storage);
1931  *result = flags_storage->GetFlags();
1932}
1933
1934// Variant of GetSanitizedEnabledFlags that also removes any flags that aren't
1935// enabled on the current platform.
1936void GetSanitizedEnabledFlagsForCurrentPlatform(
1937    FlagsStorage* flags_storage, std::set<std::string>* result) {
1938  GetSanitizedEnabledFlags(flags_storage, result);
1939
1940  // Filter out any experiments that aren't enabled on the current platform.  We
1941  // don't remove these from prefs else syncing to a platform with a different
1942  // set of experiments would be lossy.
1943  std::set<std::string> platform_experiments;
1944  int current_platform = GetCurrentPlatform();
1945  for (size_t i = 0; i < num_experiments; ++i) {
1946    if (experiments[i].supported_platforms & current_platform)
1947      AddInternalName(experiments[i], &platform_experiments);
1948#if defined(OS_CHROMEOS)
1949    if (experiments[i].supported_platforms & kOsCrOSOwnerOnly)
1950      AddInternalName(experiments[i], &platform_experiments);
1951#endif
1952  }
1953
1954  std::set<std::string> new_enabled_experiments;
1955  std::set_intersection(
1956      platform_experiments.begin(), platform_experiments.end(),
1957      result->begin(), result->end(),
1958      std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
1959
1960  result->swap(new_enabled_experiments);
1961}
1962
1963// Returns the Value representing the choice data in the specified experiment.
1964Value* CreateChoiceData(const Experiment& experiment,
1965                        const std::set<std::string>& enabled_experiments) {
1966  DCHECK(experiment.type == Experiment::MULTI_VALUE ||
1967         experiment.type == Experiment::ENABLE_DISABLE_VALUE);
1968  ListValue* result = new ListValue;
1969  for (int i = 0; i < experiment.num_choices; ++i) {
1970    DictionaryValue* value = new DictionaryValue;
1971    const std::string name = experiment.NameForChoice(i);
1972    value->SetString("internal_name", name);
1973    value->SetString("description", experiment.DescriptionForChoice(i));
1974    value->SetBoolean("selected", enabled_experiments.count(name) > 0);
1975    result->Append(value);
1976  }
1977  return result;
1978}
1979
1980}  // namespace
1981
1982std::string Experiment::NameForChoice(int index) const {
1983  DCHECK(type == Experiment::MULTI_VALUE ||
1984         type == Experiment::ENABLE_DISABLE_VALUE);
1985  DCHECK_LT(index, num_choices);
1986  return std::string(internal_name) + testing::kMultiSeparator +
1987         base::IntToString(index);
1988}
1989
1990string16 Experiment::DescriptionForChoice(int index) const {
1991  DCHECK(type == Experiment::MULTI_VALUE ||
1992         type == Experiment::ENABLE_DISABLE_VALUE);
1993  DCHECK_LT(index, num_choices);
1994  int description_id;
1995  if (type == Experiment::ENABLE_DISABLE_VALUE) {
1996    const int kEnableDisableDescriptionIds[] = {
1997      IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT,
1998      IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
1999      IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
2000    };
2001    description_id = kEnableDisableDescriptionIds[index];
2002  } else {
2003    description_id = choices[index].description_id;
2004  }
2005  return l10n_util::GetStringUTF16(description_id);
2006}
2007
2008void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
2009                            CommandLine* command_line,
2010                            SentinelsMode sentinels) {
2011  FlagsState::GetInstance()->ConvertFlagsToSwitches(flags_storage,
2012                                                    command_line,
2013                                                    sentinels);
2014}
2015
2016bool AreSwitchesIdenticalToCurrentCommandLine(
2017    const CommandLine& new_cmdline, const CommandLine& active_cmdline) {
2018  std::set<CommandLine::StringType> new_flags =
2019      ExtractFlagsFromCommandLine(new_cmdline);
2020  std::set<CommandLine::StringType> active_flags =
2021      ExtractFlagsFromCommandLine(active_cmdline);
2022
2023  // Needed because std::equal doesn't check if the 2nd set is empty.
2024  if (new_flags.size() != active_flags.size())
2025    return false;
2026
2027  return std::equal(new_flags.begin(), new_flags.end(), active_flags.begin());
2028}
2029
2030void GetFlagsExperimentsData(FlagsStorage* flags_storage,
2031                             FlagAccess access,
2032                             base::ListValue* supported_experiments,
2033                             base::ListValue* unsupported_experiments) {
2034  std::set<std::string> enabled_experiments;
2035  GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
2036
2037  int current_platform = GetCurrentPlatform();
2038
2039  for (size_t i = 0; i < num_experiments; ++i) {
2040    const Experiment& experiment = experiments[i];
2041
2042    DictionaryValue* data = new DictionaryValue();
2043    data->SetString("internal_name", experiment.internal_name);
2044    data->SetString("name",
2045                    l10n_util::GetStringUTF16(experiment.visible_name_id));
2046    data->SetString("description",
2047                    l10n_util::GetStringUTF16(
2048                        experiment.visible_description_id));
2049
2050    ListValue* supported_platforms = new ListValue();
2051    AddOsStrings(experiment.supported_platforms, supported_platforms);
2052    data->Set("supported_platforms", supported_platforms);
2053
2054    switch (experiment.type) {
2055      case Experiment::SINGLE_VALUE:
2056        data->SetBoolean(
2057            "enabled",
2058            enabled_experiments.count(experiment.internal_name) > 0);
2059        break;
2060      case Experiment::MULTI_VALUE:
2061      case Experiment::ENABLE_DISABLE_VALUE:
2062        data->Set("choices", CreateChoiceData(experiment, enabled_experiments));
2063        break;
2064      default:
2065        NOTREACHED();
2066    }
2067
2068    bool supported = (experiment.supported_platforms & current_platform) != 0;
2069#if defined(OS_CHROMEOS)
2070    if (access == kOwnerAccessToFlags &&
2071        (experiment.supported_platforms & kOsCrOSOwnerOnly) != 0) {
2072      supported = true;
2073    }
2074#endif
2075    if (supported)
2076      supported_experiments->Append(data);
2077    else
2078      unsupported_experiments->Append(data);
2079  }
2080}
2081
2082bool IsRestartNeededToCommitChanges() {
2083  return FlagsState::GetInstance()->IsRestartNeededToCommitChanges();
2084}
2085
2086void SetExperimentEnabled(FlagsStorage* flags_storage,
2087                          const std::string& internal_name,
2088                          bool enable) {
2089  FlagsState::GetInstance()->SetExperimentEnabled(flags_storage,
2090                                                  internal_name, enable);
2091}
2092
2093void RemoveFlagsSwitches(
2094    std::map<std::string, CommandLine::StringType>* switch_list) {
2095  FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list);
2096}
2097
2098void ResetAllFlags(FlagsStorage* flags_storage) {
2099  FlagsState::GetInstance()->ResetAllFlags(flags_storage);
2100}
2101
2102int GetCurrentPlatform() {
2103#if defined(OS_MACOSX)
2104  return kOsMac;
2105#elif defined(OS_WIN)
2106  return kOsWin;
2107#elif defined(OS_CHROMEOS)  // Needs to be before the OS_LINUX check.
2108  return kOsCrOS;
2109#elif defined(OS_LINUX) || defined(OS_OPENBSD)
2110  return kOsLinux;
2111#elif defined(OS_ANDROID)
2112  return kOsAndroid;
2113#else
2114#error Unknown platform
2115#endif
2116}
2117
2118void RecordUMAStatistics(FlagsStorage* flags_storage) {
2119  std::set<std::string> flags = flags_storage->GetFlags();
2120  for (std::set<std::string>::iterator it = flags.begin(); it != flags.end();
2121       ++it) {
2122    std::string action("AboutFlags_");
2123    action += *it;
2124    content::RecordComputedAction(action);
2125  }
2126  // Since flag metrics are recorded every startup, add a tick so that the
2127  // stats can be made meaningful.
2128  if (flags.size())
2129    content::RecordAction(UserMetricsAction("AboutFlags_StartupTick"));
2130  content::RecordAction(UserMetricsAction("StartupTick"));
2131}
2132
2133//////////////////////////////////////////////////////////////////////////////
2134// FlagsState implementation.
2135
2136namespace {
2137
2138typedef std::map<std::string, std::pair<std::string, std::string> >
2139    NameToSwitchAndValueMap;
2140
2141void SetFlagToSwitchMapping(const std::string& key,
2142                            const std::string& switch_name,
2143                            const std::string& switch_value,
2144                            NameToSwitchAndValueMap* name_to_switch_map) {
2145  DCHECK(name_to_switch_map->end() == name_to_switch_map->find(key));
2146  (*name_to_switch_map)[key] = std::make_pair(switch_name, switch_value);
2147}
2148
2149void FlagsState::ConvertFlagsToSwitches(FlagsStorage* flags_storage,
2150                                        CommandLine* command_line,
2151                                        SentinelsMode sentinels) {
2152  if (command_line->HasSwitch(switches::kNoExperiments))
2153    return;
2154
2155  std::set<std::string> enabled_experiments;
2156
2157  GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage,
2158                                             &enabled_experiments);
2159
2160  NameToSwitchAndValueMap name_to_switch_map;
2161  for (size_t i = 0; i < num_experiments; ++i) {
2162    const Experiment& e = experiments[i];
2163    if (e.type == Experiment::SINGLE_VALUE) {
2164      SetFlagToSwitchMapping(e.internal_name, e.command_line_switch,
2165                             e.command_line_value, &name_to_switch_map);
2166    } else if (e.type == Experiment::MULTI_VALUE) {
2167      for (int j = 0; j < e.num_choices; ++j) {
2168        SetFlagToSwitchMapping(e.NameForChoice(j),
2169                               e.choices[j].command_line_switch,
2170                               e.choices[j].command_line_value,
2171                               &name_to_switch_map);
2172      }
2173    } else {
2174      DCHECK_EQ(e.type, Experiment::ENABLE_DISABLE_VALUE);
2175      SetFlagToSwitchMapping(e.NameForChoice(0), std::string(), std::string(),
2176                             &name_to_switch_map);
2177      SetFlagToSwitchMapping(e.NameForChoice(1), e.command_line_switch,
2178                             e.command_line_value, &name_to_switch_map);
2179      SetFlagToSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch,
2180                             e.disable_command_line_value, &name_to_switch_map);
2181    }
2182  }
2183
2184  if (sentinels == kAddSentinels) {
2185    command_line->AppendSwitch(switches::kFlagSwitchesBegin);
2186    flags_switches_.insert(
2187        std::pair<std::string, std::string>(switches::kFlagSwitchesBegin,
2188                                            std::string()));
2189  }
2190  for (std::set<std::string>::iterator it = enabled_experiments.begin();
2191       it != enabled_experiments.end();
2192       ++it) {
2193    const std::string& experiment_name = *it;
2194    NameToSwitchAndValueMap::const_iterator name_to_switch_it =
2195        name_to_switch_map.find(experiment_name);
2196    if (name_to_switch_it == name_to_switch_map.end()) {
2197      NOTREACHED();
2198      continue;
2199    }
2200
2201    const std::pair<std::string, std::string>&
2202        switch_and_value_pair = name_to_switch_it->second;
2203
2204    CHECK(!switch_and_value_pair.first.empty());
2205    command_line->AppendSwitchASCII(switch_and_value_pair.first,
2206                                    switch_and_value_pair.second);
2207    flags_switches_[switch_and_value_pair.first] = switch_and_value_pair.second;
2208  }
2209  if (sentinels == kAddSentinels) {
2210    command_line->AppendSwitch(switches::kFlagSwitchesEnd);
2211    flags_switches_.insert(
2212        std::pair<std::string, std::string>(switches::kFlagSwitchesEnd,
2213                                            std::string()));
2214  }
2215}
2216
2217bool FlagsState::IsRestartNeededToCommitChanges() {
2218  return needs_restart_;
2219}
2220
2221void FlagsState::SetExperimentEnabled(FlagsStorage* flags_storage,
2222                                      const std::string& internal_name,
2223                                      bool enable) {
2224  size_t at_index = internal_name.find(testing::kMultiSeparator);
2225  if (at_index != std::string::npos) {
2226    DCHECK(enable);
2227    // We're being asked to enable a multi-choice experiment. Disable the
2228    // currently selected choice.
2229    DCHECK_NE(at_index, 0u);
2230    const std::string experiment_name = internal_name.substr(0, at_index);
2231    SetExperimentEnabled(flags_storage, experiment_name, false);
2232
2233    // And enable the new choice, if it is not the default first choice.
2234    if (internal_name != experiment_name + "@0") {
2235      std::set<std::string> enabled_experiments;
2236      GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
2237      needs_restart_ |= enabled_experiments.insert(internal_name).second;
2238      flags_storage->SetFlags(enabled_experiments);
2239    }
2240    return;
2241  }
2242
2243  std::set<std::string> enabled_experiments;
2244  GetSanitizedEnabledFlags(flags_storage, &enabled_experiments);
2245
2246  const Experiment* e = NULL;
2247  for (size_t i = 0; i < num_experiments; ++i) {
2248    if (experiments[i].internal_name == internal_name) {
2249      e = experiments + i;
2250      break;
2251    }
2252  }
2253  DCHECK(e);
2254
2255  if (e->type == Experiment::SINGLE_VALUE) {
2256    if (enable)
2257      needs_restart_ |= enabled_experiments.insert(internal_name).second;
2258    else
2259      needs_restart_ |= (enabled_experiments.erase(internal_name) > 0);
2260  } else {
2261    if (enable) {
2262      // Enable the first choice.
2263      needs_restart_ |= enabled_experiments.insert(e->NameForChoice(0)).second;
2264    } else {
2265      // Find the currently enabled choice and disable it.
2266      for (int i = 0; i < e->num_choices; ++i) {
2267        std::string choice_name = e->NameForChoice(i);
2268        if (enabled_experiments.find(choice_name) !=
2269            enabled_experiments.end()) {
2270          needs_restart_ = true;
2271          enabled_experiments.erase(choice_name);
2272          // Continue on just in case there's a bug and more than one
2273          // experiment for this choice was enabled.
2274        }
2275      }
2276    }
2277  }
2278
2279  flags_storage->SetFlags(enabled_experiments);
2280}
2281
2282void FlagsState::RemoveFlagsSwitches(
2283    std::map<std::string, CommandLine::StringType>* switch_list) {
2284  for (std::map<std::string, std::string>::const_iterator
2285           it = flags_switches_.begin(); it != flags_switches_.end(); ++it) {
2286    switch_list->erase(it->first);
2287  }
2288}
2289
2290void FlagsState::ResetAllFlags(FlagsStorage* flags_storage) {
2291  needs_restart_ = true;
2292
2293  std::set<std::string> no_experiments;
2294  flags_storage->SetFlags(no_experiments);
2295}
2296
2297void FlagsState::reset() {
2298  needs_restart_ = false;
2299  flags_switches_.clear();
2300}
2301
2302}  // namespace
2303
2304namespace testing {
2305
2306// WARNING: '@' is also used in the html file. If you update this constant you
2307// also need to update the html file.
2308const char kMultiSeparator[] = "@";
2309
2310void ClearState() {
2311  FlagsState::GetInstance()->reset();
2312}
2313
2314void SetExperiments(const Experiment* e, size_t count) {
2315  if (!e) {
2316    experiments = kExperiments;
2317    num_experiments = arraysize(kExperiments);
2318  } else {
2319    experiments = e;
2320    num_experiments = count;
2321  }
2322}
2323
2324const Experiment* GetExperiments(size_t* count) {
2325  *count = num_experiments;
2326  return experiments;
2327}
2328
2329}  // namespace testing
2330
2331}  // namespace about_flags
2332