electron/atom/browser/web_contents_preferences.cc
Cheng Zhao 6df2326a30 Cleanup the static methods of WebContentsPreferences
The static methods are totally unnecessary, and it makes code harder to
understand since we are using different ways to do the same things.
2018-03-22 15:21:56 +09:00

328 lines
12 KiB
C++

// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/web_contents_preferences.h"
#include <algorithm>
#include <string>
#include <vector>
#include "atom/browser/native_window.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "cc/base/switches.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/web_preferences.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
#if defined(OS_WIN)
#include "ui/gfx/switches.h"
#endif
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::WebContentsPreferences);
namespace atom {
// static
std::vector<WebContentsPreferences*> WebContentsPreferences::instances_;
WebContentsPreferences::WebContentsPreferences(
content::WebContents* web_contents,
const mate::Dictionary& web_preferences)
: web_contents_(web_contents) {
v8::Isolate* isolate = web_preferences.isolate();
mate::Dictionary copied(isolate, web_preferences.GetHandle()->Clone());
// Following fields should not be stored.
copied.Delete("embedder");
copied.Delete("isGuest");
copied.Delete("session");
mate::ConvertFromV8(isolate, copied.GetHandle(), &dict_);
web_contents->SetUserData(UserDataKey(), base::WrapUnique(this));
instances_.push_back(this);
// Set WebPreferences defaults onto the JS object
SetDefaultBoolIfUndefined("plugins", false);
SetDefaultBoolIfUndefined(options::kExperimentalFeatures, false);
SetDefaultBoolIfUndefined(options::kExperimentalCanvasFeatures, false);
bool node = SetDefaultBoolIfUndefined(options::kNodeIntegration, true);
SetDefaultBoolIfUndefined(options::kNodeIntegrationInWorker, false);
SetDefaultBoolIfUndefined(options::kWebviewTag, node);
SetDefaultBoolIfUndefined("sandbox", false);
SetDefaultBoolIfUndefined("nativeWindowOpen", false);
SetDefaultBoolIfUndefined(options::kContextIsolation, false);
SetDefaultBoolIfUndefined("javascript", true);
SetDefaultBoolIfUndefined("images", true);
SetDefaultBoolIfUndefined("textAreasAreResizable", true);
SetDefaultBoolIfUndefined("webgl", true);
SetDefaultBoolIfUndefined("webSecurity", true);
SetDefaultBoolIfUndefined("allowRunningInsecureContent", false);
#if defined(OS_MACOSX)
SetDefaultBoolIfUndefined(options::kScrollBounce, false);
#endif
SetDefaultBoolIfUndefined("offscreen", false);
last_dict_.MergeDictionary(&web_preferences_);
}
WebContentsPreferences::~WebContentsPreferences() {
instances_.erase(
std::remove(instances_.begin(), instances_.end(), this),
instances_.end());
}
bool WebContentsPreferences::SetDefaultBoolIfUndefined(
const base::StringPiece& key, bool val) {
bool existing;
if (!dict_.GetBoolean(key, &existing)) {
dict_.SetBoolean(key, val);
return val;
}
return existing;
}
bool WebContentsPreferences::IsEnabled(const base::StringPiece& name,
bool default_value) {
bool bool_value = default_value;
dict_.GetBoolean(name, &bool_value);
return bool_value;
}
void WebContentsPreferences::Merge(const base::DictionaryValue& extend) {
dict_.MergeDictionary(&extend);
}
// static
content::WebContents* WebContentsPreferences::GetWebContentsFromProcessID(
int process_id) {
for (WebContentsPreferences* preferences : instances_) {
content::WebContents* web_contents = preferences->web_contents_;
if (web_contents->GetMainFrame()->GetProcess()->GetID() == process_id)
return web_contents;
}
return nullptr;
}
// static
WebContentsPreferences* WebContentsPreferences::From(
content::WebContents* web_contents) {
if (!web_contents)
return nullptr;
return FromWebContents(web_contents);
}
// static
WebContentsPreferences* WebContentsPreferences::From(int process_id) {
return From(GetWebContentsFromProcessID(process_id));
}
void WebContentsPreferences::AppendCommandLineSwitches(
base::CommandLine* command_line) {
bool b;
// Check if plugins are enabled.
if (dict_.GetBoolean("plugins", &b) && b)
command_line->AppendSwitch(switches::kEnablePlugins);
// Experimental flags.
if (dict_.GetBoolean(options::kExperimentalFeatures, &b) && b)
command_line->AppendSwitch(
::switches::kEnableExperimentalWebPlatformFeatures);
if (dict_.GetBoolean(options::kExperimentalCanvasFeatures, &b) && b)
command_line->AppendSwitch(::switches::kEnableExperimentalCanvasFeatures);
// Check if we have node integration specified.
bool node_integration = true;
dict_.GetBoolean(options::kNodeIntegration, &node_integration);
command_line->AppendSwitchASCII(switches::kNodeIntegration,
node_integration ? "true" : "false");
// Whether to enable node integration in Worker.
if (dict_.GetBoolean(options::kNodeIntegrationInWorker, &b) && b)
command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
// Check if webview tag creation is enabled, default to nodeIntegration value.
// TODO(kevinsawicki): Default to false in 2.0
bool webview_tag = node_integration;
dict_.GetBoolean(options::kWebviewTag, &webview_tag);
command_line->AppendSwitchASCII(switches::kWebviewTag,
webview_tag ? "true" : "false");
// If the `sandbox` option was passed to the BrowserWindow's webPreferences,
// pass `--enable-sandbox` to the renderer so it won't have any node.js
// integration.
if (dict_.GetBoolean("sandbox", &b) && b)
command_line->AppendSwitch(switches::kEnableSandbox);
else if (!command_line->HasSwitch(switches::kEnableSandbox))
command_line->AppendSwitch(::switches::kNoSandbox);
if (dict_.GetBoolean("nativeWindowOpen", &b) && b)
command_line->AppendSwitch(switches::kNativeWindowOpen);
// The preload script.
base::FilePath::StringType preload;
if (dict_.GetString(options::kPreloadScript, &preload)) {
if (base::FilePath(preload).IsAbsolute())
command_line->AppendSwitchNative(switches::kPreloadScript, preload);
else
LOG(ERROR) << "preload script must have absolute path.";
} else if (dict_.GetString(options::kPreloadURL, &preload)) {
// Translate to file path if there is "preload-url" option.
base::FilePath preload_path;
if (net::FileURLToFilePath(GURL(preload), &preload_path))
command_line->AppendSwitchPath(switches::kPreloadScript, preload_path);
else
LOG(ERROR) << "preload url must be file:// protocol.";
}
// Custom args for renderer process
base::Value* customArgs;
if (dict_.Get(options::kCustomArgs, &customArgs) &&
customArgs->is_list()) {
for (const base::Value& customArg : customArgs->GetList()) {
if (customArg.is_string())
command_line->AppendArg(customArg.GetString());
}
}
// Run Electron APIs and preload script in isolated world
if (dict_.GetBoolean(options::kContextIsolation, &b) && b)
command_line->AppendSwitch(switches::kContextIsolation);
// --background-color.
std::string s;
if (dict_.GetString(options::kBackgroundColor, &s))
command_line->AppendSwitchASCII(switches::kBackgroundColor, s);
// --guest-instance-id, which is used to identify guest WebContents.
int guest_instance_id = 0;
if (dict_.GetInteger(options::kGuestInstanceID, &guest_instance_id))
command_line->AppendSwitchASCII(switches::kGuestInstanceID,
base::IntToString(guest_instance_id));
// Pass the opener's window id.
int opener_id;
if (dict_.GetInteger(options::kOpenerID, &opener_id))
command_line->AppendSwitchASCII(switches::kOpenerID,
base::IntToString(opener_id));
#if defined(OS_MACOSX)
// Enable scroll bounce.
if (dict_.GetBoolean(options::kScrollBounce, &b) && b)
command_line->AppendSwitch(switches::kScrollBounce);
#endif
// Custom command line switches.
const base::ListValue* args;
if (dict_.GetList("commandLineSwitches", &args)) {
for (size_t i = 0; i < args->GetSize(); ++i) {
std::string arg;
if (args->GetString(i, &arg) && !arg.empty())
command_line->AppendSwitch(arg);
}
}
// Enable blink features.
if (dict_.GetString(options::kBlinkFeatures, &s))
command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures, s);
// Disable blink features.
if (dict_.GetString(options::kDisableBlinkFeatures, &s))
command_line->AppendSwitchASCII(::switches::kDisableBlinkFeatures, s);
if (guest_instance_id) {
// Webview `document.visibilityState` tracks window visibility so we need
// to let it know if the window happens to be hidden right now.
auto* manager = WebViewManager::GetWebViewManager(web_contents_);
if (manager) {
auto* embedder = manager->GetEmbedder(guest_instance_id);
if (embedder) {
auto* relay = NativeWindowRelay::FromWebContents(embedder);
if (relay) {
auto* window = relay->window.get();
if (window) {
const bool visible = window->IsVisible() && !window->IsMinimized();
if (!visible) {
command_line->AppendSwitch(switches::kHiddenPage);
}
}
}
}
}
}
// We are appending args to a webContents so let's save the current state
// of our preferences object so that during the lifetime of the WebContents
// we can fetch the options used to initally configure the WebContents
last_dict_.Clear();
last_dict_.MergeDictionary(&dict_);
}
void WebContentsPreferences::OverrideWebkitPrefs(
content::WebPreferences* prefs) {
bool b;
if (dict_.GetBoolean("javascript", &b))
prefs->javascript_enabled = b;
if (dict_.GetBoolean("images", &b))
prefs->images_enabled = b;
if (dict_.GetBoolean("textAreasAreResizable", &b))
prefs->text_areas_are_resizable = b;
if (dict_.GetBoolean("webgl", &b)) {
prefs->webgl1_enabled = b;
prefs->webgl2_enabled = b;
}
if (dict_.GetBoolean("webSecurity", &b)) {
prefs->web_security_enabled = b;
prefs->allow_running_insecure_content = !b;
}
if (dict_.GetBoolean("allowRunningInsecureContent", &b))
prefs->allow_running_insecure_content = b;
const base::DictionaryValue* fonts = nullptr;
if (dict_.GetDictionary("defaultFontFamily", &fonts)) {
base::string16 font;
if (fonts->GetString("standard", &font))
prefs->standard_font_family_map[content::kCommonScript] = font;
if (fonts->GetString("serif", &font))
prefs->serif_font_family_map[content::kCommonScript] = font;
if (fonts->GetString("sansSerif", &font))
prefs->sans_serif_font_family_map[content::kCommonScript] = font;
if (fonts->GetString("monospace", &font))
prefs->fixed_font_family_map[content::kCommonScript] = font;
if (fonts->GetString("cursive", &font))
prefs->cursive_font_family_map[content::kCommonScript] = font;
if (fonts->GetString("fantasy", &font))
prefs->fantasy_font_family_map[content::kCommonScript] = font;
}
int size;
if (GetInteger("defaultFontSize", &size))
prefs->default_font_size = size;
if (GetInteger("defaultMonospaceFontSize", &size))
prefs->default_fixed_font_size = size;
if (GetInteger("minimumFontSize", &size))
prefs->minimum_font_size = size;
std::string encoding;
if (dict_.GetString("defaultEncoding", &encoding))
prefs->default_encoding = encoding;
}
bool WebContentsPreferences::GetInteger(const base::StringPiece& attribute_name,
int* val) {
// if it is already an integer, no conversion needed
if (dict_.GetInteger(attribute_name, val))
return true;
std::string str;
if (dict_.GetString(attribute_name, &str))
return base::StringToInt(str, val);
return false;
}
} // namespace atom