diff --git a/.travis.yml b/.travis.yml index 8b4343138994..75a5a26c6c71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,8 +19,7 @@ matrix: - os: linux env: TARGET_ARCH=ia32 allow_failures: - - env: TARGET_ARCH=arm - - env: TARGET_ARCH=ia32 + - os: osx script: './script/cibuild' diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 444ce0b4c821..e4d4c531e5a3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,24 +1,46 @@ -# Contributor Code of Conduct +# Contributor Covenant Code of Conduct -As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. +## Our Pledge -We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members Examples of unacceptable behavior by participants include: -- The use of sexualized language or imagery -- Personal attacks -- Trolling or insulting/derogatory comments -- Public or private harassment -- Publishing other's private information, such as physical or electronic addresses, without explicit permission -- Other unethical or unprofessional conduct +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. +## Scope -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. +## Enforcement -This Code of Conduct is adapted from the Contributor Covenant, version 1.3.0, available from http://contributor-covenant.org/version/1/3/0/ +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [electron@github.com](mailto:electron@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/README-ko.md b/README-ko.md index 5f809bbf05f9..bb7684e9d53a 100644 --- a/README-ko.md +++ b/README-ko.md @@ -1,7 +1,7 @@ [![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) [![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/qtmod45u0cc1ouov/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/kvxe4byi7jcxbe26/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) [![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron#info=devDependencies) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) diff --git a/README.md b/README.md index 5e891e5dd640..b1e0d6b1b9a9 100644 --- a/README.md +++ b/README.md @@ -5,19 +5,17 @@ [![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron#info=devDependencies) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) -:zap: *Formerly known as Atom Shell* :zap: - The Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and -[Chromium](http://www.chromium.org) and is used in the [Atom -editor](https://github.com/atom/atom). +[Chromium](http://www.chromium.org) and is used by the [Atom +editor](https://github.com/atom/atom) and many other [apps](http://electron.atom.io/apps). Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important announcements. This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable -behavior to atom@github.com. +behavior to electron@github.com. ## Downloads diff --git a/appveyor.yml b/appveyor.yml index 0fa0c0d9bddd..b093d2a2126e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,6 +2,8 @@ # http://www.appveyor.com/docs/appveyor-yml version: "{build}" +os: Visual Studio 2015 + init: - git config --global core.autocrlf input @@ -10,7 +12,7 @@ platform: - x64 install: - - cmd: SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH% + - cmd: SET PATH=C:\Program Files (x86)\MSBuild\14.0\bin\;%PATH% - cmd: SET PATH=C:\python27;%PATH% - cmd: python script/cibuild diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc index 25e9d0f1932a..40a6e1f5268d 100644 --- a/atom/app/atom_content_client.cc +++ b/atom/app/atom_content_client.cc @@ -89,11 +89,9 @@ content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path, // Add the supported codecs as if they came from the component manifest. std::vector codecs; - codecs.push_back(kCdmSupportedCodecVorbis); codecs.push_back(kCdmSupportedCodecVp8); codecs.push_back(kCdmSupportedCodecVp9); #if defined(USE_PROPRIETARY_CODECS) - codecs.push_back(kCdmSupportedCodecAac); codecs.push_back(kCdmSupportedCodecAvc1); #endif // defined(USE_PROPRIETARY_CODECS) std::string codec_string = base::JoinString( @@ -126,7 +124,7 @@ void ConvertStringWithSeparatorToVector(std::vector* vec, void AddPepperFlashFromCommandLine( std::vector* plugins) { auto command_line = base::CommandLine::ForCurrentProcess(); - auto flash_path = command_line->GetSwitchValueNative( + base::FilePath flash_path = command_line->GetSwitchValuePath( switches::kPpapiFlashPath); if (flash_path.empty()) return; @@ -134,20 +132,19 @@ void AddPepperFlashFromCommandLine( auto flash_version = command_line->GetSwitchValueASCII( switches::kPpapiFlashVersion); - plugins->push_back( - CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); + plugins->push_back(CreatePepperFlashInfo(flash_path, flash_version)); } #if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) void AddWidevineCdmFromCommandLine( std::vector* plugins) { auto command_line = base::CommandLine::ForCurrentProcess(); - auto widevine_cdm_path = command_line->GetSwitchValueNative( + base::FilePath widevine_cdm_path = command_line->GetSwitchValuePath( switches::kWidevineCdmPath); if (widevine_cdm_path.empty()) return; - if (!base::PathExists(base::FilePath(widevine_cdm_path))) + if (!base::PathExists(widevine_cdm_path)) return; auto widevine_cdm_version = command_line->GetSwitchValueASCII( @@ -155,7 +152,7 @@ void AddWidevineCdmFromCommandLine( if (widevine_cdm_version.empty()) return; - plugins->push_back(CreateWidevineCdmInfo(base::FilePath(widevine_cdm_path), + plugins->push_back(CreateWidevineCdmInfo(widevine_cdm_path, widevine_cdm_version)); } #endif @@ -182,14 +179,8 @@ base::string16 AtomContentClient::GetLocalizedString(int message_id) const { void AtomContentClient::AddAdditionalSchemes( std::vector* standard_schemes, + std::vector* referrer_schemes, std::vector* savable_schemes) { - std::vector schemes; - ConvertStringWithSeparatorToVector(&schemes, ",", - switches::kRegisterStandardSchemes); - if (!schemes.empty()) { - for (const std::string& scheme : schemes) - standard_schemes->push_back({scheme.c_str(), url::SCHEME_WITHOUT_PORT}); - } standard_schemes->push_back({"chrome-extension", url::SCHEME_WITHOUT_PORT}); } diff --git a/atom/app/atom_content_client.h b/atom/app/atom_content_client.h index 33dbe19d990e..f31a14605723 100644 --- a/atom/app/atom_content_client.h +++ b/atom/app/atom_content_client.h @@ -25,6 +25,7 @@ class AtomContentClient : public brightray::ContentClient { base::string16 GetLocalizedString(int message_id) const override; void AddAdditionalSchemes( std::vector* standard_schemes, + std::vector* referrer_schemes, std::vector* savable_schemes) override; void AddPepperPlugins( std::vector* plugins) override; diff --git a/atom/app/atom_main.cc b/atom/app/atom_main.cc index cbd0a85d5768..1e69ba4ba839 100644 --- a/atom/app/atom_main.cc +++ b/atom/app/atom_main.cc @@ -15,6 +15,7 @@ #include "atom/app/atom_main_delegate.h" #include "atom/common/crash_reporter/win/crash_service_main.h" #include "base/environment.h" +#include "base/process/launch.h" #include "base/win/windows_version.h" #include "content/public/app/sandbox_helper_win.h" #include "sandbox/win/src/sandbox_types.h" @@ -34,7 +35,6 @@ namespace { const char* kRunAsNode = "ELECTRON_RUN_AS_NODE"; -const char* kOldRunAsNode = "ATOM_SHELL_INTERNAL_RUN_AS_NODE"; bool IsEnvSet(const char* name) { #if defined(OS_WIN) @@ -47,50 +47,6 @@ bool IsEnvSet(const char* name) { #endif } -bool IsRunAsNode() { - return IsEnvSet(kRunAsNode) || IsEnvSet(kOldRunAsNode); -} - -#if defined(OS_WIN) -// Win8.1 supports monitor-specific DPI scaling. -bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) { - typedef HRESULT(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS); - SetProcessDpiAwarenessPtr set_process_dpi_awareness_func = - reinterpret_cast( - GetProcAddress(GetModuleHandleA("user32.dll"), - "SetProcessDpiAwarenessInternal")); - if (set_process_dpi_awareness_func) { - HRESULT hr = set_process_dpi_awareness_func(value); - if (SUCCEEDED(hr)) { - VLOG(1) << "SetProcessDpiAwareness succeeded."; - return true; - } else if (hr == E_ACCESSDENIED) { - LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. " - "Function called twice, or manifest was used."; - } - } - return false; -} - -// This function works for Windows Vista through Win8. Win8.1 must use -// SetProcessDpiAwareness[Wrapper]. -BOOL SetProcessDPIAwareWrapper() { - typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID); - SetProcessDPIAwarePtr set_process_dpi_aware_func = - reinterpret_cast( - GetProcAddress(GetModuleHandleA("user32.dll"), - "SetProcessDPIAware")); - return set_process_dpi_aware_func && - set_process_dpi_aware_func(); -} - -void EnableHighDPISupport() { - if (!SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) { - SetProcessDPIAwareWrapper(); - } -} -#endif - } // namespace #if defined(OS_WIN) @@ -98,14 +54,11 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { int argc = 0; wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - // Make output work in console if we are not in cygiwn. - if (!IsEnvSet("TERM") && !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE")) { - AttachConsole(ATTACH_PARENT_PROCESS); + bool run_as_node = IsEnvSet(kRunAsNode); - FILE* dontcare; - freopen_s(&dontcare, "CON", "w", stdout); - freopen_s(&dontcare, "CON", "w", stderr); - } + // Make sure the output is printed to console. + if (run_as_node || !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE")) + base::RouteStdioToConsole(false); // Convert argv to to UTF8 char** argv = new char*[argc]; @@ -141,12 +94,12 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { } } - if (IsRunAsNode()) { + if (run_as_node) { // Now that argv conversion is done, we can finally start. base::AtExitManager atexit_manager; base::i18n::InitializeICU(); return atom::NodeMain(argc, argv); - } else if (IsEnvSet("ATOM_SHELL_INTERNAL_CRASH_SERVICE")) { + } else if (IsEnvSet("ELECTRON_INTERNAL_CRASH_SERVICE")) { return crash_service::Main(cmd); } @@ -154,12 +107,6 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { content::InitializeSandboxInfo(&sandbox_info); atom::AtomMainDelegate delegate; - // We don't want to set DPI awareness on pre-Win7 because we don't support - // DirectWrite there. GDI fonts are kerned very badly, so better to leave - // DPI-unaware and at effective 1.0. See also ShouldUseDirectWrite(). - if (base::win::GetVersion() >= base::win::VERSION_WIN7) - EnableHighDPISupport(); - content::ContentMainParams params(&delegate); params.instance = instance; params.sandbox_info = &sandbox_info; @@ -170,7 +117,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { #elif defined(OS_LINUX) // defined(OS_WIN) int main(int argc, const char* argv[]) { - if (IsRunAsNode()) { + if (IsEnvSet(kRunAsNode)) { base::i18n::InitializeICU(); base::AtExitManager atexit_manager; return atom::NodeMain(argc, const_cast(argv)); @@ -187,7 +134,7 @@ int main(int argc, const char* argv[]) { #else // defined(OS_LINUX) int main(int argc, const char* argv[]) { - if (IsRunAsNode()) { + if (IsEnvSet(kRunAsNode)) { return AtomInitializeICUandStartNode(argc, const_cast(argv)); } diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index 0a298308ad0b..9ce8dc504a92 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -30,6 +30,13 @@ bool IsBrowserProcess(base::CommandLine* cmd) { return process_type.empty(); } +#if defined(OS_WIN) +void InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, + unsigned int, uintptr_t) { + // noop. +} +#endif + } // namespace AtomMainDelegate::AtomMainDelegate() { @@ -61,7 +68,7 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { #endif // !defined(OS_WIN) // Only enable logging when --enable-logging is specified. - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); if (!command_line->HasSwitch(switches::kEnableLogging) && !env->HasVar("ELECTRON_ENABLE_LOGGING")) { settings.logging_dest = logging::LOG_NONE; @@ -83,6 +90,15 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { chrome::RegisterPathProvider(); +#if defined(OS_MACOSX) + SetUpBundleOverrides(); +#endif + +#if defined(OS_WIN) + // Ignore invalid parameter errors. + _set_invalid_parameter_handler(InvalidParameterHandler); +#endif + return brightray::MainDelegate::BasicStartupComplete(exit_code); } @@ -90,7 +106,7 @@ void AtomMainDelegate::PreSandboxStartup() { brightray::MainDelegate::PreSandboxStartup(); // Set google API key. - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); if (!env->HasVar("GOOGLE_API_KEY")) env->SetVar("GOOGLE_API_KEY", GOOGLEAPIS_API_KEY); @@ -130,8 +146,9 @@ content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() { return utility_client_.get(); } -scoped_ptr AtomMainDelegate::CreateContentClient() { - return scoped_ptr(new AtomContentClient); +std::unique_ptr +AtomMainDelegate::CreateContentClient() { + return std::unique_ptr(new AtomContentClient); } } // namespace atom diff --git a/atom/app/atom_main_delegate.h b/atom/app/atom_main_delegate.h index 5f4369302f5f..2f9474cff563 100644 --- a/atom/app/atom_main_delegate.h +++ b/atom/app/atom_main_delegate.h @@ -24,17 +24,21 @@ class AtomMainDelegate : public brightray::MainDelegate { content::ContentUtilityClient* CreateContentUtilityClient() override; // brightray::MainDelegate: - scoped_ptr CreateContentClient() override; + std::unique_ptr CreateContentClient() override; #if defined(OS_MACOSX) void OverrideChildProcessPath() override; void OverrideFrameworkBundlePath() override; #endif private: +#if defined(OS_MACOSX) + void SetUpBundleOverrides(); +#endif + brightray::ContentClient content_client_; - scoped_ptr browser_client_; - scoped_ptr renderer_client_; - scoped_ptr utility_client_; + std::unique_ptr browser_client_; + std::unique_ptr renderer_client_; + std::unique_ptr utility_client_; DISALLOW_COPY_AND_ASSIGN(AtomMainDelegate); }; diff --git a/atom/app/atom_main_delegate_mac.mm b/atom/app/atom_main_delegate_mac.mm index 33a8dea4aabb..ea5ab320a4d0 100644 --- a/atom/app/atom_main_delegate_mac.mm +++ b/atom/app/atom_main_delegate_mac.mm @@ -7,7 +7,10 @@ #include "base/mac/bundle_locations.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_nsautorelease_pool.h" #include "base/path_service.h" +#include "base/strings/sys_string_conversions.h" #include "brightray/common/application_info.h" #include "brightray/common/mac/main_application_bundle.h" #include "content/public/common/content_paths.h" @@ -48,4 +51,15 @@ void AtomMainDelegate::OverrideChildProcessPath() { PathService::Override(content::CHILD_PROCESS_EXE, helper_path); } +void AtomMainDelegate::SetUpBundleOverrides() { + base::mac::ScopedNSAutoreleasePool pool; + NSBundle* bundle = brightray::MainApplicationBundle(); + std::string base_bundle_id = + base::SysNSStringToUTF8([bundle bundleIdentifier]); + NSString* team_id = [bundle objectForInfoDictionaryKey:@"ElectronTeamID"]; + if (team_id) + base_bundle_id = base::SysNSStringToUTF8(team_id) + "." + base_bundle_id; + base::mac::SetBaseBundleID(base_bundle_id.c_str()); +} + } // namespace atom diff --git a/atom/app/node_main.cc b/atom/app/node_main.cc index b946ae28ff94..6f71d39f5740 100644 --- a/atom/app/node_main.cc +++ b/atom/app/node_main.cc @@ -7,8 +7,9 @@ #include "atom/app/uv_task_runner.h" #include "atom/browser/javascript_environment.h" #include "atom/browser/node_debugger.h" -#include "base/command_line.h" #include "atom/common/node_includes.h" +#include "base/command_line.h" +#include "base/feature_list.h" #include "base/thread_task_runner_handle.h" #include "gin/array_buffer.h" #include "gin/public/isolate_holder.h" @@ -27,6 +28,11 @@ int NodeMain(int argc, char *argv[]) { scoped_refptr uv_task_runner(new UvTaskRunner(loop)); base::ThreadTaskRunnerHandle handle(uv_task_runner); + // Initialize feature list. + std::unique_ptr feature_list(new base::FeatureList); + feature_list->InitializeFromCommandLine("", ""); + base::FeatureList::SetInstance(std::move(feature_list)); + gin::V8Initializer::LoadV8Snapshot(); gin::V8Initializer::LoadV8Natives(); JavascriptEnvironment gin_env; diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 52a6926d1a9b..3599e3195fc5 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -27,6 +27,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/path_service.h" +#include "base/strings/string_util.h" #include "brightray/browser/brightray_paths.h" #include "chrome/common/chrome_paths.h" #include "content/public/browser/client_certificate_delegate.h" @@ -318,7 +319,7 @@ void App::AllowCertificateError( void App::SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate) { + std::unique_ptr delegate) { std::shared_ptr shared_delegate(delegate.release()); bool prevent_default = @@ -369,17 +370,11 @@ void App::SetPath(mate::Arguments* args, void App::SetDesktopName(const std::string& desktop_name) { #if defined(OS_LINUX) - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); env->SetVar("CHROME_DESKTOP", desktop_name); #endif } -void App::AllowNTLMCredentialsForAllDomains(bool should_allow) { - auto browser_context = static_cast( - AtomBrowserMainParts::Get()->browser_context()); - browser_context->AllowNTLMCredentialsForAllDomains(should_allow); -} - std::string App::GetLocale() { return l10n_util::GetApplicationLocale(""); } @@ -406,13 +401,20 @@ bool App::MakeSingleInstance( } } +void App::ReleaseSingleInstance() { + if (process_singleton_.get()) { + process_singleton_->Cleanup(); + process_singleton_.reset(); + } +} + #if defined(USE_NSS_CERTS) void App::ImportCertificate( const base::DictionaryValue& options, const net::CompletionCallback& callback) { auto browser_context = AtomBrowserMainParts::Get()->browser_context(); if (!certificate_manager_model_) { - scoped_ptr copy = options.CreateDeepCopy(); + std::unique_ptr copy = options.CreateDeepCopy(); CertificateManagerModel::Create(browser_context, base::Bind(&App::OnCertificateManagerModelCreated, base::Unretained(this), @@ -426,9 +428,9 @@ void App::ImportCertificate( } void App::OnCertificateManagerModelCreated( - scoped_ptr options, + std::unique_ptr options, const net::CompletionCallback& callback, - scoped_ptr model) { + std::unique_ptr model) { certificate_manager_model_ = std::move(model); int rv = ImportIntoCertStore(certificate_manager_model_.get(), *(options.get())); @@ -481,13 +483,12 @@ void App::BuildPrototype( .SetMethod("setPath", &App::SetPath) .SetMethod("getPath", &App::GetPath) .SetMethod("setDesktopName", &App::SetDesktopName) - .SetMethod("allowNTLMCredentialsForAllDomains", - &App::AllowNTLMCredentialsForAllDomains) .SetMethod("getLocale", &App::GetLocale) #if defined(USE_NSS_CERTS) .SetMethod("importCertificate", &App::ImportCertificate) #endif - .SetMethod("makeSingleInstance", &App::MakeSingleInstance); + .SetMethod("makeSingleInstance", &App::MakeSingleInstance) + .SetMethod("releaseSingleInstance", &App::ReleaseSingleInstance); } } // namespace api @@ -500,7 +501,8 @@ namespace { void AppendSwitch(const std::string& switch_string, mate::Arguments* args) { auto command_line = base::CommandLine::ForCurrentProcess(); - if (switch_string == atom::switches::kPpapiFlashPath || + if (base::EndsWith(switch_string, "-path", + base::CompareCase::INSENSITIVE_ASCII) || switch_string == switches::kLogNetLog) { base::FilePath path; args->GetNext(&path); @@ -546,6 +548,8 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("dockBounce", &DockBounce); dict.SetMethod("dockCancelBounce", base::Bind(&Browser::DockCancelBounce, browser)); + dict.SetMethod("dockDownloadFinished", + base::Bind(&Browser::DockDownloadFinished, browser)); dict.SetMethod("dockSetBadgeText", base::Bind(&Browser::DockSetBadgeText, browser)); dict.SetMethod("dockGetBadgeText", diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index edfd09c4d289..979f61f0d219 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -51,9 +51,9 @@ class App : public AtomBrowserClient::Delegate, #if defined(USE_NSS_CERTS) void OnCertificateManagerModelCreated( - scoped_ptr options, + std::unique_ptr options, const net::CompletionCallback& callback, - scoped_ptr model); + std::unique_ptr model); #endif protected: @@ -93,7 +93,7 @@ class App : public AtomBrowserClient::Delegate, void SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate) override; + std::unique_ptr delegate) override; // content::GpuDataManagerObserver: void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; @@ -106,9 +106,9 @@ class App : public AtomBrowserClient::Delegate, const base::FilePath& path); void SetDesktopName(const std::string& desktop_name); - void AllowNTLMCredentialsForAllDomains(bool should_allow); bool MakeSingleInstance( const ProcessSingleton::NotificationCallback& callback); + void ReleaseSingleInstance(); std::string GetLocale(); #if defined(USE_NSS_CERTS) @@ -116,10 +116,10 @@ class App : public AtomBrowserClient::Delegate, const net::CompletionCallback& callback); #endif - scoped_ptr process_singleton_; + std::unique_ptr process_singleton_; #if defined(USE_NSS_CERTS) - scoped_ptr certificate_manager_model_; + std::unique_ptr certificate_manager_model_; #endif DISALLOW_COPY_AND_ASSIGN(App); diff --git a/atom/browser/api/atom_api_cookies.cc b/atom/browser/api/atom_api_cookies.cc index 8698b43485bf..6ee15a6cba90 100644 --- a/atom/browser/api/atom_api_cookies.cc +++ b/atom/browser/api/atom_api_cookies.cc @@ -47,7 +47,7 @@ struct Converter { dict.Set("secure", val.IsSecure()); dict.Set("httpOnly", val.IsHttpOnly()); dict.Set("session", !val.IsPersistent()); - if (!val.IsPersistent()) + if (val.IsPersistent()) dict.Set("expirationDate", val.ExpiryDate().ToDoubleT()); return dict.GetHandle(); } @@ -112,7 +112,7 @@ void RunCallbackInUI(const base::Closure& callback) { } // Remove cookies from |list| not matching |filter|, and pass it to |callback|. -void FilterCookies(scoped_ptr filter, +void FilterCookies(std::unique_ptr filter, const Cookies::GetCallback& callback, const net::CookieList& list) { net::CookieList result; @@ -125,7 +125,7 @@ void FilterCookies(scoped_ptr filter, // Receives cookies matching |filter| in IO thread. void GetCookiesOnIO(scoped_refptr getter, - scoped_ptr filter, + std::unique_ptr filter, const Cookies::GetCallback& callback) { std::string url; filter->GetString("url", &url); @@ -133,12 +133,12 @@ void GetCookiesOnIO(scoped_refptr getter, auto filtered_callback = base::Bind(FilterCookies, base::Passed(&filter), callback); - net::CookieMonster* monster = GetCookieStore(getter)->GetCookieMonster(); // Empty url will match all url cookies. if (url.empty()) - monster->GetAllCookiesAsync(filtered_callback); + GetCookieStore(getter)->GetAllCookiesAsync(filtered_callback); else - monster->GetAllCookiesForURLAsync(GURL(url), filtered_callback); + GetCookieStore(getter)->GetAllCookiesForURLAsync(GURL(url), + filtered_callback); } // Removes cookie with |url| and |name| in IO thread. @@ -157,12 +157,14 @@ void OnSetCookie(const Cookies::SetCallback& callback, bool success) { // Sets cookie with |details| in IO thread. void SetCookieOnIO(scoped_refptr getter, - scoped_ptr details, + std::unique_ptr details, const Cookies::SetCallback& callback) { std::string url, name, value, domain, path; bool secure = false; bool http_only = false; + double creation_date; double expiration_date; + double last_access_date; details->GetString("url", &url); details->GetString("name", &name); details->GetString("value", &value); @@ -171,6 +173,13 @@ void SetCookieOnIO(scoped_refptr getter, details->GetBoolean("secure", &secure); details->GetBoolean("httpOnly", &http_only); + base::Time creation_time; + if (details->GetDouble("creationDate", &creation_date)) { + creation_time = (creation_date == 0) ? + base::Time::UnixEpoch() : + base::Time::FromDoubleT(creation_date); + } + base::Time expiration_time; if (details->GetDouble("expirationDate", &expiration_date)) { expiration_time = (expiration_date == 0) ? @@ -178,10 +187,18 @@ void SetCookieOnIO(scoped_refptr getter, base::Time::FromDoubleT(expiration_date); } - GetCookieStore(getter)->GetCookieMonster()->SetCookieWithDetailsAsync( - GURL(url), name, value, domain, path, expiration_time, secure, http_only, - false, false, false, net::COOKIE_PRIORITY_DEFAULT, - base::Bind(OnSetCookie, callback)); + base::Time last_access_time; + if (details->GetDouble("lastAccessDate", &last_access_date)) { + last_access_time = (last_access_date == 0) ? + base::Time::UnixEpoch() : + base::Time::FromDoubleT(last_access_date); + } + + GetCookieStore(getter)->SetCookieWithDetailsAsync( + GURL(url), name, value, domain, path, creation_time, + expiration_time, last_access_time, secure, http_only, + net::CookieSameSite::DEFAULT_MODE, false, + net::COOKIE_PRIORITY_DEFAULT, base::Bind(OnSetCookie, callback)); } } // namespace @@ -197,7 +214,7 @@ Cookies::~Cookies() { void Cookies::Get(const base::DictionaryValue& filter, const GetCallback& callback) { - scoped_ptr copied(filter.CreateDeepCopy()); + std::unique_ptr copied(filter.CreateDeepCopy()); auto getter = make_scoped_refptr(request_context_getter_); content::BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -214,7 +231,7 @@ void Cookies::Remove(const GURL& url, const std::string& name, void Cookies::Set(const base::DictionaryValue& details, const SetCallback& callback) { - scoped_ptr copied(details.CreateDeepCopy()); + std::unique_ptr copied(details.CreateDeepCopy()); auto getter = make_scoped_refptr(request_context_getter_); content::BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, diff --git a/atom/browser/api/atom_api_debugger.cc b/atom/browser/api/atom_api_debugger.cc index 03490360133a..48b7a6f70c0b 100644 --- a/atom/browser/api/atom_api_debugger.cc +++ b/atom/browser/api/atom_api_debugger.cc @@ -52,7 +52,7 @@ void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host, const std::string& message) { DCHECK(agent_host == agent_host_.get()); - scoped_ptr parsed_message(base::JSONReader::Read(message)); + std::unique_ptr parsed_message(base::JSONReader::Read(message)); if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY)) return; diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index 9200a89224c2..3cb29a9124d3 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -61,9 +61,9 @@ void DesktopCapturer::StartHandling(bool capture_window, options.set_disable_effects(false); #endif - scoped_ptr screen_capturer( + std::unique_ptr screen_capturer( capture_screen ? webrtc::ScreenCapturer::Create(options) : nullptr); - scoped_ptr window_capturer( + std::unique_ptr window_capturer( capture_window ? webrtc::WindowCapturer::Create(options) : nullptr); media_list_.reset(new NativeDesktopMediaList( std::move(screen_capturer), std::move(window_capturer))); diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index e71141fa5218..4d1755e06827 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -39,7 +39,7 @@ class DesktopCapturer: public mate::EventEmitter, bool OnRefreshFinished() override; private: - scoped_ptr media_list_; + std::unique_ptr media_list_; DISALLOW_COPY_AND_ASSIGN(DesktopCapturer); }; diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 0a544c56468c..5d853e2d5900 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -67,6 +67,7 @@ void ShowMessageBox(int type, } void ShowOpenDialog(const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const file_dialog::Filters& filters, int properties, @@ -77,17 +78,18 @@ void ShowOpenDialog(const std::string& title, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - file_dialog::ShowOpenDialog(window, title, default_path, filters, - properties, callback); + file_dialog::ShowOpenDialog(window, title, button_label, default_path, + filters, properties, callback); } else { std::vector paths; - if (file_dialog::ShowOpenDialog(window, title, default_path, filters, - properties, &paths)) + if (file_dialog::ShowOpenDialog(window, title, button_label, default_path, + filters, properties, &paths)) args->Return(paths); } } void ShowSaveDialog(const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const file_dialog::Filters& filters, atom::NativeWindow* window, @@ -97,11 +99,12 @@ void ShowSaveDialog(const std::string& title, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - file_dialog::ShowSaveDialog(window, title, default_path, filters, callback); + file_dialog::ShowSaveDialog(window, title, button_label, default_path, + filters, callback); } else { base::FilePath path; - if (file_dialog::ShowSaveDialog(window, title, default_path, filters, - &path)) + if (file_dialog::ShowSaveDialog(window, title, button_label, default_path, + filters, &path)) args->Return(path); } } diff --git a/atom/browser/api/atom_api_menu.h b/atom/browser/api/atom_api_menu.h index 5701985ab101..9ba4d7a754c4 100644 --- a/atom/browser/api/atom_api_menu.h +++ b/atom/browser/api/atom_api_menu.h @@ -55,7 +55,7 @@ class Menu : public mate::TrackableObject, int x = -1, int y = -1, int positioning_item = 0) = 0; - scoped_ptr model_; + std::unique_ptr model_; Menu* parent_; private: diff --git a/atom/browser/api/atom_api_menu_mac.mm b/atom/browser/api/atom_api_menu_mac.mm index d8ee089c1cba..3b91dac62a7f 100644 --- a/atom/browser/api/atom_api_menu_mac.mm +++ b/atom/browser/api/atom_api_menu_mac.mm @@ -7,6 +7,8 @@ #include "atom/browser/native_window.h" #include "base/message_loop/message_loop.h" #include "base/strings/sys_string_conversions.h" +#include "brightray/browser/inspectable_web_contents.h" +#include "brightray/browser/inspectable_web_contents_view.h" #include "content/public/browser/web_contents.h" #include "atom/common/node_includes.h" @@ -22,14 +24,15 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) { NativeWindow* native_window = window->window(); if (!native_window) return; - content::WebContents* web_contents = native_window->web_contents(); + brightray::InspectableWebContents* web_contents = + native_window->inspectable_web_contents(); if (!web_contents) return; base::scoped_nsobject menu_controller( [[AtomMenuController alloc] initWithModel:model_.get()]); NSMenu* menu = [menu_controller menu]; - NSView* view = web_contents->GetContentNativeView(); + NSView* view = web_contents->GetView()->GetNativeView(); // Which menu item to show. NSMenuItem* item = nil; @@ -46,6 +49,23 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) { position = NSMakePoint(x, [view frame].size.height - y); } + // If no preferred item is specified, try to show all of the menu items. + if (!positioning_item) { + CGFloat windowBottom = CGRectGetMinY([view window].frame); + CGFloat lowestMenuPoint = windowBottom + position.y - [menu size].height; + CGFloat screenBottom = CGRectGetMinY([view window].screen.frame); + CGFloat distanceFromBottom = lowestMenuPoint - screenBottom; + if (distanceFromBottom < 0) + position.y = position.y - distanceFromBottom + 4; + } + + // Place the menu left of cursor if it is overflowing off right of screen. + CGFloat windowLeft = CGRectGetMinX([view window].frame); + CGFloat rightmostMenuPoint = windowLeft + position.x + [menu size].width; + CGFloat screenRight = CGRectGetMaxX([view window].screen.frame); + if (rightmostMenuPoint > screenRight) + position.x = position.x - [menu size].width; + // Show the menu. [menu popUpMenuPositioningItem:item atLocation:position inView:view]; } diff --git a/atom/browser/api/atom_api_menu_views.cc b/atom/browser/api/atom_api_menu_views.cc index 4d1c902e1755..9340bc76732e 100644 --- a/atom/browser/api/atom_api_menu_views.cc +++ b/atom/browser/api/atom_api_menu_views.cc @@ -30,7 +30,7 @@ void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) { // (-1, -1) means showing on mouse location. gfx::Point location; if (x == -1 || y == -1) { - location = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); + location = gfx::Screen::GetScreen()->GetCursorScreenPoint(); } else { gfx::Point origin = view->GetViewBounds().origin(); location = gfx::Point(origin.x() + x, origin.y() + y); diff --git a/atom/browser/api/atom_api_power_save_blocker.cc b/atom/browser/api/atom_api_power_save_blocker.cc index b8adcb776e56..67c9b6dd83c2 100644 --- a/atom/browser/api/atom_api_power_save_blocker.cc +++ b/atom/browser/api/atom_api_power_save_blocker.cc @@ -70,7 +70,7 @@ void PowerSaveBlocker::UpdatePowerSaveBlocker() { } if (!power_save_blocker_ || new_blocker_type != current_blocker_type_) { - scoped_ptr new_blocker = + std::unique_ptr new_blocker = content::PowerSaveBlocker::Create( new_blocker_type, content::PowerSaveBlocker::kReasonOther, diff --git a/atom/browser/api/atom_api_power_save_blocker.h b/atom/browser/api/atom_api_power_save_blocker.h index c24ae0aa4b66..a20b493e75bf 100644 --- a/atom/browser/api/atom_api_power_save_blocker.h +++ b/atom/browser/api/atom_api_power_save_blocker.h @@ -37,7 +37,7 @@ class PowerSaveBlocker : public mate::TrackableObject { bool Stop(int id); bool IsStarted(int id); - scoped_ptr power_save_blocker_; + std::unique_ptr power_save_blocker_; // Currnet blocker type used by |power_save_blocker_| content::PowerSaveBlocker::PowerSaveBlockerType current_blocker_type_; diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 3835fac62d7a..226f689d32de 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -15,6 +15,7 @@ #include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/node_includes.h" #include "native_mate/dictionary.h" +#include "url/url_util.h" using content::BrowserThread; @@ -29,11 +30,6 @@ Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context) Init(isolate); } -void Protocol::RegisterStandardSchemes( - const std::vector& schemes) { - atom::AtomBrowserClient::SetCustomSchemes(schemes); -} - void Protocol::RegisterServiceWorkerSchemes( const std::vector& schemes) { atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes); @@ -131,7 +127,6 @@ mate::Handle Protocol::Create( void Protocol::BuildPrototype( v8::Isolate* isolate, v8::Local prototype) { mate::ObjectTemplateBuilder(isolate, prototype) - .SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes) .SetMethod("registerServiceWorkerSchemes", &Protocol::RegisterServiceWorkerSchemes) .SetMethod("registerStringProtocol", @@ -161,13 +156,24 @@ void Protocol::BuildPrototype( namespace { +void RegisterStandardSchemes( + const std::vector& schemes) { + for (const auto& scheme : schemes) + url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); +} + +mate::Handle CreateProtocol(v8::Isolate* isolate) { + auto browser_context = static_cast( + atom::AtomBrowserMainParts::Get()->browser_context()); + return atom::api::Protocol::Create(isolate, browser_context); +} + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); - auto browser_context = static_cast( - atom::AtomBrowserMainParts::Get()->browser_context()); - dict.Set("protocol", atom::api::Protocol::Create(isolate, browser_context)); + dict.SetMethod("createProtocolObject", base::Bind(&CreateProtocol, isolate)); + dict.SetMethod("registerStandardSchemes", &RegisterStandardSchemes); } } // namespace diff --git a/atom/browser/api/atom_api_protocol.h b/atom/browser/api/atom_api_protocol.h index d7fa7f5211f8..d33e63fa9cff 100644 --- a/atom/browser/api/atom_api_protocol.h +++ b/atom/browser/api/atom_api_protocol.h @@ -88,9 +88,6 @@ class Protocol : public mate::Wrappable { DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler); }; - // Register schemes to standard scheme list. - void RegisterStandardSchemes(const std::vector& schemes); - // Register schemes that can handle service worker. void RegisterServiceWorkerSchemes(const std::vector& schemes); @@ -113,7 +110,7 @@ class Protocol : public mate::Wrappable { const Handler& handler) { if (job_factory_->IsHandledProtocol(scheme)) return PROTOCOL_REGISTERED; - scoped_ptr> protocol_handler( + std::unique_ptr> protocol_handler( new CustomProtocolHandler( isolate(), request_context_getter_, handler)); if (job_factory_->SetProtocolHandler(scheme, std::move(protocol_handler))) @@ -155,7 +152,7 @@ class Protocol : public mate::Wrappable { return PROTOCOL_FAIL; if (ContainsKey(original_protocols_, scheme)) return PROTOCOL_INTERCEPTED; - scoped_ptr> protocol_handler( + std::unique_ptr> protocol_handler( new CustomProtocolHandler( isolate(), request_context_getter_, handler)); original_protocols_.set( @@ -179,7 +176,7 @@ class Protocol : public mate::Wrappable { // Map that stores the original protocols of schemes. using OriginalProtocolsMap = base::ScopedPtrHashMap< std::string, - scoped_ptr>; + std::unique_ptr>; OriginalProtocolsMap original_protocols_; AtomURLRequestJobFactory* job_factory_; // weak ref diff --git a/atom/browser/api/atom_api_render_process_preferences.cc b/atom/browser/api/atom_api_render_process_preferences.cc new file mode 100644 index 000000000000..59ae07b45c75 --- /dev/null +++ b/atom/browser/api/atom_api_render_process_preferences.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_render_process_preferences.h" + +#include "atom/browser/atom_browser_client.h" +#include "atom/browser/native_window.h" +#include "atom/browser/window_list.h" +#include "atom/common/native_mate_converters/value_converter.h" +#include "atom/common/node_includes.h" +#include "content/public/browser/render_process_host.h" +#include "native_mate/dictionary.h" +#include "native_mate/object_template_builder.h" + +namespace atom { + +namespace api { + +namespace { + +bool IsBrowserWindow(content::RenderProcessHost* process) { + content::WebContents* web_contents = + static_cast(AtomBrowserClient::Get())-> + GetWebContentsFromProcessID(process->GetID()); + if (!web_contents) + return false; + + NativeWindow* window = NativeWindow::FromWebContents(web_contents); + if (!window) + return false; + + return true; +} + +} // namespace + +RenderProcessPreferences::RenderProcessPreferences( + v8::Isolate* isolate, + const atom::RenderProcessPreferences::Predicate& predicate) + : preferences_(predicate) { + Init(isolate); +} + +RenderProcessPreferences::~RenderProcessPreferences() { +} + +int RenderProcessPreferences::AddEntry(const base::DictionaryValue& entry) { + return preferences_.AddEntry(entry); +} + +void RenderProcessPreferences::RemoveEntry(int id) { + preferences_.RemoveEntry(id); +} + +// static +void RenderProcessPreferences::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("addEntry", &RenderProcessPreferences::AddEntry) + .SetMethod("removeEntry", &RenderProcessPreferences::RemoveEntry); +} + +// static +mate::Handle +RenderProcessPreferences::ForAllBrowserWindow(v8::Isolate* isolate) { + return mate::CreateHandle( + isolate, + new RenderProcessPreferences(isolate, base::Bind(&IsBrowserWindow))); +} + +} // namespace api + +} // namespace atom + +namespace { + +void Initialize(v8::Local exports, v8::Local unused, + v8::Local context, void* priv) { + mate::Dictionary dict(context->GetIsolate(), exports); + dict.SetMethod("forAllBrowserWindow", + &atom::api::RenderProcessPreferences::ForAllBrowserWindow); +} + +} // namespace + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_render_process_preferences, + Initialize) diff --git a/atom/browser/api/atom_api_render_process_preferences.h b/atom/browser/api/atom_api_render_process_preferences.h new file mode 100644 index 000000000000..a305f1361b2d --- /dev/null +++ b/atom/browser/api/atom_api_render_process_preferences.h @@ -0,0 +1,44 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_RENDER_PROCESS_PREFERENCES_H_ +#define ATOM_BROWSER_API_ATOM_API_RENDER_PROCESS_PREFERENCES_H_ + +#include "atom/browser/render_process_preferences.h" +#include "native_mate/handle.h" +#include "native_mate/wrappable.h" + +namespace atom { + +namespace api { + +class RenderProcessPreferences + : public mate::Wrappable { + public: + static mate::Handle + ForAllBrowserWindow(v8::Isolate* isolate); + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + + int AddEntry(const base::DictionaryValue& entry); + void RemoveEntry(int id); + + protected: + RenderProcessPreferences( + v8::Isolate* isolate, + const atom::RenderProcessPreferences::Predicate& predicate); + ~RenderProcessPreferences() override; + + private: + atom::RenderProcessPreferences preferences_; + + DISALLOW_COPY_AND_ASSIGN(RenderProcessPreferences); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_RENDER_PROCESS_PREFERENCES_H_ diff --git a/atom/browser/api/atom_api_screen.cc b/atom/browser/api/atom_api_screen.cc index 9d845e390e31..425d906e286e 100644 --- a/atom/browser/api/atom_api_screen.cc +++ b/atom/browser/api/atom_api_screen.cc @@ -99,7 +99,7 @@ v8::Local Screen::Create(v8::Isolate* isolate) { return v8::Null(isolate); } - gfx::Screen* screen = gfx::Screen::GetNativeScreen(); + gfx::Screen* screen = gfx::Screen::GetScreen(); if (!screen) { isolate->ThrowException(v8::Exception::Error(mate::StringToV8( isolate, "Failed to get screen information"))); diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 39c435b723ea..15aa2afe9cf3 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -22,7 +22,7 @@ #include "atom/common/node_includes.h" #include "base/files/file_path.h" #include "base/guid.h" -#include "base/prefs/pref_service.h" +#include "components/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/thread_task_runner_handle.h" @@ -36,6 +36,8 @@ #include "net/base/load_flags.h" #include "net/disk_cache/disk_cache.h" #include "net/dns/host_cache.h" +#include "net/http/http_auth_handler_factory.h" +#include "net/http/http_auth_preferences.h" #include "net/proxy/proxy_service.h" #include "net/proxy/proxy_config_service_fixed.h" #include "net/url_request/url_request_context.h" @@ -190,7 +192,7 @@ class ResolveProxyHelper { // Start the request. int result = proxy_service->ResolveProxy( - url, net::LOAD_NORMAL, &proxy_info_, completion_callback, + url, "GET", net::LOAD_NORMAL, &proxy_info_, completion_callback, &pac_req_, nullptr, net::BoundNetLog()); // Completed synchronously. @@ -284,6 +286,19 @@ void ClearHostResolverCacheInIO( } } +void AllowNTLMCredentialsForDomainsInIO( + const scoped_refptr& context_getter, + const std::string& domains) { + auto request_context = context_getter->GetURLRequestContext(); + auto auth_handler = request_context->http_auth_handler_factory(); + if (auth_handler) { + auto auth_preferences = const_cast( + auth_handler->http_auth_preferences()); + if (auth_preferences) + auth_preferences->set_server_whitelist(domains); + } +} + } // namespace Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context) @@ -369,7 +384,7 @@ void Session::SetDownloadPath(const base::FilePath& path) { } void Session::EnableNetworkEmulation(const mate::Dictionary& options) { - scoped_ptr conditions; + std::unique_ptr conditions; bool offline = false; double latency, download_throughput, upload_throughput; if (options.Get("offline", &offline) && offline) { @@ -392,7 +407,7 @@ void Session::EnableNetworkEmulation(const mate::Dictionary& options) { } void Session::DisableNetworkEmulation() { - scoped_ptr conditions; + std::unique_ptr conditions; browser_context_->network_controller_handle()->SetNetworkState( devtools_network_emulation_client_id_, std::move(conditions)); browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId( @@ -432,6 +447,13 @@ void Session::ClearHostResolverCache(mate::Arguments* args) { callback)); } +void Session::AllowNTLMCredentialsForDomains(const std::string& domains) { + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&AllowNTLMCredentialsForDomainsInIO, + make_scoped_refptr(browser_context_->GetRequestContext()), + domains)); +} + v8::Local Session::Cookies(v8::Isolate* isolate) { if (cookies_.IsEmpty()) { auto handle = atom::api::Cookies::Create(isolate, browser_context()); @@ -487,6 +509,8 @@ void Session::BuildPrototype(v8::Isolate* isolate, .SetMethod("setPermissionRequestHandler", &Session::SetPermissionRequestHandler) .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache) + .SetMethod("allowNTLMCredentialsForDomains", + &Session::AllowNTLMCredentialsForDomains) .SetProperty("cookies", &Session::Cookies) .SetProperty("webRequest", &Session::WebRequest); } diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index 5e08a85aa7d1..0cebf09ea1f3 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -79,6 +79,7 @@ class Session: public mate::TrackableObject, void SetPermissionRequestHandler(v8::Local val, mate::Arguments* args); void ClearHostResolverCache(mate::Arguments* args); + void AllowNTLMCredentialsForDomains(const std::string& domains); v8::Local Cookies(v8::Isolate* isolate); v8::Local WebRequest(v8::Isolate* isolate); diff --git a/atom/browser/api/atom_api_system_preferences.cc b/atom/browser/api/atom_api_system_preferences.cc index b8c665456ade..2b11aad25278 100644 --- a/atom/browser/api/atom_api_system_preferences.cc +++ b/atom/browser/api/atom_api_system_preferences.cc @@ -5,6 +5,7 @@ #include "atom/browser/api/atom_api_system_preferences.h" #include "atom/common/native_mate_converters/callback.h" +#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_includes.h" #include "native_mate/dictionary.h" diff --git a/atom/browser/api/atom_api_system_preferences.h b/atom/browser/api/atom_api_system_preferences.h index fed1c52247b7..7779ce007816 100644 --- a/atom/browser/api/atom_api_system_preferences.h +++ b/atom/browser/api/atom_api_system_preferences.h @@ -11,6 +11,10 @@ #include "base/callback.h" #include "native_mate/handle.h" +namespace base { +class DictionaryValue; +} + namespace atom { namespace api { @@ -22,11 +26,16 @@ class SystemPreferences : public mate::EventEmitter { static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); +#if defined(OS_MACOSX) + using NotificationCallback = base::Callback< + void(const std::string&, const base::DictionaryValue&)>; +#endif + #if defined(OS_WIN) bool IsAeroGlassEnabled(); #elif defined(OS_MACOSX) int SubscribeNotification(const std::string& name, - const base::Closure& callback); + const NotificationCallback& callback); void UnsubscribeNotification(int id); v8::Local GetUserDefault(const std::string& name, const std::string& type); diff --git a/atom/browser/api/atom_api_system_preferences_mac.mm b/atom/browser/api/atom_api_system_preferences_mac.mm index 2d12b278ae92..f0b48adf2564 100644 --- a/atom/browser/api/atom_api_system_preferences_mac.mm +++ b/atom/browser/api/atom_api_system_preferences_mac.mm @@ -8,8 +8,10 @@ #import +#include "atom/browser/mac/dict_util.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "base/strings/sys_string_conversions.h" +#include "base/values.h" #include "net/base/mac/url_conversions.h" namespace atom { @@ -25,16 +27,26 @@ std::map g_id_map; } // namespace -int SystemPreferences::SubscribeNotification(const std::string& name, - const base::Closure& callback) { +int SystemPreferences::SubscribeNotification( + const std::string& name, const NotificationCallback& callback) { int request_id = g_next_id++; - __block base::Closure copied_callback = callback; + __block NotificationCallback copied_callback = callback; g_id_map[request_id] = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:base::SysUTF8ToNSString(name) object:nil queue:nil usingBlock:^(NSNotification* notification) { - copied_callback.Run(); + std::unique_ptr user_info = + NSDictionaryToDictionaryValue(notification.userInfo); + if (user_info) { + copied_callback.Run( + base::SysNSStringToUTF8(notification.name), + *user_info); + } else { + copied_callback.Run( + base::SysNSStringToUTF8(notification.name), + base::DictionaryValue()); + } } ]; return request_id; diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index 34fe81b92b22..c84e8a1d66b6 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -9,6 +9,7 @@ #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/browser.h" #include "atom/browser/ui/tray_icon.h" +#include "atom/common/api/atom_api_native_image.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" @@ -22,9 +23,9 @@ namespace atom { namespace api { -Tray::Tray(v8::Isolate* isolate, const gfx::Image& image) +Tray::Tray(v8::Isolate* isolate, mate::Handle image) : tray_icon_(TrayIcon::Create()) { - tray_icon_->SetImage(image); + SetImage(isolate, image); tray_icon_->AddObserver(this); } @@ -32,7 +33,8 @@ Tray::~Tray() { } // static -mate::WrappableBase* Tray::New(v8::Isolate* isolate, const gfx::Image& image) { +mate::WrappableBase* Tray::New(v8::Isolate* isolate, + mate::Handle image) { if (!Browser::Get()->is_ready()) { isolate->ThrowException(v8::Exception::Error(mate::StringToV8( isolate, "Cannot create Tray before app is ready"))); @@ -94,29 +96,38 @@ void Tray::OnDragEnded() { Emit("drag-end"); } -void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) { - tray_icon_->SetImage(image); +void Tray::SetImage(v8::Isolate* isolate, mate::Handle image) { +#if defined(OS_WIN) + tray_icon_->SetImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON))); +#else + tray_icon_->SetImage(image->image()); +#endif } -void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) { - tray_icon_->SetPressedImage(image); +void Tray::SetPressedImage(v8::Isolate* isolate, + mate::Handle image) { +#if defined(OS_WIN) + tray_icon_->SetPressedImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON))); +#else + tray_icon_->SetPressedImage(image->image()); +#endif } -void Tray::SetToolTip(mate::Arguments* args, const std::string& tool_tip) { +void Tray::SetToolTip(const std::string& tool_tip) { tray_icon_->SetToolTip(tool_tip); } -void Tray::SetTitle(mate::Arguments* args, const std::string& title) { +void Tray::SetTitle(const std::string& title) { tray_icon_->SetTitle(title); } -void Tray::SetHighlightMode(mate::Arguments* args, bool highlight) { +void Tray::SetHighlightMode(bool highlight) { tray_icon_->SetHighlightMode(highlight); } void Tray::DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options) { - gfx::Image icon; + mate::Handle icon; options.Get("icon", &icon); base::string16 title, content; if (!options.Get("title", &title) || @@ -125,7 +136,14 @@ void Tray::DisplayBalloon(mate::Arguments* args, return; } - tray_icon_->DisplayBalloon(icon, title, content); +#if defined(OS_WIN) + tray_icon_->DisplayBalloon( + icon.IsEmpty() ? NULL : icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), + title, content); +#else + tray_icon_->DisplayBalloon( + icon.IsEmpty() ? gfx::Image() : icon->image(), title, content); +#endif } void Tray::PopUpContextMenu(mate::Arguments* args) { @@ -136,7 +154,8 @@ void Tray::PopUpContextMenu(mate::Arguments* args) { tray_icon_->PopUpContextMenu(pos, menu.IsEmpty() ? nullptr : menu->model()); } -void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) { +void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle menu) { + menu_.Reset(isolate, menu.ToV8()); tray_icon_->SetContextMenu(menu->model()); } @@ -162,7 +181,7 @@ void Tray::BuildPrototype(v8::Isolate* isolate, .SetMethod("setHighlightMode", &Tray::SetHighlightMode) .SetMethod("displayBalloon", &Tray::DisplayBalloon) .SetMethod("popUpContextMenu", &Tray::PopUpContextMenu) - .SetMethod("_setContextMenu", &Tray::SetContextMenu); + .SetMethod("setContextMenu", &Tray::SetContextMenu); } } // namespace api diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index 84e68220dba8..a6c329567ca3 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -11,6 +11,7 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/ui/tray_icon_observer.h" #include "base/memory/scoped_ptr.h" +#include "native_mate/handle.h" namespace gfx { class Image; @@ -28,18 +29,19 @@ class TrayIcon; namespace api { class Menu; +class NativeImage; class Tray : public mate::TrackableObject, public TrayIconObserver { public: static mate::WrappableBase* New( - v8::Isolate* isolate, const gfx::Image& image); + v8::Isolate* isolate, mate::Handle image); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - Tray(v8::Isolate* isolate, const gfx::Image& image); + Tray(v8::Isolate* isolate, mate::Handle image); ~Tray() override; // TrayIconObserver: @@ -55,19 +57,20 @@ class Tray : public mate::TrackableObject, void OnDragExited() override; void OnDragEnded() override; - void SetImage(mate::Arguments* args, const gfx::Image& image); - void SetPressedImage(mate::Arguments* args, const gfx::Image& image); - void SetToolTip(mate::Arguments* args, const std::string& tool_tip); - void SetTitle(mate::Arguments* args, const std::string& title); - void SetHighlightMode(mate::Arguments* args, bool highlight); + void SetImage(v8::Isolate* isolate, mate::Handle image); + void SetPressedImage(v8::Isolate* isolate, mate::Handle image); + void SetToolTip(const std::string& tool_tip); + void SetTitle(const std::string& title); + void SetHighlightMode(bool highlight); void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); void PopUpContextMenu(mate::Arguments* args); - void SetContextMenu(mate::Arguments* args, Menu* menu); + void SetContextMenu(v8::Isolate* isolate, mate::Handle menu); private: v8::Local ModifiersToObject(v8::Isolate* isolate, int modifiers); - scoped_ptr tray_icon_; + v8::Global menu_; + std::unique_ptr tray_icon_; DISALLOW_COPY_AND_ASSIGN(Tray); }; diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 7785808f3693..9d93d980be4a 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -14,6 +14,7 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_security_state_model_client.h" +#include "atom/browser/lib/bluetooth_chooser.h" #include "atom/browser/native_window.h" #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/web_contents_permission_helper.h" @@ -63,6 +64,7 @@ #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request_context.h" #include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/WebKit/public/web/WebFindOptions.h" #include "ui/base/l10n/l10n_util.h" #include "atom/common/node_includes.h" @@ -144,7 +146,7 @@ struct Converter { net::HttpResponseHeaders* headers) { base::DictionaryValue response_headers; if (headers) { - void* iter = nullptr; + size_t iter = 0; std::string key; std::string value; while (headers->EnumerateHeaderLines(&iter, &key, &value)) { @@ -154,7 +156,7 @@ struct Converter { if (response_headers.GetList(key, &values)) values->AppendString(value); } else { - scoped_ptr values(new base::ListValue()); + std::unique_ptr values(new base::ListValue()); values->AppendString(value); response_headers.Set(key, std::move(values)); } @@ -260,8 +262,9 @@ WebContents::WebContents(v8::Isolate* isolate, content::WebContents* web_contents; if (is_guest) { - content::SiteInstance* site_instance = content::SiteInstance::CreateForURL( - session->browser_context(), GURL("chrome-guest://fake-host")); + scoped_refptr site_instance = + content::SiteInstance::CreateForURL( + session->browser_context(), GURL("chrome-guest://fake-host")); content::WebContents::CreateParams params( session->browser_context(), site_instance); guest_delegate_.reset(new WebViewGuestDelegate); @@ -273,7 +276,7 @@ WebContents::WebContents(v8::Isolate* isolate, } Observe(web_contents); - InitWithWebContents(web_contents); + InitWithWebContents(web_contents, session->browser_context()); managed_web_contents()->GetView()->SetDelegate(this); @@ -378,7 +381,7 @@ void WebContents::MoveContents(content::WebContents* source, void WebContents::CloseContents(content::WebContents* source) { Emit("close"); - if (type_ == BROWSER_WINDOW) + if (type_ == BROWSER_WINDOW && owner_window()) owner_window()->CloseContents(source); } @@ -393,14 +396,12 @@ bool WebContents::IsPopupOrPanel(const content::WebContents* source) const { void WebContents::HandleKeyboardEvent( content::WebContents* source, const content::NativeWebKeyboardEvent& event) { - if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) { - // Escape exits tabbed fullscreen mode. - ExitFullscreenModeForTab(source); - } else if (type_ == BROWSER_WINDOW) { - owner_window()->HandleKeyboardEvent(source, event); - } else if (type_ == WEB_VIEW && guest_delegate_) { + if (type_ == WEB_VIEW && embedder_) { // Send the unhandled keyboard events back to the embedder. - guest_delegate_->HandleKeyboardEvent(source, event); + embedder_->HandleKeyboardEvent(source, event); + } else { + // Go to the default keyboard handling. + CommonWebContentsDelegate::HandleKeyboardEvent(source, event); } } @@ -429,13 +430,13 @@ void WebContents::ExitFullscreenModeForTab(content::WebContents* source) { void WebContents::RendererUnresponsive(content::WebContents* source) { Emit("unresponsive"); - if (type_ == BROWSER_WINDOW) + if (type_ == BROWSER_WINDOW && owner_window()) owner_window()->RendererUnresponsive(source); } void WebContents::RendererResponsive(content::WebContents* source) { Emit("responsive"); - if (type_ == BROWSER_WINDOW) + if (type_ == BROWSER_WINDOW && owner_window()) owner_window()->RendererResponsive(source); } @@ -504,6 +505,14 @@ void WebContents::RequestToLockMouse( permission_helper->RequestPointerLockPermission(user_gesture); } +std::unique_ptr WebContents::RunBluetoothChooser( + content::RenderFrameHost* frame, + const content::BluetoothChooser::EventHandler& event_handler) { + std::unique_ptr bluetooth_chooser( + new BluetoothChooser(this, event_handler)); + return std::move(bluetooth_chooser); +} + void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { // Do nothing, we override this method just to avoid compilation error since // there are two virtual functions named BeforeUnloadFired. @@ -655,6 +664,11 @@ void WebContents::DevToolsOpened() { isolate(), managed_web_contents()->GetDevToolsWebContents()); devtools_web_contents_.Reset(isolate(), handle.ToV8()); + // Set inspected tabID. + base::FundamentalValue tab_id(ID()); + managed_web_contents()->CallClientFunction( + "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr); + // Inherit owner window in devtools. if (owner_window()) handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(), @@ -865,7 +879,7 @@ void WebContents::OpenDevTools(mate::Arguments* args) { return; std::string state; - if (type_ == WEB_VIEW) { + if (type_ == WEB_VIEW || !owner_window()) { state = "detach"; } else if (args && args->Length() == 1) { bool detach = false; @@ -1083,9 +1097,10 @@ void WebContents::TabTraverse(bool reverse) { web_contents()->FocusThroughTabTraversal(reverse); } -bool WebContents::SendIPCMessage(const base::string16& channel, +bool WebContents::SendIPCMessage(bool all_frames, + const base::string16& channel, const base::ListValue& args) { - return Send(new AtomViewMsg_Message(routing_id(), channel, args)); + return Send(new AtomViewMsg_Message(routing_id(), all_frames, channel, args)); } void WebContents::SendInputEvent(v8::Isolate* isolate, @@ -1126,7 +1141,7 @@ void WebContents::BeginFrameSubscription( const FrameSubscriber::FrameCaptureCallback& callback) { const auto view = web_contents()->GetRenderWidgetHostView(); if (view) { - scoped_ptr frame_subscriber(new FrameSubscriber( + std::unique_ptr frame_subscriber(new FrameSubscriber( isolate(), view, callback)); view->BeginFrameSubscription(std::move(frame_subscriber)); } @@ -1173,6 +1188,10 @@ v8::Local WebContents::GetOwnerBrowserWindow() { return v8::Null(isolate()); } +int32_t WebContents::ID() const { + return weak_map_id(); +} + v8::Local WebContents::Session(v8::Isolate* isolate) { return v8::Local::New(isolate, session_); } @@ -1265,6 +1284,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate, .SetMethod("_printToPDF", &WebContents::PrintToPDF) .SetMethod("addWorkSpace", &WebContents::AddWorkSpace) .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace) + .SetProperty("id", &WebContents::ID) .SetProperty("session", &WebContents::Session) .SetProperty("hostWebContents", &WebContents::HostWebContents) .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents) @@ -1328,6 +1348,8 @@ void Initialize(v8::Local exports, v8::Local unused, mate::Dictionary dict(isolate, exports); dict.SetMethod("create", &atom::api::WebContents::Create); dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents); + dict.SetMethod("fromId", + &mate::TrackableObject::FromWeakMapID); } } // namespace diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 9deb1696c411..85c43f1486aa 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -122,7 +122,8 @@ class WebContents : public mate::TrackableObject, void TabTraverse(bool reverse); // Send messages to browser. - bool SendIPCMessage(const base::string16& channel, + bool SendIPCMessage(bool all_frames, + const base::string16& channel, const base::ListValue& args); // Send WebInputEvent to the page. @@ -154,6 +155,7 @@ class WebContents : public mate::TrackableObject, v8::Local GetOwnerBrowserWindow(); // Properties. + int32_t ID() const; v8::Local Session(v8::Isolate* isolate); content::WebContents* HostWebContents(); v8::Local DevToolsWebContents(v8::Isolate* isolate); @@ -209,6 +211,9 @@ class WebContents : public mate::TrackableObject, content::WebContents* web_contents, bool user_gesture, bool last_unlocked_by_target) override; + std::unique_ptr RunBluetoothChooser( + content::RenderFrameHost* frame, + const content::BluetoothChooser::EventHandler& handler) override; // content::WebContentsObserver: void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; @@ -288,7 +293,7 @@ class WebContents : public mate::TrackableObject, v8::Global devtools_web_contents_; v8::Global debugger_; - scoped_ptr guest_delegate_; + std::unique_ptr guest_delegate_; // The host webcontents that may contain this webcontents. WebContents* embedder_; diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index f06c1105526e..1586c3a10dde 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -14,22 +14,12 @@ using atom::WebContentsPreferences; namespace { -atom::WebViewManager* GetWebViewManager(content::WebContents* web_contents) { - auto context = web_contents->GetBrowserContext(); - if (context) { - auto manager = context->GetGuestManager(); - return static_cast(manager); - } else { - return nullptr; - } -} - void AddGuest(int guest_instance_id, int element_instance_id, content::WebContents* embedder, content::WebContents* guest_web_contents, const base::DictionaryValue& options) { - auto manager = GetWebViewManager(embedder); + auto manager = atom::WebViewManager::GetWebViewManager(embedder); if (manager) manager->AddGuest(guest_instance_id, element_instance_id, embedder, guest_web_contents); @@ -38,7 +28,7 @@ void AddGuest(int guest_instance_id, } void RemoveGuest(content::WebContents* embedder, int guest_instance_id) { - auto manager = GetWebViewManager(embedder); + auto manager = atom::WebViewManager::GetWebViewManager(embedder); if (manager) manager->RemoveGuest(guest_instance_id); } diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index ae5eec64cf93..ac3c510193ed 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -21,8 +21,11 @@ #include "native_mate/dictionary.h" #include "ui/gfx/geometry/rect.h" -#if defined(OS_WIN) +#if defined(TOOLKIT_VIEWS) #include "atom/browser/native_window_views.h" +#endif + +#if defined(OS_WIN) #include "atom/browser/ui/win/taskbar_host.h" #endif @@ -52,11 +55,6 @@ namespace api { namespace { -// This function is implemented in JavaScript -using DeprecatedOptionsCheckCallback = - base::Callback)>; -DeprecatedOptionsCheckCallback g_deprecated_options_check; - void OnCapturePageDone( v8::Isolate* isolate, const base::Callback& callback, @@ -66,52 +64,6 @@ void OnCapturePageDone( callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); } -// Converts min-width to minWidth, returns false if no conversion is needed. -bool TranslateOldKey(const std::string& key, std::string* new_key) { - if (key.find('-') == std::string::npos) - return false; - new_key->reserve(key.size()); - bool next_upper_case = false; - for (char c : key) { - if (c == '-') { - next_upper_case = true; - } else if (next_upper_case) { - new_key->push_back(base::ToUpperASCII(c)); - next_upper_case = false; - } else { - new_key->push_back(c); - } - } - return true; -} - -// Converts min-width to minWidth recursively in the dictionary. -void TranslateOldOptions(v8::Isolate* isolate, v8::Local options) { - auto context = isolate->GetCurrentContext(); - auto maybe_keys = options->GetOwnPropertyNames(context); - if (maybe_keys.IsEmpty()) - return; - std::vector keys; - if (!mate::ConvertFromV8(isolate, maybe_keys.ToLocalChecked(), &keys)) - return; - mate::Dictionary dict(isolate, options); - for (const auto& key : keys) { - v8::Local value; - if (!dict.Get(key, &value)) // Shouldn't happen, but guard it anyway. - continue; - // Go recursively. - v8::Local sub_options; - if (mate::ConvertFromV8(isolate, value, &sub_options)) - TranslateOldOptions(isolate, sub_options); - // Translate key. - std::string new_key; - if (TranslateOldKey(key, &new_key)) { - dict.Set(new_key, value); - dict.Delete(key); - } - } -} - // Converts binary data to Buffer. v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { auto buffer = node::Buffer::Copy(isolate, static_cast(val), size); @@ -125,23 +77,12 @@ v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { - // Be compatible with old style field names like min-width. - TranslateOldOptions(isolate, options.GetHandle()); - // Use options.webPreferences to create WebContents. mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); options.Get(options::kWebPreferences, &web_preferences); - // Be compatible with old options which are now in web_preferences. - v8::Local value; - if (options.Get(options::kNodeIntegration, &value)) - web_preferences.Set(options::kNodeIntegration, value); - if (options.Get(options::kPreloadScript, &value)) - web_preferences.Set(options::kPreloadScript, value); - if (options.Get(options::kZoomFactor, &value)) - web_preferences.Set(options::kZoomFactor, value); - // Copy the backgroundColor to webContents. + v8::Local value; if (options.Get(options::kBackgroundColor, &value)) web_preferences.Set(options::kBackgroundColor, value); @@ -161,6 +102,13 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { window_->InitFromOptions(options); window_->AddObserver(this); AttachAsUserData(window_.get()); + +#if defined(TOOLKIT_VIEWS) + // Sets the window icon. + mate::Handle icon; + if (options.Get(options::kIcon, &icon)) + SetIcon(icon); +#endif } Window::~Window() { @@ -304,13 +252,6 @@ mate::WrappableBase* Window::New(v8::Isolate* isolate, mate::Arguments* args) { options = mate::Dictionary::CreateEmpty(isolate); } - std::string deprecation_message = g_deprecated_options_check.Run( - options.GetHandle()); - if (deprecation_message.length() > 0) { - args->ThrowError(deprecation_message); - return nullptr; - } - return new Window(isolate, options); } @@ -440,8 +381,10 @@ std::vector Window::GetMaximumSize() { return result; } -void Window::SetSheetOffset(double offset) { - window_->SetSheetOffset(offset); +void Window::SetSheetOffset(double offsetY, mate::Arguments* args) { + double offsetX = 0.0; + args->GetNext(&offsetX); + window_->SetSheetOffset(offsetX, offsetY); } void Window::SetResizable(bool resizable) { @@ -686,6 +629,19 @@ void Window::ShowDefinitionForSelection() { } #endif +#if defined(TOOLKIT_VIEWS) +void Window::SetIcon(mate::Handle icon) { +#if defined(OS_WIN) + static_cast(window_.get())->SetIcon( + icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), + icon->GetHICON(GetSystemMetrics(SM_CXICON))); +#elif defined(USE_X11) + static_cast(window_.get())->SetIcon( + icon->image().AsImageSkia()); +#endif +} +#endif + void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { gfx::Size extra_size; args->GetNext(&extra_size); @@ -807,6 +763,9 @@ void Window::BuildPrototype(v8::Isolate* isolate, #if defined(OS_MACOSX) .SetMethod("showDefinitionForSelection", &Window::ShowDefinitionForSelection) +#endif +#if defined(TOOLKIT_VIEWS) + .SetMethod("setIcon", &Window::SetIcon) #endif .SetProperty("id", &Window::ID) .SetProperty("webContents", &Window::WebContents); @@ -822,10 +781,6 @@ v8::Local Window::From(v8::Isolate* isolate, return v8::Null(isolate); } -void SetDeprecatedOptionsCheck(const DeprecatedOptionsCheckCallback& callback) { - g_deprecated_options_check = callback; -} - } // namespace api } // namespace atom @@ -848,8 +803,6 @@ void Initialize(v8::Local exports, v8::Local unused, mate::Dictionary dict(isolate, exports); dict.Set("BrowserWindow", browser_window); - dict.SetMethod("_setDeprecatedOptionsCheck", - &atom::api::SetDeprecatedOptionsCheck); } } // namespace diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index a00e063d99f8..e698eaaf78cc 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -14,6 +14,7 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/native_window.h" #include "atom/browser/native_window_observer.h" +#include "atom/common/api/atom_api_native_image.h" #include "native_mate/handle.h" class GURL; @@ -110,7 +111,7 @@ class Window : public mate::TrackableObject, std::vector GetMinimumSize(); void SetMaximumSize(int width, int height); std::vector GetMaximumSize(); - void SetSheetOffset(double offset); + void SetSheetOffset(double offsetY, mate::Arguments* args); void SetResizable(bool resizable); bool IsResizable(); void SetMovable(bool movable); @@ -172,6 +173,10 @@ class Window : public mate::TrackableObject, void ShowDefinitionForSelection(); #endif +#if defined(TOOLKIT_VIEWS) + void SetIcon(mate::Handle icon); +#endif + void SetVisibleOnAllWorkspaces(bool visible); bool IsVisibleOnAllWorkspaces(); @@ -188,7 +193,7 @@ class Window : public mate::TrackableObject, api::WebContents* api_web_contents_; - scoped_ptr window_; + std::unique_ptr window_; DISALLOW_COPY_AND_ASSIGN(Window); }; diff --git a/atom/browser/api/event.cc b/atom/browser/api/event.cc index f456cf2758bb..2554e4ad0dab 100644 --- a/atom/browser/api/event.cc +++ b/atom/browser/api/event.cc @@ -45,7 +45,10 @@ bool Event::SendReply(const base::string16& json) { return false; AtomViewHostMsg_Message_Sync::WriteReplyParams(message_, json); - return sender_->Send(message_); + bool success = sender_->Send(message_); + message_ = NULL; + sender_ = NULL; + return success; } // static diff --git a/atom/browser/api/trackable_object.h b/atom/browser/api/trackable_object.h index 1c71d84e42c9..bbed54754002 100644 --- a/atom/browser/api/trackable_object.h +++ b/atom/browser/api/trackable_object.h @@ -8,7 +8,7 @@ #include #include "atom/browser/api/event_emitter.h" -#include "atom/common/id_weak_map.h" +#include "atom/common/key_weak_map.h" #include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" @@ -113,21 +113,26 @@ class TrackableObject : public TrackableObjectBase, void AfterInit(v8::Isolate* isolate) override { if (!weak_map_) { - weak_map_.reset(new atom::IDWeakMap); + weak_map_ = new atom::KeyWeakMap; } - weak_map_id_ = weak_map_->Add(isolate, Wrappable::GetWrapper()); + weak_map_id_ = ++next_id_; + weak_map_->Set(isolate, weak_map_id_, Wrappable::GetWrapper()); if (wrapped_) AttachAsUserData(wrapped_); } private: - static scoped_ptr weak_map_; + static int32_t next_id_; + static atom::KeyWeakMap* weak_map_; // leaked on purpose DISALLOW_COPY_AND_ASSIGN(TrackableObject); }; template -scoped_ptr TrackableObject::weak_map_; +int32_t TrackableObject::next_id_ = 0; + +template +atom::KeyWeakMap* TrackableObject::weak_map_ = nullptr; } // namespace mate diff --git a/atom/browser/atom_access_token_store.cc b/atom/browser/atom_access_token_store.cc index adf2f5061cb0..ed87ea979920 100644 --- a/atom/browser/atom_access_token_store.cc +++ b/atom/browser/atom_access_token_store.cc @@ -32,18 +32,18 @@ AtomAccessTokenStore::~AtomAccessTokenStore() { } void AtomAccessTokenStore::LoadAccessTokens( - const LoadAccessTokensCallbackType& callback) { - AccessTokenSet access_token_set; + const LoadAccessTokensCallback& callback) { + AccessTokenMap access_token_map; - // Equivelent to access_token_set[kGeolocationProviderURL]. + // Equivelent to access_token_map[kGeolocationProviderURL]. // Somehow base::string16 is causing compilation errors when used in a pair // of std::map on Linux, this can work around it. std::pair token_pair; token_pair.first = GURL(kGeolocationProviderURL); - access_token_set.insert(token_pair); + access_token_map.insert(token_pair); auto browser_context = AtomBrowserMainParts::Get()->browser_context(); - callback.Run(access_token_set, browser_context->url_request_context_getter()); + callback.Run(access_token_map, browser_context->url_request_context_getter()); } void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url, diff --git a/atom/browser/atom_access_token_store.h b/atom/browser/atom_access_token_store.h index f2b734a20695..54bc2cee3c29 100644 --- a/atom/browser/atom_access_token_store.h +++ b/atom/browser/atom_access_token_store.h @@ -18,7 +18,7 @@ class AtomAccessTokenStore : public content::AccessTokenStore { // content::AccessTokenStore: void LoadAccessTokens( - const LoadAccessTokensCallbackType& callback) override; + const LoadAccessTokensCallback& callback) override; void SaveAccessToken(const GURL& server_url, const base::string16& access_token) override; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index f4add58e3a89..e3cb9c5c8c89 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -49,11 +49,12 @@ namespace { // Next navigation should not restart renderer process. bool g_suppress_renderer_process_restart = false; -// Custom schemes to be registered to standard. -std::string g_custom_schemes = ""; // Custom schemes to be registered to handle service worker. std::string g_custom_service_worker_schemes = ""; +void Noop(scoped_refptr) { +} + } // namespace // static @@ -61,11 +62,6 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() { g_suppress_renderer_process_restart = true; } -void AtomBrowserClient::SetCustomSchemes( - const std::vector& schemes) { - g_custom_schemes = base::JoinString(schemes, ","); -} - void AtomBrowserClient::SetCustomServiceWorkerSchemes( const std::vector& schemes) { g_custom_service_worker_schemes = base::JoinString(schemes, ","); @@ -77,6 +73,17 @@ AtomBrowserClient::AtomBrowserClient() : delegate_(nullptr) { AtomBrowserClient::~AtomBrowserClient() { } +content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID( + int process_id) { + // If the process is a pending process, we should use the old one. + if (ContainsKey(pending_processes_, process_id)) + process_id = pending_processes_[process_id]; + + // Certain render process will be created with no associated render view, + // for example: ServiceWorker. + return WebContentsPreferences::GetWebContentsFromProcessID(process_id); +} + void AtomBrowserClient::RenderProcessWillLaunch( content::RenderProcessHost* host) { int process_id = host->GetID(); @@ -136,7 +143,16 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation( if (url.SchemeIs(url::kJavaScriptScheme)) return; - *new_instance = content::SiteInstance::CreateForURL(browser_context, url); + scoped_refptr site_instance = + content::SiteInstance::CreateForURL(browser_context, url); + *new_instance = site_instance.get(); + + // Make sure the |site_instance| is not freed when this function returns. + // FIXME(zcbenz): We should adjust OverrideSiteInstanceForNavigation's + // interface to solve this. + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(&Noop, base::RetainedRef(site_instance))); // Remember the original renderer process of the pending renderer process. auto current_process = current_instance->GetProcess(); @@ -153,11 +169,6 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( if (process_type != "renderer") return; - // The registered standard schemes. - if (!g_custom_schemes.empty()) - command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes, - g_custom_schemes); - // The registered service worker schemes. if (!g_custom_service_worker_schemes.empty()) command_line->AppendSwitchASCII(switches::kRegisterServiceWorkerSchemes, @@ -172,14 +183,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( } #endif - // If the process is a pending process, we should use the old one. - if (ContainsKey(pending_processes_, process_id)) - process_id = pending_processes_[process_id]; - - // Certain render process will be created with no associated render view, - // for example: ServiceWorker. - content::WebContents* web_contents = - WebContentsPreferences::GetWebContentsFromProcessID(process_id); + content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); if (!web_contents) return; @@ -220,7 +224,7 @@ void AtomBrowserClient::AllowCertificateError( void AtomBrowserClient::SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate) { + std::unique_ptr delegate) { if (!cert_request_info->client_certs.empty() && delegate_) { delegate_->SelectClientCertificate( web_contents, cert_request_info, std::move(delegate)); diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index 5354e14cc617..cf1a4cc438b6 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -34,10 +34,12 @@ class AtomBrowserClient : public brightray::BrowserClient, using Delegate = content::ContentBrowserClient; void set_delegate(Delegate* delegate) { delegate_ = delegate; } + // Returns the WebContents for pending render processes. + content::WebContents* GetWebContentsFromProcessID(int process_id); + // Don't force renderer process to restart for once. static void SuppressRendererProcessRestartForOnce(); - // Custom schemes to be registered to standard. - static void SetCustomSchemes(const std::vector& schemes); + // Custom schemes to be registered to handle service worker. static void SetCustomServiceWorkerSchemes( const std::vector& schemes); @@ -74,7 +76,7 @@ class AtomBrowserClient : public brightray::BrowserClient, void SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate) override; + std::unique_ptr delegate) override; void ResourceDispatcherHostCreated() override; bool CanCreateWindow(const GURL& opener_url, const GURL& opener_top_level_frame_url, @@ -107,7 +109,7 @@ class AtomBrowserClient : public brightray::BrowserClient, // pending_render_process => current_render_process. std::map pending_processes_; - scoped_ptr + std::unique_ptr resource_dispatcher_host_delegate_; Delegate* delegate_; diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index b06c6278f53f..6f28cf6df7da 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -21,7 +21,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/path_service.h" -#include "base/prefs/pref_registry_simple.h" +#include "components/prefs/pref_registry_simple.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/threading/sequenced_worker_pool.h" @@ -46,7 +46,7 @@ namespace { class NoCacheBackend : public net::HttpCache::BackendFactory { int CreateBackend(net::NetLog* net_log, - scoped_ptr* backend, + std::unique_ptr* backend, const net::CompletionCallback& callback) override { return net::ERR_FAILED; } @@ -67,8 +67,7 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition, : brightray::BrowserContext(partition, in_memory), cert_verifier_(new AtomCertVerifier), job_factory_(new AtomURLRequestJobFactory), - network_delegate_(new AtomNetworkDelegate), - allow_ntlm_everywhere_(false) { + network_delegate_(new AtomNetworkDelegate) { } AtomBrowserContext::~AtomBrowserContext() { @@ -95,11 +94,11 @@ std::string AtomBrowserContext::GetUserAgent() { return content::BuildUserAgentFromProduct(user_agent); } -scoped_ptr +std::unique_ptr AtomBrowserContext::CreateURLRequestJobFactory( content::ProtocolHandlerMap* handlers, content::URLRequestInterceptorScopedVector* interceptors) { - scoped_ptr job_factory(job_factory_); + std::unique_ptr job_factory(job_factory_); for (auto& it : *handlers) { job_factory->SetProtocolHandler(it.first, @@ -134,7 +133,7 @@ AtomBrowserContext::CreateURLRequestJobFactory( new net::FtpNetworkLayer(host_resolver)))); // Set up interceptors in the reverse order. - scoped_ptr top_job_factory = + std::unique_ptr top_job_factory = std::move(job_factory); content::URLRequestInterceptorScopedVector::reverse_iterator it; for (it = interceptors->rbegin(); it != interceptors->rend(); ++it) @@ -177,7 +176,7 @@ content::PermissionManager* AtomBrowserContext::GetPermissionManager() { return permission_manager_.get(); } -scoped_ptr AtomBrowserContext::CreateCertVerifier() { +std::unique_ptr AtomBrowserContext::CreateCertVerifier() { return make_scoped_ptr(cert_verifier_); } @@ -195,16 +194,6 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) { pref_registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths); } -bool AtomBrowserContext::AllowNTLMCredentialsForDomain(const GURL& origin) { - if (allow_ntlm_everywhere_) - return true; - return Delegate::AllowNTLMCredentialsForDomain(origin); -} - -void AtomBrowserContext::AllowNTLMCredentialsForAllDomains(bool should_allow) { - allow_ntlm_everywhere_ = should_allow; -} - } // namespace atom namespace brightray { diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index d959adbc753a..028f5d1e79c4 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -26,14 +26,13 @@ class AtomBrowserContext : public brightray::BrowserContext { // brightray::URLRequestContextGetter::Delegate: net::NetworkDelegate* CreateNetworkDelegate() override; std::string GetUserAgent() override; - scoped_ptr CreateURLRequestJobFactory( + std::unique_ptr CreateURLRequestJobFactory( content::ProtocolHandlerMap* handlers, content::URLRequestInterceptorScopedVector* interceptors) override; net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory( const base::FilePath& base_path) override; - scoped_ptr CreateCertVerifier() override; + std::unique_ptr CreateCertVerifier() override; net::SSLConfigService* CreateSSLConfigService() override; - bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override; // content::BrowserContext: content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; @@ -43,8 +42,6 @@ class AtomBrowserContext : public brightray::BrowserContext { // brightray::BrowserContext: void RegisterPrefs(PrefRegistrySimple* pref_registry) override; - void AllowNTLMCredentialsForAllDomains(bool should_allow); - AtomCertVerifier* cert_verifier() const { return cert_verifier_; } AtomURLRequestJobFactory* job_factory() const { return job_factory_; } @@ -52,17 +49,15 @@ class AtomBrowserContext : public brightray::BrowserContext { AtomNetworkDelegate* network_delegate() const { return network_delegate_; } private: - scoped_ptr download_manager_delegate_; - scoped_ptr guest_manager_; - scoped_ptr permission_manager_; + std::unique_ptr download_manager_delegate_; + std::unique_ptr guest_manager_; + std::unique_ptr permission_manager_; // Managed by brightray::BrowserContext. AtomCertVerifier* cert_verifier_; AtomURLRequestJobFactory* job_factory_; AtomNetworkDelegate* network_delegate_; - bool allow_ntlm_everywhere_; - DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext); }; diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index e1053a257b91..0d8619f6865a 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -68,7 +68,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { #endif // A fake BrowserProcess object that used to feed the source code from chrome. - scoped_ptr fake_browser_process_; + std::unique_ptr fake_browser_process_; // The gin::PerIsolateData requires a task runner to create, so we feed it // with a task runner that will post all work to main loop. @@ -77,11 +77,11 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { // Pointer to exit code. int* exit_code_; - scoped_ptr browser_; - scoped_ptr js_env_; - scoped_ptr node_bindings_; - scoped_ptr atom_bindings_; - scoped_ptr node_debugger_; + std::unique_ptr browser_; + std::unique_ptr js_env_; + std::unique_ptr node_bindings_; + std::unique_ptr atom_bindings_; + std::unique_ptr node_debugger_; base::Timer gc_timer_; diff --git a/atom/browser/atom_download_manager_delegate.cc b/atom/browser/atom_download_manager_delegate.cc index 295747a33c4e..6d7e3c7172d8 100644 --- a/atom/browser/atom_download_manager_delegate.cc +++ b/atom/browser/atom_download_manager_delegate.cc @@ -12,7 +12,7 @@ #include "atom/browser/ui/file_dialog.h" #include "base/bind.h" #include "base/files/file_util.h" -#include "base/prefs/pref_service.h" +#include "components/prefs/pref_service.h" #include "chrome/common/pref_names.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -77,7 +77,8 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated( window = relay->window.get(); base::FilePath path; - if (file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path, + if (file_dialog::ShowSaveDialog(window, item->GetURL().spec(), + "", default_path, file_dialog::Filters(), &path)) { // Remember the last selected download directory. AtomBrowserContext* browser_context = static_cast( diff --git a/atom/browser/atom_javascript_dialog_manager.cc b/atom/browser/atom_javascript_dialog_manager.cc index c21d1fb11816..eaf311ba1cdb 100644 --- a/atom/browser/atom_javascript_dialog_manager.cc +++ b/atom/browser/atom_javascript_dialog_manager.cc @@ -13,7 +13,6 @@ namespace atom { void AtomJavaScriptDialogManager::RunJavaScriptDialog( content::WebContents* web_contents, const GURL& origin_url, - const std::string& accept_lang, content::JavaScriptMessageType javascript_message_type, const base::string16& message_text, const base::string16& default_prompt_text, @@ -24,12 +23,10 @@ void AtomJavaScriptDialogManager::RunJavaScriptDialog( void AtomJavaScriptDialogManager::RunBeforeUnloadDialog( content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { - bool prevent_reload = message_text.empty() || - message_text == base::ASCIIToUTF16("false"); - callback.Run(!prevent_reload, message_text); + // FIXME(zcbenz): the |message_text| is removed, figure out what should we do. + callback.Run(false, base::ASCIIToUTF16("This should not be displayed")); } } // namespace atom diff --git a/atom/browser/atom_javascript_dialog_manager.h b/atom/browser/atom_javascript_dialog_manager.h index c0a0dccf0fa9..3844e41f9d2f 100644 --- a/atom/browser/atom_javascript_dialog_manager.h +++ b/atom/browser/atom_javascript_dialog_manager.h @@ -17,7 +17,6 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager { void RunJavaScriptDialog( content::WebContents* web_contents, const GURL& origin_url, - const std::string& accept_lang, content::JavaScriptMessageType javascript_message_type, const base::string16& message_text, const base::string16& default_prompt_text, @@ -25,7 +24,6 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager { bool* did_suppress_message) override; void RunBeforeUnloadDialog( content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override; void CancelActiveAndPendingDialogs( diff --git a/atom/browser/atom_permission_manager.cc b/atom/browser/atom_permission_manager.cc index f7523c07ff83..7fc5fa0d0378 100644 --- a/atom/browser/atom_permission_manager.cc +++ b/atom/browser/atom_permission_manager.cc @@ -40,7 +40,7 @@ void AtomPermissionManager::SetPermissionRequestHandler( if (handler.is_null() && !pending_requests_.empty()) { for (const auto& request : pending_requests_) { if (!WebContentsDestroyed(request.second.render_process_id)) - request.second.callback.Run(content::PERMISSION_STATUS_DENIED); + request.second.callback.Run(blink::mojom::PermissionStatus::DENIED); } pending_requests_.clear(); } @@ -51,7 +51,6 @@ int AtomPermissionManager::RequestPermission( content::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - bool user_gesture, const ResponseCallback& response_callback) { int process_id = render_frame_host->GetProcess()->GetID(); @@ -74,7 +73,7 @@ int AtomPermissionManager::RequestPermission( return request_id_; } - response_callback.Run(content::PERMISSION_STATUS_GRANTED); + response_callback.Run(blink::mojom::PermissionStatus::GRANTED); return kNoPendingOperation; } @@ -82,17 +81,16 @@ int AtomPermissionManager::RequestPermissions( const std::vector& permissions, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - bool user_gesture, const base::Callback&)>& callback) { + const std::vector&)>& callback) { // FIXME(zcbenz): Just ignore multiple permissions request for now. - std::vector permissionStatuses; + std::vector permissionStatuses; for (auto permission : permissions) { if (permission == content::PermissionType::MIDI_SYSEX) { content::ChildProcessSecurityPolicy::GetInstance()-> GrantSendMidiSysExMessage(render_frame_host->GetProcess()->GetID()); } - permissionStatuses.push_back(content::PERMISSION_STATUS_GRANTED); + permissionStatuses.push_back(blink::mojom::PermissionStatus::GRANTED); } callback.Run(permissionStatuses); return kNoPendingOperation; @@ -102,7 +100,7 @@ void AtomPermissionManager::OnPermissionResponse( int request_id, const GURL& origin, const ResponseCallback& callback, - content::PermissionStatus status) { + blink::mojom::PermissionStatus status) { auto request = pending_requests_.find(request_id); if (request != pending_requests_.end()) { if (!WebContentsDestroyed(request->second.render_process_id)) @@ -115,7 +113,7 @@ void AtomPermissionManager::CancelPermissionRequest(int request_id) { auto request = pending_requests_.find(request_id); if (request != pending_requests_.end()) { if (!WebContentsDestroyed(request->second.render_process_id)) - request->second.callback.Run(content::PERMISSION_STATUS_DENIED); + request->second.callback.Run(blink::mojom::PermissionStatus::DENIED); pending_requests_.erase(request); } } @@ -126,11 +124,11 @@ void AtomPermissionManager::ResetPermission( const GURL& embedding_origin) { } -content::PermissionStatus AtomPermissionManager::GetPermissionStatus( +blink::mojom::PermissionStatus AtomPermissionManager::GetPermissionStatus( content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) { - return content::PERMISSION_STATUS_GRANTED; + return blink::mojom::PermissionStatus::GRANTED; } void AtomPermissionManager::RegisterPermissionUsage( diff --git a/atom/browser/atom_permission_manager.h b/atom/browser/atom_permission_manager.h index e16893fd8bb5..d0fcdc60768f 100644 --- a/atom/browser/atom_permission_manager.h +++ b/atom/browser/atom_permission_manager.h @@ -23,7 +23,7 @@ class AtomPermissionManager : public content::PermissionManager { ~AtomPermissionManager() override; using ResponseCallback = - base::Callback; + base::Callback; using RequestHandler = base::Callback& permissions, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - bool user_gesture, const base::Callback&)>& callback) override; + const std::vector&)>& callback) override; protected: void OnPermissionResponse(int request_id, const GURL& url, const ResponseCallback& callback, - content::PermissionStatus status); + blink::mojom::PermissionStatus status); // content::PermissionManager: void CancelPermissionRequest(int request_id) override; void ResetPermission(content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) override; - content::PermissionStatus GetPermissionStatus( + blink::mojom::PermissionStatus GetPermissionStatus( content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) override; @@ -69,7 +67,8 @@ class AtomPermissionManager : public content::PermissionManager { content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin, - const base::Callback& callback) override; + const base::Callback& callback) + override; void UnsubscribePermissionStatusChange(int subscription_id) override; private: diff --git a/atom/browser/atom_security_state_model_client.h b/atom/browser/atom_security_state_model_client.h index cc943eb7f949..0dd3aa66c125 100644 --- a/atom/browser/atom_security_state_model_client.h +++ b/atom/browser/atom_security_state_model_client.h @@ -32,7 +32,7 @@ class AtomSecurityStateModelClient friend class content::WebContentsUserData; content::WebContents* web_contents_; - scoped_ptr security_state_model_; + std::unique_ptr security_state_model_; DISALLOW_COPY_AND_ASSIGN(AtomSecurityStateModelClient); }; diff --git a/atom/browser/browser.h b/atom/browser/browser.h index eb8d2865ad82..18d0c97c93ac 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -14,6 +14,7 @@ #include "base/strings/string16.h" #include "atom/browser/browser_observer.h" #include "atom/browser/window_list_observer.h" +#include "native_mate/arguments.h" #if defined(OS_WIN) #include "base/files/file_path.h" @@ -94,7 +95,8 @@ class Browser : public WindowListObserver { // Creates an activity and sets it as the one currently in use. void SetUserActivity(const std::string& type, - const base::DictionaryValue& user_info); + const base::DictionaryValue& user_info, + mate::Arguments* args); // Returns the type name of the current user activity. std::string GetCurrentActivityType(); @@ -111,6 +113,9 @@ class Browser : public WindowListObserver { int DockBounce(BounceType type); void DockCancelBounce(int request_id); + // Bounce the Downloads stack. + void DockDownloadFinished(const std::string& filePath); + // Set/Get dock's badge text. void DockSetBadgeText(const std::string& label); std::string DockGetBadgeText(); diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index eb7191b67a23..4561eab8c950 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -13,6 +13,8 @@ #include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" #include "brightray/common/application_info.h" +#include "net/base/mac/url_conversions.h" +#include "url/gurl.h" namespace atom { @@ -43,7 +45,31 @@ void Browser::ClearRecentDocuments() { } bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol) { - return false; + NSString* identifier = [base::mac::MainBundle() bundleIdentifier]; + if (!identifier) + return false; + + if (!Browser::IsDefaultProtocolClient(protocol)) + return false; + + NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; + CFStringRef protocol_cf = base::mac::NSToCFCast(protocol_ns); + CFArrayRef bundleList = LSCopyAllHandlersForURLScheme(protocol_cf); + if (!bundleList) { + return false; + } + // On Mac OS X, we can't query the default, but the handlers list seems to put + // Apple's defaults first, so we'll use the first option that isn't our bundle + CFStringRef other = nil; + for (CFIndex i = 0; i < CFArrayGetCount(bundleList); i++) { + other = (CFStringRef)CFArrayGetValueAtIndex(bundleList, i); + if (![identifier isEqualToString: (__bridge NSString *)other]) { + break; + } + } + + OSStatus return_code = LSSetDefaultHandlerForURLScheme(protocol_cf, other); + return return_code == noErr; } bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { @@ -88,12 +114,16 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol) { void Browser::SetAppUserModelID(const base::string16& name) { } -void Browser::SetUserActivity( - const std::string& type, - const base::DictionaryValue& user_info) { +void Browser::SetUserActivity(const std::string& type, + const base::DictionaryValue& user_info, + mate::Arguments* args) { + std::string url_string; + args->GetNext(&url_string); + [[AtomApplication sharedApplication] setCurrentActivity:base::SysUTF8ToNSString(type) - withUserInfo:DictionaryValueToNSDictionary(user_info)]; + withUserInfo:DictionaryValueToNSDictionary(user_info) + withWebpageURL:net::NSURLWithGURL(GURL(url_string))]; } std::string Browser::GetCurrentActivityType() { @@ -102,9 +132,8 @@ std::string Browser::GetCurrentActivityType() { return base::SysNSStringToUTF8(userActivity.activityType); } -bool Browser::ContinueUserActivity( - const std::string& type, - const base::DictionaryValue& user_info) { +bool Browser::ContinueUserActivity(const std::string& type, + const base::DictionaryValue& user_info) { bool prevent_default = false; FOR_EACH_OBSERVER(BrowserObserver, observers_, @@ -134,6 +163,12 @@ void Browser::DockSetBadgeText(const std::string& label) { [tile setBadgeLabel:base::SysUTF8ToNSString(label)]; } +void Browser::DockDownloadFinished(const std::string& filePath) { + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName: @"com.apple.DownloadFileFinished" + object: base::SysUTF8ToNSString(filePath)]; +} + std::string Browser::DockGetBadgeText() { NSDockTile *tile = [[AtomApplication sharedApplication] dockTile]; return base::SysNSStringToUTF8([tile badgeLabel]); diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 7b1402ba2d2c..345e2bcf67ce 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -281,7 +281,7 @@ PCWSTR Browser::GetAppUserModelID() { std::string Browser::GetExecutableFileVersion() const { base::FilePath path; if (PathService::Get(base::FILE_EXE, &path)) { - scoped_ptr version_info( + std::unique_ptr version_info( FileVersionInfo::CreateFileVersionInfo(path)); return base::UTF16ToUTF8(version_info->product_version()); } @@ -292,7 +292,7 @@ std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileProductName() const { base::FilePath path; if (PathService::Get(base::FILE_EXE, &path)) { - scoped_ptr version_info( + std::unique_ptr version_info( FileVersionInfo::CreateFileVersionInfo(path)); return base::UTF16ToUTF8(version_info->product_name()); } diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 4bebf7480b89..c275d4aee74e 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -16,8 +16,8 @@ #include "atom/browser/web_dialog_helper.h" #include "atom/common/atom_constants.h" #include "base/files/file_util.h" -#include "base/prefs/pref_service.h" -#include "base/prefs/scoped_user_pref_update.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" #include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/ui/browser_dialogs.h" @@ -31,14 +31,6 @@ #include "content/public/browser/security_style_explanations.h" #include "storage/browser/fileapi/isolated_context.h" -#if defined(TOOLKIT_VIEWS) -#include "atom/browser/native_window_views.h" -#endif - -#if defined(USE_X11) -#include "atom/browser/browser.h" -#endif - using content::BrowserThread; using security_state::SecurityStateModel; @@ -145,6 +137,13 @@ std::set GetAddedFileSystemPaths( return result; } +bool IsDevToolsFileSystemAdded( + content::WebContents* web_contents, + const std::string& file_system_path) { + auto file_system_paths = GetAddedFileSystemPaths(web_contents); + return file_system_paths.find(file_system_path) != file_system_paths.end(); +} + content::SecurityStyle SecurityLevelToSecurityStyle( SecurityStateModel::SecurityLevel security_level) { switch (security_level) { @@ -167,14 +166,17 @@ content::SecurityStyle SecurityLevelToSecurityStyle( CommonWebContentsDelegate::CommonWebContentsDelegate() : html_fullscreen_(false), - native_fullscreen_(false) { + native_fullscreen_(false), + devtools_file_system_indexer_(new DevToolsFileSystemIndexer) { } CommonWebContentsDelegate::~CommonWebContentsDelegate() { } void CommonWebContentsDelegate::InitWithWebContents( - content::WebContents* web_contents) { + content::WebContents* web_contents, + AtomBrowserContext* browser_context) { + browser_context_ = browser_context; web_contents->SetDelegate(this); printing::PrintViewManagerBasic::CreateForWebContents(web_contents); @@ -381,7 +383,7 @@ void CommonWebContentsDelegate::DevToolsSaveToFile( } else { file_dialog::Filters filters; base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url)); - if (!file_dialog::ShowSaveDialog(owner_window(), url, default_path, + if (!file_dialog::ShowSaveDialog(owner_window(), url, "", default_path, filters, &path)) { base::StringValue url_value(url); web_contents_->CallClientFunction( @@ -447,7 +449,7 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem( base::FilePath default_path; std::vector paths; int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY; - if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path, + if (!file_dialog::ShowOpenDialog(owner_window(), "", "", default_path, filters, flag, &paths)) return; @@ -456,14 +458,13 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem( std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), path); - auto file_system_paths = GetAddedFileSystemPaths(GetDevToolsWebContents()); - if (file_system_paths.find(path.AsUTF8Unsafe()) != file_system_paths.end()) + if (IsDevToolsFileSystemAdded(GetDevToolsWebContents(), path.AsUTF8Unsafe())) return; FileSystem file_system = CreateFileSystemStruct(GetDevToolsWebContents(), file_system_id, path.AsUTF8Unsafe()); - scoped_ptr file_system_value( + std::unique_ptr file_system_value( CreateFileSystemValue(file_system)); auto pref_service = GetPrefService(GetDevToolsWebContents()); @@ -495,6 +496,61 @@ void CommonWebContentsDelegate::DevToolsRemoveFileSystem( nullptr, nullptr); } +void CommonWebContentsDelegate::DevToolsIndexPath( + int request_id, + const std::string& file_system_path) { + if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) { + OnDevToolsIndexingDone(request_id, file_system_path); + return; + } + if (devtools_indexing_jobs_.count(request_id) != 0) + return; + devtools_indexing_jobs_[request_id] = + scoped_refptr( + devtools_file_system_indexer_->IndexPath( + file_system_path, + base::Bind( + &CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated, + base::Unretained(this), + request_id, + file_system_path), + base::Bind(&CommonWebContentsDelegate::OnDevToolsIndexingWorked, + base::Unretained(this), + request_id, + file_system_path), + base::Bind(&CommonWebContentsDelegate::OnDevToolsIndexingDone, + base::Unretained(this), + request_id, + file_system_path))); +} + +void CommonWebContentsDelegate::DevToolsStopIndexing(int request_id) { + auto it = devtools_indexing_jobs_.find(request_id); + if (it == devtools_indexing_jobs_.end()) + return; + it->second->Stop(); + devtools_indexing_jobs_.erase(it); +} + +void CommonWebContentsDelegate::DevToolsSearchInPath( + int request_id, + const std::string& file_system_path, + const std::string& query) { + if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) { + OnDevToolsSearchCompleted(request_id, + file_system_path, + std::vector()); + return; + } + devtools_file_system_indexer_->SearchInPath( + file_system_path, + query, + base::Bind(&CommonWebContentsDelegate::OnDevToolsSearchCompleted, + base::Unretained(this), + request_id, + file_system_path)); +} + void CommonWebContentsDelegate::OnDevToolsSaveToFile( const std::string& url) { // Notify DevTools. @@ -511,22 +567,60 @@ void CommonWebContentsDelegate::OnDevToolsAppendToFile( "DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr); } -#if defined(TOOLKIT_VIEWS) -gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() { - if (!owner_window()) - return gfx::ImageSkia(); - return static_cast(static_cast( - owner_window()))->GetWindowAppIcon(); +void CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated( + int request_id, + const std::string& file_system_path, + int total_work) { + base::FundamentalValue request_id_value(request_id); + base::StringValue file_system_path_value(file_system_path); + base::FundamentalValue total_work_value(total_work); + web_contents_->CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated", + &request_id_value, + &file_system_path_value, + &total_work_value); } -#endif -#if defined(USE_X11) -void CommonWebContentsDelegate::GetDevToolsWindowWMClass( - std::string* name, std::string* class_name) { - *class_name = Browser::Get()->GetName(); - *name = base::ToLowerASCII(*class_name); +void CommonWebContentsDelegate::OnDevToolsIndexingWorked( + int request_id, + const std::string& file_system_path, + int worked) { + base::FundamentalValue request_id_value(request_id); + base::StringValue file_system_path_value(file_system_path); + base::FundamentalValue worked_value(worked); + web_contents_->CallClientFunction("DevToolsAPI.indexingWorked", + &request_id_value, + &file_system_path_value, + &worked_value); +} + +void CommonWebContentsDelegate::OnDevToolsIndexingDone( + int request_id, + const std::string& file_system_path) { + devtools_indexing_jobs_.erase(request_id); + base::FundamentalValue request_id_value(request_id); + base::StringValue file_system_path_value(file_system_path); + web_contents_->CallClientFunction("DevToolsAPI.indexingDone", + &request_id_value, + &file_system_path_value, + nullptr); +} + +void CommonWebContentsDelegate::OnDevToolsSearchCompleted( + int request_id, + const std::string& file_system_path, + const std::vector& file_paths) { + base::ListValue file_paths_value; + for (std::vector::const_iterator it(file_paths.begin()); + it != file_paths.end(); ++it) { + file_paths_value.AppendString(*it); + } + base::FundamentalValue request_id_value(request_id); + base::StringValue file_system_path_value(file_system_path); + web_contents_->CallClientFunction("DevToolsAPI.searchCompleted", + &request_id_value, + &file_system_path_value, + &file_paths_value); } -#endif void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) { // Window is already in fullscreen mode, save the state. diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index 699d00e18bce..1746d63b2082 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -12,10 +12,14 @@ #include "brightray/browser/inspectable_web_contents_impl.h" #include "brightray/browser/inspectable_web_contents_delegate.h" #include "brightray/browser/inspectable_web_contents_view_delegate.h" +#include "brightray/browser/devtools_file_system_indexer.h" #include "content/public/browser/web_contents_delegate.h" +using brightray::DevToolsFileSystemIndexer; + namespace atom { +class AtomBrowserContext; class AtomJavaScriptDialogManager; class NativeWindow; class WebDialogHelper; @@ -30,7 +34,8 @@ class CommonWebContentsDelegate // Creates a InspectableWebContents object and takes onwership of // |web_contents|. - void InitWithWebContents(content::WebContents* web_contents); + void InitWithWebContents(content::WebContents* web_contents, + AtomBrowserContext* browser_context); // Set the window as owner window. void SetOwnerWindow(NativeWindow* owner_window); @@ -79,6 +84,9 @@ class CommonWebContentsDelegate content::SecurityStyle GetSecurityStyle( content::WebContents* web_contents, content::SecurityStyleExplanations* explanations) override; + void HandleKeyboardEvent( + content::WebContents* source, + const content::NativeWebKeyboardEvent& event) override; // brightray::InspectableWebContentsDelegate: void DevToolsSaveToFile(const std::string& url, @@ -90,6 +98,12 @@ class CommonWebContentsDelegate void DevToolsAddFileSystem(const base::FilePath& path) override; void DevToolsRemoveFileSystem( const base::FilePath& file_system_path) override; + void DevToolsIndexPath(int request_id, + const std::string& file_system_path) override; + void DevToolsStopIndexing(int request_id) override; + void DevToolsSearchInPath(int request_id, + const std::string& file_system_path, + const std::string& query) override; // brightray::InspectableWebContentsViewDelegate: #if defined(TOOLKIT_VIEWS) @@ -107,6 +121,19 @@ class CommonWebContentsDelegate // Callback for when DevToolsAppendToFile has completed. void OnDevToolsAppendToFile(const std::string& url); + // + void OnDevToolsIndexingWorkCalculated(int request_id, + const std::string& file_system_path, + int total_work); + void OnDevToolsIndexingWorked(int request_id, + const std::string& file_system_path, + int worked); + void OnDevToolsIndexingDone(int request_id, + const std::string& file_system_path); + void OnDevToolsSearchCompleted(int request_id, + const std::string& file_system_path, + const std::vector& file_paths); + // Set fullscreen mode triggered by html api. void SetHtmlApiFullscreen(bool enter_fullscreen); @@ -119,19 +146,30 @@ class CommonWebContentsDelegate // Whether window is fullscreened by window api. bool native_fullscreen_; - scoped_ptr web_dialog_helper_; - scoped_ptr dialog_manager_; + std::unique_ptr web_dialog_helper_; + std::unique_ptr dialog_manager_; + scoped_refptr devtools_file_system_indexer_; + + // Make sure BrowserContext is alwasys destroyed after WebContents. + scoped_refptr browser_context_; // The stored InspectableWebContents object. // Notice that web_contents_ must be placed after dialog_manager_, so we can // make sure web_contents_ is destroyed before dialog_manager_, otherwise a // crash would happen. - scoped_ptr web_contents_; + std::unique_ptr web_contents_; // Maps url to file path, used by the file requests sent from devtools. typedef std::map PathsMap; PathsMap saved_files_; + // Map id to index job, used for file system indexing requests from devtools. + typedef std::map< + int, + scoped_refptr> + DevToolsIndexingJobsMap; + DevToolsIndexingJobsMap devtools_indexing_jobs_; + DISALLOW_COPY_AND_ASSIGN(CommonWebContentsDelegate); }; diff --git a/atom/browser/common_web_contents_delegate_mac.mm b/atom/browser/common_web_contents_delegate_mac.mm new file mode 100644 index 000000000000..69117f190532 --- /dev/null +++ b/atom/browser/common_web_contents_delegate_mac.mm @@ -0,0 +1,39 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/common_web_contents_delegate.h" + +#import + +#include "content/public/browser/native_web_keyboard_event.h" +#include "ui/events/keycodes/keyboard_codes.h" + +namespace atom { + +void CommonWebContentsDelegate::HandleKeyboardEvent( + content::WebContents* source, + const content::NativeWebKeyboardEvent& event) { + if (event.skip_in_browser || + event.type == content::NativeWebKeyboardEvent::Char) + return; + + // Escape exits tabbed fullscreen mode. + if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) + ExitFullscreenModeForTab(source); + + BOOL handled = [[NSApp mainMenu] performKeyEquivalent:event.os_event]; + if (!handled && event.os_event.window) { + // Handle the cmd+~ shortcut. + if ((event.os_event.modifierFlags & NSCommandKeyMask) /* cmd */ && + (event.os_event.keyCode == 50 /* ~ */)) { + if (event.os_event.modifierFlags & NSShiftKeyMask) { + [NSApp sendAction:@selector(_cycleWindowsReversed:) to:nil from:nil]; + } else { + [NSApp sendAction:@selector(_cycleWindows:) to:nil from:nil]; + } + } + } +} + +} // namespace atom diff --git a/atom/browser/common_web_contents_delegate_views.cc b/atom/browser/common_web_contents_delegate_views.cc new file mode 100644 index 000000000000..d70884c45c2a --- /dev/null +++ b/atom/browser/common_web_contents_delegate_views.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/common_web_contents_delegate.h" + +#include "atom/browser/native_window_views.h" +#include "base/strings/string_util.h" +#include "content/public/browser/native_web_keyboard_event.h" +#include "ui/events/keycodes/keyboard_codes.h" + +#if defined(USE_X11) +#include "atom/browser/browser.h" +#endif + +namespace atom { + +void CommonWebContentsDelegate::HandleKeyboardEvent( + content::WebContents* source, + const content::NativeWebKeyboardEvent& event) { + // Escape exits tabbed fullscreen mode. + if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) + ExitFullscreenModeForTab(source); + + // Let the NativeWindow handle other parts. + if (owner_window()) + owner_window()->HandleKeyboardEvent(source, event); +} + +gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() { + if (!owner_window()) + return gfx::ImageSkia(); + return static_cast(static_cast( + owner_window()))->GetWindowAppIcon(); +} + +#if defined(USE_X11) +void CommonWebContentsDelegate::GetDevToolsWindowWMClass( + std::string* name, std::string* class_name) { + *class_name = Browser::Get()->GetName(); + *name = base::ToLowerASCII(*class_name); +} +#endif + +} // namespace atom diff --git a/atom/browser/lib/bluetooth_chooser.cc b/atom/browser/lib/bluetooth_chooser.cc new file mode 100644 index 000000000000..2ed21bd333fd --- /dev/null +++ b/atom/browser/lib/bluetooth_chooser.cc @@ -0,0 +1,107 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/lib/bluetooth_chooser.h" +#include "atom/common/native_mate_converters/callback.h" +#include "atom/common/native_mate_converters/string16_converter.h" +#include "native_mate/dictionary.h" + +namespace mate { + +template<> +struct Converter { + static v8::Local ToV8( + v8::Isolate* isolate, const atom::BluetoothChooser::DeviceInfo& val) { + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("deviceName", val.device_name); + dict.Set("deviceId", val.device_id); + return mate::ConvertToV8(isolate, dict); + } +}; + +} // namespace mate + +namespace atom { + +namespace { + +const int kMaxScanRetries = 5; + +void OnDeviceChosen( + const content::BluetoothChooser::EventHandler& handler, + const std::string& device_id) { + if (device_id.empty()) { + handler.Run(content::BluetoothChooser::Event::CANCELLED, device_id); + } else { + handler.Run(content::BluetoothChooser::Event::SELECTED, device_id); + } +} + +} // namespace + +BluetoothChooser::BluetoothChooser( + api::WebContents* contents, + const EventHandler& event_handler) + : api_web_contents_(contents), + event_handler_(event_handler), + num_retries_(0) { +} + +BluetoothChooser::~BluetoothChooser() { +} + +void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) { + switch (presence) { + case AdapterPresence::ABSENT: + case AdapterPresence::POWERED_OFF: + event_handler_.Run(Event::CANCELLED, ""); + break; + case AdapterPresence::POWERED_ON: + break; + } +} + +void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) { + switch (state) { + case DiscoveryState::FAILED_TO_START: + event_handler_.Run(Event::CANCELLED, ""); + break; + case DiscoveryState::IDLE: + if (device_list_.empty()) { + auto event = ++num_retries_ > kMaxScanRetries ? Event::CANCELLED + : Event::RESCAN; + event_handler_.Run(event, ""); + } else { + bool prevent_default = + api_web_contents_->Emit("select-bluetooth-device", + device_list_, + base::Bind(&OnDeviceChosen, + event_handler_)); + if (!prevent_default) { + auto device_id = device_list_[0].device_id; + event_handler_.Run(Event::SELECTED, device_id); + } + } + break; + case DiscoveryState::DISCOVERING: + break; + } +} + +void BluetoothChooser::AddDevice(const std::string& device_id, + const base::string16& device_name) { + DeviceInfo info = {device_id, device_name}; + device_list_.push_back(info); +} + +void BluetoothChooser::RemoveDevice(const std::string& device_id) { + for (auto it = device_list_.begin(); it != device_list_.end(); ++it) { + if (it->device_id == device_id) { + device_list_.erase(it); + return; + } + } +} + +} // namespace atom diff --git a/atom/browser/lib/bluetooth_chooser.h b/atom/browser/lib/bluetooth_chooser.h new file mode 100644 index 000000000000..615dfcb8c663 --- /dev/null +++ b/atom/browser/lib/bluetooth_chooser.h @@ -0,0 +1,45 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ +#define ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ + +#include +#include + +#include "atom/browser/api/atom_api_web_contents.h" +#include "content/public/browser/bluetooth_chooser.h" + +namespace atom { + +class BluetoothChooser : public content::BluetoothChooser { + public: + struct DeviceInfo { + std::string device_id; + base::string16 device_name; + }; + + explicit BluetoothChooser(api::WebContents* contents, + const EventHandler& handler); + ~BluetoothChooser() override; + + // content::BluetoothChooser: + void SetAdapterPresence(AdapterPresence presence) override; + void ShowDiscoveryState(DiscoveryState state) override; + void AddDevice(const std::string& device_id, + const base::string16& device_name) override; + void RemoveDevice(const std::string& device_id) override; + + private: + std::vector device_list_; + api::WebContents* api_web_contents_; + EventHandler event_handler_; + int num_retries_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothChooser); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ diff --git a/atom/browser/login_handler.cc b/atom/browser/login_handler.cc index 7a1a77cc2b13..1a6c6947b617 100644 --- a/atom/browser/login_handler.cc +++ b/atom/browser/login_handler.cc @@ -37,10 +37,11 @@ LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info, render_frame_id_(0) { content::ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame( &render_process_host_id_, &render_frame_id_); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&Browser::RequestLogin, - base::Unretained(Browser::Get()), - make_scoped_refptr(this))); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&Browser::RequestLogin, + base::Unretained(Browser::Get()), + base::RetainedRef(make_scoped_refptr(this)))); } LoginHandler::~LoginHandler() { diff --git a/atom/browser/mac/atom_application.h b/atom/browser/mac/atom_application.h index e6489b75fb9f..73baf9e7d980 100644 --- a/atom/browser/mac/atom_application.h +++ b/atom/browser/mac/atom_application.h @@ -21,6 +21,8 @@ - (void)setHandlingSendEvent:(BOOL)handlingSendEvent; - (NSUserActivity*)getCurrentActivity; -- (void)setCurrentActivity:(NSString*)type withUserInfo:(NSDictionary*)userInfo; +- (void)setCurrentActivity:(NSString*)type + withUserInfo:(NSDictionary*)userInfo + withWebpageURL:(NSURL*)webpageURL; @end diff --git a/atom/browser/mac/atom_application.mm b/atom/browser/mac/atom_application.mm index fa91836f29e0..ea64af3a04d2 100644 --- a/atom/browser/mac/atom_application.mm +++ b/atom/browser/mac/atom_application.mm @@ -29,10 +29,12 @@ } - (void)setCurrentActivity:(NSString*)type - withUserInfo:(NSDictionary*)userInfo { + withUserInfo:(NSDictionary*)userInfo + withWebpageURL:(NSURL*)webpageURL { currentActivity_ = base::scoped_nsobject( [[NSUserActivity alloc] initWithActivityType:type]); [currentActivity_ setUserInfo:userInfo]; + [currentActivity_ setWebpageURL:webpageURL]; [currentActivity_ becomeCurrent]; } diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 7fa3b3027f6c..84caae9d5ee3 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -65,7 +65,7 @@ continueUserActivity:(NSUserActivity*)userActivity restorationHandler:(void (^)(NSArray*restorableObjects))restorationHandler { std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType)); - scoped_ptr user_info = + std::unique_ptr user_info = atom::NSDictionaryToDictionaryValue(userActivity.userInfo); if (!user_info) return NO; diff --git a/atom/browser/mac/dict_util.h b/atom/browser/mac/dict_util.h index e5b293652d8a..404636d1901a 100644 --- a/atom/browser/mac/dict_util.h +++ b/atom/browser/mac/dict_util.h @@ -18,7 +18,7 @@ namespace atom { NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value); -scoped_ptr NSDictionaryToDictionaryValue( +std::unique_ptr NSDictionaryToDictionaryValue( NSDictionary* dict); } // namespace atom diff --git a/atom/browser/mac/dict_util.mm b/atom/browser/mac/dict_util.mm index 6a98e4cfdaad..43b629cc32be 100644 --- a/atom/browser/mac/dict_util.mm +++ b/atom/browser/mac/dict_util.mm @@ -4,13 +4,55 @@ #include "atom/browser/mac/dict_util.h" -#include "base/mac/scoped_nsobject.h" -#include "base/json/json_reader.h" #include "base/json/json_writer.h" +#include "base/strings/sys_string_conversions.h" #include "base/values.h" namespace atom { +namespace { + +std::unique_ptr NSArrayToListValue(NSArray* arr) { + if (!arr) + return nullptr; + + std::unique_ptr result(new base::ListValue); + for (id value in arr) { + if ([value isKindOfClass:[NSString class]]) { + result->AppendString(base::SysNSStringToUTF8(value)); + } else if ([value isKindOfClass:[NSNumber class]]) { + const char* objc_type = [value objCType]; + if (strcmp(objc_type, @encode(BOOL)) == 0 || + strcmp(objc_type, @encode(char)) == 0) + result->AppendBoolean([value boolValue]); + else if (strcmp(objc_type, @encode(double)) == 0 || + strcmp(objc_type, @encode(float)) == 0) + result->AppendDouble([value doubleValue]); + else + result->AppendInteger([value intValue]); + } else if ([value isKindOfClass:[NSArray class]]) { + std::unique_ptr sub_arr = NSArrayToListValue(value); + if (sub_arr) + result->Append(std::move(sub_arr)); + else + result->Append(base::Value::CreateNullValue()); + } else if ([value isKindOfClass:[NSDictionary class]]) { + std::unique_ptr sub_dict = + NSDictionaryToDictionaryValue(value); + if (sub_dict) + result->Append(std::move(sub_dict)); + else + result->Append(base::Value::CreateNullValue()); + } else { + result->AppendString(base::SysNSStringToUTF8([value description])); + } + } + + return result; +} + +} // namespace + NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value) { std::string json; if (!base::JSONWriter::Write(value, &json)) @@ -24,19 +66,53 @@ NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value) return obj; } -scoped_ptr NSDictionaryToDictionaryValue( +std::unique_ptr NSDictionaryToDictionaryValue( NSDictionary* dict) { - NSData* data = [NSJSONSerialization dataWithJSONObject:dict - options:0 - error:nil]; - if (!data) + if (!dict) return nullptr; - base::scoped_nsobject json = - [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - scoped_ptr value = - base::JSONReader::Read([json UTF8String]); - return base::DictionaryValue::From(std::move(value)); + std::unique_ptr result(new base::DictionaryValue); + for (id key in dict) { + std::string str_key = base::SysNSStringToUTF8( + [key isKindOfClass:[NSString class]] ? key : [key description]); + + id value = [dict objectForKey:key]; + if ([value isKindOfClass:[NSString class]]) { + result->SetStringWithoutPathExpansion( + str_key, base::SysNSStringToUTF8(value)); + } else if ([value isKindOfClass:[NSNumber class]]) { + const char* objc_type = [value objCType]; + if (strcmp(objc_type, @encode(BOOL)) == 0 || + strcmp(objc_type, @encode(char)) == 0) + result->SetBooleanWithoutPathExpansion(str_key, [value boolValue]); + else if (strcmp(objc_type, @encode(double)) == 0 || + strcmp(objc_type, @encode(float)) == 0) + result->SetDoubleWithoutPathExpansion(str_key, [value doubleValue]); + else + result->SetIntegerWithoutPathExpansion(str_key, [value intValue]); + } else if ([value isKindOfClass:[NSArray class]]) { + std::unique_ptr sub_arr = NSArrayToListValue(value); + if (sub_arr) + result->SetWithoutPathExpansion(str_key, std::move(sub_arr)); + else + result->SetWithoutPathExpansion(str_key, + base::Value::CreateNullValue()); + } else if ([value isKindOfClass:[NSDictionary class]]) { + std::unique_ptr sub_dict = + NSDictionaryToDictionaryValue(value); + if (sub_dict) + result->SetWithoutPathExpansion(str_key, std::move(sub_dict)); + else + result->SetWithoutPathExpansion(str_key, + base::Value::CreateNullValue()); + } else { + result->SetStringWithoutPathExpansion( + str_key, + base::SysNSStringToUTF8([value description])); + } + } + + return result; } } // namespace atom diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 2379bdd053c5..c22159fc25db 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -12,12 +12,11 @@ #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/window_list.h" #include "atom/common/api/api_messages.h" -#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/options_switches.h" #include "base/files/file_util.h" #include "base/json/json_writer.h" -#include "base/prefs/pref_service.h" +#include "components/prefs/pref_service.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" @@ -49,12 +48,12 @@ NativeWindow::NativeWindow( const mate::Dictionary& options) : content::WebContentsObserver(inspectable_web_contents->GetWebContents()), has_frame_(true), - force_using_draggable_region_(false), transparent_(false), enable_larger_than_screen_(false), is_closed_(false), has_dialog_attached_(false), - sheet_offset_(0.0), + sheet_offset_x_(0.0), + sheet_offset_y_(0.0), aspect_ratio_(0.0), inspectable_web_contents_(inspectable_web_contents), weak_factory_(this) { @@ -66,9 +65,6 @@ NativeWindow::NativeWindow( // mode. ui::GpuSwitchingManager::SetTransparent(transparent_); - // Read icon before window is created. - options.Get(options::kIcon, &icon_); - WindowList::AddWindow(this); } @@ -141,11 +137,14 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { if (options.Get(options::kAlwaysOnTop, &top) && top) { SetAlwaysOnTop(true); } - // Disable fullscreen button if 'fullscreen' is specified to false. bool fullscreenable = true; bool fullscreen = false; - if (options.Get(options::kFullscreen, &fullscreen) && !fullscreen) + if (options.Get(options::kFullscreen, &fullscreen) && !fullscreen) { + // Disable fullscreen button if 'fullscreen' is specified to false. + #if defined(OS_MACOSX) fullscreenable = false; + #endif + } // Overriden by 'fullscreenable'. options.Get(options::kFullScreenable, &fullscreenable); SetFullScreenable(fullscreenable); @@ -255,12 +254,17 @@ gfx::Size NativeWindow::GetMaximumSize() { return GetSizeConstraints().GetMaximumSize(); } -void NativeWindow::SetSheetOffset(const double offset) { - sheet_offset_ = offset; +void NativeWindow::SetSheetOffset(const double offsetX, const double offsetY) { + sheet_offset_x_ = offsetX; + sheet_offset_y_ = offsetY; } -double NativeWindow::GetSheetOffset() { - return sheet_offset_; +double NativeWindow::GetSheetOffsetX() { + return sheet_offset_x_; +} + +double NativeWindow::GetSheetOffsetY() { + return sheet_offset_y_; } void NativeWindow::SetRepresentedFilename(const std::string& filename) { @@ -318,9 +322,9 @@ void NativeWindow::CapturePage(const gfx::Rect& rect, // current system, increase the requested bitmap size to capture it all. gfx::Size bitmap_size = view_size; const gfx::NativeView native_view = view->GetNativeView(); - gfx::Screen* const screen = gfx::Screen::GetScreenFor(native_view); const float scale = - screen->GetDisplayNearestWindow(native_view).device_scale_factor(); + gfx::Screen::GetScreen()->GetDisplayNearestWindow(native_view) + .device_scale_factor(); if (scale > 1.0f) bitmap_size = gfx::ScaleToCeiledSize(view_size, scale); @@ -412,7 +416,7 @@ void NativeWindow::RendererUnresponsive(content::WebContents* source) { // responsive event soon. This could happen after the whole application had // blocked for a while. // Also notice that when closing this event would be ignored because we have - // explicity started a close timeout counter. This is on purpose because we + // explicitly started a close timeout counter. This is on purpose because we // don't want the unresponsive event to be sent too early when user is closing // the window. ScheduleUnresponsiveEvent(50); @@ -526,9 +530,9 @@ void NativeWindow::NotifyWindowMessage( } #endif -scoped_ptr NativeWindow::DraggableRegionsToSkRegion( +std::unique_ptr NativeWindow::DraggableRegionsToSkRegion( const std::vector& regions) { - scoped_ptr sk_region(new SkRegion); + std::unique_ptr sk_region(new SkRegion); for (const DraggableRegion& region : regions) { sk_region->op( region.bounds.x(), @@ -573,7 +577,7 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) { void NativeWindow::UpdateDraggableRegions( const std::vector& regions) { // Draggable region is not supported for non-frameless window. - if (has_frame_ && !force_using_draggable_region_) + if (has_frame_) return; draggable_region_ = DraggableRegionsToSkRegion(regions); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index f3acf6222314..0846fbde4a9c 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -123,8 +123,9 @@ class NativeWindow : public base::SupportsUserData, virtual gfx::Size GetMinimumSize(); virtual void SetMaximumSize(const gfx::Size& size); virtual gfx::Size GetMaximumSize(); - virtual void SetSheetOffset(const double offset); - virtual double GetSheetOffset(); + virtual void SetSheetOffset(const double offsetX, const double offsetY); + virtual double GetSheetOffsetX(); + virtual double GetSheetOffsetY(); virtual void SetResizable(bool resizable) = 0; virtual bool IsResizable() = 0; virtual void SetMovable(bool movable) = 0; @@ -190,7 +191,7 @@ class NativeWindow : public base::SupportsUserData, // Set the aspect ratio when resizing window. double GetAspectRatio(); gfx::Size GetAspectRatioExtraSize(); - void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size); + virtual void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size); base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); @@ -246,17 +247,11 @@ class NativeWindow : public base::SupportsUserData, } bool has_frame() const { return has_frame_; } + void set_has_frame(bool has_frame) { has_frame_ = has_frame; } + bool transparent() const { return transparent_; } SkRegion* draggable_region() const { return draggable_region_.get(); } bool enable_larger_than_screen() const { return enable_larger_than_screen_; } - gfx::ImageSkia icon() const { return icon_; } - - bool force_using_draggable_region() const { - return force_using_draggable_region_; - } - void set_force_using_draggable_region(bool force) { - force_using_draggable_region_ = true; - } void set_has_dialog_attached(bool has_dialog_attached) { has_dialog_attached_ = has_dialog_attached; @@ -268,7 +263,7 @@ class NativeWindow : public base::SupportsUserData, // Convert draggable regions in raw format to SkRegion format. Caller is // responsible for deleting the returned SkRegion instance. - scoped_ptr DraggableRegionsToSkRegion( + std::unique_ptr DraggableRegionsToSkRegion( const std::vector& regions); // Converts between content size to window size. @@ -299,15 +294,12 @@ class NativeWindow : public base::SupportsUserData, // Whether window has standard frame. bool has_frame_; - // Force the window to be aware of draggable regions. - bool force_using_draggable_region_; - // Whether window is transparent. bool transparent_; // For custom drag, the whole window is non-draggable and the draggable region // has to been explicitly provided. - scoped_ptr draggable_region_; // used in custom drag. + std::unique_ptr draggable_region_; // used in custom drag. // Minimum and maximum size, stored as content size. extensions::SizeConstraints size_constraints_; @@ -315,9 +307,6 @@ class NativeWindow : public base::SupportsUserData, // Whether window can be resized larger than screen. bool enable_larger_than_screen_; - // Window icon. - gfx::ImageSkia icon_; - // The windows has been closed. bool is_closed_; @@ -328,8 +317,10 @@ class NativeWindow : public base::SupportsUserData, // it should be cancelled when we can prove that the window is responsive. base::CancelableClosure window_unresposive_closure_; - // Used to display sheets at the appropriate vertical offset - double sheet_offset_; + // Used to display sheets at the appropriate horizontal and vertical offsets + // on OS X. + double sheet_offset_x_; + double sheet_offset_y_; // Used to maintain the aspect ratio of a view which is inside of the // content view. diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 93d03e4c157c..c1694c3c784a 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -49,6 +49,8 @@ class NativeWindowMac : public NativeWindow { void SetResizable(bool resizable) override; bool IsResizable() override; void SetMovable(bool movable) override; + void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size) + override; bool IsMovable() override; void SetMinimizable(bool minimizable) override; bool IsMinimizable() override; @@ -91,16 +93,15 @@ class NativeWindowMac : public NativeWindow { UpdateDraggableRegionViews(draggable_regions_); } + // Set the attribute of NSWindow while work around a bug of zoom button. + void SetStyleMask(bool on, NSUInteger flag); + void SetCollectionBehavior(bool on, NSUInteger flag); + bool should_hide_native_toolbar_in_fullscreen() const { return should_hide_native_toolbar_in_fullscreen_; } protected: - // NativeWindow: - void HandleKeyboardEvent( - content::WebContents*, - const content::NativeWebKeyboardEvent&) override; - // Return a vector of non-draggable regions that fill a window of size // |width| by |height|, but leave gaps where the window should be draggable. std::vector CalculateNonDraggableRegions( @@ -120,10 +121,6 @@ class NativeWindowMac : public NativeWindow { // whehter we can drag. void UpdateDraggableRegionViews(const std::vector& regions); - // Set the attribute of NSWindow while work around a bug of zo0m button. - void SetStyleMask(bool on, NSUInteger flag); - void SetCollectionBehavior(bool on, NSUInteger flag); - base::scoped_nsobject window_; base::scoped_nsobject window_delegate_; @@ -142,6 +139,10 @@ class NativeWindowMac : public NativeWindow { // The presentation options before entering kiosk mode. NSApplicationPresentationOptions kiosk_options_; + // Force showing the buttons for frameless window. + bool force_show_buttons_; + + // Whether to hide the native toolbar under fullscreen mode. bool should_hide_native_toolbar_in_fullscreen_; DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 04569d8f50f9..8bc4052f8538 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -6,6 +6,7 @@ #include +#include "atom/browser/window_list.h" #include "atom/common/color_util.h" #include "atom/common/draggable_region.h" #include "atom/common/options_switches.h" @@ -15,7 +16,6 @@ #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" #include "content/public/browser/browser_accessibility_state.h" -#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" @@ -142,22 +142,9 @@ bool ScopedDisableResize::disable_resize_ = false; newSize.width = roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio + extraWidthPlusFrame); - - // If the new width is less than the frame size use it as the primary - // constraint. This ensures that the value returned by this method will - // never be larger than the users requested window size. - if (newSize.width <= frameSize.width) { - newSize.height = - roundf((newSize.width - extraWidthPlusFrame) / aspectRatio + - extraHeightPlusFrame); - } else { - newSize.height = - roundf((frameSize.width - extraWidthPlusFrame) / aspectRatio + - extraHeightPlusFrame); - newSize.width = - roundf((newSize.height - extraHeightPlusFrame) * aspectRatio + - extraWidthPlusFrame); - } + newSize.height = + roundf((newSize.width - extraWidthPlusFrame) / aspectRatio + + extraHeightPlusFrame); } return newSize; @@ -214,10 +201,22 @@ bool ScopedDisableResize::disable_resize_ = false; [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); [toolbar setShowsBaselineSeparator:NO]; [window setToolbar:toolbar]; + + // Set window style to hide the toolbar, otherwise the toolbar will show in + // fullscreen mode. + shell_->SetStyleMask(true, NSFullSizeContentViewWindowMask); } } +- (void)windowWillExitFullScreen:(NSNotification*)notification { + // Turn off the style for toolbar. + if (shell_->should_hide_native_toolbar_in_fullscreen()) + shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask); +} + - (void)windowDidExitFullScreen:(NSNotification*)notification { + // For certain versions of OS X the fullscreen button will automatically show + // after exiting fullscreen mode. if (!shell_->has_frame()) { NSWindow* window = shell_->GetNativeWindow(); [[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES]; @@ -246,7 +245,9 @@ bool ScopedDisableResize::disable_resize_ = false; - (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet usingRect:(NSRect)rect { NSView* view = window.contentView; - rect.origin.y = view.frame.size.height - shell_->GetSheetOffset(); + + rect.origin.x = shell_->GetSheetOffsetX(); + rect.origin.y = view.frame.size.height - shell_->GetSheetOffsetY(); return rect; } @@ -391,6 +392,7 @@ NativeWindowMac::NativeWindowMac( : NativeWindow(web_contents, options), is_kiosk_(false), attention_request_id_(0), + force_show_buttons_(false), should_hide_native_toolbar_in_fullscreen_(false) { int width = 800, height = 600; options.Get(options::kWidth, &width); @@ -438,22 +440,17 @@ NativeWindowMac::NativeWindowMac( if (closable) { styleMask |= NSClosableWindowMask; } + if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { + // The window without titlebar is treated the same with frameless window. + set_has_frame(false); + force_show_buttons_ = true; + } if (!useStandardWindow || transparent() || !has_frame()) { styleMask |= NSTexturedBackgroundWindowMask; } if (resizable) { styleMask |= NSResizableWindowMask; } - if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { - styleMask |= NSFullSizeContentViewWindowMask; - styleMask |= NSUnifiedTitleAndToolbarWindowMask; - } - // We capture this because we need to access the option later when - // entering/exiting fullscreen and since the options dict is only passed to - // the constructor but not stored, let’s store this option this way. - if (titleBarStyle == "hidden-inset") { - should_hide_native_toolbar_in_fullscreen_ = true; - } window_.reset([[AtomNSWindow alloc] initWithContentRect:cocoa_bounds @@ -490,17 +487,14 @@ NativeWindowMac::NativeWindowMac( [window_ setReleasedWhenClosed:NO]; // Hide the title bar. - if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { + if (titleBarStyle == "hidden-inset") { [window_ setTitlebarAppearsTransparent:YES]; [window_ setTitleVisibility:NSWindowTitleHidden]; - if (titleBarStyle == "hidden-inset") { - base::scoped_nsobject toolbar( - [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); - [toolbar setShowsBaselineSeparator:NO]; - [window_ setToolbar:toolbar]; - } - // We should be aware of draggable regions when using hidden titlebar. - set_force_using_draggable_region(true); + base::scoped_nsobject toolbar( + [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); + [toolbar setShowsBaselineSeparator:NO]; + [window_ setToolbar:toolbar]; + should_hide_native_toolbar_in_fullscreen_ = true; } // On OS X the initial window size doesn't include window frame. @@ -558,6 +552,11 @@ NativeWindowMac::~NativeWindowMac() { } void NativeWindowMac::Close() { + if (!IsClosable()) { + WindowList::WindowCloseCancelled(this); + return; + } + [window_ performClose:nil]; } @@ -713,6 +712,17 @@ bool NativeWindowMac::IsResizable() { return [window_ styleMask] & NSResizableWindowMask; } +void NativeWindowMac::SetAspectRatio(double aspect_ratio, + const gfx::Size& extra_size) { + NativeWindow::SetAspectRatio(aspect_ratio, extra_size); + + // Reset the behaviour to default if aspect_ratio is set to 0 or less. + if (aspect_ratio > 0.0) + [window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)]; + else + [window_ setResizeIncrements:NSMakeSize(1.0, 1.0)]; +} + void NativeWindowMac::SetMovable(bool movable) { [window_ setMovable:movable]; } @@ -928,35 +938,14 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() { return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces; } -void NativeWindowMac::HandleKeyboardEvent( - content::WebContents*, - const content::NativeWebKeyboardEvent& event) { - if (event.skip_in_browser || - event.type == content::NativeWebKeyboardEvent::Char) - return; - - BOOL handled = [[NSApp mainMenu] performKeyEquivalent:event.os_event]; - if (!handled && event.os_event.window) { - // Handle the cmd+~ shortcut. - if ((event.os_event.modifierFlags & NSCommandKeyMask) /* cmd */ && - (event.os_event.keyCode == 50 /* ~ */)) { - if (event.os_event.modifierFlags & NSShiftKeyMask) { - [NSApp sendAction:@selector(_cycleWindowsReversed:) to:nil from:nil]; - } else { - [NSApp sendAction:@selector(_cycleWindows:) to:nil from:nil]; - } - } - } -} - std::vector NativeWindowMac::CalculateNonDraggableRegions( const std::vector& regions, int width, int height) { std::vector result; if (regions.empty()) { result.push_back(gfx::Rect(0, 0, width, height)); } else { - scoped_ptr draggable(DraggableRegionsToSkRegion(regions)); - scoped_ptr non_draggable(new SkRegion); + std::unique_ptr draggable(DraggableRegionsToSkRegion(regions)); + std::unique_ptr non_draggable(new SkRegion); non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); non_draggable->op(*draggable, SkRegion::kDifference_Op); for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { @@ -1013,6 +1002,10 @@ void NativeWindowMac::InstallView() { [view setFrame:[content_view_ bounds]]; [content_view_ addSubview:view]; + if (force_show_buttons_) + return; + + // Hide the window buttons. [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; @@ -1031,7 +1024,7 @@ void NativeWindowMac::UninstallView() { void NativeWindowMac::UpdateDraggableRegionViews( const std::vector& regions) { - if (has_frame() && !force_using_draggable_region()) + if (has_frame()) return; // All ControlRegionViews should be added as children of the WebContentsView, diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 93e43661302e..e699892d4ac5 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -9,8 +9,10 @@ #include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/ui/views/menu_layout.h" +#include "atom/browser/window_list.h" #include "atom/common/color_util.h" #include "atom/common/draggable_region.h" +#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/options_switches.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" @@ -40,6 +42,7 @@ #include "chrome/browser/ui/libgtk2ui/unity_service.h" #include "ui/base/x/x11_util.h" #include "ui/gfx/x/x11_types.h" +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" #include "ui/views/window/native_frame_view.h" #elif defined(OS_WIN) #include "atom/browser/ui/views/win_frame_view.h" @@ -273,7 +276,6 @@ NativeWindowViews::NativeWindowViews( use_content_size_) size = ContentSizeToWindowSize(size); - window_->UpdateWindowIcon(); window_->CenterWindow(size); Layout(); } @@ -283,6 +285,11 @@ NativeWindowViews::~NativeWindowViews() { } void NativeWindowViews::Close() { + if (!IsClosable()) { + WindowList::WindowCloseCancelled(this); + return; + } + window_->Close(); } @@ -623,7 +630,9 @@ void NativeWindowViews::SetBackgroundColor(const std::string& color_name) { // Set the background color of native window. HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color)); ULONG_PTR previous_brush = SetClassLongPtr( - GetAcceleratedWidget(), GCLP_HBRBACKGROUND, (LONG)brush); + GetAcceleratedWidget(), + GCLP_HBRBACKGROUND, + reinterpret_cast(brush)); if (previous_brush) DeleteObject((HBRUSH)previous_brush); #endif @@ -776,6 +785,27 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); } +#if defined(OS_WIN) +void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) { + // We are responsible for storing the images. + window_icon_ = base::win::ScopedHICON(CopyIcon(window_icon)); + app_icon_ = base::win::ScopedHICON(CopyIcon(app_icon)); + + HWND hwnd = GetAcceleratedWidget(); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, + reinterpret_cast(window_icon_.get())); + SendMessage(hwnd, WM_SETICON, ICON_BIG, + reinterpret_cast(app_icon_.get())); +} +#elif defined(USE_X11) +void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) { + views::DesktopWindowTreeHostX11* tree_host = + views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget()); + static_cast(tree_host)->SetWindowIcons( + icon, icon); +} +#endif + void NativeWindowViews::OnWidgetActivationChanged( views::Widget* widget, bool active) { if (widget != window_.get()) @@ -840,14 +870,6 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const { return true; } -gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() { - return icon(); -} - -gfx::ImageSkia NativeWindowViews::GetWindowIcon() { - return GetWindowAppIcon(); -} - views::Widget* NativeWindowViews::GetWidget() { return window_.get(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index bcf3ca8bd16f..909c5b6fd4ba 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -17,6 +17,7 @@ #if defined(OS_WIN) #include "atom/browser/ui/win/message_handler_delegate.h" #include "atom/browser/ui/win/taskbar_host.h" +#include "base/win/scoped_gdi_object.h" #endif namespace views { @@ -104,6 +105,12 @@ class NativeWindowViews : public NativeWindow, gfx::AcceleratedWidget GetAcceleratedWidget() override; +#if defined(OS_WIN) + void SetIcon(HICON small_icon, HICON app_icon); +#elif defined(USE_X11) + void SetIcon(const gfx::ImageSkia& icon); +#endif + views::Widget* widget() const { return window_.get(); } #if defined(OS_WIN) @@ -125,8 +132,6 @@ class NativeWindowViews : public NativeWindow, bool CanMinimize() const override; base::string16 GetWindowTitle() const override; bool ShouldHandleSystemCommands() const override; - gfx::ImageSkia GetWindowAppIcon() override; - gfx::ImageSkia GetWindowIcon() override; views::Widget* GetWidget() override; const views::Widget* GetWidget() const override; views::View* GetContentsView() override; @@ -145,7 +150,6 @@ class NativeWindowViews : public NativeWindow, // MessageHandlerDelegate: bool PreHandleMSG( UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override; - void HandleSizeEvent(WPARAM w_param, LPARAM l_param); #endif @@ -167,19 +171,19 @@ class NativeWindowViews : public NativeWindow, // Returns the restore state for the window. ui::WindowShowState GetRestoredState(); - scoped_ptr window_; + std::unique_ptr window_; views::View* web_view_; // Managed by inspectable_web_contents_. - scoped_ptr menu_bar_; + std::unique_ptr menu_bar_; bool menu_bar_autohide_; bool menu_bar_visible_; bool menu_bar_alt_pressed_; #if defined(USE_X11) - scoped_ptr global_menu_bar_; + std::unique_ptr global_menu_bar_; // Handles window state events. - scoped_ptr window_state_watcher_; + std::unique_ptr window_state_watcher_; // The "resizable" flag on Linux is implemented by setting size constraints, // we need to make sure size constraints are restored when window becomes @@ -203,10 +207,13 @@ class NativeWindowViews : public NativeWindow, // If true we have enabled a11y bool enabled_a11y_support_; + // The icons of window and taskbar. + base::win::ScopedHICON window_icon_; + base::win::ScopedHICON app_icon_; #endif // Handles unhandled keyboard messages coming back from the renderer process. - scoped_ptr keyboard_event_handler_; + std::unique_ptr keyboard_event_handler_; // Map from accelerator to menu item's command id. accelerator_util::AcceleratorTable accelerator_table_; diff --git a/atom/browser/net/asar/url_request_asar_job.h b/atom/browser/net/asar/url_request_asar_job.h index 7103abc4139a..56c519823c0e 100644 --- a/atom/browser/net/asar/url_request_asar_job.h +++ b/atom/browser/net/asar/url_request_asar_job.h @@ -112,7 +112,7 @@ class URLRequestAsarJob : public net::URLRequestJob { base::FilePath file_path_; Archive::FileInfo file_info_; - scoped_ptr stream_; + std::unique_ptr stream_; FileMetaInfo meta_info_; scoped_refptr file_task_runner_; diff --git a/atom/browser/net/atom_cert_verifier.cc b/atom/browser/net/atom_cert_verifier.cc index 3633d805fb5b..adfba7060c90 100644 --- a/atom/browser/net/atom_cert_verifier.cc +++ b/atom/browser/net/atom_cert_verifier.cc @@ -48,7 +48,7 @@ int AtomCertVerifier::Verify( net::CRLSet* crl_set, net::CertVerifyResult* verify_result, const net::CompletionCallback& callback, - scoped_ptr* out_req, + std::unique_ptr* out_req, const net::BoundNetLog& net_log) { DCHECK_CURRENTLY_ON(BrowserThread::IO); diff --git a/atom/browser/net/atom_cert_verifier.h b/atom/browser/net/atom_cert_verifier.h index 796ae2849bda..e00ba260ec3f 100644 --- a/atom/browser/net/atom_cert_verifier.h +++ b/atom/browser/net/atom_cert_verifier.h @@ -34,14 +34,14 @@ class AtomCertVerifier : public net::CertVerifier { net::CRLSet* crl_set, net::CertVerifyResult* verify_result, const net::CompletionCallback& callback, - scoped_ptr* out_req, + std::unique_ptr* out_req, const net::BoundNetLog& net_log) override; bool SupportsOCSPStapling() override; private: base::Lock lock_; VerifyProc verify_proc_; - scoped_ptr default_cert_verifier_; + std::unique_ptr default_cert_verifier_; DISALLOW_COPY_AND_ASSIGN(AtomCertVerifier); }; diff --git a/atom/browser/net/atom_network_delegate.cc b/atom/browser/net/atom_network_delegate.cc index 3143cd3b2575..fd0c52b3554f 100644 --- a/atom/browser/net/atom_network_delegate.cc +++ b/atom/browser/net/atom_network_delegate.cc @@ -45,13 +45,13 @@ using ResponseHeadersContainer = std::pair*, const std::string&>; void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener, - scoped_ptr details) { + std::unique_ptr details) { return listener.Run(*(details.get())); } void RunResponseListener( const AtomNetworkDelegate::ResponseListener& listener, - scoped_ptr details, + std::unique_ptr details, const AtomNetworkDelegate::ResponseCallback& callback) { return listener.Run(*(details.get()), callback); } @@ -79,7 +79,7 @@ void ToDictionary(base::DictionaryValue* details, net::URLRequest* request) { details->SetString("resourceType", info ? ResourceTypeToString(info->GetResourceType()) : "other"); - scoped_ptr list(new base::ListValue); + std::unique_ptr list(new base::ListValue); GetUploadData(list.get(), request); if (!list->empty()) details->Set("uploadData", std::move(list)); @@ -87,7 +87,7 @@ void ToDictionary(base::DictionaryValue* details, net::URLRequest* request) { void ToDictionary(base::DictionaryValue* details, const net::HttpRequestHeaders& headers) { - scoped_ptr dict(new base::DictionaryValue); + std::unique_ptr dict(new base::DictionaryValue); net::HttpRequestHeaders::Iterator it(headers); while (it.GetNext()) dict->SetString(it.name(), it.value()); @@ -99,8 +99,8 @@ void ToDictionary(base::DictionaryValue* details, if (!headers) return; - scoped_ptr dict(new base::DictionaryValue); - void* iter = nullptr; + std::unique_ptr dict(new base::DictionaryValue); + size_t iter = 0; std::string key; std::string value; while (headers->EnumerateHeaderLines(&iter, &key, &value)) { @@ -109,7 +109,7 @@ void ToDictionary(base::DictionaryValue* details, if (dict->GetList(key, &values)) values->AppendString(value); } else { - scoped_ptr values(new base::ListValue); + std::unique_ptr values(new base::ListValue); values->AppendString(value); dict->Set(key, std::move(values)); } @@ -369,7 +369,7 @@ int AtomNetworkDelegate::HandleResponseEvent( if (!MatchesFilterCondition(request, info.url_patterns)) return net::OK; - scoped_ptr details(new base::DictionaryValue); + std::unique_ptr details(new base::DictionaryValue); FillDetailsObject(details.get(), request, args...); // The |request| could be destroyed before the |callback| is called. @@ -392,7 +392,7 @@ void AtomNetworkDelegate::HandleSimpleEvent( if (!MatchesFilterCondition(request, info.url_patterns)) return; - scoped_ptr details(new base::DictionaryValue); + std::unique_ptr details(new base::DictionaryValue); FillDetailsObject(details.get(), request, args...); BrowserThread::PostTask( @@ -402,7 +402,7 @@ void AtomNetworkDelegate::HandleSimpleEvent( template void AtomNetworkDelegate::OnListenerResultInIO( - uint64_t id, T out, scoped_ptr response) { + uint64_t id, T out, std::unique_ptr response) { // The request has been destroyed. if (!ContainsKey(callbacks_, id)) return; @@ -417,7 +417,7 @@ void AtomNetworkDelegate::OnListenerResultInIO( template void AtomNetworkDelegate::OnListenerResultInUI( uint64_t id, T out, const base::DictionaryValue& response) { - scoped_ptr copy = response.CreateDeepCopy(); + std::unique_ptr copy = response.CreateDeepCopy(); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&AtomNetworkDelegate::OnListenerResultInIO, diff --git a/atom/browser/net/atom_network_delegate.h b/atom/browser/net/atom_network_delegate.h index 701a953c265e..62653df0baeb 100644 --- a/atom/browser/net/atom_network_delegate.h +++ b/atom/browser/net/atom_network_delegate.h @@ -111,7 +111,7 @@ class AtomNetworkDelegate : public brightray::NetworkDelegate { // Deal with the results of Listener. template void OnListenerResultInIO( - uint64_t id, T out, scoped_ptr response); + uint64_t id, T out, std::unique_ptr response); template void OnListenerResultInUI( uint64_t id, T out, const base::DictionaryValue& response); diff --git a/atom/browser/net/atom_url_request_job_factory.cc b/atom/browser/net/atom_url_request_job_factory.cc index dbd8b4160cfd..aff2565814b5 100644 --- a/atom/browser/net/atom_url_request_job_factory.cc +++ b/atom/browser/net/atom_url_request_job_factory.cc @@ -23,7 +23,8 @@ AtomURLRequestJobFactory::~AtomURLRequestJobFactory() { } bool AtomURLRequestJobFactory::SetProtocolHandler( - const std::string& scheme, scoped_ptr protocol_handler) { + const std::string& scheme, + std::unique_ptr protocol_handler) { if (!protocol_handler) { ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme); if (it == protocol_handler_map_.end()) @@ -40,8 +41,9 @@ bool AtomURLRequestJobFactory::SetProtocolHandler( return true; } -scoped_ptr AtomURLRequestJobFactory::ReplaceProtocol( - const std::string& scheme, scoped_ptr protocol_handler) { +std::unique_ptr AtomURLRequestJobFactory::ReplaceProtocol( + const std::string& scheme, + std::unique_ptr protocol_handler) { if (!ContainsKey(protocol_handler_map_, scheme)) return nullptr; ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme]; diff --git a/atom/browser/net/atom_url_request_job_factory.h b/atom/browser/net/atom_url_request_job_factory.h index dde36225b7af..e3dbd7754240 100644 --- a/atom/browser/net/atom_url_request_job_factory.h +++ b/atom/browser/net/atom_url_request_job_factory.h @@ -24,13 +24,14 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory { // Sets the ProtocolHandler for a scheme. Returns true on success, false on // failure (a ProtocolHandler already exists for |scheme|). On success, // URLRequestJobFactory takes ownership of |protocol_handler|. - bool SetProtocolHandler( - const std::string& scheme, scoped_ptr protocol_handler); + bool SetProtocolHandler(const std::string& scheme, + std::unique_ptr protocol_handler); // Intercepts the ProtocolHandler for a scheme. Returns the original protocol // handler on success, otherwise returns NULL. - scoped_ptr ReplaceProtocol( - const std::string& scheme, scoped_ptr protocol_handler); + std::unique_ptr ReplaceProtocol( + const std::string& scheme, + std::unique_ptr protocol_handler); // Returns the protocol handler registered with scheme. ProtocolHandler* GetProtocolHandler(const std::string& scheme) const; diff --git a/atom/browser/net/js_asker.cc b/atom/browser/net/js_asker.cc index b11a69c9c13b..8362c1add1c6 100644 --- a/atom/browser/net/js_asker.cc +++ b/atom/browser/net/js_asker.cc @@ -34,7 +34,7 @@ void HandlerCallback(const BeforeStartCallback& before_start, // Pass whatever user passed to the actaul request job. V8ValueConverter converter; v8::Local context = args->isolate()->GetCurrentContext(); - scoped_ptr options(converter.FromV8Value(value, context)); + std::unique_ptr options(converter.FromV8Value(value, context)); content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(callback, true, base::Passed(&options))); diff --git a/atom/browser/net/js_asker.h b/atom/browser/net/js_asker.h index 8a70794fa946..6301f4de2c2a 100644 --- a/atom/browser/net/js_asker.h +++ b/atom/browser/net/js_asker.h @@ -26,7 +26,7 @@ namespace internal { using BeforeStartCallback = base::Callback)>; using ResponseCallback = - base::Callback options)>; + base::Callback options)>; // Ask handler for options in UI thread. void AskForOptions(v8::Isolate* isolate, @@ -58,7 +58,7 @@ class JsAsker : public RequestJob { // Subclass should do initailze work here. virtual void BeforeStartInUI(v8::Isolate*, v8::Local) {} - virtual void StartAsync(scoped_ptr options) = 0; + virtual void StartAsync(std::unique_ptr options) = 0; net::URLRequestContextGetter* request_context_getter() const { return request_context_getter_; @@ -84,7 +84,7 @@ class JsAsker : public RequestJob { // Called when the JS handler has sent the response, we need to decide whether // to start, or fail the job. - void OnResponse(bool success, scoped_ptr value) { + void OnResponse(bool success, std::unique_ptr value) { int error = net::ERR_NOT_IMPLEMENTED; if (success && value && !internal::IsErrorOptions(value.get(), &error)) { StartAsync(std::move(value)); diff --git a/atom/browser/net/url_request_async_asar_job.cc b/atom/browser/net/url_request_async_asar_job.cc index 3578f3b7971c..1234bccf4303 100644 --- a/atom/browser/net/url_request_async_asar_job.cc +++ b/atom/browser/net/url_request_async_asar_job.cc @@ -16,7 +16,7 @@ URLRequestAsyncAsarJob::URLRequestAsyncAsarJob( : JsAsker(request, network_delegate) { } -void URLRequestAsyncAsarJob::StartAsync(scoped_ptr options) { +void URLRequestAsyncAsarJob::StartAsync(std::unique_ptr options) { base::FilePath::StringType file_path; if (options->IsType(base::Value::TYPE_DICTIONARY)) { static_cast(options.get())->GetString( diff --git a/atom/browser/net/url_request_async_asar_job.h b/atom/browser/net/url_request_async_asar_job.h index d65142f0bdbb..032f3d992413 100644 --- a/atom/browser/net/url_request_async_asar_job.h +++ b/atom/browser/net/url_request_async_asar_job.h @@ -16,7 +16,7 @@ class URLRequestAsyncAsarJob : public JsAsker { URLRequestAsyncAsarJob(net::URLRequest*, net::NetworkDelegate*); // JsAsker: - void StartAsync(scoped_ptr options) override; + void StartAsync(std::unique_ptr options) override; // URLRequestJob: void GetResponseInfo(net::HttpResponseInfo* info) override; diff --git a/atom/browser/net/url_request_buffer_job.cc b/atom/browser/net/url_request_buffer_job.cc index aa273bf81693..c713099c76a1 100644 --- a/atom/browser/net/url_request_buffer_job.cc +++ b/atom/browser/net/url_request_buffer_job.cc @@ -8,17 +8,31 @@ #include "atom/common/atom_constants.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "net/base/mime_util.h" #include "net/base/net_errors.h" namespace atom { +namespace { + +std::string GetExtFromURL(const GURL& url) { + std::string spec = url.spec(); + size_t index = spec.find_last_of('.'); + if (index == std::string::npos || index == spec.size()) + return std::string(); + return spec.substr(index + 1, spec.size() - index - 1); +} + +} // namespace + URLRequestBufferJob::URLRequestBufferJob( net::URLRequest* request, net::NetworkDelegate* network_delegate) : JsAsker(request, network_delegate), status_code_(net::HTTP_NOT_IMPLEMENTED) { } -void URLRequestBufferJob::StartAsync(scoped_ptr options) { +void URLRequestBufferJob::StartAsync(std::unique_ptr options) { const base::BinaryValue* binary = nullptr; if (options->IsType(base::Value::TYPE_DICTIONARY)) { base::DictionaryValue* dict = @@ -30,6 +44,15 @@ void URLRequestBufferJob::StartAsync(scoped_ptr options) { options->GetAsBinary(&binary); } + if (mime_type_.empty()) { + std::string ext = GetExtFromURL(request()->url()); +#if defined(OS_WIN) + net::GetWellKnownMimeTypeFromExtension(base::UTF8ToUTF16(ext), &mime_type_); +#else + net::GetWellKnownMimeTypeFromExtension(ext, &mime_type_); +#endif + } + if (!binary) { NotifyStartError(net::URLRequestStatus( net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED)); diff --git a/atom/browser/net/url_request_buffer_job.h b/atom/browser/net/url_request_buffer_job.h index ab8de7e8f030..356ca9347f6f 100644 --- a/atom/browser/net/url_request_buffer_job.h +++ b/atom/browser/net/url_request_buffer_job.h @@ -19,7 +19,7 @@ class URLRequestBufferJob : public JsAsker { URLRequestBufferJob(net::URLRequest*, net::NetworkDelegate*); // JsAsker: - void StartAsync(scoped_ptr options) override; + void StartAsync(std::unique_ptr options) override; // URLRequestJob: void GetResponseInfo(net::HttpResponseInfo* info) override; diff --git a/atom/browser/net/url_request_fetch_job.cc b/atom/browser/net/url_request_fetch_job.cc index 2f907314cad4..8279d09d5dad 100644 --- a/atom/browser/net/url_request_fetch_job.cc +++ b/atom/browser/net/url_request_fetch_job.cc @@ -59,7 +59,7 @@ class ResponsePiper : public net::URLFetcherResponseWriter { job_->HeadersCompleted(); first_write_ = false; } - return job_->DataAvailable(buffer, num_bytes); + return job_->DataAvailable(buffer, num_bytes, callback); } int Finish(const net::CompletionCallback& callback) override { return net::OK; @@ -77,7 +77,8 @@ class ResponsePiper : public net::URLFetcherResponseWriter { URLRequestFetchJob::URLRequestFetchJob( net::URLRequest* request, net::NetworkDelegate* network_delegate) : JsAsker(request, network_delegate), - pending_buffer_size_(0) { + pending_buffer_size_(0), + write_num_bytes_(0) { } void URLRequestFetchJob::BeforeStartInUI( @@ -99,7 +100,7 @@ void URLRequestFetchJob::BeforeStartInUI( } } -void URLRequestFetchJob::StartAsync(scoped_ptr options) { +void URLRequestFetchJob::StartAsync(std::unique_ptr options) { if (!options->IsType(base::Value::TYPE_DICTIONARY)) { NotifyStartError(net::URLRequestStatus( net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED)); @@ -166,22 +167,23 @@ void URLRequestFetchJob::HeadersCompleted() { NotifyHeadersComplete(); } -int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, int num_bytes) { - // Do nothing if pending_buffer_ is empty, i.e. there's no ReadRawData() - // operation waiting for IO completion. - if (!pending_buffer_.get()) +int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, + int num_bytes, + const net::CompletionCallback& callback) { + // When pending_buffer_ is empty, there's no ReadRawData() operation waiting + // for IO completion, we have to save the parameters until the request is + // ready to read data. + if (!pending_buffer_.get()) { + write_buffer_ = buffer; + write_num_bytes_ = num_bytes; + write_callback_ = callback; return net::ERR_IO_PENDING; + } - // pending_buffer_ is set to the IOBuffer instance provided to ReadRawData() - // by URLRequestJob. - int bytes_read = std::min(num_bytes, pending_buffer_size_); - memcpy(pending_buffer_->data(), buffer->data(), bytes_read); - - // Clear the buffers before notifying the read is complete, so that it is - // safe for the observer to read. - pending_buffer_ = nullptr; - pending_buffer_size_ = 0; - + // Write data to the pending buffer and clear them after the writing. + int bytes_read = BufferCopy(buffer, num_bytes, + pending_buffer_.get(), pending_buffer_size_); + ClearPendingBuffer(); ReadRawDataComplete(bytes_read); return bytes_read; } @@ -196,9 +198,22 @@ int URLRequestFetchJob::ReadRawData(net::IOBuffer* dest, int dest_size) { request()->set_received_response_content_length(prefilter_bytes_read()); return net::OK; } - pending_buffer_ = dest; - pending_buffer_size_ = dest_size; - return net::ERR_IO_PENDING; + + // When write_buffer_ is empty, there is no data valable yet, we have to save + // the dest buffer util DataAvailable. + if (!write_buffer_.get()) { + pending_buffer_ = dest; + pending_buffer_size_ = dest_size; + return net::ERR_IO_PENDING; + } + + // Read from the write buffer and clear them after reading. + int bytes_read = BufferCopy(write_buffer_.get(), write_num_bytes_, + dest, dest_size); + net::CompletionCallback write_callback = write_callback_; + ClearWriteBuffer(); + write_callback.Run(bytes_read); + return bytes_read; } bool URLRequestFetchJob::GetMimeType(std::string* mime_type) const { @@ -229,12 +244,31 @@ void URLRequestFetchJob::OnURLFetchComplete(const net::URLFetcher* source) { return; } - pending_buffer_ = nullptr; - pending_buffer_size_ = 0; + ClearPendingBuffer(); + ClearWriteBuffer(); + if (fetcher_->GetStatus().is_success()) ReadRawDataComplete(0); else NotifyStartError(fetcher_->GetStatus()); } +int URLRequestFetchJob::BufferCopy(net::IOBuffer* source, int num_bytes, + net::IOBuffer* target, int target_size) { + int bytes_written = std::min(num_bytes, target_size); + memcpy(target->data(), source->data(), bytes_written); + return bytes_written; +} + +void URLRequestFetchJob::ClearPendingBuffer() { + pending_buffer_ = nullptr; + pending_buffer_size_ = 0; +} + +void URLRequestFetchJob::ClearWriteBuffer() { + write_buffer_ = nullptr; + write_num_bytes_ = 0; + write_callback_.Reset(); +} + } // namespace atom diff --git a/atom/browser/net/url_request_fetch_job.h b/atom/browser/net/url_request_fetch_job.h index 69067fdc7fd3..906ba68d3965 100644 --- a/atom/browser/net/url_request_fetch_job.h +++ b/atom/browser/net/url_request_fetch_job.h @@ -9,14 +9,10 @@ #include "atom/browser/net/js_asker.h" #include "browser/url_request_context_getter.h" -#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_fetcher_delegate.h" -#include "net/url_request/url_request_job.h" namespace atom { -class AtomBrowserContext; - class URLRequestFetchJob : public JsAsker, public net::URLFetcherDelegate, public brightray::URLRequestContextGetter::Delegate { @@ -25,12 +21,14 @@ class URLRequestFetchJob : public JsAsker, // Called by response writer. void HeadersCompleted(); - int DataAvailable(net::IOBuffer* buffer, int num_bytes); + int DataAvailable(net::IOBuffer* buffer, + int num_bytes, + const net::CompletionCallback& callback); protected: // JsAsker: void BeforeStartInUI(v8::Isolate*, v8::Local) override; - void StartAsync(scoped_ptr options) override; + void StartAsync(std::unique_ptr options) override; // net::URLRequestJob: void Kill() override; @@ -43,11 +41,23 @@ class URLRequestFetchJob : public JsAsker, void OnURLFetchComplete(const net::URLFetcher* source) override; private: + int BufferCopy(net::IOBuffer* source, int num_bytes, + net::IOBuffer* target, int target_size); + void ClearPendingBuffer(); + void ClearWriteBuffer(); + scoped_refptr url_request_context_getter_; - scoped_ptr fetcher_; + std::unique_ptr fetcher_; + std::unique_ptr response_info_; + + // Saved arguments passed to ReadRawData. scoped_refptr pending_buffer_; int pending_buffer_size_; - scoped_ptr response_info_; + + // Saved arguments passed to DataAvailable. + scoped_refptr write_buffer_; + int write_num_bytes_; + net::CompletionCallback write_callback_; DISALLOW_COPY_AND_ASSIGN(URLRequestFetchJob); }; diff --git a/atom/browser/net/url_request_string_job.cc b/atom/browser/net/url_request_string_job.cc index 606781142da0..59945e66db07 100644 --- a/atom/browser/net/url_request_string_job.cc +++ b/atom/browser/net/url_request_string_job.cc @@ -16,7 +16,7 @@ URLRequestStringJob::URLRequestStringJob( : JsAsker(request, network_delegate) { } -void URLRequestStringJob::StartAsync(scoped_ptr options) { +void URLRequestStringJob::StartAsync(std::unique_ptr options) { if (options->IsType(base::Value::TYPE_DICTIONARY)) { base::DictionaryValue* dict = static_cast(options.get()); diff --git a/atom/browser/net/url_request_string_job.h b/atom/browser/net/url_request_string_job.h index e40f0d93dab7..474473cca87d 100644 --- a/atom/browser/net/url_request_string_job.h +++ b/atom/browser/net/url_request_string_job.h @@ -17,7 +17,7 @@ class URLRequestStringJob : public JsAsker { URLRequestStringJob(net::URLRequest*, net::NetworkDelegate*); // JsAsker: - void StartAsync(scoped_ptr options) override; + void StartAsync(std::unique_ptr options) override; // URLRequestJob: void GetResponseInfo(net::HttpResponseInfo* info) override; diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc index 50aa454fe757..55025dd69f72 100644 --- a/atom/browser/node_debugger.cc +++ b/atom/browser/node_debugger.cc @@ -145,7 +145,7 @@ void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) { void NodeDebugger::DidAccept( net::test_server::StreamListenSocket* server, - scoped_ptr socket) { + std::unique_ptr socket) { // Only accept one session. if (accepted_socket_) { socket->Send(std::string("Remote debugging session already active"), true); diff --git a/atom/browser/node_debugger.h b/atom/browser/node_debugger.h index aedf7b2c0310..f708de6329f3 100644 --- a/atom/browser/node_debugger.h +++ b/atom/browser/node_debugger.h @@ -38,7 +38,7 @@ class NodeDebugger : public net::test_server::StreamListenSocket::Delegate { // net::test_server::StreamListenSocket::Delegate: void DidAccept( net::test_server::StreamListenSocket* server, - scoped_ptr socket) override; + std::unique_ptr socket) override; void DidRead(net::test_server::StreamListenSocket* socket, const char* data, int len) override; @@ -49,8 +49,8 @@ class NodeDebugger : public net::test_server::StreamListenSocket::Delegate { uv_async_t weak_up_ui_handle_; base::Thread thread_; - scoped_ptr server_; - scoped_ptr accepted_socket_; + std::unique_ptr server_; + std::unique_ptr accepted_socket_; std::string buffer_; int content_length_; diff --git a/atom/browser/render_process_preferences.cc b/atom/browser/render_process_preferences.cc new file mode 100644 index 000000000000..d109c8714f70 --- /dev/null +++ b/atom/browser/render_process_preferences.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/render_process_preferences.h" + +#include "atom/common/api/api_messages.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/render_process_host.h" + +namespace atom { + +RenderProcessPreferences::RenderProcessPreferences(const Predicate& predicate) + : predicate_(predicate), + next_id_(0), + cache_needs_update_(true) { + registrar_.Add(this, + content::NOTIFICATION_RENDERER_PROCESS_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); +} + +RenderProcessPreferences::~RenderProcessPreferences() { +} + +int RenderProcessPreferences::AddEntry(const base::DictionaryValue& entry) { + int id = ++next_id_; + entries_[id] = entry.CreateDeepCopy(); + cache_needs_update_ = true; + return id; +} + +void RenderProcessPreferences::RemoveEntry(int id) { + cache_needs_update_ = true; + entries_.erase(id); +} + +void RenderProcessPreferences::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED); + content::RenderProcessHost* process = + content::Source(source).ptr(); + + if (!predicate_.Run(process)) + return; + + UpdateCache(); + process->Send(new AtomMsg_UpdatePreferences(cached_entries_)); +} + +void RenderProcessPreferences::UpdateCache() { + if (!cache_needs_update_) + return; + + cached_entries_.Clear(); + for (const auto& iter : entries_) + cached_entries_.Append(iter.second->CreateDeepCopy()); + cache_needs_update_ = false; +} + +} // namespace atom diff --git a/atom/browser/render_process_preferences.h b/atom/browser/render_process_preferences.h new file mode 100644 index 000000000000..77bf176f492c --- /dev/null +++ b/atom/browser/render_process_preferences.h @@ -0,0 +1,61 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_RENDER_PROCESS_PREFERENCES_H_ +#define ATOM_BROWSER_RENDER_PROCESS_PREFERENCES_H_ + +#include +#include + +#include "base/callback.h" +#include "base/values.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +namespace content { +class RenderProcessHost; +} + +namespace atom { + +// Sets user preferences for render processes. +class RenderProcessPreferences : public content::NotificationObserver { + public: + using Predicate = base::Callback; + + // The |predicate| is used to determine whether to set preferences for a + // render process. + explicit RenderProcessPreferences(const Predicate& predicate); + virtual ~RenderProcessPreferences(); + + int AddEntry(const base::DictionaryValue& entry); + void RemoveEntry(int id); + + private: + // content::NotificationObserver: + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override; + + void UpdateCache(); + + // Manages our notification registrations. + content::NotificationRegistrar registrar_; + + Predicate predicate_; + + int next_id_; + std::unordered_map> entries_; + + // We need to convert the |entries_| to ListValue for multiple times, this + // caches is only updated when we are sending messages. + bool cache_needs_update_; + base::ListValue cached_entries_; + + DISALLOW_COPY_AND_ASSIGN(RenderProcessPreferences); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_RENDER_PROCESS_PREFERENCES_H_ diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 9d04617b2098..28eddfa61235 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 0.37.8 + 1.2.1 CFBundleShortVersionString - 0.37.8 + 1.2.1 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.manifest b/atom/browser/resources/win/atom.manifest index 84970c717288..64c07ded17b0 100644 --- a/atom/browser/resources/win/atom.manifest +++ b/atom/browser/resources/win/atom.manifest @@ -30,4 +30,11 @@ + + + true + true + + + diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 9f74c14d4461..7e386d319d9d 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,37,8,0 - PRODUCTVERSION 0,37,8,0 + FILEVERSION 1,2,1,0 + PRODUCTVERSION 1,2,1,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.37.8" + VALUE "FileVersion", "1.2.1" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "0.37.8" + VALUE "ProductVersion", "1.2.1" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/browser/ui/accelerator_util_mac.mm b/atom/browser/ui/accelerator_util_mac.mm index d3395884c97f..e2448833ab0d 100644 --- a/atom/browser/ui/accelerator_util_mac.mm +++ b/atom/browser/ui/accelerator_util_mac.mm @@ -32,7 +32,7 @@ void SetPlatformAccelerator(ui::Accelerator* accelerator) { NSString* characters = [[[NSString alloc] initWithCharacters:&character length:1] autorelease]; - scoped_ptr platform_accelerator( + std::unique_ptr platform_accelerator( new ui::PlatformAcceleratorCocoa(characters, modifiers)); accelerator->set_platform_accelerator(std::move(platform_accelerator)); } diff --git a/atom/browser/ui/file_dialog.h b/atom/browser/ui/file_dialog.h index 51d7f5ee9d32..b857648161b5 100644 --- a/atom/browser/ui/file_dialog.h +++ b/atom/browser/ui/file_dialog.h @@ -37,6 +37,7 @@ typedef base::Callback file_extension( + std::unique_ptr file_extension( new std::string("." + filter.second[j])); gtk_file_filter_add_custom( gtk_filter, @@ -216,6 +220,7 @@ base::FilePath FileChooserDialog::AddExtensionForFilename( bool ShowOpenDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, @@ -223,8 +228,8 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window, GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; if (properties & FILE_DIALOG_OPEN_DIRECTORY) action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; - FileChooserDialog open_dialog(action, parent_window, title, default_path, - filters); + FileChooserDialog open_dialog(action, parent_window, title, button_label, + default_path, filters); if (properties & FILE_DIALOG_MULTI_SELECTIONS) gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(open_dialog.dialog()), TRUE); @@ -241,6 +246,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, @@ -249,7 +255,7 @@ void ShowOpenDialog(atom::NativeWindow* parent_window, if (properties & FILE_DIALOG_OPEN_DIRECTORY) action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; FileChooserDialog* open_dialog = new FileChooserDialog( - action, parent_window, title, default_path, filters); + action, parent_window, title, button_label, default_path, filters); if (properties & FILE_DIALOG_MULTI_SELECTIONS) gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(open_dialog->dialog()), TRUE); @@ -259,11 +265,12 @@ void ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, base::FilePath* path) { FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, - title, default_path, filters); + title, button_label, default_path, filters); gtk_widget_show_all(save_dialog.dialog()); int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog())); if (response == GTK_RESPONSE_ACCEPT) { @@ -276,12 +283,13 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, const SaveDialogCallback& callback) { FileChooserDialog* save_dialog = new FileChooserDialog( - GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, default_path, - filters); + GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, button_label, + default_path, filters); save_dialog->RunSaveAsynchronous(callback); } diff --git a/atom/browser/ui/file_dialog_mac.mm b/atom/browser/ui/file_dialog_mac.mm index 49662c69b3b8..d674817a2a41 100644 --- a/atom/browser/ui/file_dialog_mac.mm +++ b/atom/browser/ui/file_dialog_mac.mm @@ -45,11 +45,15 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) { void SetupDialog(NSSavePanel* dialog, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters) { if (!title.empty()) [dialog setTitle:base::SysUTF8ToNSString(title)]; + if (!button_label.empty()) + [dialog setPrompt:base::SysUTF8ToNSString(button_label)]; + NSString* default_dir = nil; NSString* default_filename = nil; if (!default_path.empty()) { @@ -114,6 +118,7 @@ void ReadDialogPaths(NSOpenPanel* dialog, std::vector* paths) { bool ShowOpenDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, @@ -121,7 +126,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window, DCHECK(paths); NSOpenPanel* dialog = [NSOpenPanel openPanel]; - SetupDialog(dialog, title, default_path, filters); + SetupDialog(dialog, title, button_label, default_path, filters); SetupDialogForProperties(dialog, properties); int chosen = RunModalDialog(dialog, parent_window); @@ -134,13 +139,14 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, const OpenDialogCallback& c) { NSOpenPanel* dialog = [NSOpenPanel openPanel]; - SetupDialog(dialog, title, default_path, filters); + SetupDialog(dialog, title, button_label, default_path, filters); SetupDialogForProperties(dialog, properties); // Duplicate the callback object here since c is a reference and gcd would @@ -162,13 +168,14 @@ void ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, base::FilePath* path) { DCHECK(path); NSSavePanel* dialog = [NSSavePanel savePanel]; - SetupDialog(dialog, title, default_path, filters); + SetupDialog(dialog, title, button_label, default_path, filters); int chosen = RunModalDialog(dialog, parent_window); if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL]) @@ -180,12 +187,13 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, const SaveDialogCallback& c) { NSSavePanel* dialog = [NSSavePanel savePanel]; - SetupDialog(dialog, title, default_path, filters); + SetupDialog(dialog, title, button_label, default_path, filters); __block SaveDialogCallback callback = c; diff --git a/atom/browser/ui/file_dialog_win.cc b/atom/browser/ui/file_dialog_win.cc index 6577e4c08404..5314b63a45a8 100644 --- a/atom/browser/ui/file_dialog_win.cc +++ b/atom/browser/ui/file_dialog_win.cc @@ -63,7 +63,9 @@ void ConvertFilters(const Filters& filters, template class FileDialog { public: - FileDialog(const base::FilePath& default_path, const std::string& title, + FileDialog(const base::FilePath& default_path, + const std::string& title, + const std::string& button_label, const Filters& filters, int options) { std::wstring file_part; if (!IsDirectory(default_path)) @@ -79,6 +81,9 @@ class FileDialog { if (!title.empty()) GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str()); + if (!button_label.empty()) + GetPtr()->SetOkButtonLabel(base::UTF8ToUTF16(button_label).c_str()); + // By default, *.* will be added to the file name if file type is "*.*". In // Electron, we disable it to make a better experience. // @@ -129,7 +134,7 @@ class FileDialog { GetPtr()->SetFolder(folder_item); } - scoped_ptr dialog_; + std::unique_ptr dialog_; DISALLOW_COPY_AND_ASSIGN(FileDialog); }; @@ -140,7 +145,7 @@ struct RunState { }; bool CreateDialogThread(RunState* run_state) { - scoped_ptr thread( + std::unique_ptr thread( new base::Thread(ATOM_PRODUCT_NAME "FileDialogThread")); thread->init_com_with_mta(false); if (!thread->Start()) @@ -154,13 +159,14 @@ bool CreateDialogThread(RunState* run_state) { void RunOpenDialogInNewThread(const RunState& run_state, atom::NativeWindow* parent, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, const OpenDialogCallback& callback) { std::vector paths; - bool result = ShowOpenDialog(parent, title, default_path, filters, properties, - &paths); + bool result = ShowOpenDialog(parent, title, button_label, default_path, + filters, properties, &paths); run_state.ui_message_loop->PostTask(FROM_HERE, base::Bind(callback, result, paths)); run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread); @@ -169,11 +175,13 @@ void RunOpenDialogInNewThread(const RunState& run_state, void RunSaveDialogInNewThread(const RunState& run_state, atom::NativeWindow* parent, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, const SaveDialogCallback& callback) { base::FilePath path; - bool result = ShowSaveDialog(parent, title, default_path, filters, &path); + bool result = ShowSaveDialog(parent, title, button_label, default_path, + filters, &path); run_state.ui_message_loop->PostTask(FROM_HERE, base::Bind(callback, result, path)); run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread); @@ -183,6 +191,7 @@ void RunSaveDialogInNewThread(const RunState& run_state, bool ShowOpenDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, @@ -194,7 +203,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window, options |= FOS_ALLOWMULTISELECT; FileDialog open_dialog( - default_path, title, filters, options); + default_path, title, button_label, filters, options); if (!open_dialog.Show(parent_window)) return false; @@ -230,6 +239,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(atom::NativeWindow* parent, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, int properties, @@ -243,16 +253,17 @@ void ShowOpenDialog(atom::NativeWindow* parent, run_state.dialog_thread->message_loop()->PostTask( FROM_HERE, base::Bind(&RunOpenDialogInNewThread, run_state, parent, title, - default_path, filters, properties, callback)); + button_label, default_path, filters, properties, callback)); } bool ShowSaveDialog(atom::NativeWindow* parent_window, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, base::FilePath* path) { FileDialog save_dialog( - default_path, title, filters, + default_path, title, button_label, filters, FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT); if (!save_dialog.Show(parent_window)) return false; @@ -268,6 +279,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(atom::NativeWindow* parent, const std::string& title, + const std::string& button_label, const base::FilePath& default_path, const Filters& filters, const SaveDialogCallback& callback) { @@ -280,7 +292,7 @@ void ShowSaveDialog(atom::NativeWindow* parent, run_state.dialog_thread->message_loop()->PostTask( FROM_HERE, base::Bind(&RunSaveDialogInNewThread, run_state, parent, title, - default_path, filters, callback)); + button_label, default_path, filters, callback)); } } // namespace file_dialog diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 9615e958b275..b09ccdd48279 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -53,9 +53,16 @@ class GtkMessageBox { // Set dialog's icon. if (!icon.isNull()) { GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(*icon.bitmap()); - GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf); + GtkIconSource* iconsource = gtk_icon_source_new(); + GtkIconSet* iconset = gtk_icon_set_new(); + gtk_icon_source_set_pixbuf(iconsource, pixbuf); + gtk_icon_set_add_source(iconset, iconsource); + GtkWidget* image = gtk_image_new_from_icon_set(iconset, + GTK_ICON_SIZE_DIALOG); gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog_), image); gtk_widget_show(image); + gtk_icon_source_free(iconsource); + gtk_icon_set_unref(iconset); g_object_unref(pixbuf); } @@ -149,7 +156,7 @@ class GtkMessageBox { }; void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) { - gtk_widget_hide_all(dialog_); + gtk_widget_hide(dialog_); if (response < 0) callback_.Run(cancel_id_); diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc index 5f49151c30ff..b966ef92a8fd 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_win.cc @@ -64,7 +64,8 @@ void MapToCommonID(const std::vector& buttons, (*button_flags) |= common.button; } else { // It is a custom button. - dialog_buttons->push_back({i + kIDStart, buttons[i].c_str()}); + dialog_buttons->push_back( + {static_cast(i + kIDStart), buttons[i].c_str()}); } } } @@ -135,7 +136,8 @@ int ShowMessageBoxUTF16(HWND parent, std::vector dialog_buttons; if (options & MESSAGE_BOX_NO_LINK) { for (size_t i = 0; i < buttons.size(); ++i) - dialog_buttons.push_back({i + kIDStart, buttons[i].c_str()}); + dialog_buttons.push_back( + {static_cast(i + kIDStart), buttons[i].c_str()}); } else { MapToCommonID(buttons, &id_map, &config.dwCommonButtons, &dialog_buttons); } @@ -220,7 +222,7 @@ void ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - scoped_ptr thread( + std::unique_ptr thread( new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread")); thread->init_com_with_mta(false); if (!thread->Start()) { diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc index 60923c2ad0a6..dcdb90ac159c 100644 --- a/atom/browser/ui/tray_icon.cc +++ b/atom/browser/ui/tray_icon.cc @@ -12,7 +12,7 @@ TrayIcon::TrayIcon() { TrayIcon::~TrayIcon() { } -void TrayIcon::SetPressedImage(const gfx::Image& image) { +void TrayIcon::SetPressedImage(ImageType image) { } void TrayIcon::SetTitle(const std::string& title) { @@ -21,7 +21,7 @@ void TrayIcon::SetTitle(const std::string& title) { void TrayIcon::SetHighlightMode(bool highlight) { } -void TrayIcon::DisplayBalloon(const gfx::Image& icon, +void TrayIcon::DisplayBalloon(ImageType icon, const base::string16& title, const base::string16& contents) { } diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h index c80ff08d6a52..dd018821cd3a 100644 --- a/atom/browser/ui/tray_icon.h +++ b/atom/browser/ui/tray_icon.h @@ -19,13 +19,19 @@ class TrayIcon { public: static TrayIcon* Create(); +#if defined(OS_WIN) + using ImageType = HICON; +#else + using ImageType = const gfx::Image&; +#endif + virtual ~TrayIcon(); // Sets the image associated with this status icon. - virtual void SetImage(const gfx::Image& image) = 0; + virtual void SetImage(ImageType image) = 0; // Sets the image associated with this status icon when pressed. - virtual void SetPressedImage(const gfx::Image& image); + virtual void SetPressedImage(ImageType image); // Sets the hover text for this status icon. This is also used as the label // for the menu item which is created as a replacement for the status icon @@ -43,7 +49,7 @@ class TrayIcon { // Displays a notification balloon with the specified contents. // Depending on the platform it might not appear by the icon tray. - virtual void DisplayBalloon(const gfx::Image& icon, + virtual void DisplayBalloon(ImageType icon, const base::string16& title, const base::string16& contents); diff --git a/atom/browser/ui/tray_icon_gtk.h b/atom/browser/ui/tray_icon_gtk.h index 2be3259f218d..cfeb8ab3d0bf 100644 --- a/atom/browser/ui/tray_icon_gtk.h +++ b/atom/browser/ui/tray_icon_gtk.h @@ -32,7 +32,7 @@ class TrayIconGtk : public TrayIcon, void OnClick() override; bool HasClickAction() override; - scoped_ptr icon_; + std::unique_ptr icon_; DISALLOW_COPY_AND_ASSIGN(TrayIconGtk); }; diff --git a/atom/browser/ui/views/menu_bar.cc b/atom/browser/ui/views/menu_bar.cc index ba0a542c1e8d..872375ccbbd1 100644 --- a/atom/browser/ui/views/menu_bar.cc +++ b/atom/browser/ui/views/menu_bar.cc @@ -104,7 +104,7 @@ int MenuBar::GetAcceleratorIndex(base::char16 key) { void MenuBar::ActivateAccelerator(base::char16 key) { int i = GetAcceleratorIndex(key); if (i != -1) - static_cast(child_at(i))->Activate(); + static_cast(child_at(i))->Activate(nullptr); } int MenuBar::GetItemCount() const { @@ -141,22 +141,22 @@ const char* MenuBar::GetClassName() const { void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) { } -void MenuBar::OnMenuButtonClicked(views::View* source, - const gfx::Point& point) { +void MenuBar::OnMenuButtonClicked(views::MenuButton* source, + const gfx::Point& point, + const ui::Event* event) { // Hide the accelerator when a submenu is activated. SetAcceleratorVisibility(false); if (!menu_model_) return; - views::MenuButton* button = static_cast(source); - int id = button->tag(); + int id = source->tag(); ui::MenuModel::ItemType type = menu_model_->GetTypeAt(id); if (type != ui::MenuModel::TYPE_SUBMENU) return; MenuDelegate menu_delegate(this); - menu_delegate.RunMenu(menu_model_->GetSubmenuModelAt(id), button); + menu_delegate.RunMenu(menu_model_->GetSubmenuModelAt(id), source); } } // namespace atom diff --git a/atom/browser/ui/views/menu_bar.h b/atom/browser/ui/views/menu_bar.h index 9d77cfdf2a22..9f38a5981c7f 100644 --- a/atom/browser/ui/views/menu_bar.h +++ b/atom/browser/ui/views/menu_bar.h @@ -57,8 +57,10 @@ class MenuBar : public views::View, void ButtonPressed(views::Button* sender, const ui::Event& event) override; // views::MenuButtonListener: - void OnMenuButtonClicked(views::View* source, - const gfx::Point& point) override; + void OnMenuButtonClicked(views::MenuButton* source, + const gfx::Point& point, + const ui::Event* event) override; + private: SkColor background_color_; diff --git a/atom/browser/ui/views/menu_delegate.cc b/atom/browser/ui/views/menu_delegate.cc index f0ecf13b36b6..a107a696250b 100644 --- a/atom/browser/ui/views/menu_delegate.cc +++ b/atom/browser/ui/views/menu_delegate.cc @@ -112,7 +112,7 @@ views::MenuItemView* MenuDelegate::GetSiblingMenu( content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, base::Bind(base::IgnoreResult(&views::MenuButton::Activate), - base::Unretained(button))); + base::Unretained(button), nullptr)); } return nullptr; diff --git a/atom/browser/ui/views/menu_delegate.h b/atom/browser/ui/views/menu_delegate.h index 211ddb57bc39..ad7093b48f72 100644 --- a/atom/browser/ui/views/menu_delegate.h +++ b/atom/browser/ui/views/menu_delegate.h @@ -52,8 +52,8 @@ class MenuDelegate : public views::MenuDelegate { private: MenuBar* menu_bar_; int id_; - scoped_ptr adapter_; - scoped_ptr menu_runner_; + std::unique_ptr adapter_; + std::unique_ptr menu_runner_; DISALLOW_COPY_AND_ASSIGN(MenuDelegate); }; diff --git a/atom/browser/ui/views/submenu_button.cc b/atom/browser/ui/views/submenu_button.cc index 72cab258cbec..ca06d7d627ef 100644 --- a/atom/browser/ui/views/submenu_button.cc +++ b/atom/browser/ui/views/submenu_button.cc @@ -26,7 +26,7 @@ base::string16 FilterAccelerator(const base::string16& label) { SubmenuButton::SubmenuButton(views::ButtonListener* listener, const base::string16& title, views::MenuButtonListener* menu_button_listener) - : views::MenuButton(listener, FilterAccelerator(title), + : views::MenuButton(FilterAccelerator(title), menu_button_listener, false), accelerator_(0), show_underline_(false), diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc index 112473013808..1cc616216c6e 100644 --- a/atom/browser/ui/win/notify_icon.cc +++ b/atom/browser/ui/win/notify_icon.cc @@ -9,7 +9,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/windows_version.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/icon_util.h" #include "ui/gfx/image/image.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" @@ -91,19 +90,20 @@ void NotifyIcon::ResetIcon() { LOG(WARNING) << "Unable to re-create status tray icon."; } -void NotifyIcon::SetImage(const gfx::Image& image) { +void NotifyIcon::SetImage(HICON image) { + icon_ = base::win::ScopedHICON(CopyIcon(image)); + // Create the icon. NOTIFYICONDATA icon_data; InitIconData(&icon_data); icon_data.uFlags |= NIF_ICON; - icon_ = IconUtil::CreateHICONFromSkBitmap(image.AsBitmap()); - icon_data.hIcon = icon_.get(); + icon_data.hIcon = image; BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); if (!result) LOG(WARNING) << "Error setting status tray icon image"; } -void NotifyIcon::SetPressedImage(const gfx::Image& image) { +void NotifyIcon::SetPressedImage(HICON image) { // Ignore pressed images, since the standard on Windows is to not highlight // pressed status icons. } @@ -119,7 +119,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) { LOG(WARNING) << "Unable to set tooltip for status tray icon"; } -void NotifyIcon::DisplayBalloon(const gfx::Image& icon, +void NotifyIcon::DisplayBalloon(HICON icon, const base::string16& title, const base::string16& contents) { NOTIFYICONDATA icon_data; @@ -129,13 +129,8 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon, wcsncpy_s(icon_data.szInfoTitle, title.c_str(), _TRUNCATE); wcsncpy_s(icon_data.szInfo, contents.c_str(), _TRUNCATE); icon_data.uTimeout = 0; - - base::win::Version win_version = base::win::GetVersion(); - if (!icon.IsEmpty() && win_version != base::win::VERSION_PRE_XP) { - balloon_icon_ = IconUtil::CreateHICONFromSkBitmap(icon.AsBitmap()); - icon_data.hBalloonIcon = balloon_icon_.get(); - icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; - } + icon_data.hBalloonIcon = icon; + icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); if (!result) @@ -155,7 +150,7 @@ void NotifyIcon::PopUpContextMenu(const gfx::Point& pos, // Show menu at mouse's position by default. gfx::Rect rect(pos, gfx::Size()); if (pos.IsOrigin()) - rect.set_origin(gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); + rect.set_origin(gfx::Screen::GetScreen()->GetCursorScreenPoint()); views::MenuRunner menu_runner( menu_model, diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h index 53ed49b937c1..95e9945a17f8 100644 --- a/atom/browser/ui/win/notify_icon.h +++ b/atom/browser/ui/win/notify_icon.h @@ -45,10 +45,10 @@ class NotifyIcon : public TrayIcon { UINT message_id() const { return message_id_; } // Overridden from TrayIcon: - void SetImage(const gfx::Image& image) override; - void SetPressedImage(const gfx::Image& image) override; + void SetImage(HICON image) override; + void SetPressedImage(HICON image) override; void SetToolTip(const std::string& tool_tip) override; - void DisplayBalloon(const gfx::Image& icon, + void DisplayBalloon(HICON icon, const base::string16& title, const base::string16& contents) override; void PopUpContextMenu(const gfx::Point& pos, @@ -73,9 +73,6 @@ class NotifyIcon : public TrayIcon { // The currently-displayed icon for the window. base::win::ScopedHICON icon_; - // The currently-displayed icon for the notification balloon. - base::win::ScopedHICON balloon_icon_; - // The context menu. ui::SimpleMenuModel* menu_model_; diff --git a/atom/browser/ui/win/notify_icon_host.h b/atom/browser/ui/win/notify_icon_host.h index 6797d4f6a54c..773b3112d470 100644 --- a/atom/browser/ui/win/notify_icon_host.h +++ b/atom/browser/ui/win/notify_icon_host.h @@ -9,8 +9,7 @@ #include -#include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" +#include "base/macros.h" namespace atom { diff --git a/atom/browser/ui/x/x_window_utils.cc b/atom/browser/ui/x/x_window_utils.cc index db83753bb376..48e8bc977322 100644 --- a/atom/browser/ui/x/x_window_utils.cc +++ b/atom/browser/ui/x/x_window_utils.cc @@ -51,7 +51,7 @@ void SetWindowType(::Window xwindow, const std::string& type) { } bool ShouldUseGlobalMenuBar() { - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); if (env->HasVar("ELECTRON_FORCE_WINDOW_MENU_BAR")) return false; @@ -61,7 +61,7 @@ bool ShouldUseGlobalMenuBar() { dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)); dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames"); - scoped_ptr response(object_proxy->CallMethodAndBlock( + std::unique_ptr response(object_proxy->CallMethodAndBlock( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); if (!response) { bus->ShutdownAndBlock(); diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index 7c944832d88d..73405b571934 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -34,8 +34,8 @@ void OnPointerLockResponse(content::WebContents* web_contents, bool allowed) { } void OnPermissionResponse(const base::Callback& callback, - content::PermissionStatus status) { - if (status == content::PERMISSION_STATUS_GRANTED) + blink::mojom::PermissionStatus status) { + if (status == blink::mojom::PermissionStatus::GRANTED) callback.Run(true); else callback.Run(false); @@ -60,7 +60,7 @@ void WebContentsPermissionHelper::RequestPermission( web_contents_->GetBrowserContext()->GetPermissionManager()); auto origin = web_contents_->GetLastCommittedURL(); permission_manager->RequestPermission( - permission, rfh, origin, user_gesture, + permission, rfh, origin, base::Bind(&OnPermissionResponse, callback)); } diff --git a/atom/browser/web_contents_preferences.cc b/atom/browser/web_contents_preferences.cc index 05286a2d3ba4..a32e23de68f5 100644 --- a/atom/browser/web_contents_preferences.cc +++ b/atom/browser/web_contents_preferences.cc @@ -9,6 +9,7 @@ #include #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" @@ -130,7 +131,7 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches( base::DoubleToString(zoom_factor)); // --guest-instance-id, which is used to identify guest WebContents. - int guest_instance_id; + int guest_instance_id = 0; if (web_preferences.GetInteger(options::kGuestInstanceID, &guest_instance_id)) command_line->AppendSwitchASCII(switches::kGuestInstanceID, base::IntToString(guest_instance_id)); @@ -141,6 +142,24 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches( command_line->AppendSwitchASCII(switches::kOpenerID, base::IntToString(opener_id)); +#if defined(OS_MACOSX) + // Enable scroll bounce. + bool scroll_bounce; + if (web_preferences.GetBoolean(options::kScrollBounce, &scroll_bounce) && + scroll_bounce) + command_line->AppendSwitch(switches::kScrollBounce); +#endif + + // Custom command line switches. + const base::ListValue* args; + if (web_preferences.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. std::string blink_features; if (web_preferences.GetString(options::kBlinkFeatures, &blink_features)) @@ -149,6 +168,17 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches( // The initial visibility state. NativeWindow* window = NativeWindow::FromWebContents(web_contents); + + // Use embedder window for webviews + if (guest_instance_id && !window) { + auto manager = WebViewManager::GetWebViewManager(web_contents); + if (manager) { + auto embedder = manager->GetEmbedder(guest_instance_id); + if (embedder) + window = NativeWindow::FromWebContents(embedder); + } + } + if (window) { bool visible = window->IsVisible() && !window->IsMinimized(); if (!visible) // Default state is visible. @@ -172,8 +202,6 @@ void WebContentsPreferences::OverrideWebkitPrefs( prefs->text_areas_are_resizable = b; if (self->web_preferences_.GetBoolean("webgl", &b)) prefs->experimental_webgl_enabled = b; - if (self->web_preferences_.GetBoolean("webaudio", &b)) - prefs->webaudio_enabled = b; if (self->web_preferences_.GetBoolean("webSecurity", &b)) { prefs->web_security_enabled = b; prefs->allow_displaying_insecure_content = !b; diff --git a/atom/browser/web_contents_preferences.h b/atom/browser/web_contents_preferences.h index dd98a9658acf..daf1f6e84de5 100644 --- a/atom/browser/web_contents_preferences.h +++ b/atom/browser/web_contents_preferences.h @@ -29,6 +29,7 @@ class WebContentsPreferences : public content::WebContentsUserData { public: // Get WebContents according to process ID. + // FIXME(zcbenz): This method does not belong here. static content::WebContents* GetWebContentsFromProcessID(int process_id); // Append command paramters according to |web_contents|'s preferences. diff --git a/atom/browser/web_dialog_helper.cc b/atom/browser/web_dialog_helper.cc index c3d2a1d0f23f..2d2a9e5db80d 100644 --- a/atom/browser/web_dialog_helper.cc +++ b/atom/browser/web_dialog_helper.cc @@ -13,7 +13,7 @@ #include "base/bind.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" -#include "base/prefs/pref_service.h" +#include "components/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" #include "chrome/common/pref_names.h" #include "content/public/browser/render_view_host.h" @@ -84,6 +84,7 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents, base::FilePath path; if (file_dialog::ShowSaveDialog(window_, base::UTF16ToUTF8(params.title), + "", params.default_file_name, filters, &path)) { @@ -114,6 +115,7 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents, prefs::kSelectFileLastDirectory).Append(params.default_file_name); if (file_dialog::ShowOpenDialog(window_, base::UTF16ToUTF8(params.title), + "", default_file_path, filters, flags, diff --git a/atom/browser/web_view_guest_delegate.cc b/atom/browser/web_view_guest_delegate.cc index 6abb9713bfac..11f8219bf088 100644 --- a/atom/browser/web_view_guest_delegate.cc +++ b/atom/browser/web_view_guest_delegate.cc @@ -95,13 +95,6 @@ void WebViewGuestDelegate::SetSize(const SetSizeParams& params) { auto_size_enabled_ = enable_auto_size; } -void WebViewGuestDelegate::HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) { - if (embedder_web_contents_) - embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(source, event); -} - void WebViewGuestDelegate::DidCommitProvisionalLoadForFrame( content::RenderFrameHost* render_frame_host, const GURL& url, ui::PageTransition transition_type) { diff --git a/atom/browser/web_view_guest_delegate.h b/atom/browser/web_view_guest_delegate.h index 95888ff749fd..d65eb1463586 100644 --- a/atom/browser/web_view_guest_delegate.h +++ b/atom/browser/web_view_guest_delegate.h @@ -8,10 +8,6 @@ #include "content/public/browser/browser_plugin_guest_delegate.h" #include "content/public/browser/web_contents_observer.h" -namespace content { -struct NativeWebKeyboardEvent; -} - namespace atom { namespace api { @@ -28,10 +24,10 @@ struct SetSizeParams { SetSizeParams() {} ~SetSizeParams() {} - scoped_ptr enable_auto_size; - scoped_ptr min_size; - scoped_ptr max_size; - scoped_ptr normal_size; + std::unique_ptr enable_auto_size; + std::unique_ptr min_size; + std::unique_ptr max_size; + std::unique_ptr normal_size; }; class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate, @@ -49,10 +45,6 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate, // and normal sizes. void SetSize(const SetSizeParams& params); - // Transfer the keyboard event to embedder. - void HandleKeyboardEvent(content::WebContents* source, - const content::NativeWebKeyboardEvent& event); - protected: // content::WebContentsObserver: void DidCommitProvisionalLoadForFrame( diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index d404c1a43680..815e60a166ca 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -42,6 +42,13 @@ void WebViewManager::RemoveGuest(int guest_instance_id) { } } +content::WebContents* WebViewManager::GetEmbedder(int guest_instance_id) { + if (ContainsKey(web_contents_embedder_map_, guest_instance_id)) + return web_contents_embedder_map_[guest_instance_id].embedder; + else + return nullptr; +} + content::WebContents* WebViewManager::GetGuestByInstanceID( int owner_process_id, int element_instance_id) { @@ -65,4 +72,16 @@ bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents, return false; } +// static +WebViewManager* WebViewManager::GetWebViewManager( + content::WebContents* web_contents) { + auto context = web_contents->GetBrowserContext(); + if (context) { + auto manager = context->GetGuestManager(); + return static_cast(manager); + } else { + return nullptr; + } +} + } // namespace atom diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h index ff9a8ecba2ab..eb2ba8ad42c8 100644 --- a/atom/browser/web_view_manager.h +++ b/atom/browser/web_view_manager.h @@ -21,6 +21,9 @@ class WebViewManager : public content::BrowserPluginGuestManager { content::WebContents* embedder, content::WebContents* web_contents); void RemoveGuest(int guest_instance_id); + content::WebContents* GetEmbedder(int guest_instance_id); + + static WebViewManager* GetWebViewManager(content::WebContents* web_contents); protected: // content::BrowserPluginGuestManager: diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index eeb26614847b..ab27d5a2516e 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -30,10 +30,14 @@ IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync, base::ListValue /* arguments */, base::string16 /* result (in JSON) */) -IPC_MESSAGE_ROUTED2(AtomViewMsg_Message, +IPC_MESSAGE_ROUTED3(AtomViewMsg_Message, + bool /* send_to_all */, base::string16 /* channel */, base::ListValue /* arguments */) // Sent by the renderer when the draggable regions are updated. IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, std::vector /* regions */) + +// Update renderer process preferences. +IPC_MESSAGE_CONTROL1(AtomMsg_UpdatePreferences, base::ListValue) diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc index 1b0ea799e7d7..97c2e47fde0d 100644 --- a/atom/common/api/atom_api_asar.cc +++ b/atom/common/api/atom_api_asar.cc @@ -22,7 +22,7 @@ class Archive : public mate::Wrappable { public: static v8::Local Create(v8::Isolate* isolate, const base::FilePath& path) { - scoped_ptr archive(new asar::Archive(path)); + std::unique_ptr archive(new asar::Archive(path)); if (!archive->Init()) return v8::False(isolate); return (new Archive(isolate, std::move(archive)))->GetWrapper(); @@ -42,7 +42,7 @@ class Archive : public mate::Wrappable { } protected: - Archive(v8::Isolate* isolate, scoped_ptr archive) + Archive(v8::Isolate* isolate, std::unique_ptr archive) : archive_(std::move(archive)) { Init(isolate); } @@ -120,7 +120,7 @@ class Archive : public mate::Wrappable { } private: - scoped_ptr archive_; + std::unique_ptr archive_; DISALLOW_COPY_AND_ASSIGN(Archive); }; diff --git a/atom/common/api/atom_api_clipboard.cc b/atom/common/api/atom_api_clipboard.cc index 1f75f2cd3fe7..cb413800be77 100644 --- a/atom/common/api/atom_api_clipboard.cc +++ b/atom/common/api/atom_api_clipboard.cc @@ -146,13 +146,19 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("write", &Write); dict.SetMethod("readText", &ReadText); dict.SetMethod("writeText", &WriteText); + dict.SetMethod("readRTF", &ReadRtf); + dict.SetMethod("writeRTF", &WriteRtf); + dict.SetMethod("readHTML", &ReadHtml); + dict.SetMethod("writeHTML", &WriteHtml); + dict.SetMethod("readImage", &ReadImage); + dict.SetMethod("writeImage", &WriteImage); + dict.SetMethod("clear", &Clear); + + // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings dict.SetMethod("readRtf", &ReadRtf); dict.SetMethod("writeRtf", &WriteRtf); dict.SetMethod("readHtml", &ReadHtml); dict.SetMethod("writeHtml", &WriteHtml); - dict.SetMethod("readImage", &ReadImage); - dict.SetMethod("writeImage", &WriteImage); - dict.SetMethod("clear", &Clear); } } // namespace diff --git a/atom/common/api/atom_api_id_weak_map.cc b/atom/common/api/atom_api_id_weak_map.cc deleted file mode 100644 index 0d3ddae3cc09..000000000000 --- a/atom/common/api/atom_api_id_weak_map.cc +++ /dev/null @@ -1,79 +0,0 @@ -// 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/common/api/atom_api_id_weak_map.h" - -#include "atom/common/node_includes.h" -#include "native_mate/constructor.h" -#include "native_mate/dictionary.h" - -namespace atom { - -namespace api { - -IDWeakMap::IDWeakMap(v8::Isolate* isolate) { -} - -IDWeakMap::~IDWeakMap() { -} - -void IDWeakMap::Set(v8::Isolate* isolate, - int32_t id, - v8::Local object) { - id_weak_map_.Set(isolate, id, object); -} - -v8::Local IDWeakMap::Get(v8::Isolate* isolate, int32_t id) { - return id_weak_map_.Get(isolate, id).ToLocalChecked(); -} - -bool IDWeakMap::Has(int32_t id) { - return id_weak_map_.Has(id); -} - -void IDWeakMap::Remove(int32_t id) { - id_weak_map_.Remove(id); -} - -void IDWeakMap::Clear() { - id_weak_map_.Clear(); -} - -// static -void IDWeakMap::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - mate::ObjectTemplateBuilder(isolate, prototype) - .SetMethod("set", &IDWeakMap::Set) - .SetMethod("get", &IDWeakMap::Get) - .SetMethod("has", &IDWeakMap::Has) - .SetMethod("remove", &IDWeakMap::Remove) - .SetMethod("clear", &IDWeakMap::Clear); -} - -// static -mate::WrappableBase* IDWeakMap::Create(v8::Isolate* isolate) { - return new IDWeakMap(isolate); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::IDWeakMap; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - v8::Local constructor = mate::CreateConstructor( - isolate, "IDWeakMap", base::Bind(&IDWeakMap::Create)); - mate::Dictionary id_weak_map(isolate, constructor); - mate::Dictionary dict(isolate, exports); - dict.Set("IDWeakMap", id_weak_map); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize) diff --git a/atom/common/api/atom_api_id_weak_map.h b/atom/common/api/atom_api_id_weak_map.h deleted file mode 100644 index 616112ffe6f4..000000000000 --- a/atom/common/api/atom_api_id_weak_map.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_ -#define ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_ - -#include "atom/common/id_weak_map.h" -#include "native_mate/object_template_builder.h" -#include "native_mate/handle.h" - -namespace atom { - -namespace api { - -class IDWeakMap : public mate::Wrappable { - public: - static mate::WrappableBase* Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - explicit IDWeakMap(v8::Isolate* isolate); - ~IDWeakMap(); - - private: - // Api for IDWeakMap. - void Set(v8::Isolate* isolate, int32_t id, v8::Local object); - v8::Local Get(v8::Isolate* isolate, int32_t id); - bool Has(int32_t id); - void Remove(int32_t id); - void Clear(); - - atom::IDWeakMap id_weak_map_; - - DISALLOW_COPY_AND_ASSIGN(IDWeakMap); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_ diff --git a/atom/common/api/atom_api_key_weak_map.h b/atom/common/api/atom_api_key_weak_map.h new file mode 100644 index 000000000000..b13338badd5b --- /dev/null +++ b/atom/common/api/atom_api_key_weak_map.h @@ -0,0 +1,65 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_ +#define ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_ + +#include "atom/common/key_weak_map.h" +#include "native_mate/object_template_builder.h" +#include "native_mate/handle.h" + +namespace atom { + +namespace api { + +template +class KeyWeakMap : public mate::Wrappable> { + public: + static mate::Handle> Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new KeyWeakMap(isolate)); + } + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("set", &KeyWeakMap::Set) + .SetMethod("get", &KeyWeakMap::Get) + .SetMethod("has", &KeyWeakMap::Has) + .SetMethod("remove", &KeyWeakMap::Remove); + } + + protected: + explicit KeyWeakMap(v8::Isolate* isolate) { + mate::Wrappable>::Init(isolate); + } + ~KeyWeakMap() override {} + + private: + // API for KeyWeakMap. + void Set(v8::Isolate* isolate, const K& key, v8::Local object) { + key_weak_map_.Set(isolate, key, object); + } + + v8::Local Get(v8::Isolate* isolate, const K& key) { + return key_weak_map_.Get(isolate, key).ToLocalChecked(); + } + + bool Has(const K& key) { + return key_weak_map_.Has(key); + } + + void Remove(const K& key) { + key_weak_map_.Remove(key); + } + + atom::KeyWeakMap key_weak_map_; + + DISALLOW_COPY_AND_ASSIGN(KeyWeakMap); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_ diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 1c90fe7080fb..c0b51ba2af28 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -63,7 +63,7 @@ float GetScaleFactorFromPath(const base::FilePath& path) { // We don't try to convert string to float here because it is very very // expensive. - for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) { + for (unsigned i = 0; i < node::arraysize(kScaleFactorPairs); ++i) { if (base::EndsWith(filename, kScaleFactorPairs[i].name, base::CompareCase::INSENSITIVE_ASCII)) return kScaleFactorPairs[i].scale; @@ -76,7 +76,7 @@ bool AddImageSkiaRep(gfx::ImageSkia* image, const unsigned char* data, size_t size, double scale_factor) { - scoped_ptr decoded(new SkBitmap()); + std::unique_ptr decoded(new SkBitmap()); // Try PNG first. if (!gfx::PNGCodec::Decode(data, size, decoded.get())) @@ -142,7 +142,7 @@ bool IsTemplateFilename(const base::FilePath& path) { #endif #if defined(OS_WIN) -bool ReadImageSkiaFromICO(gfx::ImageSkia* image, const base::FilePath& path) { +base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) { // If file is in asar archive, we extract it to a temp file so LoadImage can // load it. base::FilePath asar_path, relative_path; @@ -155,16 +155,15 @@ bool ReadImageSkiaFromICO(gfx::ImageSkia* image, const base::FilePath& path) { } // Load the icon from file. - base::win::ScopedHICON icon(static_cast( - LoadImage(NULL, image_path.value().c_str(), IMAGE_ICON, 0, 0, - LR_DEFAULTSIZE | LR_LOADFROMFILE))); - if (!icon.get()) - return false; + return base::win::ScopedHICON(static_cast( + LoadImage(NULL, image_path.value().c_str(), IMAGE_ICON, size, size, + LR_LOADFROMFILE))); +} +void ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon) { // Convert the icon from the Windows specific HICON to gfx::ImageSkia. - scoped_ptr bitmap(IconUtil:: CreateSkBitmapFromHICON(icon.get())); + std::unique_ptr bitmap(IconUtil::CreateSkBitmapFromHICON(icon)); image->AddRepresentation(gfx::ImageSkiaRep(*bitmap, 1.0f)); - return true; } #endif @@ -175,8 +174,40 @@ NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) Init(isolate); } +#if defined(OS_WIN) +NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path) + : hicon_path_(hicon_path) { + // Use the 256x256 icon as fallback icon. + gfx::ImageSkia image_skia; + ReadImageSkiaFromICO(&image_skia, GetHICON(256)); + image_ = gfx::Image(image_skia); + Init(isolate); +} +#endif + NativeImage::~NativeImage() {} +#if defined(OS_WIN) +HICON NativeImage::GetHICON(int size) { + auto iter = hicons_.find(size); + if (iter != hicons_.end()) + return iter->second.get(); + + // First try loading the icon with specified size. + if (!hicon_path_.empty()) { + hicons_[size] = std::move(ReadICOFromPath(size, hicon_path_)); + return hicons_[size].get(); + } + + // Then convert the image to ICO. + if (image_.IsEmpty()) + return NULL; + hicons_[size] = std::move( + IconUtil::CreateHICONFromSkBitmap(image_.AsBitmap())); + return hicons_[size].get(); +} +#endif + v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { scoped_refptr png = image_.As1xPNGBytes(); return node::Buffer::Copy(isolate, @@ -263,16 +294,15 @@ mate::Handle NativeImage::CreateFromJPEG( // static mate::Handle NativeImage::CreateFromPath( v8::Isolate* isolate, const base::FilePath& path) { - gfx::ImageSkia image_skia; base::FilePath image_path = NormalizePath(path); - - if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) { #if defined(OS_WIN) - ReadImageSkiaFromICO(&image_skia, image_path); -#endif - } else { - PopulateImageSkiaRepsFromPath(&image_skia, image_path); + if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) { + return mate::CreateHandle(isolate, + new NativeImage(isolate, image_path)); } +#endif + gfx::ImageSkia image_skia; + PopulateImageSkiaRepsFromPath(&image_skia, image_path); gfx::Image image(image_skia); mate::Handle handle = Create(isolate, image); #if defined(OS_MACOSX) @@ -318,7 +348,6 @@ void NativeImage::BuildPrototype( .SetMethod("toJpeg", &NativeImage::ToJPEG) .SetMethod("getNativeHandle", &NativeImage::GetNativeHandle) .SetMethod("toDataURL", &NativeImage::ToDataURL) - .SetMethod("toDataUrl", &NativeImage::ToDataURL) // deprecated. .SetMethod("isEmpty", &NativeImage::IsEmpty) .SetMethod("getSize", &NativeImage::GetSize) .SetMethod("setTemplateImage", &NativeImage::SetTemplateImage) @@ -329,6 +358,35 @@ void NativeImage::BuildPrototype( } // namespace atom +namespace mate { + +v8::Local Converter>::ToV8( + v8::Isolate* isolate, + const mate::Handle& val) { + return val.ToV8(); +} + +bool Converter>::FromV8( + v8::Isolate* isolate, v8::Local val, + mate::Handle* out) { + // Try converting from file path. + base::FilePath path; + if (ConvertFromV8(isolate, val, &path)) { + *out = atom::api::NativeImage::CreateFromPath(isolate, path); + // Should throw when failed to initialize from path. + return !(*out)->image().IsEmpty(); + } + + WrappableBase* wrapper = static_cast(internal::FromV8Impl( + isolate, val)); + if (!wrapper) + return false; + + *out = CreateHandle(isolate, static_cast(wrapper)); + return true; +} + +} // namespace mate namespace { diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index 79844604706c..de4db4c0f382 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -5,12 +5,18 @@ #ifndef ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ #define ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ +#include #include #include "native_mate/handle.h" #include "native_mate/wrappable.h" #include "ui/gfx/image/image.h" +#if defined(OS_WIN) +#include "base/files/file_path.h" +#include "base/win/scoped_gdi_object.h" +#endif + class GURL; namespace base { @@ -48,10 +54,17 @@ class NativeImage : public mate::Wrappable { static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); +#if defined(OS_WIN) + HICON GetHICON(int size); +#endif + const gfx::Image& image() const { return image_; } protected: NativeImage(v8::Isolate* isolate, const gfx::Image& image); +#if defined(OS_WIN) + NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path); +#endif ~NativeImage() override; private: @@ -69,6 +82,11 @@ class NativeImage : public mate::Wrappable { // Determine if the image is a template image. bool IsTemplateImage(); +#if defined(OS_WIN) + base::FilePath hicon_path_; + std::map hicons_; +#endif + gfx::Image image_; DISALLOW_COPY_AND_ASSIGN(NativeImage); @@ -78,4 +96,19 @@ class NativeImage : public mate::Wrappable { } // namespace atom +namespace mate { + +// A custom converter that allows converting path to NativeImage. +template<> +struct Converter> { + static v8::Local ToV8( + v8::Isolate* isolate, + const mate::Handle& val); + static bool FromV8(v8::Isolate* isolate, v8::Local val, + mate::Handle* out); +}; + +} // namespace mate + + #endif // ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index 109f9f0f36c2..7b7655c6cd2e 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -3,14 +3,49 @@ // found in the LICENSE file. #include +#include +#include "atom/common/api/atom_api_key_weak_map.h" #include "atom/common/api/remote_callback_freer.h" #include "atom/common/api/remote_object_freer.h" #include "atom/common/native_mate_converters/content_converter.h" #include "atom/common/node_includes.h" +#include "base/hash.h" #include "native_mate/dictionary.h" #include "v8/include/v8-profiler.h" +namespace std { + +// The hash function used by DoubleIDWeakMap. +template +struct hash> { + std::size_t operator()(std::pair value) const { + return base::HashInts(value.first, value.second); + } +}; + +} // namespace std + +namespace mate { + +template +struct Converter> { + static bool FromV8(v8::Isolate* isolate, + v8::Local val, + std::pair* out) { + if (!val->IsArray()) + return false; + + v8::Local array(v8::Local::Cast(val)); + if (array->Length() != 2) + return false; + return Converter::FromV8(isolate, array->Get(0), &out->first) && + Converter::FromV8(isolate, array->Get(1), &out->second); + } +}; + +} // namespace mate + namespace { v8::Local GetHiddenValue(v8::Isolate* isolate, @@ -67,6 +102,9 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot); dict.SetMethod("setRemoteCallbackFreer", &atom::RemoteCallbackFreer::BindTo); dict.SetMethod("setRemoteObjectFreer", &atom::RemoteObjectFreer::BindTo); + dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap::Create); + dict.SetMethod("createDoubleIDWeakMap", + &atom::api::KeyWeakMap>::Create); } } // namespace diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index f518caf5c503..f567492b52ba 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -33,6 +33,46 @@ void Hang() { base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); } +v8::Local GetProcessMemoryInfo(v8::Isolate* isolate) { + std::unique_ptr metrics( + base::ProcessMetrics::CreateCurrentProcessMetrics()); + + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("workingSetSize", + static_cast(metrics->GetWorkingSetSize() >> 10)); + dict.Set("peakWorkingSetSize", + static_cast(metrics->GetPeakWorkingSetSize() >> 10)); + + size_t private_bytes, shared_bytes; + if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) { + dict.Set("privateBytes", static_cast(private_bytes >> 10)); + dict.Set("sharedBytes", static_cast(shared_bytes >> 10)); + } + + return dict.GetHandle(); +} + +v8::Local GetSystemMemoryInfo(v8::Isolate* isolate, + mate::Arguments* args) { + base::SystemMemoryInfoKB mem_info; + if (!base::GetSystemMemoryInfo(&mem_info)) { + args->ThrowError("Unable to retrieve system memory information"); + return v8::Undefined(isolate); + } + + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("total", mem_info.total); + dict.Set("free", mem_info.free); + + // NB: These return bogus values on OS X +#if !defined(OS_MACOSX) + dict.Set("swapTotal", mem_info.swap_total); + dict.Set("swapFree", mem_info.swap_free); +#endif + + return dict.GetHandle(); +} + // Called when there is a fatal error in V8, we just crash the process here so // we can get the stack trace. void FatalErrorCallback(const char* location, const char* message) { @@ -63,6 +103,8 @@ void AtomBindings::BindTo(v8::Isolate* isolate, dict.SetMethod("crash", &Crash); dict.SetMethod("hang", &Hang); dict.SetMethod("log", &Log); + dict.SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo); + dict.SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo); #if defined(OS_POSIX) dict.SetMethod("setFdLimit", &base::SetFdLimit); #endif diff --git a/atom/common/api/event_emitter_caller.cc b/atom/common/api/event_emitter_caller.cc index 4b44553d3740..271ea705e09c 100644 --- a/atom/common/api/event_emitter_caller.cc +++ b/atom/common/api/event_emitter_caller.cc @@ -7,7 +7,6 @@ #include "atom/common/api/locker.h" #include "atom/common/node_includes.h" #include "base/memory/scoped_ptr.h" -#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" namespace mate { @@ -17,9 +16,11 @@ v8::Local CallEmitWithArgs(v8::Isolate* isolate, v8::Local obj, ValueVector* args) { // Perform microtask checkpoint after running JavaScript. - scoped_ptr script_scope( + std::unique_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script); + nullptr : + new v8::MicrotasksScope(isolate, + v8::MicrotasksScope::kRunMicrotasks)); // Use node::MakeCallback to call the callback, and it will also run pending // tasks in Node.js. return node::MakeCallback( diff --git a/atom/common/api/locker.h b/atom/common/api/locker.h index 201217ff625a..e64ef1853ec5 100644 --- a/atom/common/api/locker.h +++ b/atom/common/api/locker.h @@ -5,7 +5,9 @@ #ifndef ATOM_COMMON_API_LOCKER_H_ #define ATOM_COMMON_API_LOCKER_H_ -#include "base/memory/scoped_ptr.h" +#include + +#include "base/macros.h" #include "v8/include/v8.h" namespace mate { @@ -24,7 +26,7 @@ class Locker { void* operator new(size_t size); void operator delete(void*, size_t); - scoped_ptr locker_; + std::unique_ptr locker_; DISALLOW_COPY_AND_ASSIGN(Locker); }; diff --git a/atom/common/api/remote_callback_freer.cc b/atom/common/api/remote_callback_freer.cc index 7bc377efc5e7..d1a185d51f39 100644 --- a/atom/common/api/remote_callback_freer.cc +++ b/atom/common/api/remote_callback_freer.cc @@ -35,7 +35,7 @@ void RemoteCallbackFreer::RunDestructor() { base::ASCIIToUTF16("ELECTRON_RENDERER_RELEASE_CALLBACK"); base::ListValue args; args.AppendInteger(object_id_); - Send(new AtomViewMsg_Message(routing_id(), channel, args)); + Send(new AtomViewMsg_Message(routing_id(), false, channel, args)); Observe(nullptr); } diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index 01fe23a88922..c2306c3c8f38 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -4,10 +4,6 @@ #include "atom/common/asar/archive.h" -#if defined(OS_WIN) -#include -#endif - #include #include @@ -20,6 +16,10 @@ #include "base/strings/string_number_conversions.h" #include "base/values.h" +#if defined(OS_WIN) +#include "atom/node/osfhandle.h" +#endif + namespace asar { namespace { @@ -118,7 +118,7 @@ Archive::Archive(const base::FilePath& path) : path_(path), file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ), #if defined(OS_WIN) - fd_(_open_osfhandle( + fd_(node::open_osfhandle( reinterpret_cast(file_.GetPlatformFile()), 0)), #elif defined(OS_POSIX) fd_(file_.GetPlatformFile()), @@ -131,7 +131,7 @@ Archive::Archive(const base::FilePath& path) Archive::~Archive() { #if defined(OS_WIN) if (fd_ != -1) { - _close(fd_); + node::close(fd_); // Don't close the handle since we already closed the fd. file_.TakePlatformFile(); } @@ -180,7 +180,7 @@ bool Archive::Init() { std::string error; base::JSONReader reader; - scoped_ptr value(reader.ReadToValue(header)); + std::unique_ptr value(reader.ReadToValue(header)); if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) { LOG(ERROR) << "Failed to parse header: " << error; return false; @@ -283,7 +283,7 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) { return true; } - scoped_ptr temp_file(new ScopedTemporaryFile); + std::unique_ptr temp_file(new ScopedTemporaryFile); base::FilePath::StringType ext = path.Extension(); if (!temp_file->InitFromFile(&file_, ext, info.offset, info.size)) return false; diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h index 79b848623c99..5438776885f3 100644 --- a/atom/common/asar/archive.h +++ b/atom/common/asar/archive.h @@ -72,10 +72,10 @@ class Archive { base::File file_; int fd_; uint32_t header_size_; - scoped_ptr header_; + std::unique_ptr header_; // Cached external temporary files. - base::ScopedPtrHashMap> + base::ScopedPtrHashMap> external_files_; DISALLOW_COPY_AND_ASSIGN(Archive); diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 4ce73bc0aeec..455bfacbfc11 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -5,9 +5,9 @@ #ifndef ATOM_VERSION_H #define ATOM_VERSION_H -#define ATOM_MAJOR_VERSION 0 -#define ATOM_MINOR_VERSION 37 -#define ATOM_PATCH_VERSION 8 +#define ATOM_MAJOR_VERSION 1 +#define ATOM_MINOR_VERSION 2 +#define ATOM_PATCH_VERSION 1 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/atom/common/chrome_version.h b/atom/common/chrome_version.h index 8b9b7ef0c826..f84f6ac15516 100644 --- a/atom/common/chrome_version.h +++ b/atom/common/chrome_version.h @@ -8,7 +8,7 @@ #ifndef ATOM_COMMON_CHROME_VERSION_H_ #define ATOM_COMMON_CHROME_VERSION_H_ -#define CHROME_VERSION_STRING "49.0.2623.75" +#define CHROME_VERSION_STRING "51.0.2704.63" #define CHROME_VERSION "v" CHROME_VERSION_STRING #endif // ATOM_COMMON_CHROME_VERSION_H_ diff --git a/atom/common/common_message_generator.h b/atom/common/common_message_generator.h index 832de1abf739..64206956863e 100644 --- a/atom/common/common_message_generator.h +++ b/atom/common/common_message_generator.h @@ -8,3 +8,4 @@ #include "chrome/common/print_messages.h" #include "chrome/common/tts_messages.h" #include "chrome/common/widevine_cdm_messages.h" +#include "chrome/common/chrome_utility_messages.h" diff --git a/atom/common/crash_reporter/crash_reporter_linux.h b/atom/common/crash_reporter/crash_reporter_linux.h index 165c288ab2b1..b74103ccbf76 100644 --- a/atom/common/crash_reporter/crash_reporter_linux.h +++ b/atom/common/crash_reporter/crash_reporter_linux.h @@ -47,7 +47,7 @@ class CrashReporterLinux : public CrashReporter { void* context, const bool succeeded); - scoped_ptr breakpad_; + std::unique_ptr breakpad_; CrashKeyStorage crash_keys_; uint64_t process_start_time_; diff --git a/atom/common/crash_reporter/crash_reporter_mac.h b/atom/common/crash_reporter/crash_reporter_mac.h index f03154359155..5556263cd350 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.h +++ b/atom/common/crash_reporter/crash_reporter_mac.h @@ -45,7 +45,7 @@ class CrashReporterMac : public CrashReporter { std::vector GetUploadedReports( const std::string& path) override; - scoped_ptr simple_string_dictionary_; + std::unique_ptr simple_string_dictionary_; DISALLOW_COPY_AND_ASSIGN(CrashReporterMac); }; diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm index 130a421665f7..ee2ce036048f 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ b/atom/common/crash_reporter/crash_reporter_mac.mm @@ -4,6 +4,8 @@ #include "atom/common/crash_reporter/crash_reporter_mac.h" +#include + #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/mac/bundle_locations.h" @@ -73,7 +75,7 @@ void CrashReporterMac::InitBreakpad(const std::string& product_name, SetCrashKeyValue(upload_parameter.first, upload_parameter.second); } if (is_browser_) { - scoped_ptr database = + std::unique_ptr database = crashpad::CrashReportDatabase::Initialize(database_path); if (database) { database->GetSettings()->SetUploadsEnabled(auto_submit); @@ -99,7 +101,7 @@ CrashReporterMac::GetUploadedReports(const std::string& path) { return uploaded_reports; } // Load crashpad database. - scoped_ptr database = + std::unique_ptr database = crashpad::CrashReportDatabase::Initialize(file_path); DCHECK(database); diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index 939a02f090c5..4264f6af9db4 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -43,6 +43,10 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast( const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent"; const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service"; +// Matches breakpad/src/client/windows/common/ipc_protocol.h. +const int kNameMaxLength = 64; +const int kValueMaxLength = 64; + typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle, NTSTATUS ExitStatus); char* g_real_terminate_process_stub = NULL; @@ -247,9 +251,18 @@ google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( for (StringMap::const_iterator iter = upload_parameters_.begin(); iter != upload_parameters_.end(); ++iter) { - custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( - base::UTF8ToWide(iter->first).c_str(), - base::UTF8ToWide(iter->second).c_str())); + // breakpad has hardcoded the length of name/value, and doesn't truncate + // the values itself, so we have to truncate them here otherwise weird + // things may happen. + std::wstring name = base::UTF8ToWide(iter->first); + std::wstring value = base::UTF8ToWide(iter->second); + if (name.length() > kNameMaxLength - 1) + name.resize(kNameMaxLength - 1); + if (value.length() > kValueMaxLength - 1) + value.resize(kValueMaxLength - 1); + + custom_info_entries_.push_back( + google_breakpad::CustomInfoEntry(name.c_str(), value.c_str())); } custom_info_.entries = &custom_info_entries_.front(); diff --git a/atom/common/crash_reporter/crash_reporter_win.h b/atom/common/crash_reporter/crash_reporter_win.h index 181c9eabd23c..0ab8f4bcfb19 100644 --- a/atom/common/crash_reporter/crash_reporter_win.h +++ b/atom/common/crash_reporter/crash_reporter_win.h @@ -62,7 +62,7 @@ class CrashReporterWin : public CrashReporter { google_breakpad::CustomClientInfo custom_info_; bool skip_system_crash_handler_; - scoped_ptr breakpad_; + std::unique_ptr breakpad_; DISALLOW_COPY_AND_ASSIGN(CrashReporterWin); }; diff --git a/atom/common/crash_reporter/win/crash_service.cc b/atom/common/crash_reporter/win/crash_service.cc index 58c7c38632ed..4563a9202a3e 100644 --- a/atom/common/crash_reporter/win/crash_service.cc +++ b/atom/common/crash_reporter/win/crash_service.cc @@ -327,7 +327,7 @@ void CrashService::OnClientConnected(void* context, void CrashService::OnClientExited(void* context, const google_breakpad::ClientInfo* client_info) { - ProcessingLock lock; + ProcessingLock processing_lock; VLOG(1) << "client end. pid = " << client_info->pid(); CrashService* self = static_cast(context); ::InterlockedIncrement(&self->clients_terminated_); @@ -440,10 +440,12 @@ DWORD CrashService::AsyncSendDump(void* context) { // termination of the service object. base::AutoLock lock(info->self->sending_); VLOG(1) << "trying to send report for pid = " << info->pid; + std::map file_map; + file_map[L"upload_file_minidump"] = info->dump_path; google_breakpad::ReportResult send_result = info->self->sender_->SendCrashReport(info->self->reporter_url_, info->map, - info->dump_path, + file_map, &report_id); switch (send_result) { case google_breakpad::RESULT_FAILED: diff --git a/atom/common/crash_reporter/win/crash_service_main.cc b/atom/common/crash_reporter/win/crash_service_main.cc index 56d46970b67f..c6325f090ade 100644 --- a/atom/common/crash_reporter/win/crash_service_main.cc +++ b/atom/common/crash_reporter/win/crash_service_main.cc @@ -20,6 +20,11 @@ const char kApplicationName[] = "application-name"; const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service"; const wchar_t kStandardLogFile[] = L"operation_log.txt"; +void InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, + unsigned int, uintptr_t) { + // noop. +} + bool GetCrashServiceDirectory(const std::wstring& application_name, base::FilePath* dir) { base::FilePath temp_dir; @@ -37,6 +42,9 @@ bool GetCrashServiceDirectory(const std::wstring& application_name, } // namespace. int Main(const wchar_t* cmd) { + // Ignore invalid parameter errors. + _set_invalid_parameter_handler(InvalidParameterHandler); + // Initialize all Chromium things. base::AtExitManager exit_manager; base::CommandLine::Init(0, NULL); diff --git a/atom/common/id_weak_map.cc b/atom/common/id_weak_map.cc deleted file mode 100644 index a78dcbceba53..000000000000 --- a/atom/common/id_weak_map.cc +++ /dev/null @@ -1,94 +0,0 @@ -// 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/common/id_weak_map.h" - -#include - -#include "native_mate/converter.h" - -namespace atom { - -namespace { - -struct ObjectKey { - ObjectKey(int id, IDWeakMap* map) : id(id), map(map) {} - int id; - IDWeakMap* map; -}; - -void OnObjectGC(const v8::WeakCallbackInfo& data) { - ObjectKey* key = data.GetParameter(); - key->map->Remove(key->id); - delete key; -} - -} // namespace - -IDWeakMap::IDWeakMap() : next_id_(0) { -} - -IDWeakMap::~IDWeakMap() { -} - -void IDWeakMap::Set(v8::Isolate* isolate, - int32_t id, - v8::Local object) { - auto global = make_linked_ptr(new v8::Global(isolate, object)); - ObjectKey* key = new ObjectKey(id, this); - global->SetWeak(key, OnObjectGC, v8::WeakCallbackType::kParameter); - map_[id] = global; -} - -int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local object) { - int32_t id = GetNextID(); - Set(isolate, id, object); - return id; -} - -v8::MaybeLocal IDWeakMap::Get(v8::Isolate* isolate, int32_t id) { - auto iter = map_.find(id); - if (iter == map_.end()) - return v8::MaybeLocal(); - else - return v8::Local::New(isolate, *iter->second); -} - -bool IDWeakMap::Has(int32_t id) const { - return map_.find(id) != map_.end(); -} - -std::vector IDWeakMap::Keys() const { - std::vector keys; - keys.reserve(map_.size()); - for (const auto& iter : map_) - keys.emplace_back(iter.first); - return keys; -} - -std::vector> IDWeakMap::Values(v8::Isolate* isolate) { - std::vector> keys; - keys.reserve(map_.size()); - for (const auto& iter : map_) - keys.emplace_back(v8::Local::New(isolate, *iter.second)); - return keys; -} - -void IDWeakMap::Remove(int32_t id) { - auto iter = map_.find(id); - if (iter == map_.end()) - LOG(WARNING) << "Removing unexist object with ID " << id; - else - map_.erase(iter); -} - -void IDWeakMap::Clear() { - map_.clear(); -} - -int32_t IDWeakMap::GetNextID() { - return ++next_id_; -} - -} // namespace atom diff --git a/atom/common/id_weak_map.h b/atom/common/id_weak_map.h deleted file mode 100644 index 72c64c6ae5d4..000000000000 --- a/atom/common/id_weak_map.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_ID_WEAK_MAP_H_ -#define ATOM_COMMON_ID_WEAK_MAP_H_ - -#include -#include - -#include "base/memory/linked_ptr.h" -#include "v8/include/v8.h" - -namespace atom { - -// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer. -class IDWeakMap { - public: - IDWeakMap(); - ~IDWeakMap(); - - // Sets the object to WeakMap with the given |id|. - void Set(v8::Isolate* isolate, int32_t id, v8::Local object); - - // Adds |object| to WeakMap and returns its allocated |id|. - int32_t Add(v8::Isolate* isolate, v8::Local object); - - // Gets the object from WeakMap by its |id|. - v8::MaybeLocal Get(v8::Isolate* isolate, int32_t id); - - // Whethere there is an object with |id| in this WeakMap. - bool Has(int32_t id) const; - - // Returns IDs of all available objects. - std::vector Keys() const; - - // Returns all objects. - std::vector> Values(v8::Isolate* isolate); - - // Remove object with |id| in the WeakMap. - void Remove(int32_t key); - - // Clears the weak map. - void Clear(); - - private: - // Returns next available ID. - int32_t GetNextID(); - - // ID of next stored object. - int32_t next_id_; - - // Map of stored objects. - std::unordered_map>> map_; - - DISALLOW_COPY_AND_ASSIGN(IDWeakMap); -}; - -} // namespace atom - -#endif // ATOM_COMMON_ID_WEAK_MAP_H_ diff --git a/atom/common/key_weak_map.h b/atom/common/key_weak_map.h new file mode 100644 index 000000000000..bce34bfe0f6e --- /dev/null +++ b/atom/common/key_weak_map.h @@ -0,0 +1,96 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_KEY_WEAK_MAP_H_ +#define ATOM_COMMON_KEY_WEAK_MAP_H_ + +#include +#include +#include + +#include "base/memory/linked_ptr.h" +#include "v8/include/v8.h" + +namespace atom { + +namespace internal { + +} // namespace internal + +// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer. +template +class KeyWeakMap { + public: + // Records the key and self, used by SetWeak. + struct KeyObject { + K key; + KeyWeakMap* self; + }; + + KeyWeakMap() {} + virtual ~KeyWeakMap() { + for (const auto& p : map_) + p.second.second->ClearWeak(); + } + + // Sets the object to WeakMap with the given |key|. + void Set(v8::Isolate* isolate, const K& key, v8::Local object) { + auto value = make_linked_ptr(new v8::Global(isolate, object)); + KeyObject key_object = {key, this}; + auto& p = map_[key] = std::make_pair(key_object, value); + value->SetWeak(&(p.first), OnObjectGC, v8::WeakCallbackType::kParameter); + } + + // Gets the object from WeakMap by its |key|. + v8::MaybeLocal Get(v8::Isolate* isolate, const K& key) { + auto iter = map_.find(key); + if (iter == map_.end()) + return v8::MaybeLocal(); + else + return v8::Local::New(isolate, *(iter->second.second)); + } + + // Whethere there is an object with |key| in this WeakMap. + bool Has(const K& key) const { + return map_.find(key) != map_.end(); + } + + // Returns all objects. + std::vector> Values(v8::Isolate* isolate) { + std::vector> keys; + keys.reserve(map_.size()); + for (const auto& iter : map_) { + const auto& value = *(iter.second.second); + keys.emplace_back(v8::Local::New(isolate, value)); + } + return keys; + } + + // Remove object with |key| in the WeakMap. + void Remove(const K& key) { + auto iter = map_.find(key); + if (iter == map_.end()) + return; + + iter->second.second->ClearWeak(); + map_.erase(iter); + } + + private: + static void OnObjectGC( + const v8::WeakCallbackInfo::KeyObject>& data) { + KeyWeakMap::KeyObject* key_object = data.GetParameter(); + key_object->self->Remove(key_object->key); + } + + // Map of stored objects. + std::unordered_map< + K, std::pair>>> map_; + + DISALLOW_COPY_AND_ASSIGN(KeyWeakMap); +}; + +} // namespace atom + +#endif // ATOM_COMMON_KEY_WEAK_MAP_H_ diff --git a/atom/common/native_mate_converters/blink_converter.cc b/atom/common/native_mate_converters/blink_converter.cc index 0ae73e9825c8..4e37836c5a55 100644 --- a/atom/common/native_mate_converters/blink_converter.cc +++ b/atom/common/native_mate_converters/blink_converter.cc @@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "content/public/browser/native_web_keyboard_event.h" #include "native_mate/dictionary.h" +#include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" #include "third_party/WebKit/public/web/WebFindOptions.h" #include "third_party/WebKit/public/web/WebInputEvent.h" @@ -91,6 +92,8 @@ struct Converter { *out = blink::WebMouseEvent::Button::ButtonMiddle; else if (button == "right") *out = blink::WebMouseEvent::Button::ButtonRight; + else + return false; return true; } }; @@ -201,7 +204,8 @@ bool Converter::FromV8( return false; if (!dict.Get("x", &out->x) || !dict.Get("y", &out->y)) return false; - dict.Get("button", &out->button); + if (!dict.Get("button", &out->button)) + out->button = blink::WebMouseEvent::Button::ButtonLeft; dict.Get("globalX", &out->globalX); dict.Get("globalY", &out->globalY); dict.Get("movementX", &out->movementX); @@ -384,4 +388,30 @@ v8::Local MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags) { return mate::ConvertToV8(isolate, dict); } +v8::Local Converter::ToV8( + v8::Isolate* isolate, + const blink::WebCache::ResourceTypeStat& stat) { + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("count", static_cast(stat.count)); + dict.Set("size", static_cast(stat.size)); + dict.Set("liveSize", static_cast(stat.liveSize)); + dict.Set("decodedSize", static_cast(stat.decodedSize)); + dict.Set("purgedSize", static_cast(stat.purgedSize)); + dict.Set("purgeableSize", static_cast(stat.purgeableSize)); + return dict.GetHandle(); +} + +v8::Local Converter::ToV8( + v8::Isolate* isolate, + const blink::WebCache::ResourceTypeStats& stats) { + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("images", stats.images); + dict.Set("scripts", stats.scripts); + dict.Set("cssStyleSheets", stats.cssStyleSheets); + dict.Set("xslStyleSheets", stats.xslStyleSheets); + dict.Set("fonts", stats.fonts); + dict.Set("other", stats.other); + return dict.GetHandle(); +} + } // namespace mate diff --git a/atom/common/native_mate_converters/blink_converter.h b/atom/common/native_mate_converters/blink_converter.h index 514c6ab680c7..78275ab62ec9 100644 --- a/atom/common/native_mate_converters/blink_converter.h +++ b/atom/common/native_mate_converters/blink_converter.h @@ -6,6 +6,7 @@ #define ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_ #include "native_mate/converter.h" +#include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebContextMenuData.h" namespace blink { @@ -100,8 +101,21 @@ struct Converter { const blink::WebContextMenuData::InputFieldType& in); }; -v8::Local EditFlagsToV8(v8::Isolate* isolate, int editFlags); +template<> +struct Converter { + static v8::Local ToV8( + v8::Isolate* isolate, + const blink::WebCache::ResourceTypeStat& stat); +}; +template<> +struct Converter { + static v8::Local ToV8( + v8::Isolate* isolate, + const blink::WebCache::ResourceTypeStats& stats); +}; + +v8::Local EditFlagsToV8(v8::Isolate* isolate, int editFlags); v8::Local MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags); } // namespace mate diff --git a/atom/common/native_mate_converters/callback.h b/atom/common/native_mate_converters/callback.h index 6ef8e74c735a..43a1baf25fa8 100644 --- a/atom/common/native_mate_converters/callback.h +++ b/atom/common/native_mate_converters/callback.h @@ -13,7 +13,6 @@ #include "base/memory/weak_ptr.h" #include "native_mate/function_template.h" #include "native_mate/scoped_persistent.h" -#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" namespace mate { @@ -49,9 +48,11 @@ struct V8FunctionInvoker(ArgTypes...)> { v8::EscapableHandleScope handle_scope(isolate); if (!function.IsAlive()) return v8::Null(isolate); - scoped_ptr script_scope( + std::unique_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script); + nullptr : + new v8::MicrotasksScope(isolate, + v8::MicrotasksScope::kRunMicrotasks)); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); @@ -70,9 +71,11 @@ struct V8FunctionInvoker { v8::HandleScope handle_scope(isolate); if (!function.IsAlive()) return; - scoped_ptr script_scope( + std::unique_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script); + nullptr : + new v8::MicrotasksScope(isolate, + v8::MicrotasksScope::kRunMicrotasks)); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); @@ -91,9 +94,11 @@ struct V8FunctionInvoker { ReturnType ret = ReturnType(); if (!function.IsAlive()) return ret; - scoped_ptr script_scope( + std::unique_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script); + nullptr : + new v8::MicrotasksScope(isolate, + v8::MicrotasksScope::kRunMicrotasks)); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index 5589c5a84af2..824065882e82 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -121,18 +121,18 @@ v8::Local Converter::ToV8( } // static -bool Converter::FromV8( +bool Converter::FromV8( v8::Isolate* isolate, v8::Local val, - content::PermissionStatus* out) { + blink::mojom::PermissionStatus* out) { bool result; if (!ConvertFromV8(isolate, val, &result)) return false; if (result) - *out = content::PERMISSION_STATUS_GRANTED; + *out = blink::mojom::PermissionStatus::GRANTED; else - *out = content::PERMISSION_STATUS_DENIED; + *out = blink::mojom::PermissionStatus::DENIED; return true; } diff --git a/atom/common/native_mate_converters/content_converter.h b/atom/common/native_mate_converters/content_converter.h index f2e7211ce5d1..522961a7e96c 100644 --- a/atom/common/native_mate_converters/content_converter.h +++ b/atom/common/native_mate_converters/content_converter.h @@ -9,8 +9,8 @@ #include "content/public/browser/permission_type.h" #include "content/public/common/menu_item.h" -#include "content/public/common/permission_status.mojom.h" #include "content/public/common/stop_find_action.h" +#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h" #include "native_mate/converter.h" namespace content { @@ -36,9 +36,9 @@ struct Converter { }; template<> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, - content::PermissionStatus* out); + blink::mojom::PermissionStatus* out); }; template<> diff --git a/atom/common/native_mate_converters/image_converter.cc b/atom/common/native_mate_converters/image_converter.cc index 550bb7b904a7..cfb1938a138f 100644 --- a/atom/common/native_mate_converters/image_converter.cc +++ b/atom/common/native_mate_converters/image_converter.cc @@ -28,16 +28,8 @@ bool Converter::FromV8(v8::Isolate* isolate, return true; Handle native_image; - if (!ConvertFromV8(isolate, val, &native_image)) { - // Try converting from file path. - base::FilePath path; - if (!Converter::FromV8(isolate, val, &path)) - return false; - - native_image = atom::api::NativeImage::CreateFromPath(isolate, path); - if (native_image->image().IsEmpty()) - return false; - } + if (!ConvertFromV8(isolate, val, &native_image)) + return false; *out = native_image->image(); return true; diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 5223709ae585..772ae6e22087 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -25,13 +25,13 @@ namespace mate { // static v8::Local Converter::ToV8( v8::Isolate* isolate, const net::URLRequest* val) { - scoped_ptr dict(new base::DictionaryValue); + std::unique_ptr dict(new base::DictionaryValue); dict->SetString("method", val->method()); std::string url; if (!val->url_chain().empty()) url = val->url().spec(); dict->SetStringWithoutPathExpansion("url", url); dict->SetString("referrer", val->referrer()); - scoped_ptr list(new base::ListValue); + std::unique_ptr list(new base::ListValue); atom::GetUploadData(list.get(), val); if (!list->empty()) dict->Set("uploadData", std::move(list)); @@ -74,15 +74,15 @@ void GetUploadData(base::ListValue* upload_data_list, const net::UploadDataStream* upload_data = request->get_upload(); if (!upload_data) return; - const std::vector>* readers = + const std::vector>* readers = upload_data->GetElementReaders(); for (const auto& reader : *readers) { - scoped_ptr upload_data_dict( + std::unique_ptr upload_data_dict( new base::DictionaryValue); if (reader->AsBytesReader()) { const net::UploadBytesElementReader* bytes_reader = reader->AsBytesReader(); - scoped_ptr bytes( + std::unique_ptr bytes( base::BinaryValue::CreateWithCopiedBuffer(bytes_reader->bytes(), bytes_reader->length())); upload_data_dict->Set("bytes", std::move(bytes)); diff --git a/atom/common/native_mate_converters/v8_value_converter.cc b/atom/common/native_mate_converters/v8_value_converter.cc index 99873cd1c4f0..ff96b727e02a 100644 --- a/atom/common/native_mate_converters/v8_value_converter.cc +++ b/atom/common/native_mate_converters/v8_value_converter.cc @@ -288,7 +288,7 @@ base::Value* V8ValueConverter::FromV8Array( if (!state->UpdateAndCheckUniqueness(val)) return base::Value::CreateNullValue().release(); - scoped_ptr scope; + std::unique_ptr scope; // If val was created in a different context than our current one, change to // that context, but change back after val is converted. if (!val->CreationContext().IsEmpty() && @@ -335,14 +335,14 @@ base::Value* V8ValueConverter::FromV8Object( if (!state->UpdateAndCheckUniqueness(val)) return base::Value::CreateNullValue().release(); - scoped_ptr scope; + std::unique_ptr scope; // If val was created in a different context than our current one, change to // that context, but change back after val is converted. if (!val->CreationContext().IsEmpty() && val->CreationContext() != isolate->GetCurrentContext()) scope.reset(new v8::Context::Scope(val->CreationContext())); - scoped_ptr result(new base::DictionaryValue()); + std::unique_ptr result(new base::DictionaryValue()); v8::Local property_names(val->GetOwnPropertyNames()); for (uint32_t i = 0; i < property_names->Length(); ++i) { @@ -371,7 +371,8 @@ base::Value* V8ValueConverter::FromV8Object( child_v8 = v8::Null(isolate); } - scoped_ptr child(FromV8ValueImpl(state, child_v8, isolate)); + std::unique_ptr child( + FromV8ValueImpl(state, child_v8, isolate)); if (!child.get()) // JSON.stringify skips properties whose values don't serialize, for // example undefined and functions. Emulate that behavior. diff --git a/atom/common/native_mate_converters/value_converter.cc b/atom/common/native_mate_converters/value_converter.cc index c9c1a861ba26..c3c7ae0383c5 100644 --- a/atom/common/native_mate_converters/value_converter.cc +++ b/atom/common/native_mate_converters/value_converter.cc @@ -12,8 +12,8 @@ namespace mate { bool Converter::FromV8(v8::Isolate* isolate, v8::Local val, base::DictionaryValue* out) { - scoped_ptr converter(new atom::V8ValueConverter); - scoped_ptr value(converter->FromV8Value( + std::unique_ptr converter(new atom::V8ValueConverter); + std::unique_ptr value(converter->FromV8Value( val, isolate->GetCurrentContext())); if (value && value->IsType(base::Value::TYPE_DICTIONARY)) { out->Swap(static_cast(value.get())); @@ -26,15 +26,15 @@ bool Converter::FromV8(v8::Isolate* isolate, v8::Local Converter::ToV8( v8::Isolate* isolate, const base::DictionaryValue& val) { - scoped_ptr converter(new atom::V8ValueConverter); + std::unique_ptr converter(new atom::V8ValueConverter); return converter->ToV8Value(&val, isolate->GetCurrentContext()); } bool Converter::FromV8(v8::Isolate* isolate, v8::Local val, base::ListValue* out) { - scoped_ptr converter(new atom::V8ValueConverter); - scoped_ptr value(converter->FromV8Value( + std::unique_ptr converter(new atom::V8ValueConverter); + std::unique_ptr value(converter->FromV8Value( val, isolate->GetCurrentContext())); if (value->IsType(base::Value::TYPE_LIST)) { out->Swap(static_cast(value.get())); @@ -47,7 +47,7 @@ bool Converter::FromV8(v8::Isolate* isolate, v8::Local Converter::ToV8( v8::Isolate* isolate, const base::ListValue& val) { - scoped_ptr converter(new atom::V8ValueConverter); + std::unique_ptr converter(new atom::V8ValueConverter); return converter->ToV8Value(&val, isolate->GetCurrentContext()); } diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 31105886eb7c..ed2ea01675a1 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -21,7 +21,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/common/content_paths.h" #include "native_mate/dictionary.h" -#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" using content::BrowserThread; @@ -43,6 +42,7 @@ REFERENCE_MODULE(atom_browser_power_monitor); REFERENCE_MODULE(atom_browser_power_save_blocker); REFERENCE_MODULE(atom_browser_protocol); REFERENCE_MODULE(atom_browser_global_shortcut); +REFERENCE_MODULE(atom_browser_render_process_preferences); REFERENCE_MODULE(atom_browser_session); REFERENCE_MODULE(atom_browser_system_preferences); REFERENCE_MODULE(atom_browser_tray); @@ -52,7 +52,6 @@ REFERENCE_MODULE(atom_browser_window); REFERENCE_MODULE(atom_common_asar); REFERENCE_MODULE(atom_common_clipboard); REFERENCE_MODULE(atom_common_crash_reporter); -REFERENCE_MODULE(atom_common_id_weak_map); REFERENCE_MODULE(atom_common_native_image); REFERENCE_MODULE(atom_common_screen); REFERENCE_MODULE(atom_common_shell); @@ -80,9 +79,9 @@ void UvNoOp(uv_async_t* handle) { // Convert the given vector to an array of C-strings. The strings in the // returned vector are only guaranteed valid so long as the vector of strings // is not modified. -scoped_ptr StringVectorToArgArray( +std::unique_ptr StringVectorToArgArray( const std::vector& vector) { - scoped_ptr array(new const char*[vector.size()]); + std::unique_ptr array(new const char*[vector.size()]); for (size_t i = 0; i < vector.size(); ++i) { array[i] = vector[i].c_str(); } @@ -147,7 +146,7 @@ void NodeBindings::Initialize() { #if defined(OS_WIN) // uv_init overrides error mode to suppress the default crash dialog, bring // it back if user wants to show it. - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); if (env->HasVar("ELECTRON_DEFAULT_ERROR_MODE")) SetErrorMode(0); #endif @@ -168,7 +167,7 @@ node::Environment* NodeBindings::CreateEnvironment( std::string script_path_str = script_path.AsUTF8Unsafe(); args.insert(args.begin() + 1, script_path_str.c_str()); - scoped_ptr c_argv = StringVectorToArgArray(args); + std::unique_ptr c_argv = StringVectorToArgArray(args); node::Environment* env = node::CreateEnvironment( context->GetIsolate(), uv_default_loop(), context, args.size(), c_argv.get(), 0, nullptr); @@ -227,8 +226,10 @@ void NodeBindings::UvRunOnce() { v8::Context::Scope context_scope(env->context()); // Perform microtask checkpoint after running JavaScript. - scoped_ptr script_scope( - is_browser_ ? nullptr : new blink::WebScopedRunV8Script); + std::unique_ptr script_scope(is_browser_ ? + nullptr : + new v8::MicrotasksScope(env->isolate(), + v8::MicrotasksScope::kRunMicrotasks)); // Deal with uv events. int r = uv_run(uv_loop_, UV_RUN_NOWAIT); diff --git a/atom/common/node_includes.h b/atom/common/node_includes.h index bb76afb54db9..3734a43e5f45 100644 --- a/atom/common/node_includes.h +++ b/atom/common/node_includes.h @@ -21,6 +21,7 @@ #undef CHECK_LT #undef DISALLOW_COPY_AND_ASSIGN #undef NO_RETURN +#undef arraysize #undef debug_string // This is defined in OS X 10.9 SDK in AssertMacros.h. #include "vendor/node/src/env.h" #include "vendor/node/src/env-inl.h" diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 562171d51f25..de130eee13eb 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -103,6 +103,9 @@ const char kExperimentalCanvasFeatures[] = "experimentalCanvasFeatures"; // Opener window's ID. const char kOpenerID[] = "openerId"; +// Enable the rubber banding effect. +const char kScrollBounce[] = "scrollBounce"; + // Enable blink features. const char kBlinkFeatures[] = "blinkFeatures"; @@ -122,9 +125,6 @@ const char kPpapiFlashVersion[] = "ppapi-flash-version"; // Disable HTTP cache. const char kDisableHttpCache[] = "disable-http-cache"; -// Register schemes to standard. -const char kRegisterStandardSchemes[] = "register-standard-schemes"; - // Register schemes to handle service worker. const char kRegisterServiceWorkerSchemes[] = "register-service-worker-schemes"; @@ -146,6 +146,7 @@ const char kPreloadURL[] = "preload-url"; const char kNodeIntegration[] = "node-integration"; const char kGuestInstanceID[] = "guest-instance-id"; const char kOpenerID[] = "opener-id"; +const char kScrollBounce[] = "scroll-bounce"; // Widevine options // Path to Widevine CDM binaries. diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 5746a7bbfe54..fadde79f18c8 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -56,6 +56,7 @@ extern const char kGuestInstanceID[]; extern const char kExperimentalFeatures[]; extern const char kExperimentalCanvasFeatures[]; extern const char kOpenerID[]; +extern const char kScrollBounce[]; extern const char kBlinkFeatures[]; } // namespace options @@ -69,7 +70,6 @@ extern const char kEnablePlugins[]; extern const char kPpapiFlashPath[]; extern const char kPpapiFlashVersion[]; extern const char kDisableHttpCache[]; -extern const char kRegisterStandardSchemes[]; extern const char kRegisterServiceWorkerSchemes[]; extern const char kSSLVersionFallbackMin[]; extern const char kCipherSuiteBlacklist[]; @@ -82,6 +82,7 @@ extern const char kPreloadURL[]; extern const char kNodeIntegration[]; extern const char kGuestInstanceID[]; extern const char kOpenerID[]; +extern const char kScrollBounce[]; extern const char kWidevineCdmPath[]; extern const char kWidevineCdmVersion[]; diff --git a/atom/node/osfhandle.cc b/atom/node/osfhandle.cc new file mode 100644 index 000000000000..33403dc52371 --- /dev/null +++ b/atom/node/osfhandle.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "osfhandle.h" + +#include + +namespace node { + +int open_osfhandle(intptr_t osfhandle, int flags) { + return _open_osfhandle(osfhandle, flags); +} + +int close(int fd) { + return _close(fd); +} + +} // namespace node diff --git a/atom/node/osfhandle.h b/atom/node/osfhandle.h new file mode 100644 index 000000000000..6ebb2ab11e9d --- /dev/null +++ b/atom/node/osfhandle.h @@ -0,0 +1,28 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_NODE_OSFHANDLE_H_ +#define ATOM_NODE_OSFHANDLE_H_ + +#include + +#include "node_extern.h" + +namespace node { + +// The _open_osfhandle and _close functions on Windows are provided by the +// Visual C++ library, so the fd returned by them can only be used in the +// same instance of VC++ library. +// However Electron is linking with VC++ library statically, so electron.exe +// shares a different instance of VC++ library with node.exe. This results +// in fd created in electron.exe not usable in node.dll, so we have to ensure +// we always create fd in one instance of VC++ library. +// Followings wrappers are compiled in node.dll, and all code in electron.exe +// should call these wrappers instead of calling _open_osfhandle directly. +NODE_EXTERN int open_osfhandle(intptr_t osfhandle, int flags); +NODE_EXTERN int close(int fd); + +} // namespace node + +#endif // ATOM_NODE_OSFHANDLE_H_ diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index 0eebc94fc141..0b291d3b552a 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -5,14 +5,17 @@ #include "atom/renderer/api/atom_api_web_frame.h" #include "atom/common/api/event_emitter_caller.h" +#include "atom/common/native_mate_converters/blink_converter.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/renderer/api/atom_api_spell_check_client.h" +#include "base/memory/memory_pressure_listener.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" +#include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebScriptExecutionCallback.h" @@ -155,7 +158,7 @@ void WebFrame::ExecuteJavaScript(const base::string16& code, args->GetNext(&has_user_gesture); ScriptExecutionCallback::CompletionCallback completion_callback; args->GetNext(&completion_callback); - scoped_ptr callback( + std::unique_ptr callback( new ScriptExecutionCallback(completion_callback)); web_frame_->requestExecuteScriptAndReturnValue( blink::WebScriptSource(code), @@ -168,6 +171,20 @@ mate::Handle WebFrame::Create(v8::Isolate* isolate) { return mate::CreateHandle(isolate, new WebFrame(isolate)); } +blink::WebCache::ResourceTypeStats WebFrame::GetResourceUsage( + v8::Isolate* isolate) { + blink::WebCache::ResourceTypeStats stats; + blink::WebCache::getResourceTypeStats(&stats); + return stats; +} + +void WebFrame::ClearCache(v8::Isolate* isolate) { + isolate->IdleNotificationDeadline(0.5); + blink::WebCache::clear(); + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); +} + // static void WebFrame::BuildPrototype( v8::Isolate* isolate, v8::Local prototype) { @@ -191,7 +208,9 @@ void WebFrame::BuildPrototype( .SetMethod("registerURLSchemeAsPrivileged", &WebFrame::RegisterURLSchemeAsPrivileged) .SetMethod("insertText", &WebFrame::InsertText) - .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript); + .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript) + .SetMethod("getResourceUsage", &WebFrame::GetResourceUsage) + .SetMethod("clearCache", &WebFrame::ClearCache); } } // namespace api diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index e1eeb224930b..df0392a933e0 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "native_mate/handle.h" #include "native_mate/wrappable.h" +#include "third_party/WebKit/public/web/WebCache.h" namespace blink { class WebLocalFrame; @@ -69,7 +70,11 @@ class WebFrame : public mate::Wrappable { // Excecuting scripts. void ExecuteJavaScript(const base::string16& code, mate::Arguments* args); - scoped_ptr spell_check_client_; + // Resource related methods + blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate); + void ClearCache(v8::Isolate* isolate); + + std::unique_ptr spell_check_client_; blink::WebLocalFrame* web_frame_; diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index 96dffbd512a6..7ee93efb39b7 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -27,7 +27,6 @@ #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebKit.h" -#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebView.h" #include "ui/base/resource/resource_bundle.h" #include "native_mate/dictionary.h" @@ -60,6 +59,34 @@ std::vector> ListValueToVector( return result; } +void EmitIPCEvent(blink::WebFrame* frame, + const base::string16& channel, + const base::ListValue& args) { + if (!frame || frame->isWebRemoteFrame()) + return; + + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::Local context = frame->mainWorldScriptContext(); + v8::Context::Scope context_scope(context); + + // Only emit IPC event for context with node integration. + node::Environment* env = node::Environment::GetCurrent(context); + if (!env) + return; + + v8::Local ipc; + if (GetIPCObject(isolate, context, &ipc)) { + auto args_vector = ListValueToVector(isolate, args); + // Insert the Event object, event.sender is ipc. + mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate); + event.Set("sender", ipc); + args_vector.insert(args_vector.begin(), event.GetHandle()); + mate::EmitEvent(isolate, ipc, channel, args_vector); + } +} + base::StringPiece NetResourceProvider(int key) { if (key == IDR_DIR_HEADER_HTML) { base::StringPiece html_data = @@ -89,9 +116,6 @@ void AtomRenderViewObserver::DidCreateDocumentElement( blink::WebLocalFrame* frame) { document_created_ = true; - // Make sure every page will get a script context created. - frame->executeScript(blink::WebScriptSource("void 0")); - // Read --zoom-factor from command line. std::string zoom_factor_str = base::CommandLine::ForCurrentProcess()-> GetSwitchValueASCII(switches::kZoomFactor); @@ -127,7 +151,8 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { return handled; } -void AtomRenderViewObserver::OnBrowserMessage(const base::string16& channel, +void AtomRenderViewObserver::OnBrowserMessage(bool send_to_all, + const base::string16& channel, const base::ListValue& args) { if (!document_created_) return; @@ -139,20 +164,13 @@ void AtomRenderViewObserver::OnBrowserMessage(const base::string16& channel, if (!frame || frame->isWebRemoteFrame()) return; - v8::Isolate* isolate = blink::mainThreadIsolate(); - v8::HandleScope handle_scope(isolate); + EmitIPCEvent(frame, channel, args); - v8::Local context = frame->mainWorldScriptContext(); - v8::Context::Scope context_scope(context); - - v8::Local ipc; - if (GetIPCObject(isolate, context, &ipc)) { - auto args_vector = ListValueToVector(isolate, args); - // Insert the Event object, event.sender is ipc. - mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate); - event.Set("sender", ipc); - args_vector.insert(args_vector.begin(), event.GetHandle()); - mate::EmitEvent(isolate, ipc, channel, args_vector); + // Also send the message to all sub-frames. + if (send_to_all) { + for (blink::WebFrame* child = frame->firstChild(); child; + child = child->nextSibling()) + EmitIPCEvent(child, channel, args); } } diff --git a/atom/renderer/atom_render_view_observer.h b/atom/renderer/atom_render_view_observer.h index 4b9d59f3fa08..376138f0849a 100644 --- a/atom/renderer/atom_render_view_observer.h +++ b/atom/renderer/atom_render_view_observer.h @@ -30,7 +30,8 @@ class AtomRenderViewObserver : public content::RenderViewObserver { void DraggableRegionsChanged(blink::WebFrame* frame) override; bool OnMessageReceived(const IPC::Message& message) override; - void OnBrowserMessage(const base::string16& channel, + void OnBrowserMessage(bool send_to_all, + const base::string16& channel, const base::ListValue& args); // Weak reference to renderer client. diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 4bb3cd2168c8..ee2dd7d54e04 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -11,13 +11,16 @@ #include "atom/common/api/atom_bindings.h" #include "atom/common/api/event_emitter_caller.h" #include "atom/common/color_util.h" +#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_bindings.h" #include "atom/common/node_includes.h" #include "atom/common/options_switches.h" #include "atom/renderer/atom_render_view_observer.h" #include "atom/renderer/guest_view_container.h" #include "atom/renderer/node_array_buffer_bridge.h" +#include "atom/renderer/preferences_manager.h" #include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/renderer/media/chrome_key_systems.h" #include "chrome/renderer/pepper/pepper_helper.h" #include "chrome/renderer/printing/print_web_view_helper.h" @@ -28,14 +31,24 @@ #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "ipc/ipc_message_macros.h" +#include "native_mate/dictionary.h" +#include "net/base/net_errors.h" #include "third_party/WebKit/public/web/WebCustomElement.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebFrameWidget.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebPluginParams.h" #include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebView.h" +#if defined(OS_MACOSX) +#include "base/mac/mac_util.h" +#include "base/strings/sys_string_conversions.h" +#endif + #if defined(OS_WIN) #include #endif @@ -50,32 +63,60 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { AtomRenderFrameObserver(content::RenderFrame* frame, AtomRendererClient* renderer_client) : content::RenderFrameObserver(frame), + render_frame_(frame), world_id_(-1), renderer_client_(renderer_client) {} // content::RenderFrameObserver: + void DidClearWindowObject() override { + renderer_client_->DidClearWindowObject(render_frame_); + } + void DidCreateScriptContext(v8::Handle context, int extension_group, int world_id) override { if (world_id_ != -1 && world_id_ != world_id) return; world_id_ = world_id; - renderer_client_->DidCreateScriptContext(context); + renderer_client_->DidCreateScriptContext(context, render_frame_); } void WillReleaseScriptContext(v8::Local context, int world_id) override { if (world_id_ != world_id) return; - renderer_client_->WillReleaseScriptContext(context); + renderer_client_->WillReleaseScriptContext(context, render_frame_); } private: + content::RenderFrame* render_frame_; int world_id_; AtomRendererClient* renderer_client_; DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); }; +v8::Local GetRenderProcessPreferences( + const PreferencesManager* preferences_manager, v8::Isolate* isolate) { + if (preferences_manager->preferences()) + return mate::ConvertToV8(isolate, *preferences_manager->preferences()); + else + return v8::Null(isolate); +} + +void AddRenderBindings(v8::Isolate* isolate, + v8::Local process, + const PreferencesManager* preferences_manager) { + mate::Dictionary dict(isolate, process); + dict.SetMethod( + "getRenderProcessPreferences", + base::Bind(GetRenderProcessPreferences, preferences_manager)); +} + +bool IsDevToolsExtension(content::RenderFrame* render_frame) { + return static_cast(render_frame->GetWebFrame()->document().url()) + .SchemeIs("chrome-extension"); +} + } // namespace AtomRendererClient::AtomRendererClient() @@ -86,17 +127,16 @@ AtomRendererClient::AtomRendererClient() AtomRendererClient::~AtomRendererClient() { } -void AtomRendererClient::WebKitInitialized() { +void AtomRendererClient::RenderThreadStarted() { blink::WebCustomElement::addEmbedderCustomElementName("webview"); blink::WebCustomElement::addEmbedderCustomElementName("browserplugin"); OverrideNodeArrayBuffer(); -} -void AtomRendererClient::RenderThreadStarted() { - content::RenderThread::Get()->AddObserver(this); + preferences_manager_.reset(new PreferencesManager); #if defined(OS_WIN) + // Set ApplicationUserModelID in renderer process. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); base::string16 app_id = command_line->GetSwitchValueNative(switches::kAppUserModelId); @@ -104,37 +144,75 @@ void AtomRendererClient::RenderThreadStarted() { SetCurrentProcessExplicitAppUserModelID(app_id.c_str()); } #endif + +#if defined(OS_MACOSX) + // Disable rubber banding by default. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switches::kScrollBounce)) { + base::ScopedCFTypeRef key( + base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); + base::ScopedCFTypeRef value( + base::SysUTF8ToCFStringRef("false")); + CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); + CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); + } +#endif } void AtomRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { new PepperHelper(render_frame); + new AtomRenderFrameObserver(render_frame, this); // Allow file scheme to handle service worker by default. + // FIXME(zcbenz): Can this be moved elsewhere? blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file"); - - // Only insert node integration for the main frame. - if (!render_frame->IsMainFrame()) - return; - - new AtomRenderFrameObserver(render_frame, this); } void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { + new printing::PrintWebViewHelper(render_view); + new AtomRenderViewObserver(render_view, this); + + blink::WebFrameWidget* web_frame_widget = render_view->GetWebFrameWidget(); + if (!web_frame_widget) + return; + base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview. - // Set transparent background. - render_view->GetWebView()->setBaseBackgroundColor(SK_ColorTRANSPARENT); + web_frame_widget->setBaseBackgroundColor(SK_ColorTRANSPARENT); } else { // normal window. // If backgroundColor is specified then use it. std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor); // Otherwise use white background. SkColor color = name.empty() ? SK_ColorWHITE : ParseHexColor(name); - render_view->GetWebView()->setBaseBackgroundColor(color); + web_frame_widget->setBaseBackgroundColor(color); } +} - new printing::PrintWebViewHelper(render_view); - new AtomRenderViewObserver(render_view, this); +void AtomRendererClient::DidClearWindowObject( + content::RenderFrame* render_frame) { + // Make sure every page will get a script context created. + render_frame->GetWebFrame()->executeScript(blink::WebScriptSource("void 0")); +} + +void AtomRendererClient::RunScriptsAtDocumentStart( + content::RenderFrame* render_frame) { + // Inform the document start pharse. + node::Environment* env = node_bindings_->uv_env(); + if (env) { + v8::HandleScope handle_scope(env->isolate()); + mate::EmitEvent(env->isolate(), env->process_object(), "document-start"); + } +} + +void AtomRendererClient::RunScriptsAtDocumentEnd( + content::RenderFrame* render_frame) { + // Inform the document end pharse. + node::Environment* env = node_bindings_->uv_env(); + if (env) { + v8::HandleScope handle_scope(env->isolate()); + mate::EmitEvent(env->isolate(), env->process_object(), "document-end"); + } } blink::WebSpeechSynthesizer* AtomRendererClient::OverrideSpeechSynthesizer( @@ -157,7 +235,12 @@ bool AtomRendererClient::OverrideCreatePlugin( } void AtomRendererClient::DidCreateScriptContext( - v8::Handle context) { + v8::Handle context, content::RenderFrame* render_frame) { + // Only allow node integration for the main frame, unless it is a devtools + // extension page. + if (!render_frame->IsMainFrame() && !IsDevToolsExtension(render_frame)) + return; + // Whether the node binding has been initialized. bool first_time = node_bindings_->uv_env() == nullptr; @@ -172,6 +255,8 @@ void AtomRendererClient::DidCreateScriptContext( // Add atom-shell extended APIs. atom_bindings_->BindTo(env->isolate(), env->process_object()); + AddRenderBindings(env->isolate(), env->process_object(), + preferences_manager_.get()); // Load everything. node_bindings_->LoadEnvironment(env); @@ -186,9 +271,10 @@ void AtomRendererClient::DidCreateScriptContext( } void AtomRendererClient::WillReleaseScriptContext( - v8::Handle context) { + v8::Handle context, content::RenderFrame* render_frame) { node::Environment* env = node::Environment::GetCurrent(context); - mate::EmitEvent(env->isolate(), env->process_object(), "exit"); + if (env) + mate::EmitEvent(env->isolate(), env->process_object(), "exit"); } bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame, @@ -221,4 +307,16 @@ void AtomRendererClient::AddKeySystems( AddChromeKeySystems(key_systems); } +void AtomRendererClient::GetNavigationErrorStrings( + content::RenderFrame* render_frame, + const blink::WebURLRequest& failed_request, + const blink::WebURLError& error, + std::string* error_html, + base::string16* error_description) { + if (!error_description) + return; + + *error_description = base::UTF8ToUTF16(net::ErrorToShortString(error.reason)); +} + } // namespace atom diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 59b407ba1efb..f4a548908e06 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -9,21 +9,23 @@ #include #include "content/public/renderer/content_renderer_client.h" -#include "content/public/renderer/render_process_observer.h" namespace atom { class AtomBindings; +class PreferencesManager; class NodeBindings; -class AtomRendererClient : public content::ContentRendererClient, - public content::RenderProcessObserver { +class AtomRendererClient : public content::ContentRendererClient { public: AtomRendererClient(); virtual ~AtomRendererClient(); - void DidCreateScriptContext(v8::Handle context); - void WillReleaseScriptContext(v8::Handle context); + void DidClearWindowObject(content::RenderFrame* render_frame); + void DidCreateScriptContext( + v8::Handle context, content::RenderFrame* render_frame); + void WillReleaseScriptContext( + v8::Handle context, content::RenderFrame* render_frame); private: enum NodeIntegration { @@ -33,13 +35,12 @@ class AtomRendererClient : public content::ContentRendererClient, DISABLE, }; - // content::RenderProcessObserver: - void WebKitInitialized() override; - // content::ContentRendererClient: void RenderThreadStarted() override; void RenderFrameCreated(content::RenderFrame*) override; void RenderViewCreated(content::RenderView*) override; + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override; + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override; blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( blink::WebSpeechSynthesizerClient* client) override; bool OverrideCreatePlugin(content::RenderFrame* render_frame, @@ -57,9 +58,15 @@ class AtomRendererClient : public content::ContentRendererClient, const std::string& mime_type, const GURL& original_url) override; void AddKeySystems(std::vector* key_systems) override; + void GetNavigationErrorStrings(content::RenderFrame* render_frame, + const blink::WebURLRequest& failed_request, + const blink::WebURLError& error, + std::string* error_html, + base::string16* error_description) override; - scoped_ptr node_bindings_; - scoped_ptr atom_bindings_; + std::unique_ptr node_bindings_; + std::unique_ptr atom_bindings_; + std::unique_ptr preferences_manager_; DISALLOW_COPY_AND_ASSIGN(AtomRendererClient); }; diff --git a/atom/renderer/node_array_buffer_bridge.cc b/atom/renderer/node_array_buffer_bridge.cc index c4b8d26adaa7..61ad25222f99 100644 --- a/atom/renderer/node_array_buffer_bridge.cc +++ b/atom/renderer/node_array_buffer_bridge.cc @@ -53,7 +53,7 @@ v8::Local BlinkUint8ArrayNew( ab, mate::ConvertToV8(isolate, offset), mate::ConvertToV8(isolate, size) }; return v8::Local::Cast(constructor->NewInstance( - context, arraysize(args), args).ToLocalChecked()); + context, node::arraysize(args), args).ToLocalChecked()); } } // namespace diff --git a/atom/renderer/preferences_manager.cc b/atom/renderer/preferences_manager.cc new file mode 100644 index 000000000000..a9ed710a9dbd --- /dev/null +++ b/atom/renderer/preferences_manager.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/renderer/preferences_manager.h" + +#include "atom/common/api/api_messages.h" +#include "content/public/renderer/render_thread.h" + +namespace atom { + +PreferencesManager::PreferencesManager() { + content::RenderThread::Get()->AddObserver(this); +} + +PreferencesManager::~PreferencesManager() { +} + +bool PreferencesManager::OnControlMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PreferencesManager, message) + IPC_MESSAGE_HANDLER(AtomMsg_UpdatePreferences, OnUpdatePreferences) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PreferencesManager::OnUpdatePreferences( + const base::ListValue& preferences) { + preferences_ = preferences.CreateDeepCopy(); +} + +} // namespace atom diff --git a/atom/renderer/preferences_manager.h b/atom/renderer/preferences_manager.h new file mode 100644 index 000000000000..451928085d12 --- /dev/null +++ b/atom/renderer/preferences_manager.h @@ -0,0 +1,35 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_PREFERENCES_MANAGER_H_ +#define ATOM_RENDERER_PREFERENCES_MANAGER_H_ + +#include + +#include "base/values.h" +#include "content/public/renderer/render_process_observer.h" + +namespace atom { + +class PreferencesManager : public content::RenderProcessObserver { + public: + PreferencesManager(); + ~PreferencesManager() override; + + const base::ListValue* preferences() const { return preferences_.get(); } + + private: + // content::RenderThreadObserver: + bool OnControlMessageReceived(const IPC::Message& message) override; + + void OnUpdatePreferences(const base::ListValue& preferences); + + std::unique_ptr preferences_; + + DISALLOW_COPY_AND_ASSIGN(PreferencesManager); +}; + +} // namespace atom + +#endif // ATOM_RENDERER_PREFERENCES_MANAGER_H_ diff --git a/chromium_src/SkUserConfig.h b/chromium_src/SkUserConfig.h new file mode 100644 index 000000000000..755b050de6c0 --- /dev/null +++ b/chromium_src/SkUserConfig.h @@ -0,0 +1,158 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkUserConfig_DEFINED +#define SkUserConfig_DEFINED + +/* SkTypes.h, the root of the public header files, does the following trick: + + #include "SkPreConfig.h" + #include "SkUserConfig.h" + #include "SkPostConfig.h" + + SkPreConfig.h runs first, and it is responsible for initializing certain + skia defines. + + SkPostConfig.h runs last, and its job is to just check that the final + defines are consistent (i.e. that we don't have mutually conflicting + defines). + + SkUserConfig.h (this file) runs in the middle. It gets to change or augment + the list of flags initially set in preconfig, and then postconfig checks + that everything still makes sense. + + Below are optional defines that add, subtract, or change default behavior + in Skia. Your port can locally edit this file to enable/disable flags as + you choose, or these can be delared on your command line (i.e. -Dfoo). + + By default, this include file will always default to having all of the flags + commented out, so including it will have no effect. +*/ + +/////////////////////////////////////////////////////////////////////////////// + +/* Skia has lots of debug-only code. Often this is just null checks or other + parameter checking, but sometimes it can be quite intrusive (e.g. check that + each 32bit pixel is in premultiplied form). This code can be very useful + during development, but will slow things down in a shipping product. + + By default, these mutually exclusive flags are defined in SkPreConfig.h, + based on the presence or absence of NDEBUG, but that decision can be changed + here. + */ +//#define SK_DEBUG +//#define SK_RELEASE + +/* Skia has certain debug-only code that is extremely intensive even for debug + builds. This code is useful for diagnosing specific issues, but is not + generally applicable, therefore it must be explicitly enabled to avoid + the performance impact. By default these flags are undefined, but can be + enabled by uncommenting them below. + */ +//#define SK_DEBUG_GLYPH_CACHE +//#define SK_DEBUG_PATH + +/* If, in debugging mode, Skia needs to stop (presumably to invoke a debugger) + it will call SK_CRASH(). If this is not defined it, it is defined in + SkPostConfig.h to write to an illegal address + */ +//#define SK_CRASH() *(int *)(uintptr_t)0 = 0 + + +/* preconfig will have attempted to determine the endianness of the system, + but you can change these mutually exclusive flags here. + */ +//#define SK_CPU_BENDIAN +//#define SK_CPU_LENDIAN + +/* Most compilers use the same bit endianness for bit flags in a byte as the + system byte endianness, and this is the default. If for some reason this + needs to be overridden, specify which of the mutually exclusive flags to + use. For example, some atom processors in certain configurations have big + endian byte order but little endian bit orders. +*/ +//#define SK_UINT8_BITFIELD_BENDIAN +//#define SK_UINT8_BITFIELD_LENDIAN + + +/* To write debug messages to a console, skia will call SkDebugf(...) following + printf conventions (e.g. const char* format, ...). If you want to redirect + this to something other than printf, define yours here + */ +// Log the file and line number for assertions. +#define SkDebugf(...) + +/* + * To specify a different default font cache limit, define this. If this is + * undefined, skia will use a built-in value. + */ +//#define SK_DEFAULT_FONT_CACHE_LIMIT (1024 * 1024) + +/* + * To specify the default size of the image cache, undefine this and set it to + * the desired value (in bytes). SkGraphics.h as a runtime API to set this + * value as well. If this is undefined, a built-in value will be used. + */ +//#define SK_DEFAULT_IMAGE_CACHE_LIMIT (1024 * 1024) + +/* Define this to allow PDF scalars above 32k. The PDF/A spec doesn't allow + them, but modern PDF interpreters should handle them just fine. + */ +//#define SK_ALLOW_LARGE_PDF_SCALARS + +/* Define this to provide font subsetter in PDF generation. + */ +//#define SK_SFNTLY_SUBSETTER "sfntly/subsetter/font_subsetter.h" + +/* Define this to set the upper limit for text to support LCD. Values that + are very large increase the cost in the font cache and draw slower, without + improving readability. If this is undefined, Skia will use its default + value (e.g. 48) + */ +//#define SK_MAX_SIZE_FOR_LCDTEXT 48 + +/* If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST + which will run additional self-tests at startup. These can take a long time, + so this flag is optional. + */ +#ifdef SK_DEBUG +//#define SK_SUPPORT_UNITTEST +#endif + +/* Change the ordering to work in X windows. + */ +#ifdef SK_SAMPLES_FOR_X + #define SK_R32_SHIFT 16 + #define SK_G32_SHIFT 8 + #define SK_B32_SHIFT 0 + #define SK_A32_SHIFT 24 +#endif + + +/* Determines whether to build code that supports the GPU backend. Some classes + that are not GPU-specific, such as SkShader subclasses, have optional code + that is used allows them to interact with the GPU backend. If you'd like to + omit this code set SK_SUPPORT_GPU to 0. This also allows you to omit the gpu + directories from your include search path when you're not building the GPU + backend. Defaults to 1 (build the GPU code). + */ +//#define SK_SUPPORT_GPU 1 + + +/* The PDF generation code uses Path Ops to handle complex clipping paths, + * but at this time, Path Ops is not release ready yet. So, the code is + * hidden behind this #define guard. If you are feeling adventurous and + * want the latest and greatest PDF generation code, uncomment the #define. + * When Path Ops is release ready, the define guards and this user config + * define should be removed entirely. + */ +//#define SK_PDF_USE_PATHOPS_CLIPPING + +#endif + diff --git a/chromium_src/chrome/browser/browser_process.h b/chromium_src/chrome/browser/browser_process.h index 8baa899f7ada..53ec0ba75f1c 100644 --- a/chromium_src/chrome/browser/browser_process.h +++ b/chromium_src/chrome/browser/browser_process.h @@ -31,7 +31,7 @@ class BrowserProcess { printing::PrintJobManager* print_job_manager(); private: - scoped_ptr print_job_manager_; + std::unique_ptr print_job_manager_; DISALLOW_COPY_AND_ASSIGN(BrowserProcess); }; diff --git a/chromium_src/chrome/browser/certificate_manager_model.cc b/chromium_src/chrome/browser/certificate_manager_model.cc index b0db6edc357c..2274c09e3415 100644 --- a/chromium_src/chrome/browser/certificate_manager_model.cc +++ b/chromium_src/chrome/browser/certificate_manager_model.cc @@ -138,7 +138,7 @@ void CertificateManagerModel::DidGetCertDBOnUIThread( const CreationCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - scoped_ptr model(new CertificateManagerModel( + std::unique_ptr model(new CertificateManagerModel( cert_db, is_user_db_available)); callback.Run(std::move(model)); } diff --git a/chromium_src/chrome/browser/certificate_manager_model.h b/chromium_src/chrome/browser/certificate_manager_model.h index 1eb350876803..81c3b6c8a8d1 100644 --- a/chromium_src/chrome/browser/certificate_manager_model.h +++ b/chromium_src/chrome/browser/certificate_manager_model.h @@ -24,7 +24,7 @@ class ResourceContext; // manager dialog, and processes changes from the view. class CertificateManagerModel { public: - typedef base::Callback)> + typedef base::Callback)> CreationCallback; // Creates a CertificateManagerModel. The model will be passed to the callback diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h b/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h index b3917e9a160e..1999e0e7747b 100644 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h +++ b/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h @@ -41,7 +41,7 @@ class GlobalShortcutListenerWin : public GlobalShortcutListener { typedef std::map HotkeyIdMap; HotkeyIdMap hotkey_ids_; - scoped_ptr singleton_hwnd_observer_; + std::unique_ptr singleton_hwnd_observer_; DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin); }; diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc index 9a3cca69d538..00a689a7cb2f 100644 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc +++ b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc @@ -4,10 +4,13 @@ #include "chrome/browser/extensions/global_shortcut_listener_x11.h" +#include + +#include "base/macros.h" #include "content/public/browser/browser_thread.h" #include "ui/base/accelerators/accelerator.h" #include "ui/events/keycodes/keyboard_code_conversion_x.h" -#include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/platform/platform_event_source.h" #include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_types.h" @@ -69,7 +72,7 @@ void GlobalShortcutListenerX11::StartListening() { DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is // registered. - ui::X11EventSource::GetInstance()->AddPlatformEventDispatcher(this); + ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); is_listening_ = true; } @@ -79,7 +82,7 @@ void GlobalShortcutListenerX11::StopListening() { DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before // ending. - ui::X11EventSource::GetInstance()->RemovePlatformEventDispatcher(this); + ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); is_listening_ = false; } @@ -149,7 +152,6 @@ void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) { modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0; modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0; modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0; - // For Windows key modifiers |= (x_event->xkey.state & Mod4Mask) ? ui::EF_COMMAND_DOWN: 0; ui::Accelerator accelerator( diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h index 8d551993841d..43230b7aa310 100644 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h +++ b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h @@ -5,9 +5,12 @@ #ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ #define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ +#include #include + #include +#include "base/macros.h" #include "chrome/browser/extensions/global_shortcut_listener.h" #include "ui/events/platform/platform_event_dispatcher.h" @@ -20,20 +23,18 @@ class GlobalShortcutListenerX11 : public GlobalShortcutListener, public ui::PlatformEventDispatcher { public: GlobalShortcutListenerX11(); - virtual ~GlobalShortcutListenerX11(); + ~GlobalShortcutListenerX11() override; // ui::PlatformEventDispatcher implementation. - virtual bool CanDispatchEvent(const ui::PlatformEvent& event) override; - virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) override; + bool CanDispatchEvent(const ui::PlatformEvent& event) override; + uint32_t DispatchEvent(const ui::PlatformEvent& event) override; private: // GlobalShortcutListener implementation. - virtual void StartListening() override; - virtual void StopListening() override; - virtual bool RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) override; - virtual void UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) override; + void StartListening() override; + void StopListening() override; + bool RegisterAcceleratorImpl(const ui::Accelerator& accelerator) override; + void UnregisterAcceleratorImpl(const ui::Accelerator& accelerator) override; // Invoked when a global shortcut is pressed. void OnXKeyPressEvent(::XEvent* x_event); diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index 3c1848df3ef9..a524dfcf38cb 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -39,7 +39,7 @@ uint32_t GetFrameHash(webrtc::DesktopFrame* frame) { return base::SuperFastHash(reinterpret_cast(frame->data()), data_size); } -gfx::ImageSkia ScaleDesktopFrame(scoped_ptr frame, +gfx::ImageSkia ScaleDesktopFrame(std::unique_ptr frame, gfx::Size size) { gfx::Rect scaled_rect = media::ComputeLetterboxRegion( gfx::Rect(0, 0, size.width(), size.height()), @@ -86,8 +86,8 @@ class NativeDesktopMediaList::Worker : public webrtc::DesktopCapturer::Callback { public: Worker(base::WeakPtr media_list, - scoped_ptr screen_capturer, - scoped_ptr window_capturer); + std::unique_ptr screen_capturer, + std::unique_ptr window_capturer); ~Worker() override; void Refresh(const gfx::Size& thumbnail_size, @@ -102,10 +102,10 @@ class NativeDesktopMediaList::Worker base::WeakPtr media_list_; - scoped_ptr screen_capturer_; - scoped_ptr window_capturer_; + std::unique_ptr screen_capturer_; + std::unique_ptr window_capturer_; - scoped_ptr current_frame_; + std::unique_ptr current_frame_; ImageHashesMap image_hashes_; @@ -114,8 +114,8 @@ class NativeDesktopMediaList::Worker NativeDesktopMediaList::Worker::Worker( base::WeakPtr media_list, - scoped_ptr screen_capturer, - scoped_ptr window_capturer) + std::unique_ptr screen_capturer, + std::unique_ptr window_capturer) : media_list_(media_list), screen_capturer_(std::move(screen_capturer)), window_capturer_(std::move(window_capturer)) { @@ -229,8 +229,8 @@ void NativeDesktopMediaList::Worker::OnCaptureCompleted( } NativeDesktopMediaList::NativeDesktopMediaList( - scoped_ptr screen_capturer, - scoped_ptr window_capturer) + std::unique_ptr screen_capturer, + std::unique_ptr window_capturer) : screen_capturer_(std::move(screen_capturer)), window_capturer_(std::move(window_capturer)), update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.h b/chromium_src/chrome/browser/media/native_desktop_media_list.h index f789a368be90..803243979801 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.h +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.h @@ -25,8 +25,8 @@ class NativeDesktopMediaList : public DesktopMediaList { // types of sources the model should be populated with (e.g. it will only // contain windows, if |screen_capturer| is NULL). NativeDesktopMediaList( - scoped_ptr screen_capturer, - scoped_ptr window_capturer); + std::unique_ptr screen_capturer, + std::unique_ptr window_capturer); ~NativeDesktopMediaList() override; // DesktopMediaList interface. @@ -66,8 +66,8 @@ class NativeDesktopMediaList : public DesktopMediaList { void OnRefreshFinished(); // Capturers specified in SetCapturers() and passed to the |worker_| later. - scoped_ptr screen_capturer_; - scoped_ptr window_capturer_; + std::unique_ptr screen_capturer_; + std::unique_ptr window_capturer_; // Time interval between mode updates. base::TimeDelta update_period_; @@ -87,7 +87,7 @@ class NativeDesktopMediaList : public DesktopMediaList { // An object that does all the work of getting list of sources on a background // thread (see |capture_task_runner_|). Destroyed on |capture_task_runner_| // after the model is destroyed. - scoped_ptr worker_; + std::unique_ptr worker_; // Current list of sources. std::vector sources_; diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc index 5d42264144a5..e13effd64de0 100644 --- a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc +++ b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc @@ -48,7 +48,7 @@ class RefCountedTempDir DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir); }; -typedef scoped_ptr +typedef std::unique_ptr ScopedTempFile; // Wrapper for Emf to keep only file handle in memory, and load actual data only @@ -58,7 +58,7 @@ typedef scoped_ptr class LazyEmf : public MetafilePlayer { public: LazyEmf(const scoped_refptr& temp_dir, ScopedTempFile file) - : temp_dir_(temp_dir), file_(file.Pass()) {} + : temp_dir_(temp_dir), file_(std::move(file)) {} virtual ~LazyEmf() { Close(); } virtual bool SafePlayback(HDC hdc) const override; @@ -131,8 +131,8 @@ class PdfToEmfUtilityProcessHostClient const PdfToEmfConverter::GetPageCallback& callback() const { return callback_; } - ScopedTempFile emf() { return emf_.Pass(); } - void set_emf(ScopedTempFile emf) { emf_ = emf.Pass(); } + ScopedTempFile TakeEmf() { return std::move(emf_); } + void set_emf(ScopedTempFile emf) { emf_ = std::move(emf); } private: int page_number_; @@ -203,10 +203,10 @@ ScopedTempFile CreateTempFile(scoped_refptr* temp_dir) { *temp_dir = new RefCountedTempDir(); ScopedTempFile file; if (!(*temp_dir)->IsValid()) - return file.Pass(); + return file; base::FilePath path; if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) - return file.Pass(); + return file; file.reset(new base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | @@ -215,7 +215,7 @@ ScopedTempFile CreateTempFile(scoped_refptr* temp_dir) { base::File::FLAG_TEMPORARY)); if (!file->IsValid()) file.reset(); - return file.Pass(); + return file; } ScopedTempFile CreateTempPdfFile( @@ -230,7 +230,7 @@ ScopedTempFile CreateTempPdfFile( pdf_file.reset(); } pdf_file->Seek(base::File::FROM_BEGIN, 0); - return pdf_file.Pass(); + return pdf_file; } bool LazyEmf::SafePlayback(HDC hdc) const { @@ -319,12 +319,11 @@ void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!utility_process_host_) + if (!utility_process_host_ || !pdf) return OnFailed(); - base::ProcessHandle process = utility_process_host_->GetData().handle; // Should reply with OnPageCount(). Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( - IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false), + IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false), settings_)); } @@ -373,12 +372,11 @@ void PdfToEmfUtilityProcessHostClient::OnTempEmfReady( GetPageCallbackData* callback_data, ScopedTempFile emf) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!utility_process_host_) + if (!utility_process_host_ || !emf) return OnFailed(); - base::ProcessHandle process = utility_process_host_->GetData().handle; IPC::PlatformFileForTransit transit = - IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false); - callback_data->set_emf(emf.Pass()); + IPC::GetPlatformFileForTransit(emf->GetPlatformFile(), false); + callback_data->set_emf(std::move(emf)); // Should reply with OnPageDone(). Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage( callback_data->page_number(), transit)); @@ -389,10 +387,16 @@ void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, DCHECK_CURRENTLY_ON(BrowserThread::IO); if (get_page_callbacks_.empty()) return OnFailed(); - scoped_ptr emf; GetPageCallbackData& data = get_page_callbacks_.front(); - if (success) - emf.reset(new LazyEmf(temp_dir_, data.emf().Pass())); + std::unique_ptr emf; + + if (success) { + ScopedTempFile temp_emf = data.TakeEmf(); + if (!temp_emf) // Unexpected message from utility process. + return OnFailed(); + emf.reset(new LazyEmf(temp_dir_, std::move(temp_emf))); + } + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(&PdfToEmfConverterImpl::RunCallback, @@ -487,8 +491,8 @@ PdfToEmfConverter::~PdfToEmfConverter() { } // static -scoped_ptr PdfToEmfConverter::CreateDefault() { - return scoped_ptr(new PdfToEmfConverterImpl()); +std::unique_ptr PdfToEmfConverter::CreateDefault() { + return std::unique_ptr(new PdfToEmfConverterImpl()); } } // namespace printing diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h index 60fdbc4b7e4e..859d42293135 100644 --- a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h +++ b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h @@ -23,11 +23,11 @@ class PdfToEmfConverter { typedef base::Callback StartCallback; typedef base::Callback emf)> GetPageCallback; + std::unique_ptr emf)> GetPageCallback; virtual ~PdfToEmfConverter(); - static scoped_ptr CreateDefault(); + static std::unique_ptr CreateDefault(); // Starts conversion of PDF provided as |data|. Calls |start_callback| // with positive |page_count|. |page_count| is 0 if initialization failed. diff --git a/chromium_src/chrome/browser/printing/print_job.cc b/chromium_src/chrome/browser/printing/print_job.cc index 60dcebe08033..87971055e68f 100644 --- a/chromium_src/chrome/browser/printing/print_job.cc +++ b/chromium_src/chrome/browser/printing/print_job.cc @@ -133,7 +133,7 @@ void PrintJob::StartPrinting() { make_scoped_refptr(this), base::Bind(&PrintJobWorker::StartPrinting, base::Unretained(worker_.get()), - document_))); + base::RetainedRef(document_)))); // Set the flag right now. is_job_pending_ = true; @@ -267,7 +267,7 @@ class PrintJob::PdfToEmfState { int pages_in_progress_; gfx::Size page_size_; gfx::Rect content_area_; - scoped_ptr converter_; + std::unique_ptr converter_; }; void PrintJob::StartPdfToEmfConversion( @@ -296,7 +296,7 @@ void PrintJob::OnPdfToEmfStarted(int page_count) { void PrintJob::OnPdfToEmfPageConverted(int page_number, float scale_factor, - scoped_ptr emf) { + std::unique_ptr emf) { DCHECK(ptd_to_emf_state_); if (!document_.get() || !emf) { ptd_to_emf_state_.reset(); @@ -306,7 +306,7 @@ void PrintJob::OnPdfToEmfPageConverted(int page_number, // Update the rendered document. It will send notifications to the listener. document_->SetPage(page_number, - emf.Pass(), + std::move(emf), scale_factor, ptd_to_emf_state_->page_size(), ptd_to_emf_state_->content_area()); @@ -335,7 +335,7 @@ void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) { make_scoped_refptr(this), base::Bind(&PrintJobWorker::OnDocumentChanged, base::Unretained(worker_.get()), - document_))); + base::RetainedRef(document_)))); } } diff --git a/chromium_src/chrome/browser/printing/print_job.h b/chromium_src/chrome/browser/printing/print_job.h index 4963a94f14f5..5569f87679f7 100644 --- a/chromium_src/chrome/browser/printing/print_job.h +++ b/chromium_src/chrome/browser/printing/print_job.h @@ -98,7 +98,7 @@ class PrintJob : public PrintJobWorkerOwner, void OnPdfToEmfStarted(int page_count); void OnPdfToEmfPageConverted(int page_number, float scale_factor, - scoped_ptr emf); + std::unique_ptr emf); #endif // OS_WIN @@ -134,7 +134,7 @@ class PrintJob : public PrintJobWorkerOwner, // All the UI is done in a worker thread because many Win32 print functions // are blocking and enters a message loop without your consent. There is one // worker thread per print job. - scoped_ptr worker_; + std::unique_ptr worker_; // Cache of the print context settings for access in the UI thread. PrintSettings settings_; @@ -151,7 +151,7 @@ class PrintJob : public PrintJobWorkerOwner, #if defined(OS_WIN) class PdfToEmfState; - scoped_ptr ptd_to_emf_state_; + std::unique_ptr ptd_to_emf_state_; #endif // OS_WIN // Used at shutdown so that we can quit a nested message loop. diff --git a/chromium_src/chrome/browser/printing/print_job_worker.cc b/chromium_src/chrome/browser/printing/print_job_worker.cc index 889ad6d2523f..7a88a8570c42 100644 --- a/chromium_src/chrome/browser/printing/print_job_worker.cc +++ b/chromium_src/chrome/browser/printing/print_job_worker.cc @@ -146,7 +146,7 @@ void PrintJobWorker::GetSettings( } void PrintJobWorker::SetSettings( - scoped_ptr new_settings) { + std::unique_ptr new_settings) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); BrowserThread::PostTask( @@ -160,7 +160,7 @@ void PrintJobWorker::SetSettings( } void PrintJobWorker::UpdatePrintSettings( - scoped_ptr new_settings) { + std::unique_ptr new_settings) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PrintingContext::Result result = printing_context_->UpdatePrintSettings(*new_settings); @@ -338,11 +338,9 @@ void PrintJobWorker::OnDocumentDone() { } owner_->PostTask(FROM_HERE, - base::Bind(&NotificationCallback, - make_scoped_refptr(owner_), + base::Bind(&NotificationCallback, base::RetainedRef(owner_), JobEventDetails::DOC_DONE, - document_, - scoped_refptr())); + base::RetainedRef(document_), nullptr)); // Makes sure the variables are reinitialized. document_ = NULL; @@ -354,11 +352,9 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) { // Signal everyone that the page is about to be printed. owner_->PostTask(FROM_HERE, - base::Bind(&NotificationCallback, - make_scoped_refptr(owner_), - JobEventDetails::NEW_PAGE, - document_, - make_scoped_refptr(page))); + base::Bind(&NotificationCallback, base::RetainedRef(owner_), + JobEventDetails::NEW_PAGE, base::RetainedRef(document_), + base::RetainedRef(page))); // Preprocess. if (printing_context_->NewPage() != PrintingContext::OK) { @@ -380,12 +376,11 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) { } // Signal everyone that the page is printed. - owner_->PostTask(FROM_HERE, - base::Bind(&NotificationCallback, - make_scoped_refptr(owner_), - JobEventDetails::PAGE_DONE, - document_, - make_scoped_refptr(page))); + owner_->PostTask( + FROM_HERE, + base::Bind(&NotificationCallback, base::RetainedRef(owner_), + JobEventDetails::PAGE_DONE, base::RetainedRef(document_), + base::RetainedRef(page))); } void PrintJobWorker::OnFailure() { @@ -394,12 +389,11 @@ void PrintJobWorker::OnFailure() { // We may loose our last reference by broadcasting the FAILED event. scoped_refptr handle(owner_); - owner_->PostTask(FROM_HERE, - base::Bind(&NotificationCallback, - make_scoped_refptr(owner_), - JobEventDetails::FAILED, - document_, - scoped_refptr())); + owner_->PostTask( + FROM_HERE, + base::Bind(&NotificationCallback, base::RetainedRef(owner_), + JobEventDetails::FAILED, + base::RetainedRef(document_), nullptr)); Cancel(); // Makes sure the variables are reinitialized. diff --git a/chromium_src/chrome/browser/printing/print_job_worker.h b/chromium_src/chrome/browser/printing/print_job_worker.h index a8378bb2353d..6b15097b7af4 100644 --- a/chromium_src/chrome/browser/printing/print_job_worker.h +++ b/chromium_src/chrome/browser/printing/print_job_worker.h @@ -48,7 +48,7 @@ class PrintJobWorker { MarginType margin_type); // Set the new print settings. - void SetSettings(scoped_ptr new_settings); + void SetSettings(std::unique_ptr new_settings); // Starts the printing loop. Every pages are printed as soon as the data is // available. Makes sure the new_document is the right one. @@ -116,7 +116,7 @@ class PrintJobWorker { void GetSettingsWithUIDone(PrintingContext::Result result); // Called on the UI thread to update the print settings. - void UpdatePrintSettings(scoped_ptr new_settings); + void UpdatePrintSettings(std::unique_ptr new_settings); // Reports settings back to owner_. void GetSettingsDone(PrintingContext::Result result); @@ -127,10 +127,10 @@ class PrintJobWorker { void UseDefaultSettings(); // Printing context delegate. - scoped_ptr printing_context_delegate_; + std::unique_ptr printing_context_delegate_; // Information about the printer setting. - scoped_ptr printing_context_; + std::unique_ptr printing_context_; // The printed document. Only has read-only access. scoped_refptr document_; diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index a195ad4c6adf..d1f3660f8d2d 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -43,7 +43,7 @@ void StopWorker(int document_cookie) { char* CopyPDFDataOnIOThread( const PrintHostMsg_DidPreviewDocument_Params& params) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - scoped_ptr shared_buf( + std::unique_ptr shared_buf( new base::SharedMemory(params.metafile_data_handle, true)); if (!shared_buf->Map(params.data_size)) return nullptr; diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc index 688256e4251f..2bbafdd8e55a 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.cc @@ -6,7 +6,7 @@ #include "base/bind.h" #include "base/memory/scoped_ptr.h" -#include "base/prefs/pref_service.h" +#include "components/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" #include "base/timer/timer.h" #include "chrome/browser/browser_process.h" @@ -132,7 +132,7 @@ void PrintViewManagerBase::OnDidPrintPage( } } - scoped_ptr metafile(new PdfMetafileSkia); + std::unique_ptr metafile(new PdfMetafileSkia); if (metafile_must_be_valid) { if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) { NOTREACHED() << "Invalid metafile header"; diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.h b/chromium_src/chrome/browser/printing/print_view_manager_base.h index 0d44248bfe29..78e5729a5fb1 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.h +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.h @@ -6,7 +6,7 @@ #define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_ #include "base/memory/ref_counted.h" -#include "base/prefs/pref_member.h" +#include "components/prefs/pref_member.h" #include "base/strings/string16.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" diff --git a/chromium_src/chrome/browser/printing/printer_query.cc b/chromium_src/chrome/browser/printing/printer_query.cc index 6cd11ff067ef..72e2b85f635c 100644 --- a/chromium_src/chrome/browser/printing/printer_query.cc +++ b/chromium_src/chrome/browser/printing/printer_query.cc @@ -85,7 +85,7 @@ void PrinterQuery::GetSettings( margin_type)); } -void PrinterQuery::SetSettings(scoped_ptr new_settings, +void PrinterQuery::SetSettings(std::unique_ptr new_settings, const base::Closure& callback) { StartWorker(callback); diff --git a/chromium_src/chrome/browser/printing/printer_query.h b/chromium_src/chrome/browser/printing/printer_query.h index 9fd9a82b33ea..934c18592646 100644 --- a/chromium_src/chrome/browser/printing/printer_query.h +++ b/chromium_src/chrome/browser/printing/printer_query.h @@ -50,7 +50,7 @@ class PrinterQuery : public PrintJobWorkerOwner { const base::Closure& callback); // Updates the current settings with |new_settings| dictionary values. - void SetSettings(scoped_ptr new_settings, + void SetSettings(std::unique_ptr new_settings, const base::Closure& callback); // Stops the worker thread since the client is done with this object. @@ -73,7 +73,7 @@ class PrinterQuery : public PrintJobWorkerOwner { // All the UI is done in a worker thread because many Win32 print functions // are blocking and enters a message loop without your consent. There is one // worker thread per print job. - scoped_ptr worker_; + std::unique_ptr worker_; // Cache of the print context settings for access in the UI thread. PrintSettings settings_; diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.cc b/chromium_src/chrome/browser/printing/printing_message_filter.cc index eac4405fbcf6..819c6af5b020 100644 --- a/chromium_src/chrome/browser/printing/printing_message_filter.cc +++ b/chromium_src/chrome/browser/printing/printing_message_filter.cc @@ -71,10 +71,6 @@ void RenderParamsFromPrintSettings(const PrintSettings& settings, params->margin_top = settings.page_setup_device_units().content_area().y(); params->margin_left = settings.page_setup_device_units().content_area().x(); params->dpi = settings.dpi(); - // Currently hardcoded at 1.25. See PrintSettings' constructor. - params->min_shrink = settings.min_shrink(); - // Currently hardcoded at 2.0. See PrintSettings' constructor. - params->max_shrink = settings.max_shrink(); // Currently hardcoded at 72dpi. See PrintSettings' constructor. params->desired_dpi = settings.desired_dpi(); // Always use an invalid cookie. @@ -144,7 +140,7 @@ void PrintingMessageFilter::OnDuplicateSection( base::SharedMemoryHandle* browser_handle) { // Duplicate the handle in this process right now so the memory is kept alive // (even if it is not mapped) - base::SharedMemory shared_buf(renderer_handle, true, PeerHandle()); + base::SharedMemory shared_buf(renderer_handle, true); shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle); } #endif @@ -377,7 +373,7 @@ void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) { void PrintingMessageFilter::OnUpdatePrintSettings( int document_cookie, const base::DictionaryValue& job_settings, IPC::Message* reply_msg) { - scoped_ptr new_settings(job_settings.DeepCopy()); + std::unique_ptr new_settings(job_settings.DeepCopy()); scoped_refptr printer_query; printer_query = queue_->PopPrinterQuery(document_cookie); diff --git a/chromium_src/chrome/browser/process_singleton_posix.cc b/chromium_src/chrome/browser/process_singleton_posix.cc index 5c26d7b6157a..5742b3585205 100644 --- a/chromium_src/chrome/browser/process_singleton_posix.cc +++ b/chromium_src/chrome/browser/process_singleton_posix.cc @@ -79,7 +79,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "content/public/browser/browser_thread.h" -#include "net/base/net_util.h" +#include "net/base/network_interfaces.h" #include "ui/base/l10n/l10n_util.h" #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) diff --git a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc index 98932a494bf8..5364aa0b881f 100644 --- a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc +++ b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc @@ -29,7 +29,7 @@ ChromeBrowserPepperHostFactory::ChromeBrowserPepperHostFactory( ChromeBrowserPepperHostFactory::~ChromeBrowserPepperHostFactory() {} -scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( +std::unique_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( ppapi::host::PpapiHost* host, PP_Resource resource, PP_Instance instance, @@ -38,7 +38,7 @@ scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( // Make sure the plugin is giving us a valid instance for this resource. if (!host_->IsValidInstance(instance)) - return scoped_ptr(); + return std::unique_ptr(); // Private interfaces. if (host_->GetPpapiHost()->permissions().HasPermission( @@ -47,7 +47,7 @@ scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( case PpapiHostMsg_Broker_Create::ID: { scoped_refptr broker_filter( new PepperBrokerMessageFilter(instance, host_)); - return scoped_ptr(new MessageFilterHost( + return std::unique_ptr(new MessageFilterHost( host_->GetPpapiHost(), instance, resource, broker_filter)); } } @@ -58,16 +58,16 @@ scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( ppapi::PERMISSION_FLASH)) { switch (message.type()) { case PpapiHostMsg_Flash_Create::ID: - return scoped_ptr( + return std::unique_ptr( new PepperFlashBrowserHost(host_, instance, resource)); case PpapiHostMsg_FlashClipboard_Create::ID: { scoped_refptr clipboard_filter( new PepperFlashClipboardMessageFilter); - return scoped_ptr(new MessageFilterHost( + return std::unique_ptr(new MessageFilterHost( host_->GetPpapiHost(), instance, resource, clipboard_filter)); } case PpapiHostMsg_FlashDRM_Create::ID: - return scoped_ptr( + return std::unique_ptr( new chrome::PepperFlashDRMHost(host_, instance, resource)); } } @@ -82,12 +82,12 @@ scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( PepperIsolatedFileSystemMessageFilter* isolated_fs_filter = PepperIsolatedFileSystemMessageFilter::Create(instance, host_); if (!isolated_fs_filter) - return scoped_ptr(); - return scoped_ptr( + return std::unique_ptr(); + return std::unique_ptr( new MessageFilterHost(host, instance, resource, isolated_fs_filter)); } - return scoped_ptr(); + return std::unique_ptr(); } } // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h index b817953b54dc..84385140ceca 100644 --- a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h +++ b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h @@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ #define CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ -#include "base/compiler_specific.h" +#include "base/macros.h" #include "ppapi/host/host_factory.h" namespace content { @@ -20,7 +20,7 @@ class ChromeBrowserPepperHostFactory : public ppapi::host::HostFactory { explicit ChromeBrowserPepperHostFactory(content::BrowserPpapiHost* host); ~ChromeBrowserPepperHostFactory() override; - scoped_ptr CreateResourceHost( + std::unique_ptr CreateResourceHost( ppapi::host::PpapiHost* host, PP_Resource resource, PP_Instance instance, diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc index 9ddb9fa56d77..4e66d772ec38 100644 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc @@ -4,6 +4,8 @@ #include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" +#include + #include "base/pickle.h" #include "base/strings/utf_string_conversions.h" #include "content/public/browser/browser_thread.h" @@ -48,10 +50,10 @@ ui::ClipboardType ConvertClipboardType(uint32_t type) { // clipboard interface for custom data. bool JumpToFormatInPickle(const base::string16& format, base::PickleIterator* iter) { - size_t size = 0; - if (!iter->ReadSizeT(&size)) + uint32_t size = 0; + if (!iter->ReadUInt32(&size)) return false; - for (size_t i = 0; i < size; ++i) { + for (uint32_t i = 0; i < size; ++i) { base::string16 stored_format; if (!iter->ReadString16(&stored_format)) return false; @@ -83,7 +85,7 @@ std::string ReadDataFromPickle(const base::string16& format, bool WriteDataToPickle(const std::map& data, base::Pickle* pickle) { - pickle->WriteSizeT(data.size()); + pickle->WriteUInt32(data.size()); for (std::map::const_iterator it = data.begin(); it != data.end(); ++it) { diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc index f94216461769..34a7ff881f48 100644 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc @@ -21,7 +21,7 @@ #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/pepper_plugin_info.h" -#include "net/base/net_util.h" +#include "net/base/network_interfaces.h" #include "ppapi/c/pp_errors.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/host_message_context.h" diff --git a/chromium_src/chrome/browser/speech/tts_controller.h b/chromium_src/chrome/browser/speech/tts_controller.h index 3c40b9e5471d..f4dcd7747047 100644 --- a/chromium_src/chrome/browser/speech/tts_controller.h +++ b/chromium_src/chrome/browser/speech/tts_controller.h @@ -240,7 +240,7 @@ class Utterance { // The full options arg passed to tts.speak, which may include fields // other than the ones we explicitly parse, below. - scoped_ptr options_; + std::unique_ptr options_; // The extension ID of the extension that called speak() and should // receive events. diff --git a/chromium_src/chrome/browser/speech/tts_linux.cc b/chromium_src/chrome/browser/speech/tts_linux.cc index ba15516ce036..b1e8bc404336 100644 --- a/chromium_src/chrome/browser/speech/tts_linux.cc +++ b/chromium_src/chrome/browser/speech/tts_linux.cc @@ -81,7 +81,7 @@ class TtsPlatformImplLinux : public TtsPlatformImpl { // Map a string composed of a voicename and module to the voicename. Used to // uniquely identify a voice across all available modules. - scoped_ptr > all_native_voices_; + std::unique_ptr > all_native_voices_; friend struct base::DefaultSingletonTraits; diff --git a/chromium_src/chrome/browser/speech/tts_message_filter.cc b/chromium_src/chrome/browser/speech/tts_message_filter.cc index 66e4c40bd5eb..1a198d9e26e1 100644 --- a/chromium_src/chrome/browser/speech/tts_message_filter.cc +++ b/chromium_src/chrome/browser/speech/tts_message_filter.cc @@ -83,7 +83,7 @@ void TtsMessageFilter::OnInitializeVoiceList() { void TtsMessageFilter::OnSpeak(const TtsUtteranceRequest& request) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - scoped_ptr utterance(new Utterance(browser_context_)); + std::unique_ptr utterance(new Utterance(browser_context_)); utterance->set_src_id(request.id); utterance->set_text(request.text); utterance->set_lang(request.lang); diff --git a/chromium_src/chrome/common/chrome_paths_linux.cc b/chromium_src/chrome/common/chrome_paths_linux.cc index 91348fec4808..e89ae822d904 100644 --- a/chromium_src/chrome/common/chrome_paths_linux.cc +++ b/chromium_src/chrome/common/chrome_paths_linux.cc @@ -60,7 +60,7 @@ bool GetUserMediaDirectory(const std::string& xdg_name, // ~/.config/google-chrome/ for official builds. // (This also helps us sidestep issues with other apps grabbing ~/.chromium .) bool GetDefaultUserDataDirectory(base::FilePath* result) { - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); base::FilePath config_dir(GetXDGDirectory(env.get(), kXdgConfigHomeEnvVar, kDotConfigDir)); @@ -85,7 +85,7 @@ void GetUserCacheDirectory(const base::FilePath& profile_dir, // Default value in cases where any of the following fails. *result = profile_dir; - scoped_ptr env(base::Environment::Create()); + std::unique_ptr env(base::Environment::Create()); base::FilePath cache_dir; if (!PathService::Get(base::DIR_CACHE, &cache_dir)) diff --git a/chromium_src/chrome/common/chrome_paths_mac.mm b/chromium_src/chrome/common/chrome_paths_mac.mm index 4a4eb87dc254..bbfd6c9b23b0 100644 --- a/chromium_src/chrome/common/chrome_paths_mac.mm +++ b/chromium_src/chrome/common/chrome_paths_mac.mm @@ -13,7 +13,7 @@ #include "base/logging.h" #import "base/mac/foundation_util.h" #import "base/mac/scoped_nsautorelease_pool.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/free_deleter.h" #include "base/path_service.h" #include "chrome/common/chrome_constants.h" @@ -235,7 +235,7 @@ NSBundle* OuterAppBundle() { bool GetUserDataDirectoryForBrowserBundle(NSBundle* bundle, base::FilePath* result) { - scoped_ptr + std::unique_ptr product_dir_name(ProductDirNameForBundle(bundle)); return GetDefaultUserDataDirectoryForProduct(product_dir_name.get(), result); } diff --git a/chromium_src/chrome/renderer/media/chrome_key_systems.cc b/chromium_src/chrome/renderer/media/chrome_key_systems.cc index 5d97169005b4..417a61fcdab9 100644 --- a/chromium_src/chrome/renderer/media/chrome_key_systems.cc +++ b/chromium_src/chrome/renderer/media/chrome_key_systems.cc @@ -124,7 +124,7 @@ static void AddPepperBasedWidevine( } cdm::AddWidevineWithCodecs( - cdm::WIDEVINE, supported_codecs, + supported_codecs, #if defined(OS_CHROMEOS) media::EmeRobustness::HW_SECURE_ALL, // Maximum audio robustness. media::EmeRobustness::HW_SECURE_ALL, // Maximim video robustness. diff --git a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc index dd83b8191c06..bcf6debc4cf5 100644 --- a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc +++ b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc @@ -24,7 +24,7 @@ ChromeRendererPepperHostFactory::ChromeRendererPepperHostFactory( ChromeRendererPepperHostFactory::~ChromeRendererPepperHostFactory() {} -scoped_ptr ChromeRendererPepperHostFactory::CreateResourceHost( +std::unique_ptr ChromeRendererPepperHostFactory::CreateResourceHost( ppapi::host::PpapiHost* host, PP_Resource resource, PP_Instance instance, @@ -33,24 +33,24 @@ scoped_ptr ChromeRendererPepperHostFactory::CreateResourceHost( // Make sure the plugin is giving us a valid instance for this resource. if (!host_->IsValidInstance(instance)) - return scoped_ptr(); + return std::unique_ptr(); if (host_->GetPpapiHost()->permissions().HasPermission( ppapi::PERMISSION_FLASH)) { switch (message.type()) { case PpapiHostMsg_Flash_Create::ID: { - return scoped_ptr( + return std::unique_ptr( new PepperFlashRendererHost(host_, instance, resource)); } case PpapiHostMsg_FlashFullscreen_Create::ID: { - return scoped_ptr( + return std::unique_ptr( new PepperFlashFullscreenHost(host_, instance, resource)); } case PpapiHostMsg_FlashMenu_Create::ID: { ppapi::proxy::SerializedFlashMenu serialized_menu; if (ppapi::UnpackMessage( message, &serialized_menu)) { - return scoped_ptr(new PepperFlashMenuHost( + return std::unique_ptr(new PepperFlashMenuHost( host_, instance, resource, serialized_menu)); } break; @@ -71,7 +71,7 @@ scoped_ptr ChromeRendererPepperHostFactory::CreateResourceHost( PP_PrivateFontCharset charset; if (ppapi::UnpackMessage( message, &description, &charset)) { - return scoped_ptr(new PepperFlashFontFileHost( + return std::unique_ptr(new PepperFlashFontFileHost( host_, instance, resource, description, charset)); } break; @@ -79,5 +79,5 @@ scoped_ptr ChromeRendererPepperHostFactory::CreateResourceHost( } } - return scoped_ptr(); + return std::unique_ptr(); } diff --git a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h index dd12e9d91608..c52c73b56f04 100644 --- a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h +++ b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h @@ -5,6 +5,7 @@ #ifndef CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ #define CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ +#include "base/macros.h" #include "ppapi/host/host_factory.h" namespace content { @@ -17,7 +18,7 @@ class ChromeRendererPepperHostFactory : public ppapi::host::HostFactory { ~ChromeRendererPepperHostFactory() override; // HostFactory. - scoped_ptr CreateResourceHost( + std::unique_ptr CreateResourceHost( ppapi::host::PpapiHost* host, PP_Resource resource, PP_Instance instance, diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc index 66edd3f938ad..59046b328bfe 100644 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc @@ -205,7 +205,7 @@ int32_t PepperFlashRendererHost::OnDrawGlyphs( style |= SkTypeface::kBold; if (params.font_desc.italic) style |= SkTypeface::kItalic; - skia::RefPtr typeface = skia::AdoptRef(SkTypeface::CreateFromName( + sk_sp typeface(SkTypeface::CreateFromName( params.font_desc.face.c_str(), static_cast(style))); if (!typeface) return PP_ERROR_FAILED; @@ -255,7 +255,7 @@ int32_t PepperFlashRendererHost::OnDrawGlyphs( paint.setAntiAlias(true); paint.setHinting(SkPaint::kFull_Hinting); paint.setTextSize(SkIntToScalar(params.font_desc.size)); - paint.setTypeface(typeface.get()); // Takes a ref and manages lifetime. + paint.setTypeface(std::move(typeface)); if (params.allow_subpixel_aa) { paint.setSubpixelText(true); paint.setLCDRenderText(true); diff --git a/chromium_src/chrome/renderer/pepper/pepper_helper.cc b/chromium_src/chrome/renderer/pepper/pepper_helper.cc index a610a30dfff5..c9700c997137 100644 --- a/chromium_src/chrome/renderer/pepper/pepper_helper.cc +++ b/chromium_src/chrome/renderer/pepper/pepper_helper.cc @@ -18,9 +18,9 @@ void PepperHelper::DidCreatePepperPlugin(content::RendererPpapiHost* host) { // TODO(brettw) figure out how to hook up the host factory. It needs some // kind of filter-like system to allow dynamic additions. host->GetPpapiHost()->AddHostFactoryFilter( - scoped_ptr( + std::unique_ptr( new ChromeRendererPepperHostFactory(host))); host->GetPpapiHost()->AddInstanceMessageFilter( - scoped_ptr( + std::unique_ptr( new PepperSharedMemoryMessageFilter(host))); } diff --git a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc index 6fbadd121163..7c219f60b814 100644 --- a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc +++ b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc @@ -43,7 +43,7 @@ void PepperSharedMemoryMessageFilter::OnHostMsgCreateSharedMemory( ppapi::proxy::SerializedHandle* plugin_handle) { plugin_handle->set_null_shmem(); *host_handle_id = -1; - scoped_ptr shm( + std::unique_ptr shm( content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(size)); if (!shm.get()) return; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index eb3599198d98..7ff3471f953a 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -39,6 +39,7 @@ #include "third_party/WebKit/public/web/WebSettings.h" #include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/public/web/WebViewClient.h" +#include "third_party/skia/include/core/SkCanvas.h" #include "ui/base/resource/resource_bundle.h" using content::WebPreferences; @@ -62,9 +63,9 @@ int GetDPI(const PrintMsg_Print_Params* print_params) { bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) { return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() && !params.printable_area.IsEmpty() && params.document_cookie && - params.desired_dpi && params.max_shrink && params.min_shrink && - params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0) && - params.dpi > kMinDpi && params.document_cookie != 0; + params.desired_dpi && params.dpi && params.margin_top >= 0 && + params.margin_left >= 0 && params.dpi > kMinDpi && + params.document_cookie != 0; } PrintMsg_Print_Params GetCssPrintParams( @@ -425,8 +426,9 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, blink::WebLocalFrame* parent, blink::WebTreeScopeType scope, const blink::WebString& name, - blink::WebSandboxFlags sandboxFlags, - const blink::WebFrameOwnerProperties& frameOwnerProperties) override; + const blink::WebString& unique_name, + blink::WebSandboxFlags sandbox_flags, + const blink::WebFrameOwnerProperties& frame_owner_properties) override; void frameDetached(blink::WebFrame* frame, DetachType type) override; private: @@ -491,6 +493,7 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() { // think the page is 125% larger so the size of the page is correct for // minimum (default) scaling. // This is important for sites that try to fill the page. + // The 1.25 value is |printingMinimumShrinkFactor|. gfx::Size print_layout_size(web_print_params_.printContentArea.width, web_print_params_.printContentArea.height); print_layout_size.set_height( @@ -573,8 +576,9 @@ blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame( blink::WebLocalFrame* parent, blink::WebTreeScopeType scope, const blink::WebString& name, - blink::WebSandboxFlags sandboxFlags, - const blink::WebFrameOwnerProperties& frameOwnerProperties) { + const blink::WebString& unique_name, + blink::WebSandboxFlags sandbox_flags, + const blink::WebFrameOwnerProperties& frame_owner_properties) { blink::WebFrame* frame = blink::WebLocalFrame::create(scope, this); parent->appendChild(frame); return frame; @@ -1165,7 +1169,7 @@ bool PrintWebViewHelper::CopyMetafileDataToSharedMem( if (buf_size == 0) return false; - scoped_ptr shared_buf( + std::unique_ptr shared_buf( content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(buf_size)); if (!shared_buf) return false; @@ -1263,11 +1267,7 @@ bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument( } metafile_.reset(new PdfMetafileSkia); - if (!metafile_->Init()) { - set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED); - LOG(ERROR) << "PdfMetafileSkia Init failed"; - return false; - } + CHECK(metafile_->Init()); current_page_index_ = 0; pages_to_render_ = pages; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.h b/chromium_src/chrome/renderer/printing/print_web_view_helper.h index 05f145b5bb87..e3e644880974 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.h +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.h @@ -83,9 +83,9 @@ class PrintWebViewHelper PREVIEW_ERROR_NONE, // Always first. PREVIEW_ERROR_BAD_SETTING, PREVIEW_ERROR_METAFILE_COPY_FAILED, - PREVIEW_ERROR_METAFILE_INIT_FAILED, + PREVIEW_ERROR_METAFILE_INIT_FAILED_DEPRECATED, PREVIEW_ERROR_ZERO_PAGES, - PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED, + PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED_DEPRECATED, PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE, PREVIEW_ERROR_INVALID_PRINTER_SETTINGS, PREVIEW_ERROR_LAST_ENUM // Always last. @@ -244,10 +244,10 @@ class PrintWebViewHelper void SetPrintPagesParams(const PrintMsg_PrintPages_Params& settings); // WebView used only to print the selection. - scoped_ptr prep_frame_view_; + std::unique_ptr prep_frame_view_; bool reset_prep_frame_view_; - scoped_ptr print_pages_params_; + std::unique_ptr print_pages_params_; bool is_print_ready_metafile_sent_; bool ignore_css_margins_; @@ -343,8 +343,8 @@ class PrintWebViewHelper FrameReference source_frame_; blink::WebNode source_node_; - scoped_ptr prep_frame_view_; - scoped_ptr metafile_; + std::unique_ptr prep_frame_view_; + std::unique_ptr metafile_; // Total page count in the renderer. int total_page_count_; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc index d37aec628bab..608f406e623f 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc @@ -29,7 +29,7 @@ bool PrintWebViewHelper::RenderPreviewPage( PrintMsg_PrintPage_Params page_params; page_params.params = print_params; page_params.page_number = page_number; - scoped_ptr draft_metafile; + std::unique_ptr draft_metafile; PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { draft_metafile.reset(new PdfMetafileSkia); @@ -123,7 +123,7 @@ void PrintWebViewHelper::PrintPageInternal( &content_area); gfx::Rect canvas_area = content_area; - skia::PlatformCanvas* canvas = metafile->GetVectorCanvasForNewPage( + SkCanvas* canvas = metafile->GetVectorCanvasForNewPage( page_size, canvas_area, scale_factor); if (!canvas) return; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm index b10ba616a1f6..36ba4a597cdd 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm @@ -12,9 +12,9 @@ #include "chrome/common/print_messages.h" #include "printing/metafile_skia_wrapper.h" #include "printing/page_size_margins.h" -#include "skia/ext/platform_device.h" #include "third_party/WebKit/public/platform/WebCanvas.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/skia/include/core/SkCanvas.h" namespace printing { @@ -24,8 +24,7 @@ void PrintWebViewHelper::PrintPageInternal( const PrintMsg_PrintPage_Params& params, WebFrame* frame) { PdfMetafileSkia metafile; - if (!metafile.Init()) - return; + CHECK(metafile.Init()); int page_number = params.page_number; gfx::Size page_size_in_dpi; @@ -55,7 +54,7 @@ bool PrintWebViewHelper::RenderPreviewPage( int page_number, const PrintMsg_Print_Params& print_params) { PrintMsg_Print_Params printParams = print_params; - scoped_ptr draft_metafile; + std::unique_ptr draft_metafile; PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); bool render_to_draft = print_preview_context_.IsModifiable() && @@ -63,12 +62,7 @@ bool PrintWebViewHelper::RenderPreviewPage( if (render_to_draft) { draft_metafile.reset(new PdfMetafileSkia()); - if (!draft_metafile->Init()) { - print_preview_context_.set_error( - PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED); - LOG(ERROR) << "Draft PdfMetafileSkia Init failed"; - return false; - } + CHECK(draft_metafile->Init()); initial_render_metafile = draft_metafile.get(); } diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc index ce1e962505f1..7ff17a388bcc 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc @@ -27,7 +27,7 @@ bool PrintWebViewHelper::RenderPreviewPage( PrintMsg_PrintPage_Params page_params; page_params.params = print_params; page_params.page_number = page_number; - scoped_ptr draft_metafile; + std::unique_ptr draft_metafile; PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { draft_metafile.reset(new PdfMetafileSkia); @@ -158,7 +158,7 @@ void PrintWebViewHelper::PrintPageInternal( frame->getPrintPageShrink(params.page_number); float scale_factor = css_scale_factor * webkit_page_shrink_factor; - skia::PlatformCanvas* canvas = metafile->GetVectorCanvasForNewPage( + SkCanvas* canvas = metafile->GetVectorCanvasForNewPage( page_size, canvas_area, scale_factor); if (!canvas) return; diff --git a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc b/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc index a3b51a8c46e2..46465f4dfd4a 100644 --- a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc +++ b/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc @@ -322,7 +322,7 @@ bool SpellcheckWordIterator::Initialize( if (rule.empty()) return false; - scoped_ptr iterator( + std::unique_ptr iterator( new base::i18n::BreakIterator(base::string16(), rule)); if (!iterator->Init()) { // Since we're not passing in any text, the only reason this could fail diff --git a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h b/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h index 03fd8e666f5f..4490c7a90e8e 100644 --- a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h +++ b/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h @@ -167,7 +167,7 @@ class SpellcheckWordIterator { const SpellcheckCharAttribute* attribute_; // The break iterator. - scoped_ptr iterator_; + std::unique_ptr iterator_; DISALLOW_COPY_AND_ASSIGN(SpellcheckWordIterator); }; diff --git a/chromium_src/chrome/utility/printing_handler_win.cc b/chromium_src/chrome/utility/printing_handler_win.cc index b0bbac523671..105e574f7358 100644 --- a/chromium_src/chrome/utility/printing_handler_win.cc +++ b/chromium_src/chrome/utility/printing_handler_win.cc @@ -53,7 +53,7 @@ void PrintingHandlerWin::OnRenderPDFPagesToMetafile( const PdfRenderSettings& settings) { pdf_rendering_settings_ = settings; base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit); - int page_count = LoadPDF(pdf_file.Pass()); + int page_count = LoadPDF(std::move(pdf_file)); //int page_count = 1; Send( new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count)); @@ -65,7 +65,7 @@ void PrintingHandlerWin::OnRenderPDFPagesToMetafileGetPage( base::File emf_file = IPC::PlatformFileForTransitToFile(output_file); float scale_factor = 1.0f; bool success = - RenderPdfPageToMetafile(page_number, emf_file.Pass(), &scale_factor); + RenderPdfPageToMetafile(page_number, std::move(emf_file), &scale_factor); Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone( success, scale_factor)); } diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc b/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc index 6495b23b8409..2514c636cbee 100644 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc +++ b/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc @@ -27,7 +27,7 @@ #include "build/build_config.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" -#include "net/base/net_util.h" +#include "net/base/network_interfaces.h" #include "net/base/sockaddr_storage.h" #include "net/socket/socket_descriptor.h" diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.h b/chromium_src/net/test/embedded_test_server/stream_listen_socket.h index 9df512583063..7ad25437ec39 100644 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.h +++ b/chromium_src/net/test/embedded_test_server/stream_listen_socket.h @@ -58,7 +58,7 @@ class StreamListenSocket : // |server| is the original listening Socket, connection is the new // Socket that was created. virtual void DidAccept(StreamListenSocket* server, - scoped_ptr connection) = 0; + std::unique_ptr connection) = 0; virtual void DidRead(StreamListenSocket* connection, const char* data, int len) = 0; @@ -140,7 +140,7 @@ class StreamListenSocketFactory { virtual ~StreamListenSocketFactory() {} // Returns a new instance of StreamListenSocket or NULL if an error occurred. - virtual scoped_ptr CreateAndListen( + virtual std::unique_ptr CreateAndListen( StreamListenSocket::Delegate* delegate) const = 0; }; diff --git a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc index 1a72b2efe370..50aac809052e 100644 --- a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc +++ b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc @@ -22,7 +22,7 @@ #include "base/sys_byteorder.h" #include "base/threading/platform_thread.h" #include "build/build_config.h" -#include "net/base/net_util.h" +#include "net/base/network_interfaces.h" #include "net/base/winsock_init.h" #include "net/socket/socket_descriptor.h" @@ -33,14 +33,14 @@ namespace net { namespace test_server { // static -scoped_ptr TCPListenSocket::CreateAndListen( +std::unique_ptr TCPListenSocket::CreateAndListen( const string& ip, uint16_t port, StreamListenSocket::Delegate* del) { SocketDescriptor s = CreateAndBind(ip, port); if (s == kInvalidSocket) - return scoped_ptr(); - scoped_ptr sock(new TCPListenSocket(s, del)); + return std::unique_ptr(); + std::unique_ptr sock(new TCPListenSocket(s, del)); sock->Listen(); return sock; } @@ -108,7 +108,7 @@ void TCPListenSocket::Accept() { SocketDescriptor conn = AcceptSocket(); if (conn == kInvalidSocket) return; - scoped_ptr sock(new TCPListenSocket(conn, socket_delegate_)); + std::unique_ptr sock(new TCPListenSocket(conn, socket_delegate_)); #if defined(OS_POSIX) sock->WatchSocket(WAITING_READ); #endif diff --git a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h index 6990845f3928..db18fd0f0eb4 100644 --- a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h +++ b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h @@ -23,7 +23,7 @@ class TCPListenSocket : public StreamListenSocket { // Listen on port for the specified IP address. Use 127.0.0.1 to only // accept local connections. - static scoped_ptr CreateAndListen( + static std::unique_ptr CreateAndListen( const std::string& ip, uint16_t port, StreamListenSocket::Delegate* del); diff --git a/common.gypi b/common.gypi index 1088beb1b7b8..29fe70afc02c 100644 --- a/common.gypi +++ b/common.gypi @@ -49,6 +49,7 @@ 4054, # 4055, # 'type cast' : from data pointer 'void *' to function pointer 4057, # 'function' : 'volatile LONG *' differs in indirection to slightly different base types from 'unsigned long *' + 4065, # switch statement contains 'default' but no 'case' labels 4189, # 4131, # uses old-style declarator 4133, # incompatible types @@ -62,7 +63,12 @@ 4232, # address of dllimport 'free' is not static, identity not guaranteed 4291, # no matching operator delete found 4295, # array is too small to include a terminating null character + 4311, # 'type cast': pointer truncation from 'void *const ' to 'unsigned long' 4389, # '==' : signed/unsigned mismatch + 4456, # declaration of 'm' hides previous local declaration + 4457, # declaration of 'message' hides function parameter + 4459, # declaration of 'wq' hides global declaration + 4477, # format string '%.*s' requires an argument of type 'int' 4505, # unreferenced local function has been removed 4701, # potentially uninitialized local variable 'sizew' used 4703, # potentially uninitialized local pointer variable 'req' used @@ -124,36 +130,47 @@ }, }], ['OS=="win"', { + # Fix passing fd across modules, see |osfhandle.h| for more. + 'sources': [ + '<(DEPTH)/atom/node/osfhandle.cc', + '<(DEPTH)/atom/node/osfhandle.h', + ], + 'include_dirs': [ + '<(DEPTH)/atom/node', + ], + # Node is using networking API but linking with this itself. 'libraries': [ '-lwinmm.lib' ], + # Fix the linking error with icu. 'conditions': [ ['libchromiumcontent_component==0', { 'variables': { 'conditions': [ ['target_arch=="ia32"', { 'reference_symbols': [ - '_u_errorName_54', - '_ubidi_setPara_54', - '_ucsdet_getName_54', - '_uidna_openUTS46_54', - '_ulocdata_close_54', - '_unorm_normalize_54', - '_uregex_matches_54', - '_uscript_getCode_54', - '_usearch_setPattern_54', - '?createInstance@Transliterator@icu_54@@SAPAV12@ABVUnicodeString@2@W4UTransDirection@@AAW4UErrorCode@@@Z', + '_u_errorName_56', + '_ubidi_setPara_56', + '_ucsdet_getName_56', + '_uidna_openUTS46_56', + '_ulocdata_close_56', + '_unorm_normalize_56', + '_uregex_matches_56', + '_uscript_getCode_56', + '_uspoof_open_56', + '_usearch_setPattern_56', + '?createInstance@Transliterator@icu_56@@SAPAV12@ABVUnicodeString@2@W4UTransDirection@@AAW4UErrorCode@@@Z', ], }, { 'reference_symbols': [ - 'u_errorName_54', - 'ubidi_setPara_54', - 'ucsdet_getName_54', - 'uidna_openUTS46_54', - 'ulocdata_close_54', - 'unorm_normalize_54', - 'uregex_matches_54', - 'uscript_getCode_54', - 'usearch_setPattern_54', - '?createInstance@Transliterator@icu_54@@SAPEAV12@AEBVUnicodeString@2@W4UTransDirection@@AEAW4UErrorCode@@@Z', + 'u_errorName_56', + 'ubidi_setPara_56', + 'ucsdet_getName_56', + 'uidna_openUTS46_56', + 'ulocdata_close_56', + 'unorm_normalize_56', + 'uregex_matches_56', + 'uspoof_open_56', + 'usearch_setPattern_56', + '?createInstance@Transliterator@icu_56@@SAPEAV12@AEBVUnicodeString@2@W4UTransDirection@@AEAW4UErrorCode@@@Z', ], }], ], @@ -234,9 +251,12 @@ 4189, # local variable is initialized but not referenced 4201, # (uv.h) nameless struct/union 4267, # conversion from 'size_t' to 'int', possible loss of data + 4302, # (atldlgs.h) 'type cast': truncation from 'LPCTSTR' to 'WORD' + 4458, # (atldlgs.h) declaration of 'dwCommonButtons' hides class member 4503, # decorated name length exceeded, name was truncated 4800, # (v8.h) forcing value to bool 'true' or 'false' 4819, # The file contains a character that cannot be represented in the current code page + 4838, # (atlgdi.h) conversion from 'int' to 'UINT' requires a narrowing conversion 4996, # (atlapp.h) 'GetVersionExW': was declared deprecated ], }, diff --git a/default_app/default_app.js b/default_app/default_app.js index 5f5b2c800316..a72675ea6fdc 100644 --- a/default_app/default_app.js +++ b/default_app/default_app.js @@ -1,16 +1,14 @@ -const electron = require('electron') -const app = electron.app -const BrowserWindow = electron.BrowserWindow +const {app, BrowserWindow} = require('electron') var mainWindow = null // Quit when all windows are closed. -app.on('window-all-closed', function () { +app.on('window-all-closed', () => { app.quit() }) -exports.load = function (appUrl) { - app.on('ready', function () { +exports.load = (appUrl) => { + app.on('ready', () => { mainWindow = new BrowserWindow({ width: 800, height: 600, diff --git a/default_app/index.html b/default_app/index.html index c10d67a089ac..edfb3e6ddc92 100644 --- a/default_app/index.html +++ b/default_app/index.html @@ -4,16 +4,21 @@ +``` + +## Tag 属性 + +`webview`タグは下記のような属性を持っています: + +### `src` + +```html + +``` + +表示されているURLを返します。本属性への書き込みは、トップレベルナビゲーションを開始させます。 + +`src`の値を現在の値に再度設定することで、現在のページを再読み込みさせることができます。 + +また、`src`属性はdata URLを指定することができます(例: `data:text/plain,Hello, world!`)。 + +### `autosize` + +```html + +``` + +"on"の際は、`minwidth`, `minheight`, `maxwidth`, `maxheight`で設定された範囲内で、自動的に大きさが変化します。 +これらの制限値は、`autosize`が有効でない場合は影響しません。 +`autosize`が有効の際は、`webview`コンテナサイズは指定した最小値より小さくなりませんし、最大値より大きくなりません。 + +### `nodeintegration` + +```html + +``` + +"on"の際は、`webview`内のゲストページ(外部コンテンツ)でnode integrationが有効となり、`require`や`process`と行ったnode APIでシステムリソースにアクセスできるようになります。1 + +**注意:** 親ウィンドウでnode integrationが無効の場合は、`webview`でも常に無効になります。 + + +### `plugins` + +```html + +``` + +"on"の際は、ゲストページはブラウザプラグインを使用できます。 + +### `preload` + +```html + +``` + +ゲストページ上のスクリプトより先に実行されるスクリプトを指定してください。内部では、ゲストページ内で`require`で読み込まれるので、スクリプトのURLのプロトコルはは`file:`または`asar:`でなければなりません。 + +ゲストページがnode integrationが無効の場合でも、このスクリプトは全てのNode APIにアクセスできます。ただし、グローバルオブジェクトはこのスクリプトの実行終了後にすべて削除されます。 + +### `httpreferrer` + +```html + +``` + +ゲストページのためにリファラを設定します。 + +### `useragent` + +```html + +``` + +ページ遷移の前に、User agentを指定します。すでにページが読み込まれている場合は、`setUserAgent`メソッドを利用して変更してください。 + +### `disablewebsecurity` + +```html + +``` + +"on"の際は、ゲストページのウェブセキュリティは無効となります。 + +### `partition` + +```html + + +``` + +ページで使用されるセッションを設定します。もし、`partition`が`persist:`から始まる場合、アプリ上の同じ`partition`を指定した全てのページで有効な永続セッションを使用します。 +`persist:`接頭辞なしで指定した場合、メモリ内セッションを使用します。同じセッションを指定すると複数のページで同じセッションを使用できます。 +`partition`を設定しない場合は、アプリケーションのデフォルトセッションが使用されます。 + +レンダラプロセスのセッションは変更できないため、この値は最初のページ遷移の前に変更されないといけません。 +その後に変更をしようとしても、DOM例外を起こすことになります。 + +### `allowpopups` + +```html + +``` + +"on"の場合、ゲストページは新しいウィンドウを開くことができます。 + +### `blinkfeatures` + +```html + +``` + +有効にしたいblink featureを`,`で区切って指定します。 +サポートされている全ての機能は、[setFeatureEnabledFromString][blink-feature-string]にリストがあります。 + +## メソッド + +`webview`タグは、下記のようなメソッドを持っています: + +**注意:** webview要素はメソッドを使用する前に読み込まれていないといけません。 + +**例** + +```javascript +webview.addEventListener('dom-ready', () => { + webview.openDevTools(); +}); +``` + +### `.loadURL(url[, options])` + +* `url` URL +* `options` Object (optional) + * `httpReferrer` String - リファラURL + * `userAgent` String - リクエストに使用されるUser agent + * `extraHeaders` String - 追加のヘッダを"\n"で区切って指定します。 + +`url`をwebviewで読み込みます。`url`はプロトコル接頭辞(`http://`や`file://`など)を含んでいなければいけません。 + +### `.getURL()` + +ゲストページのURLを取得します。 + +### `.getTitle()` + +ゲストページのタイトルを返します。 + +### `.isLoading()` + +ゲストページが読み込み中かのbool値を返します。 + +### `.isWaitingForResponse()` + +ゲストページがページの最初の返答を待っているかのbool値を返します。 + +### `.stop()` + +実行待ち中のナビゲーションを中止します。 + +### `.reload()` + +ゲストページを再読み込みします。 + +### `.reloadIgnoringCache()` + +キャッシュを無効にして再読み込みします。 + +### `.canGoBack()` + +ページを戻ることができるかのbool値を返します。 + +### `.canGoForward()` + +ページを進むことができるかのbool値を返します。 + +### `.canGoToOffset(offset)` + +* `offset` Integer + +`offset`だけ、移動できるかのbool値を返します。 + +### `.clearHistory()` + +移動履歴をクリアします。 + +### `.goBack()` + +ページを戻ります。 + +### `.goForward()` + +ページを進みます。 + +### `.goToIndex(index)` + +* `index` Integer + +インデックスを指定して移動します。 + +### `.goToOffset(offset)` + +* `offset` Integer + +現在の場所からの移動量を指定して移動します。 + +### `.isCrashed()` + +レンダラプロセスがクラッシュしているかを返します。 + +### `.setUserAgent(userAgent)` + +* `userAgent` String + +ゲストページ用のUser agentを変更します。 + +### `.getUserAgent()` + +User agentを取得します。 + +### `.insertCSS(css)` + +* `css` String + +ゲストエージにCSSを追加します。 + +### `.executeJavaScript(code, userGesture, callback)` + +* `code` String +* `userGesture` Boolean - Default `false`. +* `callback` Function (optional) - Called after script has been executed. + * `result` + +ページ内で`code`を評価します。`userGesture`を設定した場合、ページ内でgesture contextを作成します。例えば`requestFullScreen`のようなユーザーの対応が必要なHTML APIでは、自動化時にこれが有利になる時があります。 + +### `.openDevTools()` + +DevToolsを開きます。 + +### `.closeDevTools()` + +DevToolsを閉じます。 + +### `.isDevToolsOpened()` + +DevToolsが開いているかのbool値を返します。 + +### `.isDevToolsFocused()` + +DevToolsがフォーカスを得ているかのbool値を返します。 + +### `.inspectElement(x, y)` + +* `x` Integer +* `y` Integer + +ゲストページの(`x`, `y`)の位置にある要素を調べます。 + +### `.inspectServiceWorker()` + +ゲストページのサービスワーカーのDevToolsを開きます。 + +### `.setAudioMuted(muted)` + +* `muted` Boolean + +ページをミュートするかを設定します。 + +### `.isAudioMuted()` + +ページがミュートされているかを返します。 + +### `.undo()` + +`undo` (元に戻す)を行います。 +Executes editing command `undo` in page. + +### `.redo()` + +`redo` (やり直し)を行います。 + +### `.cut()` + +`cut` (切り取り)を行います。 + +### `.copy()` + +`copy` (コピー)を行います。 + +### `.paste()` + +`paste` (貼り付け)を行います。 + +### `.pasteAndMatchStyle()` + +`pasteAndMatchStyle`(貼り付けてスタイルを合わせる)を行います。 + +### `.delete()` + +`delete` (削除)を行います。 + +### `.selectAll()` + +`selectAll` (全て選択)を行います。 + +### `.unselect()` + +`unselect` (選択を解除)を行います。 + +### `.replace(text)` + +* `text` String + +`replace` (置き換え)を行います。 + +### `.replaceMisspelling(text)` + +* `text` String + +`replaceMisspelling` (スペル違いを置き換え)を行います。 + +### `.insertText(text)` + +* `text` String + +`text`を選択された要素に挿入します。 + +### `.findInPage(text[, options])` + +* `text` String - 検索する文字列(空文字列にはできません) +* `options` Object (省略可) + * `forward` Boolean - 前方・後方のどちらを検索するかどうかです。省略時は`true`で前方に検索します。 + * `findNext` Boolean - 初回検索か、次を検索するかを選びます。省略時は`false`で、初回検索です。 + * `matchCase` Boolean - 大文字・小文字を区別するかを指定します。省略時は`false`で、区別しません。 + * `wordStart` Boolean - ワード始まりからの検索かを指定します。省略時は`false`で、語途中でもマッチします。 + * `medialCapitalAsWordStart` Boolean - `wordStart`指定時、CamelCaseの途中もワード始まりと見なすかを指定します。省略時は`false`です。 + +`text`をページ内全てから検索し、リクエストに使用するリクエストID(`Integer`)を返します。リクエストの結果は、[`found-in-page`](web-view-tag.md#event-found-in-page)イベントを介して受け取ることができます。 + +### `.stopFindInPage(action)` + +* `action` String - [`.findInPage`](web-view-tag.md#webviewtagfindinpage)リクエストを終わらせる時にとるアクションを指定します。 + * `clearSelection` - 選択をクリアします。 + * `keepSelection` - 選択を通常の選択へと変換します。 + * `activateSelection` - 選択ノードにフォーカスを当て、クリックします。 + +`action`にしたがって`webview`への`findInPage`リクエストを中止します。 + +### `.print([options])` + +`webview`で表示されているウェブページを印刷します。`webContents.print([options])`と同じです。 + +### `.printToPDF(options, callback)` + +`webview`のウェブサイトをPDFとして印刷します。`webContents.printToPDF(options, callback)`と同じです。 + +### `.send(channel[, arg1][, arg2][, ...])` + +* `channel` String +* `arg` (optional) + +`channel`を通じてレンダラプロセスに非同期メッセージを送ります。合わせて、 +任意のメッセージを送ることができます。レンダラプロセスは`ipcRenderer`モジュールを +使用して、`channel`イベントでメッセージを把握することができます。 + +サンプルが[webContents.send](web-contents.md#webcontentssendchannel-args)にあります。 + +### `.sendInputEvent(event)` + +* `event` Object + +入力イベント(`event`)をページに送ります。 + +`event`に関する詳しい説明は、[webContents.sendInputEvent](web-contents.md##webcontentssendinputeventevent)を +参照してください。 + +### `.getWebContents()` + +`webview`に関連付けられた[WebContents](web-contents.md)を取得します。 + +## DOM events + +`webview`タグで有効なイベントは次の通りです: + +### Event: 'load-commit' + +返り値: + +* `url` String +* `isMainFrame` Boolean + +読み込みが行われる時に発生するイベントです。 +これには、現在のドキュメントやサブフレームの読み込みが含まれます。ただし、非同期なリソース読み込みは含まれません。 + +### Event: 'did-finish-load' + +ナビゲーションが完了した際に発生するイベントです。 +言い換えると、タブ上の"くるくる"が止まった時に発生し、`onload`イベントが配信されます。 + +### Event: 'did-fail-load' + +返り値: + +* `errorCode` Integer +* `errorDescription` String +* `validatedURL` String +* `isMainFrame` Boolean + +`did-finish-load`と同じようですが、読み込みに失敗した時やキャンセルされた時に発生します。 +例えば、`window.stop()`が呼ばれた時などです。 + +### Event: 'did-frame-finish-load' + +返り値: + +* `isMainFrame` Boolean + +フレームがナビゲーションを終えた時に発生します。 + +### Event: 'did-start-loading' + +タブ上の"くるくる"が回転を始めた時点でこのイベントが発生します。 + +### Event: 'did-stop-loading' + +タブ上の"くるくる"が回転をやめた時点でこのイベントが発生します。 + +### Event: 'did-get-response-details' + +返り値: + +* `status` Boolean +* `newURL` String +* `originalURL` String +* `httpResponseCode` Integer +* `requestMethod` String +* `referrer` String +* `headers` Object +* `resourceType` String + +読み込むリソースの詳細がわかった時点で発生します。 +`status`は、リソースをダウンロードするソケット接続であるかを示します。 + +### Event: 'did-get-redirect-request' + +返り値: + +* `oldURL` String +* `newURL` String +* `isMainFrame` Boolean + +リソースの取得中に、リダイレクトを受け取った際に発生します。 + +### Event: 'dom-ready' + +該当フレーム内のドキュメントが読み込まれた時に発生します。 + +### Event: 'page-title-updated' + +返り値: + +* `title` String +* `explicitSet` Boolean + +ページのタイトルが設定された時に発生します。 +タイトルがurlから作られたものであれば、`explicitSet`は`false`になります。 + +### Event: 'page-favicon-updated' + +返り値: + +* `favicons` Array - URLの配列 + +ページのfavicon URLを受け取った時に発生します。 + +### Event: 'enter-html-full-screen' + +HTML APIでフルスクリーンになった際に発生します。 + +### Event: 'leave-html-full-screen' + +HTML APIでフルスクリーンでなくなった際に発生します。 + +### Event: 'console-message' + +返り値: + +* `level` Integer +* `message` String +* `line` Integer +* `sourceId` String + +ゲストウィンドウがコンソールメッセージを記録する際に発生します。 + +下記のサンプルは、埋め込まれたサイトのログを、log levelに関係なく親側に転送します。 + + +```javascript +webview.addEventListener('console-message', (e) => { + console.log('Guest page logged a message:', e.message); +}); +``` + +### Event: 'found-in-page' + +返り値: + +* `result` Object + * `requestId` Integer + * `finalUpdate` Boolean - 次のレスポンスが待っているかを示します。 + * `activeMatchOrdinal` Integer (optional) - このマッチの場所を示します。 + * `matches` Integer (optional) - マッチした数です。 + * `selectionArea` Object (optional) - 最初のマッチした場所です。 + +[`webview.findInPage`](web-view-tag.md#webviewtagfindinpage)リクエストで結果が得られた場合に発生します。 + +```javascript +webview.addEventListener('found-in-page', (e) => { + if (e.result.finalUpdate) + webview.stopFindInPage('keepSelection'); +}); + +const requestId = webview.findInPage('test'); +``` + +### Event: 'new-window' + +返り値: + +* `url` String +* `frameName` String +* `disposition` String -`default`, `foreground-tab`, `background-tab`, + `new-window`, `other`のどれかです。 +* `options` Object - 新しい`BrowserWindow`を作る際に使用されるoptionです。 + +ゲストページが新しいブラウザウィンドウを開こうとする際に発生します。 + +下記のサンプルは、新しいURLをシステムのデフォルトブラウザで開きます。 + +```javascript +const {shell} = require('electron'); + +webview.addEventListener('new-window', (e) => { + const protocol = require('url').parse(e.url).protocol; + if (protocol === 'http:' || protocol === 'https:') { + shell.openExternal(e.url); + } +}); +``` + +### Event: 'will-navigate' + +返り値: + +* `url` String + +ユーザーまたはページがナビゲーションを始めようとする際に発生します。これは、 +`window.location`が変更になる時や、ユーザーがリンクをクリックした際に発生します。 + +`.loadURL`や`.back`でプログラムによりナビゲーションが始まった場合は +このイベントは発生しません。 + +アンカーリンクのクリックや`window.location.hash`の変更といった、ページ内遷移でも、このイベントは発生しません。 +この場合は、`did-navigate-in-page`イベントを使ってください。 + +`event.preventDefault()`は使用しても__何も起こりません__。 + +### Event: 'did-navigate' + +返り値: + +* `url` String + +ナビゲーション終了時に呼ばれます。 + +アンカーリンクのクリックや`window.location.hash`の変更といった、ページ内遷移では、このイベントは発生しません。 +この場合は、`did-navigate-in-page`イベントを使ってください。 + +### Event: 'did-navigate-in-page' + +返り値: + +* `url` String + +ページ内遷移の際に発生します。 + +ページ内遷移の際は、ページURLは変更になりますが、ページ外部へのナビゲーションは発生しません。 +例として、アンカーリンクのクリック時や、DOMの`hashchange`イベントが発生した時にこれが起こります。 + +### Event: 'close' + +ゲストページそのものが、閉じられようとしている際に発生します。 + +下記のサンプルは、`webview`が閉じられる際に、`about:blank`にナビゲートします。 + +```javascript +webview.addEventListener('close', () => { + webview.src = 'about:blank'; +}); +``` + +### Event: 'ipc-message' + +返り値: + +* `channel` String +* `args` Array + +ゲストページが埋め込み元に非同期メッセージを送ってきた際に発生します。 + +`sendToHost`メソッドと、`ipc-message`イベントを利用すると、ゲストページと埋め込み元のページでデータのやり取りを簡単に行うことができます。 + +```javascript +// 埋め込み元ページ(があるページ)で +webview.addEventListener('ipc-message', (event) => { + console.log(event.channel); + // Prints "pong" +}); +webview.send('ping'); +``` + +```javascript +// ゲストページ(内)で +const {ipcRenderer} = require('electron'); +ipcRenderer.on('ping', () => { + ipcRenderer.sendToHost('pong'); +}); +``` + +### Event: 'crashed' + +プロセスがクラッシュした際に発生します。 + +### Event: 'gpu-crashed' + +GPUプロセスがクラッシュした際に発生します。 + +### Event: 'plugin-crashed' + +返り値: + +* `name` String +* `version` String + +プラグインプロセスがクラッシュした際に発生します。 + +### Event: 'destroyed' + +WebContentsが破壊された際に呼ばれます。 + +### Event: 'media-started-playing' + +メディアの再生が開始された際に呼ばれます。 + +### Event: 'media-paused' + +メディアが一時停止になるか、再生を終えた際に呼ばれます。 + +### Event: 'did-change-theme-color' + +返り値: + +* `themeColor` String + +ページのテーマカラーが変更になった際に呼ばれます。 +これは、下記のようなメタタグがある際に通常発生します: + +```html + +``` + +### Event: 'devtools-opened' + +DevToolsが開かれた際に発生します。 + +### Event: 'devtools-closed' + +DevToolsが閉じられた際に発生します。 + +### Event: 'devtools-focused' + +DevToolsにフォーカスが当たった際 / 開かれた際に発生します。 + +[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 diff --git a/docs-translations/jp/faq/electron-faq.md b/docs-translations/jp/faq/electron-faq.md index eef30c013a3f..3991b71953cd 100644 --- a/docs-translations/jp/faq/electron-faq.md +++ b/docs-translations/jp/faq/electron-faq.md @@ -2,10 +2,12 @@ ## Electronは、いつ最新のChromeにアップグレードされますか? -ElectronのChromeバージョンは、通常、新しいChromeのstabeleバージョンがリリースされた後、1~2週間以内に上げられます。 +ElectronのChromeバージョンは、通常、新しいChromeのstabeleバージョンがリリースされた後、1~2週間以内に上げられます。ただし、この期間というのは保障されてはおらず、またバージョンアップでの作業量に左右されます。 また、Chromeのstableチャンネルのみを使用し、もし、重要な修正がbetaまたはdevチャンネルにある場合、それをバックポートします。 +もっと知りたければ、[セキュリティについて](../tutorial/security.md)をご参照ください。 + ## Electronは、いつ最新のNode.jsにアップグレードされますか? Node.js の新しいバージョンがリリースされたとき、私たちは Electron の Node.js を更新するのを通常約1か月待ちます。そのようにして、とても頻繁に発生している、新しい Node.js バージョンによって取り込まれたバグによる影響を避けることができます。 @@ -69,7 +71,7 @@ Electronに組み込まれているNode.jsの影響で, `module`, `exports`, `re ```javascript // In the main process. -var mainWindow = new BrowserWindow({ +var win = new BrowserWindow({ webPreferences: { nodeIntegration: false } @@ -113,7 +115,7 @@ console.log(require.resolve('electron')); "/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js" ``` -If it is something like もし、`node_modules/electron/index.js` のような形式の場合は、npm `electron` モジュールを削除するか、それをリネームします。 +もし、`node_modules/electron/index.js` のような形式の場合は、npm `electron` モジュールを削除するか、それをリネームします。 ```bash npm uninstall electron diff --git a/docs-translations/jp/tutorial/application-distribution.md b/docs-translations/jp/tutorial/application-distribution.md index f05b098514b9..19cc42979e13 100644 --- a/docs-translations/jp/tutorial/application-distribution.md +++ b/docs-translations/jp/tutorial/application-distribution.md @@ -25,7 +25,7 @@ electron/resources/app ## ファイルにアプリケーションをパッケージングする -すべてのソースコードをコピーすることでアプリケーションを提供する方法とは別に、アプリケーションのソースコードをユーザーに見えるのを避けるために、[asar](https://github.com/atom/asar) にアーカイブしてアプリケーションをパッケージ化することができます。 +すべてのソースコードをコピーすることでアプリケーションを提供する方法とは別に、アプリケーションのソースコードをユーザーに見えるのを避けるために、[asar](https://github.com/electron/asar) にアーカイブしてアプリケーションをパッケージ化することができます。 `app` フォルダの代わりに `asar` アーカイブを使用するためには、アーカイブファイルを `app.asar` という名前に変更し、Electron のリソースディレクトリに以下のように配置する必要があります。すると、Electron はアーカイブを読み込もうとし、それを開始します。 diff --git a/docs-translations/jp/tutorial/application-packaging.md b/docs-translations/jp/tutorial/application-packaging.md index e5196a6f6262..79b807d3111e 100644 --- a/docs-translations/jp/tutorial/application-packaging.md +++ b/docs-translations/jp/tutorial/application-packaging.md @@ -63,8 +63,8 @@ require('/path/to/example.asar/dir/module.js'); `BrowserWindow` を使って `asar` アーカイブ内の Web ページを表示することもできます: ```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({width: 800, height: 600}); +const {BrowserWindow} = require('electron'); +let win = new BrowserWindow({width: 800, height: 600}); win.loadURL('file:///path/to/example.asar/static/index.html'); ``` @@ -78,7 +78,7 @@ Node API と同様、`asar` アーカイブはディレクトリのように扱 ```html @@ -89,7 +89,7 @@ $.get('file:///path/to/example.asar/file.txt', function(data) { アーカイブのチェックサムを検証する等の幾つかのケースでは、`asar` アーカイブをファイルとして読み込む必要があります。この目的のために、 `asar` サポートしないオリジナルの `fs` API を提供するビルトインの `original-fs` モジュールを使用できます。 ```javascript -var originalFs = require('original-fs'); +const originalFs = require('original-fs'); originalFs.readFileSync('/path/to/example.asar'); ``` @@ -146,4 +146,4 @@ $ asar pack app app.asar --unpack *.node このコマンドを実行した後、`app.asar` とは別に、アンパックされたファイルを含んだ`app.asar.unpacked` フォルダーが生成されます。ユーザーに提供するときには、`app.asar` と一緒にコピーしなければなりません。 -[asar]: https://github.com/atom/asar +[asar]: https://github.com/electron/asar diff --git a/docs-translations/jp/tutorial/desktop-environment-integration.md b/docs-translations/jp/tutorial/desktop-environment-integration.md index 96bf76d73709..6cd838afa7d7 100644 --- a/docs-translations/jp/tutorial/desktop-environment-integration.md +++ b/docs-translations/jp/tutorial/desktop-environment-integration.md @@ -8,14 +8,17 @@ 3つのオペレーティングシステム全てで、アプリケーションからユーザーに通知を送る手段が提供されています。通知を表示するためにオペレーティングシステムのネイティブ通知APIを使用しする[HTML5 Notification API](https://notifications.spec.whatwg.org/)で、Electronは、開発者に通知を送ることができます。 +**注意:** これはHTML5 APIですので、レンダラプロセス内のみで有効です。 + + ```javascript -var myNotification = new Notification('Title', { +let myNotification = new Notification('Title', { body: 'Lorem Ipsum Dolor Sit Amet' }); -myNotification.onclick = function () { - console.log('Notification clicked') -} +myNotification.onclick = () => { + console.log('Notification clicked'); +}; ``` オペレーティングシステム間でコードとユーザ体験は似ていますが、細かい違いがあります。 @@ -88,8 +91,8 @@ const electron = require('electron'); const app = electron.app; const Menu = electron.Menu; -var dockMenu = Menu.buildFromTemplate([ - { label: 'New Window', click: function() { console.log('New Window'); } }, +const dockMenu = Menu.buildFromTemplate([ + { label: 'New Window', click() { console.log('New Window'); } }, { label: 'New Window with Settings', submenu: [ { label: 'Basic' }, { label: 'Pro'} @@ -153,24 +156,24 @@ __Windows Media Playerの縮小表示ツールバー:__ アプリケーションに縮小表示ツールバーを設定するために、[BrowserWindow.setThumbarButtons][setthumbarbuttons]を使えます: ```javascript -const BrowserWindow = require('electron').BrowserWindow; +const {BrowserWindow} = require('electron'); const path = require('path'); -var win = new BrowserWindow({ +let win = new BrowserWindow({ width: 800, height: 600 }); win.setThumbarButtons([ { - tooltip: "button1", + tooltip: 'button1', icon: path.join(__dirname, 'button1.png'), - click: function() { console.log("button2 clicked"); } + click() { console.log("button2 clicked"); } }, { - tooltip: "button2", + tooltip: 'button2', icon: path.join(__dirname, 'button2.png'), - flags:['enabled', 'dismissonclick'], - click: function() { console.log("button2 clicked."); } + flags: ['enabled', 'dismissonclick'], + click() { console.log("button2 clicked."); } } ]); ``` @@ -189,25 +192,22 @@ __Audaciousのランチャーショートカット:__ ![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) -## タスクバーの進行状況バー (Windows & Unity) +## タスクバーの進行状況バー (Windows, OS X, Unity) Windowsでは、タスクバーボタンは、進行状況バーを表示するのに使えます。ウィンドウを切り替えることなくウィンドウの進行状況情報をユーザーに提供することができます。 +OS Xではプログレスバーはドックアイコンの一部として表示されます。 Unity DEは、ランチャーに進行状況バーの表示をするのと同様の機能を持っています。 __タスクバーボタン上の進行状況バー:__ ![Taskbar Progress Bar](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) -__Unityランチャーでの進行状況バー:__ - -![Unity Launcher](https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png) - ウィンドウに進行状況バーを設定するために、[BrowserWindow.setProgressBar][setprogressbar] APIを使えます: ```javascript -var window = new BrowserWindow({...}); -window.setProgressBar(0.5); +let win = new BrowserWindow({...}); +win.setProgressBar(0.5); ``` ## タスクバーでアイコンをオーバーレイする (Windows) @@ -223,8 +223,8 @@ __タスクバーボタンでのオーバーレイ:__ ウィンドウでオーバーレイアイコンを設定するために、[BrowserWindow.setOverlayIcon][setoverlayicon] APIを使用できます。 ```javascript -var window = new BrowserWindow({...}); -window.setOverlayIcon('path/to/overlay.png', 'Description for overlay'); +let win = new BrowserWindow({...}); +win.setOverlayIcon('path/to/overlay.png', 'Description for overlay'); ``` ## Windowのファイル表示 (OS X) @@ -240,9 +240,9 @@ __Represented file ポップアップメニュー:__ ウィンドウにrepresented fileを設定するために、[BrowserWindow.setRepresentedFilename][setrepresentedfilename] と [BrowserWindow.setDocumentEdited][setdocumentedited] APIsを使えます: ```javascript -var window = new BrowserWindow({...}); -window.setRepresentedFilename('/etc/passwd'); -window.setDocumentEdited(true); +let win = new BrowserWindow({...}); +win.setRepresentedFilename('/etc/passwd'); +win.setDocumentEdited(true); ``` [addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows diff --git a/docs-translations/jp/tutorial/devtools-extension.md b/docs-translations/jp/tutorial/devtools-extension.md index 2c8816a666f8..b631b4e406e9 100644 --- a/docs-translations/jp/tutorial/devtools-extension.md +++ b/docs-translations/jp/tutorial/devtools-extension.md @@ -4,7 +4,7 @@ DevToolsエクステンションのために、ソースコードをダウンローし、`BrowserWindow.addDevToolsExtension` APIを使って読み込みます。読み込んだエクステンションは維持されているので、ウィンドウを作成するとき、毎回APIをコールする必要はありません。 -** NOTE: React DevTools は動作しません。issue https://github.com/electron/electron/issues/915 でフォローしています** +** NOTE: React DevTools は動作しません。issue https://github.com/electron/electron/issues/915 をご覧ください ** 例えば、[React DevTools Extension](https://github.com/facebook/react-devtools)を使うために、最初にソースコードをダウンロードする必要があります。 @@ -22,7 +22,7 @@ const BrowserWindow = require('electron').remote.BrowserWindow; BrowserWindow.addDevToolsExtension('/some-directory/react-devtools/shells/chrome'); ``` -エクステンションをアンロードするために、名前と`BrowserWindow.removeDevToolsExtension` APIをコールすると、次回DevToolsを開いた時にはロードされません。 +エクステンションをアンロードするために、`BrowserWindow.removeDevToolsExtension` APIを名前を指定してコールすると、次回DevToolsを開いた時にはロードされません。 ```javascript BrowserWindow.removeDevToolsExtension('React Developer Tools'); @@ -34,12 +34,12 @@ BrowserWindow.removeDevToolsExtension('React Developer Tools'); ## バックグラウンドページ -今のところ、ElectronはChromエクステンションのバックグラウンドページ機能に対応していません。そのため、Electronでは、この機能に依存するDevToolsエクステンションは動作しません。 +今のところ、ElectronはChromeエクステンションのバックグラウンドページ機能に対応していません。そのため、Electronでは、この機能に依存するDevToolsエクステンションは動作しません。 ## `chrome.*` APIs いくつかのChromeエクステンションは、`chrome.*` APIsを使用しており、ElectronでそれらのAPIを実装するための努力をしていますが、すべては実装されていません。 -すべては実装されていない`chrome.*` APIについて考えると、もしDevToolsエクステンションが `chrome.devtools.*` 以外のAPIを使用していると、エクステンションは動作しない可能性が非常に高いです。 +すべては実装されていない`chrome.*` APIについて考えると、もしDevToolsエクステンションが `chrome.devtools.*` 以外のAPIを使用していると、エクステンションは動作しない可能性が非常に高いです。うまく動作しないエクステンションがあれば、APIのサポートの追加のために、issue trackerへご報告ください。 [devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/jp/tutorial/electron-versioning.md b/docs-translations/jp/tutorial/electron-versioning.md new file mode 100644 index 000000000000..e8fc8b64c5f8 --- /dev/null +++ b/docs-translations/jp/tutorial/electron-versioning.md @@ -0,0 +1,11 @@ +# Electronのバージョン管理 + +もしあなたが経験豊富なNodeプログラマなら、`semver`(セマンティックバージョニング)のことはご存知でしょうし、バージョン番号をきっちり固定するのではなく、大まかな指針をパッケージの依存管理システムに指定していることと思います。ElectronはNodeとChromiumに強く依存しているので、少し難しい位置付けにあってsemverにきっちり従っていません。そのため、いつでも特定バージョンのElectronを参照しないといけません。 + +バージョン番号は次のルールに沿ってあげられます。 + + * メジャーバージョン: ElectronのAPIに大きな変更があった時- 例えば、`0.37.0`から`1.0.0`にアップグレードした時は、あなたはアプリケーションのアップデートをしなければなりません。 + * マイナーバージョン: ChromeのメジャーバージョンまたはNodeのマイナーバージョンのアップデート、またはElectronの重大な変更 - 例えば`1.0.0`から`1.1.0`にアップグレードした時は、あなたのアプリは多分動きますが、もしかしたら少々の変更をしないといけないかもしれません。 + * パッチ: 新しい機能やバグフィックス - `1.0.0`から`1.0.1`へのアップグレードでは、あなたのアプリはそのまま動くはずです。 + +もし、`electron-prebuilt`を使用しているのであれば、Electronのすべてのアップデートが開発者であるあなたによって手動で行われることを保証するために、固定バージョンを指定(`^1.1.0`ではなく`1.1.0`)することをお勧めします。 diff --git a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md index c4bbf0706eba..fd42d55937d9 100644 --- a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md +++ b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md @@ -2,13 +2,11 @@ v0.34.0から、ElectronはMac App Store (MAS)にパッケージ化したアプリを登録することができます。このガイドでは、MASビルド用の制限とアプリを登録する方法についての情報を提供します。 -__Note:__ v0.36.0から、アプリがサンドボックス化された後GPUプロセスを妨害するバグがあるので、このバグが修正されるまでは、v0.35.xを使用することを推奨します。[issue #3871][issue-3871]で、このことに関する追加情報を確認できます。 - __Note:__ Mac App Storeにアプリを登録するには、費用が発生する[Apple Developer Program][developer-program]に登録する必要があります。 ## アプリを登録する方法 -次の手順は、Mac App Sotreにアプリを登録する簡単な手順を説明します。しかし、これらの手順はAppleによってAppが承認されることを保証するものではありません。Mac App Storeの要件については、Appleの[Submitting Your App][submitting-your-app]ガイドを読んでおく必要があります。 +次の手順は、Mac App Storeにアプリを登録する簡単な手順を説明します。しかし、これらの手順はAppleによってAppが承認されることを保証するものではありません。Mac App Storeの要件については、Appleの[Submitting Your App][submitting-your-app]ガイドを読んでおく必要があります。 ### 証明書の取得 @@ -44,11 +42,16 @@ Appleから証明書を取得した後、[Application Distribution](application- com.apple.security.app-sandbox + com.apple.security.application-groups + + your.bundle.id + ``` -次のスクリプトでアプリをサインします。 +_`your.bundle.id`は`Info.plist`で指定されているあなたのアプリのBundle IDに置き換えてください。_ +そして、次のスクリプトでアプリを署名します。 ```bash #!/bin/bash @@ -65,26 +68,31 @@ INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" -if [ -d "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" ]; then - # Signing a non-MAS build. - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Mantle.framework/Versions/A" - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/ReactiveCocoa.framework/Versions/A" - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" -fi -codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$APP_PATH/Contents/MacOS/$APP" +codesign -s "$APP_KEY" -f --entitlements parent.plist "$APP_PATH" productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" ``` -OS Xで、サンドボックスにアプリを新しく追加した場合、基本的な考え方は、Appleの[Enabling App Sandbox][enable-app-sandbox]を読み、エンタイトルメントファイルにアプリに必要なパーミッションキーを追加します。 +OS Xでのアプリのサンドボックス化を行うことが初めてなら、Appleの[Enabling App Sandbox][enable-app-sandbox]を通読し、基本的な考え方を確認してから、、エンタイトルメントファイルにアプリに必要なパーミッションキーを追加します。 -### Appをアップロードし、レビューに登録する +### Appをアップロードする。 -アプリに署名後、iTunes ConnectにアップロードするためにApplication Loaderを使用できます。アップロードする前に[created a record][create-record]を確認してください。そして[レビュー用にアプリを登録できます][submit-for-review]. +アプリに署名後、iTunes ConnectにアップロードするためにApplication Loaderを使用できます。アップロードする前に[created a record][create-record]を確認してください。 + +### アプリケーションを審査に提出 + +これらのステップを終えた後、[レビュー用にアプリを登録できます][submit-for-review]. ## MAS Buildの制限 @@ -131,7 +139,7 @@ Electron は次の暗号アルゴリズムを使用しています: * RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf * RIPEMD - [ISO/IEC 10118-3](http://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004) -ERNの同意を取得するには、 [How to legally submit an app to Apple’s App Store when it uses encryption (or how to obtain an ERN)][ern-tutorial]を参照してくだsだい。 +ERNの同意を取得するには、 [How to legally submit an app to Apple's App Store when it uses encryption (or how to obtain an ERN)][ern-tutorial]を参照してください。 [developer-program]: https://developer.apple.com/support/compare-memberships/ [submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html @@ -142,3 +150,4 @@ ERNの同意を取得するには、 [How to legally submit an app to Apple’s [app-sandboxing]: https://developer.apple.com/app-sandboxing/ [issue-3871]: https://github.com/electron/electron/issues/3871 [ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ +[temporary-exception]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html diff --git a/docs-translations/jp/tutorial/online-offline-events.md b/docs-translations/jp/tutorial/online-offline-events.md index 92503b04dfcb..3b4f669c1f2d 100644 --- a/docs-translations/jp/tutorial/online-offline-events.md +++ b/docs-translations/jp/tutorial/online-offline-events.md @@ -9,10 +9,11 @@ const electron = require('electron'); const app = electron.app; const BrowserWindow = electron.BrowserWindow; -var onlineStatusWindow; -app.on('ready', function() { +let onlineStatusWindow; + +app.on('ready', () => { onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); + onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`); }); ``` @@ -23,7 +24,7 @@ _online-status.html_ @@ -50,35 +48,28 @@ app.on('ready', function() { ## 분리 할당 -만약 CoffeeScript나 Babel을 사용하고 있다면, 빌트인 모듈을 사용할 때 -[분리 할당][destructuring-assignment]을 통해 직관적으로 사용할 수 있습니다: +0.37 버전부터, [분리 할당][destructuring-assignment]을 통해 빌트인 모듈을 더 +직관적으로 사용할 수 있습니다: ```javascript -const {app, BrowserWindow} = require('electron') +const {app, BrowserWindow} = require('electron'); ``` -아직 플레인 자바스크립트를 쓰고 있다면, Chrome이 ES6를 완전히 지원하기 전까지 기다려야 -합니다. - -## 이전 스타일의 빌트인 모듈 비활성화 - -v0.35.0 이전 버전에선 빌트인 모듈이 모두 `require('module-name')`같은 형식으로 -사용되었습니다. 하지만 [많은 단점][issue-387]이 있기 때문에 현재 API가 변경되었습니다. -하지만 오래된 앱의 호환성 유지를 위해 아직 구 버전 API를 지원하고 있습니다. - -완벽하게 모든 구 버전 API를 비활성화하려면 `ELECTRON_HIDE_INTERNAL_MODULES` 환경 -변수를 설정하면 됩니다: +모든 `electron` 모듈이 필요하다면, 먼저 require한 후 각 독립적인 모듈을 +`electron`에서 분리 할당함으로써 모듈을 사용할 수 있습니다. ```javascript -process.env.ELECTRON_HIDE_INTERNAL_MODULES = 'true' -``` +const electron = require('electron'); +const {app, BrowserWindow} = electron; + ``` -또는 `hideInternalModules` API를 사용해도 됩니다: +위 코드는 다음과 같습니다: ```javascript -require('electron').hideInternalModules() +const electron = require('electron'); +const app = electron.app; +const BrowserWindow = electron.BrowserWindow; ``` [gui]: https://en.wikipedia.org/wiki/Graphical_user_interface [destructuring-assignment]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment -[issue-387]: https://github.com/electron/electron/issues/387 diff --git a/docs-translations/ko-KR/api/system-preferences.md b/docs-translations/ko-KR/api/system-preferences.md index c5707ea7eaf1..8a98dd1d5432 100644 --- a/docs-translations/ko-KR/api/system-preferences.md +++ b/docs-translations/ko-KR/api/system-preferences.md @@ -14,11 +14,14 @@ * `event` String * `callback` Function -OS X의 네이티브 알림을 구독하며, 해당하는 `event`가 발생하면 `callback`이 호출됩니다. +OS X의 네이티브 알림을 구독하며, 해당하는 `event`가 발생하면 `callback`이 +`callback(event, userInfo)` 형태로 호출됩니다. `userInfo`는 알림과 함께 전송되는 +사용자 정보 딕셔너리를 포함하는 객체입니다. + 구독자의 `id`가 반환되며 `event`를 구독 해제할 때 사용할 수 있습니다. -이 API는 후드에서 `NSDistributedNotificationCenter`를 구독하며, `event`에서 사용 -가능한 값은 다음과 같습니다: +이 API는 후드에서 `NSDistributedNotificationCenter`를 구독하며, `event`의 예시 +값은 다음과 같습니다: * `AppleInterfaceThemeChangedNotification` * `AppleAquaColorVariantChanged` diff --git a/docs-translations/ko-KR/api/tray.md b/docs-translations/ko-KR/api/tray.md index 6162557e1a7c..d208de250201 100644 --- a/docs-translations/ko-KR/api/tray.md +++ b/docs-translations/ko-KR/api/tray.md @@ -3,24 +3,20 @@ > 아이콘과 컨텍스트 메뉴를 시스템 알림 영역에 추가합니다. ```javascript -const electron = require('electron'); -const app = electron.app; -const Menu = electron.Menu; -const Tray = electron.Tray; +const {app, Menu, Tray} = require('electron'); -var appIcon = null; -app.on('ready', function(){ +let appIcon = null; +app.on('ready', () => { appIcon = new Tray('/path/to/my/icon'); // 현재 어플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야 합니다. - var contextMenu = Menu.buildFromTemplate([ - { label: 'Item1', type: 'radio' }, - { label: 'Item2', type: 'radio' }, - { label: 'Item3', type: 'radio', checked: true }, - { label: 'Item4', type: 'radio' } + const contextMenu = Menu.buildFromTemplate([ + {label: 'Item1', type: 'radio'}, + {label: 'Item2', type: 'radio'}, + {label: 'Item3', type: 'radio', checked: true}, + {label: 'Item4', type: 'radio'} ]); appIcon.setToolTip('이것은 나의 어플리케이션 입니다!'); appIcon.setContextMenu(contextMenu); }); - ``` __플랫폼별 한계:__ diff --git a/docs-translations/ko-KR/api/web-contents.md b/docs-translations/ko-KR/api/web-contents.md index 3405d5f0266e..0510f0bd5788 100644 --- a/docs-translations/ko-KR/api/web-contents.md +++ b/docs-translations/ko-KR/api/web-contents.md @@ -8,12 +8,12 @@ 접근하는 예시입니다: ```javascript -const BrowserWindow = require('electron').BrowserWindow; +const {BrowserWindow} = require('electron'); -var win = new BrowserWindow({width: 800, height: 1500}); -win.loadURL("http://github.com"); +let win = new BrowserWindow({width: 800, height: 1500}); +win.loadURL('http://github.com'); -var webContents = win.webContents; +let webContents = win.webContents; ``` ## Events @@ -37,8 +37,9 @@ Returns: 이 이벤트는 `did-finish-load`와 비슷하나, 로드가 실패했거나 취소되었을 때 발생합니다. 예를 들면 `window.stop()`이 실행되었을 때 발생합니다. 발생할 수 있는 전체 에러 코드의 -목록과 설명은 [여기](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h)서 -확인할 수 있습니다. +목록과 설명은 [여기서](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) +확인할 수 있습니다. 참고로 리다이렉트 응답은 `errorCode` -3과 함께 발생합니다; 이 +에러는 명시적으로 무시할 수 있습니다. ### Event: 'did-frame-finish-load' @@ -225,7 +226,7 @@ Returns: * `issuerName` String - 인증서 발급자 이름 * `callback` Function -클라이언트 인증이 요청되었을 때 발생하는 이벤트 입니다. +클라이언트 인증이 요청되었을 때 발생하는 이벤트입니다. 사용법은 [`app`의 `select-client-certificate` 이벤트](app.md#event-select-client-certificate)와 같습니다. @@ -292,7 +293,7 @@ Returns: * `image` NativeImage (optional) * `scale` Float (optional) -커서 타입이 변경될 때 발생하는 이벤트입니다. `type` 매개변수는 다음 값이 될 수 있습니다: +커서 종류가 변경될 때 발생하는 이벤트입니다. `type` 인수는 다음 값이 될 수 있습니다: `default`, `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, `ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, `ns-resize`, `ew-resize`, `nesw-resize`, `nwse-resize`, `col-resize`, @@ -301,10 +302,64 @@ Returns: `cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, `not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing`, `custom`. -만약 `type` 매개변수가 `custom` 이고 `image` 매개변수가 `NativeImage`를 통한 커스텀 -커서를 지정했을 때, 해당 이미지로 커서가 변경됩니다. 또한 `scale` 매개변수는 이미지의 +만약 `type` 인수가 `custom` 이고 `image` 인수가 `NativeImage`를 통한 커스텀 +커서를 지정했을 때, 해당 이미지로 커서가 변경됩니다. 또한 `scale` 인수는 이미지의 크기를 조정합니다. +### Event: 'context-menu' + +Returns: + +* `event` Event +* `params` Object + * `x` Integer - x 좌표 + * `y` Integer - y 좌표 + * `linkURL` String - 컨텍스트 메뉴가 호출된 노드를 둘러싸는 링크의 URL. + * `linkText` String - 링크에 연관된 텍스트. 콘텐츠의 링크가 이미지인 경우 빈 + 문자열이 됩니다. + * `pageURL` String - 컨텍스트 메뉴가 호출된 상위 수준 페이지의 URL. + * `frameURL` String - 컨텍스트 메뉴가 호출된 서브 프레임의 URL. + * `srcURL` String - 컨텍스트 메뉴가 호출된 요소에 대한 소스 URL. 요소와 소스 URL은 + 이미지, 오디오, 비디오입니다. + * `mediaType` String - 컨텍스트 메뉴가 호출된 노드의 종류. 값은 `none`, `image`, + `audio`, `video`, `canvas`, `file` 또는 `plugin`이 될 수 있습니다. + * `hasImageContent` Boolean - 컨텍스트 메뉴가 내용이 있는 이미지에서 호출되었는지 + 여부. + * `isEditable` Boolean - 컨텍스트를 편집할 수 있는지 여부. + * `selectionText` String - 컨텍스트 메뉴가 호출된 부분에 있는 선택된 텍스트. + * `titleText` String - 컨텍스트 메뉴가 호출된 선택된 제목 또는 알림 텍스트. + * `misspelledWord` String - 만약 있는 경우, 커서가 가르키는 곳에서 발생한 오타. + * `frameCharset` String - 메뉴가 호출된 프레임의 문자열 인코딩. + * `inputFieldType` String - 컨텍스트 메뉴가 입력 필드에서 호출되었을 때, 그 필드의 + 종류. 값은 `none`, `plainText`, `password`, `other` 중 한 가지가 될 수 있습니다. + * `menuSourceType` String - 컨텍스트 메뉴를 호출한 입력 소스. 값은 `none`, + `mouse`, `keyboard`, `touch`, `touchMenu` 중 한 가지가 될 수 있습니다. + * `mediaFlags` Object - 컨텍스트 메뉴가 호출된 미디어 요소에 대한 플래그. 자세한 + 사항은 아래를 참고하세요. + * `editFlags` Object - 이 플래그는 렌더러가 어떤 행동을 이행할 수 있는지 여부를 + 표시합니다. 자세한 사항은 아래를 참고하세요. + +`mediaFlags`는 다음과 같은 속성을 가지고 있습니다: + * `inError` Boolean - 미디어 객체가 크래시되었는지 여부. + * `isPaused` Boolean - 미디어 객체가 일시중지되었는지 여부. + * `isMuted` Boolean - 미디어 객체가 음소거되었는지 여부. + * `hasAudio` Boolean - 미디어 객체가 오디오를 가지고 있는지 여부. + * `isLooping` Boolean - 미디어 객체가 루프중인지 여부. + * `isControlsVisible` Boolean - 미디어 객체의 컨트롤이 보이는지 여부. + * `canToggleControls` Boolean - 미디어 객체의 컨트롤을 토글할 수 있는지 여부. + * `canRotate` Boolean - 미디어 객체를 돌릴 수 있는지 여부. + +`editFlags`는 다음과 같은 속성을 가지고 있습니다: + * `canUndo` Boolean - 렌더러에서 실행 취소할 수 있는지 여부. + * `canRedo` Boolean - 렌더러에서 다시 실행할 수 있는지 여부. + * `canCut` Boolean - 렌더러에서 잘라내기를 실행할 수 있는지 여부. + * `canCopy` Boolean - 렌더러에서 복사를 실행할 수 있는지 여부. + * `canPaste` Boolean - 렌더러에서 붙여넣기를 실행할 수 있는지 여부. + * `canDelete` Boolean - 렌더러에서 삭제를 실행할 수 있는지 여부. + * `canSelectAll` Boolean - 렌더러에서 모두 선택을 실행할 수 있는지 여부. + +새로운 컨텍스트 메뉴의 제어가 필요할 때 발생하는 이벤트입니다. + ## Instance Methods `webContents`객체는 다음과 같은 인스턴스 메서드들을 가지고 있습니다. @@ -322,7 +377,7 @@ Returns: 하는 경우 `pragma` 헤더를 사용할 수 있습니다. ```javascript -const options = {"extraHeaders" : "pragma: no-cache\n"} +const options = {extraHeaders: 'pragma: no-cache\n'}; webContents.loadURL(url, options) ``` @@ -338,10 +393,10 @@ webContents.loadURL(url, options) 현재 웹 페이지의 URL을 반환합니다. ```javascript -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL("http://github.com"); +let win = new BrowserWindow({width: 800, height: 600}); +win.loadURL('http://github.com'); -var currentURL = win.webContents.getURL(); +let currentURL = win.webContents.getURL(); ``` ### `webContents.getTitle()` @@ -533,12 +588,12 @@ CSS 코드를 현재 웹 페이지에 삽입합니다. 제공된 `action`에 대한 `webContents`의 모든 `findInPage` 요청을 중지합니다. ```javascript -webContents.on('found-in-page', function(event, result) { +webContents.on('found-in-page', (event, result) => { if (result.finalUpdate) - webContents.stopFindInPage("clearSelection"); + webContents.stopFindInPage('clearSelection'); }); -const requestId = webContents.findInPage("api"); +const requestId = webContents.findInPage('api'); ``` ### `webContents.hasServiceWorker(callback)` @@ -584,7 +639,7 @@ print기능을 사용하지 않는 경우 전체 바이너리 크기를 줄이 * `printSelectionOnly` Boolean - 선택된 영역만 프린트할지 여부를 정합니다. * `landscape` Boolean - landscape을 위해선 `true`를, portrait를 위해선 `false`를 사용합니다. -* `callback` Function - `function(error, data) {}` +* `callback` Function - `(error, data) => {}` Chromium의 미리보기 프린팅 커스텀 설정을 이용하여 윈도우의 웹 페이지를 PDF로 프린트합니다. @@ -604,22 +659,22 @@ Chromium의 미리보기 프린팅 커스텀 설정을 이용하여 윈도우의 ``` ```javascript -const BrowserWindow = require('electron').BrowserWindow; +const {BrowserWindow} = require('electron'); const fs = require('fs'); -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL("http://github.com"); +let win = new BrowserWindow({width: 800, height: 600}); +win.loadURL('http://github.com'); -win.webContents.on("did-finish-load", function() { - // Use default printing options - win.webContents.printToPDF({}, function(error, data) { +win.webContents.on('did-finish-load', () => { + // 기본 프린트 옵션을 사용합니다 + win.webContents.printToPDF({}, (error, data) => { if (error) throw error; - fs.writeFile("/tmp/print.pdf", data, function(error) { + fs.writeFile('/tmp/print.pdf', data, (error) => { if (error) throw error; - console.log("Write PDF successfully."); - }) - }) + console.log('Write PDF successfully.'); + }); + }); }); ``` @@ -631,8 +686,8 @@ win.webContents.on("did-finish-load", function() { 이후에 사용해야 합니다. ```javascript -mainWindow.webContents.on('devtools-opened', function() { - mainWindow.webContents.addWorkSpace(__dirname); +win.webContents.on('devtools-opened', () => { + win.webContents.addWorkSpace(__dirname); }); ``` @@ -648,7 +703,7 @@ mainWindow.webContents.on('devtools-opened', function() { * `detach` Boolean - 새 창에서 개발자 도구를 엽니다. * `mode` String - 개발자 도구 표시 상태를 지정합니다. 옵션은 "right", "bottom", "undocked", "detach"가 될 수 있습니다. 기본값은 마지막 표시 상태를 - 사용합니다. `undocked` 모드에선 다시 독을 할 수 있습니다. 하지만 `detach` + 사용합니다. `undocked` 모드에선 다시 도킹할 수 있습니다. 하지만 `detach` 모드에선 할 수 없습니다. 개발자 도구를 엽니다. @@ -674,7 +729,7 @@ mainWindow.webContents.on('devtools-opened', function() { * `x` Integer * `y` Integer -(`x`, `y`)위치의 엘레먼트를 조사합니다. +(`x`, `y`)위치의 요소를 조사합니다. ### `webContents.inspectServiceWorker()` @@ -696,12 +751,12 @@ mainWindow.webContents.on('devtools-opened', function() { ```javascript // In the main process. -var window = null; -app.on('ready', function() { - window = new BrowserWindow({width: 800, height: 600}); - window.loadURL('file://' + __dirname + '/index.html'); - window.webContents.on('did-finish-load', function() { - window.webContents.send('ping', 'whoooooooh!'); +let win = null; +app.on('ready', () => { + win = new BrowserWindow({width: 800, height: 600}); + win.loadURL('file://' + __dirname + '/index.html'); + win.webContents.on('did-finish-load', () => { + win.webContents.send('ping', 'whoooooooh!'); }); }); ``` @@ -711,8 +766,8 @@ app.on('ready', function() { @@ -759,7 +814,7 @@ app.on('ready', function() { ### `webContents.sendInputEvent(event)` * `event` Object - * `type` String (**required**) - 이벤트의 타입. 다음 값들을 사용할 수 있습니다: + * `type` String (**required**) - 이벤트의 종류. 다음 값들을 사용할 수 있습니다: `mouseDown`, `mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`, `mouseMove`, `keyDown`, `keyUp`, `char`. * `modifiers` Array - 이벤트의 수정자(modifier)들에 대한 배열. 다음 값들을 포함 @@ -816,11 +871,11 @@ Input `event`를 웹 페이지로 전송합니다. ### `webContents.savePage(fullPath, saveType, callback)` * `fullPath` String - 전체 파일 경로. -* `saveType` String - 저장 타입을 지정합니다. +* `saveType` String - 저장 종류를 지정합니다. * `HTMLOnly` - 페이지의 HTML만 저장합니다. * `HTMLComplete` - 페이지의 완성된 HTML을 저장합니다. * `MHTML` - 페이지의 완성된 HTML을 MHTML로 저장합니다. -* `callback` Function - `function(error) {}`. +* `callback` Function - `(error) => {}`. * `error` Error 만약 페이지를 저장하는 프로세스가 성공적으로 끝났을 경우 true를 반환합니다. @@ -828,10 +883,10 @@ Input `event`를 웹 페이지로 전송합니다. ```javascript win.loadURL('https://github.com'); -win.webContents.on('did-finish-load', function() { - win.webContents.savePage('/tmp/test.html', 'HTMLComplete', function(error) { +win.webContents.on('did-finish-load', () => { + win.webContents.savePage('/tmp/test.html', 'HTMLComplete', (error) => { if (!error) - console.log("Save page successfully"); + console.log('Save page successfully'); }); }); ``` @@ -840,6 +895,10 @@ win.webContents.on('did-finish-load', function() { `WebContents`객체들은 다음 속성들을 가지고 있습니다: +### `webContents.id` + +이 WebContents의 유일 ID. + ### `webContents.session` 이 webContents에서 사용하는 [session](session.md) 객체를 반환합니다. @@ -861,23 +920,23 @@ win.webContents.on('did-finish-load', function() { ```javascript try { - win.webContents.debugger.attach("1.1"); + win.webContents.debugger.attach('1.1'); } catch(err) { - console.log("Debugger attach failed : ", err); + console.log('Debugger attach failed : ', err); }; -win.webContents.debugger.on('detach', function(event, reason) { - console.log("Debugger detached due to : ", reason); +win.webContents.debugger.on('detach', (event, reason) => { + console.log('Debugger detached due to : ', reason); }); -win.webContents.debugger.on('message', function(event, method, params) { - if (method == "Network.requestWillBeSent") { - if (params.request.url == "https://www.github.com") +win.webContents.debugger.on('message', (event, method, params) => { + if (method === 'Network.requestWillBeSent') { + if (params.request.url === 'https://www.github.com') win.webContents.debugger.detach(); } -}) +}); -win.webContents.debugger.sendCommand("Network.enable"); +win.webContents.debugger.sendCommand('Network.enable'); ``` #### `webContents.debugger.attach([protocolVersion])` @@ -898,7 +957,7 @@ win.webContents.debugger.sendCommand("Network.enable"); * `method` String - 메서드 이름, 반드시 원격 디버깅 프로토콜에 의해 정의된 메서드중 하나가 됩니다. -* `commandParams` Object (optional) - 요청 매개변수를 표현한 JSON 객체. +* `commandParams` Object (optional) - 요청 인수를 표현한 JSON 객체. * `callback` Function (optional) - 응답 * `error` Object - 커맨드의 실패를 표시하는 에러 메시지. * `result` Object - 원격 디버깅 프로토콜에서 커맨드 설명의 'returns' 속성에 의해 @@ -918,8 +977,7 @@ win.webContents.debugger.sendCommand("Network.enable"); * `event` Event * `method` String - 메서드 이름. -* `params` Object - 원격 디버깅 프로토콜의 'parameters' 속성에서 정의된 이벤트 - 매개변수 +* `params` Object - 원격 디버깅 프로토콜의 'parameters' 속성에서 정의된 이벤트 인수 디버깅 타겟이 관련 이벤트를 발생시킬 때 마다 발생하는 이벤트입니다. diff --git a/docs-translations/ko-KR/api/web-frame.md b/docs-translations/ko-KR/api/web-frame.md index 4b9ade4bebed..fdc68d222313 100644 --- a/docs-translations/ko-KR/api/web-frame.md +++ b/docs-translations/ko-KR/api/web-frame.md @@ -5,7 +5,7 @@ 다음 예시는 현재 페이지를 200% 줌 합니다: ```javascript -var webFrame = require('electron').webFrame; +const {webFrame} = require('electron'); webFrame.setZoomFactor(2); ``` @@ -58,8 +58,8 @@ Input field나 text area에 철자 검사(spell checking) 제공자를 설정합 [node-spellchecker][spellchecker]를 철자 검사 제공자로 사용하는 예시입니다: ```javascript -webFrame.setSpellCheckProvider("en-US", true, { - spellCheck: function(text) { +webFrame.setSpellCheckProvider('en-US', true, { + spellCheck(text) { return !(require('spellchecker').isMisspelled(text)); } }); @@ -103,4 +103,40 @@ ServiceWorker의 등록과 fetch API를 사용할 수 있도록 지원합니다. 브라우저 윈도우에서 어떤 `requestFullScreen` 같은 HTML API는 사용자의 승인이 필요합니다. `userGesture`를 `true`로 설정하면 이러한 제약을 제거할 수 있습니다. +### `webFrame.getResourceUsage()` + +Blink의 내부 메모리 캐시 사용 정보를 담고있는 객체를 반환합니다. + +```javascript +console.log(webFrame.getResourceUsage()) +``` + +다음이 출력됩니다: + +```javascript +{ + images: { + count: 22, + size: 2549, + liveSize: 2542, + decodedSize: 478, + purgedSize: 0, + purgeableSize: 0 + }, + cssStyleSheets: { /* same with "images" */ }, + xslStyleSheets: { /* same with "images" */ }, + fonts: { /* same with "images" */ }, + other: { /* same with "images" */ }, +} +``` + +### `webFrame.clearCache()` + +사용하지 않는 메모리 비우기를 시도합니다. (이전 페이지의 이미지 등) + +참고로 맹목적으로 이 메서드를 호출하는 것은 이 빈 캐시를 다시 채워야하기 때문에 +Electron을 느리게 만듭니다. 따라서 이 메서드는 페이지가 예상했던 것 보다 실질적으로 더 +적은 메모리를 사용하게 만드는 어플리케이션 이벤트가 발생했을 때만 호출해야 합니다. +(i.e. 아주 무거운 페이지에서 거의 빈 페이지로 이동한 후 계속 유지할 경우) + [spellchecker]: https://github.com/atom/node-spellchecker diff --git a/docs-translations/ko-KR/api/web-view-tag.md b/docs-translations/ko-KR/api/web-view-tag.md index ae446975ef28..7adbe5cbd188 100644 --- a/docs-translations/ko-KR/api/web-view-tag.md +++ b/docs-translations/ko-KR/api/web-view-tag.md @@ -11,6 +11,8 @@ 상호작용이 비동기로 작동한다는 것을 의미합니다. 따라서 임베디드 콘텐츠로부터 어플리케이션을 안전하게 유지할 수 있습니다. +보안상의 이유로, `webview`는 `nodeIntegration`이 활성화된 `BrowserWindow`에서만 사용할 수 있습니다. + ## 예시 웹 페이지를 어플리케이션에 삽입하려면 `webview` 태그를 사용해 원하는 타겟 페이지에 @@ -29,19 +31,21 @@ ```html ``` @@ -205,7 +209,7 @@ API를 사용할 수 있습니다. 이를 지정하면 내부에서 로우레벨 **예시** ```javascript -webview.addEventListener("dom-ready", function() { +webview.addEventListener('dom-ready', () => { webview.openDevTools(); }); ``` @@ -450,7 +454,7 @@ Webview 페이지를 PDF 형식으로 인쇄합니다. * `args` (optional) `channel`을 통해 렌더러 프로세스로 비동기 메시지를 보냅니다. 또한 `args`를 지정하여 -임의의 인자를 보낼 수도 있습니다. 렌더러 프로세스는 `ipcRenderer` 모듈의 `channel` +임의의 인수를 보낼 수도 있습니다. 렌더러 프로세스는 `ipcRenderer` 모듈의 `channel` 이벤트로 이 메시지를 받아 처리할 수 있습니다. 예시는 [webContents.send](web-contents.md#webcontentssendchannel-args)를 참고하세요. @@ -588,7 +592,7 @@ Returns: 콘솔에 다시 로깅하는 예시입니다. ```javascript -webview.addEventListener('console-message', function(e) { +webview.addEventListener('console-message', (e) => { console.log('Guest page logged a message:', e.message); }); ``` @@ -608,12 +612,12 @@ Returns: 사용할 수 있을 때 발생하는 이벤트입니다. ```javascript -webview.addEventListener('found-in-page', function(e) { +webview.addEventListener('found-in-page', (e) => { if (e.result.finalUpdate) - webview.stopFindInPage("keepSelection"); + webview.stopFindInPage('keepSelection'); }); -const rquestId = webview.findInPage("test"); +const rquestId = webview.findInPage('test'); ``` ### Event: 'new-window' @@ -631,10 +635,12 @@ Returns: 다음 예시 코드는 새 URL을 시스템의 기본 브라우저로 여는 코드입니다. ```javascript -webview.addEventListener('new-window', function(e) { - var protocol = require('url').parse(e.url).protocol; +const {shell} = require('electron'); + +webview.addEventListener('new-window', (e) => { + const protocol = require('url').parse(e.url).protocol; if (protocol === 'http:' || protocol === 'https:') { - require('electron').shell.openExternal(e.url); + shell.openExternal(e.url); } }); ``` @@ -687,7 +693,7 @@ Returns: 이동시키는 예시입니다. ```javascript -webview.addEventListener('close', function() { +webview.addEventListener('close', () => { webview.src = 'about:blank'; }); ``` @@ -706,7 +712,7 @@ Returns: ```javascript // In embedder page. -webview.addEventListener('ipc-message', function(event) { +webview.addEventListener('ipc-message', (event) => { console.log(event.channel); // Prints "pong" }); @@ -715,8 +721,8 @@ webview.send('ping'); ```javascript // In guest page. -var ipcRenderer = require('electron').ipcRenderer; -ipcRenderer.on('ping', function() { +const {ipcRenderer} = require('electron'); +ipcRenderer.on('ping', () => { ipcRenderer.sendToHost('pong'); }); ``` diff --git a/docs-translations/ko-KR/api/window-open.md b/docs-translations/ko-KR/api/window-open.md index 259b08dc5966..ac291283f546 100644 --- a/docs-translations/ko-KR/api/window-open.md +++ b/docs-translations/ko-KR/api/window-open.md @@ -11,7 +11,7 @@ 합니다. 새롭게 생성된 `BrowserWindow`는 기본적으로 부모 창의 옵션을 상속합니다. 이 옵션을 -변경하려면 새 창을 열 때 `features` 인자를 지정해야 합니다. +변경하려면 새 창을 열 때 `features` 인수를 지정해야 합니다. ### `window.open(url[, frameName][, features])` diff --git a/docs-translations/ko-KR/development/build-instructions-windows.md b/docs-translations/ko-KR/development/build-instructions-windows.md index 7d30635a6a04..4e4a9354d92c 100644 --- a/docs-translations/ko-KR/development/build-instructions-windows.md +++ b/docs-translations/ko-KR/development/build-instructions-windows.md @@ -5,7 +5,7 @@ ## 빌드전 요구 사항 * Windows 7 / Server 2008 R2 또는 최신 버전 -* Visual Studio 2013 Update 4 - [VS 2013 커뮤니티 에디션 무료 다운로드](https://www.visualstudio.com/news/vs2013-community-vs) +* Visual Studio 2015 - [VS 2015 커뮤니티 에디션 무료 다운로드](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) * [Python 2.7](http://www.python.org/download/releases/2.7/) * [Node.js](http://nodejs.org/download/) * [Git](http://git-scm.com) @@ -21,7 +21,7 @@ Studio를 사용할 수 없습니다. 하지만 여전히 Electron을 개발할 **참고:** Visual Studio가 직접 빌드에 사용되지 않더라도 IDE와 같이 제공된 빌드 툴체인이 빌드에 **반드시** 사용되므로 여전히 필요합니다. -**참고:** Visual Studio 2015는 사용할 수 없습니다 MSVS **2013** 을 사용하고 있는지 +**참고:** Visual Studio 2013는 사용할 수 없습니다 MSVS **2015** 을 사용하고 있는지 확인해주세요. ## 코드 가져오기 @@ -61,7 +61,7 @@ $ python script\build.py -c D ## 64비트 빌드 64비트를 타겟으로 빌드 하려면 부트스트랩 스크립트를 실행할 때 `--target_arch=x64` -인자를 같이 넘겨주면 됩니다: +인수를 같이 넘겨주면 됩니다: ```powershell $ python script\bootstrap.py -v --target_arch=x64 @@ -97,7 +97,7 @@ $ python script\test.py -R ### Command xxxx not found 만약 `Command xxxx not found`와 같은 형식의 에러가 발생했다면 -`VS2012 Command Prompt` 콘솔로 빌드 스크립트를 실행해볼 필요가 있습니다. +`VS2015 Command Prompt` 콘솔로 빌드 스크립트를 실행해볼 필요가 있습니다. ### Fatal internal compiler error: C1001 @@ -146,4 +146,4 @@ $ mkdir ~\AppData\Roaming\npm ### node-gyp is not recognized as an internal or external command Git Bash로 빌드 했을 때 이러한 에러가 발생할 수 있습니다. 반드시 PowerShell이나 -VS2012 Command Prompt에서 빌드를 진행해야 합니다. +VS2015 Command Prompt에서 빌드를 진행해야 합니다. diff --git a/docs-translations/ko-KR/development/debug-instructions-windows.md b/docs-translations/ko-KR/development/debug-instructions-windows.md index a0d50e475c76..27f96c284b00 100644 --- a/docs-translations/ko-KR/development/debug-instructions-windows.md +++ b/docs-translations/ko-KR/development/debug-instructions-windows.md @@ -8,7 +8,7 @@ Electron 소스 코드가 중단점을 통해 순차적으로 쉽게 디버깅 ## 요구 사항 * **Electron의 디버그 빌드**: 가장 쉬운 방법은 보통 - [Windows용 빌드 설명서](build-instructions-windows.md)에 명시된 요구사항과 툴을 + [Windows용 빌드 설명서](build-instructions-windows.md)에 명시된 요구 사항과 툴을 사용하여 스스로 빌드하는 것입니다. 물론 직접 다운로드 받은 Electron 바이너리에도 디버거 연결 및 디버깅을 사용할 수 있지만, 실질적으로 디버깅이 까다롭게 고도의 최적화가 되어있음을 발견하게 될 것입니다: 인라인화, 꼬리 호출, 이외 여러 가지 @@ -21,13 +21,13 @@ Electron 소스 코드가 중단점을 통해 순차적으로 쉽게 디버깅 설정해야 합니다. 이 작업은 Visual Studio가 Electron에서 무슨일이 일어나는지 더 잘 이해할 수 있도록 하며 변수를 사람이 읽기 좋은 포맷으로 쉽게 표현할 수 있도록 합니다. -* **ProcMon**: 이 무료 [SysInternals][sys-internals] 툴은 프로세스 인자, 파일 +* **ProcMon**: 이 무료 [SysInternals][sys-internals] 툴은 프로세스 인수, 파일 핸들러 그리고 레지스트리 작업을 탐색할 수 있게 도와줍니다. ## Electron에 디버거 연결하고 디버깅하기 디버깅 작업을 시작하려면, PowerShell/CMD 중 한 가지를 열고 디버그 빌드 상태의 -Electron에 인자로 어플리케이션을 전달하여 실행합니다: +Electron에 인수로 어플리케이션을 전달하여 실행합니다: ```powershell $ ./out/D/electron.exe ~/my-electron-app/ diff --git a/docs-translations/ko-KR/development/source-code-directory-structure.md b/docs-translations/ko-KR/development/source-code-directory-structure.md index 98a3fd2a1de0..003eca596839 100644 --- a/docs-translations/ko-KR/development/source-code-directory-structure.md +++ b/docs-translations/ko-KR/development/source-code-directory-structure.md @@ -60,7 +60,7 @@ Electron ## Git 서브 모듈 최신 버전으로 유지 -Electron 저장소는 몇 가지 외부 벤더 종속성을 가지고 있으며 [/vendor](/vendor) +Electron 저장소는 몇 가지 외부 벤더 종속성을 가지고 있으며 [/vendor][vendor] 디렉터리에서 확인할 수 있습니다. 때때로 `git status`를 실행했을 때 아마 다음과 같은 메시지를 흔히 목격할 것입니다: @@ -84,3 +84,5 @@ git submodule update --init --recursive [alias] su = submodule update --init --recursive ``` + +[vendor]: https://github.com/electron/electron/tree/master/vendor diff --git a/docs-translations/ko-KR/faq/electron-faq.md b/docs-translations/ko-KR/faq/electron-faq.md index a038142c5ae3..c186d148c2a0 100644 --- a/docs-translations/ko-KR/faq/electron-faq.md +++ b/docs-translations/ko-KR/faq/electron-faq.md @@ -3,16 +3,19 @@ ## 언제 Electron이 최신 버전의 Chrome으로 업그레이드 되나요? Electron의 Chrome 버전은 보통 새로운 Chrome 안정 버전이 릴리즈 된 이후 1주 내지 2주 -내로 업데이트됩니다. +내로 업데이트됩니다. 하지만 이러한 업데이트 주기는 보장되지 않으며 업그레이드에 필요한 +작업의 양에 따라 달라집니다. -또한 우리는 크롬의 안정된 채널만을 이용합니다, 만약 중요한 수정이 베타 또는 개발 채널인 -경우, 우리는 해당 버전 대신 이전 버전을 다시 사용합니다. +Electron은 크롬이 사용하는 안정된 채널만을 이용합니다, 만약 중요한 수정이 베타 또는 +개발 채널에 패치된 경우, 이전 버전의 채널로 롤백합니다. + +자세한 내용은 [보안 설명](../tutorial/security.md)을 참고하세요. ## Electron은 언제 최신 버전의 Node.js로 업그레이드 하나요? -새로운 버전의 Node.js가 릴리즈 되면, 우리는 보통 Electron을 업그레이드 하기 전에 한 -달 정도 대기합니다. 이렇게 하면 새로운 Node.js 버전을 업데이트 함으로써 발생하는 -버그들을 피할 수 있습니다. 이러한 상황은 자주 발생합니다. +새로운 버전의 Node.js가 릴리즈 되면, 보통 Electron을 업그레이드 하기 전에 한 달 정도 +대기합니다. 이렇게 하면 새로운 Node.js 버전을 업데이트 함으로써 발생하는 버그들을 +피할 수 있기 때문입니다. 이러한 상황은 자주 발생합니다. Node.js의 새로운 기능은 보통 V8 업그레이드에서 가져옵니다. Electron은 Chrome 브라우저에 탑재된 V8을 사용하고 있습니다. 눈부신 새로운 Node.js 버전의 자바스크립트 @@ -59,18 +62,18 @@ console.log(require('remote').getGlobal('sharedObject').someProperty); 만약 빠르게 고치고 싶다면, 다음과 같이 변수를 전역 변수로 만드는 방법이 있습니다: ```javascript -app.on('ready', function() { - var tray = new Tray('/path/to/icon.png'); -}) +app.on('ready', () => { + const tray = new Tray('/path/to/icon.png'); +}); ``` 를 이렇게: ```javascript -var tray = null; -app.on('ready', function() { +let tray = null; +app.on('ready', () => { tray = new Tray('/path/to/icon.png'); -}) +}); ``` ## Electron에서 jQuery/RequireJS/Meteor/AngularJS를 사용할 수 없습니다. @@ -83,7 +86,7 @@ Node.js가 Electron에 합쳐졌기 때문에, DOM에 `module`, `exports`, `requ ```javascript // 메인 프로세스에서. -var mainWindow = new BrowserWindow({ +let win = new BrowserWindow({ webPreferences: { nodeIntegration: false } diff --git a/docs-translations/ko-KR/styleguide.md b/docs-translations/ko-KR/styleguide.md index 3896f3d21d10..340fa4204a05 100644 --- a/docs-translations/ko-KR/styleguide.md +++ b/docs-translations/ko-KR/styleguide.md @@ -92,7 +92,7 @@ Returns: 다음과 같이 사용할 수 있습니다: ```javascript -Alarm.on('wake-up', function(time) { +Alarm.on('wake-up', (time) => { console.log(time) -}) +}); ``` diff --git a/docs-translations/ko-KR/tutorial/application-packaging.md b/docs-translations/ko-KR/tutorial/application-packaging.md index bc56d824617a..8002350b56b1 100644 --- a/docs-translations/ko-KR/tutorial/application-packaging.md +++ b/docs-translations/ko-KR/tutorial/application-packaging.md @@ -70,8 +70,8 @@ require('/path/to/example.asar/dir/module.js'); `BrowserWindow` 클래스를 이용해 원하는 웹 페이지도 표시할 수 있습니다: ```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({width: 800, height: 600}); +const {BrowserWindow} = require('electron'); +let win = new BrowserWindow({width: 800, height: 600}); win.loadURL('file:///path/to/example.asar/static/index.html'); ``` @@ -84,8 +84,8 @@ win.loadURL('file:///path/to/example.asar/static/index.html'); ```html @@ -99,7 +99,7 @@ $.get('file:///path/to/example.asar/file.txt', function(data) { 읽어들입니다: ```javascript -var originalFs = require('original-fs'); +const originalFs = require('original-fs'); originalFs.readFileSync('/path/to/example.asar'); ``` diff --git a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md index 961bfc83076f..beece23e3f75 100644 --- a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md +++ b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md @@ -17,13 +17,13 @@ Windows, Linux, OS X 운영체제 모두 기본적으로 어플리케이션에 **참고:** 이 API는 HTML5 API이기 때문에 렌더러 프로세스에서만 사용할 수 있습니다. ```javascript -var myNotification = new Notification('Title', { +let myNotification = new Notification('Title', { body: 'Lorem Ipsum Dolor Sit Amet' }); -myNotification.onclick = function () { - console.log('Notification clicked') -} +myNotification.onclick = () => { + console.log('Notification clicked'); +}; ``` 위 코드를 통해 생성한 데스크톱 알림은 각 운영체제 모두 비슷한 사용자 경험을 제공하지만, @@ -90,7 +90,7 @@ app.clearRecentDocuments(); 않습니다. 어플리케이션 등록에 관련된 API의 모든 내용은 [Application Registration][app-registration]에서 찾아볼 수 있습니다. -유저가 JumpList에서 파일을 클릭할 경우 클릭된 파일의 경로가 커맨드 라인 인자로 추가되어 +유저가 JumpList에서 파일을 클릭할 경우 클릭된 파일의 경로가 커맨드 라인 인수로 추가되어 새로운 인스턴스의 어플리케이션이 실행됩니다. ### OS X에서 주의할 점 @@ -110,18 +110,17 @@ __Terminal.app의 dock menu:__ OS X에서만 사용 가능합니다: ```javascript -const electron = require('electron'); -const app = electron.app; -const Menu = electron.Menu; +const {app, Menu} = require('electron'); -var dockMenu = Menu.buildFromTemplate([ - { label: 'New Window', click: function() { console.log('New Window'); } }, - { label: 'New Window with Settings', submenu: [ - { label: 'Basic' }, - { label: 'Pro'} +const dockMenu = Menu.buildFromTemplate([ + {label: 'New Window', click() { console.log('New Window'); }}, + {label: 'New Window with Settings', submenu: [ + {label: 'Basic'}, + {label: 'Pro'} ]}, - { label: 'New Command...'} + {label: 'New Command...'} ]); + app.dock.setMenu(dockMenu); ``` @@ -149,7 +148,7 @@ __Internet Explorer의 작업:__ ![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) OS X의 dock menu(진짜 메뉴)와는 달리 Windows의 사용자 작업은 어플리케이션 바로 -가기처럼 작동합니다. 유저가 작업을 클릭할 때 설정한 인자와 함께 새로운 어플리케이션이 +가기처럼 작동합니다. 유저가 작업을 클릭할 때 설정한 인수와 함께 새로운 어플리케이션이 실행됩니다. 사용자 작업을 설정하려면 [app.setUserTasks][setusertaskstasks] 메서드를 통해 구현할 @@ -168,7 +167,7 @@ app.setUserTasks([ ]); ``` -작업 리스트를 비우려면 간단히 `app.setUserTasks` 메서드의 첫번째 인자에 빈 배열을 넣어 +작업 리스트를 비우려면 간단히 `app.setUserTasks` 메서드의 첫번째 인수에 빈 배열을 넣어 호출하면 됩니다: ```javascript @@ -203,24 +202,25 @@ __Windows Media Player의 미리보기 툴바:__ 미리보기 툴바를 설정할 수 있습니다: ```javascript -const BrowserWindow = require('electron').BrowserWindow; +const {BrowserWindow} = require('electron'); const path = require('path'); -var win = new BrowserWindow({ +let win = new BrowserWindow({ width: 800, height: 600 }); + win.setThumbarButtons([ { - tooltip: "button1", + tooltip: 'button1', icon: path.join(__dirname, 'button1.png'), - click: function() { console.log("button2 clicked"); } + click() { console.log('button2 clicked'); } }, { - tooltip: "button2", + tooltip: 'button2', icon: path.join(__dirname, 'button2.png'), flags:['enabled', 'dismissonclick'], - click: function() { console.log("button2 clicked."); } + click() { console.log('button2 clicked.'); } } ]); ``` @@ -259,8 +259,8 @@ __작업 표시줄 버튼의 프로그래스 바:__ 있습니다: ```javascript -var window = new BrowserWindow({...}); -window.setProgressBar(0.5); +let win = new BrowserWindow({...}); +win.setProgressBar(0.5); ``` ## 작업 표시줄의 아이콘 오버레이 (Windows) @@ -286,8 +286,8 @@ __작업 표시줄 버튼 위의 오버레이:__ API를 사용할 수 있습니다: ```javascript -var window = new BrowserWindow({...}); -window.setOverlayIcon('path/to/overlay.png', 'Description for overlay'); +let win = new BrowserWindow({...}); +win.setOverlayIcon('path/to/overlay.png', 'Description for overlay'); ``` ## 대표 파일 제시 (OS X) @@ -305,9 +305,9 @@ __대표 파일 팝업 메뉴:__ [BrowserWindow.setDocumentEdited][setdocumentedited]를 사용할 수 있습니다: ```javascript -var window = new BrowserWindow({...}); -window.setRepresentedFilename('/etc/passwd'); -window.setDocumentEdited(true); +let win = new BrowserWindow({...}); +win.setRepresentedFilename('/etc/passwd'); +win.setDocumentEdited(true); ``` [addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows diff --git a/docs-translations/ko-KR/tutorial/electron-versioning.md b/docs-translations/ko-KR/tutorial/electron-versioning.md new file mode 100644 index 000000000000..13d83563033d --- /dev/null +++ b/docs-translations/ko-KR/tutorial/electron-versioning.md @@ -0,0 +1,20 @@ +# Electron 버전 관리 + +노련한 Node 개발자라면, `semver` (유의적 버전)에 대해 확실히 알고 있을 것입니다 - +그리고 제공된 의존성 관리 시스템은 고정된 버전 숫자 대신 견고한 가이드라인을 따릅니다. +Electron은 Node와 Chromium에 큰 의존성을 지니고 있는 만큼, 유의적 버전을 그대로 +따르지 않습니다. 따라서 항상 Electron의 특정 버전을 참조해야 합니다. + +버전 숫자는 다음과 같은 규칙으로 올라갑니다: + +* Major: Electron API의 주요 변경 사항을 반영합니다 - 만약 `0.37.0`에서 `1.0.0`로 + 업그레이드하는 경우, 어플리케이션을 업데이트해야 합니다. +* Minor: 주요 Chrome과 Node 버전의 업그레이드를 반영하거나; Electron의 중요한 변경 + 사항을 반영합니다 - 만약 `1.0.0`에서 `1.1.0`로 업그레이드하는 경우, 어플리케이션은 + 여전히 작동하겠지만, 약간의 업데이트가 필요할 수 있습니다. +* Patch: 새로운 기능과 버그 수정을 반영합니다 - 만약 `1.0.0`에서 `1.0.1`로 + 업그레이드하는 경우, 어플리케이션은 잘 작동할 것입니다. + +`electron-prebuilt`를 사용하고 있다면, Electron의 변경 사항을 확실하게 인지하고 +개발자 스스로 업그레이드를 적용하기 위해 고정된 버전 숫자를 사용하는 것을 권장합니다. +(`^1.1.0` 대신 `1.1.0` 사용) diff --git a/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md b/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md index 8fd25a303af0..c4dd2ca0423a 100644 --- a/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md +++ b/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md @@ -20,13 +20,32 @@ Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출 앱 스토어에 어플리케이션을 제출하려면, 먼저 Apple로부터 인증서를 취득해야 합니다. 취득 방법은 웹에서 찾아볼 수 있는 [가이드][nwjs-guide]를 참고하면 됩니다. +### Team ID 얻기 + +어플리케이션에 서명하기 전에, 먼저 개발 계정의 Team ID를 알아야 합니다. Team ID를 +알아보려면 [Apple Developer Center](https://developer.apple.com/account/)에 +로그인한 후, 사이드바의 Membership을 클릭합니다. Team ID는 Membership Information +섹션의 팀 이름 밑에 위치합니다. + ### 앱에 서명하기 -Apple로부터 인증서를 취득했다면, [어플리케이션 배포](application-distribution.md) -문서에 따라 어플리케이션을 패키징한 후 어플리케이션에 서명 합니다. 이 절차는 기본적으로 -다른 프로그램과 같습니다. 하지만 키는 Electron 종속성 파일에 각각 따로 서명 해야 합니다. +준비 작업이 끝난 후, [어플리케이션 배포](application-distribution.md) 문서에 따라 +어플리케이션을 패키징한 후 어플리케이션에 서명 합니다. -첫번째, 다음 두 자격(plist) 파일을 준비합니다. +먼저, Team ID를 키로 가지고 있는 어플리케이션의 `Info.plist`에 `ElectronTeamID` 키를 +추가해야 합니다: + +```xml + + + ... + ElectronTeamID + TEAM_ID + + +``` + +그리고, 다음 두 자격 파일을 준비해야 합니다. `child.plist`: @@ -52,13 +71,16 @@ Apple로부터 인증서를 취득했다면, [어플리케이션 배포](applica com.apple.security.app-sandbox - com.apple.security.temporary-exception.sbpl - (allow mach-lookup (global-name-regex #"^org.chromium.Chromium.rohitfork.[0-9]+$")) + com.apple.security.application-groups + TEAM_ID.your.bundle.id ``` -그리고 다음 스크립트에 따라 어플리케이션에 서명합니다: +`TEAM_ID` 부분은 Team ID로 치환하고, `your.bundle.id` 부분은 어플리케이션의 Bundle +ID로 치환해야 합니다. + +그리고 다음 스크립트를 통해 어플리케이션에 서명합니다: ```bash #!/bin/bash @@ -101,22 +123,6 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES 사용할 수 있습니다. 참고로 업로드하기 전에 [레코드][create-record]를 만들었는지 확인해야 합니다. -### `temporary-exception`의 사용처 설명 - -어플리케이션을 샌드박싱할 때 `temporary-exception` 엔트리가 자격에 추가되며 -[어플리케이션 샌드박스 임시 예외 적용][temporary-exception] 문서에 따라 -왜 이 엔트리가 필요한지 설명해야 합니다: - -> Note: If you request a temporary-exception entitlement, be sure to follow the -guidance regarding entitlements provided on the iTunes Connect website. In -particular, identify the entitlement and corresponding issue number in the App -Sandbox Entitlement Usage Information section in iTunes Connect and explain why -your app needs the exception. - -아마 제출하려는 어플리케이션이 Chromium 브라우저를 기반으로 만들어졌고, 또한 -멀티-프로세스 구조를 위해 Mach 포트를 사용하는 것도 설명해야 할 수 있습니다. 하지만 -여전히 이러한 문제 때문에 어플리케이션 심사에 실패할 수 있습니다. - ### 어플리케이션을 심사에 제출 위 과정을 마치면 [어플리케이션을 심사를 위해 제출][submit-for-review]할 수 있습니다. diff --git a/docs-translations/ko-KR/tutorial/online-offline-events.md b/docs-translations/ko-KR/tutorial/online-offline-events.md index 698544e83b6c..de2e10f9efe9 100644 --- a/docs-translations/ko-KR/tutorial/online-offline-events.md +++ b/docs-translations/ko-KR/tutorial/online-offline-events.md @@ -6,13 +6,12 @@ _main.js_ ```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; +const {app, BrowserWindow} = require('electron'); -var onlineStatusWindow; -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); +let onlineStatusWindow; + +app.on('ready', () => { + onlineStatusWindow = new BrowserWindow({width: 0, height: 0, show: false}); onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); }); ``` @@ -24,7 +23,7 @@ _online-status.html_ @@ -53,7 +53,7 @@ As of 0.37, you can use built-in modules. ```javascript -const { app, BrowserWindow } = require('electron'); +const {app, BrowserWindow} = require('electron'); ``` If you need the entire `electron` module, you can require it and then using @@ -61,7 +61,7 @@ destructuring to access the individual modules from `electron`. ```javascript const electron = require('electron'); -const { app, BrowserWindow } = electron; +const {app, BrowserWindow} = electron; ``` This is equivalent to the following code: @@ -72,25 +72,5 @@ const app = electron.app; const BrowserWindow = electron.BrowserWindow; ``` -## Disable old styles of using built-in modules - -Before v0.35.0, all built-in modules have to be used in the form of -`require('module-name')`, though it has [many disadvantages][issue-387], we are -still supporting it for compatibility with old apps. - -To disable the old styles completely, you can set the -`ELECTRON_HIDE_INTERNAL_MODULES` environment variable: - -```javascript -process.env.ELECTRON_HIDE_INTERNAL_MODULES = 'true' -``` - -Or call the `hideInternalModules` API: - -```javascript -require('electron').hideInternalModules() -``` - [gui]: https://en.wikipedia.org/wiki/Graphical_user_interface [destructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment -[issue-387]: https://github.com/electron/electron/issues/387 diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index cafb1d3745f3..8f4dc8993852 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -13,12 +13,16 @@ This method returns `true` if the system is in Dark Mode, and `false` otherwise. * `event` String * `callback` Function -Subscribes to native notifications of OS X, `callback` will be called when the -corresponding `event` happens. The `id` of the subscriber is returned, which can -be used to unsubscribe the `event`. +Subscribes to native notifications of OS X, `callback` will be called with +`callback(event, userInfo)` when the corresponding `event` happens. The +`userInfo` is an Object that contains the user information dictionary sent +along with the notification. + +The `id` of the subscriber is returned, which can be used to unsubscribe the +`event`. Under the hood this API subscribes to `NSDistributedNotificationCenter`, -possible values of `event` are: +example values of `event` are: * `AppleInterfaceThemeChangedNotification` * `AppleAquaColorVariantChanged` @@ -56,7 +60,7 @@ An example of using it to determine if you should create a transparent window or not (transparent windows won't work correctly when DWM composition is disabled): ```javascript -let browserOptions = { width: 1000, height: 800 }; +let browserOptions = {width: 1000, height: 800}; // Make the window transparent only if the platform supports it. if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) { diff --git a/docs/api/tray.md b/docs/api/tray.md index eaf3f6c42bbd..4c4891ef8960 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -3,19 +3,16 @@ > Add icons and context menus to the system's notification area. ```javascript -const electron = require('electron'); -const app = electron.app; -const Menu = electron.Menu; -const Tray = electron.Tray; +const {app, Menu, Tray} = require('electron'); let appIcon = null; app.on('ready', () => { appIcon = new Tray('/path/to/my/icon'); const contextMenu = Menu.buildFromTemplate([ - { label: 'Item1', type: 'radio' }, - { label: 'Item2', type: 'radio' }, - { label: 'Item3', type: 'radio', checked: true }, - { label: 'Item4', type: 'radio' } + {label: 'Item1', type: 'radio'}, + {label: 'Item2', type: 'radio'}, + {label: 'Item3', type: 'radio', checked: true}, + {label: 'Item4', type: 'radio'} ]); appIcon.setToolTip('This is my application.'); appIcon.setContextMenu(contextMenu); @@ -32,6 +29,7 @@ __Platform limitations:__ * When app indicator is used on Linux, the `click` event is ignored. * On Linux in order for changes made to individual `MenuItem`s to take effect, you have to call `setContextMenu` again. For example: +* On Windows it is recommended to use `ICO` icons to get best visual effects. ```javascript contextMenu.items[2].checked = false; diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index f304ad98d7b1..03d573c59c61 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -9,10 +9,10 @@ the [`BrowserWindow`](browser-window.md) object. An example of accessing the `webContents` object: ```javascript -const { BrowserWindow } = require('electron'); +const {BrowserWindow} = require('electron'); let win = new BrowserWindow({width: 800, height: 1500}); -win.loadURL("http://github.com"); +win.loadURL('http://github.com'); let webContents = win.webContents; ``` @@ -39,6 +39,8 @@ Returns: This event is like `did-finish-load` but emitted when the load failed or was cancelled, e.g. `window.stop()` is invoked. The full list of error codes and their meaning is available [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h). +Note that redirect responses will emit `errorCode` -3; you may want to ignore +that error explicitly. ### Event: 'did-frame-finish-load' @@ -317,54 +319,96 @@ Returns: * `x` Integer - x coodinate * `y` Integer - y coodinate * `linkURL` String - URL of the link that encloses the node the context menu -was invoked on. + was invoked on. * `linkText` String - Text associated with the link. May be an empty -string if the contents of the link are an image. + string if the contents of the link are an image. * `pageURL` String - URL of the top level page that the context menu was -invoked on. + invoked on. * `frameURL` String - URL of the subframe that the context menu was invoked -on. + on. * `srcURL` String - Source URL for the element that the context menu -was invoked on. Elements with source URLs are images, audio and video. + was invoked on. Elements with source URLs are images, audio and video. * `mediaType` String - Type of the node the context menu was invoked on. Can -be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. - * `mediaFlags` Object - Parameters for the media element the context menu was -invoked on. - * `inError` - Boolean - * `isPaused` - Boolean - * `isMuted` - Boolean - * `hasAudio` - Boolean - * `isLooping` - Boolean - * `isControlsVisible` - Boolean - * `canToggleControls` - Boolean - * `canRotate` - Boolean + be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. * `hasImageContent` Boolean - Wether the context menu was invoked on an image -which has non-empty contents. + which has non-empty contents. * `isEditable` Boolean - Wether the context is editable. - * `editFlags` Object - These flags indicate wether the renderer believes it is -able to perform the corresponding action. - * `canUndo` - Boolean - * `canRedo` - Boolean - * `canCut` - Boolean - * `canCopy` - Boolean - * `canPaste` - Boolean - * `canDelete` - Boolean - * `canSelectAll` - Boolean * `selectionText` String - Text of the selection that the context menu was -invoked on. + invoked on. * `titleText` String - Title or alt text of the selection that the context -was invoked on. + was invoked on. * `misspelledWord` String - The misspelled word under the cursor, if any. * `frameCharset` String - The character encoding of the frame on which the -menu was invoked. + menu was invoked. * `inputFieldType` String - If the context menu was invoked on an input -field, the type of that field. Possible values are `none`, `plainText`, -`password`, `other`. + field, the type of that field. Possible values are `none`, `plainText`, + `password`, `other`. * `menuSourceType` String - Input source that invoked the context menu. -Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`. + * `mediaFlags` Object - The flags for the media element the context menu was + invoked on. See more about this below. + * `editFlags` Object - These flags indicate wether the renderer believes it is + able to perform the corresponding action. See more about this below. + +The `mediaFlags` is an object with the following properties: + * `inError` Boolean - Wether the media element has crashed. + * `isPaused` Boolean - Wether the media element is paused. + * `isMuted` Boolean - Wether the media element is muted. + * `hasAudio` Boolean - Wether the media element has audio. + * `isLooping` Boolean - Wether the media element is looping. + * `isControlsVisible` Boolean - Wether the media element's controls are + visible. + * `canToggleControls` Boolean - Wether the media element's controls are + toggleable. + * `canRotate` Boolean - Wether the media element can be rotated. + +The `editFlags` is an object with the following properties: + * `canUndo` Boolean - Wether the renderer believes it can undo. + * `canRedo` Boolean - Wether the renderer believes it can redo. + * `canCut` Boolean - Wether the renderer believes it can cut. + * `canCopy` Boolean - Wether the renderer believes it can copy + * `canPaste` Boolean - Wether the renderer believes it can paste. + * `canDelete` Boolean - Wether the renderer believes it can delete. + * `canSelectAll` Boolean - Wether the renderer believes it can select all. Emitted when there is a new context menu that needs to be handled. +### Event: 'select-bluetooth-device' + +Returns: + +* `event` Event +* `devices` [Objects] + * `deviceName` String + * `deviceId` String +* `callback` Function + * `deviceId` String + +Emitted when bluetooth device needs to be selected on call to +`navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api +`webBluetooth` should be enabled. If `event.preventDefault` is not called, +first available device will be selected. `callback` should be called with +`deviceId` to be selected, passing empty string to `callback` will +cancel the request. + +```javacript +app.commandLine.appendSwitch('enable-web-bluetooth') + +app.on('ready', () => { + webContents.on('select-bluetooth-device', (event, deviceList, callback) => { + event.preventDefault() + let result = deviceList.find((device) => { + return device.deviceName === 'test' + }) + if (!result) { + callback('') + } else { + callback(result.deviceId) + } + }) +}) +``` + ## Instance Methods The `webContents` object has the following instance methods: @@ -382,8 +426,8 @@ e.g. the `http://` or `file://`. If the load should bypass http cache then use the `pragma` header to achieve it. ```javascript -const options = {"extraHeaders" : "pragma: no-cache\n"} -webContents.loadURL(url, options) +const options = {extraHeaders: 'pragma: no-cache\n'}; +webContents.loadURL(url, options); ``` ### `webContents.downloadURL(url)` @@ -399,7 +443,7 @@ Returns URL of the current web page. ```javascript let win = new BrowserWindow({width: 800, height: 600}); -win.loadURL("http://github.com"); +win.loadURL('http://github.com'); let currentURL = win.webContents.getURL(); ``` @@ -601,12 +645,12 @@ the request can be obtained by subscribing to Stops any `findInPage` request for the `webContents` with the provided `action`. ```javascript -webContents.on('found-in-page', function(event, result) { +webContents.on('found-in-page', (event, result) => { if (result.finalUpdate) - webContents.stopFindInPage("clearSelection"); + webContents.stopFindInPage('clearSelection'); }); -const requestId = webContents.findInPage("api"); +const requestId = webContents.findInPage('api'); ``` ### `webContents.hasServiceWorker(callback)` @@ -647,7 +691,8 @@ size. * `marginsType` Integer - Specifies the type of margins to use. Uses 0 for default margin, 1 for no margin, and 2 for minimum margin. * `pageSize` String - Specify page size of the generated PDF. Can be `A3`, - `A4`, `A5`, `Legal`, `Letter` and `Tabloid`. + `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` + and `width` in microns. * `printBackground` Boolean - Whether to print CSS backgrounds. * `printSelectionOnly` Boolean - Whether to print selection only. * `landscape` Boolean - `true` for landscape, `false` for portrait. @@ -670,8 +715,10 @@ By default, an empty `options` will be regarded as: } ``` +An example of `webContents.printToPDF`: + ```javascript -const { BrowserWindow } = require('electron'); +const {BrowserWindow} = require('electron'); const fs = require('fs'); let win = new BrowserWindow({width: 800, height: 600}); @@ -698,8 +745,8 @@ Adds the specified path to DevTools workspace. Must be used after DevTools creation: ```javascript -mainWindow.webContents.on('devtools-opened', function() { - mainWindow.webContents.addWorkSpace(__dirname); +win.webContents.on('devtools-opened', () => { + win.webContents.addWorkSpace(__dirname); }); ``` @@ -761,13 +808,13 @@ An example of sending messages from the main process to the renderer process: ```javascript // In the main process. -let mainWindow = null; +let win = null; app.on('ready', () => { - mainWindow = new BrowserWindow({width: 800, height: 600}); - mainWindow.loadURL(`file://${__dirname}/index.html`); - mainWindow.webContents.on('did-finish-load', () => { - mainWindow.webContents.send('ping', 'whoooooooh!'); + win = new BrowserWindow({width: 800, height: 600}); + win.loadURL(`file://${__dirname}/index.html`); + win.webContents.on('did-finish-load', () => { + win.webContents.send('ping', 'whoooooooh!'); }); }); ``` @@ -885,7 +932,7 @@ End subscribing for frame presentation events. * `HTMLOnly` - Save only the HTML of the page. * `HTMLComplete` - Save complete-html page. * `MHTML` - Save complete-html page as MHTML. -* `callback` Function - `function(error) {}`. +* `callback` Function - `(error) => {}`. * `error` Error Returns true if the process of saving page has been initiated successfully. @@ -896,7 +943,7 @@ win.loadURL('https://github.com'); win.webContents.on('did-finish-load', () => { win.webContents.savePage('/tmp/test.html', 'HTMLComplete', (error) => { if (!error) - console.log("Save page successfully"); + console.log('Save page successfully'); }); }); ``` @@ -905,6 +952,10 @@ win.webContents.on('did-finish-load', () => { `WebContents` objects also have the following properties: +### `webContents.id` + +The unique ID of this WebContents. + ### `webContents.session` Returns the [session](session.md) object used by this webContents. @@ -926,23 +977,23 @@ Debugger API serves as an alternate transport for [remote debugging protocol][rd ```javascript try { - win.webContents.debugger.attach("1.1"); + win.webContents.debugger.attach('1.1'); } catch(err) { - console.log("Debugger attach failed : ", err); + console.log('Debugger attach failed : ', err); }; win.webContents.debugger.on('detach', (event, reason) => { - console.log("Debugger detached due to : ", reason); + console.log('Debugger detached due to : ', reason); }); win.webContents.debugger.on('message', (event, method, params) => { - if (method === "Network.requestWillBeSent") { - if (params.request.url === "https://www.github.com") + if (method === 'Network.requestWillBeSent') { + if (params.request.url === 'https://www.github.com') win.webContents.debugger.detach(); } -}) +}); -win.webContents.debugger.sendCommand("Network.enable"); +win.webContents.debugger.sendCommand('Network.enable'); ``` #### `webContents.debugger.attach([protocolVersion])` diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index dcd595d3d973..a933b8b48138 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -5,7 +5,7 @@ An example of zooming current page to 200%. ```javascript -const { webFrame } = require('electron'); +const {webFrame} = require('electron'); webFrame.setZoomFactor(2); ``` @@ -58,8 +58,8 @@ whether the word passed is correctly spelled. An example of using [node-spellchecker][spellchecker] as provider: ```javascript -webFrame.setSpellCheckProvider("en-US", true, { - spellCheck: function(text) { +webFrame.setSpellCheckProvider('en-US', true, { + spellCheck(text) { return !(require('spellchecker').isMisspelled(text)); } }); @@ -106,4 +106,43 @@ In the browser window some HTML APIs like `requestFullScreen` can only be invoked by a gesture from the user. Setting `userGesture` to `true` will remove this limitation. +### `webFrame.getResourceUsage()` + +Returns an object describing usage information of Blink's internal memory +caches. + +```javascript +console.log(webFrame.getResourceUsage()) +``` + +This will generate: + +```javascript +{ + images: { + count: 22, + size: 2549, + liveSize: 2542, + decodedSize: 478, + purgedSize: 0, + purgeableSize: 0 + }, + cssStyleSheets: { /* same with "images" */ }, + xslStyleSheets: { /* same with "images" */ }, + fonts: { /* same with "images" */ }, + other: { /* same with "images" */ }, +} +``` + +### `webFrame.clearCache()` + +Attempts to free memory that is no longer being used (like images from a +previous navigation). + +Note that blindly calling this method probably makes Electron slower since it +will have to refill these emptied caches, you should only call it if an event +in your app has occured that makes you think your page is actually using less +memory (i.e. you have navigated from a super heavy page to a mostly empty one, +and intend to stay there). + [spellchecker]: https://github.com/atom/node-spellchecker diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index a7410e146ae7..f99bb4fdb5a1 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -1,4 +1,4 @@ -# The `` tag +# `` Tag > Display external web content in an isolated frame and process. @@ -12,6 +12,9 @@ app. It doesn't have the same permissions as your web page and all interactions between your app and embedded content will be asynchronous. This keeps your app safe from the embedded content. +For security purpose, `webview` can only be used in `BrowserWindow`s that have +`nodeIntegration` enabled. + ## Example To embed a web page in your app, add the `webview` tag to your app's embedder @@ -37,15 +40,15 @@ and displays a "loading..." message during the load time: const loadstart = () => { indicator.innerText = 'loading...'; - } + }; const loadstop = () => { indicator.innerText = ''; - } + }; webview.addEventListener('did-start-loading', loadstart); webview.addEventListener('did-stop-loading', loadstop); - } + }; ``` @@ -168,7 +171,7 @@ page is loaded, use the `setUserAgent` method to change the user agent. If "on", the guest page will have web security disabled. -### partition +### `partition` ```html @@ -213,7 +216,7 @@ The `webview` tag has the following methods: **Example** ```javascript -webview.addEventListener("dom-ready", () => { +webview.addEventListener('dom-ready', () => { webview.openDevTools(); }); ``` @@ -442,8 +445,8 @@ obtained by subscribing to [`found-in-page`](web-view-tag.md#event-found-in-page * `action` String - Specifies the action to take place when ending [`.findInPage`](web-view-tag.md#webviewtagfindinpage) request. - * `clearSelection` - Translate the selection into a normal selection. - * `keepSelection` - Clear the selection. + * `clearSelection` - Clear the selection. + * `keepSelection` - Translate the selection into a normal selection. * `activateSelection` - Focus and click the selection node. Stops any `findInPage` request for the `webview` with the provided `action`. @@ -454,7 +457,7 @@ Prints `webview`'s web page. Same with `webContents.print([options])`. ### `.printToPDF(options, callback)` -Prints webview's web page as PDF, Same with `webContents.printToPDF(options, callback)` +Prints `webview`'s web page as PDF, Same with `webContents.printToPDF(options, callback)` ### `.send(channel[, arg1][, arg2][, ...])` @@ -600,7 +603,7 @@ The following example code forwards all log messages to the embedder's console without regard for log level or other properties. ```javascript -webview.addEventListener('console-message', function(e) { +webview.addEventListener('console-message', (e) => { console.log('Guest page logged a message:', e.message); }); ``` @@ -620,12 +623,12 @@ Fired when a result is available for [`webview.findInPage`](web-view-tag.md#webviewtagfindinpage) request. ```javascript -webview.addEventListener('found-in-page', function(e) { +webview.addEventListener('found-in-page', (e) => { if (e.result.finalUpdate) - webview.stopFindInPage("keepSelection"); + webview.stopFindInPage('keepSelection'); }); -const rquestId = webview.findInPage("test"); +const requestId = webview.findInPage('test'); ``` ### Event: 'new-window' @@ -644,7 +647,7 @@ Fired when the guest page attempts to open a new browser window. The following example code opens the new url in system's default browser. ```javascript -const { shell } = require('electron'); +const {shell} = require('electron'); webview.addEventListener('new-window', (e) => { const protocol = require('url').parse(e.url).protocol; @@ -732,7 +735,7 @@ webview.send('ping'); ```javascript // In guest page. -var { ipcRenderer } = require('electron'); +const {ipcRenderer} = require('electron'); ipcRenderer.on('ping', () => { ipcRenderer.sendToHost('pong'); }); diff --git a/docs/api/window-open.md b/docs/api/window-open.md index abb0760f121e..b615a4b6488e 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -1,4 +1,4 @@ -# The `window.open` function +# `window.open` Function > Open a new window and load a URL. @@ -63,6 +63,10 @@ Evaluates the code in the child window. Focuses the child window (brings the window to front). +### `BrowserWindowProxy.print()` + +Invokes the print dialog on the child window. + ### `BrowserWindowProxy.postMessage(message, targetOrigin)` * `message` String diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 3f94a18393cf..b3c2c4573462 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -5,8 +5,8 @@ Follow the guidelines below for building Electron on Windows. ## Prerequisites * Windows 7 / Server 2008 R2 or higher -* Visual Studio 2013 with Update 4 - [download VS 2013 Community Edition for - free](https://www.visualstudio.com/news/vs2013-community-vs). +* Visual Studio 2015 - [download VS 2015 Community Edition for + free](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) * [Python 2.7](http://www.python.org/download/releases/2.7/) * [Node.js](http://nodejs.org/download/) * [Git](http://git-scm.com) @@ -22,8 +22,7 @@ building with Visual Studio will come in the future. **Note:** Even though Visual Studio is not used for building, it's still **required** because we need the build toolchains it provides. -**Note:** Visual Studio 2015 will not work. Please make sure to get MSVS -**2013**. +**Note:** While older versions of Electron required Visual Studio 2013, Electron 1.1 and later does require Visual Studio 2015. ## Getting the Code @@ -99,7 +98,7 @@ $ python script\test.py -R ### Command xxxx not found If you encountered an error like `Command xxxx not found`, you may try to use -the `VS2012 Command Prompt` console to execute the build scripts. +the `VS2015 Command Prompt` console to execute the build scripts. ### Fatal internal compiler error: C1001 @@ -148,4 +147,4 @@ $ mkdir ~\AppData\Roaming\npm ### node-gyp is not recognized as an internal or external command You may get this error if you are using Git Bash for building, you should use -PowerShell or VS2012 Command Prompt instead. +PowerShell or VS2015 Command Prompt instead. diff --git a/docs/development/debug-instructions-windows.md b/docs/development/debug-instructions-windows.md index 509970237d66..b2d33473934a 100644 --- a/docs/development/debug-instructions-windows.md +++ b/docs/development/debug-instructions-windows.md @@ -1,4 +1,4 @@ -# Debugging Electron in Windows +# Debugging on Windows If you experience crashes or issues in Electron that you believe are not caused by your JavaScript application, but instead by Electron itself, debugging can diff --git a/docs/development/source-code-directory-structure.md b/docs/development/source-code-directory-structure.md index 27cf36b9d4e7..cc74fe69427a 100644 --- a/docs/development/source-code-directory-structure.md +++ b/docs/development/source-code-directory-structure.md @@ -11,38 +11,38 @@ to understand the source code better. ``` Electron -├── atom - C++ source code. -| ├── app - System entry code. -| ├── browser - The frontend including the main window, UI, and all of the +├── atom/ - C++ source code. +| ├── app/ - System entry code. +| ├── browser/ - The frontend including the main window, UI, and all of the | | main process things. This talks to the renderer to manage web pages. -| | ├── ui - Implementation of UI stuff for different platforms. -| | | ├── cocoa - Cocoa specific source code. -| | | ├── gtk - GTK+ specific source code. -| | | └── win - Windows GUI specific source code. -| | ├── api - The implementation of the main process APIs. -| | ├── net - Network related code. -| | ├── mac - Mac specific Objective-C source code. -| | └── resources - Icons, platform-dependent files, etc. -| ├── renderer - Code that runs in renderer process. -| | └── api - The implementation of renderer process APIs. -| └── common - Code that used by both the main and renderer processes, +| | ├── ui/ - Implementation of UI stuff for different platforms. +| | | ├── cocoa/ - Cocoa specific source code. +| | | ├── win/ - Windows GUI specific source code. +| | | └── x/ - X11 specific source code. +| | ├── api/ - The implementation of the main process APIs. +| | ├── net/ - Network related code. +| | ├── mac/ - Mac specific Objective-C source code. +| | └── resources/ - Icons, platform-dependent files, etc. +| ├── renderer/ - Code that runs in renderer process. +| | └── api/ - The implementation of renderer process APIs. +| └── common/ - Code that used by both the main and renderer processes, | including some utility functions and code to integrate node's message | loop into Chromium's message loop. -| └── api - The implementation of common APIs, and foundations of +| └── api/ - The implementation of common APIs, and foundations of | Electron's built-in modules. -├── chromium_src - Source code that copied from Chromium. -├── default_app - The default page to show when Electron is started without +├── chromium_src/ - Source code that copied from Chromium. +├── default_app/ - The default page to show when Electron is started without | providing an app. -├── docs - Documentations. -├── lib - JavaScript source code. -| ├── browser - Javascript main process initialization code. -| | └── api - Javascript API implementation. -| ├── common - JavaScript used by both the main and renderer processes -| | └── api - Javascript API implementation. -| └── renderer - Javascript renderer process initialization code. -| └── api - Javascript API implementation. -├── spec - Automatic tests. -├── atom.gyp - Building rules of Electron. +├── docs/ - Documentations. +├── lib/ - JavaScript source code. +| ├── browser/ - Javascript main process initialization code. +| | └── api/ - Javascript API implementation. +| ├── common/ - JavaScript used by both the main and renderer processes +| | └── api/ - Javascript API implementation. +| └── renderer/ - Javascript renderer process initialization code. +| └── api/ - Javascript API implementation. +├── spec/ - Automatic tests. +├── electron.gyp - Building rules of Electron. └── common.gypi - Compiler specific settings and building rules for other components like `node` and `breakpad`. ``` @@ -66,7 +66,7 @@ Electron ## Keeping Git Submodules Up to Date The Electron repository has a few vendored dependencies, found in the -[/vendor](/vendor) directory. Occasionally you might see a message like this +[/vendor][vendor] directory. Occasionally you might see a message like this when running `git status`: ```sh @@ -89,3 +89,5 @@ in your `~/.gitconfig` file: [alias] su = submodule update --init --recursive ``` + +[vendor]: https://github.com/electron/electron/tree/master/vendor diff --git a/docs/faq/electron-faq.md b/docs/faq/electron-faq.md index c690b7ed3dc0..cefc5a54a2c7 100644 --- a/docs/faq/electron-faq.md +++ b/docs/faq/electron-faq.md @@ -3,11 +3,14 @@ ## When will Electron upgrade to latest Chrome? The Chrome version of Electron is usually bumped within one or two weeks after -a new stable Chrome version gets released. +a new stable Chrome version gets released. This estimate is not guaranteed and +depends on the amount of work involved with upgrading. -Also we only use stable channel of Chrome. If an important fix is in beta or dev +Only the stable channel of Chrome is used. If an important fix is in beta or dev channel, we will back-port it. +For more information, please see the [security introduction](../tutorial/security.md). + ## When will Electron upgrade to latest Node.js? When a new version of Node.js gets released, we usually wait for about a month @@ -62,7 +65,7 @@ code from this: ```javascript app.on('ready', () => { const tray = new Tray('/path/to/icon.png'); -}) +}); ``` to this: @@ -71,7 +74,7 @@ to this: let tray = null; app.on('ready', () => { tray = new Tray('/path/to/icon.png'); -}) +}); ``` ## I can not use jQuery/RequireJS/Meteor/AngularJS in Electron. @@ -84,7 +87,7 @@ To solve this, you can turn off node integration in Electron: ```javascript // In the main process. -let mainWindow = new BrowserWindow({ +let win = new BrowserWindow({ webPreferences: { nodeIntegration: false } diff --git a/docs/styleguide.md b/docs/styleguide.md index cd68414ac240..a34889d2ca34 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -93,6 +93,6 @@ this event it might look something like this: ```javascript Alarm.on('wake-up', (time) => { - console.log(time) -}) + console.log(time); +}); ``` diff --git a/docs/tutorial/application-distribution.md b/docs/tutorial/application-distribution.md index 313c924e881c..4d3e12db75fc 100644 --- a/docs/tutorial/application-distribution.md +++ b/docs/tutorial/application-distribution.md @@ -30,7 +30,7 @@ your distribution to deliver to final users. ## Packaging Your App into a File Apart from shipping your app by copying all of its source files, you can also -package your app into an [asar](https://github.com/atom/asar) archive to avoid +package your app into an [asar](https://github.com/electron/asar) archive to avoid exposing your app's source code to users. To use an `asar` archive to replace the `app` folder, you need to rename the @@ -102,6 +102,14 @@ MyApp.app/Contents You can rename the `electron` executable to any name you like. +## Packaging Tools + +Apart from packaging your app manually, you can also choose to use third party +packaging tools to do the work for you: + +* [electron-packager](https://github.com/maxogden/electron-packager) +* [electron-builder](https://github.com/loopline-systems/electron-builder) + ## Rebranding by Rebuilding Electron from Source It is also possible to rebrand Electron by changing the product name and @@ -118,10 +126,49 @@ This task will automatically handle editing the `.gyp` file, building from source, then rebuilding your app's native Node modules to match the new executable name. -## Packaging Tools +### Creating a Custom Electron Fork -Apart from packaging your app manually, you can also choose to use third party -packaging tools to do the work for you: +Creating a custom fork of Electron is almost certainly not something you will +need to do in order to build your app, even for "Production Level" applications. +Using a tool such as `electron-packager` or `electron-builder` will allow you to +"Rebrand" Electron without having to do these steps. -* [electron-packager](https://github.com/maxogden/electron-packager) -* [electron-builder](https://github.com/loopline-systems/electron-builder) +You need to fork Electron when you have custom C++ code that you have patched +directly into Electron, that either cannot be upstreamed, or has been rejected +from the official version. As maintainers of Electron, we very much would like +to make your scenario work, so please try as hard as you can to get your changes +into the official version of Electron, it will be much much easier on you, and +we appreciate your help. + +#### Creating a Custom Release with surf-build + +1. Install [Surf](https://github.com/surf-build/surf), via npm: + `npm install -g surf-build@latest` + +2. Create a new S3 bucket and create the following empty directory structure: + +``` +- atom-shell/ + - symbols/ + - dist/ +``` + +3. Set the following Environment Variables: + + * `ELECTRON_GITHUB_TOKEN` - a token that can create releases on GitHub + * `ELECTRON_S3_ACCESS_KEY`, `ELECTRON_S3_BUCKET`, `ELECTRON_S3_SECRET_KEY` - + the place where you'll upload node.js headers as well as symbols + * `ELECTRON_RELEASE` - Set to `true` and the upload part will run, leave unset + and `surf-build` will just do CI-type checks, appropriate to run for every + pull request. + * `CI` - Set to `true` or else it will fail + * `GITHUB_TOKEN` - set it to the same as `ELECTRON_GITHUB_TOKEN` + * `SURF_TEMP` - set to `C:\Temp` on Windows to prevent path too long issues + * `TARGET_ARCH` - set to `ia32` or `x64` + +4. In `script/upload.py`, you _must_ set `ELECTRON_REPO` to your fork (`MYORG/electron`), + especially if you are a contributor to Electron proper. + +5. `surf-build -r https://github.com/MYORG/electron -s YOUR_COMMIT -n 'surf-PLATFORM-ARCH'` + +6. Wait a very, very long time for the build to complete. diff --git a/docs/tutorial/application-packaging.md b/docs/tutorial/application-packaging.md index 257119a573a6..8a7f8701610f 100644 --- a/docs/tutorial/application-packaging.md +++ b/docs/tutorial/application-packaging.md @@ -71,7 +71,7 @@ require('/path/to/example.asar/dir/module.js'); You can also display a web page in an `asar` archive with `BrowserWindow`: ```javascript -const { BrowserWindow } = require('electron'); +const {BrowserWindow} = require('electron'); let win = new BrowserWindow({width: 800, height: 600}); win.loadURL('file:///path/to/example.asar/static/index.html'); ``` @@ -85,7 +85,7 @@ For example, to get a file with `$.get`: ```html ` + }).join('') + const html = new Buffer(`${scripts}`) + + const contents = webContents.create({ + commandLineSwitches: ['--background-page'] + }) + backgroundPages[manifest.extensionId] = { html: html, webContents: contents } + contents.loadURL(url.format({ + protocol: 'chrome-extension', + slashes: true, + hostname: manifest.extensionId, + pathname: '_generated_background_page.html' + })) +} + +const removeBackgroundPages = function (manifest) { + if (!backgroundPages[manifest.extensionId]) return + + backgroundPages[manifest.extensionId].webContents.destroy() + delete backgroundPages[manifest.extensionId] +} + +// Dispatch tabs events. +const hookWindowForTabEvents = function (win) { + const tabId = win.webContents.id + for (const page of objectValues(backgroundPages)) { + page.webContents.sendToAll('CHROME_TABS_ONCREATED', tabId) + } + + win.once('closed', () => { + for (const page of objectValues(backgroundPages)) { + page.webContents.sendToAll('CHROME_TABS_ONREMOVED', tabId) + } + }) +} + +// Handle the chrome.* API messages. +let nextId = 0 + +ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) { + const page = backgroundPages[extensionId] + if (!page) { + console.error(`Connect to unkown extension ${extensionId}`) + return + } + + const portId = ++nextId + event.returnValue = {tabId: page.webContents.id, portId: portId} + + event.sender.once('render-view-deleted', () => { + if (page.webContents.isDestroyed()) return + page.webContents.sendToAll(`CHROME_PORT_DISCONNECT_${portId}`) + }) + page.webContents.sendToAll(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, event.sender.id, portId, connectInfo) +}) + +ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message) { + const page = backgroundPages[extensionId] + if (!page) { + console.error(`Connect to unkown extension ${extensionId}`) + return + } + + page.webContents.sendToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, event.sender.id, message) +}) + +ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBackgroundPage, message) { + const contents = webContents.fromId(tabId) + if (!contents) { + console.error(`Sending message to unkown tab ${tabId}`) + return + } + + const senderTabId = isBackgroundPage ? null : event.sender.id + + contents.sendToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, senderTabId, message) +}) + +ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, extensionId, details) { + const contents = webContents.fromId(tabId) + if (!contents) { + console.error(`Sending message to unkown tab ${tabId}`) + return + } + + let code, url + if (details.file) { + const manifest = manifestMap[extensionId] + code = String(fs.readFileSync(path.join(manifest.srcDirectory, details.file))) + url = `chrome-extension://${extensionId}${details.file}` + } else { + code = details.code + url = `chrome-extension://${extensionId}/${String(Math.random()).substr(2, 8)}.js` + } + + contents.send('CHROME_TABS_EXECUTESCRIPT', event.sender.id, requestId, extensionId, url, code) +}) + +// Transfer the content scripts to renderer. +const contentScripts = {} + +const injectContentScripts = function (manifest) { + if (contentScripts[manifest.name] || !manifest.content_scripts) return + + const readArrayOfFiles = function (relativePath) { + return { + url: `chrome-extension://${manifest.extensionId}/${relativePath}`, + code: String(fs.readFileSync(path.join(manifest.srcDirectory, relativePath))) + } + } + + const contentScriptToEntry = function (script) { + return { + matches: script.matches, + js: script.js.map(readArrayOfFiles), + runAt: script.run_at || 'document_idle' + } + } + + try { + const entry = { + extensionId: manifest.extensionId, + contentScripts: manifest.content_scripts.map(contentScriptToEntry) + } + contentScripts[manifest.name] = renderProcessPreferences.addEntry(entry) + } catch (e) { + console.error('Failed to read content scripts', e) + } +} + +const removeContentScripts = function (manifest) { + if (!contentScripts[manifest.name]) return + + renderProcessPreferences.removeEntry(contentScripts[manifest.name]) + delete contentScripts[manifest.name] +} + +// Transfer the |manifest| to a format that can be recognized by the +// |DevToolsAPI.addExtensions|. +const manifestToExtensionInfo = function (manifest) { + return { + startPage: manifest.startPage, + srcDirectory: manifest.srcDirectory, + name: manifest.name, + exposeExperimentalAPIs: true + } +} + +// Load the extensions for the window. +const loadExtension = function (manifest) { + startBackgroundPages(manifest) + injectContentScripts(manifest) +} + +const loadDevToolsExtensions = function (win, manifests) { + if (!win.devToolsWebContents) return + + manifests.forEach(loadExtension) + + const extensionInfoArray = manifests.map(manifestToExtensionInfo) + win.devToolsWebContents.executeJavaScript(`DevToolsAPI.addExtensions(${JSON.stringify(extensionInfoArray)})`) +} + +// The persistent path of "DevTools Extensions" preference file. +let loadedExtensionsPath = null app.on('will-quit', function () { try { - loadedExtensions = Object.keys(extensionInfoMap).map(function (key) { - return extensionInfoMap[key].srcDirectory + const loadedExtensions = objectValues(manifestMap).map(function (manifest) { + return manifest.srcDirectory }) if (loadedExtensions.length > 0) { try { @@ -70,76 +237,78 @@ app.on('will-quit', function () { // We can not use protocol or BrowserWindow until app is ready. app.once('ready', function () { - var BrowserWindow, chromeExtensionHandler, i, init, len, protocol, srcDirectory - protocol = electron.protocol - BrowserWindow = electron.BrowserWindow + // The chrome-extension: can map a extension URL request to real file path. + const chromeExtensionHandler = function (request, callback) { + const parsed = url.parse(request.url) + if (!parsed.hostname || !parsed.path) return callback() + + const manifest = manifestMap[parsed.hostname] + if (!manifest) return callback() + + if (parsed.path === '/_generated_background_page.html' && + backgroundPages[parsed.hostname]) { + return callback({ + mimeType: 'text/html', + data: backgroundPages[parsed.hostname].html + }) + } + + fs.readFile(path.join(manifest.srcDirectory, parsed.path), function (err, content) { + if (err) { + return callback(-6) // FILE_NOT_FOUND + } else { + return callback(content) + } + }) + } + protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) { + if (error) { + console.error(`Unable to register chrome-extension protocol: ${error}`) + } + }) // Load persisted extensions. loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions') try { - loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath)) - if (!Array.isArray(loadedExtensions)) { - loadedExtensions = [] - } - - // Preheat the extensionInfo cache. - for (i = 0, len = loadedExtensions.length; i < len; i++) { - srcDirectory = loadedExtensions[i] - getExtensionInfoFromPath(srcDirectory) + const loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath)) + if (Array.isArray(loadedExtensions)) { + for (const srcDirectory of loadedExtensions) { + // Start background pages and set content scripts. + const manifest = getManifestFromPath(srcDirectory) + loadExtension(manifest) + } } } catch (error) { // Ignore error } - // The chrome-extension: can map a extension URL request to real file path. - chromeExtensionHandler = function (request, callback) { - var directory, parsed - parsed = url.parse(request.url) - if (!(parsed.hostname && (parsed.path != null))) { - return callback() - } - if (!/extension-\d+/.test(parsed.hostname)) { - return callback() - } - directory = getPathForHost(parsed.hostname) - if (directory == null) { - return callback() - } - return callback(path.join(directory, parsed.path)) - } - protocol.registerFileProtocol('chrome-extension', chromeExtensionHandler, function (error) { - if (error) { - return console.error('Unable to register chrome-extension protocol') - } - }) - BrowserWindow.prototype._loadDevToolsExtensions = function (extensionInfoArray) { - var ref - return (ref = this.devToolsWebContents) != null ? ref.executeJavaScript('DevToolsAPI.addExtensions(' + (JSON.stringify(extensionInfoArray)) + ');') : void 0 - } + // The public API to add/remove extensions. BrowserWindow.addDevToolsExtension = function (srcDirectory) { - var extensionInfo, j, len1, ref, window - extensionInfo = getExtensionInfoFromPath(srcDirectory) - if (extensionInfo) { - ref = BrowserWindow.getAllWindows() - for (j = 0, len1 = ref.length; j < len1; j++) { - window = ref[j] - window._loadDevToolsExtensions([extensionInfo]) + const manifest = getManifestFromPath(srcDirectory) + if (manifest) { + for (const win of BrowserWindow.getAllWindows()) { + loadDevToolsExtensions(win, [manifest]) } - return extensionInfo.name + return manifest.name } } BrowserWindow.removeDevToolsExtension = function (name) { - return delete extensionInfoMap[name] + const manifest = manifestNameMap[name] + if (!manifest) return + + removeBackgroundPages(manifest) + removeContentScripts(manifest) + delete manifestMap[manifest.extensionId] + delete manifestNameMap[name] } - // Load persisted extensions when devtools is opened. - init = BrowserWindow.prototype._init + // Load extensions automatically when devtools is opened. + const init = BrowserWindow.prototype._init BrowserWindow.prototype._init = function () { init.call(this) - return this.on('devtools-opened', function () { - return this._loadDevToolsExtensions(Object.keys(extensionInfoMap).map(function (key) { - return extensionInfoMap[key] - })) + hookWindowForTabEvents(this) + this.webContents.on('devtools-opened', () => { + loadDevToolsExtensions(this, objectValues(manifestMap)) }) } }) diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index 5e8ad3e7328c..da1d481c6052 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -28,7 +28,7 @@ ipcMain.on('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, cap // If the WebContents is destroyed before receiving result, just remove the // reference from requestsQueue to make the module not send the result to it. - return event.sender.once('destroyed', function () { + event.sender.once('destroyed', function () { request.webContents = null }) }) @@ -45,7 +45,7 @@ desktopCapturer.emit = function (event, name, sources) { results.push({ id: source.id, name: source.name, - thumbnail: source.thumbnail.toDataUrl() + thumbnail: source.thumbnail.toDataURL() }) } return results diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index 58775669c2f4..6876a8d22c12 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -137,7 +137,7 @@ var createGuest = function (embedder, params) { // Dispatch events to embedder. fn = function (event) { return guest.on(event, function (_, ...args) { - return embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + guest.viewInstanceId, event].concat(args)) + embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + guest.viewInstanceId, event].concat(args)) }) } for (j = 0, len1 = supportedWebViewEvents.length; j < len1; j++) { @@ -147,12 +147,12 @@ var createGuest = function (embedder, params) { // Dispatch guest's IPC messages to embedder. guest.on('ipc-message-host', function (_, [channel, ...args]) { - return embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + guest.viewInstanceId, channel].concat(args)) + embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + guest.viewInstanceId, channel].concat(args)) }) // Autosize. guest.on('size-changed', function (_, ...args) { - return embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + guest.viewInstanceId].concat(args)) + embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + guest.viewInstanceId].concat(args)) }) return id } @@ -179,14 +179,11 @@ var attachGuest = function (embedder, elementInstanceId, guestInstanceId, params guestInstanceId: guestInstanceId, nodeIntegration: (ref1 = params.nodeintegration) != null ? ref1 : false, plugins: params.plugins, + zoomFactor: params.zoomFactor, webSecurity: !params.disablewebsecurity, blinkFeatures: params.blinkfeatures } - if (embedder.getWebPreferences().nodeIntegration === false) { - webPreferences.nodeIntegration = false - } - if (params.preload) { webPreferences.preloadURL = params.preload } @@ -210,15 +207,15 @@ var destroyGuest = function (embedder, id) { } ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) { - return event.sender.send('ELECTRON_RESPONSE_' + requestId, createGuest(event.sender, params)) + event.sender.send('ELECTRON_RESPONSE_' + requestId, createGuest(event.sender, params)) }) ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, elementInstanceId, guestInstanceId, params) { - return attachGuest(event.sender, elementInstanceId, guestInstanceId, params) + attachGuest(event.sender, elementInstanceId, guestInstanceId, params) }) ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, id) { - return destroyGuest(event.sender, id) + destroyGuest(event.sender, id) }) ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', function (event, id, params) { diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index c5189bee60ce..a3d60bee8add 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -79,7 +79,7 @@ var createGuest = function (embedder, url, frameName, options) { frameToGuest[frameName] = guest guest.frameName = frameName guest.once('closed', function () { - return delete frameToGuest[frameName] + delete frameToGuest[frameName] }) } return guest.id @@ -98,7 +98,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, fr ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestId) { var ref1 - return (ref1 = BrowserWindow.fromId(guestId)) != null ? ref1.destroy() : void 0 + (ref1 = BrowserWindow.fromId(guestId)) != null ? ref1.destroy() : void 0 }) ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) { @@ -114,11 +114,11 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, } guestContents = (ref2 = BrowserWindow.fromId(guestId)) != null ? ref2.webContents : void 0 if ((guestContents != null ? guestContents.getURL().indexOf(targetOrigin) : void 0) === 0 || targetOrigin === '*') { - return guestContents != null ? guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) : void 0 + guestContents != null ? guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) : void 0 } }) ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) { var ref1, ref2 - return (ref1 = BrowserWindow.fromId(guestId)) != null ? (ref2 = ref1.webContents) != null ? ref2[method].apply(ref2, args) : void 0 : void 0 + (ref1 = BrowserWindow.fromId(guestId)) != null ? (ref2 = ref1.webContents) != null ? ref2[method].apply(ref2, args) : void 0 : void 0 }) diff --git a/lib/browser/init.js b/lib/browser/init.js index fc4f90c399ba..924ad1420c2e 100644 --- a/lib/browser/init.js +++ b/lib/browser/init.js @@ -18,10 +18,6 @@ require('../common/init') var globalPaths = Module.globalPaths -if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { - globalPaths.push(path.join(__dirname, 'api')) -} - // Expose public APIs. globalPaths.push(path.join(__dirname, 'api', 'exports')) @@ -65,14 +61,14 @@ process.on('uncaughtException', function (error) { dialog = require('electron').dialog stack = (ref = error.stack) != null ? ref : error.name + ': ' + error.message message = 'Uncaught Exception:\n' + stack - return dialog.showErrorBox('A JavaScript error occurred in the main process', message) + dialog.showErrorBox('A JavaScript error occurred in the main process', message) }) // Emit 'exit' event on quit. var app = require('electron').app app.on('quit', function (event, exitCode) { - return process.emit('exit', exitCode) + process.emit('exit', exitCode) }) if (process.platform === 'win32') { diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 1dff5fdb8ade..0b954e518b95 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -1,10 +1,12 @@ 'use strict' const electron = require('electron') -const ipcMain = electron.ipcMain -const objectsRegistry = require('./objects-registry') const v8Util = process.atomBinding('v8_util') -const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap +const {ipcMain, isPromise, webContents} = electron + +const objectsRegistry = require('./objects-registry') + +const hasProp = {}.hasOwnProperty // The internal properties of Function. const FUNCTION_PROPERTIES = [ @@ -13,18 +15,7 @@ const FUNCTION_PROPERTIES = [ // The remote functions in renderer processes. // id => Function -let rendererFunctions = new IDWeakMap() - -// Merge two IDs together. -let mergeIds = function (webContentsId, metaId) { - const PADDING_BITS = 20 - if ((webContentsId << PADDING_BITS) < 0) { - throw new Error(`webContents ID is too large: ${webContentsId}`) - } else if (metaId > (1 << PADDING_BITS)) { - throw new Error(`Object ID is too large: ${metaId}`) - } - return (webContentsId << PADDING_BITS) + metaId -} +let rendererFunctions = v8Util.createDoubleIDWeakMap() // Return the description of object's members: let getObjectMembers = function (object) { @@ -76,9 +67,9 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) { meta.type = 'error' } else if (value instanceof Date) { meta.type = 'date' - } else if (value.constructor != null && value.constructor.name === 'Promise') { + } else if (isPromise(value)) { meta.type = 'promise' - } else if (value.hasOwnProperty('callee') && value.length != null) { + } else if (hasProp.call(value, 'callee') && value.length != null) { // Treat the arguments object as array. meta.type = 'array' } else if (optimizeSimpleObject && v8Util.getHiddenValue(value, 'simple')) { @@ -102,7 +93,9 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) { } else if (meta.type === 'buffer') { meta.value = Array.prototype.slice.call(value, 0) } else if (meta.type === 'promise') { - meta.then = valueToMeta(sender, function (v) { value.then(v) }) + meta.then = valueToMeta(sender, function (onFulfilled, onRejected) { + value.then(onFulfilled, onRejected) + }) } else if (meta.type === 'error') { meta.members = plainObjectToMeta(value) @@ -179,7 +172,7 @@ var unwrapArgs = function (sender, args) { // Merge webContentsId and meta.id, since meta.id can be the same in // different webContents. const webContentsId = sender.getId() - const objectId = mergeIds(webContentsId, meta.id) + const objectId = [webContentsId, meta.id] // Cache the callbacks in renderer. if (rendererFunctions.has(objectId)) { @@ -284,7 +277,7 @@ ipcMain.on('ELECTRON_BROWSER_FUNCTION_CALL', function (event, id, args) { try { args = unwrapArgs(event.sender, args) let func = objectsRegistry.get(id) - return callFunction(event, func, global, args) + callFunction(event, func, global, args) } catch (error) { event.returnValue = exceptionToMeta(error) } @@ -307,7 +300,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) { try { args = unwrapArgs(event.sender, args) let obj = objectsRegistry.get(id) - return callFunction(event, obj[method], obj, args) + callFunction(event, obj[method], obj, args) } catch (error) { event.returnValue = exceptionToMeta(error) } @@ -333,7 +326,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_GET', function (event, id, name) { }) ipcMain.on('ELECTRON_BROWSER_DEREFERENCE', function (event, id) { - return objectsRegistry.remove(event.sender.getId(), id) + objectsRegistry.remove(event.sender.getId(), id) }) ipcMain.on('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, guestInstanceId) { @@ -360,3 +353,17 @@ ipcMain.on('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function (event, request event.returnValue = exceptionToMeta(error) } }) + +ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId, channel, ...args) { + let contents = webContents.fromId(webContentsId) + if (!contents) { + console.error(`Sending message to WebContents with unknown ID ${webContentsId}`) + return + } + + if (sendToAll) { + contents.sendToAll(channel, ...args) + } else { + contents.send(channel, ...args) + } +}) diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index f10887550113..13d7a07ad9cf 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -10,7 +10,7 @@ var CrashReporter = (function () { function CrashReporter () {} CrashReporter.prototype.start = function (options) { - var app, args, autoSubmit, companyName, deprecate, env, extra, ignoreSystemCrashHandler, start, submitURL + var app, args, autoSubmit, companyName, env, extra, ignoreSystemCrashHandler, start, submitURL if (options == null) { options = {} } @@ -21,14 +21,6 @@ var CrashReporter = (function () { ignoreSystemCrashHandler = options.ignoreSystemCrashHandler extra = options.extra - // Deprecated. - deprecate = electron.deprecate - if (options.submitUrl) { - if (submitURL == null) { - submitURL = options.submitUrl - } - deprecate.warn('submitUrl', 'submitURL') - } app = (process.type === 'browser' ? electron : electron.remote).app if (this.productName == null) { this.productName = app.getName() @@ -52,12 +44,10 @@ var CrashReporter = (function () { extra._version = app.getVersion() } if (companyName == null) { - deprecate.log('companyName is now a required option to crashReporter.start') - return + throw new Error('companyName is a required option to crashReporter.start') } if (submitURL == null) { - deprecate.log('submitURL is now a required option to crashReporter.start') - return + throw new Error('submitURL is a required option to crashReporter.start') } start = () => { binding.start(this.productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra) @@ -65,7 +55,7 @@ var CrashReporter = (function () { if (process.platform === 'win32') { args = ['--reporter-url=' + submitURL, '--application-name=' + this.productName, '--v=1'] env = { - ATOM_SHELL_INTERNAL_CRASH_SERVICE: 1 + ELECTRON_INTERNAL_CRASH_SERVICE: 1 } spawn(process.execPath, args, { env: env, diff --git a/lib/common/api/deprecate.js b/lib/common/api/deprecate.js index ff34a2bdfe78..c146e03e6a80 100644 --- a/lib/common/api/deprecate.js +++ b/lib/common/api/deprecate.js @@ -59,8 +59,7 @@ deprecate.property = function (object, property, method) { // Deprecate an event. deprecate.event = function (emitter, oldName, newName, fn) { - var warned - warned = false + var warned = false return emitter.on(newName, function (...args) { // there is listeners for old API. if (this.listenerCount(oldName) > 0) { @@ -69,9 +68,9 @@ deprecate.event = function (emitter, oldName, newName, fn) { deprecate.warn("'" + oldName + "' event", "'" + newName + "' event") } if (fn != null) { - return fn.apply(this, arguments) + fn.apply(this, arguments) } else { - return this.emit.apply(this, [oldName].concat(args)) + this.emit.apply(this, [oldName].concat(args)) } } }) diff --git a/lib/common/api/exports/electron.js b/lib/common/api/exports/electron.js index 3bef1f0c50f6..efa44d452cc6 100644 --- a/lib/common/api/exports/electron.js +++ b/lib/common/api/exports/electron.js @@ -1,20 +1,6 @@ -// Do not expose the internal modules to `require`. -const hideInternalModules = function () { - var globalPaths = require('module').globalPaths - if (globalPaths.length === 3) { - // Remove the "common/api/lib" and "browser-or-renderer/api/lib". - return globalPaths.splice(0, 2) - } -} - // Attaches properties to |exports|. exports.defineProperties = function (exports) { return Object.defineProperties(exports, { - hideInternalModules: { - enumerable: true, - value: hideInternalModules - }, - // Common modules, please sort with alphabet order. clipboard: { // Must be enumerable, otherwise it woulde be invisible to remote module. @@ -29,12 +15,6 @@ exports.defineProperties = function (exports) { return require('../crash-reporter') } }, - deprecations: { - enumerable: true, - get: function () { - return require('../deprecations') - } - }, nativeImage: { enumerable: true, get: function () { @@ -58,6 +38,16 @@ exports.defineProperties = function (exports) { get: function () { return require('../deprecate') } + }, + deprecations: { + get: function () { + return require('../deprecations') + } + }, + isPromise: { + get: function () { + return require('../is-promise') + } } }) } diff --git a/lib/common/api/is-promise.js b/lib/common/api/is-promise.js new file mode 100644 index 000000000000..d6115a145585 --- /dev/null +++ b/lib/common/api/is-promise.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = function isPromise (val) { + return ( + val && + val.then && + val.then instanceof Function && + val.constructor && + val.constructor.reject && + val.constructor.reject instanceof Function && + val.constructor.resolve && + val.constructor.resolve instanceof Function + ) +} diff --git a/lib/common/api/native-image.js b/lib/common/api/native-image.js index ebb06138210e..614298f51a0e 100644 --- a/lib/common/api/native-image.js +++ b/lib/common/api/native-image.js @@ -1,7 +1 @@ -const deprecate = require('electron').deprecate -const nativeImage = process.atomBinding('native_image') - -// Deprecated. -deprecate.rename(nativeImage, 'createFromDataUrl', 'createFromDataURL') - -module.exports = nativeImage +module.exports = process.atomBinding('native_image') diff --git a/lib/common/asar.js b/lib/common/asar.js index 262412813221..6adc24e8ded0 100644 --- a/lib/common/asar.js +++ b/lib/common/asar.js @@ -1,6 +1,6 @@ (function () { const asar = process.binding('atom_common_asar') - const child_process = require('child_process') + const childProcess = require('child_process') const path = require('path') const util = require('util') @@ -589,11 +589,28 @@ return mkdirSync(p, mode) } } + + // Executing a command string containing a path to an asar + // archive confuses `childProcess.execFile`, which is internally + // called by `childProcess.{exec,execSync}`, causing + // Electron to consider the full command as a single path + // to an archive. + [ 'exec', 'execSync' ].forEach(function (functionName) { + var old = childProcess[functionName] + childProcess[functionName] = function () { + var processNoAsarOriginalValue = process.noAsar + process.noAsar = true + var result = old.apply(this, arguments) + process.noAsar = processNoAsarOriginalValue + return result + } + }) + overrideAPI(fs, 'open') - overrideAPI(child_process, 'execFile') + overrideAPI(childProcess, 'execFile') overrideAPISync(process, 'dlopen', 1) overrideAPISync(require('module')._extensions, '.node', 1) overrideAPISync(fs, 'openSync') - return overrideAPISync(child_process, 'execFileSync') + return overrideAPISync(childProcess, 'execFileSync') } })() diff --git a/lib/common/asar_init.js b/lib/common/asar_init.js index 13ee449a42c0..b8488aefb3ca 100644 --- a/lib/common/asar_init.js +++ b/lib/common/asar_init.js @@ -1,6 +1,6 @@ ;(function () { return function (process, require, asarSource) { - // Make asar.coffee accessible via "require". + // Make asar.js accessible via "require". process.binding('natives').ELECTRON_ASAR = asarSource // Monkey-patch the fs module. diff --git a/lib/common/init.js b/lib/common/init.js index 11c098d3ce5c..257249f0a639 100644 --- a/lib/common/init.js +++ b/lib/common/init.js @@ -1,6 +1,4 @@ -const path = require('path') const timers = require('timers') -const Module = require('module') process.atomBinding = function (name) { try { @@ -12,11 +10,6 @@ process.atomBinding = function (name) { } } -if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { - // Add common/api/lib to module search paths. - Module.globalPaths.push(path.join(__dirname, 'api')) -} - // setImmediate and process.nextTick makes use of uv_check and uv_prepare to // run the callbacks, however since we only run uv loop on requests, the // callbacks wouldn't be called until something else activated the uv loop, diff --git a/lib/common/reset-search-paths.js b/lib/common/reset-search-paths.js index 30709b56a78c..4d09f6c89ca6 100644 --- a/lib/common/reset-search-paths.js +++ b/lib/common/reset-search-paths.js @@ -4,29 +4,30 @@ const Module = require('module') // Clear Node's global search paths. Module.globalPaths.length = 0 -// Clear current and parent(init.coffee)'s search paths. +// Clear current and parent(init.js)'s search paths. module.paths = [] - module.parent.paths = [] // Prevent Node from adding paths outside this app to search paths. Module._nodeModulePaths = function (from) { - var dir, i, part, parts, paths, skipOutsidePaths, splitRe, tip from = path.resolve(from) // If "from" is outside the app then we do nothing. - skipOutsidePaths = from.startsWith(process.resourcesPath) + const skipOutsidePaths = from.startsWith(process.resourcesPath) - // Following logoic is copied from module.js. - splitRe = process.platform === 'win32' ? /[\/\\]/ : /\// - paths = [] - parts = from.split(splitRe) + // Following logic is copied from module.js. + const splitRe = process.platform === 'win32' ? /[\/\\]/ : /\// + const paths = [] + const parts = from.split(splitRe) + + let tip + let i for (tip = i = parts.length - 1; i >= 0; tip = i += -1) { - part = parts[tip] + const part = parts[tip] if (part === 'node_modules') { continue } - dir = parts.slice(0, tip + 1).join(path.sep) + const dir = parts.slice(0, tip + 1).join(path.sep) if (skipOutsidePaths && !dir.startsWith(process.resourcesPath)) { break } @@ -34,3 +35,15 @@ Module._nodeModulePaths = function (from) { } return paths } + +// Patch Module._resolveFilename to always require the Electron API when +// require('electron') is done. +const electronPath = path.join(__dirname, '..', process.type, 'api', 'exports', 'electron.js') +const originalResolveFilename = Module._resolveFilename +Module._resolveFilename = function (request, parent, isMain) { + if (request === 'electron') { + return electronPath + } else { + return originalResolveFilename(request, parent, isMain) + } +} diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index 32f78f7a6a37..e998c786a593 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -30,7 +30,7 @@ exports.getSources = function (options, callback) { ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id) return ipcRenderer.once('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + id, function (event, sources) { var source - return callback(null, (function () { + callback(null, (function () { var i, len, results results = [] for (i = 0, len = sources.length; i < len; i++) { diff --git a/lib/renderer/api/ipc-renderer.js b/lib/renderer/api/ipc-renderer.js index a6b6b1851ea3..66c40d311da2 100644 --- a/lib/renderer/api/ipc-renderer.js +++ b/lib/renderer/api/ipc-renderer.js @@ -18,4 +18,20 @@ ipcRenderer.sendToHost = function (...args) { return binding.send('ipc-message-host', args) } +ipcRenderer.sendTo = function (webContentsId, channel, ...args) { + if (typeof webContentsId !== 'number') { + throw new TypeError('First argument has to be webContentsId') + } + + ipcRenderer.send('ELECTRON_BROWSER_SEND_TO', false, webContentsId, channel, ...args) +} + +ipcRenderer.sendToAll = function (webContentsId, channel, ...args) { + if (typeof webContentsId !== 'number') { + throw new TypeError('First argument has to be webContentsId') + } + + ipcRenderer.send('ELECTRON_BROWSER_SEND_TO', true, webContentsId, channel, ...args) +} + module.exports = ipcRenderer diff --git a/lib/renderer/api/ipc.js b/lib/renderer/api/ipc.js deleted file mode 100644 index 25519a308daf..000000000000 --- a/lib/renderer/api/ipc.js +++ /dev/null @@ -1,27 +0,0 @@ -const ipcRenderer = require('electron').ipcRenderer -const deprecate = require('electron').deprecate -const EventEmitter = require('events').EventEmitter - -// This module is deprecated, we mirror everything from ipcRenderer. -deprecate.warn('ipc module', 'require("electron").ipcRenderer') - -// Routes events of ipcRenderer. -var ipc = new EventEmitter() - -ipcRenderer.emit = function (channel, event, ...args) { - ipc.emit.apply(ipc, [channel].concat(args)) - return EventEmitter.prototype.emit.apply(ipcRenderer, arguments) -} - -// Deprecated. -for (var method in ipcRenderer) { - if (method.startsWith('send')) { - ipc[method] = ipcRenderer[method] - } -} - -deprecate.rename(ipc, 'sendChannel', 'send') - -deprecate.rename(ipc, 'sendChannelSync', 'sendSync') - -module.exports = ipc diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index 6631ea22575a..b5c9fe3a0e49 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -1,15 +1,13 @@ 'use strict' -const ipcRenderer = require('electron').ipcRenderer -const CallbacksRegistry = require('electron').CallbacksRegistry const v8Util = process.atomBinding('v8_util') -const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap +const {ipcRenderer, isPromise, CallbacksRegistry} = require('electron') const callbacksRegistry = new CallbacksRegistry() var includes = [].includes -var remoteObjectCache = new IDWeakMap() +var remoteObjectCache = v8Util.createIDWeakMap() // Check for circular reference. var isCircular = function (field, visited) { @@ -46,10 +44,12 @@ var wrapArgs = function (args, visited) { value: value.getTime() } } else if ((value != null) && typeof value === 'object') { - if (value.constructor != null && value.constructor.name === 'Promise') { + if (isPromise(value)) { return { type: 'promise', - then: valueToMeta(function (v) { value.then(v) }) + then: valueToMeta(function (onFulfilled, onRejected) { + value.then(onFulfilled, onRejected) + }) } } else if (v8Util.getHiddenValue(value, 'atomId')) { return { @@ -240,28 +240,25 @@ var metaToPlainObject = function (meta) { // Browser calls a callback in renderer. ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', function (event, id, args) { - return callbacksRegistry.apply(id, metaToValue(args)) + callbacksRegistry.apply(id, metaToValue(args)) }) // A callback in browser is released. ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', function (event, id) { - return callbacksRegistry.remove(id) + callbacksRegistry.remove(id) }) // List all built-in modules in browser process. const browserModules = require('../../browser/api/exports/electron') // And add a helper receiver for each one. -var fn = function (name) { - return Object.defineProperty(exports, name, { +for (let name of Object.getOwnPropertyNames(browserModules)) { + Object.defineProperty(exports, name, { get: function () { return exports.getBuiltin(name) } }) } -for (var name in browserModules) { - fn(name) -} // Get remote module. exports.require = function (module) { diff --git a/lib/renderer/api/web-frame.js b/lib/renderer/api/web-frame.js index 4a152d4f3646..81855c391f8f 100644 --- a/lib/renderer/api/web-frame.js +++ b/lib/renderer/api/web-frame.js @@ -1,6 +1,5 @@ 'use strict' -const deprecate = require('electron').deprecate const EventEmitter = require('events').EventEmitter const webFrame = process.atomBinding('web_frame').webFrame @@ -11,9 +10,4 @@ Object.setPrototypeOf(webFrame, EventEmitter.prototype) // Lots of webview would subscribe to webFrame's events. webFrame.setMaxListeners(0) -// Deprecated. -deprecate.rename(webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure') -deprecate.rename(webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP') -deprecate.rename(webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged') - module.exports = webFrame diff --git a/lib/renderer/chrome-api.js b/lib/renderer/chrome-api.js index 719066a6fae7..61fce14c5ba9 100644 --- a/lib/renderer/chrome-api.js +++ b/lib/renderer/chrome-api.js @@ -1,13 +1,200 @@ +const {ipcRenderer} = require('electron') const url = require('url') -const chrome = window.chrome = window.chrome || {} -chrome.extension = { - getURL: function (path) { - return url.format({ - protocol: window.location.protocol, - slashes: true, - hostname: window.location.hostname, - pathname: path - }) +let nextId = 0 + +class Event { + constructor () { + this.listeners = [] + } + + addListener (callback) { + this.listeners.push(callback) + } + + removeListener (callback) { + const index = this.listeners.indexOf(callback) + if (index !== -1) { + this.listeners.splice(index, 1) + } + } + + emit (...args) { + for (const listener of this.listeners) { + listener(...args) + } + } +} + +class Tab { + constructor (tabId) { + this.id = tabId + } +} + +class MessageSender { + constructor (tabId, extensionId) { + this.tab = tabId ? new Tab(tabId) : null + this.id = extensionId + this.url = `chrome-extension://${extensionId}` + } +} + +class Port { + constructor (tabId, portId, extensionId, name) { + this.tabId = tabId + this.portId = portId + this.disconnected = false + + this.name = name + this.onDisconnect = new Event() + this.onMessage = new Event() + this.sender = new MessageSender(tabId, extensionId) + + ipcRenderer.once(`CHROME_PORT_DISCONNECT_${portId}`, () => { + this._onDisconnect() + }) + ipcRenderer.on(`CHROME_PORT_POSTMESSAGE_${portId}`, (event, message) => { + const sendResponse = function () { console.error('sendResponse is not implemented') } + this.onMessage.emit(message, this.sender, sendResponse) + }) + } + + disconnect () { + if (this.disconnected) return + + ipcRenderer.sendToAll(this.tabId, `CHROME_PORT_DISCONNECT_${this.portId}`) + this._onDisconnect() + } + + postMessage (message) { + ipcRenderer.sendToAll(this.tabId, `CHROME_PORT_POSTMESSAGE_${this.portId}`, message) + } + + _onDisconnect () { + this.disconnected = true + ipcRenderer.removeAllListeners(`CHROME_PORT_POSTMESSAGE_${this.portId}`) + this.onDisconnect.emit() + } +} + +// Inject chrome API to the |context| +exports.injectTo = function (extensionId, isBackgroundPage, context) { + const chrome = context.chrome = context.chrome || {} + + ipcRenderer.on(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, (event, tabId, portId, connectInfo) => { + chrome.runtime.onConnect.emit(new Port(tabId, portId, extensionId, connectInfo.name)) + }) + + ipcRenderer.on(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, (event, tabId, message) => { + chrome.runtime.onMessage.emit(message, new MessageSender(tabId, extensionId)) + }) + + ipcRenderer.on('CHROME_TABS_ONCREATED', (event, tabId) => { + chrome.tabs.onCreated.emit(new Tab(tabId)) + }) + + ipcRenderer.on('CHROME_TABS_ONREMOVED', (event, tabId) => { + chrome.tabs.onRemoved.emit(tabId) + }) + + chrome.runtime = { + getURL: function (path) { + return url.format({ + protocol: 'chrome-extension', + slashes: true, + hostname: extensionId, + pathname: path + }) + }, + + connect (...args) { + if (isBackgroundPage) { + console.error('chrome.runtime.connect is not supported in background page') + return + } + + // Parse the optional args. + let targetExtensionId = extensionId + let connectInfo = {name: ''} + if (args.length === 1) { + connectInfo = args[0] + } else if (args.length === 2) { + [targetExtensionId, connectInfo] = args + } + + const {tabId, portId} = ipcRenderer.sendSync('CHROME_RUNTIME_CONNECT', targetExtensionId, connectInfo) + return new Port(tabId, portId, extensionId, connectInfo.name) + }, + + sendMessage (...args) { + if (isBackgroundPage) { + console.error('chrome.runtime.sendMessage is not supported in background page') + return + } + + // Parse the optional args. + let targetExtensionId = extensionId + let message + if (args.length === 1) { + message = args[0] + } else if (args.length === 2) { + [targetExtensionId, message] = args + } else { + console.error('options and responseCallback are not supported') + } + + ipcRenderer.send('CHROME_RUNTIME_SENDMESSAGE', targetExtensionId, message) + }, + + onConnect: new Event(), + onMessage: new Event(), + onInstalled: new Event() + } + + chrome.tabs = { + executeScript (tabId, details, callback) { + const requestId = ++nextId + ipcRenderer.once(`CHROME_TABS_EXECUTESCRIPT_RESULT_${requestId}`, (event, result) => { + callback([event.result]) + }) + ipcRenderer.send('CHROME_TABS_EXECUTESCRIPT', requestId, tabId, extensionId, details) + }, + + sendMessage (tabId, message, options, responseCallback) { + if (responseCallback) { + console.error('responseCallback is not supported') + } + ipcRenderer.send('CHROME_TABS_SEND_MESSAGE', tabId, extensionId, isBackgroundPage, message) + }, + + onUpdated: new Event(), + onCreated: new Event(), + onRemoved: new Event() + } + + chrome.extension = { + getURL: chrome.runtime.getURL, + connect: chrome.runtime.connect, + onConnect: chrome.runtime.onConnect, + sendMessage: chrome.runtime.sendMessage, + onMessage: chrome.runtime.onMessage + } + + chrome.storage = { + sync: { + get () {}, + set () {} + } + } + + chrome.pageAction = { + show () {}, + hide () {}, + setTitle () {}, + getTitle () {}, + setIcon () {}, + setPopup () {}, + getPopup () {} } } diff --git a/lib/renderer/content-scripts-injector.js b/lib/renderer/content-scripts-injector.js new file mode 100644 index 000000000000..e4a801110f62 --- /dev/null +++ b/lib/renderer/content-scripts-injector.js @@ -0,0 +1,61 @@ +const {ipcRenderer} = require('electron') +const {runInThisContext} = require('vm') + +// Check whether pattern matches. +// https://developer.chrome.com/extensions/match_patterns +const matchesPattern = function (pattern) { + if (pattern === '') return true + + const regexp = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$') + return location.href.match(regexp) +} + +// Run the code with chrome API integrated. +const runContentScript = function (extensionId, url, code) { + const context = {} + require('./chrome-api').injectTo(extensionId, false, context) + const wrapper = `(function (chrome) {\n ${code}\n })` + const compiledWrapper = runInThisContext(wrapper, { + filename: url, + lineOffset: 1, + displayErrors: true + }) + return compiledWrapper.call(this, context.chrome) +} + +// Run injected scripts. +// https://developer.chrome.com/extensions/content_scripts +const injectContentScript = function (extensionId, script) { + for (const match of script.matches) { + if (!matchesPattern(match)) return + } + + for (const {url, code} of script.js) { + const fire = runContentScript.bind(window, extensionId, url, code) + if (script.runAt === 'document_start') { + process.once('document-start', fire) + } else if (script.runAt === 'document_end') { + process.once('document-end', fire) + } else if (script.runAt === 'document_idle') { + document.addEventListener('DOMContentLoaded', fire) + } + } +} + +// Handle the request of chrome.tabs.executeJavaScript. +ipcRenderer.on('CHROME_TABS_EXECUTESCRIPT', function (event, senderWebContentsId, requestId, extensionId, url, code) { + const result = runContentScript.call(window, extensionId, url, code) + ipcRenderer.sendToAll(senderWebContentsId, `CHROME_TABS_EXECUTESCRIPT_RESULT_${requestId}`, result) +}) + +// Read the renderer process preferences. +const preferences = process.getRenderProcessPreferences() +if (preferences) { + for (const pref of preferences) { + if (pref.contentScripts) { + for (const script of pref.contentScripts) { + injectContentScript(pref.extensionId, script) + } + } + } +} diff --git a/lib/renderer/init.js b/lib/renderer/init.js index a9f4acc5cbfe..f0875cae12c2 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -16,10 +16,6 @@ require('../common/init') var globalPaths = Module.globalPaths -if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { - globalPaths.push(path.join(__dirname, 'api')) -} - // Expose public APIs. globalPaths.push(path.join(__dirname, 'api', 'exports')) @@ -45,8 +41,9 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev }) // Process command line arguments. -var nodeIntegration = 'false' -var preloadScript = null +let nodeIntegration = 'false' +let preloadScript = null +let isBackgroundPage = false for (let arg of process.argv) { if (arg.indexOf('--guest-instance-id=') === 0) { // This is a guest web view. @@ -58,6 +55,8 @@ for (let arg of process.argv) { nodeIntegration = arg.substr(arg.indexOf('=') + 1) } else if (arg.indexOf('--preload=') === 0) { preloadScript = arg.substr(arg.indexOf('=') + 1) + } else if (arg === '--background-page') { + isBackgroundPage = true } } @@ -67,14 +66,17 @@ if (window.location.protocol === 'chrome-devtools:') { nodeIntegration = 'true' } else if (window.location.protocol === 'chrome-extension:') { // Add implementations of chrome API. - require('./chrome-api') - nodeIntegration = 'true' + require('./chrome-api').injectTo(window.location.hostname, isBackgroundPage, window) + nodeIntegration = 'false' } else { // Override default web functions. require('./override') + // Inject content scripts. + require('./content-scripts-injector') + // Load webview tag implementation. - if (process.guestInstanceId == null) { + if (nodeIntegration === 'true' && process.guestInstanceId == null) { require('./web-view/web-view') require('./web-view/web-view-attributes') } @@ -125,11 +127,7 @@ if (preloadScript) { try { require(preloadScript) } catch (error) { - if (error.code === 'MODULE_NOT_FOUND') { - console.error('Unable to load preload script ' + preloadScript) - } else { - console.error(error) - console.error(error.stack) - } + console.error('Unable to load preload script: ' + preloadScript) + console.error(error.stack || error.message) } } diff --git a/lib/renderer/inspector.js b/lib/renderer/inspector.js index df151cf1b5e6..ca60c84d4be9 100644 --- a/lib/renderer/inspector.js +++ b/lib/renderer/inspector.js @@ -3,7 +3,7 @@ window.onload = function () { window.InspectorFrontendHost.showContextMenuAtPoint = createMenu // Use dialog API to override file chooser dialog. - return (window.WebInspector.createFileSelectorElement = createFileSelectorElement) + window.WebInspector.createFileSelectorElement = createFileSelectorElement } var convertToMenuTemplate = function (items) { diff --git a/lib/renderer/override.js b/lib/renderer/override.js index db56eadd3484..5667e5e16f55 100644 --- a/lib/renderer/override.js +++ b/lib/renderer/override.js @@ -15,8 +15,9 @@ var BrowserWindowProxy = (function () { BrowserWindowProxy.proxies = {} BrowserWindowProxy.getOrCreate = function (guestId) { - var base - return (base = this.proxies)[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId) + var base = this.proxies + base[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId) + return base[guestId] } BrowserWindowProxy.remove = function (guestId) { @@ -44,6 +45,10 @@ var BrowserWindowProxy = (function () { return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur') } + BrowserWindowProxy.prototype.print = function () { + return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print') + } + Object.defineProperty(BrowserWindowProxy.prototype, 'location', { get: function () { return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'getURL') @@ -85,9 +90,8 @@ window.open = function (url, frameName, features) { } options = {} - // TODO remove hyphenated options in both of the following arrays for 1.0 - const ints = ['x', 'y', 'width', 'height', 'min-width', 'minWidth', 'max-width', 'maxWidth', 'min-height', 'minHeight', 'max-height', 'maxHeight', 'zoom-factor', 'zoomFactor'] - const webPreferences = ['zoom-factor', 'zoomFactor', 'node-integration', 'nodeIntegration', 'preload'] + const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor'] + const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload'] const disposition = 'new-window' // Make sure to get rid of excessive whitespace in the property name @@ -194,7 +198,7 @@ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, m event.data = message event.origin = sourceOrigin event.source = BrowserWindowProxy.getOrCreate(sourceId) - return window.dispatchEvent(event) + window.dispatchEvent(event) }) // Forward history operations to browser. diff --git a/lib/renderer/web-view/guest-view-internal.js b/lib/renderer/web-view/guest-view-internal.js index 4f920707d1be..7432444c6da6 100644 --- a/lib/renderer/web-view/guest-view-internal.js +++ b/lib/renderer/web-view/guest-view-internal.js @@ -62,14 +62,14 @@ var dispatchEvent = function (webView, eventName, eventKey, ...args) { module.exports = { registerEvents: function (webView, viewInstanceId) { ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId, function (event, eventName, ...args) { - return dispatchEvent.apply(null, [webView, eventName, eventName].concat(args)) + dispatchEvent.apply(null, [webView, eventName, eventName].concat(args)) }) ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId, function (event, channel, ...args) { var domEvent = new Event('ipc-message') domEvent.channel = channel domEvent.args = args - return webView.dispatchEvent(domEvent) + webView.dispatchEvent(domEvent) }) return ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId, function (event, ...args) { @@ -80,7 +80,7 @@ module.exports = { f = ref1[i] domEvent[f] = args[i] } - return webView.onSizeChanged(domEvent) + webView.onSizeChanged(domEvent) }) }, deregisterEvents: function (viewInstanceId) { diff --git a/lib/renderer/web-view/web-view.js b/lib/renderer/web-view/web-view.js index 20f5f07465b5..e9d300aabbcb 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -1,6 +1,5 @@ 'use strict' -const deprecate = require('electron').deprecate const webFrame = require('electron').webFrame const remote = require('electron').remote const ipcRenderer = require('electron').ipcRenderer @@ -43,13 +42,17 @@ var WebViewImpl = (function () { this.webviewNode.setZoomLevel(zoomLevel) } webFrame.on('zoom-level-changed', this.onZoomLevelChanged) + + this.onVisibilityChanged = (event, visibilityState) => { + this.webviewNode.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', visibilityState) + } + ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.onVisibilityChanged) } WebViewImpl.prototype.createBrowserPluginNode = function () { // We create BrowserPlugin as a custom element in order to observe changes // to attributes synchronously. - var browserPluginNode - browserPluginNode = new WebViewImpl.BrowserPlugin() + var browserPluginNode = new WebViewImpl.BrowserPlugin() v8Util.setHiddenValue(browserPluginNode, 'internal', this) return browserPluginNode } @@ -58,6 +61,7 @@ var WebViewImpl = (function () { WebViewImpl.prototype.reset = function () { // Unlisten the zoom-level-changed event. webFrame.removeListener('zoom-level-changed', this.onZoomLevelChanged) + ipcRenderer.removeListener('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.onVisibilityChanged) // If guestInstanceId is defined then the has navigated and has // already picked up a partition ID. Thus, we need to reset the initialization @@ -225,7 +229,8 @@ var WebViewImpl = (function () { var attribute, attributeName, css, elementRect, params, ref1 params = { instanceId: this.viewInstanceId, - userAgentOverride: this.userAgentOverride + userAgentOverride: this.userAgentOverride, + zoomFactor: webFrame.getZoomFactor() } ref1 = this.attributes for (attributeName in ref1) { @@ -260,8 +265,7 @@ var WebViewImpl = (function () { // Registers browser plugin custom element. var registerBrowserPluginElement = function () { - var proto - proto = Object.create(HTMLObjectElement.prototype) + var proto = Object.create(HTMLObjectElement.prototype) proto.createdCallback = function () { this.setAttribute('type', 'application/browser-plugin') this.setAttribute('id', 'browser-plugin-' + getNextId()) @@ -432,8 +436,6 @@ var registerWebViewElement = function () { return internal.webContents } - // Deprecated. - deprecate.rename(proto, 'getUrl', 'getURL') window.WebView = webFrame.registerEmbedderCustomElement('webview', { prototype: proto }) diff --git a/package.json b/package.json index 7d40098f099a..6f873786e3f0 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "electron", - "version": "0.37.8", + "version": "1.2.1", "devDependencies": { "asar": "^0.11.0", "request": "*", - "standard": "^6.0.8" + "standard": "^7.1.0" }, "optionalDependencies": { "runas": "^3.0.0" diff --git a/script/bootstrap.py b/script/bootstrap.py index 816a6182b201..6380ffe27c7a 100755 --- a/script/bootstrap.py +++ b/script/bootstrap.py @@ -7,7 +7,7 @@ import sys from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL, PLATFORM, \ enable_verbose_mode, is_verbose_mode, get_target_arch -from lib.util import execute_stdout, get_atom_shell_version, scoped_cwd +from lib.util import execute_stdout, get_electron_version, scoped_cwd SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) @@ -50,11 +50,9 @@ def main(): libcc_static_library_path = os.path.join(dist_dir, 'static_library') if PLATFORM != 'win32': - # Download prebuilt clang binaries. - update_clang() if not args.disable_clang and args.clang_dir == '': - # Build with prebuilt clang. - set_clang_env(os.environ) + # Download prebuilt clang binaries. + update_clang() setup_python_libs() update_node_modules('.') @@ -67,7 +65,7 @@ def main(): create_chrome_version_h() touch_config_gypi() - run_update(defines) + run_update(defines, args.disable_clang, args.clang_dir) update_electron_modules('spec', args.target_arch) @@ -125,7 +123,7 @@ def check_root(): def update_submodules(): - execute_stdout(['git', 'submodule', 'sync']) + execute_stdout(['git', 'submodule', 'sync', '--recursive']) execute_stdout(['git', 'submodule', 'update', '--init', '--recursive']) @@ -186,7 +184,7 @@ def update_node_modules(dirname, env=None): def update_electron_modules(dirname, target_arch): env = os.environ.copy() env['npm_config_arch'] = target_arch - env['npm_config_target'] = get_atom_shell_version() + env['npm_config_target'] = get_electron_version() env['npm_config_disturl'] = 'https://atom.io/download/atom-shell' update_node_modules(dirname, env) @@ -250,9 +248,14 @@ def touch_config_gypi(): f.write(content) -def run_update(defines): +def run_update(defines, disable_clang, clang_dir): + env = os.environ.copy() + if not disable_clang and clang_dir == '': + # Build with prebuilt clang. + set_clang_env(env) + update = os.path.join(SOURCE_ROOT, 'script', 'update.py') - execute_stdout([sys.executable, update, '--defines', defines]) + execute_stdout([sys.executable, update, '--defines', defines], env) if __name__ == '__main__': diff --git a/script/build.py b/script/build.py index c428b95f329f..1a7378bf9758 100755 --- a/script/build.py +++ b/script/build.py @@ -5,7 +5,8 @@ import os import subprocess import sys -from lib.util import atom_gyp +from lib.config import get_target_arch +from lib.util import electron_gyp, import_vs_env CONFIGURATIONS = ['Release', 'Debug'] @@ -15,6 +16,9 @@ SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def main(): os.chdir(SOURCE_ROOT) + # Update the VS build env. + import_vs_env(get_target_arch()) + ninja = os.path.join('vendor', 'depot_tools', 'ninja') if sys.platform == 'win32': ninja += '.exe' @@ -36,7 +40,7 @@ def parse_args(): required=False) parser.add_argument('-t', '--target', help='Build specified target', - default=atom_gyp()['project_name%'], + default=electron_gyp()['project_name%'], required=False) return parser.parse_args() diff --git a/script/bump-version.py b/script/bump-version.py index 5c70d4494e8d..4db30b71fca9 100755 --- a/script/bump-version.py +++ b/script/bump-version.py @@ -4,7 +4,7 @@ import os import re import sys -from lib.util import execute, get_atom_shell_version, parse_version, scoped_cwd +from lib.util import execute, get_electron_version, parse_version, scoped_cwd SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) @@ -18,7 +18,7 @@ def main(): option = sys.argv[1] increments = ['major', 'minor', 'patch', 'build'] if option in increments: - version = get_atom_shell_version() + version = get_electron_version() versions = parse_version(version.split('-')[0]) versions = increase_version(versions, increments.index(option)) else: @@ -27,7 +27,7 @@ def main(): version = '.'.join(versions[:3]) with scoped_cwd(SOURCE_ROOT): - update_atom_gyp(version) + update_electron_gyp(version) update_win_rc(version, versions) update_version_h(versions) update_info_plist(version) @@ -42,7 +42,7 @@ def increase_version(versions, index): return versions -def update_atom_gyp(version): +def update_electron_gyp(version): pattern = re.compile(" *'version%' *: *'[0-9.]+'") with open('electron.gyp', 'r') as f: lines = f.readlines() diff --git a/script/cibuild.ps1 b/script/cibuild.ps1 new file mode 100644 index 000000000000..b06d48d1a8be --- /dev/null +++ b/script/cibuild.ps1 @@ -0,0 +1,2 @@ +$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition +& python "$scriptPath/cibuild" diff --git a/script/create-dist.py b/script/create-dist.py index e25845432c77..3f95cf2281d6 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -11,11 +11,11 @@ import stat from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL, PLATFORM, \ get_target_arch, get_chromedriver_version, \ get_platform_key -from lib.util import scoped_cwd, rm_rf, get_atom_shell_version, make_zip, \ - execute, atom_gyp +from lib.util import scoped_cwd, rm_rf, get_electron_version, make_zip, \ + execute, electron_gyp -ATOM_SHELL_VERSION = get_atom_shell_version() +ELECTRON_VERSION = get_electron_version() SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) DIST_DIR = os.path.join(SOURCE_ROOT, 'dist') @@ -23,8 +23,8 @@ OUT_DIR = os.path.join(SOURCE_ROOT, 'out', 'R') CHROMIUM_DIR = os.path.join(SOURCE_ROOT, 'vendor', 'brightray', 'vendor', 'download', 'libchromiumcontent', 'static_library') -PROJECT_NAME = atom_gyp()['project_name%'] -PRODUCT_NAME = atom_gyp()['product_name%'] +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] TARGET_BINARIES = { 'darwin': [ @@ -36,8 +36,6 @@ TARGET_BINARIES = { 'icudtl.dat', 'libEGL.dll', 'libGLESv2.dll', - 'msvcp120.dll', - 'msvcr120.dll', 'ffmpeg.dll', 'node.dll', 'content_resources_200_percent.pak', @@ -45,7 +43,6 @@ TARGET_BINARIES = { 'xinput1_3.dll', 'natives_blob.bin', 'snapshot_blob.bin', - 'vccorlib120.dll', ], 'linux': [ PROJECT_NAME, # 'electron' @@ -89,7 +86,7 @@ def main(): create_version() create_dist_zip() create_chrome_binary_zip('chromedriver', get_chromedriver_version()) - create_chrome_binary_zip('mksnapshot', ATOM_SHELL_VERSION) + create_chrome_binary_zip('mksnapshot', ELECTRON_VERSION) create_ffmpeg_zip() create_symbols_zip() @@ -127,19 +124,23 @@ def copy_license(): def strip_binaries(): - if get_target_arch() == 'arm': - strip = 'arm-linux-gnueabihf-strip' - else: - strip = 'strip' for binary in TARGET_BINARIES[PLATFORM]: if binary.endswith('.so') or '.' not in binary: - execute([strip, os.path.join(DIST_DIR, binary)]) + strip_binary(os.path.join(DIST_DIR, binary)) + + +def strip_binary(binary_path): + if get_target_arch() == 'arm': + strip = 'arm-linux-gnueabihf-strip' + else: + strip = 'strip' + execute([strip, binary_path]) def create_version(): version_path = os.path.join(SOURCE_ROOT, 'dist', 'version') with open(version_path, 'w') as version_file: - version_file.write(ATOM_SHELL_VERSION) + version_file.write(ELECTRON_VERSION) def create_symbols(): @@ -154,7 +155,7 @@ def create_symbols(): def create_dist_zip(): - dist_name = '{0}-{1}-{2}-{3}.zip'.format(PROJECT_NAME, ATOM_SHELL_VERSION, + dist_name = '{0}-{1}-{2}-{3}.zip'.format(PROJECT_NAME, ELECTRON_VERSION, get_platform_key(), get_target_arch()) zip_file = os.path.join(SOURCE_ROOT, 'dist', dist_name) @@ -182,7 +183,7 @@ def create_chrome_binary_zip(binary, version): def create_ffmpeg_zip(): dist_name = 'ffmpeg-{0}-{1}-{2}.zip'.format( - ATOM_SHELL_VERSION, get_platform_key(), get_target_arch()) + ELECTRON_VERSION, get_platform_key(), get_target_arch()) zip_file = os.path.join(SOURCE_ROOT, 'dist', dist_name) if PLATFORM == 'darwin': @@ -194,13 +195,17 @@ def create_ffmpeg_zip(): shutil.copy2(os.path.join(CHROMIUM_DIR, '..', 'ffmpeg', ffmpeg_name), DIST_DIR) + + if PLATFORM == 'linux': + strip_binary(os.path.join(DIST_DIR, ffmpeg_name)) + with scoped_cwd(DIST_DIR): make_zip(zip_file, [ffmpeg_name, 'LICENSE', 'LICENSES.chromium.html'], []) def create_symbols_zip(): dist_name = '{0}-{1}-{2}-{3}-symbols.zip'.format(PROJECT_NAME, - ATOM_SHELL_VERSION, + ELECTRON_VERSION, get_platform_key(), get_target_arch()) zip_file = os.path.join(DIST_DIR, dist_name) @@ -212,7 +217,7 @@ def create_symbols_zip(): if PLATFORM == 'darwin': dsym_name = '{0}-{1}-{2}-{3}-dsym.zip'.format(PROJECT_NAME, - ATOM_SHELL_VERSION, + ELECTRON_VERSION, get_platform_key(), get_target_arch()) with scoped_cwd(DIST_DIR): diff --git a/script/dump-symbols.py b/script/dump-symbols.py index 5c98d38a31f8..76949e95aa92 100755 --- a/script/dump-symbols.py +++ b/script/dump-symbols.py @@ -4,7 +4,7 @@ import os import sys from lib.config import PLATFORM -from lib.util import atom_gyp, execute, rm_rf +from lib.util import electron_gyp, execute, rm_rf SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) @@ -56,7 +56,7 @@ def register_required_dll(): def get_names_from_gyp(): - variables = atom_gyp() + variables = electron_gyp() return (variables['project_name%'], variables['product_name%']) diff --git a/script/lib/config.py b/script/lib/config.py index 4b3f4ba6fb34..43423e514368 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '1a4c5e51a670633ff3ecd4448ad01ba21b440542' +LIBCHROMIUMCONTENT_COMMIT = '8f2a0aa0a9dd107e4d574cc9d552781c55c86bab' PLATFORM = { 'cygwin': 'win32', @@ -38,23 +38,29 @@ def get_target_arch(): if e.errno != errno.ENOENT: raise - if PLATFORM == 'win32': - return 'ia32' - else: - return 'x64' + return 'x64' def get_chromedriver_version(): - return 'v2.15' + return 'v2.21' + +def get_env_var(name): + value = os.environ.get('ELECTRON_' + name, '') + if not value: + # TODO Remove ATOM_SHELL_* fallback values + value = os.environ.get('ATOM_SHELL_' + name, '') + if value: + print 'Warning: Use $ELECTRON_' + name + ' instead of $ATOM_SHELL_' + name + return value def s3_config(): - config = (os.environ.get('ATOM_SHELL_S3_BUCKET', ''), - os.environ.get('ATOM_SHELL_S3_ACCESS_KEY', ''), - os.environ.get('ATOM_SHELL_S3_SECRET_KEY', '')) - message = ('Error: Please set the $ATOM_SHELL_S3_BUCKET, ' - '$ATOM_SHELL_S3_ACCESS_KEY, and ' - '$ATOM_SHELL_S3_SECRET_KEY environment variables') + config = (get_env_var('S3_BUCKET'), + get_env_var('S3_ACCESS_KEY'), + get_env_var('S3_SECRET_KEY')) + message = ('Error: Please set the $ELECTRON_S3_BUCKET, ' + '$ELECTRON_S3_ACCESS_KEY, and ' + '$ELECTRON_S3_SECRET_KEY environment variables') assert all(len(c) for c in config), message return config diff --git a/script/lib/env_util.py b/script/lib/env_util.py new file mode 100644 index 000000000000..df759241fe80 --- /dev/null +++ b/script/lib/env_util.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import itertools +import subprocess +import sys + + +def validate_pair(ob): + if not (len(ob) == 2): + print("Unexpected result:", ob, file=sys.stderr) + return False + else: + return True + + +def consume(iter): + try: + while True: next(iter) + except StopIteration: + pass + + +def get_environment_from_batch_command(env_cmd, initial=None): + """ + Take a command (either a single command or list of arguments) + and return the environment created after running that command. + Note that if the command must be a batch file or .cmd file, or the + changes to the environment will not be captured. + + If initial is supplied, it is used as the initial environment passed + to the child process. + """ + if not isinstance(env_cmd, (list, tuple)): + env_cmd = [env_cmd] + # Construct the command that will alter the environment. + env_cmd = subprocess.list2cmdline(env_cmd) + # Create a tag so we can tell in the output when the proc is done. + tag = 'END OF BATCH COMMAND' + # Construct a cmd.exe command to do accomplish this. + cmd = 'cmd.exe /s /c "{env_cmd} && echo "{tag}" && set"'.format(**vars()) + # Launch the process. + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=initial) + # Parse the output sent to stdout. + lines = proc.stdout + # Consume whatever output occurs until the tag is reached. + consume(itertools.takewhile(lambda l: tag not in l, lines)) + # Define a way to handle each KEY=VALUE line. + handle_line = lambda l: l.rstrip().split('=',1) + # Parse key/values into pairs. + pairs = map(handle_line, lines) + # Make sure the pairs are valid. + valid_pairs = filter(validate_pair, pairs) + # Construct a dictionary of the pairs. + result = dict(valid_pairs) + # Let the process finish. + proc.communicate() + return result + + +def get_vs_env(vs_version, arch): + """ + Returns the env object for VS building environment. + + The vs_version can be strings like "12.0" (e.g. VS2013), the arch has to + be one of "x86", "amd64", "arm", "x86_amd64", "x86_arm", "amd64_x86", + "amd64_arm", e.g. the args passed to vcvarsall.bat. + """ + vsvarsall = "C:\\Program Files (x86)\\Microsoft Visual Studio {0}\\VC\\vcvarsall.bat".format(vs_version) + return get_environment_from_batch_command([vsvarsall, arch]) diff --git a/script/lib/util.py b/script/lib/util.py index 4e5fb90988d7..4db4e5fa6748 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -16,6 +16,7 @@ import os import zipfile from config import is_verbose_mode +from env_util import get_vs_env def get_host_arch(): @@ -178,7 +179,7 @@ def execute_stdout(argv, env=os.environ): execute(argv, env) -def atom_gyp(): +def electron_gyp(): SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..')) gyp = os.path.join(SOURCE_ROOT, 'electron.gyp') with open(gyp) as f: @@ -186,8 +187,8 @@ def atom_gyp(): return obj['variables'] -def get_atom_shell_version(): - return 'v' + atom_gyp()['version%'] +def get_electron_version(): + return 'v' + electron_gyp()['version%'] def parse_version(version): @@ -223,3 +224,15 @@ def s3put(bucket, access_key, secret_key, prefix, key_prefix, files): ] + files execute(args, env) + + +def import_vs_env(target_arch): + if sys.platform != 'win32': + return + + if target_arch == 'ia32': + vs_arch = 'amd64_x86' + else: + vs_arch = 'x86_amd64' + env = get_vs_env('14.0', vs_arch) + os.environ.update(env) diff --git a/script/start.py b/script/start.py index 76a079cb26ea..839ddf997348 100644 --- a/script/start.py +++ b/script/start.py @@ -4,13 +4,13 @@ import os import subprocess import sys -from lib.util import atom_gyp +from lib.util import electron_gyp SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) -PROJECT_NAME = atom_gyp()['project_name%'] -PRODUCT_NAME = atom_gyp()['product_name%'] +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] def main(): diff --git a/script/test.py b/script/test.py index 5adfd4eed6c5..02377f481c5b 100755 --- a/script/test.py +++ b/script/test.py @@ -4,13 +4,13 @@ import os import subprocess import sys -from lib.util import atom_gyp, rm_rf +from lib.util import electron_gyp, rm_rf SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) -PROJECT_NAME = atom_gyp()['project_name%'] -PRODUCT_NAME = atom_gyp()['product_name%'] +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] def main(): @@ -21,18 +21,18 @@ def main(): config = 'R' if sys.platform == 'darwin': - atom_shell = os.path.join(SOURCE_ROOT, 'out', config, + electron = os.path.join(SOURCE_ROOT, 'out', config, '{0}.app'.format(PRODUCT_NAME), 'Contents', 'MacOS', PRODUCT_NAME) elif sys.platform == 'win32': - atom_shell = os.path.join(SOURCE_ROOT, 'out', config, + electron = os.path.join(SOURCE_ROOT, 'out', config, '{0}.exe'.format(PROJECT_NAME)) else: - atom_shell = os.path.join(SOURCE_ROOT, 'out', config, PROJECT_NAME) + electron = os.path.join(SOURCE_ROOT, 'out', config, PROJECT_NAME) returncode = 0 try: - subprocess.check_call([atom_shell, 'spec'] + sys.argv[1:]) + subprocess.check_call([electron, 'spec'] + sys.argv[1:]) except subprocess.CalledProcessError as e: returncode = e.returncode diff --git a/script/update-clang.sh b/script/update-clang.sh index 801d60397145..0175bc2a0730 100755 --- a/script/update-clang.sh +++ b/script/update-clang.sh @@ -8,7 +8,7 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://code.google.com/p/chromium/wiki/UpdatingClang # Reverting problematic clang rolls is safe, though. -CLANG_REVISION=247874 +CLANG_REVISION=261368 # This is incremented when pushing a new build of Clang at the same revision. CLANG_SUB_REVISION=1 diff --git a/script/update-external-binaries.py b/script/update-external-binaries.py index fae268ea8cb7..470f735fdb42 100755 --- a/script/update-external-binaries.py +++ b/script/update-external-binaries.py @@ -8,9 +8,9 @@ from lib.config import get_target_arch from lib.util import safe_mkdir, rm_rf, extract_zip, tempdir, download -VERSION = 'v0.8.0' +VERSION = 'v1.0.0' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) -FRAMEWORKS_URL = 'http://github.com/atom/atom-shell-frameworks/releases' \ +FRAMEWORKS_URL = 'http://github.com/electron/electron-frameworks/releases' \ '/download/' + VERSION @@ -30,7 +30,6 @@ def main(): download_and_unzip('Squirrel') elif sys.platform in ['cygwin', 'win32']: download_and_unzip('directxsdk-' + get_target_arch()) - download_and_unzip('vs2012-crt-' + get_target_arch()) with open(version_file, 'w') as f: f.write(VERSION) diff --git a/script/update.py b/script/update.py index f820248d0aa2..a67a49e7ab51 100755 --- a/script/update.py +++ b/script/update.py @@ -7,7 +7,7 @@ import subprocess import sys from lib.config import get_target_arch, PLATFORM -from lib.util import get_host_arch +from lib.util import get_host_arch, import_vs_env SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) @@ -49,11 +49,14 @@ def update_gyp(): def run_gyp(target_arch, component): + # Update the VS build env. + import_vs_env(target_arch) + env = os.environ.copy() if PLATFORM == 'linux' and target_arch != get_host_arch(): env['GYP_CROSSCOMPILE'] = '1' elif PLATFORM == 'win32': - env['GYP_MSVS_VERSION'] = '2013' + env['GYP_MSVS_VERSION'] = '2015' python = sys.executable if sys.platform == 'cygwin': # Force using win32 python on cygwin. diff --git a/script/upload-index-json.py b/script/upload-index-json.py index 671408fa9219..f5e5b3c7a6ad 100755 --- a/script/upload-index-json.py +++ b/script/upload-index-json.py @@ -4,28 +4,28 @@ import os import sys from lib.config import PLATFORM, s3_config -from lib.util import atom_gyp, execute, s3put, scoped_cwd +from lib.util import electron_gyp, execute, s3put, scoped_cwd SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) OUT_DIR = os.path.join(SOURCE_ROOT, 'out', 'D') -PROJECT_NAME = atom_gyp()['project_name%'] -PRODUCT_NAME = atom_gyp()['product_name%'] +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] def main(): # Upload the index.json. with scoped_cwd(SOURCE_ROOT): if sys.platform == 'darwin': - atom_shell = os.path.join(OUT_DIR, '{0}.app'.format(PRODUCT_NAME), + electron = os.path.join(OUT_DIR, '{0}.app'.format(PRODUCT_NAME), 'Contents', 'MacOS', PRODUCT_NAME) elif sys.platform == 'win32': - atom_shell = os.path.join(OUT_DIR, '{0}.exe'.format(PROJECT_NAME)) + electron = os.path.join(OUT_DIR, '{0}.exe'.format(PROJECT_NAME)) else: - atom_shell = os.path.join(OUT_DIR, PROJECT_NAME) + electron = os.path.join(OUT_DIR, PROJECT_NAME) index_json = os.path.relpath(os.path.join(OUT_DIR, 'index.json')) - execute([atom_shell, + execute([electron, os.path.join('tools', 'dump-version-info.js'), index_json]) diff --git a/script/upload-windows-pdb.py b/script/upload-windows-pdb.py index 12186aad2edc..6e8030337f3c 100755 --- a/script/upload-windows-pdb.py +++ b/script/upload-windows-pdb.py @@ -5,15 +5,15 @@ import glob import sys from lib.config import s3_config -from lib.util import atom_gyp, execute, rm_rf, safe_mkdir, s3put +from lib.util import electron_gyp, execute, rm_rf, safe_mkdir, s3put SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) SYMBOLS_DIR = 'dist\\symbols' DOWNLOAD_DIR = 'vendor\\brightray\\vendor\\download\\libchromiumcontent' -PROJECT_NAME = atom_gyp()['project_name%'] -PRODUCT_NAME = atom_gyp()['product_name%'] +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] PDB_LIST = [ 'out\\R\\{0}.exe.pdb'.format(PROJECT_NAME), diff --git a/script/upload.py b/script/upload.py index 80d9e5e9e090..9faf4fa8d05b 100755 --- a/script/upload.py +++ b/script/upload.py @@ -8,31 +8,31 @@ import sys import tempfile from lib.config import PLATFORM, get_target_arch, get_chromedriver_version, \ - get_platform_key -from lib.util import atom_gyp, execute, get_atom_shell_version, parse_version, \ - scoped_cwd + get_platform_key, get_env_var +from lib.util import electron_gyp, execute, get_electron_version, \ + parse_version, scoped_cwd from lib.github import GitHub -ATOM_SHELL_REPO = 'electron/electron' -ATOM_SHELL_VERSION = get_atom_shell_version() +ELECTRON_REPO = 'electron/electron' +ELECTRON_VERSION = get_electron_version() -PROJECT_NAME = atom_gyp()['project_name%'] -PRODUCT_NAME = atom_gyp()['product_name%'] +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) OUT_DIR = os.path.join(SOURCE_ROOT, 'out', 'R') DIST_DIR = os.path.join(SOURCE_ROOT, 'dist') DIST_NAME = '{0}-{1}-{2}-{3}.zip'.format(PROJECT_NAME, - ATOM_SHELL_VERSION, + ELECTRON_VERSION, get_platform_key(), get_target_arch()) SYMBOLS_NAME = '{0}-{1}-{2}-{3}-symbols.zip'.format(PROJECT_NAME, - ATOM_SHELL_VERSION, + ELECTRON_VERSION, get_platform_key(), get_target_arch()) DSYM_NAME = '{0}-{1}-{2}-{3}-dsym.zip'.format(PROJECT_NAME, - ATOM_SHELL_VERSION, + ELECTRON_VERSION, get_platform_key(), get_target_arch()) @@ -45,16 +45,16 @@ def main(): create_dist = os.path.join(SOURCE_ROOT, 'script', 'create-dist.py') execute([sys.executable, create_dist]) - build_version = get_atom_shell_build_version() - if not ATOM_SHELL_VERSION.startswith(build_version): + build_version = get_electron_build_version() + if not ELECTRON_VERSION.startswith(build_version): error = 'Tag name ({0}) should match build version ({1})\n'.format( - ATOM_SHELL_VERSION, build_version) + ELECTRON_VERSION, build_version) sys.stderr.write(error) sys.stderr.flush() return 1 github = GitHub(auth_token()) - releases = github.repos(ATOM_SHELL_REPO).releases.get() + releases = github.repos(ELECTRON_REPO).releases.get() tag_exists = False for release in releases: if not release['draft'] and release['tag_name'] == args.version: @@ -68,7 +68,7 @@ def main(): # Upload the SHASUMS.txt. execute([sys.executable, os.path.join(SOURCE_ROOT, 'script', 'upload-checksums.py'), - '-v', ATOM_SHELL_VERSION]) + '-v', ELECTRON_VERSION]) # Upload the index.json. execute([sys.executable, @@ -80,25 +80,25 @@ def main(): # Do not upload other files when passed "-p". return - # Upload atom-shell with GitHub Releases API. - upload_atom_shell(github, release, os.path.join(DIST_DIR, DIST_NAME)) - upload_atom_shell(github, release, os.path.join(DIST_DIR, SYMBOLS_NAME)) + # Upload Electron with GitHub Releases API. + upload_electron(github, release, os.path.join(DIST_DIR, DIST_NAME)) + upload_electron(github, release, os.path.join(DIST_DIR, SYMBOLS_NAME)) if PLATFORM == 'darwin': - upload_atom_shell(github, release, os.path.join(DIST_DIR, DSYM_NAME)) + upload_electron(github, release, os.path.join(DIST_DIR, DSYM_NAME)) # Upload free version of ffmpeg. ffmpeg = 'ffmpeg-{0}-{1}-{2}.zip'.format( - ATOM_SHELL_VERSION, get_platform_key(), get_target_arch()) - upload_atom_shell(github, release, os.path.join(DIST_DIR, ffmpeg)) + ELECTRON_VERSION, get_platform_key(), get_target_arch()) + upload_electron(github, release, os.path.join(DIST_DIR, ffmpeg)) # Upload chromedriver and mksnapshot for minor version update. if parse_version(args.version)[2] == '0': chromedriver = 'chromedriver-{0}-{1}-{2}.zip'.format( get_chromedriver_version(), get_platform_key(), get_target_arch()) - upload_atom_shell(github, release, os.path.join(DIST_DIR, chromedriver)) + upload_electron(github, release, os.path.join(DIST_DIR, chromedriver)) mksnapshot = 'mksnapshot-{0}-{1}-{2}.zip'.format( - ATOM_SHELL_VERSION, get_platform_key(), get_target_arch()) - upload_atom_shell(github, release, os.path.join(DIST_DIR, mksnapshot)) + ELECTRON_VERSION, get_platform_key(), get_target_arch()) + upload_electron(github, release, os.path.join(DIST_DIR, mksnapshot)) if PLATFORM == 'win32' and not tag_exists: # Upload PDBs to Windows symbol server. @@ -114,28 +114,28 @@ def main(): def parse_args(): parser = argparse.ArgumentParser(description='upload distribution file') parser.add_argument('-v', '--version', help='Specify the version', - default=ATOM_SHELL_VERSION) + default=ELECTRON_VERSION) parser.add_argument('-p', '--publish-release', help='Publish the release', action='store_true') return parser.parse_args() -def get_atom_shell_build_version(): +def get_electron_build_version(): if get_target_arch() == 'arm' or os.environ.has_key('CI'): # In CI we just build as told. - return ATOM_SHELL_VERSION + return ELECTRON_VERSION if PLATFORM == 'darwin': - atom_shell = os.path.join(SOURCE_ROOT, 'out', 'R', + electron = os.path.join(SOURCE_ROOT, 'out', 'R', '{0}.app'.format(PRODUCT_NAME), 'Contents', 'MacOS', PRODUCT_NAME) elif PLATFORM == 'win32': - atom_shell = os.path.join(SOURCE_ROOT, 'out', 'R', + electron = os.path.join(SOURCE_ROOT, 'out', 'R', '{0}.exe'.format(PROJECT_NAME)) else: - atom_shell = os.path.join(SOURCE_ROOT, 'out', 'R', PROJECT_NAME) + electron = os.path.join(SOURCE_ROOT, 'out', 'R', PROJECT_NAME) - return subprocess.check_output([atom_shell, '--version']).strip() + return subprocess.check_output([electron, '--version']).strip() def dist_newer_than_head(): @@ -192,17 +192,17 @@ def create_release_draft(github, tag): sys.exit(0) data = dict(tag_name=tag, name=name, body=body, draft=True) - r = github.repos(ATOM_SHELL_REPO).releases.post(data=data) + r = github.repos(ELECTRON_REPO).releases.post(data=data) return r -def upload_atom_shell(github, release, file_path): +def upload_electron(github, release, file_path): # Delete the original file before uploading in CI. if os.environ.has_key('CI'): try: for asset in release['assets']: if asset['name'] == os.path.basename(file_path): - github.repos(ATOM_SHELL_REPO).releases.assets(asset['id']).delete() + github.repos(ELECTRON_REPO).releases.assets(asset['id']).delete() break except Exception: pass @@ -211,18 +211,18 @@ def upload_atom_shell(github, release, file_path): params = {'name': os.path.basename(file_path)} headers = {'Content-Type': 'application/zip'} with open(file_path, 'rb') as f: - github.repos(ATOM_SHELL_REPO).releases(release['id']).assets.post( + github.repos(ELECTRON_REPO).releases(release['id']).assets.post( params=params, headers=headers, data=f, verify=False) def publish_release(github, release_id): data = dict(draft=False) - github.repos(ATOM_SHELL_REPO).releases(release_id).patch(data=data) + github.repos(ELECTRON_REPO).releases(release_id).patch(data=data) def auth_token(): - token = os.environ.get('ATOM_SHELL_GITHUB_TOKEN') - message = ('Error: Please set the $ATOM_SHELL_GITHUB_TOKEN ' + token = get_env_var('GITHUB_TOKEN') + message = ('Error: Please set the $ELECTRON_GITHUB_TOKEN ' 'environment variable, which is your personal token') assert token, message return token diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 8afa90bb9f96..df356ecb9053 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -3,29 +3,47 @@ const ChildProcess = require('child_process') const https = require('https') const fs = require('fs') const path = require('path') -const remote = require('electron').remote +const {remote} = require('electron') -const app = remote.require('electron').app -const BrowserWindow = remote.require('electron').BrowserWindow +const {app, BrowserWindow, ipcMain} = remote const isCI = remote.getGlobal('isCi') describe('electron module', function () { - it('allows old style require by default', function () { - require('shell') + it('does not expose internal modules to require', function () { + assert.throws(function () { + require('clipboard') + }, /Cannot find module 'clipboard'/) }) - it('can prevent exposing internal modules to require', function (done) { - const electron = require('electron') - const clipboard = require('clipboard') - assert.equal(typeof clipboard, 'object') - electron.hideInternalModules() - try { - require('clipboard') - } catch (err) { - assert.equal(err.message, "Cannot find module 'clipboard'") - done() - } + describe('require("electron")', function () { + let window = null + + beforeEach(function () { + if (window != null) { + window.destroy() + } + window = new BrowserWindow({ + show: false, + width: 400, + height: 400 + }) + }) + + afterEach(function () { + if (window != null) { + window.destroy() + } + window = null + }) + + it('always returns the internal electron module', function (done) { + ipcMain.once('answer', function () { + done() + }) + window.loadURL('file://' + path.join(__dirname, 'fixtures', 'api', 'electron-module-app', 'index.html')) + }) }) + }) describe('app module', function () { diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index e76821020bdc..8af2fb826574 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -148,6 +148,7 @@ describe('browser-window module', function () { it('should emit did-fail-load event for files that do not exist', function (done) { w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { assert.equal(code, -6) + assert.equal(desc, 'ERR_FILE_NOT_FOUND') assert.equal(isMainFrame, true) done() }) @@ -283,6 +284,21 @@ describe('browser-window module', function () { }) }) + describe('BrowserWindow.setAspectRatio(ratio)', function () { + it('resets the behaviour when passing in 0', function (done) { + var size = [300, 400] + w.setAspectRatio(1/2) + w.setAspectRatio(0) + w.once('resize', function () { + var newSize = w.getSize() + assert.equal(newSize[0], size[0]) + assert.equal(newSize[1], size[1]) + done() + }) + w.setSize(size[0], size[1]) + }) + }) + describe('BrowserWindow.setPosition(x, y)', function () { it('sets the window position', function (done) { var pos = [10, 10] @@ -475,18 +491,11 @@ describe('browser-window module', function () { }) describe('beforeunload handler', function () { - it('returning true would not prevent close', function (done) { + it('returning undefined would not prevent close', function (done) { w.on('closed', function () { done() }) - w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-true.html')) - }) - - it('returning non-empty string would not prevent close', function (done) { - w.on('closed', function () { - done() - }) - w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-string.html')) + w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-undefined.html')) }) it('returning false would prevent close', function (done) { @@ -824,6 +833,54 @@ describe('browser-window module', function () { }) describe('dev tool extensions', function () { + describe('BrowserWindow.addDevToolsExtension', function () { + this.timeout(10000) + + beforeEach(function () { + BrowserWindow.removeDevToolsExtension('foo') + + var extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo') + BrowserWindow.addDevToolsExtension(extensionPath) + + w.webContents.on('devtools-opened', function () { + var showPanelIntevalId = setInterval(function () { + if (w && w.devToolsWebContents) { + w.devToolsWebContents.executeJavaScript('(' + (function () { + var lastPanelId = WebInspector.inspectorView._tabbedPane._tabs.peekLast().id + WebInspector.inspectorView.showPanel(lastPanelId) + }).toString() + ')()') + } else { + clearInterval(showPanelIntevalId) + } + }, 100) + }) + + w.loadURL('about:blank') + }) + + describe('when the devtools is docked', function () { + it('creates the extension', function (done) { + w.webContents.openDevTools({mode: 'bottom'}) + + ipcMain.once('answer', function (event, message) { + assert.equal(message, 'extension loaded') + done() + }) + }) + }) + + describe('when the devtools is undocked', function () { + it('creates the extension', function (done) { + w.webContents.openDevTools({mode: 'undocked'}) + + ipcMain.once('answer', function (event, message) { + assert.equal(message, 'extension loaded') + done() + }) + }) + }) + }) + it('serializes the registered extensions on quit', function () { var extensionName = 'foo' var extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', extensionName) @@ -880,24 +937,4 @@ describe('browser-window module', function () { w.loadURL(server.url) }) }) - - describe('deprecated options', function () { - it('throws a deprecation error for option keys using hyphens instead of camel case', function () { - assert.throws(function () { - return new BrowserWindow({'min-width': 500}) - }, 'min-width is deprecated. Use minWidth instead.') - }) - - it('throws a deprecation error for webPreference keys using hyphens instead of camel case', function () { - assert.throws(function () { - return new BrowserWindow({webPreferences: {'node-integration': false}}) - }, 'node-integration is deprecated. Use nodeIntegration instead.') - }) - - it('throws a deprecation error for option keys that should be set on webPreferences', function () { - assert.throws(function () { - return new BrowserWindow({zoomFactor: 1}) - }, 'options.zoomFactor is deprecated. Use options.webPreferences.zoomFactor instead.') - }) - }) }) diff --git a/spec/api-clipboard-spec.js b/spec/api-clipboard-spec.js index 63f1d907e8a9..344e01452fba 100644 --- a/spec/api-clipboard-spec.js +++ b/spec/api-clipboard-spec.js @@ -24,20 +24,20 @@ describe('clipboard module', function () { }) }) - describe('clipboard.readHtml()', function () { + describe('clipboard.readHTML()', function () { it('returns markup correctly', function () { var text = 'Hi' var markup = process.platform === 'darwin' ? "Hi" : process.platform === 'linux' ? 'Hi' : 'Hi' - clipboard.writeHtml(text) - assert.equal(clipboard.readHtml(), markup) + clipboard.writeHTML(text) + assert.equal(clipboard.readHTML(), markup) }) }) - describe('clipboard.readRtf', function () { + describe('clipboard.readRTF', function () { it('returns rtf text correctly', function () { var rtf = '{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}' - clipboard.writeRtf(rtf) - assert.equal(clipboard.readRtf(), rtf) + clipboard.writeRTF(rtf) + assert.equal(clipboard.readRTF(), rtf) }) }) @@ -55,8 +55,8 @@ describe('clipboard module', function () { image: p }) assert.equal(clipboard.readText(), text) - assert.equal(clipboard.readHtml(), markup) - assert.equal(clipboard.readRtf(), rtf) + assert.equal(clipboard.readHTML(), markup) + assert.equal(clipboard.readRTF(), rtf) assert.equal(clipboard.readImage().toDataURL(), i.toDataURL()) }) }) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index e5a3223eed8f..b4f63fe1ef27 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -81,12 +81,12 @@ describe('crash-reporter module', function () { crashReporter.start({ companyName: 'Missing submitURL' }) - }) + }, /submitURL is a required option to crashReporter\.start/) assert.throws(function () { crashReporter.start({ submitURL: 'Missing companyName' }) - }) + }, /companyName is a required option to crashReporter\.start/) }) }) }) diff --git a/spec/api-deprecations-spec.js b/spec/api-deprecations-spec.js index 375de5895fee..5b618ac90165 100644 --- a/spec/api-deprecations-spec.js +++ b/spec/api-deprecations-spec.js @@ -14,14 +14,14 @@ describe('deprecations', function () { messages.push(message) }) - require('electron').webFrame.registerUrlSchemeAsSecure('some-scheme') + require('electron').deprecate.log('this is deprecated') - assert.deepEqual(messages, ['registerUrlSchemeAsSecure is deprecated. Use registerURLSchemeAsSecure instead.']) + assert.deepEqual(messages, ['this is deprecated']) }) it('throws an exception if no deprecation handler is specified', function () { assert.throws(function () { - require('electron').webFrame.registerUrlSchemeAsPrivileged('some-scheme') - }, 'registerUrlSchemeAsPrivileged is deprecated. Use registerURLSchemeAsPrivileged instead.') + require('electron').deprecate.log('this is deprecated') + }, /this is deprecated/) }) }) diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index c98689287cea..e88815873af9 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -3,11 +3,8 @@ const assert = require('assert') const path = require('path') -const ipcRenderer = require('electron').ipcRenderer -const remote = require('electron').remote - -const ipcMain = remote.require('electron').ipcMain -const BrowserWindow = remote.require('electron').BrowserWindow +const {ipcRenderer, remote} = require('electron') +const {ipcMain, webContents, BrowserWindow} = remote const comparePaths = function (path1, path2) { if (process.platform === 'win32') { @@ -32,6 +29,13 @@ describe('ipc module', function () { assert.equal(a.id, 1127) }) + it('should work when object has no prototype', function () { + var a = remote.require(path.join(fixtures, 'module', 'no-prototype.js')) + assert.equal(a.foo.bar, 'baz') + assert.equal(a.foo.baz, false) + assert.equal(a.bar, 1234) + }) + it('should search module from the user app', function () { comparePaths(path.normalize(remote.process.mainModule.filename), path.resolve(__dirname, 'static', 'main.js')) comparePaths(path.normalize(remote.process.mainModule.paths[0]), path.resolve(__dirname, 'static', 'node_modules')) @@ -106,6 +110,22 @@ describe('ipc module', function () { done() }) }) + + it('handles rejections via catch(onRejected)', function (done) { + var promise = remote.require(path.join(fixtures, 'module', 'rejected-promise.js')) + promise.reject(Promise.resolve(1234)).catch(function (error) { + assert.equal(error.message, 'rejected') + done() + }) + }) + + it('handles rejections via then(onFulfilled, onRejected)', function (done) { + var promise = remote.require(path.join(fixtures, 'module', 'rejected-promise.js')) + promise.reject(Promise.resolve(1234)).then(function () {}, function (error) { + assert.equal(error.message, 'rejected') + done() + }) + }) }) describe('remote webContents', function () { @@ -182,6 +202,10 @@ describe('ipc module', function () { }) describe('ipc.sendSync', function () { + afterEach(function () { + ipcMain.removeAllListeners('send-sync-message') + }) + it('can be replied by setting event.returnValue', function () { var msg = ipcRenderer.sendSync('echo', 'test') assert.equal(msg, 'test') @@ -200,6 +224,45 @@ describe('ipc module', function () { }) w.loadURL('file://' + path.join(fixtures, 'api', 'send-sync-message.html')) }) + + it('does not crash when reply is sent by multiple listeners', function (done) { + var w = new BrowserWindow({ + show: false + }) + ipcMain.on('send-sync-message', function (event) { + event.returnValue = null + }) + ipcMain.on('send-sync-message', function (event) { + event.returnValue = null + w.destroy() + done() + }) + w.loadURL('file://' + path.join(fixtures, 'api', 'send-sync-message.html')) + }) + }) + + describe('ipcRenderer.sendTo', function () { + let contents = null + beforeEach(function () { + contents = webContents.create({}) + }) + afterEach(function () { + ipcRenderer.removeAllListeners('pong') + contents.destroy() + contents = null + }) + + it('sends message to WebContents', function (done) { + const webContentsId = remote.getCurrentWebContents().id + ipcRenderer.once('pong', function (event, id) { + assert.equal(webContentsId, id) + done() + }) + contents.once('did-finish-load', function () { + ipcRenderer.sendTo(contents.id, 'ping', webContentsId) + }) + contents.loadURL('file://' + path.join(fixtures, 'pages', 'ping-pong.html')) + }) }) describe('remote listeners', function () { diff --git a/spec/api-protocol-spec.js b/spec/api-protocol-spec.js index 9f2a25eb4a54..803511917104 100644 --- a/spec/api-protocol-spec.js +++ b/spec/api-protocol-spec.js @@ -3,7 +3,7 @@ const http = require('http') const path = require('path') const qs = require('querystring') const remote = require('electron').remote -const protocol = remote.require('electron').protocol +const {BrowserWindow, protocol, webContents} = remote describe('protocol module', function () { var protocolName = 'sp' @@ -344,6 +344,7 @@ describe('protocol module', function () { }) }) }) + it('sends object as response', function (done) { var handler = function (request, callback) { callback({ @@ -394,7 +395,7 @@ describe('protocol module', function () { var handler = function (request, callback) { callback(fakeFilePath) } - protocol.registerBufferProtocol(protocolName, handler, function (error) { + protocol.registerFileProtocol(protocolName, handler, function (error) { if (error) { return done(error) } @@ -415,7 +416,7 @@ describe('protocol module', function () { var handler = function (request, callback) { callback(new Date()) } - protocol.registerBufferProtocol(protocolName, handler, function (error) { + protocol.registerFileProtocol(protocolName, handler, function (error) { if (error) { return done(error) } @@ -509,6 +510,42 @@ describe('protocol module', function () { }) }) }) + + it('works when target URL redirects', function (done) { + var contents = null + var server = http.createServer(function (req, res) { + if (req.url == '/serverRedirect') { + res.statusCode = 301 + res.setHeader('Location', 'http://' + req.rawHeaders[1]) + res.end() + } else { + res.end(text) + } + }) + server.listen(0, '127.0.0.1', function () { + var port = server.address().port + var url = `${protocolName}://fake-host` + var redirectURL = `http://127.0.0.1:${port}/serverRedirect` + var handler = function (request, callback) { + callback({ + url: redirectURL + }) + } + protocol.registerHttpProtocol(protocolName, handler, function (error) { + if (error) { + return done(error) + } + contents = webContents.create({}) + contents.on('did-finish-load', function () { + assert.equal(contents.getURL(), url) + server.close() + contents.destroy() + done() + }) + contents.loadURL(url) + }) + }) + }) }) describe('protocol.isProtocolHandled', function () { @@ -814,4 +851,74 @@ describe('protocol module', function () { }) }) }) + + describe('protocol.registerStandardSchemes', function () { + const standardScheme = remote.getGlobal('standardScheme') + const origin = standardScheme + '://fake-host' + const imageURL = origin + '/test.png' + const filePath = path.join(__dirname, 'fixtures', 'pages', 'b.html') + const fileContent = '' + var w = null + var success = null + + beforeEach(function () { + w = new BrowserWindow({show: false}) + success = false + }) + + afterEach(function (done) { + protocol.unregisterProtocol(standardScheme, function () { + if (w != null) { + w.destroy() + } + w = null + done() + }) + }) + + it('resolves relative resources', function (done) { + var handler = function (request, callback) { + if (request.url === imageURL) { + success = true + callback() + } else { + callback(filePath) + } + } + protocol.registerFileProtocol(standardScheme, handler, function (error) { + if (error) { + return done(error) + } + w.webContents.on('did-finish-load', function () { + assert(success) + done() + }) + w.loadURL(origin) + }) + }) + + it('resolves absolute resources', function (done) { + var handler = function (request, callback) { + if (request.url === imageURL) { + success = true + callback() + } else { + callback({ + data: fileContent, + mimeType: 'text/html' + }) + } + } + protocol.registerStringProtocol(standardScheme, handler, function (error) { + if (error) { + return done(error) + } + w.webContents.on('did-finish-load', function () { + assert(success) + done() + }) + w.loadURL(origin) + }) + }) + }) }) diff --git a/spec/asar-spec.js b/spec/asar-spec.js index a0cb7b4aabd2..ac0779d2f266 100644 --- a/spec/asar-spec.js +++ b/spec/asar-spec.js @@ -17,7 +17,7 @@ describe('asar package', function () { it('does not leak fd', function () { var readCalls = 1 while (readCalls <= 10000) { - fs.readFileSync(path.join(process.resourcesPath, 'electron.asar', 'renderer', 'api', 'ipc.js')) + fs.readFileSync(path.join(process.resourcesPath, 'electron.asar', 'renderer', 'api', 'ipc-renderer.js')) readCalls++ } }) @@ -555,6 +555,30 @@ describe('asar package', function () { }) }) + describe('child_process.exec', function () { + var child_process = require('child_process'); + var echo = path.join(fixtures, 'asar', 'echo.asar', 'echo') + + it('should not try to extract the command if there is a reference to a file inside an .asar', function (done) { + child_process.exec('echo ' + echo + ' foo bar', function (error, stdout) { + assert.equal(error, null) + assert.equal(stdout.toString().replace(/\r/g, ''), echo + ' foo bar\n') + done() + }) + }) + }) + + describe('child_process.execSync', function () { + var child_process = require('child_process'); + var echo = path.join(fixtures, 'asar', 'echo.asar', 'echo') + + it('should not try to extract the command if there is a reference to a file inside an .asar', function (done) { + var stdout = child_process.execSync('echo ' + echo + ' foo bar') + assert.equal(stdout.toString().replace(/\r/g, ''), echo + ' foo bar\n') + done() + }) + }) + describe('child_process.execFile', function () { var echo, execFile, execFileSync, ref2 if (process.platform !== 'darwin') { diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 577f020128ad..cd046ab29abf 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -155,6 +155,10 @@ describe('chromium feature', function () { }) describe('window.open', function () { + if (process.env.TRAVIS === 'true' && process.platform === 'darwin') { + return + } + this.timeout(20000) it('returns a BrowserWindowProxy object', function () { diff --git a/spec/fixtures/api/close-beforeunload-string.html b/spec/fixtures/api/close-beforeunload-string.html deleted file mode 100644 index c8c6c6beacdd..000000000000 --- a/spec/fixtures/api/close-beforeunload-string.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/spec/fixtures/api/close-beforeunload-true.html b/spec/fixtures/api/close-beforeunload-undefined.html similarity index 93% rename from spec/fixtures/api/close-beforeunload-true.html rename to spec/fixtures/api/close-beforeunload-undefined.html index 6de0c6cd3989..b4e4178f6a1d 100644 --- a/spec/fixtures/api/close-beforeunload-true.html +++ b/spec/fixtures/api/close-beforeunload-undefined.html @@ -5,7 +5,6 @@ setTimeout(function() { require('electron').remote.getCurrentWindow().emit('onbeforeunload'); }, 0); - return true; } window.close(); diff --git a/spec/fixtures/api/electron-module-app/index.html b/spec/fixtures/api/electron-module-app/index.html new file mode 100644 index 000000000000..02bfee958747 --- /dev/null +++ b/spec/fixtures/api/electron-module-app/index.html @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/spec/fixtures/api/electron-module-app/node_modules/electron/index.js b/spec/fixtures/api/electron-module-app/node_modules/electron/index.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/spec/fixtures/api/electron-module-app/node_modules/electron/package.json b/spec/fixtures/api/electron-module-app/node_modules/electron/package.json new file mode 100644 index 000000000000..07e3804ebb16 --- /dev/null +++ b/spec/fixtures/api/electron-module-app/node_modules/electron/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron", + "main": "index.js" +} diff --git a/spec/fixtures/api/electron-module-app/node_modules/foo/index.js b/spec/fixtures/api/electron-module-app/node_modules/foo/index.js new file mode 100644 index 000000000000..11d763e51742 --- /dev/null +++ b/spec/fixtures/api/electron-module-app/node_modules/foo/index.js @@ -0,0 +1 @@ +exports.bar = function () {} diff --git a/spec/fixtures/api/electron-module-app/node_modules/foo/package.json b/spec/fixtures/api/electron-module-app/node_modules/foo/package.json new file mode 100644 index 000000000000..596ac286ecad --- /dev/null +++ b/spec/fixtures/api/electron-module-app/node_modules/foo/package.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "main": "index.js" +} diff --git a/spec/fixtures/devtools-extensions/foo/foo.html b/spec/fixtures/devtools-extensions/foo/foo.html new file mode 100644 index 000000000000..a326639c38de --- /dev/null +++ b/spec/fixtures/devtools-extensions/foo/foo.html @@ -0,0 +1,10 @@ + + + + + foo + + + diff --git a/spec/fixtures/devtools-extensions/foo/index.html b/spec/fixtures/devtools-extensions/foo/index.html new file mode 100644 index 000000000000..4e7439422e47 --- /dev/null +++ b/spec/fixtures/devtools-extensions/foo/index.html @@ -0,0 +1,14 @@ + + + + + + + + + a custom devtools extension + + diff --git a/spec/fixtures/devtools-extensions/foo/manifest.json b/spec/fixtures/devtools-extensions/foo/manifest.json index bde99de9287a..413853e8d351 100644 --- a/spec/fixtures/devtools-extensions/foo/manifest.json +++ b/spec/fixtures/devtools-extensions/foo/manifest.json @@ -1,3 +1,5 @@ { - "name": "foo" + "name": "foo", + "version": "1.0", + "devtools_page": "foo.html" } diff --git a/spec/fixtures/module/no-prototype.js b/spec/fixtures/module/no-prototype.js new file mode 100644 index 000000000000..f298925b80f2 --- /dev/null +++ b/spec/fixtures/module/no-prototype.js @@ -0,0 +1,4 @@ +const foo = Object.create(null) +foo.bar = 'baz' +foo.baz = false +module.exports = {foo: foo, bar: 1234} diff --git a/spec/fixtures/module/preload-webview.js b/spec/fixtures/module/preload-webview.js new file mode 100644 index 000000000000..273065cdaacd --- /dev/null +++ b/spec/fixtures/module/preload-webview.js @@ -0,0 +1,5 @@ +const {ipcRenderer} = require('electron') + +window.onload = function () { + ipcRenderer.send('webview', typeof WebView) +} diff --git a/spec/fixtures/module/process-stdout.js b/spec/fixtures/module/process-stdout.js new file mode 100644 index 000000000000..953750a247f9 --- /dev/null +++ b/spec/fixtures/module/process-stdout.js @@ -0,0 +1 @@ +process.stdout.write('pipes stdio') diff --git a/spec/fixtures/module/rejected-promise.js b/spec/fixtures/module/rejected-promise.js new file mode 100644 index 000000000000..93dd9accc030 --- /dev/null +++ b/spec/fixtures/module/rejected-promise.js @@ -0,0 +1,5 @@ +exports.reject = function (promise) { + return promise.then(function () { + throw Error('rejected') + }) +} diff --git a/spec/fixtures/pages/b.html b/spec/fixtures/pages/b.html index 812431f2b45b..d35c863b42c5 100644 --- a/spec/fixtures/pages/b.html +++ b/spec/fixtures/pages/b.html @@ -1,8 +1,8 @@ + - diff --git a/spec/fixtures/pages/ping-pong.html b/spec/fixtures/pages/ping-pong.html new file mode 100644 index 000000000000..d10e7898653b --- /dev/null +++ b/spec/fixtures/pages/ping-pong.html @@ -0,0 +1,11 @@ + + + + + + diff --git a/spec/fixtures/pages/visibilitychange.html b/spec/fixtures/pages/visibilitychange.html new file mode 100644 index 000000000000..9f49f520de1f --- /dev/null +++ b/spec/fixtures/pages/visibilitychange.html @@ -0,0 +1,11 @@ + + + + + diff --git a/spec/fixtures/pages/webview-visibilitychange.html b/spec/fixtures/pages/webview-visibilitychange.html new file mode 100644 index 000000000000..7c8b7cef9df5 --- /dev/null +++ b/spec/fixtures/pages/webview-visibilitychange.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/pages/webview-zoom-factor.html b/spec/fixtures/pages/webview-zoom-factor.html new file mode 100644 index 000000000000..006b416cfef5 --- /dev/null +++ b/spec/fixtures/pages/webview-zoom-factor.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/pages/zoom-factor.html b/spec/fixtures/pages/zoom-factor.html new file mode 100644 index 000000000000..b9f8f988caea --- /dev/null +++ b/spec/fixtures/pages/zoom-factor.html @@ -0,0 +1,8 @@ + + + + + diff --git a/spec/modules-spec.js b/spec/modules-spec.js index 0f694e5e6d80..fbc66a082512 100644 --- a/spec/modules-spec.js +++ b/spec/modules-spec.js @@ -23,6 +23,8 @@ describe('third-party module', function () { }) describe('ffi', function () { + if (process.platform === 'win32') return + it('does not crash', function () { var ffi = require('ffi') var libm = ffi.Library('libm', { diff --git a/spec/node-spec.js b/spec/node-spec.js index 0ab98aa67ab9..93a247ef4ff6 100644 --- a/spec/node-spec.js +++ b/spec/node-spec.js @@ -3,7 +3,7 @@ const child_process = require('child_process') const fs = require('fs') const path = require('path') const os = require('os') -const remote = require('electron').remote +const {remote} = require('electron') describe('node feature', function () { var fixtures = path.join(__dirname, 'fixtures') @@ -76,6 +76,19 @@ describe('node feature', function () { }) child.send('message') }) + + it('pipes stdio', function (done) { + let child = child_process.fork(path.join(fixtures, 'module', 'process-stdout.js'), {silent: true}) + let data = '' + child.stdout.on('data', (chunk) => { + data += String(chunk) + }) + child.on('exit', (code) => { + assert.equal(code, 0) + assert.equal(data, 'pipes stdio') + done() + }) + }) }) }) diff --git a/spec/static/main.js b/spec/static/main.js index 025ff394bc66..33c3bb48136a 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -6,6 +6,7 @@ const app = electron.app const ipcMain = electron.ipcMain const dialog = electron.dialog const BrowserWindow = electron.BrowserWindow +const protocol = electron.protocol const fs = require('fs') const path = require('path') @@ -71,6 +72,10 @@ if (global.isCi) { }) } +// Register app as standard scheme. +global.standardScheme = 'app' +protocol.registerStandardSchemes([global.standardScheme]) + app.on('window-all-closed', function () { app.quit() }) diff --git a/spec/webview-spec.js b/spec/webview-spec.js index d2c37c857df1..b1fa4405ada8 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -5,10 +5,12 @@ const url = require('url') const {app, session, ipcMain, BrowserWindow} = require('electron').remote describe(' tag', function () { - this.timeout(10000) + this.timeout(20000) var fixtures = path.join(__dirname, 'fixtures') + var webview = null + let w = null beforeEach(function () { webview = new WebView() @@ -18,17 +20,38 @@ describe(' tag', function () { if (document.body.contains(webview)) { document.body.removeChild(webview) } + if (w) { + w.destroy() + w = null + } }) it('works without script tag in page', function (done) { - let w = new BrowserWindow({show: false}) + w = new BrowserWindow({show: false}) ipcMain.once('pong', function () { - w.destroy() done() }) w.loadURL('file://' + fixtures + '/pages/webview-no-script.html') }) + it('is disabled when nodeIntegration is disabled', function (done) { + w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: false, + preload: path.join(fixtures, 'module', 'preload-webview.js') + }, + }) + ipcMain.once('webview', function (event, type) { + if (type === 'undefined') { + done() + } else { + done('WebView still exists') + } + }) + w.loadURL('file://' + fixtures + '/pages/webview-no-script.html') + }) + describe('src attribute', function () { it('specifies the page to load', function (done) { webview.addEventListener('console-message', function (e) { @@ -84,40 +107,6 @@ describe(' tag', function () { document.body.appendChild(webview) }) - it('disables node integration when disabled on the parent BrowserWindow', function (done) { - var b = undefined - - ipcMain.once('answer', function (event, typeofProcess) { - try { - assert.equal(typeofProcess, 'undefined') - done() - } finally { - b.close() - } - }) - - var windowUrl = require('url').format({ - pathname: `${fixtures}/pages/webview-no-node-integration-on-window.html`, - protocol: 'file', - query: { - p: `${fixtures}/pages/web-view-log-process.html` - }, - slashes: true - }) - var preload = path.join(fixtures, 'module', 'answer.js') - - b = new BrowserWindow({ - height: 400, - width: 400, - show: false, - webPreferences: { - preload: preload, - nodeIntegration: false, - } - }) - b.loadURL(windowUrl) - }) - it('disables node integration on child windows when it is disabled on the webview', function (done) { app.once('browser-window-created', function (event, window) { assert.equal(window.webContents.getWebPreferences().nodeIntegration, false) @@ -270,6 +259,30 @@ describe(' tag', function () { webview.src = 'data:text/html;base64,' + encoded document.body.appendChild(webview) }) + + it('does not break node integration', function (done) { + webview.addEventListener('console-message', function (e) { + assert.equal(e.message, 'function object object') + done() + }) + webview.setAttribute('nodeintegration', 'on') + webview.setAttribute('disablewebsecurity', '') + webview.src = 'file://' + fixtures + '/pages/d.html' + document.body.appendChild(webview) + }) + + it('does not break preload script', function (done) { + var listener = function (e) { + assert.equal(e.message, 'function object object') + webview.removeEventListener('console-message', listener) + done() + } + webview.addEventListener('console-message', listener) + webview.setAttribute('disablewebsecurity', '') + webview.setAttribute('preload', fixtures + '/module/preload.js') + webview.src = 'file://' + fixtures + '/pages/e.html' + document.body.appendChild(webview) + }) }) describe('partition attribute', function () { @@ -321,6 +334,10 @@ describe(' tag', function () { }) describe('allowpopups attribute', function () { + if (process.env.TRAVIS === 'true' && process.platform === 'darwin') { + return + } + it('can not open new window when not set', function (done) { var listener = function (e) { assert.equal(e.message, 'null') @@ -346,6 +363,10 @@ describe(' tag', function () { }) describe('new-window event', function () { + if (process.env.TRAVIS === 'true' && process.platform === 'darwin') { + return + } + it('emits when window.open is called', function (done) { webview.addEventListener('new-window', function (e) { assert.equal(e.url, 'http://host/') @@ -855,4 +876,40 @@ describe(' tag', function () { document.body.appendChild(webview) }) }) + + it('inherits the zoomFactor of the parent window', function (done) { + w = new BrowserWindow({ + show: false, + webPreferences: { + zoomFactor: 1.2 + } + }) + ipcMain.once('pong', function (event, zoomFactor, zoomLevel) { + assert.equal(zoomFactor, 1.2) + assert.equal(zoomLevel, 1) + done() + }) + w.loadURL('file://' + fixtures + '/pages/webview-zoom-factor.html') + }) + + it('inherits the parent window visibility state and receives visibilitychange events', function (done) { + w = new BrowserWindow({ + show: false + }) + + ipcMain.once('pong', function (event, visibilityState, hidden) { + assert.equal(visibilityState, 'hidden') + assert.equal(hidden, true) + + w.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', 'visible') + + ipcMain.once('pong', function (event, visibilityState, hidden) { + assert.equal(visibilityState, 'visible') + assert.equal(hidden, false) + done() + }) + }) + + w.loadURL('file://' + fixtures + '/pages/webview-visibilitychange.html') + }) }) diff --git a/tools/dump-version-info.js b/tools/dump-version-info.js index b5df69f4e9b1..8b0255352e1f 100644 --- a/tools/dump-version-info.js +++ b/tools/dump-version-info.js @@ -1,4 +1,4 @@ -var app = require('app') +var app = require('electron').app var fs = require('fs') var request = require('request') diff --git a/tools/js2asar.py b/tools/js2asar.py index 7860176c93c7..adad1751e33d 100755 --- a/tools/js2asar.py +++ b/tools/js2asar.py @@ -29,22 +29,10 @@ def copy_files(source_files, output_dir): def call_asar(archive, output_dir): - asar = os.path.join(SOURCE_ROOT, 'node_modules', 'asar', 'bin', 'asar') - subprocess.check_call([find_node(), asar, 'pack', output_dir, archive]) - - -def find_node(): - WINDOWS_NODE_PATHs = [ - 'C:/Program Files (x86)/nodejs', - 'C:/Program Files/nodejs', - ] + os.environ['PATH'].split(os.pathsep) - + asar = os.path.join(SOURCE_ROOT, 'node_modules', '.bin', 'asar') if sys.platform in ['win32', 'cygwin']: - for path in WINDOWS_NODE_PATHs: - full_path = os.path.join(path, 'node.exe') - if os.path.exists(full_path): - return full_path - return 'node' + asar += '.cmd' + subprocess.check_call([asar, 'pack', output_dir, archive]) def safe_mkdir(path): diff --git a/vendor/breakpad b/vendor/breakpad index 4ee7e1a703d0..c566c50d81f7 160000 --- a/vendor/breakpad +++ b/vendor/breakpad @@ -1 +1 @@ -Subproject commit 4ee7e1a703d066861b7bf6fce28526f8ed07dcd6 +Subproject commit c566c50d81f7b1edeaee9f11f5d07bda858d6b64 diff --git a/vendor/brightray b/vendor/brightray index 9a5b443e4953..9ccab3c9a87c 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 9a5b443e4953fa51ddd0a8d4739e60edf0a666a3 +Subproject commit 9ccab3c9a87cc57b4a37c4a03e17b589ac81d6ae diff --git a/vendor/crashpad b/vendor/crashpad index db713da7554f..51f78aefa872 160000 --- a/vendor/crashpad +++ b/vendor/crashpad @@ -1 +1 @@ -Subproject commit db713da7554f565e43c6dcf9a51b59ccc4f06066 +Subproject commit 51f78aefa872211022ae2d44260cbfd07a6aeb6a diff --git a/vendor/native_mate b/vendor/native_mate index 0df2d882ea22..4ad6ecd19617 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit 0df2d882ea2286e6335f206b7002037fce66c4a5 +Subproject commit 4ad6ecd19617ac33c09e93ccb6d8e652ac1ac126 diff --git a/vendor/node b/vendor/node index 6bcd8af891a9..d4528c219df8 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 6bcd8af891a991f8aa196e49e6bf908ebbe24cae +Subproject commit d4528c219df8f442d769bae054883e1af79f105e