#include "fuchsia_web/webengine/browser/web_engine_config.h"
#include <string_view>
#include <vector>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/embedder_support/switches.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/viz/common/features.h"
#include "components/viz/common/switches.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "fuchsia_web/webengine/switches.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_switches.h"
#include "media/base/media_switches.h"
#include "services/network/public/cpp/features.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/widevine/cdm/buildflags.h"
#include "ui/display/display_switches.h"
#include "ui/gl/gl_switches.h"
#include "ui/ozone/public/ozone_switches.h"
#include "url/gurl.h"
namespace {
bool IsProtectedMemorySupported() {
#if defined(ARCH_CPU_ARM64)
return true;
#else
return false;
#endif
}
void AppendToSwitch(std::string_view switch_name,
std::string_view value,
base::CommandLine* command_line,
std::string_view separator = ",") {
if (!command_line->HasSwitch(switch_name)) {
command_line->AppendSwitchNative(switch_name, value);
return;
}
std::string new_value = base::StrCat(
{command_line->GetSwitchValueASCII(switch_name), separator, value});
command_line->RemoveSwitch(switch_name);
command_line->AppendSwitchNative(switch_name, new_value);
}
bool AddCommandLineArgsFromConfig(const base::Value::Dict& config,
base::CommandLine* command_line) {
const base::Value::Dict* args = config.FindDict("command-line-args");
if (!args) {
return true;
}
static const std::string_view kAllowedArgs[] = {
blink::switches::kGpuRasterizationMSAASampleCount,
blink::switches::kMinHeightForGpuRasterTile,
blink::switches::kForceGpuMemAvailableMb,
switches::kEnableClippedImageScaling,
switches::kEnableGpuBenchmarking,
embedder_support::kOriginTrialPublicKey,
embedder_support::kOriginTrialDisabledFeatures,
switches::kDisableFeatures,
switches::kDisableGpuWatchdog,
switches::kDisableQuic,
switches::kDisableMipmapGeneration,
switches::kEnableCastStreamingReceiver,
switches::kEnableFeatures,
switches::kEnableLowEndDeviceMode,
switches::kForceDeviceScaleFactor,
switches::kForceGpuMemDiscardableLimitMb,
switches::kForceMaxTextureSize,
switches::kGoogleApiKey,
switches::kInProcessGPU,
switches::kMaxDecodedImageSizeMb,
switches::kMinVideoDecoderOutputBufferSize,
switches::kOzonePlatform,
switches::kRendererProcessLimit,
switches::kUseCmdDecoder,
switches::kV,
switches::kVModule,
switches::kVulkanHeapMemoryLimitMb,
switches::kVulkanSyncCpuMemoryLimitMb,
switches::kWebglAntialiasingMode,
switches::kWebglMSAASampleCount,
switches::kProtectedServiceWorkers,
};
for (const auto arg : *args) {
if (!base::Contains(kAllowedArgs, arg.first)) {
LOG(WARNING) << "Unknown command-line arg: '" << arg.first
<< "'. Config file and WebEngine version may not match.";
continue;
}
if (arg.first == switches::kEnableFeatures ||
arg.first == switches::kDisableFeatures) {
if (!arg.second.is_string()) {
LOG(ERROR) << "Config command-line arg must be a string: " << arg.first;
return false;
}
AppendToSwitch(arg.first, arg.second.GetString(), command_line);
continue;
}
if (command_line->HasSwitch(arg.first)) {
continue;
}
if (arg.second.is_none()) {
command_line->AppendSwitch(arg.first);
continue;
}
if (arg.second.is_string()) {
command_line->AppendSwitchNative(arg.first, arg.second.GetString());
continue;
}
LOG(ERROR) << "Config command-line arg must be a string: " << arg.first;
return false;
}
AppendToSwitch(switches::kDisableFeatures, features::kWebRtcHWDecoding.name,
command_line);
AppendToSwitch(switches::kDisableFeatures,
network::features::kLocalNetworkAccessChecks.name,
command_line);
return true;
}
std::vector<ContentSettingsPattern> GetProtectedServiceWorkers() {
const auto tokens = base::SplitString(
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProtectedServiceWorkers),
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::vector<ContentSettingsPattern> patterns;
for (const auto& token : tokens) {
patterns.push_back(ContentSettingsPattern::FromString(token));
}
return patterns;
}
}
bool UpdateCommandLineFromConfigFile(const base::Value::Dict& config,
base::CommandLine* command_line) {
CHECK(!base::FieldTrialList::GetInstance());
if (!AddCommandLineArgsFromConfig(config, command_line)) {
return false;
}
const bool playready_enabled =
command_line->HasSwitch(switches::kPlayreadyKeySystem);
const bool widevine_enabled =
command_line->HasSwitch(switches::kEnableWidevine);
const bool force_protected_video_buffers =
IsProtectedMemorySupported() &&
config.FindBool("force-protected-video-buffers").value_or(false);
const bool enable_protected_graphics =
playready_enabled || widevine_enabled || force_protected_video_buffers;
if (enable_protected_graphics) {
command_line->AppendSwitch(switches::kEnableVulkanProtectedMemory);
command_line->AppendSwitch(switches::kEnableProtectedVideoBuffers);
}
if (force_protected_video_buffers) {
command_line->AppendSwitch(switches::kForceProtectedVideoOutputBuffers);
}
command_line->AppendSwitchASCII(switches::kEnableHardwareOverlays,
"underlay");
std::optional<int> max_old_space =
config.FindInt("js-heap-max-old-space-size");
if (max_old_space) {
AppendToSwitch(
blink::switches::kJavaScriptFlags,
"--max_old_space_size=" + base::NumberToString(max_old_space.value()),
command_line, " ");
}
std::optional<int> max_semi_space =
config.FindInt("js-heap-max-semi-space-size");
if (max_semi_space) {
AppendToSwitch(
blink::switches::kJavaScriptFlags,
"--max_semi_space_size=" + base::NumberToString(max_semi_space.value()),
command_line, " ");
}
return true;
}
bool IsProtectedServiceWorker(const GURL& scope) {
static const auto protected_service_workers = GetProtectedServiceWorkers();
for (const auto& pattern : protected_service_workers) {
if (pattern.Matches(scope)) {
return true;
}
}
return false;
}
bool AllowNotifications(const GURL& origin) {
return IsProtectedServiceWorker(origin);
}