1 // Copyright 2013 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 "content/child/runtime_features.h"
6 
7 #include <vector>
8 
9 #include "base/base_switches.h"
10 #include "base/command_line.h"
11 #include "base/feature_list.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/field_trial_params.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "build/build_config.h"
17 #include "cc/base/features.h"
18 #include "content/common/content_navigation_policy.h"
19 #include "content/common/content_switches_internal.h"
20 #include "content/public/common/content_features.h"
21 #include "content/public/common/content_switches.h"
22 #include "device/fido/features.h"
23 #include "device/gamepad/public/cpp/gamepad_features.h"
24 #include "gpu/config/gpu_switches.h"
25 #include "media/base/media_switches.h"
26 #include "net/base/features.h"
27 #include "services/device/public/cpp/device_features.h"
28 #include "services/network/public/cpp/features.h"
29 #include "third_party/blink/public/common/features.h"
30 #include "third_party/blink/public/common/loader/referrer_utils.h"
31 #include "third_party/blink/public/common/switches.h"
32 #include "third_party/blink/public/platform/web_runtime_features.h"
33 #include "ui/accessibility/accessibility_features.h"
34 #include "ui/base/ui_base_features.h"
35 #include "ui/events/blink/blink_features.h"
36 #include "ui/gfx/switches.h"
37 #include "ui/gl/gl_switches.h"
38 #include "ui/native_theme/native_theme_features.h"
39 
40 #if defined(OS_ANDROID)
41 #include "base/android/build_info.h"
42 #endif
43 
44 #if defined(OS_WIN)
45 #include "base/win/windows_version.h"
46 #endif
47 
48 using blink::WebRuntimeFeatures;
49 
50 namespace {
51 
52 // Sets blink runtime features for specific platforms.
53 // This should be a last resort vs runtime_enabled_features.json5.
SetRuntimeFeatureDefaultsForPlatform(const base::CommandLine & command_line)54 void SetRuntimeFeatureDefaultsForPlatform(
55     const base::CommandLine& command_line) {
56   // Please consider setting up feature defaults for different platforms
57   // in runtime_enabled_features.json5 instead of here
58   // TODO(rodneyding): Move the more common cases here
59   // to baseFeature/switch functions below and move more complex
60   // ones to special case functions.
61 #if defined(USE_AURA)
62   WebRuntimeFeatures::EnableCompositedSelectionUpdate(true);
63 #endif
64 #if defined(OS_WIN)
65   if (base::win::GetVersion() >= base::win::Version::WIN10) {
66     WebRuntimeFeatures::EnableWebBluetooth(true);
67     WebRuntimeFeatures::EnableWebBluetoothRemoteCharacteristicNewWriteValue(
68         true);
69   }
70 #endif
71 
72 #if defined(OS_MAC)
73   const bool enable_canvas_2d_image_chromium =
74       command_line.HasSwitch(
75           blink::switches::kEnableGpuMemoryBufferCompositorResources) &&
76       !command_line.HasSwitch(switches::kDisable2dCanvasImageChromium) &&
77       !command_line.HasSwitch(switches::kDisableGpu) &&
78       base::FeatureList::IsEnabled(features::kCanvas2DImageChromium);
79 #else
80   constexpr bool enable_canvas_2d_image_chromium = false;
81 #endif
82   WebRuntimeFeatures::EnableCanvas2dImageChromium(
83       enable_canvas_2d_image_chromium);
84 
85 #if defined(OS_MAC)
86   const bool enable_web_gl_image_chromium =
87       command_line.HasSwitch(
88           blink::switches::kEnableGpuMemoryBufferCompositorResources) &&
89       !command_line.HasSwitch(switches::kDisableWebGLImageChromium) &&
90       !command_line.HasSwitch(switches::kDisableGpu) &&
91       base::FeatureList::IsEnabled(features::kWebGLImageChromium);
92 #else
93   const bool enable_web_gl_image_chromium =
94       command_line.HasSwitch(switches::kEnableWebGLImageChromium);
95 #endif
96   WebRuntimeFeatures::EnableWebGLImageChromium(enable_web_gl_image_chromium);
97 
98 #if defined(OS_ANDROID)
99   if (command_line.HasSwitch(switches::kDisableMediaSessionAPI))
100     WebRuntimeFeatures::EnableMediaSession(false);
101 #endif
102 
103 #if defined(OS_ANDROID)
104   // APIs for Web Authentication are not available prior to N.
105   WebRuntimeFeatures::EnableWebAuth(
106       base::FeatureList::IsEnabled(features::kWebAuth) &&
107       base::android::BuildInfo::GetInstance()->sdk_int() >=
108           base::android::SDK_VERSION_NOUGAT);
109 #else
110   WebRuntimeFeatures::EnableWebAuth(
111       base::FeatureList::IsEnabled(features::kWebAuth));
112 #endif
113 
114 #if defined(OS_ANDROID)
115   WebRuntimeFeatures::EnablePictureInPictureAPI(
116       base::FeatureList::IsEnabled(media::kPictureInPictureAPI));
117 #endif
118 
119 #if defined(OS_ANDROID)
120   if (base::android::BuildInfo::GetInstance()->sdk_int() >=
121       base::android::SDK_VERSION_P) {
122     // Display Cutout is limited to Android P+.
123     WebRuntimeFeatures::EnableDisplayCutoutAPI(true);
124   }
125 #endif
126 
127 #if defined(OS_ANDROID)
128   WebRuntimeFeatures::EnableMediaControlsExpandGesture(
129       base::FeatureList::IsEnabled(media::kMediaControlsExpandGesture));
130 #endif
131 }
132 
133 enum RuntimeFeatureEnableOptions {
134   // - If the base::Feature default is overridden by field trial or command
135   //   line, set Blink feature to the state of the base::Feature;
136   // - Otherwise if the base::Feature is enabled, enable the Blink feature.
137   // - Otherwise no change.
138   kDefault,
139   // Enables the Blink feature when the base::Feature is overridden by field
140   // trial or command line. Otherwise no change. Its difference from kDefault is
141   // that the Blink feature isn't affected by the default state of the
142   // base::Feature. This is useful for Blink origin trial features especially
143   // those implemented in both Chromium and Blink. As origin trial only controls
144   // the Blink features, for now we require the base::Feature to be enabled by
145   // default, but we don't want the default enabled status affect the Blink
146   // feature. See also https://crbug.com/1048656#c10.
147   // This can also be used for features that are enabled by default in Chromium
148   // but not in Blink on all platforms and we want to use the Blink status.
149   // However, we would prefer consistent Chromium and Blink status to this.
150   kSetOnlyIfOverridden,
151 };
152 
153 template <typename T>
154 // Helper class that describes the desired actions for the runtime feature
155 // depending on a check for chromium base::Feature.
156 struct RuntimeFeatureToChromiumFeatureMap {
157   // This can be either an enabler function defined in web_runtime_features.cc
158   // or the string name of the feature in runtime_enabled_features.json5.
159   T feature_enabler;
160   // The chromium base::Feature to check.
161   const base::Feature& chromium_feature;
162   const RuntimeFeatureEnableOptions option = kDefault;
163 };
164 
165 template <typename Enabler>
SetRuntimeFeatureFromChromiumFeature(const base::Feature & chromium_feature,RuntimeFeatureEnableOptions option,const Enabler & enabler)166 void SetRuntimeFeatureFromChromiumFeature(const base::Feature& chromium_feature,
167                                           RuntimeFeatureEnableOptions option,
168                                           const Enabler& enabler) {
169   using FeatureList = base::FeatureList;
170   const bool feature_enabled = FeatureList::IsEnabled(chromium_feature);
171   const bool is_overridden =
172       FeatureList::GetInstance()->IsFeatureOverridden(chromium_feature.name);
173   switch (option) {
174     case kSetOnlyIfOverridden:
175       if (is_overridden)
176         enabler(feature_enabled);
177       break;
178     case kDefault:
179       if (feature_enabled || is_overridden)
180         enabler(feature_enabled);
181       break;
182     default:
183       NOTREACHED();
184   }
185 }
186 
187 // Sets blink runtime features that are either directly
188 // controlled by Chromium base::Feature or are overridden
189 // by base::Feature states.
SetRuntimeFeaturesFromChromiumFeatures()190 void SetRuntimeFeaturesFromChromiumFeatures() {
191   using wf = WebRuntimeFeatures;
192   // To add a runtime feature control, add a new
193   // RuntimeFeatureToChromiumFeatureMap entry here if there is a custom
194   // enabler function defined. Otherwise add the entry with string name
195   // in the next list.
196   const RuntimeFeatureToChromiumFeatureMap<void (*)(bool)>
197       blinkFeatureToBaseFeatureMapping[] =
198   {
199     // TODO(rodneyding): Sort features in alphabetical order
200     {wf::EnableWebUsb, features::kWebUsb},
201     {wf::EnableBlockingFocusWithoutUserActivation,
202      blink::features::kBlockingFocusWithoutUserActivation},
203     {wf::EnableNotificationContentImage, features::kNotificationContentImage,
204      kSetOnlyIfOverridden},
205     {wf::EnablePeriodicBackgroundSync, features::kPeriodicBackgroundSync},
206     {wf::EnableWebXR, features::kWebXr},
207     {wf::EnableWebXRARModule, features::kWebXrArModule},
208     {wf::EnableWebXRHitTest, features::kWebXrHitTest},
209     {wf::EnableWebXRAnchors, features::kWebXrIncubations},
210     {wf::EnableWebXRCameraAccess, features::kWebXrIncubations},
211     {wf::EnableWebXRDepth, features::kWebXrIncubations},
212     {wf::EnableWebXRImageTracking, features::kWebXrIncubations},
213     {wf::EnableWebXRLightEstimation, features::kWebXrIncubations},
214     {wf::EnableWebXRPlaneDetection, features::kWebXrIncubations},
215     {wf::EnableWebXRViewportScale, features::kWebXrIncubations},
216     {wf::EnableUserActivationSameOriginVisibility,
217      features::kUserActivationSameOriginVisibility},
218     {wf::EnableExpensiveBackgroundTimerThrottling,
219      features::kExpensiveBackgroundTimerThrottling},
220     {wf::EnableTimerThrottlingForHiddenFrames,
221      features::kTimerThrottlingForHiddenFrames},
222     {wf::EnableSendBeaconThrowForBlobWithNonSimpleType,
223      features::kSendBeaconThrowForBlobWithNonSimpleType},
224     {wf::EnablePaymentRequest, features::kWebPayments},
225     {wf::EnableSecurePaymentConfirmationDebug,
226      features::kSecurePaymentConfirmationDebug},
227     {wf::EnablePaymentHandlerMinimalUI, features::kWebPaymentsMinimalUI},
228     {wf::EnablePaymentApp, features::kServiceWorkerPaymentApps},
229     {wf::EnablePushSubscriptionChangeEvent,
230      features::kPushSubscriptionChangeEvent},
231     {wf::EnableGenericSensorExtraClasses, features::kGenericSensorExtraClasses},
232     {wf::EnableMediaCastOverlayButton, media::kMediaCastOverlayButton},
233     {wf::EnableLazyInitializeMediaControls,
234      features::kLazyInitializeMediaControls},
235     {wf::EnableMediaEngagementBypassAutoplayPolicies,
236      media::kMediaEngagementBypassAutoplayPolicies},
237     {wf::EnableAllowActivationDelegationAttr,
238      features::kAllowActivationDelegationAttr},
239     {wf::EnableLazyFrameLoading, features::kLazyFrameLoading},
240     {wf::EnableLazyFrameVisibleLoadTimeMetrics,
241      features::kLazyFrameVisibleLoadTimeMetrics},
242     {wf::EnableLazyImageLoading, features::kLazyImageLoading},
243     {wf::EnableLazyImageVisibleLoadTimeMetrics,
244      features::kLazyImageVisibleLoadTimeMetrics},
245     {wf::EnablePictureInPicture, media::kPictureInPicture},
246     {wf::EnableCacheInlineScriptCode, features::kCacheInlineScriptCode},
247     {wf::EnableExperimentalProductivityFeatures,
248      features::kExperimentalProductivityFeatures},
249     {wf::EnableFeaturePolicyForSandbox, features::kFeaturePolicyForSandbox},
250     {wf::EnableAccessibilityExposeDisplayNone,
251      features::kEnableAccessibilityExposeDisplayNone},
252     {wf::EnableAccessibilityExposeHTMLElement,
253      features::kEnableAccessibilityExposeHTMLElement},
254     {wf::EnableAccessibilityExposeIgnoredNodes,
255      features::kEnableAccessibilityExposeIgnoredNodes},
256     {wf::EnableAccessibilityUseAXPositionForDocumentMarkers,
257      features::kUseAXPositionForDocumentMarkers},
258     {wf::EnableAllowSyncXHRInPageDismissal,
259      blink::features::kAllowSyncXHRInPageDismissal},
260     {wf::EnableAutoplayIgnoresWebAudio, media::kAutoplayIgnoreWebAudio},
261     {wf::EnablePortals, blink::features::kPortals, kSetOnlyIfOverridden},
262     {wf::EnableImplicitRootScroller, blink::features::kImplicitRootScroller},
263     {wf::EnableTextFragmentAnchor, blink::features::kTextFragmentAnchor},
264     {wf::EnableBackgroundFetch, features::kBackgroundFetch},
265     {wf::EnableForcedColors, features::kForcedColors},
266     {wf::EnableFractionalScrollOffsets, features::kFractionalScrollOffsets},
267 #if defined(OS_ANDROID)
268     {wf::EnableGetDisplayMedia, features::kUserMediaScreenCapturing},
269 #endif
270     {wf::EnableGetCurrentBrowsingContextMedia,
271      blink::features::kRTCGetCurrentBrowsingContextMedia},
272     {wf::EnableSignedExchangePrefetchCacheForNavigations,
273      features::kSignedExchangePrefetchCacheForNavigations},
274     {wf::EnableSignedExchangeSubresourcePrefetch,
275      features::kSignedExchangeSubresourcePrefetch},
276     {wf::EnableIdleDetection, features::kIdleDetection, kSetOnlyIfOverridden},
277     {wf::EnableSkipTouchEventFilter, blink::features::kSkipTouchEventFilter},
278     {wf::EnableWebOTP, features::kWebOTP, kSetOnlyIfOverridden},
279     {wf::EnableClickPointerEvent, features::kClickPointerEvent},
280     {wf::EnableConsolidatedMovementXY, features::kConsolidatedMovementXY},
281     {wf::EnableCooperativeScheduling, features::kCooperativeScheduling},
282     {wf::EnableMouseSubframeNoImplicitCapture,
283      features::kMouseSubframeNoImplicitCapture},
284     {wf::EnableSubresourceWebBundles, features::kSubresourceWebBundles},
285     {wf::EnableCookieDeprecationMessages, features::kCookieDeprecationMessages},
286     {wf::EnableSameSiteByDefaultCookies,
287      net::features::kSameSiteByDefaultCookies},
288     {wf::EnableCookiesWithoutSameSiteMustBeSecure,
289      net::features::kCookiesWithoutSameSiteMustBeSecure},
290     {wf::EnablePointerLockOptions, features::kPointerLockOptions,
291      kSetOnlyIfOverridden},
292     {wf::EnableDocumentPolicy, features::kDocumentPolicy},
293     {wf::EnableDocumentPolicyNegotiation, features::kDocumentPolicyNegotiation},
294     {wf::EnableScrollUnification, features::kScrollUnification},
295     {wf::EnableNeverSlowMode, features::kNeverSlowMode},
296     {wf::EnableVideoPlaybackQuality, features::kVideoPlaybackQuality},
297     {wf::EnableBrowserVerifiedUserActivationKeyboard,
298      features::kBrowserVerifiedUserActivationKeyboard},
299     {wf::EnableBrowserVerifiedUserActivationMouse,
300      features::kBrowserVerifiedUserActivationMouse},
301     {wf::EnablePercentBasedScrolling, features::kPercentBasedScrolling},
302 #if defined(OS_ANDROID)
303     {wf::EnableWebNfc, features::kWebNfc, kSetOnlyIfOverridden},
304 #endif
305     {wf::EnableInstalledApp, features::kInstalledApp},
306     {wf::EnableWebAuthenticationGetAssertionFeaturePolicy,
307      device::kWebAuthGetAssertionFeaturePolicy},
308     {wf::EnableTransformInterop, blink::features::kTransformInterop},
309     {wf::EnableVideoWakeLockOptimisationHiddenMuted,
310      media::kWakeLockOptimisationHiddenMuted},
311     {wf::EnableMediaFeeds, media::kMediaFeeds},
312     {wf::EnableRestrictGamepadAccess, features::kRestrictGamepadAccess},
313     {wf::EnableCompositingOptimizations,
314      blink::features::kCompositingOptimizations},
315     {wf::EnableConversionMeasurementInfraSupport,
316      features::kConversionMeasurement},
317     {wf::EnableParseUrlProtocolHandler,
318      blink::features::kWebAppEnableProtocolHandlers},
319     {wf::EnableWebID, features::kWebID},
320     {wf::EnableWheelEventRegions, features::kWheelEventRegions},
321   };
322   for (const auto& mapping : blinkFeatureToBaseFeatureMapping) {
323     SetRuntimeFeatureFromChromiumFeature(
324         mapping.chromium_feature, mapping.option, mapping.feature_enabler);
325   }
326 
327   // TODO(crbug/832393): Cleanup the inconsistency between custom WRF enabler
328   // function and using feature string name with EnableFeatureFromString.
329   const RuntimeFeatureToChromiumFeatureMap<const char*>
330       runtimeFeatureNameToChromiumFeatureMapping[] = {
331           {"AddressSpace", features::kBlockInsecurePrivateNetworkRequests},
332           {"AllowContentInitiatedDataUrlNavigations",
333            features::kAllowContentInitiatedDataUrlNavigations},
334           {"AndroidDownloadableFontsMatching",
335            features::kAndroidDownloadableFontsMatching},
336           {"AudioWorkletRealtimeThread",
337            blink::features::kAudioWorkletRealtimeThread},
338           {"BlockCredentialedSubresources",
339            features::kBlockCredentialedSubresources},
340           {"BlockHTMLParserOnStyleSheets",
341            blink::features::kBlockHTMLParserOnStyleSheets},
342           {"CSSColorSchemeUARendering", features::kCSSColorSchemeUARendering},
343           {"CSSReducedFontLoadingLayoutInvalidations",
344            blink::features::kCSSReducedFontLoadingLayoutInvalidations},
345           {"CSSMatchedPropertiesCacheDependencies",
346            blink::features::kCSSMatchedPropertiesCacheDependencies},
347           {"FeaturePolicyForClientHints",
348            features::kFeaturePolicyForClientHints},
349           {"EditingNG", blink::features::kEditingNG},
350           {"FlexAspectRatio", blink::features::kFlexAspectRatio},
351           {"FontAccess", blink::features::kFontAccess},
352           {"FontSrcLocalMatching", features::kFontSrcLocalMatching},
353           {"ForceSynchronousHTMLParsing",
354            blink::features::kForceSynchronousHTMLParsing},
355           {"IgnoreCrossOriginWindowWhenNamedAccessOnWindow",
356            blink::features::kIgnoreCrossOriginWindowWhenNamedAccessOnWindow},
357           {"LangClientHintHeader", features::kLangClientHintHeader},
358           {"LayoutNG", blink::features::kLayoutNG},
359           {"LayoutNGFieldset", blink::features::kLayoutNGFieldset},
360           {"LayoutNGFragmentItem", blink::features::kFragmentItem},
361           {"LegacyWindowsDWriteFontFallback",
362            features::kLegacyWindowsDWriteFontFallback},
363           {"LinkDisabledNewSpecBehavior",
364            blink::features::kLinkDisabledNewSpecBehavior},
365           {"OriginPolicy", features::kOriginPolicy},
366           {"OriginIsolationHeader", features::kOriginIsolationHeader},
367           {"ParentNodeReplaceChildren",
368            blink::features::kParentNodeReplaceChildren},
369           {"RawClipboard", blink::features::kRawClipboard},
370           {"StorageAccessAPI", blink::features::kStorageAccessAPI},
371           {"TargetBlankImpliesNoOpener",
372            blink::features::kTargetBlankImpliesNoOpener},
373           {"TrustedDOMTypes", features::kTrustedDOMTypes},
374           {"UserAgentClientHint", features::kUserAgentClientHint},
375           {"WebAppManifestDisplayOverride",
376            features::kWebAppManifestDisplayOverride},
377           {"WebAppWindowControlsOverlay",
378            features::kWebAppWindowControlsOverlay},
379           {"WebXRMultiGpu", blink::features::kWebXrMultiGpu},
380       };
381   for (const auto& mapping : runtimeFeatureNameToChromiumFeatureMapping) {
382     SetRuntimeFeatureFromChromiumFeature(
383         mapping.chromium_feature, mapping.option, [&mapping](bool enabled) {
384           wf::EnableFeatureFromString(mapping.feature_enabler, enabled);
385         });
386   }
387 }
388 
389 // Helper class that describes the desired enable/disable action
390 // for a runtime feature when a command line switch exists.
391 struct SwitchToFeatureMap {
392   // The enabler function defined in web_runtime_features.cc.
393   void (*feature_enabler)(bool);
394   // The switch to check for on command line.
395   const char* switch_name;
396   // This is the desired state for the runtime feature if the
397   // switch exists on command line.
398   bool target_enabled_state;
399 };
400 
401 // Sets blink runtime features controlled by command line switches.
SetRuntimeFeaturesFromCommandLine(const base::CommandLine & command_line)402 void SetRuntimeFeaturesFromCommandLine(const base::CommandLine& command_line) {
403   // To add a new switch-controlled runtime feature, add a new
404   // SwitchToFeatureMap entry to the initializer list below.
405   // Note: command line switches are now discouraged, please consider
406   // using base::Feature instead.
407   // https://chromium.googlesource.com/chromium/src/+/refs/heads/master/docs/configuration.md#switches
408   using wrf = WebRuntimeFeatures;
409   const SwitchToFeatureMap switchToFeatureMapping[] = {
410       // Stable Features
411       {wrf::EnablePermissionsAPI, switches::kDisablePermissionsAPI, false},
412       {wrf::EnablePresentationAPI, switches::kDisablePresentationAPI, false},
413       {wrf::EnableRemotePlaybackAPI, switches::kDisableRemotePlaybackAPI,
414        false},
415       {wrf::EnableTargetBlankImpliesNoOpener,
416        switches::kDisableTargetBlankImpliesNoOpener, false},
417       {wrf::EnableTimerThrottlingForBackgroundTabs,
418        switches::kDisableBackgroundTimerThrottling, false},
419       // End of Stable Features
420       {wrf::EnableDatabase, switches::kDisableDatabases, false},
421       {wrf::EnableNotifications, switches::kDisableNotifications, false},
422       // Chrome's Push Messaging implementation relies on Web Notifications.
423       {wrf::EnablePushMessaging, switches::kDisableNotifications, false},
424       {wrf::EnableSharedWorker, switches::kDisableSharedWorkers, false},
425       {wrf::EnableScriptedSpeechRecognition, switches::kDisableSpeechAPI,
426        false},
427       {wrf::EnableScriptedSpeechSynthesis, switches::kDisableSpeechAPI, false},
428       {wrf::EnableScriptedSpeechSynthesis, switches::kDisableSpeechSynthesisAPI,
429        false},
430       {wrf::EnableFileSystem, switches::kDisableFileSystem, false},
431       {wrf::EnableWebGLDraftExtensions, switches::kEnableWebGLDraftExtensions,
432        true},
433       {wrf::EnableAutomationControlled, switches::kEnableAutomation, true},
434       {wrf::EnableAutomationControlled, switches::kHeadless, true},
435       {wrf::EnableAutomationControlled, switches::kRemoteDebuggingPipe, true},
436       {wrf::ForceOverlayFullscreenVideo, switches::kForceOverlayFullscreenVideo,
437        true},
438       {wrf::EnablePreciseMemoryInfo, switches::kEnablePreciseMemoryInfo, true},
439       {wrf::EnableNetInfoDownlinkMax,
440        switches::kEnableNetworkInformationDownlinkMax, true},
441       {wrf::EnableWebGPU, switches::kEnableUnsafeWebGPU, true},
442       {wrf::EnableTextFragmentAnchor, switches::kDisableScrollToTextFragment,
443        false},
444       {wrf::EnableAccessibilityObjectModel,
445        switches::kEnableAccessibilityObjectModel, true},
446       {wrf::EnableAllowSyncXHRInPageDismissal,
447        switches::kAllowSyncXHRInPageDismissal, true},
448   };
449   for (const auto& mapping : switchToFeatureMapping) {
450     if (command_line.HasSwitch(mapping.switch_name))
451       mapping.feature_enabler(mapping.target_enabled_state);
452   }
453 
454   // Set EnableAutomationControlled if the caller passes
455   // --remote-debugging-port=0 on the command line. This means
456   // the caller has requested an ephemeral port which is how ChromeDriver
457   // launches the browser by default.
458   // If the caller provides a specific port number, this is
459   // more likely for attaching a debugger, so we should leave
460   // EnableAutomationControlled unset to ensure the browser behaves as it does
461   // when not under automation control.
462   if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
463     std::string port_str =
464         command_line.GetSwitchValueASCII(::switches::kRemoteDebuggingPort);
465     int port;
466     if (base::StringToInt(port_str, &port) && port == 0) {
467       WebRuntimeFeatures::EnableAutomationControlled(true);
468     }
469   }
470 }
471 
472 // Sets blink runtime features controlled by FieldTrial parameter values.
SetRuntimeFeaturesFromFieldTrialParams()473 void SetRuntimeFeaturesFromFieldTrialParams() {
474   // Automatic lazy frame loading by default is enabled and restricted to users
475   // with Lite Mode (aka Data Saver) turned on. Note that in practice, this also
476   // restricts automatic lazy loading by default to Android, since Lite Mode is
477   // only accessible through UI on Android.
478   WebRuntimeFeatures::EnableAutomaticLazyFrameLoading(
479       base::GetFieldTrialParamByFeatureAsBool(
480           features::kLazyFrameLoading, "automatic-lazy-load-frames-enabled",
481           true));
482   WebRuntimeFeatures::EnableRestrictAutomaticLazyFrameLoadingToDataSaver(
483       base::GetFieldTrialParamByFeatureAsBool(
484           features::kLazyFrameLoading,
485           "restrict-lazy-load-frames-to-data-saver-only", true));
486   WebRuntimeFeatures::EnableAutoLazyLoadOnReloads(
487       base::GetFieldTrialParamByFeatureAsBool(
488           features::kLazyFrameLoading, "enable-lazy-load-on-reload", false));
489 
490   // Automatic lazy image loading by default is enabled and restricted to users
491   // with Lite Mode (aka Data Saver) turned on. Note that in practice, this also
492   // restricts automatic lazy loading by default to Android, since Lite Mode is
493   // only accessible through UI on Android.
494   WebRuntimeFeatures::EnableAutomaticLazyImageLoading(
495       base::GetFieldTrialParamByFeatureAsBool(
496           features::kLazyImageLoading, "automatic-lazy-load-images-enabled",
497           true));
498   WebRuntimeFeatures::EnableRestrictAutomaticLazyImageLoadingToDataSaver(
499       base::GetFieldTrialParamByFeatureAsBool(
500           features::kLazyImageLoading,
501           "restrict-lazy-load-images-to-data-saver-only", true));
502 }
503 
504 // Sets blink runtime features that depend on a combination
505 // of args rather than a single check of base::Feature or switch.
506 // This can be a combination of both or custom checking logic
507 // not covered by other functions. In short, this should be used
508 // as a last resort.
SetCustomizedRuntimeFeaturesFromCombinedArgs(const base::CommandLine & command_line)509 void SetCustomizedRuntimeFeaturesFromCombinedArgs(
510     const base::CommandLine& command_line) {
511   // CAUTION: Only add custom enabling logic here if it cannot
512   // be covered by the other functions.
513 
514   if (!command_line.HasSwitch(switches::kDisableYUVImageDecoding) &&
515       base::FeatureList::IsEnabled(
516           blink::features::kDecodeJpeg420ImagesToYUV)) {
517     WebRuntimeFeatures::EnableDecodeJpeg420ImagesToYUV(true);
518   }
519   if (!command_line.HasSwitch(switches::kDisableYUVImageDecoding) &&
520       base::FeatureList::IsEnabled(
521           blink::features::kDecodeLossyWebPImagesToYUV)) {
522     WebRuntimeFeatures::EnableDecodeLossyWebPImagesToYUV(true);
523   }
524 
525   WebRuntimeFeatures::EnableSharedArrayBuffer(
526       base::FeatureList::IsEnabled(features::kSharedArrayBuffer) ||
527       base::FeatureList::IsEnabled(features::kWebAssemblyThreads));
528 
529   // These checks are custom wrappers around base::FeatureList::IsEnabled
530   // They're moved here to distinguish them from actual base checks
531   WebRuntimeFeatures::EnableOverlayScrollbars(ui::IsOverlayScrollbarEnabled());
532 
533   if (base::FeatureList::IsEnabled(blink::features::kFileHandlingAPI)) {
534     WebRuntimeFeatures::EnableFeatureFromString("FileHandling", true);
535   }
536 
537   // TODO(rodneyding): This is a rare case for a stable feature
538   // Need to investigate more to determine whether to refactor it.
539   if (command_line.HasSwitch(switches::kDisableV8IdleTasks))
540     WebRuntimeFeatures::EnableV8IdleTasks(false);
541   else
542     WebRuntimeFeatures::EnableV8IdleTasks(true);
543 
544   WebRuntimeFeatures::EnableBackForwardCache(
545       content::IsBackForwardCacheEnabled());
546 
547   if (base::FeatureList::IsEnabled(features::kDirectSockets))
548     WebRuntimeFeatures::EnableDirectSockets(true);
549 
550   if (base::FeatureList::IsEnabled(
551           blink::features::kAppCacheRequireOriginTrial)) {
552     // The kAppCacheRequireOriginTrial is a flag that controls whether or not
553     // the renderer AppCache api and backend is gated by an origin trial.  If
554     // on, then AppCache is disabled but can be re-enabled by the origin trial.
555     // The origin trial will not turn on the feature if the base::Feature
556     // AppCache is disabled.
557     WebRuntimeFeatures::EnableFeatureFromString("AppCache", false);
558   } else {
559     // If the origin trial is not required, then the kAppCache feature /
560     // about:flag is a disable-only kill switch to allow developers to test
561     // their application with AppCache fully disabled.
562     if (!base::FeatureList::IsEnabled(blink::features::kAppCache))
563       WebRuntimeFeatures::EnableFeatureFromString("AppCache", false);
564   }
565 
566   if (base::FeatureList::IsEnabled(network::features::kTrustTokens)) {
567     // See https://bit.ly/configuring-trust-tokens.
568     using network::features::TrustTokenOriginTrialSpec;
569     switch (
570         network::features::kTrustTokenOperationsRequiringOriginTrial.Get()) {
571       case TrustTokenOriginTrialSpec::kOriginTrialNotRequired:
572         // Setting TrustTokens=true enables the Trust Tokens interface;
573         // TrustTokensAlwaysAllowIssuance disables a runtime check during
574         // issuance that the origin trial is active (see
575         // blink/.../trust_token_issuance_authorization.h).
576         WebRuntimeFeatures::EnableTrustTokens(true);
577         WebRuntimeFeatures::EnableTrustTokensAlwaysAllowIssuance(true);
578         break;
579       case TrustTokenOriginTrialSpec::kAllOperationsRequireOriginTrial:
580         // The origin trial itself will be responsible for enabling the
581         // TrustTokens RuntimeEnabledFeature.
582         WebRuntimeFeatures::EnableTrustTokens(false);
583         WebRuntimeFeatures::EnableTrustTokensAlwaysAllowIssuance(false);
584         break;
585       case TrustTokenOriginTrialSpec::kOnlyIssuanceRequiresOriginTrial:
586         // At issuance, a runtime check will be responsible for checking that
587         // the origin trial is present.
588         WebRuntimeFeatures::EnableTrustTokens(true);
589         WebRuntimeFeatures::EnableTrustTokensAlwaysAllowIssuance(false);
590         break;
591     }
592   }
593 }
594 
595 // Ensures that the various ways of enabling/disabling features do not produce
596 // an invalid configuration.
ResolveInvalidConfigurations()597 void ResolveInvalidConfigurations() {
598   // Portals cannot be enabled without the support of the browser process.
599   if (!base::FeatureList::IsEnabled(blink::features::kPortals)) {
600     LOG_IF(WARNING, WebRuntimeFeatures::IsPortalsEnabled())
601         << "Portals cannot be enabled in this configuration. Use --"
602         << switches::kEnableFeatures << "=" << blink::features::kPortals.name
603         << " instead.";
604     WebRuntimeFeatures::EnablePortals(false);
605   }
606 }
607 
608 }  // namespace
609 
610 namespace content {
611 
SetRuntimeFeaturesDefaultsAndUpdateFromArgs(const base::CommandLine & command_line)612 void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
613     const base::CommandLine& command_line) {
614   // Sets experimental features.
615   bool enable_experimental_web_platform_features =
616       command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures);
617   bool enable_blink_test_features =
618       command_line.HasSwitch(switches::kEnableBlinkTestFeatures);
619 
620   if (enable_blink_test_features) {
621     enable_experimental_web_platform_features = true;
622     WebRuntimeFeatures::EnableTestOnlyFeatures(true);
623   }
624 
625   if (enable_experimental_web_platform_features)
626     WebRuntimeFeatures::EnableExperimentalFeatures(true);
627 
628   SetRuntimeFeatureDefaultsForPlatform(command_line);
629 
630   // Sets origin trial features.
631   if (command_line.HasSwitch(
632           switches::kDisableOriginTrialControlledBlinkFeatures)) {
633     WebRuntimeFeatures::EnableOriginTrialControlledFeatures(false);
634   }
635 
636   // TODO(rodneyding): add doc explaining ways to add new runtime features
637   // controls in the following functions.
638 
639   SetRuntimeFeaturesFromChromiumFeatures();
640 
641   SetRuntimeFeaturesFromCommandLine(command_line);
642 
643   SetRuntimeFeaturesFromFieldTrialParams();
644 
645   SetCustomizedRuntimeFeaturesFromCombinedArgs(command_line);
646 
647   // Enable explicitly enabled features, and then disable explicitly disabled
648   // ones.
649   for (const std::string& feature :
650        FeaturesFromSwitch(command_line, switches::kEnableBlinkFeatures)) {
651     WebRuntimeFeatures::EnableFeatureFromString(feature, true);
652   }
653   for (const std::string& feature :
654        FeaturesFromSwitch(command_line, switches::kDisableBlinkFeatures)) {
655     WebRuntimeFeatures::EnableFeatureFromString(feature, false);
656   }
657 
658   ResolveInvalidConfigurations();
659 }
660 
661 }  // namespace content
662