From 19d7f0733e77a57a5bf5743917c7d6f9abc10b50 Mon Sep 17 00:00:00 2001 From: Catalin Ionut Fratila Date: Fri, 10 Feb 2017 14:26:53 +0100 Subject: [PATCH 01/98] create-dist: Adding argument to supress api docs generation. --- script/create-dist.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/script/create-dist.py b/script/create-dist.py index 4aa67eacd676..f9d590259c1e 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import argparse import glob import os import re @@ -86,7 +87,9 @@ def main(): copy_chrome_binary('mksnapshot') copy_license() - if PLATFORM != 'win32': + args = parse_args() + + if PLATFORM != 'win32' and not args.no_api_docs: create_api_json_schema() if PLATFORM == 'linux': @@ -241,5 +244,13 @@ def create_symbols_zip(): make_zip(os.path.join(DIST_DIR, pdb_name), pdbs + licenses, []) +def parse_args(): + parser = argparse.ArgumentParser(description='Create Electron Distribution') + parser.add_argument('--no_api_docs', + action='store_true', + help='Skip generating the Electron API Documentation!') + return parser.parse_args() + + if __name__ == '__main__': sys.exit(main()) From 8aba64025038e79f043793b29871e77dd88bc118 Mon Sep 17 00:00:00 2001 From: mst128256 Date: Thu, 9 Mar 2017 16:01:33 +0100 Subject: [PATCH 02/98] added default menu items for 'Edit' and 'Window' #2814 --- docs/api/menu-item.md | 3 ++ lib/browser/api/menu-item-roles.js | 81 ++++++++++++++++++++++++++++++ lib/browser/api/menu-item.js | 2 +- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 1c12d9fdacd1..76fcae1129f3 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -64,6 +64,9 @@ The `role` property can have following values: * `zoomin` - Zoom in the focused page by 10% * `zoomout` - Zoom out the focused page by 10% +* `menuEdit` - Whole default "Edit" menu (Undo,Copy, etc.) +* `menuWindow` - Whole default "Window" menu (Minimize, Close, etc.) + On macOS `role` can also have following additional values: * `about` - Map to the `orderFrontStandardAboutPanel` action diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 8a78670267ae..254283b86be8 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -154,6 +154,73 @@ const roles = { webContents.setZoomLevel(zoomLevel - 0.5) }) } + }, + // submenu Edit (should fit both Mac & Windows) + menuEdit: { + label: 'Edit', + submenu: [ + { + role: 'undo' + }, + { + role: 'redo' + }, + { + type: 'separator' + }, + { + role: 'cut' + }, + { + role: 'copy' + }, + { + role: 'paste' + }, + + process.platform === 'darwin' ? + { + role: 'pasteandmatchstyle' + } : {}, + + { + role: 'delete' + }, + + process.platform === 'win32' ? + { + type: 'separator' + } : {}, + + { + role: 'selectall' + } + ] + }, + + // submenu Window should be used for Mac only + menuWindow: { + label: 'Window', + submenu: [ + { + role: 'minimize' + }, + { + role: 'close' + }, + + process.platform === 'darwin' ? + { + type: 'separator' + } : {}, + + process.platform === 'darwin' ? + { + label: 'Bring All to Front', + role: 'front' + } : {} + + ] } } @@ -176,6 +243,20 @@ exports.getDefaultAccelerator = (role) => { if (roles.hasOwnProperty(role)) return roles[role].accelerator } +exports.getDefaultSubmenu = (role) => { + if (roles.hasOwnProperty(role)) { + submenu = roles[role].submenu + + // remove empty objects from within the submenu + if (Array.isArray(submenu)) + submenu = submenu.filter(function(n){ + return n.constructor !== Object || Object.keys(n).length > 0 + }) + + return submenu + } +} + exports.execute = (role, focusedWindow, focusedWebContents) => { if (!canExecuteRole(role)) return false diff --git a/lib/browser/api/menu-item.js b/lib/browser/api/menu-item.js index 98b8e9980e28..e95226d3b364 100644 --- a/lib/browser/api/menu-item.js +++ b/lib/browser/api/menu-item.js @@ -11,7 +11,7 @@ const MenuItem = function (options) { for (let key in options) { if (!(key in this)) this[key] = options[key] } - + this.submenu = this.submenu || roles.getDefaultSubmenu(this.role) if (this.submenu != null && this.submenu.constructor !== Menu) { this.submenu = Menu.buildFromTemplate(this.submenu) } From 7fefb75de5dd6cb4e4c8501d02e419d8fd5b206a Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 10 Mar 2017 08:08:23 -0800 Subject: [PATCH 03/98] update versioning doc --- docs/tutorial/electron-versioning.md | 60 +++++++++++++++++++++------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index cae99344a657..b1812d84b4c4 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -1,21 +1,51 @@ # Electron Versioning -If you are a seasoned Node developer, you are surely aware of `semver` - and -might be used to giving your dependency management systems only rough guidelines -rather than fixed version numbers. Due to the hard dependency on Node and -Chromium, Electron is in a slightly more difficult position and does not follow -semver. You should therefore always reference a specific version of Electron. +If you've been using Node and npm for a while, you are probably aware of [Semantic Versioning], or SemVer for short. It's a convention for specifying version numbers for software that helps communicate intentions to the users of your software. -Version numbers are bumped using the following rules: +## Overview of Semantic Versioning -* Major: For breaking changes in Electron's API - if you upgrade from `0.37.0` - to `1.0.0`, you will have to update your app. -* Minor: For major Chrome and minor Node upgrades; or significant Electron - changes - if you upgrade from `1.0.0` to `1.1.0`, your app is supposed to +Semantic versions are always made up of three numbers: + +``` +major.minor.patch +``` + +Semantic version numbers are bumped (incremented) using the following rules: + +* **Major** is for changes that break backwards compatibility. +* **Minor** is for new features that don't break backwards compatibility. +* **Patch** is for bug fixes and other minor changes. + +A simple mnemonic for remembering this scheme is as follows: + +``` +breaking.feature.fix +``` + +## Electron Versioning + +Due to its dependency on Node and Chromium, it is not possible for the Electron +project to adhere to a SemVer policy. **You should therefore always +reference a specific version of Electron.** + +Electron version numbers are bumped using the following rules: + +* **Major** is for breaking changes in Electron's API. If you upgrade from `0.37.0` + to `1.0.0`, you will have to make changes to your app. +* **Minor** is for major Chrome and minor Node upgrades, or significant Electron + changes. If you upgrade from `1.5.0` to `1.6.0`, your app is supposed to still work, but you might have to work around small changes. -* Patch: For new features and bug fixes - if you upgrade from `1.0.0` to - `1.0.1`, your app will continue to work as-is. +* **Patch** is for new features and bug fixes. If you upgrade from `1.6.2` to + `1.6.3`, your app will continue to work as-is. -If you are using `electron` or `electron-prebuilt`, we recommend that you set a fixed version -number (`1.1.0` instead of `^1.1.0`) to ensure that all upgrades of Electron are -a manual operation made by you, the developer. +We recommend that you set a fixed version when installing Electron from npm: + +```sh +npm install electron --save-exact --save-dev +``` + +The `--save-exact` flag will add `electron` to your `package.json` file without +using a `^` or `~`, e.g. `1.6.2` instead of `^1.6.2`. This practice ensures that +all upgrades of Electron are a manual operation made by you, the developer. + +[Semantic Versioning](http://semver.org) From 582662e40fc96801e5d2be9dd4d9bc8b9981de78 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 10 Mar 2017 09:03:04 -0800 Subject: [PATCH 04/98] fix markdown link --- docs/tutorial/electron-versioning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index b1812d84b4c4..eccd9459f881 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -48,4 +48,4 @@ The `--save-exact` flag will add `electron` to your `package.json` file without using a `^` or `~`, e.g. `1.6.2` instead of `^1.6.2`. This practice ensures that all upgrades of Electron are a manual operation made by you, the developer. -[Semantic Versioning](http://semver.org) +[Semantic Versioning]: http://semver.org From 76ee7fda2b2ec83de0755555604c80442f9882b3 Mon Sep 17 00:00:00 2001 From: mst128256 Date: Mon, 13 Mar 2017 14:26:34 +0100 Subject: [PATCH 05/98] Fixed linting --- lib/browser/api/menu-item-roles.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 254283b86be8..8919b8d10ec7 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -178,8 +178,7 @@ const roles = { role: 'paste' }, - process.platform === 'darwin' ? - { + process.platform === 'darwin' ? { role: 'pasteandmatchstyle' } : {}, @@ -187,9 +186,8 @@ const roles = { role: 'delete' }, - process.platform === 'win32' ? - { - type: 'separator' + process.platform === 'win32' ? { + type: 'separator' } : {}, { @@ -209,13 +207,11 @@ const roles = { role: 'close' }, - process.platform === 'darwin' ? - { + process.platform === 'darwin' ? { type: 'separator' } : {}, - process.platform === 'darwin' ? - { + process.platform === 'darwin' ? { label: 'Bring All to Front', role: 'front' } : {} @@ -245,13 +241,14 @@ exports.getDefaultAccelerator = (role) => { exports.getDefaultSubmenu = (role) => { if (roles.hasOwnProperty(role)) { - submenu = roles[role].submenu + let submenu = roles[role].submenu // remove empty objects from within the submenu - if (Array.isArray(submenu)) - submenu = submenu.filter(function(n){ + if (Array.isArray(submenu)) { + submenu = submenu.filter(function (n) { return n.constructor !== Object || Object.keys(n).length > 0 }) + } return submenu } From 46af3cefec37e13fa03d4b52c155fcb555dcbf40 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 15:42:26 -0700 Subject: [PATCH 06/98] Clarify remote require of relative modules The docs for the `remote.require(module)` method were a little too terse for me to understand the behavior of relative module loading for `remote.require` and I had to run an experiment to understand the behavior (e.g. is the relative path relative to caller of `remote.require` or relative to some other path in the project related to the main process?). I think this is correct but someone please double check my understanding. Adding an example and additional explanation should help clarify this. Feel free to edit the copy as needed. --- docs/api/remote.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 0bed3ad9b511..7f1c7f09292c 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -140,7 +140,26 @@ The `remote` module has the following methods: * `module` String -Returns `any` - The object returned by `require(module)` in the main process. +Returns `any` - The object returned by `require(module)` in the main process. Modules specified by their relative path will resolve relative to the entrypoint of the main process. + +e.g. + +```js +// main process: main/index.js +const { app, ipcMain } = require('electron') +app.on('ready', () => { +//... +``` + +```js +// some relative module: main/foo.js +module.exports = 'bar' +``` + +```js +// renderer process: renderer/index.js +const foo = require('electron').remote.require('./foo') // bar +``` ### `remote.getCurrentWindow()` From f82590b9ab0288409d817e948332a3ab122d4eb3 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 15:48:42 -0700 Subject: [PATCH 07/98] Wrap at 80 --- docs/api/remote.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 7f1c7f09292c..ccbfbf3fb14f 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -140,7 +140,9 @@ The `remote` module has the following methods: * `module` String -Returns `any` - The object returned by `require(module)` in the main process. Modules specified by their relative path will resolve relative to the entrypoint of the main process. +Returns `any` - The object returned by `require(module)` in the main process. +Modules specified by their relative path will resolve relative to the entrypoint +of the main process. e.g. From 2276357f723ada06b31c9595e7bd76a3898e7562 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 17:18:23 -0700 Subject: [PATCH 08/98] update with a tree --- docs/api/remote.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index ccbfbf3fb14f..36b38b835408 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -146,11 +146,24 @@ of the main process. e.g. +``` +project/ +├── main +│   ├── foo.js +│   └── index.js +├── package.json +└── renderer + └── index.js +``` + ```js // main process: main/index.js -const { app, ipcMain } = require('electron') +const { app } = require('electron') app.on('ready', () => { -//... + +// ... + +}) ``` ```js From 85c48a23368317bc134c938876d5515abab17349 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 17:20:11 -0700 Subject: [PATCH 09/98] make main process example shorter --- docs/api/remote.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 36b38b835408..4da19daaa34f 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -159,11 +159,7 @@ project/ ```js // main process: main/index.js const { app } = require('electron') -app.on('ready', () => { - -// ... - -}) +app.on('ready', () => {/* ... */}) ``` ```js From b67c81226c05856b09cef9b5066a0d74e23ff424 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Tue, 14 Mar 2017 10:48:44 -0700 Subject: [PATCH 10/98] fix linting --- docs/api/remote.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 4da19daaa34f..2db8d17c9992 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -159,7 +159,7 @@ project/ ```js // main process: main/index.js const { app } = require('electron') -app.on('ready', () => {/* ... */}) +app.on('ready', () => { /* ... */ }) ``` ```js From 16f97544459abab741eeeffe8d0a51e260c4fa33 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 14 Mar 2017 21:08:10 +0530 Subject: [PATCH 11/98] Create separate request context for geolocation service. * Geolocation service cannot hold reference to browser context, since it is destroyed at the end of everything and this will confuse the shutdown path of browser context. * Geolocation service run on its own thread. --- atom/browser/atom_access_token_store.cc | 82 ++++++++++++------------- atom/browser/atom_access_token_store.h | 8 +-- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/atom/browser/atom_access_token_store.cc b/atom/browser/atom_access_token_store.cc index aef54dfa0ebc..6a5597ca7780 100644 --- a/atom/browser/atom_access_token_store.cc +++ b/atom/browser/atom_access_token_store.cc @@ -7,11 +7,13 @@ #include #include -#include "atom/browser/atom_browser_context.h" #include "atom/common/google_api_key.h" #include "base/environment.h" #include "content/public/browser/browser_thread.h" #include "device/geolocation/geolocation_provider.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_builder.h" +#include "net/url_request/url_request_context_getter.h" using content::BrowserThread; @@ -19,51 +21,40 @@ namespace atom { namespace internal { -// Loads access tokens and other necessary data on the UI thread, and -// calls back to the originator on the originating thread. -class TokenLoadingJob : public base::RefCountedThreadSafe { +class GeoURLRequestContextGetter : public net::URLRequestContextGetter { public: - explicit TokenLoadingJob( - const device::AccessTokenStore::LoadAccessTokensCallback& callback) - : callback_(callback), request_context_getter_(nullptr) {} + net::URLRequestContext* GetURLRequestContext() override { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!url_request_context_.get()) { + net::URLRequestContextBuilder builder; + builder.set_proxy_config_service( + net::ProxyService::CreateSystemProxyConfigService( + BrowserThread::GetTaskRunnerForThread(BrowserThread::IO), + BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); + url_request_context_ = builder.Build(); + } + return url_request_context_.get(); + } - void Run(AtomBrowserContext* browser_context) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - request_context_getter_ = browser_context->GetRequestContext(); - std::unique_ptr env(base::Environment::Create()); - if (!env->GetVar("GOOGLE_API_KEY", &api_key_)) - api_key_ = GOOGLEAPIS_API_KEY; - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&TokenLoadingJob::RespondOnIOThread, this)); + scoped_refptr GetNetworkTaskRunner() + const override { + return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO); } private: - friend class base::RefCountedThreadSafe; + friend class atom::AtomAccessTokenStore; - ~TokenLoadingJob() {} + GeoURLRequestContextGetter() {} + ~GeoURLRequestContextGetter() override {} - void RespondOnIOThread() { - // Equivalent 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. - device::AccessTokenStore::AccessTokenMap access_token_map; - std::pair token_pair; - token_pair.first = GURL(GOOGLEAPIS_ENDPOINT + api_key_); - access_token_map.insert(token_pair); - - callback_.Run(access_token_map, request_context_getter_); - } - - device::AccessTokenStore::LoadAccessTokensCallback callback_; - net::URLRequestContextGetter* request_context_getter_; - std::string api_key_; + std::unique_ptr url_request_context_; + DISALLOW_COPY_AND_ASSIGN(GeoURLRequestContextGetter); }; } // namespace internal -AtomAccessTokenStore::AtomAccessTokenStore() { - browser_context_ = AtomBrowserContext::From("", false); +AtomAccessTokenStore::AtomAccessTokenStore() + : request_context_getter_(new internal::GeoURLRequestContextGetter) { device::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); } @@ -72,16 +63,19 @@ AtomAccessTokenStore::~AtomAccessTokenStore() { void AtomAccessTokenStore::LoadAccessTokens( const LoadAccessTokensCallback& callback) { - scoped_refptr job( - new internal::TokenLoadingJob(callback)); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&AtomAccessTokenStore::RunTokenLoadingJob, - this, base::RetainedRef(job))); -} + std::unique_ptr env(base::Environment::Create()); + std::string api_key; + if (!env->GetVar("GOOGLE_API_KEY", &api_key)) + api_key = GOOGLEAPIS_API_KEY; + // Equivalent 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. + device::AccessTokenStore::AccessTokenMap access_token_map; + std::pair token_pair; + token_pair.first = GURL(GOOGLEAPIS_ENDPOINT + api_key); + access_token_map.insert(token_pair); -void AtomAccessTokenStore::RunTokenLoadingJob( - scoped_refptr job) { - job->Run(browser_context_.get()); + callback.Run(access_token_map, request_context_getter_.get()); } 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 07884e58d60a..820ceddce4fd 100644 --- a/atom/browser/atom_access_token_store.h +++ b/atom/browser/atom_access_token_store.h @@ -9,10 +9,8 @@ namespace atom { -class AtomBrowserContext; - namespace internal { -class TokenLoadingJob; +class GeoURLRequestContextGetter; } class AtomAccessTokenStore : public device::AccessTokenStore { @@ -27,9 +25,7 @@ class AtomAccessTokenStore : public device::AccessTokenStore { const base::string16& access_token) override; private: - void RunTokenLoadingJob(scoped_refptr job); - - scoped_refptr browser_context_; + scoped_refptr request_context_getter_; DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore); }; From 72adbf7a2fef7aaef83fb56db9d3e9ddacc99b3a Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sun, 19 Mar 2017 01:10:30 +0530 Subject: [PATCH 12/98] destroy guest webcontents before embedder --- atom/browser/api/atom_api_web_contents.cc | 16 ++++++++-------- atom/browser/api/atom_api_web_contents.h | 3 +++ vendor/brightray | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 6ba23b3c9afc..0f188d0d222e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -411,14 +411,18 @@ WebContents::~WebContents() { if (type_ == WEB_VIEW) guest_delegate_->Destroy(); - // The WebContentsDestroyed will not be called automatically because we - // unsubscribe from webContents before destroying it. So we have to manually - // call it here to make sure "destroyed" event is emitted. RenderViewDeleted(web_contents()->GetRenderViewHost()); - WebContentsDestroyed(); + DestroyWebContents(); } } +void WebContents::DestroyWebContents() { + // This event is only for internal use, which is emitted when WebContents is + // being destroyed. + Emit("will-destroy"); + CommonWebContentsDelegate::DestroyWebContents(); +} + bool WebContents::DidAddMessageToConsole(content::WebContents* source, int32_t level, const base::string16& message, @@ -919,10 +923,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { // be destroyed on close, and WebContentsDestroyed would be called for it, so // we need to make sure the api::WebContents is also deleted. void WebContents::WebContentsDestroyed() { - // This event is only for internal use, which is emitted when WebContents is - // being destroyed. - Emit("will-destroy"); - // Cleanup relationships with other parts. RemoveFromWeakMap(); diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 2513dc7722a8..c289503b43c9 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -76,6 +76,9 @@ class WebContents : public mate::TrackableObject, static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); + // Notifies to destroy any guest web contents before destroying self. + void DestroyWebContents(); + int64_t GetID() const; int GetProcessID() const; Type GetType() const; diff --git a/vendor/brightray b/vendor/brightray index d0144ba2c902..53aa2cfc8a40 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit d0144ba2c9024d65cdf260abf5c03c742afff3fd +Subproject commit 53aa2cfc8a40627d62bf5be757ff9dea444f80bd From 4ab2c9241896fc96ef3ba7f158897b92a90aa463 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 22 Mar 2017 07:30:36 +0530 Subject: [PATCH 13/98] CommonWebContentsDelegate::DestroyWebContents => ResetManagedWebContents --- atom/browser/api/atom_api_web_contents.cc | 2 +- atom/browser/common_web_contents_delegate.cc | 2 +- atom/browser/common_web_contents_delegate.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 0f188d0d222e..a0100fd65c6e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -420,7 +420,7 @@ void WebContents::DestroyWebContents() { // This event is only for internal use, which is emitted when WebContents is // being destroyed. Emit("will-destroy"); - CommonWebContentsDelegate::DestroyWebContents(); + ResetManagedWebContents(); } bool WebContents::DidAddMessageToConsole(content::WebContents* source, diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 89c1e372558c..59ffc7dcbc08 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -183,7 +183,7 @@ void CommonWebContentsDelegate::SetOwnerWindow( web_contents->SetUserData(relay->key, relay); } -void CommonWebContentsDelegate::DestroyWebContents() { +void CommonWebContentsDelegate::ResetManagedWebContents() { web_contents_.reset(); } diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index c08f8d246cee..27209411c72b 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -42,9 +42,6 @@ class CommonWebContentsDelegate void SetOwnerWindow(content::WebContents* web_contents, NativeWindow* owner_window); - // Destroy the managed InspectableWebContents object. - void DestroyWebContents(); - // Returns the WebContents managed by this delegate. content::WebContents* GetWebContents() const; @@ -114,6 +111,9 @@ class CommonWebContentsDelegate std::string* name, std::string* class_name) override; #endif + // Destroy the managed InspectableWebContents object. + void ResetManagedWebContents(); + private: // Callback for when DevToolsSaveToFile has completed. void OnDevToolsSaveToFile(const std::string& url); From 426563a8439adef225af5335a87901ca83902ce6 Mon Sep 17 00:00:00 2001 From: Hansen Zhang Date: Wed, 22 Mar 2017 11:52:25 -0400 Subject: [PATCH 14/98] #8881 - Display '&' in MenuItem label --- atom/browser/ui/views/submenu_button.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/atom/browser/ui/views/submenu_button.cc b/atom/browser/ui/views/submenu_button.cc index b398d84deec8..92f2a791cd09 100644 --- a/atom/browser/ui/views/submenu_button.cc +++ b/atom/browser/ui/views/submenu_button.cc @@ -16,21 +16,10 @@ namespace atom { -namespace { - -// Filter out the "&" in menu label. -base::string16 FilterAccelerator(const base::string16& label) { - base::string16 out; - base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out); - return out; -} - -} // namespace - SubmenuButton::SubmenuButton(const base::string16& title, views::MenuButtonListener* menu_button_listener, const SkColor& background_color) - : views::MenuButton(FilterAccelerator(title), + : views::MenuButton(gfx::RemoveAcceleratorChar(title, '&', NULL, NULL), menu_button_listener, false), accelerator_(0), show_underline_(false), From d22910f554f5527826deb02d925e55719787a444 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Wed, 22 Mar 2017 16:13:24 -0700 Subject: [PATCH 15/98] mention tilde --- docs/tutorial/electron-versioning.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index eccd9459f881..3f6c9ef90d43 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -48,4 +48,8 @@ The `--save-exact` flag will add `electron` to your `package.json` file without using a `^` or `~`, e.g. `1.6.2` instead of `^1.6.2`. This practice ensures that all upgrades of Electron are a manual operation made by you, the developer. +Alternatively, you can use the `~` prefix in your SemVer range, like `~1.6.2`. +This will lock your major and minor version, but allow new patch versions to +be installed. + [Semantic Versioning]: http://semver.org From 360d2b45f40b2312ad5d2907c3265204d70f564a Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Wed, 22 Mar 2017 22:59:11 -0700 Subject: [PATCH 16/98] document resources for tracking chromium development --- docs/README.md | 2 ++ docs/development/chromium-development.md | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 docs/development/chromium-development.md diff --git a/docs/README.md b/docs/README.md index 56a423f491de..2df14cc5c1ac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -103,3 +103,5 @@ an issue: * [Debug Instructions (Windows)](development/debug-instructions-windows.md) * [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) * [Documentation Styleguide](styleguide.md) +* [Updating Chrome](development/updating-chrome.md) +* [Chromium Development](development/chromium-development.md) diff --git a/docs/development/chromium-development.md b/docs/development/chromium-development.md new file mode 100644 index 000000000000..a692714482e4 --- /dev/null +++ b/docs/development/chromium-development.md @@ -0,0 +1,12 @@ +# Chromium Development + +> A collection of resources for learning about Chromium and tracking its development + +- [chromiumdev](https://chromiumdev-slack.herokuapp.com) on Slack +- [@ChromiumDev](https://twitter.com/ChromiumDev) on Twitter +- [@googlechrome](https://twitter.com/googlechrome) on Twitter +- [Blog](https://blog.chromium.org) +- [Code Search](https://cs.chromium.org/) +- [Source Code](https://cs.chromium.org/chromium/src/) +- [Development Calendar and Release Info](https://www.chromium.org/developers/calendar) +- [Discussion Groups](http://www.chromium.org/developers/discussion-groups) From e1aebef57c00bd254b64c813e388eaeea53c6e5f Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:41:23 -0300 Subject: [PATCH 17/98] Make sandbox APIs more compatible with normal renderers - Expose remote shortcuts for the `fs`, `os` and `child_process` modules. - Expose the `url` and `timers` modules(the browserify versions) - Add `process.crash` and `process.platform` --- .../atom_sandboxed_renderer_client.cc | 2 ++ electron.gyp | 8 +++++- .../api/exports/child_process.js | 1 + lib/sandboxed_renderer/api/exports/fs.js | 1 + lib/sandboxed_renderer/api/exports/os.js | 1 + lib/sandboxed_renderer/init.js | 27 ++++++++++--------- 6 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 lib/sandboxed_renderer/api/exports/child_process.js create mode 100644 lib/sandboxed_renderer/api/exports/fs.js create mode 100644 lib/sandboxed_renderer/api/exports/os.js diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index 7d0dfde8c5ab..cb0dfd6db1fa 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -9,6 +9,7 @@ #include "atom_natives.h" // NOLINT: This file is generated with js2c #include "atom/common/api/api_messages.h" +#include "atom/common/api/atom_bindings.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/v8_value_converter.h" #include "atom/common/native_mate_converters/value_converter.h" @@ -85,6 +86,7 @@ void InitializeBindings(v8::Local binding, auto isolate = context->GetIsolate(); mate::Dictionary b(isolate, binding); b.SetMethod("get", GetBinding); + b.SetMethod("crash", AtomBindings::Crash); } class AtomSandboxedRenderFrameObserver : public content::RenderFrameObserver { diff --git a/electron.gyp b/electron.gyp index 15336a4e6bf3..78eed743cc36 100644 --- a/electron.gyp +++ b/electron.gyp @@ -441,7 +441,13 @@ 'sandbox_args': [ './lib/sandboxed_renderer/init.js', '-r', - './lib/sandboxed_renderer/api/exports/electron.js:electron' + './lib/sandboxed_renderer/api/exports/electron.js:electron', + '-r', + './lib/sandboxed_renderer/api/exports/fs.js:fs', + '-r', + './lib/sandboxed_renderer/api/exports/os.js:os', + '-r', + './lib/sandboxed_renderer/api/exports/child_process.js:child_process' ], 'isolated_args': [ 'lib/isolated_renderer/init.js', diff --git a/lib/sandboxed_renderer/api/exports/child_process.js b/lib/sandboxed_renderer/api/exports/child_process.js new file mode 100644 index 000000000000..ff39e96a120e --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/child_process.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('child_process') diff --git a/lib/sandboxed_renderer/api/exports/fs.js b/lib/sandboxed_renderer/api/exports/fs.js new file mode 100644 index 000000000000..7342908e59a9 --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/fs.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('fs') diff --git a/lib/sandboxed_renderer/api/exports/os.js b/lib/sandboxed_renderer/api/exports/os.js new file mode 100644 index 000000000000..ecd0d38a63a6 --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/os.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('os') diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index 7f2d252865a8..46b74ee7b042 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -21,23 +21,23 @@ for (let prop of Object.keys(events.EventEmitter.prototype)) { Object.setPrototypeOf(process, events.EventEmitter.prototype) const electron = require('electron') +const fs = require('fs') const preloadModules = new Map([ - ['electron', electron] + ['child_process', require('child_process')], + ['electron', electron], + ['fs', fs], + ['os', require('os')], + ['url', require('url')], + ['timers', require('timers')] ]) -const extraModules = [ - 'fs' -] -for (let extraModule of extraModules) { - preloadModules.set(extraModule, electron.remote.require(extraModule)) -} - -// Fetch the preload script using the "fs" module proxy. -let preloadSrc = preloadModules.get('fs').readFileSync(preloadPath).toString() +const preloadSrc = fs.readFileSync(preloadPath).toString() // Pass different process object to the preload script(which should not have // access to things like `process.atomBinding`). const preloadProcess = new events.EventEmitter() +preloadProcess.platform = electron.remote.process.platform +preloadProcess.crash = () => binding.crash() process.on('exit', () => preloadProcess.emit('exit')) // This is the `require` function that will be visible to the preload script @@ -67,12 +67,13 @@ function preloadRequire (module) { // and any `require('electron')` calls in `preload.js` will work as expected // since browserify won't try to include `electron` in the bundle, falling back // to the `preloadRequire` function above. -let preloadWrapperSrc = `(function(require, process, Buffer, global) { +const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate) { ${preloadSrc} })` // eval in window scope: // http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.2 const geval = eval -let preloadFn = geval(preloadWrapperSrc) -preloadFn(preloadRequire, preloadProcess, Buffer, global) +const preloadFn = geval(preloadWrapperSrc) +const {setImmediate} = require('timers') +preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate) From bf756e3c00c79f4f7886dd7ea4d3c27eb5fbfcb0 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:45:40 -0300 Subject: [PATCH 18/98] Prevent browserify from leaking the require function Define a "require" argument in the wrapper functions that runs browserify bundles, which will prevent browserify from leaking the require function. Note that this doesn't affect the isolated renderer script, only when `-r` flag is passed to browserify command it will export a require function. It is still added to isolated renderer script to prevent future mistakes(doesn't hurt defining a "require" local). --- atom/renderer/atom_renderer_client.cc | 2 +- atom/renderer/atom_sandboxed_renderer_client.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 8dd8e04e1ac2..eb1bdccbe34c 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -115,7 +115,7 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { // an argument. std::string bundle(node::isolated_bundle_data, node::isolated_bundle_data + sizeof(node::isolated_bundle_data)); - std::string wrapper = "(function (binding) {\n" + bundle + "\n})"; + std::string wrapper = "(function (binding, require) {\n" + bundle + "\n})"; auto script = v8::Script::Compile( mate::ConvertToV8(isolate, wrapper)->ToString()); auto func = v8::Handle::Cast( diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index cb0dfd6db1fa..bf9ea6fd9ef8 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -206,7 +206,7 @@ void AtomSandboxedRendererClient::DidCreateScriptContext( std::string preload_bundle_native(node::preload_bundle_data, node::preload_bundle_data + sizeof(node::preload_bundle_data)); std::stringstream ss; - ss << "(function(binding, preloadPath) {\n"; + ss << "(function(binding, preloadPath, require) {\n"; ss << preload_bundle_native << "\n"; ss << "})"; std::string preload_wrapper = ss.str(); From 3a97cfc359e009caf1a42b00d7a7df27439849a6 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:47:18 -0300 Subject: [PATCH 19/98] Expose `crashReporter` to sandbox --- lib/sandboxed_renderer/api/exports/electron.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/sandboxed_renderer/api/exports/electron.js b/lib/sandboxed_renderer/api/exports/electron.js index 2a1d34123116..02f23be3966d 100644 --- a/lib/sandboxed_renderer/api/exports/electron.js +++ b/lib/sandboxed_renderer/api/exports/electron.js @@ -11,6 +11,12 @@ Object.defineProperties(exports, { return require('../../../renderer/api/remote') } }, + crashReporter: { + enumerable: true, + get: function () { + return require('../../../common/api/crash-reporter') + } + }, CallbacksRegistry: { get: function () { return require('../../../common/api/callbacks-registry') From 5ee6205c0a5eac585d10d878b8200e40f7c79168 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:48:36 -0300 Subject: [PATCH 20/98] Run the crash reporter specs with sandbox option. - Create a function that accepts BrowserWindow options and generates a suite that contains the renderer-specific tests. - Run the function twice to execute the tests with and without sandbox option. --- spec/api-crash-reporter-spec.js | 23 +++++++++++++++++------ spec/fixtures/module/preload-sandbox.js | 2 ++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index c269cfe1324b..41910d6228a8 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,15 +11,20 @@ const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') describe('crashReporter module', function () { + if (process.mas) { + return + } var fixtures = path.resolve(__dirname, 'fixtures') + const generateSpecs = (description, browserWindowOpts) => { + describe(description, function () { var w = null var originalTempDirectory = null var tempDirectory = null beforeEach(function () { - w = new BrowserWindow({ + w = new BrowserWindow(Object.assign({ show: false - }) + }, browserWindowOpts)) tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') originalTempDirectory = app.getPath('temp') app.setPath('temp', tempDirectory) @@ -30,10 +35,6 @@ describe('crashReporter module', function () { return closeWindow(w).then(function () { w = null }) }) - if (process.mas) { - return - } - it('should send minidump when renderer crashes', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() @@ -91,6 +92,16 @@ describe('crashReporter module', function () { done: done }) }) + }) + } + + generateSpecs('without sandbox', {}) + generateSpecs('with sandbox ', { + webPreferences: { + sandbox: true, + preload: path.join(fixtures, 'module', 'preload-sandbox.js') + } + }) describe('.start(options)', function () { it('requires that the companyName and submitURL options be specified', function () { diff --git a/spec/fixtures/module/preload-sandbox.js b/spec/fixtures/module/preload-sandbox.js index 39a8704e1329..15d6e06a862c 100644 --- a/spec/fixtures/module/preload-sandbox.js +++ b/spec/fixtures/module/preload-sandbox.js @@ -1,6 +1,8 @@ (function () { + const {setImmediate} = require('timers') const {ipcRenderer} = require('electron') window.ipcRenderer = ipcRenderer + window.setImmediate = setImmediate if (location.protocol === 'file:') { window.test = 'preload' window.require = require From a5eef516a793b01f3eed2e8586fe7e459142ee42 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:53:17 -0300 Subject: [PATCH 21/98] Fix indent in api-crash-reporter-spec.js --- spec/api-crash-reporter-spec.js | 132 ++++++++++++++++---------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 41910d6228a8..dc4b98150160 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -16,83 +16,83 @@ describe('crashReporter module', function () { } var fixtures = path.resolve(__dirname, 'fixtures') const generateSpecs = (description, browserWindowOpts) => { - describe(description, function () { - var w = null - var originalTempDirectory = null - var tempDirectory = null + describe(description, function () { + var w = null + var originalTempDirectory = null + var tempDirectory = null - beforeEach(function () { - w = new BrowserWindow(Object.assign({ - show: false - }, browserWindowOpts)) - tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') - originalTempDirectory = app.getPath('temp') - app.setPath('temp', tempDirectory) - }) + beforeEach(function () { + w = new BrowserWindow(Object.assign({ + show: false + }, browserWindowOpts)) + tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') + originalTempDirectory = app.getPath('temp') + app.setPath('temp', tempDirectory) + }) - afterEach(function () { - app.setPath('temp', originalTempDirectory) - return closeWindow(w).then(function () { w = null }) - }) + afterEach(function () { + app.setPath('temp', originalTempDirectory) + return closeWindow(w).then(function () { w = null }) + }) - it('should send minidump when renderer crashes', function (done) { - if (process.env.APPVEYOR === 'True') return done() - if (process.env.TRAVIS === 'true') return done() + it('should send minidump when renderer crashes', function (done) { + if (process.env.APPVEYOR === 'True') return done() + if (process.env.TRAVIS === 'true') return done() - this.timeout(120000) + this.timeout(120000) - startServer({ - callback (port) { - const crashUrl = url.format({ - protocol: 'file', - pathname: path.join(fixtures, 'api', 'crash.html'), - search: '?port=' + port + startServer({ + callback (port) { + const crashUrl = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash.html'), + search: '?port=' + port + }) + w.loadURL(crashUrl) + }, + processType: 'renderer', + done: done }) - w.loadURL(crashUrl) - }, - processType: 'renderer', - done: done - }) - }) + }) - it('should send minidump when node processes crash', function (done) { - if (process.env.APPVEYOR === 'True') return done() - if (process.env.TRAVIS === 'true') return done() + it('should send minidump when node processes crash', function (done) { + if (process.env.APPVEYOR === 'True') return done() + if (process.env.TRAVIS === 'true') return done() - this.timeout(120000) + this.timeout(120000) - startServer({ - callback (port) { - const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`) - const version = app.getVersion() - const crashPath = path.join(fixtures, 'module', 'crash.js') - childProcess.fork(crashPath, [port, version, crashesDir], {silent: true}) - }, - processType: 'browser', - done: done - }) - }) - - it('should send minidump with updated extra parameters', function (done) { - if (process.env.APPVEYOR === 'True') return done() - if (process.env.TRAVIS === 'true') return done() - - this.timeout(10000) - - startServer({ - callback (port) { - const crashUrl = url.format({ - protocol: 'file', - pathname: path.join(fixtures, 'api', 'crash-restart.html'), - search: '?port=' + port + startServer({ + callback (port) { + const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`) + const version = app.getVersion() + const crashPath = path.join(fixtures, 'module', 'crash.js') + childProcess.fork(crashPath, [port, version, crashesDir], {silent: true}) + }, + processType: 'browser', + done: done }) - w.loadURL(crashUrl) - }, - processType: 'renderer', - done: done + }) + + it('should send minidump with updated extra parameters', function (done) { + if (process.env.APPVEYOR === 'True') return done() + if (process.env.TRAVIS === 'true') return done() + + this.timeout(10000) + + startServer({ + callback (port) { + const crashUrl = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash-restart.html'), + search: '?port=' + port + }) + w.loadURL(crashUrl) + }, + processType: 'renderer', + done: done + }) + }) }) - }) - }) } generateSpecs('without sandbox', {}) From 93b444eef972968353e2bce08dd2b9e4338177cf Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Thu, 23 Mar 2017 23:36:05 +0530 Subject: [PATCH 22/98] net: catch source stream creation failure for content encoding --- atom/browser/net/atom_url_request.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/atom/browser/net/atom_url_request.cc b/atom/browser/net/atom_url_request.cc index 2c7bb61da0b1..83d2548a9c29 100644 --- a/atom/browser/net/atom_url_request.cc +++ b/atom/browser/net/atom_url_request.cc @@ -348,6 +348,14 @@ void AtomURLRequest::OnReadCompleted(net::URLRequest* request, int bytes_read) { DCHECK_EQ(request, request_.get()); const auto status = request_->status(); + if (status.error() == bytes_read && + bytes_read == net::ERR_CONTENT_DECODING_INIT_FAILED) { + // When the request job is unable to create a source stream for the + // content encoding, we fail the request. + DoCancelWithError(net::ErrorToString(net::ERR_CONTENT_DECODING_INIT_FAILED), + true); + return; + } bool response_error = false; bool data_ended = false; From 437f1192d9e570d98ff016d729eda21533ffb8ed Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 9 Mar 2017 09:23:03 -0300 Subject: [PATCH 23/98] Add initial documentation for `sandbox` option. --- docs/api/browser-window.md | 5 + docs/api/sandbox-option.md | 186 +++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 docs/api/sandbox-option.md diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 2456c73e8033..13d823c231c3 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -225,6 +225,11 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope. See example [here](process.md#event-loaded). + * `sandbox` Boolean (optional) - If set, this will sandbox the renderer + associated with the window, making it compatible with chromium sandbox and + disabling the node.js engine. This is not the same as the + `nodeIntegration` option and the APIs available to the preload script are + more limited. Read more about the option [here](sandbox-option.md). * `session` [Session](session.md#class-session) (optional) - Sets the session used by the page. Instead of passing the Session object directly, you can also choose to use the `partition` option instead, which accepts a partition string. When diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md new file mode 100644 index 000000000000..454a8ad05cca --- /dev/null +++ b/docs/api/sandbox-option.md @@ -0,0 +1,186 @@ +# `sandbox` Option + +> Create a browser window with renderer that can run inside chromium OS sandbox. + +One of chromium key security features is that all blink rendering/javascript +code is confined in a sandbox. This sandbox uses OS-specific features to ensure +that exploits in the renderer process cannot harm the system. + +In other words, when the sandbox is enabled, the renderers can only make changes +to the system by delegating tasks to the main process via IPC. +[Here's](https://www.chromium.org/developers/design-documents/sandbox) more +information about the sandbox. + +Since a major feature in electron is the ability to run node.js in the +renderer process(making it easier to develop desktop applications using only web +technologies), the sandbox has to disabled by electron. One of the reasons is +that most node.js APIs require system access. `require()` for example, is not +possible without file system permissions, which are unavailable in a sandboxed +environment. + +Usually this is not a problem for desktop applications since the code is always +trusted, but it makes electron less secure than chromium for displaying +untrusted web content. For applications that require more security, the +`sandbox` flag will force electron to spawn a classic chromium renderer that is +compatible with the sandbox. + +A sandboxed renderer doesn't have a node.js environment running and doesn't +expose javascript APIs to client code. The only exception is the preload script, +which has access to a subset of electron renderer API. + +Another difference is that sandboxed renderers don't modify any of the default +javascript APIs. Consequently, some APIs such as `window.open` will work as they +do in chromium(no `BrowserWindowProxy`). + +## Example + +Create a sandboxed window, simply pass `sandbox: true` to `webPreferences`: + +```js +let win +app.on('ready', () => { + win = new BrowserWindow({ + webPreferences: { + sandbox: true + } + }) + w.loadURL('http://google.com') +}) +``` + +This alone won't enable the OS-enforced sandbox. To use it, the +`--enable-sandbox` command-line argument must be passed to electron, which will +force `sandbox: true` to all BrowserWindow instances. + +```js +let win +app.on('ready', () => { + // no need to pass `sandbox: true` since `--enable-sandbox` was enabled. + win = new BrowserWindow() + w.loadURL('http://google.com') +}) +``` + +Note that it is not enough to call +`app.commandLine.appendSwitch('--enable-sandbox')`, as electron/node startup +code runs after it is possible to make changes to chromium sandbox settings. The +switch must be passed to electron command-line: + +``` +electron --enable-sandbox app.js +``` + +It is not possible to have the OS sandbox active only for some renderers, if +`--enable-sandbox` is enabled, normal electron windows cannot be created. + +If you need to mix sandboxed and non-sandboxed renderers in one application, +simply omit the `--enable-sandbox` argument. Without this argument, windows +created with `sandbox: true` will still have node.js disabled and communicate +only via IPC, which by itself is already a gain from security POV. + +## Preload + +An app can make customizations to sandboxed renderers using a preload script. +Here's an example: + +```js +let win +app.on('ready', () => { + win = new BrowserWindow({ + webPreferences: { + sandbox: true, + preload: 'preload.js' + } + }) + w.loadURL('http://google.com') +}) +``` + +and preload.js: + +```js +// This file is loaded whenever a javascript context is created. It runs in a +// private scope that can access a subset of electron renderer APIs. We must be +// careful to not leak any objects into the global scope! +const fs = require('fs') +const {ipcRenderer} = require('electron') + +// read a configuration file using the `fs` module +const buf = fs.readFileSync('allowed-popup-urls.json') +const allowedUrls = JSON.parse(buf.toString('utf8')) + +const defaultWindowOpen = window.open + +function customWindowOpen (url, ...args) { + if (allowedUrls.indexOf(url) === -1) { + ipcRenderer.sendSync('blocked-popup-notification', location.origin, url) + return null + } + return defaultWindowOpen(url, ...args) +} + +window.open = customWindowOpen +``` + +Important things to notice in the preload script: + +- Even though the sandboxed renderer doesn't have node.js running, it still has + access to a limited node-like environment:`Buffer`, `process`, `setImmediate` + and `require` are available. +- The preload can indirectly access all APIs from the main process through the + `remote` and `ipcRenderer` modules. This is how `fs`(used above) and other + modules are implemented: They are proxies to remote counterparts in the main + process. +- The preload must be contained in a single script, but it is possible to have + complex preload code composed with multiple modules by using a tool like + browserify, as explained below. In fact, browserify is already used by + electron to provide a node-like environment to the preload script. + +To create a browserify bundle and use it as a preload script, something like +the following should be used: + + browserify preload/index.js \ + -x electron \ + -x fs \ + --insert-global-vars=__filename,__dirname -o preload.js + +The `-x` flag should be used with any required module that is already exposed in +the preload scope, and tells browserify to use the enclosing `require` function +for it. `--insert-global-vars` will ensure that `process`,`Buffer` and +`setImmediate` are also taken from the enclosing scope(normally browserify +injects code for those). + +Currently the `require` function provided in the preload scope exposes the +following modules: + +- `child_process` +- `electron`(crashReporter, remote and ipcRenderer) +- `fs` +- `os` +- `timers` +- `url` + +More may be added as needed to expose more electron APIs in the sandbox, but any +module in the main process can already be used through +`electron.remote.require`. + +## Status + +Please use the `sandbox` option with care, as it still is an experimental +feature. We are still not aware of the security implications of exposing some +electron renderer APIs to the preload script, but here are some things to +consider before rendering untrusted content: + +- A preload script can accidentaly leak privileged APIs to untrusted code. +- Some bug in V8 engine may allow malicious code to access the renderer preload + APIs, effectively granting full access to the system through the `remote` + module. + +Since renderering untrusted content in electron is still uncharted territory, +the APIs exposed to the sandbox preload script should be considered more +unstable than the rest of electron APIs, and may have breaking changes to fix +security issues. + +One planned enhancement that should greatly increase security is to block IPC +messages from sandboxed renderers by default, allowing the main process +explicitly define a set of messages the renderer is allowed to send. From 9e471d8f1cce79626491cea4be21be3b30cd6c2e Mon Sep 17 00:00:00 2001 From: mst128256 Date: Fri, 24 Mar 2017 12:14:08 +0100 Subject: [PATCH 24/98] Added specs --- docs/api/menu-item.md | 4 +-- lib/browser/api/menu-item-roles.js | 4 +-- spec/api-menu-spec.js | 46 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 76fcae1129f3..dc403ea8f7be 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -64,8 +64,8 @@ The `role` property can have following values: * `zoomin` - Zoom in the focused page by 10% * `zoomout` - Zoom out the focused page by 10% -* `menuEdit` - Whole default "Edit" menu (Undo,Copy, etc.) -* `menuWindow` - Whole default "Window" menu (Minimize, Close, etc.) +* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.) +* `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.) On macOS `role` can also have following additional values: diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 8919b8d10ec7..b843bb82e8b6 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -156,7 +156,7 @@ const roles = { } }, // submenu Edit (should fit both Mac & Windows) - menuEdit: { + editMenu: { label: 'Edit', submenu: [ { @@ -197,7 +197,7 @@ const roles = { }, // submenu Window should be used for Mac only - menuWindow: { + windowMenu: { label: 'Window', submenu: [ { diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index 176f1eafae52..cfe5e3934821 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -455,6 +455,52 @@ describe('menu module', function () { }) }) + describe('MenuItem editMenu', function() { + it('includes a default submenu layout when submenu is empty', function() { + var item = new MenuItem({role: 'editMenu'}) + assert.equal(item.label, 'Edit') + assert.equal(item.submenu.items[0].role, 'undo') + assert.equal(item.submenu.items[1].role, 'redo') + assert.equal(item.submenu.items[2].type, 'separator') + assert.equal(item.submenu.items[3].role, 'cut') + assert.equal(item.submenu.items[4].role, 'copy') + assert.equal(item.submenu.items[5].role, 'paste') + if (process.platform == 'darwin') { + assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle') + assert.equal(item.submenu.items[7].role, 'delete') + assert.equal(item.submenu.items[8].role, 'selectall') + } + if (process.platform == 'win32') { + assert.equal(item.submenu.items[6].role, 'delete') + assert.equal(item.submenu.items[7].type, 'separator') + assert.equal(item.submenu.items[8].role, 'selectall') + } + }) + it('overrides default layout when submenu is specified', function() { + var item = new MenuItem({role: 'editMenu', submenu: [{ role: 'close'}]}) + assert.equal(item.label, 'Edit') + assert.equal(item.submenu.items[0].role, 'close') + }) + }) + + describe('MenuItem windowMenu', function() { + it('includes a default submenu layout when submenu is empty', function() { + var item = new MenuItem({role: 'windowMenu'}) + assert.equal(item.label, 'Window') + assert.equal(item.submenu.items[0].role, 'minimize') + assert.equal(item.submenu.items[1].role, 'close') + if (process.platform == 'darwin') { + assert.equal(item.submenu.items[2].type, 'separator') + assert.equal(item.submenu.items[3].role, 'front') + } + }) + it('overrides default layout when submenu is specified', function() { + var item = new MenuItem({role: 'windowMenu', submenu: [{ role: 'copy'}]}) + assert.equal(item.label, 'Window') + assert.equal(item.submenu.items[0].role, 'copy') + }) + }) + describe('MenuItem with custom properties in constructor', function () { it('preserves the custom properties', function () { var template = [{ From 6a7b4feb35ad46b71aea0ffd74c91d248660269e Mon Sep 17 00:00:00 2001 From: mst128256 Date: Fri, 24 Mar 2017 12:31:49 +0100 Subject: [PATCH 25/98] Fixed for linting --- spec/api-menu-spec.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index cfe5e3934821..0d809789d71e 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -455,8 +455,8 @@ describe('menu module', function () { }) }) - describe('MenuItem editMenu', function() { - it('includes a default submenu layout when submenu is empty', function() { + describe('MenuItem editMenu', function () { + it('includes a default submenu layout when submenu is empty', function () { var item = new MenuItem({role: 'editMenu'}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'undo') @@ -465,37 +465,37 @@ describe('menu module', function () { assert.equal(item.submenu.items[3].role, 'cut') assert.equal(item.submenu.items[4].role, 'copy') assert.equal(item.submenu.items[5].role, 'paste') - if (process.platform == 'darwin') { + if (process.platform === 'darwin') { assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle') assert.equal(item.submenu.items[7].role, 'delete') assert.equal(item.submenu.items[8].role, 'selectall') } - if (process.platform == 'win32') { + if (process.platform === 'win32') { assert.equal(item.submenu.items[6].role, 'delete') assert.equal(item.submenu.items[7].type, 'separator') assert.equal(item.submenu.items[8].role, 'selectall') } }) - it('overrides default layout when submenu is specified', function() { - var item = new MenuItem({role: 'editMenu', submenu: [{ role: 'close'}]}) + it('overrides default layout when submenu is specified', function () { + var item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'close') }) }) - describe('MenuItem windowMenu', function() { - it('includes a default submenu layout when submenu is empty', function() { + describe('MenuItem windowMenu', function () { + it('includes a default submenu layout when submenu is empty', function () { var item = new MenuItem({role: 'windowMenu'}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'minimize') assert.equal(item.submenu.items[1].role, 'close') - if (process.platform == 'darwin') { + if (process.platform === 'darwin') { assert.equal(item.submenu.items[2].type, 'separator') assert.equal(item.submenu.items[3].role, 'front') } }) - it('overrides default layout when submenu is specified', function() { - var item = new MenuItem({role: 'windowMenu', submenu: [{ role: 'copy'}]}) + it('overrides default layout when submenu is specified', function () { + var item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'copy') }) From 095df457b23a0308ba14c08c0de6e5da6c458008 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 24 Mar 2017 11:14:43 -0700 Subject: [PATCH 26/98] fix docs for thumbnailSize --- docs/api/desktop-capturer.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 85755dc03ef9..f552753445d4 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -60,8 +60,9 @@ The `desktopCapturer` module has the following methods: * `options` Object * `types` String[] - An array of Strings that lists the types of desktop sources to be captured, available types are `screen` and `window`. - * `thumbnailSize` Object (optional) - The suggested size that the media source - thumbnail should be scaled to, defaults to `{width: 150, height: 150}`. + * `thumbnailSize` Object (optional) - The size that the media source thumbnail should be scaled to. + * `width` Integer - Default is `150` + * `height` Integer - Default is `150` * `callback` Function * `error` Error * `sources` [DesktopCapturerSource[]](structures/desktop-capturer-source.md) From d95114016dea559872a06fb2fcedfaa564f66b63 Mon Sep 17 00:00:00 2001 From: Hari Juturu Date: Fri, 24 Mar 2017 15:40:23 -0700 Subject: [PATCH 27/98] V8 dev resources (#9008) * Adding V8 documentation links * Removing extra space * use electron markdown conventions * cross-link v8 and chromium dev docs * fix v8 link --- docs/README.md | 1 + docs/development/chromium-development.md | 2 ++ docs/development/v8-development.md | 11 +++++++++++ 3 files changed, 14 insertions(+) create mode 100644 docs/development/v8-development.md diff --git a/docs/README.md b/docs/README.md index 2df14cc5c1ac..24b23f92a760 100644 --- a/docs/README.md +++ b/docs/README.md @@ -105,3 +105,4 @@ an issue: * [Documentation Styleguide](styleguide.md) * [Updating Chrome](development/updating-chrome.md) * [Chromium Development](development/chromium-development.md) +* [V8 Development](development/v8-development.md) diff --git a/docs/development/chromium-development.md b/docs/development/chromium-development.md index a692714482e4..23506ae918fa 100644 --- a/docs/development/chromium-development.md +++ b/docs/development/chromium-development.md @@ -10,3 +10,5 @@ - [Source Code](https://cs.chromium.org/chromium/src/) - [Development Calendar and Release Info](https://www.chromium.org/developers/calendar) - [Discussion Groups](http://www.chromium.org/developers/discussion-groups) + +See also [V8 Development](v8-development.md) diff --git a/docs/development/v8-development.md b/docs/development/v8-development.md new file mode 100644 index 000000000000..76d13299ca7e --- /dev/null +++ b/docs/development/v8-development.md @@ -0,0 +1,11 @@ +# V8 Development + +> A collection of resources for learning and using V8 + +* [V8 Tracing](https://github.com/v8/v8/wiki/Tracing-V8) +* [V8 Profiler](https://github.com/v8/v8/wiki/V8-Profiler) - Profiler combinations which are useful for profiling: `--prof`, `--trace-ic`, `--trace-opt`, `--trace-deopt`, `--print-bytecode`, `--print-opt-code` +* [V8 Interpreter Design](https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/edit?ts=56f27d9d#heading=h.6jz9dj3bnr8t) +* [Optimizing compiler](https://github.com/v8/v8/wiki/TurboFan) +* [V8 GDB Debugging](https://github.com/v8/v8/wiki/GDB-JIT-Interface) + +See also [Chromium Development](chromium-development.md) From aa5c778ca23182085c331e098175c5c13ac3dec9 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 12:37:07 +1100 Subject: [PATCH 28/98] Generic doc fixes --- docs/api/client-request.md | 2 ++ docs/api/touch-bar-scrubber.md | 4 ++-- docs/api/touch-bar-segmented-control.md | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 0b722f2f09d3..71ade14a8ef3 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -65,6 +65,8 @@ Returns: * `port` Integer * `realm` String * `callback` Function + * `username` String + * `password` String Emitted when an authenticating proxy is asking for user credentials. diff --git a/docs/api/touch-bar-scrubber.md b/docs/api/touch-bar-scrubber.md index 370c98beed1d..31f65d8770cb 100644 --- a/docs/api/touch-bar-scrubber.md +++ b/docs/api/touch-bar-scrubber.md @@ -9,9 +9,9 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `options` Object * `items` [ScrubberItem[]](structures/scrubber-item.md) - An array of items to place in this scrubber * `select` Function - Called when the user taps an item that was not the last tapped item - * `selectedIndex` - The index of the item the user selected + * `selectedIndex` Integer - The index of the item the user selected * `highlight` Function - Called when the user taps any item - * `highlightedIndex` - The index of the item the user touched + * `highlightedIndex` Integer - The index of the item the user touched * `selectedStyle` String - Selected item style. Defaults to `null`. * `overlayStyle` String - Selected overlay item style. Defaults to `null`. * `showArrowButtons` Boolean - Defaults to `false`. diff --git a/docs/api/touch-bar-segmented-control.md b/docs/api/touch-bar-segmented-control.md index 5c8a0de7eba1..4ea037057670 100644 --- a/docs/api/touch-bar-segmented-control.md +++ b/docs/api/touch-bar-segmented-control.md @@ -19,7 +19,7 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `segments` [SegmentedControlSegment[]](structures/segmented-control-segment.md) - An array of segments to place in this control * `selectedIndex` Integer (Optional) - The index of the currently selected segment, will update automatically with user interaction * `change` Function - Called when the user selects a new segment - * `selectedIndex` - The index of the segment the user selected + * `selectedIndex` Integer - The index of the segment the user selected ### Instance Properties From a80148aa299711b81cd587c256261309e7b06de7 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 14:51:23 +1100 Subject: [PATCH 29/98] Add missing property types on the process docs --- docs/api/process.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/api/process.md b/docs/api/process.md index 951abc7df1af..84320ca98bb0 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -32,38 +32,38 @@ process.once('loaded', () => { ### `process.noAsar` -Setting this to `true` can disable the support for `asar` archives in Node's -built-in modules. +A `Boolean` that controls ASAR support inside your application. Setting this to `true` +will disable the support for `asar` archives in Node's built-in modules. ### `process.type` -Current process's type, can be `"browser"` (i.e. main process) or `"renderer"`. +A `String` representing the current process's type, can be `"browser"` (i.e. main process) or `"renderer"`. ### `process.versions.electron` -Electron's version string. +A `String` representing Electron's version string. ### `process.versions.chrome` -Chrome's version string. +A `String` representing Chrome's version string. ### `process.resourcesPath` -Path to the resources directory. +A `String` representing the path to the resources directory. ### `process.mas` -For Mac App Store build, this property is `true`, for other builds it is +A `Boolean`. For Mac App Store build, this property is `true`, for other builds it is `undefined`. ### `process.windowsStore` -If the app is running as a Windows Store app (appx), this property is `true`, +A `Boolean`. If the app is running as a Windows Store app (appx), this property is `true`, for otherwise it is `undefined`. ### `process.defaultApp` -When app is started by being passed as parameter to the default app, this +A `Boolean`. When app is started by being passed as parameter to the default app, this property is `true` in the main process, otherwise it is `undefined`. ## Methods From b62f1fd0229343cf0fdce6ca2ca46de93d78073f Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 14:59:48 +1100 Subject: [PATCH 30/98] Add missing return type on executeJavaScript --- docs/api/web-frame.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 25ae3480f938..abe8e4d91626 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -136,6 +136,9 @@ Inserts `text` to the focused element. * `callback` Function (optional) - Called after script has been executed. * `result` Any +Returns `Promise` - A promise that resolves with the result of the executed code +or is rejected if the result of the code is a rejected promise. + Evaluates `code` in page. In the browser window some HTML APIs like `requestFullScreen` can only be From 168c47bf105d0f3081612b7f78cea12866bd2a2a Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 18:27:43 +1100 Subject: [PATCH 31/98] Update web-contents.md --- docs/api/web-contents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index b91f6d9edef5..72dc4b0f7454 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1247,7 +1247,7 @@ one through the `'paint'` event. #### `contents.getWebRTCIPHandlingPolicy()` -* Returns `String` - Returns the WebRTC IP Handling Policy. +Returns `String` - Returns the WebRTC IP Handling Policy. #### `contents.setWebRTCIPHandlingPolicy(policy)` From 4e1b237649ab47be976d7df6598f63f32b207c19 Mon Sep 17 00:00:00 2001 From: owwo Date: Sun, 26 Mar 2017 18:42:07 -0500 Subject: [PATCH 32/98] Fix translation error --- docs-translations/zh-CN/tutorial/electron-versioning.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs-translations/zh-CN/tutorial/electron-versioning.md b/docs-translations/zh-CN/tutorial/electron-versioning.md index 18bd3735404f..7027347b3927 100644 --- a/docs-translations/zh-CN/tutorial/electron-versioning.md +++ b/docs-translations/zh-CN/tutorial/electron-versioning.md @@ -5,7 +5,7 @@ 版本号使用参照以下规则: * 主要版本: 适用于 Electron API 的突破性变更 - 如果您从 `0.37.0` 升级到 `1.0.0`, 您将需要升级您的应用程序。 -* 次要版本: 适用于 Chrome 主要版本 和 Node 次要版本升级; 或重大的 Electron 变动 - 如果您从 `0.37.0` 升级到 `1.0.0`, 您的应用程序仍然可以正常运行, 但你可能需要解决一些小幅的变动。 -* 补丁版本: 适用于新功能的添加和 bug 修复 - 如果您从 `0.37.0` 升级到 `1.0.0`, 你的应用程序仍然像之前一样正常运行。 +* 次要版本: 适用于 Chrome 主要版本 和 Node 次要版本升级; 或重大的 Electron 变动 - 如果您从 `1.0.0` 升级到 `1.1.0`, 您的应用程序仍然可以正常运行, 但你可能需要解决一些小幅的变动。 +* 补丁版本: 适用于新功能的添加和 bug 修复 - 如果您从 `1.0.0` 升级到 `1.0.1`, 你的应用程序仍然像之前一样正常运行。 如果你使用 `electron` 或 `electron-prebuilt`,我们建议您设置固定的版本号(如 1.1.0 而不是 ^1.1.0),以确保Electron的所有升级都是由您(开发人员)进行的手动操作。 From dccfadd2bce9d8231787c201d096372d0580dac4 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Mon, 27 Mar 2017 11:16:05 +0800 Subject: [PATCH 33/98] add getFileIcon method --- docs-translations/zh-CN/api/app.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs-translations/zh-CN/api/app.md b/docs-translations/zh-CN/api/app.md index 99429119f3f6..04680d548ba5 100644 --- a/docs-translations/zh-CN/api/app.md +++ b/docs-translations/zh-CN/api/app.md @@ -356,6 +356,27 @@ Windows, 使应用的第一个窗口获取焦点. * `pictures` 用户图片目录的路径. * `videos` 用户视频目录的路径. +### `app.getFileIcon(path[, options], callback)` +* `path` String +* `options` Object(可选) + * `size` String + * `small` - 16x16 + * `normal` - 32x32 + * `large` - Linux 为 48x48, Windows 为 32x32, Mac 系统不支持 +* `callback` Function + * `error` Error + * `icon` [NativeImage](native-image.md) + + +获取文件关联的图标. + +在 Windows 系统中, 有2种图标类型: + +- 图标与某些文件扩展名关联, 比如 `.mp3`, `.png`, 等等. +- 图标在文件内部, 比如 `.exe`, `.dll`, `.ico`. + +在 Linux 和 Mac 系统中, 图标取决于应用程序相关文件的 mime 类型 + ### `app.setPath(name, path)` * `name` String From 9a4783bf34ba07a3f181418eb7c3766aad3bb190 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 09:15:40 -0700 Subject: [PATCH 34/98] Disable flaky post navigation spec on AppVeyor --- spec/webview-spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 2f5cb8068c4d..4ea9369d666f 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -121,6 +121,9 @@ describe(' tag', function () { }) it('loads node symbols after POST navigation when set', function (done) { + // FIXME Figure out why this is timing out on AppVeyor + if (process.env.APPVEYOR === 'True') return done() + webview.addEventListener('console-message', function (e) { assert.equal(e.message, 'function object object') done() From 870dcb9071fe9f5a883dfd2c0f04e77d1d7bb90b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 10:14:38 -0700 Subject: [PATCH 35/98] Remove old sandbox option in list and mark as experimental --- docs/api/browser-window.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 13d823c231c3..182e798158b1 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -226,10 +226,12 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. Node global symbols back to the global scope. See example [here](process.md#event-loaded). * `sandbox` Boolean (optional) - If set, this will sandbox the renderer - associated with the window, making it compatible with chromium sandbox and - disabling the node.js engine. This is not the same as the - `nodeIntegration` option and the APIs available to the preload script are - more limited. Read more about the option [here](sandbox-option.md). + associated with the window, making it compatible with the Chromium + OS-level sandbox and disabling the Node.js engine. This is not the same as + the `nodeIntegration` option and the APIs available to the preload script + are more limited. Read more about the option [here](sandbox-option.md). + **Note:** This option is currently experimental and may change or be + removed in future Electron releases. * `session` [Session](session.md#class-session) (optional) - Sets the session used by the page. Instead of passing the Session object directly, you can also choose to use the `partition` option instead, which accepts a partition string. When @@ -287,7 +289,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. window. Defaults to `false`. See the [offscreen rendering tutorial](../tutorial/offscreen-rendering.md) for more details. - * `sandbox` Boolean (optional) - Whether to enable Chromium OS-level sandbox. * `contextIsolation` Boolean (optional) - Whether to run Electron APIs and the specified `preload` script in a separate JavaScript context. Defaults to `false`. The context that the `preload` script runs in will still From f24baffc79b770cbbee25327650f17d228ad1cc6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 10:21:01 -0700 Subject: [PATCH 36/98] Expect count to be 0 --- spec/api-session-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index f5a4cbf56c2a..c34cdfdab0ff 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -226,7 +226,7 @@ describe('session module', function () { it('clears localstorage data', function (done) { ipcMain.on('count', function (event, count) { ipcMain.removeAllListeners('count') - assert(!count) + assert.equal(count, 0) done() }) w.loadURL('file://' + path.join(fixtures, 'api', 'localstorage.html')) From 3028bffa736f0e22b1fd4106d36fd012c64bb139 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 11:40:52 -0700 Subject: [PATCH 37/98] Upgrade libcc for webview dnd fix --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index fc87d083750c..94109bdbb231 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - '44448acf6a21024b9adb7140ffef6402a509f8bf' + 'dd95b11e52f1e5596184d83d91c91d7b089d05f6' PLATFORM = { 'cygwin': 'win32', From c3a8f665f299bb73dafdcefb515691c3b9dc3eb0 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 27 Mar 2017 18:19:34 -0300 Subject: [PATCH 38/98] Extract base class from AtomRendererClient The new `RendererClientBase` class contains code that is not specific to node.js integration with the renderer. --- atom/renderer/atom_renderer_client.cc | 165 +--------------------- atom/renderer/atom_renderer_client.h | 19 +-- atom/renderer/renderer_client_base.cc | 190 ++++++++++++++++++++++++++ atom/renderer/renderer_client_base.h | 50 +++++++ filenames.gypi | 2 + 5 files changed, 248 insertions(+), 178 deletions(-) create mode 100644 atom/renderer/renderer_client_base.cc create mode 100644 atom/renderer/renderer_client_base.h diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index eb1bdccbe34c..9d015b4f229f 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -9,53 +9,23 @@ #include "atom_natives.h" // NOLINT: This file is generated with js2c -#include "atom/common/api/api_messages.h" #include "atom/common/api/atom_bindings.h" #include "atom/common/api/event_emitter_caller.h" #include "atom/common/asar/asar_util.h" #include "atom/common/atom_constants.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/options_switches.h" #include "atom/renderer/api/atom_api_renderer_ipc.h" #include "atom/renderer/atom_render_view_observer.h" -#include "atom/renderer/content_settings_observer.h" -#include "atom/renderer/guest_view_container.h" #include "atom/renderer/node_array_buffer_bridge.h" -#include "atom/renderer/preferences_manager.h" #include "atom/renderer/web_worker_observer.h" #include "base/command_line.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" -#include "chrome/renderer/tts_dispatcher.h" -#include "content/public/common/content_constants.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" -#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 "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/WebKit.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebPluginParams.h" -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebScriptSource.h" -#include "third_party/WebKit/public/web/WebSecurityPolicy.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 #include "atom/common/node_includes.h" @@ -184,35 +154,11 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { 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"); } -std::vector ParseSchemesCLISwitch(const char* switch_name) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name); - return base::SplitString( - custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); -} - } // namespace AtomRendererClient::AtomRendererClient() @@ -221,11 +167,6 @@ AtomRendererClient::AtomRendererClient() atom_bindings_(new AtomBindings(uv_default_loop())) { isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kContextIsolation); - // Parse --standard-schemes=scheme1,scheme2 - std::vector standard_schemes_list = - ParseSchemesCLISwitch(switches::kStandardSchemes); - for (const std::string& scheme : standard_schemes_list) - url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); } AtomRendererClient::~AtomRendererClient() { @@ -233,80 +174,19 @@ AtomRendererClient::~AtomRendererClient() { } void AtomRendererClient::RenderThreadStarted() { - blink::WebCustomElement::addEmbedderCustomElementName("webview"); - blink::WebCustomElement::addEmbedderCustomElementName("browserplugin"); - OverrideNodeArrayBuffer(); - - 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); - if (!app_id.empty()) { - 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 + RendererClientBase::RenderThreadStarted(); } void AtomRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { - new PepperHelper(render_frame); new AtomRenderFrameObserver(render_frame, this); - new ContentSettingsObserver(render_frame); - new printing::PrintWebViewHelper(render_frame); - - // Allow file scheme to handle service worker by default. - // FIXME(zcbenz): Can this be moved elsewhere? - blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file"); - - // This is required for widevine plugin detection provided during runtime. - blink::resetPluginCache(); - - // Allow access to file scheme from pdf viewer. - blink::WebSecurityPolicy::addOriginAccessWhitelistEntry( - GURL(kPdfViewerUIOrigin), "file", "", true); - - // Parse --secure-schemes=scheme1,scheme2 - std::vector secure_schemes_list = - ParseSchemesCLISwitch(switches::kSecureSchemes); - for (const std::string& secure_scheme : secure_schemes_list) - blink::WebSecurityPolicy::registerURLSchemeAsSecure( - blink::WebString::fromUTF8(secure_scheme)); + RendererClientBase::RenderFrameCreated(render_frame); } void AtomRendererClient::RenderViewCreated(content::RenderView* 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. - 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); - web_frame_widget->setBaseBackgroundColor(color); - } + RendererClientBase::RenderViewCreated(render_view); } void AtomRendererClient::DidClearWindowObject( @@ -335,26 +215,6 @@ void AtomRendererClient::RunScriptsAtDocumentEnd( } } -blink::WebSpeechSynthesizer* AtomRendererClient::OverrideSpeechSynthesizer( - blink::WebSpeechSynthesizerClient* client) { - return new TtsDispatcher(client); -} - -bool AtomRendererClient::OverrideCreatePlugin( - content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - blink::WebPlugin** plugin) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (params.mimeType.utf8() == content::kBrowserPluginMimeType || - params.mimeType.utf8() == kPdfPluginMimeType || - command_line->HasSwitch(switches::kEnablePlugins)) - return false; - - *plugin = nullptr; - return true; -} - void AtomRendererClient::DidCreateScriptContext( v8::Handle context, content::RenderFrame* render_frame) { // Only allow node integration for the main frame, unless it is a devtools @@ -374,8 +234,7 @@ void AtomRendererClient::DidCreateScriptContext( // Add Electron extended APIs. atom_bindings_->BindTo(env->isolate(), env->process_object()); - AddRenderBindings(env->isolate(), env->process_object(), - preferences_manager_.get()); + AddRenderBindings(env->isolate(), env->process_object()); // Load everything. node_bindings_->LoadEnvironment(env); @@ -423,22 +282,6 @@ bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame, return http_method == "GET"; } -content::BrowserPluginDelegate* AtomRendererClient::CreateBrowserPluginDelegate( - content::RenderFrame* render_frame, - const std::string& mime_type, - const GURL& original_url) { - if (mime_type == content::kBrowserPluginMimeType) { - return new GuestViewContainer(render_frame); - } else { - return nullptr; - } -} - -void AtomRendererClient::AddSupportedKeySystems( - std::vector>* key_systems) { - AddChromeKeySystems(key_systems); -} - void AtomRendererClient::DidInitializeWorkerContextOnWorkerThread( v8::Local context) { if (base::CommandLine::ForCurrentProcess()->HasSwitch( diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index af8397854e3e..5a1141d1036d 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -8,15 +8,14 @@ #include #include -#include "content/public/renderer/content_renderer_client.h" +#include "atom/renderer/renderer_client_base.h" namespace atom { class AtomBindings; -class PreferencesManager; class NodeBindings; -class AtomRendererClient : public content::ContentRendererClient { +class AtomRendererClient : public RendererClientBase { public: AtomRendererClient(); virtual ~AtomRendererClient(); @@ -46,25 +45,12 @@ class AtomRendererClient : public content::ContentRendererClient { 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, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - blink::WebPlugin** plugin) override; bool ShouldFork(blink::WebLocalFrame* frame, const GURL& url, const std::string& http_method, bool is_initial_navigation, bool is_server_redirect, bool* send_referrer) override; - content::BrowserPluginDelegate* CreateBrowserPluginDelegate( - content::RenderFrame* render_frame, - const std::string& mime_type, - const GURL& original_url) override; - void AddSupportedKeySystems( - std::vector>* key_systems) - override; void DidInitializeWorkerContextOnWorkerThread( v8::Local context) override; void WillDestroyWorkerContextOnWorkerThread( @@ -75,7 +61,6 @@ class AtomRendererClient : public content::ContentRendererClient { std::unique_ptr node_bindings_; std::unique_ptr atom_bindings_; - std::unique_ptr preferences_manager_; bool isolated_world_; DISALLOW_COPY_AND_ASSIGN(AtomRendererClient); diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc new file mode 100644 index 000000000000..3ee72b3c0da2 --- /dev/null +++ b/atom/renderer/renderer_client_base.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/renderer/renderer_client_base.h" + +#include +#include + +#include "atom/common/atom_constants.h" +#include "atom/common/color_util.h" +#include "atom/common/native_mate_converters/value_converter.h" +#include "atom/common/options_switches.h" +#include "atom/renderer/content_settings_observer.h" +#include "atom/renderer/guest_view_container.h" +#include "atom/renderer/preferences_manager.h" +#include "base/command_line.h" +#include "base/strings/string_split.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" +#include "chrome/renderer/tts_dispatcher.h" +#include "content/public/common/content_constants.h" +#include "content/public/renderer/render_view.h" +#include "native_mate/dictionary.h" +#include "third_party/WebKit/public/web/WebCustomElement.h" +#include "third_party/WebKit/public/web/WebFrameWidget.h" +#include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebPluginParams.h" +#include "third_party/WebKit/public/web/WebSecurityPolicy.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 + +namespace atom { + +namespace { + +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); +} + +std::vector ParseSchemesCLISwitch(const char* switch_name) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name); + return base::SplitString( + custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); +} + +} // namespace + +RendererClientBase::RendererClientBase() { + // Parse --standard-schemes=scheme1,scheme2 + std::vector standard_schemes_list = + ParseSchemesCLISwitch(switches::kStandardSchemes); + for (const std::string& scheme : standard_schemes_list) + url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); +} + +RendererClientBase::~RendererClientBase() { +} + +void RendererClientBase::AddRenderBindings( + v8::Isolate* isolate, + v8::Local binding_object) { + mate::Dictionary dict(isolate, binding_object); + dict.SetMethod( + "getRenderProcessPreferences", + base::Bind(GetRenderProcessPreferences, preferences_manager_.get())); +} + +void RendererClientBase::RenderThreadStarted() { + blink::WebCustomElement::addEmbedderCustomElementName("webview"); + blink::WebCustomElement::addEmbedderCustomElementName("browserplugin"); + + 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); + if (!app_id.empty()) { + 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 RendererClientBase::RenderFrameCreated( + content::RenderFrame* render_frame) { + new PepperHelper(render_frame); + new ContentSettingsObserver(render_frame); + new printing::PrintWebViewHelper(render_frame); + + // Allow file scheme to handle service worker by default. + // FIXME(zcbenz): Can this be moved elsewhere? + blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file"); + + // This is required for widevine plugin detection provided during runtime. + blink::resetPluginCache(); + + // Allow access to file scheme from pdf viewer. + blink::WebSecurityPolicy::addOriginAccessWhitelistEntry( + GURL(kPdfViewerUIOrigin), "file", "", true); + + // Parse --secure-schemes=scheme1,scheme2 + std::vector secure_schemes_list = + ParseSchemesCLISwitch(switches::kSecureSchemes); + for (const std::string& secure_scheme : secure_schemes_list) + blink::WebSecurityPolicy::registerURLSchemeAsSecure( + blink::WebString::fromUTF8(secure_scheme)); +} + +void RendererClientBase::RenderViewCreated(content::RenderView* render_view) { + 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. + 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); + web_frame_widget->setBaseBackgroundColor(color); + } +} + +blink::WebSpeechSynthesizer* RendererClientBase::OverrideSpeechSynthesizer( + blink::WebSpeechSynthesizerClient* client) { + return new TtsDispatcher(client); +} + +bool RendererClientBase::OverrideCreatePlugin( + content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + blink::WebPlugin** plugin) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (params.mimeType.utf8() == content::kBrowserPluginMimeType || + params.mimeType.utf8() == kPdfPluginMimeType || + command_line->HasSwitch(switches::kEnablePlugins)) + return false; + + *plugin = nullptr; + return true; +} + +content::BrowserPluginDelegate* RendererClientBase::CreateBrowserPluginDelegate( + content::RenderFrame* render_frame, + const std::string& mime_type, + const GURL& original_url) { + if (mime_type == content::kBrowserPluginMimeType) { + return new GuestViewContainer(render_frame); + } else { + return nullptr; + } +} + +void RendererClientBase::AddSupportedKeySystems( + std::vector>* key_systems) { + AddChromeKeySystems(key_systems); +} + +} // namespace atom diff --git a/atom/renderer/renderer_client_base.h b/atom/renderer/renderer_client_base.h new file mode 100644 index 000000000000..3a91255c60b1 --- /dev/null +++ b/atom/renderer/renderer_client_base.h @@ -0,0 +1,50 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_RENDERER_CLIENT_BASE_H_ +#define ATOM_RENDERER_RENDERER_CLIENT_BASE_H_ + +#include +#include + +#include "content/public/renderer/content_renderer_client.h" + +namespace atom { + +class PreferencesManager; + +class RendererClientBase : public content::ContentRendererClient { + public: + RendererClientBase(); + virtual ~RendererClientBase(); + + protected: + void AddRenderBindings(v8::Isolate* isolate, + v8::Local binding_object); + + // content::ContentRendererClient: + void RenderThreadStarted() override; + void RenderFrameCreated(content::RenderFrame*) override; + void RenderViewCreated(content::RenderView*) override; + blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( + blink::WebSpeechSynthesizerClient* client) override; + bool OverrideCreatePlugin(content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + blink::WebPlugin** plugin) override; + content::BrowserPluginDelegate* CreateBrowserPluginDelegate( + content::RenderFrame* render_frame, + const std::string& mime_type, + const GURL& original_url) override; + void AddSupportedKeySystems( + std::vector>* key_systems) + override; + + private: + std::unique_ptr preferences_manager_; +}; + +} // namespace atom + +#endif // ATOM_RENDERER_RENDERER_CLIENT_BASE_H_ diff --git a/filenames.gypi b/filenames.gypi index 3b557fcb88a4..935d7033153a 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -480,6 +480,8 @@ 'atom/renderer/node_array_buffer_bridge.h', 'atom/renderer/preferences_manager.cc', 'atom/renderer/preferences_manager.h', + 'atom/renderer/renderer_client_base.cc', + 'atom/renderer/renderer_client_base.h', 'atom/renderer/web_worker_observer.cc', 'atom/renderer/web_worker_observer.h', 'atom/utility/atom_content_utility_client.cc', From d1f08beddfb7991411a890c6b0afd5f73ee2cdb5 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 27 Mar 2017 18:31:18 -0300 Subject: [PATCH 39/98] Make AtomSandboxedRendererClient a RendererClientBase subclass. --- atom/renderer/atom_sandboxed_renderer_client.cc | 4 +++- atom/renderer/atom_sandboxed_renderer_client.h | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index bf9ea6fd9ef8..48d1640f976c 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -182,12 +182,13 @@ AtomSandboxedRendererClient::~AtomSandboxedRendererClient() { void AtomSandboxedRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { new AtomSandboxedRenderFrameObserver(render_frame, this); - new printing::PrintWebViewHelper(render_frame); + RendererClientBase::RenderFrameCreated(render_frame); } void AtomSandboxedRendererClient::RenderViewCreated( content::RenderView* render_view) { new AtomSandboxedRenderViewObserver(render_view, this); + RendererClientBase::RenderViewCreated(render_view); } void AtomSandboxedRendererClient::DidCreateScriptContext( @@ -218,6 +219,7 @@ void AtomSandboxedRendererClient::DidCreateScriptContext( // Create and initialize the binding object auto binding = v8::Object::New(isolate); InitializeBindings(binding, context); + AddRenderBindings(isolate, binding); v8::Local args[] = { binding, mate::ConvertToV8(isolate, preload_script) diff --git a/atom/renderer/atom_sandboxed_renderer_client.h b/atom/renderer/atom_sandboxed_renderer_client.h index 0912c6b24bd0..aefd10caf70d 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.h +++ b/atom/renderer/atom_sandboxed_renderer_client.h @@ -7,12 +7,11 @@ #include #include -#include "content/public/renderer/content_renderer_client.h" -#include "content/public/renderer/render_frame.h" +#include "atom/renderer/renderer_client_base.h" namespace atom { -class AtomSandboxedRendererClient : public content::ContentRendererClient { +class AtomSandboxedRendererClient : public RendererClientBase { public: AtomSandboxedRendererClient(); virtual ~AtomSandboxedRendererClient(); From 3004f3c76216c44613c5ff766bad7bd7022309bf Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Tue, 28 Mar 2017 11:49:47 +0800 Subject: [PATCH 40/98] Update dialog.md --- docs-translations/zh-CN/api/dialog.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs-translations/zh-CN/api/dialog.md b/docs-translations/zh-CN/api/dialog.md index 702b6ea3e2bf..41ec25672196 100644 --- a/docs-translations/zh-CN/api/dialog.md +++ b/docs-translations/zh-CN/api/dialog.md @@ -107,20 +107,23 @@ console.log(dialog) * `options` Object * `type` String - 可以是 `"none"`, `"info"`, `"error"`, `"question"` 或 `"warning"`. 在 Windows, "question" 与 "info" 展示图标相同, 除非你使用 "icon" 参数. - * `buttons` Array - buttons 内容,数组. - * `defaultId` Integer - 在message box 对话框打开的时候,设置默认button选中,值为在 buttons 数组中的button索引. - * `title` String - message box 的标题,一些平台不显示. - * `message` String - message box 内容. - * `detail` String - 额外信息. - * `icon` [NativeImage](native-image.md) - * `cancelId` Integer - 当用户关闭对话框的时候,不是通过点击对话框的button,就返回值.默认值为对应 "cancel" 或 "no" 标签button 的索引值, 或者如果没有这种button,就返回0. 在 macOS 和 Windows 上, "Cancel" button 的索引值将一直是 `cancelId`, 不管之前是不是特别指出的. - * `noLink` Boolean - 在 Windows ,Electron 将尝试识别哪个button 是普通 button (如 "Cancel" 或 "Yes"), 然后在对话框中以链接命令(command links)方式展现其它的 button . 这能让对话框展示得很炫酷.如果你不喜欢这种效果,你可以设置 `noLink` 为 `true`. - * `callback` Function (可选) - * `response` Number - The index of the button that was clicked + * `buttons` String[]- (可选) - 按钮上文字的数组,在 Windows 系统中,空数组在按钮上会显示 “OK”. + * `defaultId` Integer (可选) - 在 message box 对话框打开的时候,设置默认选中的按钮,值为在 buttons 数组中的索引. + * `title` String (可选) - message box 的标题,一些平台不显示. + * `message` String (可选) - message box 的内容. + * `detail` String (可选)- 额外信息. + * `checkboxLabel` String (可选) - 如果有该参数,message box 中会显示一个 checkbox 复选框,它的勾选状态可以在 `callback` 回调方法中获取。 + * `checkboxChecked` Boolean (可选) - checkbox 的初始值,默认为`false`. + * `icon` [NativeImage](native-image.md)(可选) + * `cancelId` Integer - 当用户不是通过按钮而是使用其他方式关闭对话框时,比如按`Esc`键,就返回该值.默认值为对应 "cancel" 或 "no" 标签 button 的索引值, 如果没有这种 button,就返回0. 该选项在 Windows 上无效. + * `noLink` Boolean(可选) - 在 Windows 系统中,Electron 将尝试识别哪个button 是普通 button (如 "Cancel" 或 "Yes"), 然后在对话框中以链接命令(command links)方式展现其它的 button . 这能让对话框展示得很炫酷.如果你不喜欢这种效果,你可以设置 `noLink` 为 `true`. +* `callback` Function (可选) + * `response` Number - 被点击按钮的索引值。 + * `checkboxChecked` Boolean - 如果设置了 `checkboxLabel` ,会显示 checkbox 的选中状态,否则显示 `false` 返回 `Integer`,如果提供了回调,它会返回点击的按钮的索引或者 undefined 。 -展示 message box, 它会阻塞进程,直到 message box 关闭为止.返回点击按钮的索引值。 +显示 message box 时, 它会阻塞进程,直到 message box 关闭为止.返回点击按钮的索引值。 `browserWindow` 参数允许对话框将自身附加到父窗口,使其成为模态。 From 2ef1b70897cbc86afe4cde7350fe6d2a801c4966 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 28 Mar 2017 17:19:14 +0900 Subject: [PATCH 41/98] Fix crash happened in UvRunOnce --- atom/common/node_bindings.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 314a7b9c0330..f4696773dad6 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -232,6 +232,12 @@ void NodeBindings::RunMessageLoop() { void NodeBindings::UvRunOnce() { node::Environment* env = uv_env(); + // When doing navigation without restarting renderer process, it may happen + // that the node environment is destroyed but the message loop is still there. + // In this case we should not run uv loop. + if (!env) + return; + // Use Locker in browser process. mate::Locker locker(env->isolate()); v8::HandleScope handle_scope(env->isolate()); From 3ae62615f4248a874c5614098ccbd19444a73fce Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Fri, 24 Mar 2017 01:07:54 +0530 Subject: [PATCH 42/98] net: allow controlling redirects --- atom/browser/api/atom_api_url_request.cc | 37 ++++- atom/browser/api/atom_api_url_request.h | 6 + atom/browser/net/atom_url_request.cc | 55 ++++++- atom/browser/net/atom_url_request.h | 15 +- lib/browser/api/net.js | 12 +- spec/api-net-spec.js | 193 +++++++++++++++++++++++ 6 files changed, 312 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/atom_api_url_request.cc b/atom/browser/api/atom_api_url_request.cc index 967ae50a7e1f..d3607e7283cc 100644 --- a/atom/browser/api/atom_api_url_request.cc +++ b/atom/browser/api/atom_api_url_request.cc @@ -8,6 +8,7 @@ #include "atom/browser/net/atom_url_request.h" #include "atom/common/api/event_emitter_caller.h" #include "atom/common/native_mate_converters/callback.h" +#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/node_includes.h" @@ -145,6 +146,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) { dict.Get("method", &method); std::string url; dict.Get("url", &url); + std::string redirect_policy; + dict.Get("redirect", &redirect_policy); std::string partition; mate::Handle session; if (dict.Get("session", &session)) { @@ -156,8 +159,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) { } auto browser_context = session->browser_context(); auto api_url_request = new URLRequest(args->isolate(), args->GetThis()); - auto atom_url_request = - AtomURLRequest::Create(browser_context, method, url, api_url_request); + auto atom_url_request = AtomURLRequest::Create( + browser_context, method, url, redirect_policy, api_url_request); api_url_request->atom_request_ = atom_url_request; @@ -176,6 +179,7 @@ void URLRequest::BuildPrototype(v8::Isolate* isolate, .SetMethod("setExtraHeader", &URLRequest::SetExtraHeader) .SetMethod("removeExtraHeader", &URLRequest::RemoveExtraHeader) .SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload) + .SetMethod("followRedirect", &URLRequest::FollowRedirect) .SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags) .SetProperty("notStarted", &URLRequest::NotStarted) .SetProperty("finished", &URLRequest::Finished) @@ -246,6 +250,17 @@ void URLRequest::Cancel() { Close(); } +void URLRequest::FollowRedirect() { + if (request_state_.Canceled() || request_state_.Closed()) { + return; + } + + DCHECK(atom_request_); + if (atom_request_) { + atom_request_->FollowRedirect(); + } +} + bool URLRequest::SetExtraHeader(const std::string& name, const std::string& value) { // Request state must be in the initial non started state. @@ -305,6 +320,24 @@ void URLRequest::SetLoadFlags(int flags) { } } +void URLRequest::OnReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers) { + if (request_state_.Canceled() || request_state_.Closed()) { + return; + } + + DCHECK(atom_request_); + if (!atom_request_) { + return; + } + + EmitRequestEvent(false, "redirect", status_code, method, url, + response_headers.get()); +} + void URLRequest::OnAuthenticationRequired( scoped_refptr auth_info) { if (request_state_.Canceled() || request_state_.Closed()) { diff --git a/atom/browser/api/atom_api_url_request.h b/atom/browser/api/atom_api_url_request.h index c92ac01961cd..372ac98ac657 100644 --- a/atom/browser/api/atom_api_url_request.h +++ b/atom/browser/api/atom_api_url_request.h @@ -99,6 +99,11 @@ class URLRequest : public mate::EventEmitter { v8::Local prototype); // Methods for reporting events into JavaScript. + void OnReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers); void OnAuthenticationRequired( scoped_refptr auth_info); void OnResponseStarted( @@ -170,6 +175,7 @@ class URLRequest : public mate::EventEmitter { bool Failed() const; bool Write(scoped_refptr buffer, bool is_last); void Cancel(); + void FollowRedirect(); bool SetExtraHeader(const std::string& name, const std::string& value); void RemoveExtraHeader(const std::string& name); void SetChunkedUpload(bool is_chunked_upload); diff --git a/atom/browser/net/atom_url_request.cc b/atom/browser/net/atom_url_request.cc index 2c7bb61da0b1..19c526700d20 100644 --- a/atom/browser/net/atom_url_request.cc +++ b/atom/browser/net/atom_url_request.cc @@ -13,6 +13,7 @@ #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/upload_bytes_element_reader.h" +#include "net/url_request/redirect_info.h" namespace { const int kBufferSize = 4096; @@ -58,6 +59,7 @@ scoped_refptr AtomURLRequest::Create( AtomBrowserContext* browser_context, const std::string& method, const std::string& url, + const std::string& redirect_policy, api::URLRequest* delegate) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -76,7 +78,7 @@ scoped_refptr AtomURLRequest::Create( if (content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&AtomURLRequest::DoInitialize, atom_url_request, - request_context_getter, method, url))) { + request_context_getter, method, url, redirect_policy))) { return atom_url_request; } return nullptr; @@ -93,10 +95,12 @@ void AtomURLRequest::Terminate() { void AtomURLRequest::DoInitialize( scoped_refptr request_context_getter, const std::string& method, - const std::string& url) { + const std::string& url, + const std::string& redirect_policy) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(request_context_getter); + redirect_policy_ = redirect_policy; request_context_getter_ = request_context_getter; request_context_getter_->AddObserver(this); auto context = request_context_getter_->GetURLRequestContext(); @@ -150,6 +154,13 @@ void AtomURLRequest::Cancel() { base::Bind(&AtomURLRequest::DoCancel, this)); } +void AtomURLRequest::FollowRedirect() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&AtomURLRequest::DoFollowRedirect, this)); +} + void AtomURLRequest::SetExtraHeader(const std::string& name, const std::string& value) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -246,6 +257,13 @@ void AtomURLRequest::DoCancel() { DoTerminate(); } +void AtomURLRequest::DoFollowRedirect() { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (request_ && request_->is_redirecting() && redirect_policy_ == "manual") { + request_->FollowDeferredRedirect(); + } +} + void AtomURLRequest::DoSetExtraHeader(const std::string& name, const std::string& value) const { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -297,6 +315,29 @@ void AtomURLRequest::DoSetLoadFlags(int flags) const { request_->SetLoadFlags(request_->load_flags() | flags); } +void AtomURLRequest::OnReceivedRedirect(net::URLRequest* request, + const net::RedirectInfo& info, + bool* defer_redirect) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (!request_ || redirect_policy_ == "follow") + return; + + if (redirect_policy_ == "error") { + request->Cancel(); + DoCancelWithError( + "Request cannot follow redirect with the current redirect mode", true); + } else if (redirect_policy_ == "manual") { + *defer_redirect = true; + scoped_refptr response_headers = + request->response_headers(); + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(&AtomURLRequest::InformDelegateReceivedRedirect, this, + info.status_code, info.new_method, info.new_url, + response_headers)); + } +} + void AtomURLRequest::OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* auth_info) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -399,6 +440,16 @@ bool AtomURLRequest::CopyAndPostBuffer(int bytes_read) { buffer_copy)); } +void AtomURLRequest::InformDelegateReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers) const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (delegate_) + delegate_->OnReceivedRedirect(status_code, method, url, response_headers); +} + void AtomURLRequest::InformDelegateAuthenticationRequired( scoped_refptr auth_info) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); diff --git a/atom/browser/net/atom_url_request.h b/atom/browser/net/atom_url_request.h index db00390b955c..654798d8aac8 100644 --- a/atom/browser/net/atom_url_request.h +++ b/atom/browser/net/atom_url_request.h @@ -30,12 +30,14 @@ class AtomURLRequest : public base::RefCountedThreadSafe, AtomBrowserContext* browser_context, const std::string& method, const std::string& url, + const std::string& redirect_policy, api::URLRequest* delegate); void Terminate(); bool Write(scoped_refptr buffer, bool is_last); void SetChunkedUpload(bool is_chunked_upload); void Cancel(); + void FollowRedirect(); void SetExtraHeader(const std::string& name, const std::string& value) const; void RemoveExtraHeader(const std::string& name) const; void PassLoginInformation(const base::string16& username, @@ -44,6 +46,9 @@ class AtomURLRequest : public base::RefCountedThreadSafe, protected: // Overrides of net::URLRequest::Delegate + void OnReceivedRedirect(net::URLRequest* request, + const net::RedirectInfo& info, + bool* defer_redirect) override; void OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* auth_info) override; void OnResponseStarted(net::URLRequest* request) override; @@ -60,11 +65,13 @@ class AtomURLRequest : public base::RefCountedThreadSafe, void DoInitialize(scoped_refptr, const std::string& method, - const std::string& url); + const std::string& url, + const std::string& redirect_policy); void DoTerminate(); void DoWriteBuffer(scoped_refptr buffer, bool is_last); void DoCancel(); + void DoFollowRedirect(); void DoSetExtraHeader(const std::string& name, const std::string& value) const; void DoRemoveExtraHeader(const std::string& name) const; @@ -77,6 +84,11 @@ class AtomURLRequest : public base::RefCountedThreadSafe, void ReadResponse(); bool CopyAndPostBuffer(int bytes_read); + void InformDelegateReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers) const; void InformDelegateAuthenticationRequired( scoped_refptr auth_info) const; void InformDelegateResponseStarted( @@ -92,6 +104,7 @@ class AtomURLRequest : public base::RefCountedThreadSafe, scoped_refptr request_context_getter_; bool is_chunked_upload_; + std::string redirect_policy_; std::unique_ptr chunked_stream_; std::unique_ptr chunked_stream_writer_; std::vector> diff --git a/lib/browser/api/net.js b/lib/browser/api/net.js index 10d903919e9d..049cef9e3ab4 100644 --- a/lib/browser/api/net.js +++ b/lib/browser/api/net.js @@ -156,9 +156,15 @@ class ClientRequest extends EventEmitter { urlStr = url.format(urlObj) } + const redirectPolicy = options.redirect || 'follow' + if (!['follow', 'error', 'manual'].includes(redirectPolicy)) { + throw new Error('redirect mode should be one of follow, error or manual') + } + let urlRequestOptions = { method: method, - url: urlStr + url: urlStr, + redirect: redirectPolicy } if (options.session) { if (options.session instanceof Session) { @@ -339,6 +345,10 @@ class ClientRequest extends EventEmitter { return this._write(data, encoding, callback, true) } + followRedirect () { + this.urlRequest.followRedirect() + } + abort () { this.urlRequest.cancel() } diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 49fe2edadcce..80f24a46e9c4 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -906,6 +906,199 @@ describe('net module', function () { urlRequest.end() }) + it('should throw if given an invalid redirect mode', function (done) { + const requestUrl = '/requestUrl' + try { + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'custom' + }) + urlRequest + } catch (exception) { + done() + } + }) + + it('should follow redirect when no redirect mode is provided', function (done) { + const requestUrl = '/301' + server.on('request', function (request, response) { + switch (request.url) { + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}` + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + done() + }) + urlRequest.end() + }) + + it('should follow redirect chain when no redirect mode is provided', function (done) { + const requestUrl = '/redirectChain' + server.on('request', function (request, response) { + switch (request.url) { + case '/redirectChain': + response.statusCode = '301' + response.setHeader('Location', '/301') + response.end() + break + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}` + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + done() + }) + urlRequest.end() + }) + + it('should not follow redirect when mode is error', function (done) { + const requestUrl = '/301' + server.on('request', function (request, response) { + switch (request.url) { + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'error' + }) + urlRequest.on('error', function (error) { + assert.equal(error.message, 'Request cannot follow redirect with the current redirect mode') + }) + urlRequest.on('close', function () { + done() + }) + urlRequest.end() + }) + + it('should allow follow redirect when mode is manual', function (done) { + const requestUrl = '/redirectChain' + let redirectCount = 0 + server.on('request', function (request, response) { + switch (request.url) { + case '/redirectChain': + response.statusCode = '301' + response.setHeader('Location', '/301') + response.end() + break + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'manual' + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + assert.equal(redirectCount, 2) + done() + }) + urlRequest.on('redirect', function (status, method, url) { + if (url === `${server.url}/301` || url === `${server.url}/200`) { + redirectCount += 1 + urlRequest.followRedirect() + } + }) + urlRequest.end() + }) + + it('should allow cancelling redirect when mode is manual', function (done) { + const requestUrl = '/redirectChain' + let redirectCount = 0 + server.on('request', function (request, response) { + switch (request.url) { + case '/redirectChain': + response.statusCode = '301' + response.setHeader('Location', '/redirect/1') + response.end() + break + case '/redirect/1': + response.statusCode = '200' + response.setHeader('Location', '/redirect/2') + response.end() + break + case '/redirect/2': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'manual' + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + response.pause() + response.on('data', function (chunk) { + }) + response.on('end', function () { + urlRequest.abort() + }) + response.resume() + }) + urlRequest.on('close', function () { + assert.equal(redirectCount, 1) + done() + }) + urlRequest.on('redirect', function (status, method, url) { + if (url === `${server.url}/redirect/1`) { + redirectCount += 1 + urlRequest.followRedirect() + } + }) + urlRequest.end() + }) + it('should throw if given an invalid session option', function (done) { const requestUrl = '/requestUrl' try { From 8db1eacd1c19f0570bd76783ac1077ae2e831f85 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sat, 25 Mar 2017 12:37:34 +0530 Subject: [PATCH 43/98] [skip ci] add docs --- docs/api/client-request.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 71ade14a8ef3..4a16d9510ec4 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -29,6 +29,11 @@ the hostname and the port number 'hostname:port' * `hostname` String (optional) - The server host name. * `port` Integer (optional) - The server's listening port number. * `path` String (optional) - The path part of the request URL. + * `redirect` String (optional) - The redirect mode for this request. Should be +one of `follow`, `error` or `manual`. Defaults to `follow`. When mode is `error`, +any redirection will be aborted. When mode is `manual` the redirection will be +deferred until [`request.followRedirect`](#requestfollowRedirect) is invoked. Listen for the [`redirect`](#event-redirect) event in +this mode to get more details about the redirect request. `options` properties such as `protocol`, `host`, `hostname`, `port` and `path` strictly follow the Node.js model as described in the @@ -121,6 +126,19 @@ Emitted as the last event in the HTTP request-response transaction. The `close` event indicates that no more events will be emitted on either the `request` or `response` objects. + +#### Event: 'redirect' + +Returns: + +* `statusCode` Integer +* `method` String +* `redirectUrl` String +* `responseHeaders` Object + +Emitted when there is redirection and the mode is `manual`. Calling +[`request.followRedirect`](#requestfollowRedirect) will continue with the redirection. + ### Instance Properties #### `request.chunkedEncoding` @@ -192,3 +210,7 @@ Cancels an ongoing HTTP transaction. If the request has already emitted the `close` event, the abort operation will have no effect. Otherwise an ongoing event will emit `abort` and `close` events. Additionally, if there is an ongoing response object,it will emit the `aborted` event. + +#### `request.followRedirect()` + +Continues any deferred redirection request when the redirection mode is `manual`. From b14c4dcdc060d0f2f0f7133ce371e94b7b00ee34 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 28 Mar 2017 19:05:44 +0530 Subject: [PATCH 44/98] address review comments --- spec/api-net-spec.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 80f24a46e9c4..68db813d6495 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -906,17 +906,15 @@ describe('net module', function () { urlRequest.end() }) - it('should throw if given an invalid redirect mode', function (done) { + it('should throw if given an invalid redirect mode', function () { const requestUrl = '/requestUrl' - try { - const urlRequest = net.request({ - url: `${server.url}${requestUrl}`, - redirect: 'custom' - }) - urlRequest - } catch (exception) { - done() + const options = { + url: `${server.url}${requestUrl}`, + redirect: 'custom' } + assert.throws(function () { + net.request(options) + }, 'redirect mode should be one of follow, error or manual') }) it('should follow redirect when no redirect mode is provided', function (done) { From f9dbdf45228ccda206b9e7280b481aa85a664f85 Mon Sep 17 00:00:00 2001 From: Anatzum Date: Sat, 28 Jan 2017 02:54:26 -0600 Subject: [PATCH 45/98] Updated MoveItemToTrash in platform_util_linux.cc If ELECTRON_TRASH is null, first check the DESKTOP_SESSION variable and set trash accordingly. Additional desktop environments can be added easily this way with the fallback of ELECTRON_DEFAULT_TRASH. --- atom/common/platform_util_linux.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index 923adbd882be..66ef0cc477e2 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -98,11 +98,19 @@ void OpenExternal(const GURL& url, bool activate, bool MoveItemToTrash(const base::FilePath& full_path) { std::string trash; if (getenv(ELECTRON_TRASH) != NULL) { - trash = getenv(ELECTRON_TRASH); + trash = getenv(ELECTRON_TRASH); } else { - trash = ELECTRON_DEFAULT_TRASH; + // Determine desktop environment and set accordingly. + std::string desktopEnv = getenv(DESKTOP_SESSION); + if (desktopEnv.find("plasma") != std::string::npos) { + trash = "kioclient5"; + } else if (desktopEnv.find("kde") != std::string::npos) { + trash = "kioclient"; + } else { + trash = ELECTRON_DEFAULT_TRASH; + } } - + std::vector argv; if (trash.compare("kioclient5") == 0 || trash.compare("kioclient") == 0) { From 6db827cc9a6221cb20f7b9831187a4e3ffe0805a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 29 Mar 2017 16:21:38 +0900 Subject: [PATCH 46/98] Use GetDesktopEnvironment to determien desktop env Which can get a much more precise result for us. --- atom/common/platform_util_linux.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index 66ef0cc477e2..5c0eaecdd1c2 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -7,7 +7,9 @@ #include #include "base/cancelable_callback.h" +#include "base/environment.h" #include "base/files/file_util.h" +#include "base/nix/xdg_util.h" #include "base/process/kill.h" #include "base/process/launch.h" #include "url/gurl.h" @@ -98,19 +100,22 @@ void OpenExternal(const GURL& url, bool activate, bool MoveItemToTrash(const base::FilePath& full_path) { std::string trash; if (getenv(ELECTRON_TRASH) != NULL) { - trash = getenv(ELECTRON_TRASH); + trash = getenv(ELECTRON_TRASH); } else { // Determine desktop environment and set accordingly. - std::string desktopEnv = getenv(DESKTOP_SESSION); - if (desktopEnv.find("plasma") != std::string::npos) { + std::unique_ptr env(base::Environment::Create()); + base::nix::DesktopEnvironment desktop_env( + base::nix::GetDesktopEnvironment(env.get())); + if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4 || + desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE5) { trash = "kioclient5"; - } else if (desktopEnv.find("kde") != std::string::npos) { + } else if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3) { trash = "kioclient"; } else { - trash = ELECTRON_DEFAULT_TRASH; + trash = ELECTRON_DEFAULT_TRASH; } } - + std::vector argv; if (trash.compare("kioclient5") == 0 || trash.compare("kioclient") == 0) { From 6ae198a6253fdf2321a280ea4b7ac582e69979cc Mon Sep 17 00:00:00 2001 From: mst128256 Date: Wed, 29 Mar 2017 12:17:50 +0200 Subject: [PATCH 47/98] Empty objects within default menu replaced by nulls --- lib/browser/api/menu-item-roles.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index b843bb82e8b6..30ea3f888dba 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -180,7 +180,7 @@ const roles = { process.platform === 'darwin' ? { role: 'pasteandmatchstyle' - } : {}, + } : null, { role: 'delete' @@ -188,7 +188,7 @@ const roles = { process.platform === 'win32' ? { type: 'separator' - } : {}, + } : null, { role: 'selectall' @@ -209,12 +209,11 @@ const roles = { process.platform === 'darwin' ? { type: 'separator' - } : {}, + } : null, process.platform === 'darwin' ? { - label: 'Bring All to Front', role: 'front' - } : {} + } : null ] } @@ -246,7 +245,7 @@ exports.getDefaultSubmenu = (role) => { // remove empty objects from within the submenu if (Array.isArray(submenu)) { submenu = submenu.filter(function (n) { - return n.constructor !== Object || Object.keys(n).length > 0 + return n != null }) } From ed76e0373069570d1825ba0ad91d5470d846bf24 Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Tue, 21 Mar 2017 10:18:57 +0100 Subject: [PATCH 48/98] Revert "Add forward declaration of NSWindow.allowsAutomaticWindowTabbing" This reverts commit 770a3509cfcd62c958dc2b70bd497585f55b565c. --- atom/browser/mac/atom_application_delegate.mm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 9e245f99078d..74f45e2d2669 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -10,10 +10,6 @@ #include "base/strings/sys_string_conversions.h" #include "base/values.h" -@interface NSWindow (SierraSDK) -@property(class) BOOL allowsAutomaticWindowTabbing; -@end - @implementation AtomApplicationDelegate - (void)setApplicationDockMenu:(atom::AtomMenuModel*)model { @@ -26,8 +22,9 @@ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; // Don't add the "Show Tab Bar" menu item. - if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)]) + if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)]) { NSWindow.allowsAutomaticWindowTabbing = NO; + } atom::Browser::Get()->WillFinishLaunching(); } From 9e02c60e2229d38de47405030a99acdc8830a0af Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Tue, 21 Mar 2017 10:19:08 +0100 Subject: [PATCH 49/98] Revert "Disable Show Tab Bar menu item on macOS Sierrra" This reverts commit 24b93139581836ea8ec3f88cda0edbb3baba8812. --- atom/browser/mac/atom_application_delegate.mm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 74f45e2d2669..4c6a938fba59 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -21,11 +21,6 @@ // Don't add the "Enter Full Screen" menu item automatically. [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; - // Don't add the "Show Tab Bar" menu item. - if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)]) { - NSWindow.allowsAutomaticWindowTabbing = NO; - } - atom::Browser::Get()->WillFinishLaunching(); } From a7565f0d5704c1c5a12ec24a3ee669358efc413b Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Mon, 27 Mar 2017 16:15:17 +0200 Subject: [PATCH 50/98] Enable native tabs on macOS --- atom/browser/native_window_mac.h | 2 ++ atom/browser/native_window_mac.mm | 15 ++++++++++++++- atom/common/options_switches.cc | 3 +++ atom/common/options_switches.h | 1 + docs/api/browser-window.md | 3 +++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index bd34993fb119..066bcc503ea9 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -179,6 +179,8 @@ class NativeWindowMac : public NativeWindow, // The "titleBarStyle" option. TitleBarStyle title_bar_style_; + std::string tabbing_identifier_; + DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); }; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index c88469a9c8a1..f73cda1fd07c 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -656,7 +656,8 @@ NativeWindowMac::NativeWindowMac( was_fullscreen_(false), zoom_to_page_width_(false), attention_request_id_(0), - title_bar_style_(NORMAL) { + title_bar_style_(NORMAL), + tabbing_identifier_(""){ int width = 800, height = 600; options.Get(options::kWidth, &width); options.Get(options::kHeight, &height); @@ -682,6 +683,8 @@ NativeWindowMac::NativeWindowMac( options.Get(options::kTitleBarStyle, &title_bar_style_); + options.Get(options::kTabbingIdentifier, &tabbing_identifier_); + std::string windowType; options.Get(options::kType, &windowType); @@ -754,6 +757,16 @@ NativeWindowMac::NativeWindowMac( [window_ setOpaque:NO]; } + if (base::mac::IsAtLeastOS10_12()) { + // Create a tab only if tabbing identifier is specified and window has + // a native title bar. + if (tabbing_identifier_.empty() || transparent() || !has_frame()) { + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + } else { + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + } + } + // We will manage window's lifetime ourselves. [window_ setReleasedWhenClosed:NO]; diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index d040489b9f76..288fcd3a0753 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -51,6 +51,9 @@ const char kZoomToPageWidth[] = "zoomToPageWidth"; // The requested title bar style for the window const char kTitleBarStyle[] = "titleBarStyle"; +// Tabbing identifier for the window if native tabs are enabled on macOS. +const char kTabbingIdentifier[] = "tabbingIdentifier"; + // The menu bar is hidden unless "Alt" is pressed. const char kAutoHideMenuBar[] = "autoHideMenuBar"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index dd2824c55c74..9e1a71ca5bda 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -36,6 +36,7 @@ extern const char kAcceptFirstMouse[]; extern const char kUseContentSize[]; extern const char kZoomToPageWidth[]; extern const char kTitleBarStyle[]; +extern const char kTabbingIdentifier[]; extern const char kAutoHideMenuBar[]; extern const char kEnableLargerThanScreen[]; extern const char kDarkTheme[]; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 182e798158b1..73b7fe9c18b8 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -264,6 +264,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. canvas features. Default is `false`. * `scrollBounce` Boolean (optional) - Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. + * `tabbingIdentifier` String (optional) - Tab group name, allows opening the + window as a native tab on macOS 10.12+. Windows with the same tabbing identifier will + be grouped together. * `blinkFeatures` String (optional) - A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][blink-feature-string] From 99293dd57ffd152e68cf549041680145c495da24 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 29 Mar 2017 20:47:41 +0200 Subject: [PATCH 51/98] Fix namespace comments. --- atom/browser/auto_updater_mac.mm | 2 +- atom/browser/osr/osr_render_widget_host_view_mac.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/auto_updater_mac.mm b/atom/browser/auto_updater_mac.mm index a6102f3e73fa..3802fef16299 100644 --- a/atom/browser/auto_updater_mac.mm +++ b/atom/browser/auto_updater_mac.mm @@ -27,7 +27,7 @@ namespace { bool g_update_available = false; std::string update_url_ = ""; -} +} // namespace std::string AutoUpdater::GetFeedURL() { return update_url_; diff --git a/atom/browser/osr/osr_render_widget_host_view_mac.mm b/atom/browser/osr/osr_render_widget_host_view_mac.mm index 664261947d1d..7cf010ff8e28 100644 --- a/atom/browser/osr/osr_render_widget_host_view_mac.mm +++ b/atom/browser/osr/osr_render_widget_host_view_mac.mm @@ -145,4 +145,4 @@ OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const { return browser_compositor_->GetDelegatedFrameHost(); } -} // namespace +} // namespace atom From 8b4bf1f29ed5629037c93525beabab246e9eda92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:27:59 -0700 Subject: [PATCH 52/98] :art: --- lib/browser/api/menu-item-roles.js | 20 +++++++++----------- spec/api-menu-spec.js | 5 +++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 30ea3f888dba..af0d35b4a56a 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -155,7 +155,7 @@ const roles = { }) } }, - // submenu Edit (should fit both Mac & Windows) + // Edit submenu (should fit both Mac & Windows) editMenu: { label: 'Edit', submenu: [ @@ -196,7 +196,7 @@ const roles = { ] }, - // submenu Window should be used for Mac only + // Window submenu should be used for Mac only windowMenu: { label: 'Window', submenu: [ @@ -239,18 +239,16 @@ exports.getDefaultAccelerator = (role) => { } exports.getDefaultSubmenu = (role) => { - if (roles.hasOwnProperty(role)) { - let submenu = roles[role].submenu + if (!roles.hasOwnProperty(role)) return - // remove empty objects from within the submenu - if (Array.isArray(submenu)) { - submenu = submenu.filter(function (n) { - return n != null - }) - } + let {submenu} = roles[role] - return submenu + // remove null items from within the submenu + if (Array.isArray(submenu)) { + submenu = submenu.filter((item) => item != null) } + + return submenu } exports.execute = (role, focusedWindow, focusedWebContents) => { diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index 0d809789d71e..9b1f3de36906 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -465,17 +465,20 @@ describe('menu module', function () { assert.equal(item.submenu.items[3].role, 'cut') assert.equal(item.submenu.items[4].role, 'copy') assert.equal(item.submenu.items[5].role, 'paste') + if (process.platform === 'darwin') { assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle') assert.equal(item.submenu.items[7].role, 'delete') assert.equal(item.submenu.items[8].role, 'selectall') } + if (process.platform === 'win32') { assert.equal(item.submenu.items[6].role, 'delete') assert.equal(item.submenu.items[7].type, 'separator') assert.equal(item.submenu.items[8].role, 'selectall') } }) + it('overrides default layout when submenu is specified', function () { var item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) assert.equal(item.label, 'Edit') @@ -489,11 +492,13 @@ describe('menu module', function () { assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'minimize') assert.equal(item.submenu.items[1].role, 'close') + if (process.platform === 'darwin') { assert.equal(item.submenu.items[2].type, 'separator') assert.equal(item.submenu.items[3].role, 'front') } }) + it('overrides default layout when submenu is specified', function () { var item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) assert.equal(item.label, 'Window') From 5f724e57bccd3c1d4b84f7516db41d4ea8c78e8c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 29 Mar 2017 21:29:52 +0200 Subject: [PATCH 53/98] Avoid unnecessary copy of parameters. --- atom/browser/api/atom_api_session.cc | 2 +- atom/browser/api/atom_api_web_contents.cc | 2 +- atom/browser/browser.h | 2 +- atom/browser/browser_linux.cc | 2 +- atom/browser/browser_mac.mm | 2 +- atom/browser/browser_win.cc | 2 +- atom/renderer/atom_sandboxed_renderer_client.cc | 2 +- atom/renderer/atom_sandboxed_renderer_client.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 0c850888e8e7..83d103a631f7 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -233,7 +233,7 @@ class ResolveProxyHelper { public: ResolveProxyHelper(AtomBrowserContext* browser_context, const GURL& url, - Session::ResolveProxyCallback callback) + const Session::ResolveProxyCallback& callback) : callback_(callback), original_thread_(base::ThreadTaskRunnerHandle::Get()) { scoped_refptr context_getter = diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index a0100fd65c6e..9390777f9c58 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -240,7 +240,7 @@ content::ServiceWorkerContext* GetServiceWorkerContext( } // Called when CapturePage is done. -void OnCapturePageDone(base::Callback callback, +void OnCapturePageDone(const base::Callback& callback, const SkBitmap& bitmap, content::ReadbackResponse response) { callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 28103a99c704..78cac65f7e40 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -102,7 +102,7 @@ class Browser : public WindowListObserver { std::vector args; }; void SetLoginItemSettings(LoginItemSettings settings); - LoginItemSettings GetLoginItemSettings(LoginItemSettings options); + LoginItemSettings GetLoginItemSettings(const LoginItemSettings& options); #if defined(OS_MACOSX) // Hide the application. diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index 6abfcf5c3481..4dd799dfaf02 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -64,7 +64,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) { } Browser::LoginItemSettings Browser::GetLoginItemSettings( - LoginItemSettings options) { + const LoginItemSettings& options) { return LoginItemSettings(); } diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index c318cf850701..bbc848cb6990 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -152,7 +152,7 @@ bool Browser::ContinueUserActivity(const std::string& type, } Browser::LoginItemSettings Browser::GetLoginItemSettings( - LoginItemSettings options) { + const LoginItemSettings& options) { LoginItemSettings settings; settings.open_at_login = base::mac::CheckLoginItemStatus( &settings.open_as_hidden); diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 85990bbc67e3..50a9f9da330e 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -287,7 +287,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) { } Browser::LoginItemSettings Browser::GetLoginItemSettings( - LoginItemSettings options) { + const LoginItemSettings& options) { LoginItemSettings settings; base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index bf9ea6fd9ef8..fe10860621a9 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -236,7 +236,7 @@ void AtomSandboxedRendererClient::WillReleaseScriptContext( void AtomSandboxedRendererClient::InvokeIpcCallback( v8::Handle context, - std::string callback_name, + const std::string& callback_name, std::vector> args) { auto isolate = context->GetIsolate(); auto binding_key = mate::ConvertToV8(isolate, kIpcKey)->ToString(); diff --git a/atom/renderer/atom_sandboxed_renderer_client.h b/atom/renderer/atom_sandboxed_renderer_client.h index 0912c6b24bd0..6754e0cb89d4 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.h +++ b/atom/renderer/atom_sandboxed_renderer_client.h @@ -22,7 +22,7 @@ class AtomSandboxedRendererClient : public content::ContentRendererClient { void WillReleaseScriptContext( v8::Handle context, content::RenderFrame* render_frame); void InvokeIpcCallback(v8::Handle context, - std::string callback_name, + const std::string& callback_name, std::vector> args); // content::ContentRendererClient: void RenderFrameCreated(content::RenderFrame*) override; From bed32682b736e8a4564afc55ea37b8cea2fbc472 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Wed, 29 Mar 2017 14:27:01 +0100 Subject: [PATCH 54/98] Clarification of the chromium sandbox support --- docs/api/sandbox-option.md | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md index 454a8ad05cca..9598e47257d1 100644 --- a/docs/api/sandbox-option.md +++ b/docs/api/sandbox-option.md @@ -1,9 +1,12 @@ # `sandbox` Option -> Create a browser window with renderer that can run inside chromium OS sandbox. +> Create a browser window with a renderer that can run inside Chromium OS sandbox. With this +option enabled, the renderer must communicate via IPC to the main process in order to access node APIs. +However, in order to enable the Chromium OS sandbox, electron must be run with the `--enable-sandbox` +command line argument. -One of chromium key security features is that all blink rendering/javascript -code is confined in a sandbox. This sandbox uses OS-specific features to ensure +One of the key security features of Chromium is that all blink rendering/JavaScript +code is executed within a sandbox. This sandbox uses OS-specific features to ensure that exploits in the renderer process cannot harm the system. In other words, when the sandbox is enabled, the renderers can only make changes @@ -12,10 +15,10 @@ to the system by delegating tasks to the main process via IPC. information about the sandbox. Since a major feature in electron is the ability to run node.js in the -renderer process(making it easier to develop desktop applications using only web -technologies), the sandbox has to disabled by electron. One of the reasons is -that most node.js APIs require system access. `require()` for example, is not -possible without file system permissions, which are unavailable in a sandboxed +renderer process (making it easier to develop desktop applications using web +technologies), the sandbox is disabled by electron. This is because +most node.js APIs require system access. `require()` for example, is not +possible without file system permissions, which are not available in a sandboxed environment. Usually this is not a problem for desktop applications since the code is always @@ -25,16 +28,16 @@ untrusted web content. For applications that require more security, the compatible with the sandbox. A sandboxed renderer doesn't have a node.js environment running and doesn't -expose javascript APIs to client code. The only exception is the preload script, -which has access to a subset of electron renderer API. +expose node.js JavaScript APIs to client code. The only exception is the preload script, +which has access to a subset of the electron renderer API. Another difference is that sandboxed renderers don't modify any of the default -javascript APIs. Consequently, some APIs such as `window.open` will work as they -do in chromium(no `BrowserWindowProxy`). +JavaScript APIs. Consequently, some APIs such as `window.open` will work as they +do in chromium (i.e. they do not return a `BrowserWindowProxy`). ## Example -Create a sandboxed window, simply pass `sandbox: true` to `webPreferences`: +To create a sandboxed window, simply pass `sandbox: true` to `webPreferences`: ```js let win @@ -48,9 +51,15 @@ app.on('ready', () => { }) ``` -This alone won't enable the OS-enforced sandbox. To use it, the +In the above code the `BrowserWindow` that was created has node.js disabled and can communicate +only via IPC. The use of this option stops electron from creating a node.js runtime in the renderer. Also, +within this new window `window.open` follows the native behaviour (by default electron creates a `BrowserWindow` +and returns a proxy to this via `window.open`). + +It is important to note that this option alone won't enable the OS-enforced sandbox. To enable this feature, the `--enable-sandbox` command-line argument must be passed to electron, which will -force `sandbox: true` to all BrowserWindow instances. +force `sandbox: true` for all `BrowserWindow` instances. + ```js let win @@ -64,7 +73,7 @@ app.on('ready', () => { Note that it is not enough to call `app.commandLine.appendSwitch('--enable-sandbox')`, as electron/node startup code runs after it is possible to make changes to chromium sandbox settings. The -switch must be passed to electron command-line: +switch must be passed to electron on the command-line: ``` electron --enable-sandbox app.js @@ -125,16 +134,16 @@ window.open = customWindowOpen Important things to notice in the preload script: - Even though the sandboxed renderer doesn't have node.js running, it still has - access to a limited node-like environment:`Buffer`, `process`, `setImmediate` + access to a limited node-like environment: `Buffer`, `process`, `setImmediate` and `require` are available. -- The preload can indirectly access all APIs from the main process through the - `remote` and `ipcRenderer` modules. This is how `fs`(used above) and other +- The preload script can indirectly access all APIs from the main process through the + `remote` and `ipcRenderer` modules. This is how `fs` (used above) and other modules are implemented: They are proxies to remote counterparts in the main process. -- The preload must be contained in a single script, but it is possible to have +- The preload script must be contained in a single script, but it is possible to have complex preload code composed with multiple modules by using a tool like browserify, as explained below. In fact, browserify is already used by - electron to provide a node-like environment to the preload script. + electron to provide a node-like environment to the preload script. To create a browserify bundle and use it as a preload script, something like the following should be used: @@ -146,7 +155,7 @@ the following should be used: The `-x` flag should be used with any required module that is already exposed in the preload scope, and tells browserify to use the enclosing `require` function -for it. `--insert-global-vars` will ensure that `process`,`Buffer` and +for it. `--insert-global-vars` will ensure that `process`, `Buffer` and `setImmediate` are also taken from the enclosing scope(normally browserify injects code for those). @@ -154,7 +163,7 @@ Currently the `require` function provided in the preload scope exposes the following modules: - `child_process` -- `electron`(crashReporter, remote and ipcRenderer) +- `electron` (crashReporter, remote and ipcRenderer) - `fs` - `os` - `timers` @@ -166,7 +175,7 @@ module in the main process can already be used through ## Status -Please use the `sandbox` option with care, as it still is an experimental +Please use the `sandbox` option with care, as it is still an experimental feature. We are still not aware of the security implications of exposing some electron renderer APIs to the preload script, but here are some things to consider before rendering untrusted content: @@ -176,11 +185,11 @@ consider before rendering untrusted content: APIs, effectively granting full access to the system through the `remote` module. -Since renderering untrusted content in electron is still uncharted territory, +Since rendering untrusted content in electron is still uncharted territory, the APIs exposed to the sandbox preload script should be considered more unstable than the rest of electron APIs, and may have breaking changes to fix security issues. One planned enhancement that should greatly increase security is to block IPC -messages from sandboxed renderers by default, allowing the main process +messages from sandboxed renderers by default, allowing the main process to explicitly define a set of messages the renderer is allowed to send. From bd935b213f2c9a9aa1807aefecb33d8c47aaead1 Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Thu, 30 Mar 2017 15:13:49 +0200 Subject: [PATCH 55/98] Fix compilation against macOS 10.10 SDK --- atom/browser/native_window_mac.mm | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index f73cda1fd07c..f006873efd78 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -336,6 +336,14 @@ bool ScopedDisableResize::disable_resize_ = false; @end +enum { + NSWindowTabbingModeDisallowed = 2 +}; +@interface NSWindow (SierraSDK) +- (void)setTabbingMode:(NSInteger)mode; +- (void)setTabbingIdentifier:(NSString *)identifier; +@end + @interface AtomNSWindow : EventDispatchingWindow { @private atom::NativeWindowMac* shell_; @@ -656,8 +664,7 @@ NativeWindowMac::NativeWindowMac( was_fullscreen_(false), zoom_to_page_width_(false), attention_request_id_(0), - title_bar_style_(NORMAL), - tabbing_identifier_(""){ + title_bar_style_(NORMAL) { int width = 800, height = 600; options.Get(options::kWidth, &width); options.Get(options::kHeight, &height); @@ -761,9 +768,13 @@ NativeWindowMac::NativeWindowMac( // Create a tab only if tabbing identifier is specified and window has // a native title bar. if (tabbing_identifier_.empty() || transparent() || !has_frame()) { - [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + if ([window_ respondsToSelector:@selector(tabbingMode)]) { + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + } } else { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + } } } From d779ecf6745a6cf08ad6fa4c765dfae2474bb1a7 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 30 Mar 2017 11:07:25 -0700 Subject: [PATCH 56/98] create a linkable heading for MenuItem roles --- docs/api/menu-item.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index dc403ea8f7be..494bdb74f196 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -15,7 +15,7 @@ See [`Menu`](menu.md) for examples. * `browserWindow` BrowserWindow * `event` Event * `role` String (optional) - Define the action of the menu item, when specified the - `click` property will be ignored. + `click` property will be ignored. See [roles](#roles). * `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. * `label` String - (optional) @@ -36,12 +36,16 @@ See [`Menu`](menu.md) for examples. * `position` String (optional) - This field allows fine-grained definition of the specific location within a given menu. +### Roles + +Roles allow menu items to have predefined behaviors. + It is best to specify `role` for any menu item that matches a standard role, rather than trying to manually implement the behavior in a `click` function. The built-in `role` behavior will give the best native experience. -The `label` and `accelerator` are optional when using a `role` and will default -to appropriate values for each platform. +The `label` and `accelerator` values are optional when using a `role` and will +default to appropriate values for each platform. The `role` property can have following values: @@ -63,11 +67,10 @@ The `role` property can have following values: * `resetzoom` - Reset the focused page's zoom level to the original size * `zoomin` - Zoom in the focused page by 10% * `zoomout` - Zoom out the focused page by 10% - * `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.) * `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.) -On macOS `role` can also have following additional values: +The following additional roles are avaiable on macOS: * `about` - Map to the `orderFrontStandardAboutPanel` action * `hide` - Map to the `hide` action @@ -81,8 +84,8 @@ On macOS `role` can also have following additional values: * `help` - The submenu is a "Help" menu * `services` - The submenu is a "Services" menu -When specifying `role` on macOS, `label` and `accelerator` are the only options -that will affect the MenuItem. All other options will be ignored. +When specifying a `role` on macOS, `label` and `accelerator` are the only +options that will affect the menu item. All other options will be ignored. ### Instance Properties From b24be19fac195bfd3fe19459c6498851dfa34ebd Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 30 Mar 2017 11:07:59 -0700 Subject: [PATCH 57/98] tighten up formatting of menu example --- docs/api/menu.md | 161 ++++++++++++----------------------------------- 1 file changed, 41 insertions(+), 120 deletions(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index cd6817625a35..391b52d43724 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -115,76 +115,36 @@ const template = [ { label: 'Edit', submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - } + {role: 'undo'}, + {role: 'redo'}, + {type: 'separator'}, + {role: 'cut'}, + {role: 'copy'}, + {role: 'paste'}, + {role: 'pasteandmatchstyle'}, + {role: 'delete'}, + {role: 'selectall'} ] }, { label: 'View', submenu: [ - { - role: 'reload' - }, - { - role: 'forcereload' - }, - { - role: 'toggledevtools' - }, - { - type: 'separator' - }, - { - role: 'resetzoom' - }, - { - role: 'zoomin' - }, - { - role: 'zoomout' - }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - } + {role: 'reload'}, + {role: 'forcereload'}, + {role: 'toggledevtools'}, + {type: 'separator'}, + {role: 'resetzoom'}, + {role: 'zoomin'}, + {role: 'zoomout'}, + {type: 'separator'}, + {role: 'togglefullscreen'} ] }, { role: 'window', submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - } + {role: 'minimize'}, + {role: 'close'} ] }, { @@ -202,76 +162,37 @@ if (process.platform === 'darwin') { template.unshift({ label: app.getName(), submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, - { - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - } + {role: 'about'}, + {type: 'separator'}, + {role: 'services', submenu: []}, + {type: 'separator'}, + {role: 'hide'}, + {role: 'hideothers'}, + {role: 'unhide'}, + {type: 'separator'}, + {role: 'quit'} ] }) - // Edit menu. + + // Edit menu template[1].submenu.push( - { - type: 'separator' - }, + {type: 'separator'}, { label: 'Speech', submenu: [ - { - role: 'startspeaking' - }, - { - role: 'stopspeaking' - } + {role: 'startspeaking'}, + {role: 'stopspeaking'} ] } ) - // Window menu. + + // Window menu template[3].submenu = [ - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Zoom', - role: 'zoom' - }, - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } + {role: 'close'}, + {role: 'minimize'}, + {role: 'zoom'}, + {type: 'separator'}, + {role: 'front'} ] } From d5bc8990fc18a9e0af7a34b82f7c3933824e0c50 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 30 Mar 2017 11:08:12 -0700 Subject: [PATCH 58/98] link to roles list from Menu doc --- docs/api/menu.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index 391b52d43724..42724e1d4afc 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -30,8 +30,8 @@ Returns `Menu` - The application menu, if set, or `null`, if not set. * `action` String Sends the `action` to the first responder of application. This is used for -emulating default Cocoa menu behaviors, usually you would just use the -`role` property of `MenuItem`. +emulating default macOS menu behaviors. Usually you would just use the +[`role`](menu-item.md#roles) property of a [`MenuItem`](menu-item.md). See the [macOS Cocoa Event Handling Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html#//apple_ref/doc/uid/10000060i-CH3-SW7) for more information on macOS' native actions. From 55bf2239dfa332197abd54874ddfb6a55c43119e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 11:58:09 -0700 Subject: [PATCH 59/98] Remove spaces around brackets --- docs/api/remote.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 2db8d17c9992..2abb2a843110 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -158,7 +158,7 @@ project/ ```js // main process: main/index.js -const { app } = require('electron') +const {app} = require('electron') app.on('ready', () => { /* ... */ }) ``` From b3cf00a19aa57c32774e60eb2a0b70c0f25aef1e Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 30 Mar 2017 13:24:40 -0300 Subject: [PATCH 60/98] Fix net module to accept non-string header values This is required to be compatible with node.js http module. --- docs/api/client-request.md | 7 ++++--- lib/browser/api/net.js | 4 ++-- spec/api-net-spec.js | 43 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 4a16d9510ec4..9821b44261a5 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -158,17 +158,18 @@ internally buffered inside Electron process memory. #### `request.setHeader(name, value)` * `name` String - An extra HTTP header name. -* `value` String - An extra HTTP header value. +* `value` Object - An extra HTTP header value. Adds an extra HTTP header. The header name will issued as it is without lowercasing. It can be called only before first write. Calling this method after -the first write will throw an error. +the first write will throw an error. If the passed value is not a `String`, its +`toString()` method will be called to obtain the final value. #### `request.getHeader(name)` * `name` String - Specify an extra header name. -Returns String - The value of a previously set extra header name. +Returns Object - The value of a previously set extra header name. #### `request.removeHeader(name)` diff --git a/lib/browser/api/net.js b/lib/browser/api/net.js index 049cef9e3ab4..5a4d23b07397 100644 --- a/lib/browser/api/net.js +++ b/lib/browser/api/net.js @@ -246,7 +246,7 @@ class ClientRequest extends EventEmitter { if (typeof name !== 'string') { throw new TypeError('`name` should be a string in setHeader(name, value).') } - if (value === undefined) { + if (value == null) { throw new Error('`value` required in setHeader("' + name + '", value).') } if (!this.urlRequest.notStarted) { @@ -255,7 +255,7 @@ class ClientRequest extends EventEmitter { const key = name.toLowerCase() this.extraHeaders[key] = value - this.urlRequest.setExtraHeader(name, value) + this.urlRequest.setExtraHeader(name, value.toString()) } getHeader (name) { diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 68db813d6495..ec4f45fb7246 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -364,6 +364,49 @@ describe('net module', function () { urlRequest.end() }) + it('should be able to set a non-string object as a header value', function (done) { + const requestUrl = '/requestUrl' + const customHeaderName = 'Some-Integer-Value' + const customHeaderValue = 900 + server.on('request', function (request, response) { + switch (request.url) { + case requestUrl: + assert.equal(request.headers[customHeaderName.toLowerCase()], + customHeaderValue.toString()) + response.statusCode = 200 + response.statusMessage = 'OK' + response.end() + break + default: + assert.equal(request.url, requestUrl) + } + }) + const urlRequest = net.request({ + method: 'GET', + url: `${server.url}${requestUrl}` + }) + urlRequest.on('response', function (response) { + const statusCode = response.statusCode + assert.equal(statusCode, 200) + response.pause() + response.on('end', function () { + done() + }) + response.resume() + }) + urlRequest.setHeader(customHeaderName, customHeaderValue) + assert.equal(urlRequest.getHeader(customHeaderName), + customHeaderValue) + assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()), + customHeaderValue) + urlRequest.write('') + assert.equal(urlRequest.getHeader(customHeaderName), + customHeaderValue) + assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()), + customHeaderValue) + urlRequest.end() + }) + it('should not be able to set a custom HTTP request header after first write', function (done) { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' From 4001ba038e66812c50707687114f7cadf87c6bf0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 12:06:33 -0700 Subject: [PATCH 61/98] Add descriptions for each segmentStyle --- docs/api/touch-bar-segmented-control.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/api/touch-bar-segmented-control.md b/docs/api/touch-bar-segmented-control.md index 4ea037057670..42be09079082 100644 --- a/docs/api/touch-bar-segmented-control.md +++ b/docs/api/touch-bar-segmented-control.md @@ -8,14 +8,19 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `options` Object * `segmentStyle` String - (Optional) Style of the segments: - * `automatic` - Default - * `rounded` - * `textured-rounded` - * `round-rect` - * `textured-square` - * `capsule` - * `small-square` - * `separated` + * `automatic` - Default. The appearance of the segmented control is + automatically determined based on the type of window in which the control + is displayed and the position within the window. + * `rounded` - The control is displayed using the rounded style. + * `textured-rounded` - The control is displayed using the textured rounded + style. + * `round-rect` - The control is displayed using the round rect style. + * `textured-square` - The control is displayed using the textured square + style. + * `capsule` - The control is displayed using the capsule style + * `small-square` - The control is displayed using the small square style. + * `separated` - The segments in the control are displayed very close to each + other but not touching. * `segments` [SegmentedControlSegment[]](structures/segmented-control-segment.md) - An array of segments to place in this control * `selectedIndex` Integer (Optional) - The index of the currently selected segment, will update automatically with user interaction * `change` Function - Called when the user selects a new segment From 6ef3be23fd9685a803908cf8aaa20acbe482cb68 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 21:56:28 +0200 Subject: [PATCH 62/98] Avoid copy in for range loop. --- atom/browser/common_web_contents_delegate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 59ffc7dcbc08..f7f9e46250eb 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -338,7 +338,7 @@ void CommonWebContentsDelegate::DevToolsRequestFileSystems() { } std::vector file_systems; - for (auto file_system_path : file_system_paths) { + for (const auto& file_system_path : file_system_paths) { base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), path); From 00693ba075504fd006bde3c66ca8dc8bcf31d8fe Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 21:59:18 +0200 Subject: [PATCH 63/98] Replace "size()" with "empty()". --- atom/app/atom_content_client.cc | 2 +- atom/browser/api/atom_api_app.cc | 2 +- atom/browser/api/atom_api_auto_updater.cc | 2 +- atom/browser/browser.cc | 4 ++-- atom/browser/node_debugger.cc | 2 +- atom/browser/ui/cocoa/atom_touch_bar.mm | 2 +- atom/browser/window_list.cc | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc index 954d239b5034..8e2a6c573097 100644 --- a/atom/app/atom_content_client.cc +++ b/atom/app/atom_content_client.cc @@ -44,7 +44,7 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, std::vector flash_version_numbers = base::SplitString( version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (flash_version_numbers.size() < 1) + if (flash_version_numbers.empty()) flash_version_numbers.push_back("11"); // |SplitString()| puts in an empty string given an empty string. :( else if (flash_version_numbers[0].empty()) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 56a11daf69bd..c64ad41113f8 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -427,7 +427,7 @@ void OnClientCertificateSelected( auto certs = net::X509Certificate::CreateCertificateListFromBytes( data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO); - if (certs.size() > 0) + if (!certs.empty()) delegate->ContinueWithCertificate(certs[0].get()); } diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 67079abf2864..276d889006d1 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -88,7 +88,7 @@ void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) { void AutoUpdater::QuitAndInstall() { // If we don't have any window then quitAndInstall immediately. WindowList* window_list = WindowList::GetInstance(); - if (window_list->size() == 0) { + if (window_list->empty()) { auto_updater::AutoUpdater::QuitAndInstall(); return; } diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 9b7423cd7d9f..b18ab7b70fd7 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -44,7 +44,7 @@ void Browser::Quit() { return; atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->size() == 0) + if (window_list->empty()) NotifyAndShutdown(); window_list->CloseAllWindows(); @@ -66,7 +66,7 @@ void Browser::Exit(mate::Arguments* args) { // Must destroy windows before quitting, otherwise bad things can happen. atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->size() == 0) { + if (window_list->empty()) { Shutdown(); } else { // Unlike Quit(), we do not ask to close window, but destroy the window diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc index e95369fba190..9fdeb6099e6a 100644 --- a/atom/browser/node_debugger.cc +++ b/atom/browser/node_debugger.cc @@ -164,7 +164,7 @@ void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket, buffer_.append(data, len); do { - if (buffer_.size() == 0) + if (buffer_.empty()) return; // Read the "Content-Length" header. diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 4952e28876c6..639ec2aaa698 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -319,7 +319,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; - (void)updateColorPicker:(NSColorPickerTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings { std::vector colors; - if (settings.Get("availableColors", &colors) && colors.size() > 0) { + if (settings.Get("availableColors", &colors) && !colors.empty()) { NSColorList* color_list = [[[NSColorList alloc] initWithName:@""] autorelease]; for (size_t i = 0; i < colors.size(); ++i) { [color_list insertColor:[self colorFromHexColorString:colors[i]] diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index b835e07e752a..d627f6d1206b 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -46,7 +46,7 @@ void WindowList::RemoveWindow(NativeWindow* window) { for (WindowListObserver& observer : observers_.Get()) observer.OnWindowRemoved(window); - if (windows.size() == 0) { + if (windows.empty()) { for (WindowListObserver& observer : observers_.Get()) observer.OnWindowAllClosed(); } From d425b63b0da1ee7d922b36dde3f8173847ef509e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:12:14 +0200 Subject: [PATCH 64/98] NULL => nullptr --- atom/browser/native_window_mac.mm | 2 +- atom/browser/ui/cocoa/atom_menu_controller.mm | 2 +- atom/browser/ui/file_dialog_mac.mm | 4 ++-- atom/common/platform_util_mac.mm | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index c88469a9c8a1..520ba2d6698e 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1262,7 +1262,7 @@ void NativeWindowMac::SetProgressBar(double progress, const NativeWindow::Progre NSDockTile* dock_tile = [NSApp dockTile]; // For the first time API invoked, we need to create a ContentView in DockTile. - if (dock_tile.contentView == NULL) { + if (dock_tile.contentView == nullptr) { NSImageView* image_view = [[NSImageView alloc] init]; [image_view setImage:[NSApp applicationIconImage]]; [dock_tile setContentView:image_view]; diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm index b3e293153f96..d0bbf6a153a3 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ b/atom/browser/ui/cocoa/atom_menu_controller.mm @@ -70,7 +70,7 @@ Role kRolesMap[] = { // while its context menu is still open. [self cancel]; - model_ = NULL; + model_ = nullptr; [super dealloc]; } diff --git a/atom/browser/ui/file_dialog_mac.mm b/atom/browser/ui/file_dialog_mac.mm index 70272cbddc8f..80143a987bc7 100644 --- a/atom/browser/ui/file_dialog_mac.mm +++ b/atom/browser/ui/file_dialog_mac.mm @@ -154,7 +154,7 @@ void ShowOpenDialog(const DialogSettings& settings, NSWindow* window = settings.parent_window ? settings.parent_window->GetNativeWindow() : - NULL; + nullptr; [dialog beginSheetModalForWindow:window completionHandler:^(NSInteger chosen) { if (chosen == NSFileHandlingPanelCancelButton) { @@ -193,7 +193,7 @@ void ShowSaveDialog(const DialogSettings& settings, NSWindow* window = settings.parent_window ? settings.parent_window->GetNativeWindow() : - NULL; + nullptr; [dialog beginSheetModalForWindow:window completionHandler:^(NSInteger chosen) { if (chosen == NSFileHandlingPanelCancelButton) { diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index aa64678caffe..4a91efd70538 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -71,10 +71,10 @@ std::string MessageForOSStatus(OSStatus status, const char* default_message) { // thread safe, including LSGetApplicationForURL (> 10.2) and // NSWorkspace#openURLs. std::string OpenURL(NSURL* ns_url, bool activate) { - CFURLRef openingApp = NULL; + CFURLRef openingApp = nullptr; OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, kLSRolesAll, - NULL, + nullptr, &openingApp); if (status != noErr) return MessageForOSStatus(status, "Failed to open"); @@ -156,7 +156,7 @@ bool OpenItem(const base::FilePath& full_path) { // Create the list of files (only ever one) to open. base::mac::ScopedAEDesc fileList; - status = AECreateList(NULL, // factoringPtr + status = AECreateList(nullptr, // factoringPtr 0, // factoredSize false, // isRecord fileList.OutPointer()); // resultList @@ -202,8 +202,8 @@ bool OpenItem(const base::FilePath& full_path) { kAENoReply + kAEAlwaysInteract, // sendMode kAENormalPriority, // sendPriority kAEDefaultTimeout, // timeOutInTicks - NULL, // idleProc - NULL); // filterProc + nullptr, // idleProc + nullptr); // filterProc if (status != noErr) { OSSTATUS_LOG(WARNING, status) << "Could not send AE to Finder in OpenItem()"; From 1b9780035c7aeb57ec8e03087aacef1544947abb Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:22:40 +0200 Subject: [PATCH 65/98] Remove redundant calls to smart pointer's get method. --- atom/browser/api/atom_api_app.cc | 6 +++--- atom/browser/net/atom_network_delegate.cc | 2 +- atom/browser/osr/osr_render_widget_host_view.cc | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index c64ad41113f8..709696340274 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -520,7 +520,7 @@ void App::OnQuit() { int exitCode = AtomBrowserMainParts::Get()->GetExitCode(); Emit("quit", exitCode); - if (process_singleton_.get()) { + if (process_singleton_) { process_singleton_->Cleanup(); process_singleton_.reset(); } @@ -695,7 +695,7 @@ std::string App::GetLocale() { bool App::MakeSingleInstance( const ProcessSingleton::NotificationCallback& callback) { - if (process_singleton_.get()) + if (process_singleton_) return false; base::FilePath user_dir; @@ -716,7 +716,7 @@ bool App::MakeSingleInstance( } void App::ReleaseSingleInstance() { - if (process_singleton_.get()) { + if (process_singleton_) { process_singleton_->Cleanup(); process_singleton_.reset(); } diff --git a/atom/browser/net/atom_network_delegate.cc b/atom/browser/net/atom_network_delegate.cc index 2ba3f8e35781..3a5b667f06d0 100644 --- a/atom/browser/net/atom_network_delegate.cc +++ b/atom/browser/net/atom_network_delegate.cc @@ -402,7 +402,7 @@ void AtomNetworkDelegate::OnListenerResultInIO( if (!base::ContainsKey(callbacks_, id)) return; - ReadFromResponseObject(*response.get(), out); + ReadFromResponseObject(*response, out); bool cancel = false; response->GetBoolean("cancel", &cancel); diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index 7355f1a0c1e2..2003118f389e 100644 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ b/atom/browser/osr/osr_render_widget_host_view.cc @@ -851,12 +851,12 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval( base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_)); - if (copy_frame_generator_.get()) { + if (copy_frame_generator_) { copy_frame_generator_->set_frame_rate_threshold_ms( frame_rate_threshold_ms_); } - if (begin_frame_timer_.get()) { + if (begin_frame_timer_) { begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_); } else { begin_frame_timer_.reset(new AtomBeginFrameTimer( @@ -871,7 +871,7 @@ void OffScreenRenderWidgetHostView::Invalidate() { if (software_output_device_) { software_output_device_->OnPaint(bounds_in_pixels); - } else if (copy_frame_generator_.get()) { + } else if (copy_frame_generator_) { copy_frame_generator_->GenerateCopyFrame(true, bounds_in_pixels); } } From bb51401c4c13e56c35337ab2f335683eca29a8f5 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:33:09 +0200 Subject: [PATCH 66/98] Use base::mac::NSToCast. --- atom/common/platform_util_mac.mm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index 4a91efd70538..9cbbaedbe181 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -11,6 +11,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/mac/foundation_util.h" #include "base/mac/mac_logging.h" #include "base/mac/scoped_aedesc.h" #include "base/strings/stringprintf.h" @@ -72,10 +73,10 @@ std::string MessageForOSStatus(OSStatus status, const char* default_message) { // NSWorkspace#openURLs. std::string OpenURL(NSURL* ns_url, bool activate) { CFURLRef openingApp = nullptr; - OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, - kLSRolesAll, - nullptr, - &openingApp); + OSStatus status = LSGetApplicationForURL(base::mac::NSToCFCast(ns_url), + kLSRolesAll, + nullptr, + &openingApp); if (status != noErr) return MessageForOSStatus(status, "Failed to open"); @@ -167,7 +168,8 @@ bool OpenItem(const base::FilePath& full_path) { // Add the single path to the file list. C-style cast to avoid both a // static_cast and a const_cast to get across the toll-free bridge. - CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; + CFURLRef pathURLRef = base::mac::NSToCFCast( + [NSURL fileURLWithPath:path_string]); FSRef pathRef; if (CFURLGetFSRef(pathURLRef, &pathRef)) { status = AEPutPtr(fileList.OutPointer(), // theAEDescList From c8b992fa3982ffd880c8c2cc931d5a0c892f56e3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:46:34 -0700 Subject: [PATCH 67/98] Remove 10.12 check handled by respondsToSelector --- atom/browser/native_window_mac.mm | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index f006873efd78..077eee52288f 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -764,17 +764,15 @@ NativeWindowMac::NativeWindowMac( [window_ setOpaque:NO]; } - if (base::mac::IsAtLeastOS10_12()) { - // Create a tab only if tabbing identifier is specified and window has - // a native title bar. - if (tabbing_identifier_.empty() || transparent() || !has_frame()) { - if ([window_ respondsToSelector:@selector(tabbingMode)]) { - [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; - } - } else { - if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; - } + // Create a tab only if tabbing identifier is specified and window has + // a native title bar. + if (tabbing_identifier_.empty() || transparent() || !has_frame()) { + if ([window_ respondsToSelector:@selector(tabbingMode)]) { + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + } + } else { + if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; } } From e699e88b4caed3929ce8b3e077a08660f0612ccc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:46:58 -0700 Subject: [PATCH 68/98] Add initial tabbingIdentifier spec --- spec/api-browser-window-spec.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index b5985e4b7406..d83c173f26f1 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -692,7 +692,7 @@ describe('BrowserWindow module', function () { }) }) - describe('"title-bar-style" option', function () { + describe('"titleBarStyle" option', function () { if (process.platform !== 'darwin') { return } @@ -772,6 +772,20 @@ describe('BrowserWindow module', function () { }) }) + describe('"tabbingIdentifier" option', function () { + it('can be set on a window', function () { + w.destroy() + w = new BrowserWindow({ + tabbingIdentifier: 'group1' + }) + w.destroy() + w = new BrowserWindow({ + tabbingIdentifier: 'group2', + frame: false + }) + }) + }) + describe('"web-preferences" option', function () { afterEach(function () { ipcMain.removeAllListeners('answer') From 42300ae58ef31a911a20828718741275f0fdf067 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:47:11 -0700 Subject: [PATCH 69/98] Make tabbing identifier var local --- atom/browser/native_window_mac.h | 2 -- atom/browser/native_window_mac.mm | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 066bcc503ea9..bd34993fb119 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -179,8 +179,6 @@ class NativeWindowMac : public NativeWindow, // The "titleBarStyle" option. TitleBarStyle title_bar_style_; - std::string tabbing_identifier_; - DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); }; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 077eee52288f..2912022bd634 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -690,7 +690,8 @@ NativeWindowMac::NativeWindowMac( options.Get(options::kTitleBarStyle, &title_bar_style_); - options.Get(options::kTabbingIdentifier, &tabbing_identifier_); + std::string tabbingIdentifier; + options.Get(options::kTabbingIdentifier, &tabbingIdentifier); std::string windowType; options.Get(options::kType, &windowType); @@ -766,13 +767,13 @@ NativeWindowMac::NativeWindowMac( // Create a tab only if tabbing identifier is specified and window has // a native title bar. - if (tabbing_identifier_.empty() || transparent() || !has_frame()) { + if (tabbingIdentifier.empty() || transparent() || !has_frame()) { if ([window_ respondsToSelector:@selector(tabbingMode)]) { [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; } } else { if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)]; } } From 6f27d466a508852455d973441f99dbdf77a483ab Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:49:00 -0700 Subject: [PATCH 70/98] Move tabbingIdentifier out of webPreferences list --- docs/api/browser-window.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 73b7fe9c18b8..01f5431ecf73 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -211,6 +211,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. width of the web page when zoomed, `false` will cause it to zoom to the width of the screen. This will also affect the behavior when calling `maximize()` directly. Default is `false`. + * `tabbingIdentifier` String (optional) - Tab group name, allows opening the + window as a native tab on macOS 10.12+. Windows with the same tabbing + identifier will be grouped together. * `webPreferences` Object (optional) - Settings of web page's features. * `devTools` Boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. * `nodeIntegration` Boolean (optional) - Whether node integration is enabled. Default @@ -264,9 +267,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. canvas features. Default is `false`. * `scrollBounce` Boolean (optional) - Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. - * `tabbingIdentifier` String (optional) - Tab group name, allows opening the - window as a native tab on macOS 10.12+. Windows with the same tabbing identifier will - be grouped together. * `blinkFeatures` String (optional) - A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][blink-feature-string] From 8d8c7ce6ad37ce0b512d0775b297c2880e401927 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:53:20 +0200 Subject: [PATCH 71/98] Correct type cast. --- atom/browser/browser_mac.mm | 3 ++- atom/browser/ui/cocoa/atom_touch_bar.mm | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index bbc848cb6990..f231d7a4f0ae 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -65,7 +65,8 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol, // 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); + other = base::mac::CFCast(CFArrayGetValueAtIndex(bundleList, + i)); if (![identifier isEqualToString: (__bridge NSString *)other]) { break; } diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 639ec2aaa698..6e3fc838c157 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -474,7 +474,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("segments", &segments); control.segmentCount = segments.size(); - for (int i = 0; i < (int)segments.size(); i++) { + for (size_t i = 0; i < segments.size(); i++) { std::string label; gfx::Image image; bool enabled = true; @@ -581,7 +581,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; std::vector items; if (!settings.Get("items", &items)) return nil; - if (index >= (long)items.size()) return nil; + if (index >= static_cast(items.size())) return nil; mate::PersistentDictionary item = items[index]; From ff745e1a823b059c243aa39895e7160b69a7a0b6 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:56:21 +0200 Subject: [PATCH 72/98] Use prefix increment in for loops. --- atom/browser/browser_mac.mm | 2 +- atom/browser/ui/cocoa/atom_touch_bar.mm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index f231d7a4f0ae..1a15bc013917 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -64,7 +64,7 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol, // On macOS, 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++) { + for (CFIndex i = 0; i < CFArrayGetCount(bundleList); ++i) { other = base::mac::CFCast(CFArrayGetValueAtIndex(bundleList, i)); if (![identifier isEqualToString: (__bridge NSString *)other]) { diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 6e3fc838c157..69926684b67a 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -414,7 +414,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; NSMutableArray* generatedItems = [NSMutableArray array]; NSMutableArray* identifiers = [self identifiersFromSettings:items]; - for (NSUInteger i = 0; i < [identifiers count]; i++) { + for (NSUInteger i = 0; i < [identifiers count]; ++i) { if ([identifiers objectAtIndex:i] != NSTouchBarItemIdentifierOtherItemsProxy) { NSTouchBarItem* generatedItem = [self makeItemForIdentifier:[identifiers objectAtIndex:i]]; if (generatedItem) { @@ -474,7 +474,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("segments", &segments); control.segmentCount = segments.size(); - for (size_t i = 0; i < segments.size(); i++) { + for (size_t i = 0; i < segments.size(); ++i) { std::string label; gfx::Image image; bool enabled = true; From fcb7cbc54a552f67a064ca564fdf898cdcc91746 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 12:37:40 -0700 Subject: [PATCH 73/98] Check name directly instead of arguments length --- lib/browser/api/net.js | 4 ++-- spec/api-net-spec.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/browser/api/net.js b/lib/browser/api/net.js index 5a4d23b07397..d32f6946eee5 100644 --- a/lib/browser/api/net.js +++ b/lib/browser/api/net.js @@ -259,7 +259,7 @@ class ClientRequest extends EventEmitter { } getHeader (name) { - if (arguments.length < 1) { + if (name == null) { throw new Error('`name` is required for getHeader(name).') } @@ -272,7 +272,7 @@ class ClientRequest extends EventEmitter { } removeHeader (name) { - if (arguments.length < 1) { + if (name == null) { throw new Error('`name` is required for removeHeader(name).') } diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index ec4f45fb7246..dc024553a858 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -960,6 +960,26 @@ describe('net module', function () { }, 'redirect mode should be one of follow, error or manual') }) + it('should throw when calling getHeader without a name', function () { + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).getHeader() + }, /`name` is required for getHeader\(name\)\./) + + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).getHeader(null) + }, /`name` is required for getHeader\(name\)\./) + }) + + it('should throw when calling removeHeader without a name', function () { + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).removeHeader() + }, /`name` is required for removeHeader\(name\)\./) + + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).removeHeader(null) + }, /`name` is required for removeHeader\(name\)\./) + }) + it('should follow redirect when no redirect mode is provided', function (done) { const requestUrl = '/301' server.on('request', function (request, response) { From e8abee9ca904abc744db42dba200c808c6630b1e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 23:05:47 +0200 Subject: [PATCH 74/98] Replace C-style casts with static_cast. --- atom/browser/api/atom_api_dialog.cc | 4 ++-- atom/browser/browser_mac.mm | 2 +- atom/browser/native_window_mac.mm | 12 ++++++------ atom/browser/web_contents_permission_helper.cc | 6 +++--- .../native_mate_converters/content_converter.cc | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 326834472d24..c226d3d20218 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -78,11 +78,11 @@ void ShowMessageBox(int type, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, + atom::ShowMessageBox(window, static_cast(type), buttons, default_id, cancel_id, options, title, message, detail, checkbox_label, checkbox_checked, icon, callback); } else { - int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, + int chosen = atom::ShowMessageBox(window, static_cast(type), buttons, default_id, cancel_id, options, title, message, detail, icon); args->Return(chosen); diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 1a15bc013917..51604e377cd6 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -180,7 +180,7 @@ std::string Browser::GetExecutableFileProductName() const { int Browser::DockBounce(BounceType type) { return [[AtomApplication sharedApplication] - requestUserAttention:(NSRequestUserAttentionType)type]; + requestUserAttention:static_cast(type)]; } void Browser::DockCancelBounce(int request_id) { diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 520ba2d6698e..4cec64e1cade 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1358,22 +1358,22 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { // they are available in the minimum SDK version if (type == "selection") { // NSVisualEffectMaterialSelection - vibrancyType = (NSVisualEffectMaterial) 4; + vibrancyType = static_cast( 4); } else if (type == "menu") { // NSVisualEffectMaterialMenu - vibrancyType = (NSVisualEffectMaterial) 5; + vibrancyType = static_cast( 5); } else if (type == "popover") { // NSVisualEffectMaterialPopover - vibrancyType = (NSVisualEffectMaterial) 6; + vibrancyType = static_cast( 6); } else if (type == "sidebar") { // NSVisualEffectMaterialSidebar - vibrancyType = (NSVisualEffectMaterial) 7; + vibrancyType = static_cast( 7); } else if (type == "medium-light") { // NSVisualEffectMaterialMediumLight - vibrancyType = (NSVisualEffectMaterial) 8; + vibrancyType = static_cast( 8); } else if (type == "ultra-dark") { // NSVisualEffectMaterialUltraDark - vibrancyType = (NSVisualEffectMaterial) 9; + vibrancyType = static_cast( 9); } } diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index 2c79270591b8..050e1d6b4a29 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -66,7 +66,7 @@ void WebContentsPermissionHelper::RequestPermission( void WebContentsPermissionHelper::RequestFullscreenPermission( const base::Callback& callback) { - RequestPermission((content::PermissionType)(PermissionType::FULLSCREEN), + RequestPermission(static_cast(PermissionType::FULLSCREEN), callback); } @@ -86,7 +86,7 @@ void WebContentsPermissionHelper::RequestWebNotificationPermission( void WebContentsPermissionHelper::RequestPointerLockPermission( bool user_gesture) { - RequestPermission((content::PermissionType)(PermissionType::POINTER_LOCK), + RequestPermission(static_cast(PermissionType::POINTER_LOCK), base::Bind(&OnPointerLockResponse, web_contents_), user_gesture); } @@ -94,7 +94,7 @@ void WebContentsPermissionHelper::RequestPointerLockPermission( void WebContentsPermissionHelper::RequestOpenExternalPermission( const base::Callback& callback, bool user_gesture) { - RequestPermission((content::PermissionType)(PermissionType::OPEN_EXTERNAL), + RequestPermission(static_cast(PermissionType::OPEN_EXTERNAL), callback, user_gesture); } diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index 72f1011a72c3..444faa697247 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -168,11 +168,11 @@ v8::Local Converter::ToV8( break; } - if (val == (content::PermissionType)(PermissionType::POINTER_LOCK)) + if (val == static_cast(PermissionType::POINTER_LOCK)) return StringToV8(isolate, "pointerLock"); - else if (val == (content::PermissionType)(PermissionType::FULLSCREEN)) + else if (val == static_cast(PermissionType::FULLSCREEN)) return StringToV8(isolate, "fullscreen"); - else if (val == (content::PermissionType)(PermissionType::OPEN_EXTERNAL)) + else if (val == static_cast(PermissionType::OPEN_EXTERNAL)) return StringToV8(isolate, "openExternal"); return StringToV8(isolate, "unknown"); From 328cf4789bc021a4cd1664245cae0619530d13a3 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 23:13:23 +0200 Subject: [PATCH 75/98] Should override the virtual destructor. --- atom/browser/net/atom_cert_verifier.cc | 2 +- atom/browser/web_dialog_helper.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/net/atom_cert_verifier.cc b/atom/browser/net/atom_cert_verifier.cc index 5dee107eb36e..2a2229f19d1f 100644 --- a/atom/browser/net/atom_cert_verifier.cc +++ b/atom/browser/net/atom_cert_verifier.cc @@ -50,7 +50,7 @@ class CertVerifierRequest : public AtomCertVerifier::Request { first_response_(true), weak_ptr_factory_(this) {} - ~CertVerifierRequest() { + ~CertVerifierRequest() override { cert_verifier_->RemoveRequest(params_); default_verifier_request_.reset(); while (!response_list_.empty() && !first_response_) { diff --git a/atom/browser/web_dialog_helper.cc b/atom/browser/web_dialog_helper.cc index 448fccd31f5a..fcd598b1aaea 100644 --- a/atom/browser/web_dialog_helper.cc +++ b/atom/browser/web_dialog_helper.cc @@ -51,7 +51,7 @@ class FileSelectHelper : public base::RefCounted, private: friend class base::RefCounted; - ~FileSelectHelper() {} + ~FileSelectHelper() override {} void OnOpenDialogDone(bool result, const std::vector& paths) { std::vector file_info; From c8951d0d4d419766fb47a12d4c10c971ab9ddc98 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 09:19:21 -0700 Subject: [PATCH 76/98] Upgrade libcc for ffmpeg linking fix --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 94109bdbb231..7a66fd560d60 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - 'dd95b11e52f1e5596184d83d91c91d7b089d05f6' + 'd101a45ee8705e14fa7b5d9691e8268bcfa818b5' PLATFORM = { 'cygwin': 'win32', From 5b4f715d2e6ffc1427205448825e85857f28240b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 15:07:30 -0700 Subject: [PATCH 77/98] Add test page to check for proprietary codecs --- docs/development/upgrading-chrome.md | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/development/upgrading-chrome.md b/docs/development/upgrading-chrome.md index 5cb9337cd09c..fa877faba5ee 100644 --- a/docs/development/upgrading-chrome.md +++ b/docs/development/upgrading-chrome.md @@ -45,6 +45,46 @@ Chrome/Node API changes. - 64-bit Linux - ARM Linux +## Verify ffmpeg builds + +Electron ships with a version of `ffmpeg` that includes proprietary codecs by +default. A version without these codecs is built and distributed with each +release as well. Each Chrome upgrade should verify that switching this version is +still supported. + +You can verify Electron's support for multiple `ffmpeg` builds by loading the +following page. It should work with the default `ffmpeg` library distributed +with Electron and not work with the `ffmpeg` library built without proprietary +codecs. + +```html + + + + + Proprietary Codec Check + + +

Checking if Electron is using proprietary codecs by loading video from http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4

+

+ + + + +``` + ## Links - [Chrome Release Schedule](https://www.chromium.org/developers/calendar) From 740de02d6c80c25009ce2e7e1e8627ef5cb7d419 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 15:08:06 -0700 Subject: [PATCH 78/98] builds -> Support --- docs/development/upgrading-chrome.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development/upgrading-chrome.md b/docs/development/upgrading-chrome.md index fa877faba5ee..6e47a8b4f521 100644 --- a/docs/development/upgrading-chrome.md +++ b/docs/development/upgrading-chrome.md @@ -45,7 +45,7 @@ Chrome/Node API changes. - 64-bit Linux - ARM Linux -## Verify ffmpeg builds +## Verify ffmpeg Support Electron ships with a version of `ffmpeg` that includes proprietary codecs by default. A version without these codecs is built and distributed with each From 6b8f840da05e9cc326770c8c7105f3b5d8ce395b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 16:23:30 -0700 Subject: [PATCH 79/98] Add script to verify ffmpeg without proprietary codecs --- script/cibuild | 1 + script/verify-ffmpeg.py | 75 ++++++++++++++++++++++++++ spec/fixtures/no-proprietary-codecs.js | 36 +++++++++++++ 3 files changed, 112 insertions(+) create mode 100755 script/verify-ffmpeg.py create mode 100644 spec/fixtures/no-proprietary-codecs.js diff --git a/script/cibuild b/script/cibuild index 92dec9db2dee..dc2d9d081045 100755 --- a/script/cibuild +++ b/script/cibuild @@ -91,6 +91,7 @@ def main(): run_script('build.py', ['-c', 'D']) if PLATFORM == 'win32' or target_arch == 'x64': run_script('test.py', ['--ci']) + run_script('verify-ffmpeg.py') def run_script(script, args=[]): diff --git a/script/verify-ffmpeg.py b/script/verify-ffmpeg.py new file mode 100755 index 000000000000..0024552076b7 --- /dev/null +++ b/script/verify-ffmpeg.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python + +import os +import shutil +import subprocess +import sys + +from lib.util import electron_gyp, rm_rf + + +SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) +FFMPEG_LIBCC_PATH = os.path.join(SOURCE_ROOT, 'vendor', 'brightray', 'vendor', + 'download', 'libchromiumcontent', 'ffmpeg') + +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] + + +def main(): + os.chdir(SOURCE_ROOT) + + if len(sys.argv) == 2 and sys.argv[1] == '-R': + config = 'R' + else: + config = 'D' + + app_path = create_app_copy(config) + + if sys.platform == 'darwin': + electron = os.path.join(app_path, 'Contents', 'MacOS', PRODUCT_NAME) + ffmpeg_name = 'libffmpeg.dylib' + ffmpeg_app_path = os.path.join(app_path, 'Contents', 'Frameworks', + '{0} Framework.framework'.format(PROJECT_NAME), + 'Libraries') + elif sys.platform == 'win32': + electron = os.path.join(app_path, '{0}.exe'.format(PROJECT_NAME)) + ffmpeg_app_path = app_path + ffmpeg_name = 'libffmpeg.dll' + else: + electron = os.path.join(app_path, PROJECT_NAME) + ffmpeg_app_path = app_path + ffmpeg_name = 'libffmpeg.so' + + # Copy ffmpeg without proprietary codecs into app + shutil.copy(os.path.join(FFMPEG_LIBCC_PATH, ffmpeg_name), ffmpeg_app_path) + + returncode = 0 + try: + test_path = os.path.join('spec', 'fixtures', 'no-proprietary-codecs.js') + subprocess.check_call([electron, test_path] + sys.argv[1:]) + except subprocess.CalledProcessError as e: + returncode = e.returncode + except KeyboardInterrupt: + returncode = 0 + + return returncode + + +# Create copy of app to install ffmpeg library without proprietary codecs into +def create_app_copy(config): + initial_app_path = os.path.join(SOURCE_ROOT, 'out', config) + app_path = os.path.join(SOURCE_ROOT, 'out', config + '-no-proprietary-codecs') + + if sys.platform == 'darwin': + app_name = '{0}.app'.format(PRODUCT_NAME) + initial_app_path = os.path.join(initial_app_path, app_name) + app_path = os.path.join(app_path, app_name) + + rm_rf(app_path) + shutil.copytree(initial_app_path, app_path, symlinks=True) + return app_path + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js new file mode 100644 index 000000000000..b1450d45b926 --- /dev/null +++ b/spec/fixtures/no-proprietary-codecs.js @@ -0,0 +1,36 @@ +const {app, BrowserWindow, ipcMain} = require('electron') +const path = require('path') +const url = require('url') + +const MEDIA_ERR_SRC_NOT_SUPPORTED = 4 + +let window + +app.once('ready', () => { + window = new BrowserWindow({ + show: false + }) + + window.loadURL(url.format({ + protocol: 'file', + slashed: true, + pathname: path.resolve(__dirname, 'asar', 'video.asar', 'index.html') + })) + + ipcMain.on('asar-video', function (event, message, error) { + if (message === 'ended') { + console.log('Video played, proprietary codecs are included') + app.exit(1) + return + } + + if (message === 'error' && error === MEDIA_ERR_SRC_NOT_SUPPORTED) { + console.log('Video format not supported, proprietary codecs are not included') + app.exit(0) + return + } + + console.log(`Unexpected error: ${error}`) + app.exit(1) + }) +}) From 787313001927ec8f3a0cff490c1fa861612ad100 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 16:30:04 -0700 Subject: [PATCH 80/98] Add comment to codecs app script --- spec/fixtures/no-proprietary-codecs.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index b1450d45b926..b561e14e580f 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -1,3 +1,9 @@ +// Verifies that Electron cannot play a video that uses proprietary codecs +// +// This application should be run with the ffmpeg that does not include +// proprietary codecs to ensure Electron uses it instead of the version +// that does include proprietary codecs. + const {app, BrowserWindow, ipcMain} = require('electron') const path = require('path') const url = require('url') From b85ebb00aaa5ded34c95c83807514972068717c8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 16:38:34 -0700 Subject: [PATCH 81/98] Tweak logged messages --- spec/fixtures/no-proprietary-codecs.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index b561e14e580f..3e0e40933745 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -31,12 +31,11 @@ app.once('ready', () => { } if (message === 'error' && error === MEDIA_ERR_SRC_NOT_SUPPORTED) { - console.log('Video format not supported, proprietary codecs are not included') app.exit(0) return } - console.log(`Unexpected error: ${error}`) + console.log(`Unexpected response from page: ${message} ${error}`) app.exit(1) }) }) From 90d0179fe96773fe819f794c1be72f1a70d058bd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 17:01:25 -0700 Subject: [PATCH 82/98] Use correct dll name --- script/verify-ffmpeg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/verify-ffmpeg.py b/script/verify-ffmpeg.py index 0024552076b7..9d9dba067030 100755 --- a/script/verify-ffmpeg.py +++ b/script/verify-ffmpeg.py @@ -35,7 +35,7 @@ def main(): elif sys.platform == 'win32': electron = os.path.join(app_path, '{0}.exe'.format(PROJECT_NAME)) ffmpeg_app_path = app_path - ffmpeg_name = 'libffmpeg.dll' + ffmpeg_name = 'ffmpeg.dll' else: electron = os.path.join(app_path, PROJECT_NAME) ffmpeg_app_path = app_path From c85d667e663cfa213d7a7d1303511bbef294c617 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 14:37:19 -0700 Subject: [PATCH 83/98] Upgrade libcc to latest master --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 7a66fd560d60..d033d8a41c6a 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - 'd101a45ee8705e14fa7b5d9691e8268bcfa818b5' + '8d551064d2b3d11f89ce8d5c4610f34e0408bad8' PLATFORM = { 'cygwin': 'win32', From 39fdc26921023d9b4bf3ac94de0779556f9786dc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 14:39:48 -0700 Subject: [PATCH 84/98] Time out after 5 minutes --- spec/fixtures/no-proprietary-codecs.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index 3e0e40933745..23a7d815a924 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -9,6 +9,7 @@ const path = require('path') const url = require('url') const MEDIA_ERR_SRC_NOT_SUPPORTED = 4 +const FIVE_MINUTES = 5 * 60 * 1000 let window @@ -23,7 +24,7 @@ app.once('ready', () => { pathname: path.resolve(__dirname, 'asar', 'video.asar', 'index.html') })) - ipcMain.on('asar-video', function (event, message, error) { + ipcMain.on('asar-video', (event, message, error) => { if (message === 'ended') { console.log('Video played, proprietary codecs are included') app.exit(1) @@ -38,4 +39,9 @@ app.once('ready', () => { console.log(`Unexpected response from page: ${message} ${error}`) app.exit(1) }) + + setTimeout(() => { + console.log('No IPC message after 5 minutes') + app.exit(1) + }, FIVE_MINUTES) }) From f0d447cd681c276acc4ab560650770a270b030c0 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 29 Mar 2017 09:16:27 -0300 Subject: [PATCH 85/98] Pass `uploadToServer` to windows crash reporter --- atom/common/crash_reporter/crash_reporter_win.cc | 11 ++++++++--- atom/common/crash_reporter/crash_reporter_win.h | 3 ++- atom/common/crash_reporter/win/crash_service.cc | 2 +- docs/api/crash-reporter.md | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index 25969dc32eb3..b13108dbfec5 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -179,7 +179,7 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name, google_breakpad::ExceptionHandler::HANDLER_ALL, kSmallDumpType, pipe_name.c_str(), - GetCustomInfo(product_name, version, company_name))); + GetCustomInfo(product_name, version, company_name, upload_to_server))); if (!breakpad_->IsOutOfProcess()) LOG(ERROR) << "Cannot initialize out-of-process crash handler"; @@ -238,14 +238,19 @@ bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path, google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( const std::string& product_name, const std::string& version, - const std::string& company_name) { + const std::string& company_name, + bool upload_to_server) { custom_info_entries_.clear(); - custom_info_entries_.reserve(2 + upload_parameters_.size()); + custom_info_entries_.reserve(3 + upload_parameters_.size()); custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( L"prod", L"Electron")); custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( L"ver", base::UTF8ToWide(version).c_str())); + if (!upload_to_server) { + custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( + L"skip_upload", L"1")); + } for (StringMap::const_iterator iter = upload_parameters_.begin(); iter != upload_parameters_.end(); ++iter) { diff --git a/atom/common/crash_reporter/crash_reporter_win.h b/atom/common/crash_reporter/crash_reporter_win.h index 3fc139aca190..5070df206006 100644 --- a/atom/common/crash_reporter/crash_reporter_win.h +++ b/atom/common/crash_reporter/crash_reporter_win.h @@ -56,7 +56,8 @@ class CrashReporterWin : public CrashReporter { google_breakpad::CustomClientInfo* GetCustomInfo( const std::string& product_name, const std::string& version, - const std::string& company_name); + const std::string& company_name, + bool upload_to_server); // Custom information to be passed to crash handler. std::vector custom_info_entries_; diff --git a/atom/common/crash_reporter/win/crash_service.cc b/atom/common/crash_reporter/win/crash_service.cc index 5782fd72a3fb..a306a567a711 100644 --- a/atom/common/crash_reporter/win/crash_service.cc +++ b/atom/common/crash_reporter/win/crash_service.cc @@ -391,7 +391,7 @@ void CrashService::OnClientDumpRequest(void* context, LOG(ERROR) << "could not write custom info file"; } - if (!self->sender_) + if (!self->sender_ || map.find(L"skip_upload") != map.end()) return; // Send the crash dump using a worker thread. This operation has retry diff --git a/docs/api/crash-reporter.md b/docs/api/crash-reporter.md index 98bf0f3662f2..2f0848c1193e 100644 --- a/docs/api/crash-reporter.md +++ b/docs/api/crash-reporter.md @@ -40,7 +40,7 @@ The `crashReporter` module has the following methods: * `companyName` String (optional) * `submitURL` String - URL that crash reports will be sent to as POST. * `productName` String (optional) - Defaults to `app.getName()`. - * `uploadToServer` Boolean (optional) _Linux_ _macOS_ - Whether crash reports should be sent to the server + * `uploadToServer` Boolean (optional) - Whether crash reports should be sent to the server Default is `true`. * `ignoreSystemCrashHandler` Boolean (optional) - Default is `false`. * `extra` Object (optional) - An object you can define that will be sent along with the From 460fb9cdb93a160a8e3ebf8d3351ad87551a4906 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 30 Mar 2017 11:11:49 -0300 Subject: [PATCH 86/98] Add tests for `uploadToServer` option. --- spec/api-crash-reporter-spec.js | 89 +++++++++++++++++++++++++++++++++ spec/fixtures/api/crash.html | 12 +++-- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index dc4b98150160..555445ee7813 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -1,5 +1,6 @@ const assert = require('assert') const childProcess = require('child_process') +const fs = require('fs') const http = require('http') const multiparty = require('multiparty') const path = require('path') @@ -73,6 +74,93 @@ describe('crashReporter module', function () { }) }) + it('should not send minidump if uploadToServer is false', function (done) { + this.timeout(120000) + + if (process.platform === 'darwin') { + crashReporter.setUploadToServer(false) + } + + let server + let dumpFile + let crashesDir + const testDone = (uploaded) => { + if (uploaded) { + return done(new Error('fail')) + } + server.close() + if (process.platform === 'darwin') { + crashReporter.setUploadToServer(true) + } + assert(fs.existsSync(dumpFile)) + fs.unlinkSync(dumpFile) + done() + } + + let pollInterval + const pollDumpFile = () => { + fs.readdir(crashesDir, (err, files) => { + if (err) { + return + } + let dumps = files.filter((f) => /\.dmp$/.test(f)) + if (!dumps.length) { + return + } + assert.equal(1, dumps.length) + dumpFile = path.join(crashesDir, dumps[0]) + clearInterval(pollInterval) + // dump file should not be deleted when not uploading, so we wait + // 500 ms and assert it still exists in `testDone` + setTimeout(testDone, 500) + }) + } + + remote.ipcMain.once('set-crash-directory', (event, dir) => { + if (process.platform === 'linux') { + crashesDir = dir + } else { + crashesDir = crashReporter.getCrashesDirectory() + if (process.platform === 'darwin') { + // crashpad uses an extra subdirectory + crashesDir = path.join(crashesDir, 'completed') + } + } + + // Before starting, remove all dump files in the crash directory. + // This is required because: + // - mac crashpad not seem to allow changing the crash directory after + // the first "start" call. + // - Other tests in this suite may leave dumps there. + // - We want to verify in `testDone` that a dump file is created and + // not deleted. + fs.readdir(crashesDir, (err, files) => { + if (!err) { + for (let file of files) { + if (/\.dmp$/.test(file)) { + fs.unlinkSync(path.join(crashesDir, file)) + } + } + } + event.returnValue = null // allow the renderer to crash + pollInterval = setInterval(pollDumpFile, 100) + }) + }) + + server = startServer({ + callback (port) { + const crashUrl = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash.html'), + search: `?port=${port}&skipUpload=1` + }) + w.loadURL(crashUrl) + }, + processType: 'renderer', + done: testDone.bind(null, true) + }) + }) + it('should send minidump with updated extra parameters', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() @@ -215,4 +303,5 @@ const startServer = ({callback, processType, done}) => { } callback(port) }) + return server } diff --git a/spec/fixtures/api/crash.html b/spec/fixtures/api/crash.html index 2b1cea6e9af3..6f013a2c7ba5 100644 --- a/spec/fixtures/api/crash.html +++ b/spec/fixtures/api/crash.html @@ -1,20 +1,24 @@ From d677a436ec91eec708e78bfcb1e1d96827dfc6fa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 10:42:43 -0700 Subject: [PATCH 87/98] :art: --- atom/common/crash_reporter/crash_reporter_win.cc | 2 +- spec/api-crash-reporter-spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index b13108dbfec5..a7908ef30c6b 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -249,7 +249,7 @@ google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( L"ver", base::UTF8ToWide(version).c_str())); if (!upload_to_server) { custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( - L"skip_upload", L"1")); + L"skip_upload", L"1")); } for (StringMap::const_iterator iter = upload_parameters_.begin(); diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 555445ee7813..8a51b5ef2db1 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -103,7 +103,7 @@ describe('crashReporter module', function () { if (err) { return } - let dumps = files.filter((f) => /\.dmp$/.test(f)) + const dumps = files.filter((file) => /\.dmp$/.test(file)) if (!dumps.length) { return } @@ -136,7 +136,7 @@ describe('crashReporter module', function () { // not deleted. fs.readdir(crashesDir, (err, files) => { if (!err) { - for (let file of files) { + for (const file of files) { if (/\.dmp$/.test(file)) { fs.unlinkSync(path.join(crashesDir, file)) } From 8ae91682cbb0a2e727db9e21a361e0dc68db7c7e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 31 Mar 2017 20:09:13 +0200 Subject: [PATCH 88/98] Lines should be <= 80 characters. --- atom/browser/api/atom_api_dialog.cc | 13 +++++++------ atom/browser/web_contents_permission_helper.cc | 17 +++++++++-------- .../native_mate_converters/content_converter.cc | 6 ++++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index c226d3d20218..cc849e026ea1 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -78,13 +78,14 @@ void ShowMessageBox(int type, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - atom::ShowMessageBox(window, static_cast(type), buttons, - default_id, cancel_id, options, title, message, detail, - checkbox_label, checkbox_checked, icon, callback); + atom::ShowMessageBox(window, static_cast(type), + buttons, default_id, cancel_id, options, title, + message, detail, checkbox_label, checkbox_checked, + icon, callback); } else { - int chosen = atom::ShowMessageBox(window, static_cast(type), - buttons, default_id, cancel_id, - options, title, message, detail, icon); + int chosen = atom::ShowMessageBox( + window, static_cast(type), buttons, default_id, + cancel_id, options, title, message, detail, icon); args->Return(chosen); } } diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index 050e1d6b4a29..ec9e4ad6e941 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -66,8 +66,9 @@ void WebContentsPermissionHelper::RequestPermission( void WebContentsPermissionHelper::RequestFullscreenPermission( const base::Callback& callback) { - RequestPermission(static_cast(PermissionType::FULLSCREEN), - callback); + RequestPermission( + static_cast(PermissionType::FULLSCREEN), + callback); } void WebContentsPermissionHelper::RequestMediaAccessPermission( @@ -86,17 +87,17 @@ void WebContentsPermissionHelper::RequestWebNotificationPermission( void WebContentsPermissionHelper::RequestPointerLockPermission( bool user_gesture) { - RequestPermission(static_cast(PermissionType::POINTER_LOCK), - base::Bind(&OnPointerLockResponse, web_contents_), - user_gesture); + RequestPermission( + static_cast(PermissionType::POINTER_LOCK), + base::Bind(&OnPointerLockResponse, web_contents_), user_gesture); } void WebContentsPermissionHelper::RequestOpenExternalPermission( const base::Callback& callback, bool user_gesture) { - RequestPermission(static_cast(PermissionType::OPEN_EXTERNAL), - callback, - user_gesture); + RequestPermission( + static_cast(PermissionType::OPEN_EXTERNAL), + callback, user_gesture); } } // namespace atom diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index 444faa697247..7869e37deeea 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -170,9 +170,11 @@ v8::Local Converter::ToV8( if (val == static_cast(PermissionType::POINTER_LOCK)) return StringToV8(isolate, "pointerLock"); - else if (val == static_cast(PermissionType::FULLSCREEN)) + else if (val == + static_cast(PermissionType::FULLSCREEN)) return StringToV8(isolate, "fullscreen"); - else if (val == static_cast(PermissionType::OPEN_EXTERNAL)) + else if (val == + static_cast(PermissionType::OPEN_EXTERNAL)) return StringToV8(isolate, "openExternal"); return StringToV8(isolate, "unknown"); From 08db63c3cc6a0079b004ca81deb636c85bff947e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 10:20:02 -0700 Subject: [PATCH 89/98] Only define NSWindowTabbingModeDisallowed on pre-10.12 --- atom/browser/native_window_mac.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 2912022bd634..10b6e3e311cf 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -336,14 +336,19 @@ bool ScopedDisableResize::disable_resize_ = false; @end +#if !defined(MAC_OS_X_VERSION_10_12) + enum { NSWindowTabbingModeDisallowed = 2 }; + @interface NSWindow (SierraSDK) - (void)setTabbingMode:(NSInteger)mode; -- (void)setTabbingIdentifier:(NSString *)identifier; +- (void)setTabbingIdentifier:(NSString*)identifier; @end +#endif // MAC_OS_X_VERSION_10_12 + @interface AtomNSWindow : EventDispatchingWindow { @private atom::NativeWindowMac* shell_; From a724b6555fdbcc4c135e67129332e580dc49684d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 09:39:43 -0700 Subject: [PATCH 90/98] Bump v1.6.5 --- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- electron.gyp | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 091614ffd428..6fc30bf6a3b3 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 1.6.4 + 1.6.5 CFBundleShortVersionString - 1.6.4 + 1.6.5 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 5a2d8ea32ece..34879fe41ec9 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 1,6,4,0 - PRODUCTVERSION 1,6,4,0 + FILEVERSION 1,6,5,0 + PRODUCTVERSION 1,6,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "1.6.4" + VALUE "FileVersion", "1.6.5" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.6.4" + VALUE "ProductVersion", "1.6.5" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 73528b45eaae..1054a3dc9f1e 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 1 #define ATOM_MINOR_VERSION 6 -#define ATOM_PATCH_VERSION 4 +#define ATOM_PATCH_VERSION 5 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/electron.gyp b/electron.gyp index 78eed743cc36..3dec2ee8a072 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '1.6.4', + 'version%': '1.6.5', 'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c', }, 'includes': [ diff --git a/package.json b/package.json index d321d7831f05..015be4a12e09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "1.6.4", + "version": "1.6.5", "devDependencies": { "asar": "^0.11.0", "browserify": "^13.1.0", From 6d516fbae3c61b9bda188de3d77428d0123acbe2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 15:08:03 -0700 Subject: [PATCH 91/98] Move normalizeAccessKeys docs to right method --- docs/api/dialog.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 230930abd948..8885c315144b 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -46,16 +46,8 @@ The `dialog` module has the following methods: * `noResolveAliases` - Disable the automatic alias (symlink) path resolution. Selected aliases will now return the alias path instead of their target path. _macOS_ - * `normalizeAccessKeys` Boolean (optional) - Normalize the keyboard access keys - across platforms. Default is `false`. Enabling this assumes `&` is used in - the button labels for the placement of the keyboard shortcut access key - and labels will be converted so they work correctly on each platform, `&` - characters are removed on macOS, converted to `_` on Linux, and left - untouched on Windows. For example, a button label of `Vie&w` will be - converted to `Vie_w` on Linux and `View` on macOS and can be selected - via `Alt-W` on Windows and Linux. - * `message` String (optional) _macOS_ - Message to display above input - boxes. + * `message` String (optional) _macOS_ - Message to display above input + boxes. * `callback` Function (optional) * `filePaths` String[] - An array of file paths chosen by the user @@ -147,6 +139,14 @@ will be passed via `callback(filename)` others as command links in the dialog. This can make the dialog appear in the style of modern Windows apps. If you don't like this behavior, you can set `noLink` to `true`. + * `normalizeAccessKeys` Boolean (optional) - Normalize the keyboard access keys + across platforms. Default is `false`. Enabling this assumes `&` is used in + the button labels for the placement of the keyboard shortcut access key + and labels will be converted so they work correctly on each platform, `&` + characters are removed on macOS, converted to `_` on Linux, and left + untouched on Windows. For example, a button label of `Vie&w` will be + converted to `Vie_w` on Linux and `View` on macOS and can be selected + via `Alt-W` on Windows and Linux. * `callback` Function (optional) * `response` Number - The index of the button that was clicked * `checkboxChecked` Boolean - The checked state of the checkbox if From f757912f902e09df340ed48ed1ff60a7cc8dff58 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 1 Apr 2017 12:11:34 +1100 Subject: [PATCH 92/98] Add missing finalUpdate prop --- docs/api/web-contents.md | 1 + docs/api/webview-tag.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 72dc4b0f7454..87530234a282 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -336,6 +336,7 @@ Returns: * `activeMatchOrdinal` Integer - Position of the active match. * `matches` Integer - Number of Matches. * `selectionArea` Object - Coordinates of first match region. + * `finalUpdate` Boolean Emitted when a result is available for [`webContents.findInPage`] request. diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 5efc225a1d65..9c09c8ef730e 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -749,6 +749,7 @@ Returns: * `activeMatchOrdinal` Integer - Position of the active match. * `matches` Integer - Number of Matches. * `selectionArea` Object - Coordinates of first match region. + * `finalUpdate` Boolean Fired when a result is available for [`webview.findInPage`](webview-tag.md#webviewtagfindinpage) request. From f09e3f38355532a7cfb4a477de9231677986127c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 1 Apr 2017 15:09:53 +0200 Subject: [PATCH 93/98] Remove extra blank. --- atom/common/platform_util_mac.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index 9cbbaedbe181..7259b3b13031 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -73,10 +73,10 @@ std::string MessageForOSStatus(OSStatus status, const char* default_message) { // NSWorkspace#openURLs. std::string OpenURL(NSURL* ns_url, bool activate) { CFURLRef openingApp = nullptr; - OSStatus status = LSGetApplicationForURL(base::mac::NSToCFCast(ns_url), - kLSRolesAll, - nullptr, - &openingApp); + OSStatus status = LSGetApplicationForURL(base::mac::NSToCFCast(ns_url), + kLSRolesAll, + nullptr, + &openingApp); if (status != noErr) return MessageForOSStatus(status, "Failed to open"); From 671bcf2161b37faa22b5f04b88cf3374dcbb52ce Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Sun, 2 Apr 2017 00:41:36 +0800 Subject: [PATCH 94/98] Update web-contents.md --- docs-translations/zh-CN/api/web-contents.md | 820 +++++++++++++------- 1 file changed, 558 insertions(+), 262 deletions(-) diff --git a/docs-translations/zh-CN/api/web-contents.md b/docs-translations/zh-CN/api/web-contents.md index b13628533ee1..dd5c926126c2 100644 --- a/docs-translations/zh-CN/api/web-contents.md +++ b/docs-translations/zh-CN/api/web-contents.md @@ -48,15 +48,14 @@ console.log(webContents) 可使用的进程: [主进程](../tutorial/quick-start.md#main-process) -## 事件 +### 实例事件 -`webContents` 对象可发出下列事件: -### Event: 'did-finish-load' +#### Event: 'did-finish-load' -当导航完成时发出事件,`onload` 事件也完成。 +当导航完成时,发出 `onload` 事件。 -### Event: 'did-fail-load' +#### Event: 'did-fail-load' 返回: @@ -66,9 +65,9 @@ console.log(webContents) * `validatedURL` String * `isMainFrame` Boolean -这个事件类似 `did-finish-load` ,但是是在加载失败或取消加载时发出, 例如, `window.stop()` 请求结束。错误代码的完整列表和它们的含义都可以在 [这里](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) 找到。 +这个事件类似 `did-finish-load` ,但是是在加载失败或取消加载时发出, 例如, `window.stop()` 被调用时。错误代码的完整列表和它们的含义都可以在 [这里](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) 找到。 -### Event: 'did-frame-finish-load' +#### Event: 'did-frame-finish-load' 返回: @@ -77,15 +76,15 @@ console.log(webContents) 当一个 frame 导航完成的时候发出事件。 -### Event: 'did-start-loading' +#### Event: 'did-start-loading' 当 tab 的spinner 开始 spinning的时候。 -### Event: 'did-stop-loading' +#### Event: 'did-stop-loading' 当 tab 的spinner 结束 spinning的时候。 -### Event: 'did-get-response-details' +#### Event: 'did-get-response-details' 返回: @@ -102,7 +101,7 @@ console.log(webContents) 当有关请求资源的详细信息可用的时候发出事件。 `status` 标识了 socket 链接来下载资源。 -### Event: 'did-get-redirect-request' +#### Event: 'did-get-redirect-request' 返回: @@ -117,7 +116,7 @@ console.log(webContents) 当在请求资源时收到重定向的时候发出事件。 -### Event: 'dom-ready' +#### Event: 'dom-ready' 返回: @@ -125,7 +124,7 @@ console.log(webContents) 当指定 frame 中的 文档加载完成的时候发出事件。 -### Event: 'page-favicon-updated' +#### Event: 'page-favicon-updated' 返回: @@ -134,15 +133,15 @@ console.log(webContents) 当 page 收到图标 url 的时候发出事件。 -### Event: 'new-window' +#### Event: 'new-window' 返回: * `event` Event * `url` String * `frameName` String -* `disposition` String - 可为 `default`、 `foreground-tab`、 `background-tab`、 - `new-window` 和 `other`。 +* `disposition` String - 可为 `default`, `foreground-tab`, `background-tab`, + `new-window`, `save-to-disk` 和 `other` * `options` Object - 创建新的 `BrowserWindow`时使用的参数。 * `additionalFeatures` String[] - 非标准功能(功能未处理    由 Chromium 或 Electron )赋予 `window.open()`。 @@ -168,7 +167,7 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { }) ``` -### Event: 'will-navigate' +#### Event: 'will-navigate' 返回: @@ -183,7 +182,7 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { 调用 `event.preventDefault()` 可以阻止导航。 -### Event: 'did-navigate' +#### Event: 'did-navigate' 返回: @@ -194,22 +193,28 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { 页内跳转时不会发出这个事件,例如点击锚链接或更新 `window.location.hash`。使用 `did-navigate-in-page` 事件可以达到目的。 -### Event: 'did-navigate-in-page' +#### Event: 'did-navigate-in-page' 返回: * `event` Event * `url` String +* `isMainFrame ` Boolean 当页内导航发生的时候发出事件。 当页内导航发生的时候,page 的url 改变,但是不会跳出界面。例如当点击锚链接时或者 DOM 的 `hashchange` 事件发生。 -### Event: 'crashed' +#### Event: 'crashed' + +返回: + +* `event` Event +* `killed` Boolean 当渲染进程崩溃的时候发出事件。 -### Event: 'plugin-crashed' +#### Event: 'plugin-crashed' 返回: @@ -219,54 +224,70 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { 当插件进程崩溃时候发出事件。 -### Event: 'destroyed' +#### Event: 'destroyed' 当 `webContents` 被删除的时候发出事件。 -### Event: 'devtools-opened' +#### Event: 'before-input-event' + +返回: + +* `event` Event +* `input` Object - 属性 + * `type` String - `keyUp` 或者 `keyDown` + * `key` String - [KeyboardEvent.key][keyboardevent] + * `code` String - [KeyboardEvent.code][keyboardevent] + * `isAutoRepeat` Boolean - [KeyboardEvent.repeat][keyboardevent] + * `shift` Boolean - [KeyboardEvent.shiftKey][keyboardevent] + * `control` Boolean - [KeyboardEvent.controlKey][keyboardevent] + * `alt` Boolean - [KeyboardEvent.altKey][keyboardevent] + * `meta` Boolean - [KeyboardEvent.metaKey][keyboardevent] + +在 `keydown` 和 `keyup` 事件触发前发送。调用 `event.preventDefault` 方法可以阻止页面的 `keydown/keyup` 事件。 + +#### Event: 'devtools-opened' 当开发者工具栏打开的时候发出事件。 -### Event: 'devtools-closed' +#### Event: 'devtools-closed' 当开发者工具栏关闭时候发出事件。 -### Event: 'devtools-focused' +#### Event: 'devtools-focused' 当开发者工具栏获得焦点或打开的时候发出事件。 -### Event: 'certificate-error' +#### Event: 'certificate-error' 返回: * `event` Event * `url` URL * `error` String - The error code -* `certificate` Object - * `data` Buffer - PEM encoded data - * `issuerName` String +* `certificate` [Certificate](structures/certificate.md) * `callback` Function + * `isTrusted ` Boolean - 表明证书是否可以被认为是可信的 -当验证证书或 `url` 失败的时候发出事件。 +当验证 `certificate` 或 `url` 失败的时候发出事件。 使用方法类似 [`app` 的 `certificate-error` 事件](app.md#event-certificate-error)。 -### Event: 'select-client-certificate' + +#### Event: 'select-client-certificate' 返回: * `event` Event * `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM encoded data - * `issuerName` String - Issuer's Common Name +* `certificateList` [Certificate[]](structures/certificate.md) * `callback` Function + * `certificate` [Certificate](structures/certificate.md) - 证书必须来自于指定的列表 当请求客户端证书的时候发出事件。 使用方法类似 [`app` 的 `select-client-certificate` 事件](app.md#event-select-client-certificate)。 -### Event: 'login' +#### Event: 'login' 返回: @@ -282,34 +303,37 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { * `port` Integer * `realm` String * `callback` Function + * `username` String + * `password` String 当 `webContents` 想做基本验证的时候发出事件. 使用方法类似 [the `login` event of `app`](app.md#event-login)。 -### Event: 'found-in-page' +#### Event: 'found-in-page' 返回: * `event` Event * `result` Object * `requestId` Integer - * `finalUpdate` Boolean - 标识是否还有更多的值可以查看。 - * `activeMatchOrdinal` Integer (可选) - 活动匹配位置。 - * `matches` Integer (可选) - 匹配数量。 - * `selectionArea` Object (可选) - 协调首个匹配位置。 + * `activeMatchOrdinal` Integer - 活动匹配位置。 + * `matches` Integer - 匹配数量。 + * `selectionArea` Object - 协调首个匹配位置。 + * `finalUpdate` Boolean + 当使用 [`webContents.findInPage`] 进行页内查找并且找到可用值得时候发出事件。 -### Event: 'media-started-playing' +#### Event: 'media-started-playing' 当媒体开始播放的时候发出事件。 -### Event: 'media-paused' +#### Event: 'media-paused' 当媒体停止播放的时候发出事件。 -### Event: 'did-change-theme-color' +#### Event: 'did-change-theme-color' 当page 的主题色时候发出事件。这通常由于引入了一个 meta 标签: @@ -317,14 +341,29 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { ``` -### Event: 'cursor-changed' +#### Event: 'update-target-url' + +返回: + +* `event` Event +* `url` String + +当鼠标移到一个链接上或键盘焦点移动到一个链接上时发送。 + +#### Event: 'cursor-changed' 返回: * `event` Event * `type` String * `image` NativeImage (可选) -* `scale` Float (可选) +* `scale` Float (可选) 自定义光标的比例 +* `size` Object (可选) - `image`的大小 + * `width` Integer + * `height` Integer +* `hotspot` Object (可选) - 自定义光标热点的坐标 + * `x` Integer - x 坐标 + * `y` Integer - y 坐标 当鼠标的类型发生改变的时候发出事件. `type` 的参数可以是 `default`, `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, @@ -333,221 +372,428 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { `row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, `s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, `cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, -`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing`, `custom`。 +`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing`, `custom`. -如果 `type` 参数值为 `custom`、 `image` 参数会在一个`NativeImage` 中控制自定义鼠标图片,并且 `scale` 会控制图片的缩放比例。 +如果 `type` 参数值为 `custom`、 `image` 参数会在一个`NativeImage` 中控制自定义鼠标图片,并且 `scale` 、`size` 和 `hotspot`会控制自定义光标的属性。 -## 实例方法 +#### Event: 'context-menu' -`webContents` 对象有如下的实例方法: +Returns: -### `webContents.loadURL(url[, options])` +* `event` Event +* `params` Object + * `x` Integer - x 坐标 + * `y` Integer - y 坐标 + * `linkURL` String - 菜单中调用的节点的 URL 链接. + * `linkText` String - 链接的文本。当链接是一个图像时文本可以为空. + * `pageURL` String - 菜单被调用时顶级页面的 URL 链接. + * `frameURL` String - 菜单被调用时子级页面的 URL 链接. + * `srcURL` String - 菜单被调用时元素的原始链接。带有链接的元素可以为图像、音频和视频。 + * `mediaType` String - 菜单被调用时的节点类型。可以为 `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. + * `hasImageContents` Boolean - 菜单中是否含有图像. + * `isEditable` Boolean - 菜单是否可以被编辑. + * `selectionText` String - Text of the selection that the context menu was + invoked on. + * `titleText` String - Title or alt text of the selection that the context + 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. + * `inputFieldType` String - If the context menu was invoked on an input + 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`. + * `mediaFlags` Object - The flags for the media element the context menu was + invoked on. + * `inError` Boolean - Whether the media element has crashed. + * `isPaused` Boolean - Whether the media element is paused. + * `isMuted` Boolean - Whether the media element is muted. + * `hasAudio` Boolean - Whether the media element has audio. + * `isLooping` Boolean - Whether the media element is looping. + * `isControlsVisible` Boolean - Whether the media element's controls are + visible. + * `canToggleControls` Boolean - Whether the media element's controls are + toggleable. + * `canRotate` Boolean - Whether the media element can be rotated. + * `editFlags` Object - These flags indicate whether the renderer believes it + is able to perform the corresponding action. + * `canUndo` Boolean - Whether the renderer believes it can undo. + * `canRedo` Boolean - Whether the renderer believes it can redo. + * `canCut` Boolean - Whether the renderer believes it can cut. + * `canCopy` Boolean - Whether the renderer believes it can copy + * `canPaste` Boolean - Whether the renderer believes it can paste. + * `canDelete` Boolean - Whether the renderer believes it can delete. + * `canSelectAll` Boolean - Whether 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` [BluetoothDevice[]](structures/bluetooth-device.md) +* `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. + +```javascript +const {app, webContents} = require('electron') +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) + } + }) +}) +``` + +#### Event: 'paint' + +Returns: + +* `event` Event +* `dirtyRect` [Rectangle](structures/rectangle.md) +* `image` [NativeImage](native-image.md) - The image data of the whole frame. + +Emitted when a new frame is generated. Only the dirty area is passed in the +buffer. + +```javascript +const {BrowserWindow} = require('electron') + +let win = new BrowserWindow({webPreferences: {offscreen: true}}) +win.webContents.on('paint', (event, dirty, image) => { + // updateBitmap(dirty, image.getBitmap()) +}) +win.loadURL('http://github.com') +``` + +#### Event: 'devtools-reload-page' +当 devtools 调试工具页面重新加载时发送 + +#### Event: 'will-attach-webview' + +Returns: + +* `event` Event +* `webPreferences` Object - The web preferences that will be used by the guest + page. This object can be modified to adjust the preferences for the guest + page. +* `params` Object - The other `` parameters such as the `src` URL. + This object can be modified to adjust the parameters of the guest page. + +Emitted when a ``'s web contents is being attached to this web +contents. Calling `event.preventDefault()` will destroy the guest page. + +This event can be used to configure `webPreferences` for the `webContents` +of a `` before it's loaded, and provides the ability to set settings +that can't be set via `` attributes. +### 实例方法 + + +#### `contents.loadURL(url[, options])` * `url` URL * `options` Object (可选) - * `httpReferrer` String - A HTTP Referrer url. + * `httpReferrer` String - HTTP 的 url 链接. * `userAgent` String - 产生请求的用户代理 * `extraHeaders` String - 以 "\n" 分隔的额外头 + * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md) | [UploadFileSystem](structures/upload-file-system.md) | [UploadBlob](structures/upload-blob.md))[] - (optional) + * `baseURLForDataURL` String (optional) - 由数据URL加载的文件的基本URL(带尾随路径分隔符)。只有当指定的URL是一个数据URL并且需要加载其他文件时才需要设置。 -在窗口中加载 `url` 、 `url` 必须包含协议前缀, +在窗口中加载 `url`。 `url` 必须包含协议前缀, 比如 `http://` 或 `file://`。如果加载想要忽略 http 缓存,可以使用 `pragma` 头来达到目的。 ```javascript -const options = {'extraHeaders': 'pragma: no-cache\n'} -webContents.loadURL(url, options) +const {webContents} = require('electron') +const options = {extraHeaders: 'pragma: no-cache\n'} +webContents.loadURL('https://github.com', options) ``` -### `webContents.downloadURL(url)` +#### `contents.downloadURL(url)` * `url` URL 初始化一个指定 `url` 的资源下载,不导航跳转。 `session` 的 `will-download` 事件会触发。 -### `webContents.getURL()` +#### `contents.getURL()` -返回当前 page 的 url。 +Returns `String` - 当前页面的 URL. ```javascript -var win = new BrowserWindow({width: 800, height: 600}) +const {BrowserWindow} = require('electron') +let win = new BrowserWindow({width: 800, height: 600}) win.loadURL('http://github.com') -var currentURL = win.webContents.getURL() +let currentURL = win.webContents.getURL() +console.log(currentURL) ``` -### `webContents.getTitle()` +#### `contents.getTitle()` -返回当前 page 的标题。 +Returns `String` - 当前页面的标题. -### `webContents.isLoading()` +#### `contents.isDestroyed()` -返回一个布尔值,标识当前页是否正在加载。 +Returns `Boolean` - 当前的页面是否被销毁了 -### `webContents.isWaitingForResponse()` +#### `contents.isFocused()` -返回一个布尔值,标识当前页是否正在等待主要资源的第一次响应。 +Returns `Boolean` - 焦点是否在当前页面上. -### `webContents.stop()` +#### `contents.isLoading()` + +Returns `Boolean` - 当前页是否正在加载资源。 + +#### `contents.isLoadingMainFrame()` + +Returns `Boolean` - 是否主框架(而不仅是 iframe 或者在帧内)仍在加载中。 + +#### `contents.isWaitingForResponse()` + +Returns `Boolean` - 当前页是否正在等待主要资源的第一次响应。 + +#### `contents.stop()` 停止还为开始的导航。 -### `webContents.reload()` +#### `contents.reload()` 重载当前页。 -### `webContents.reloadIgnoringCache()` +#### `contents.reloadIgnoringCache()` 重载当前页,忽略缓存。 -### `webContents.canGoBack()` +#### `contents.canGoBack()` -返回一个布尔值,标识浏览器是否能回到前一个page。 +Returns `Boolean` - 浏览器是否能回到前一个页面。 -### `webContents.canGoForward()` +#### `contents.canGoForward()` -返回一个布尔值,标识浏览器是否能前往下一个page。 +Returns `Boolean` - 浏览器是否能前往下一个页面。 -### `webContents.canGoToOffset(offset)` +#### `contents.canGoToOffset(offset)` * `offset` Integer -返回一个布尔值,标识浏览器是否能前往指定 `offset` 的page。 +Returns `Boolean` - 页面是否能前往 `offset`。 -### `webContents.clearHistory()` +#### `contents.clearHistory()` 清除导航历史。 -### `webContents.goBack()` +#### `contents.goBack()` -让浏览器回退到前一个page。 +让浏览器回退到前一个页面。 -### `webContents.goForward()` +#### `contents.goForward()` -让浏览器回前往下一个page。 +让浏览器回前往下一个页面。 -### `webContents.goToIndex(index)` +#### `contents.goToIndex(index)` * `index` Integer -让浏览器回前往指定 `index` 的page。 +让浏览器回前往指定 `index` 的页面。 -### `webContents.goToOffset(offset)` +#### `contents.goToOffset(offset)` * `offset` Integer 导航到相对于当前页的偏移位置页。 -### `webContents.isCrashed()` +#### `contents.isCrashed()` -渲染进程是否崩溃。 +Returns `Boolean` - 渲染进程是否崩溃。 -### `webContents.setUserAgent(userAgent)` +#### `contents.setUserAgent(userAgent)` * `userAgent` String 重写本页用户代理。 -### `webContents.getUserAgent()` +#### `contents.getUserAgent()` -返回一个 `String` ,标识本页用户代理信息。 +Returns `String` - 页面的用户代理信息。 -### `webContents.insertCSS(css)` +#### `contents.insertCSS(css)` * `css` String 为当前页插入css。 -### `webContents.executeJavaScript(code[, userGesture, callback])` +#### `contents.executeJavaScript(code[, userGesture, callback])` * `code` String -* `userGesture` Boolean (可选) +* `userGesture` Boolean (可选) - 默认值为 `false` * `callback` Function (可选) - 脚本执行完成后调用的回调函数. - * `result` + * `result` Any -评估 page `代码`。 +Returns `Promise` - 成功了返回 resolves,失败了返回 rejected + +评估页面的 `code` 代码。 浏览器窗口中的一些 HTML API ,例如 `requestFullScreen`,只能被用户手势请求。设置 `userGesture` 为 `true` 可以取消这个限制。 -### `webContents.setAudioMuted(muted)` +如果执行的代码的结果是一个 promise,回调方法将为 promise 的 resolved 的值。我们建议您使用返回的 Promise 来处理导致结果的代码。 + +```js +contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true) + .then((result) => { + console.log(result) // Will be the JSON object from the fetch call + }) +``` +#### `contents.setAudioMuted(muted)` * `muted` Boolean -减缓当前页的 audio 的播放速度。 +设置当前页为静音。 -### `webContents.isAudioMuted()` +#### `contents.isAudioMuted()` -返回一个布尔值,标识当前页是否减缓了 audio 的播放速度。 +Returns `Boolean` - 当前页是否为静音状态 -### `webContents.undo()` +#### `contents.setZoomFactor(factor)` -执行网页的编辑命令 `undo`。 +* `factor` Number - 缩放系数 -### `webContents.redo()` +改变缩放系数为指定的数值。缩放系数是缩放的百分比除以100,比如 300% = 3.0 -执行网页的编辑命令 `redo`。 +#### `contents.getZoomFactor(callback)` -### `webContents.cut()` +* `callback` Function + * `zoomFactor` Number -执行网页的编辑命令 `cut`。 +发送一个请求来获取当前的缩放系数,`callback` 回调方法会在 `callback(zoomFactor)` 中调用. -### `webContents.copy()` +#### `contents.setZoomLevel(level)` -执行网页的编辑命令 `copy`。 +* `level` Number - 缩放等级 -### `webContents.paste()` +改变缩放等级为指定的等级。原始大小为0,每升高或降低一次,代表 20% 的大小缩放。限制为原始大小的 300% 到 50%。 -执行网页的编辑命令 `paste`。 +#### `contents.getZoomLevel(callback)` -### `webContents.pasteAndMatchStyle()` +* `callback` Function + * `zoomLevel` Number -执行网页的编辑命令 `pasteAndMatchStyle`。 +发送一个请求来获取当前的缩放等级,`callback` 回调方法会在 `callback(zoomLevel)` 中调用. +#### `contents.setZoomLevelLimits(minimumLevel, maximumLevel)` -### `webContents.delete()` +* `minimumLevel` Number +* `maximumLevel` Number -执行网页的编辑命令 `delete`。 +**废弃:** 使用 `setVisualZoomLevelLimits` 来代替. 这个方法将在 Electron 2.0 中移除. -### `webContents.selectAll()` +#### `contents.setVisualZoomLevelLimits(minimumLevel, maximumLevel)` -执行网页的编辑命令 `selectAll`。 +* `minimumLevel` Number +* `maximumLevel` Number -### `webContents.unselect()` +设置最大和最小的手势缩放等级。 -执行网页的编辑命令 `unselect`。 +#### `contents.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)` -### `webContents.replace(text)` +* `minimumLevel` Number +* `maximumLevel` Number + +设置最大和最小的 layout-based (i.e. non-visual) zoom level. + +#### `contents.undo()` + +在网页中执行编辑命令 `undo`。 + +#### `contents.redo()` + +在网页中执行编辑命令 `redo`。 + +#### `contents.cut()` + +在网页中执行编辑命令 `cut`。 + +#### `contents.copy()` + +在网页中执行编辑命令 `copy`。 + +#### `contents.copyImageAt(x, y)` + +* `x` Integer +* `y` Integer + +拷贝剪贴板中指定位置的图像. + +#### `contents.paste()` + +在网页中执行编辑命令 `paste`。 + +#### `contents.pasteAndMatchStyle()` + +在网页中执行编辑命令 `pasteAndMatchStyle`。 + +#### `contents.delete()` + +在网页中执行编辑命令 `delete`。 + +#### `contents.selectAll()` + +在网页中执行编辑命令 `selectAll`。 + +#### `contents.unselect()` + +在网页中执行编辑命令 `unselect`。 + +#### `contents.replace(text)` * `text` String -执行网页的编辑命令 `replace`。 +在网页中执行编辑命令 `replace`。 -### `webContents.replaceMisspelling(text)` +#### `contents.replaceMisspelling(text)` * `text` String -执行网页的编辑命令 `replaceMisspelling`。 +在网页中执行编辑命令 `replaceMisspelling`。 -### `webContents.insertText(text)` +#### `contents.insertText(text)` * `text` String 插入 `text` 到获得了焦点的元素。 -### `webContents.findInPage(text[, options])` +#### `contents.findInPage(text[, options])` * `text` String - 查找内容,不能为空。 * `options` Object (可选) - * `forward` Boolean - 是否向前或向后查找,默认为 `true`。 - * `findNext` Boolean - 当前操作是否是第一次查找或下一次查找, + * `forward` Boolean - (可选) 是否向前或向后查找,默认为 `true`。 + * `findNext` Boolean - (可选) 当前操作是否是第一次查找或下一次查找, 默认为 `false`。 - * `matchCase` Boolean - 查找是否区分大小写, + * `matchCase` Boolean - (可选) 查找是否区分大小写, 默认为 `false`。 - * `wordStart` Boolean -是否仅以首字母查找, + * `wordStart` Boolean - (可选) 是否仅以首字母查找, 默认为 `false`。 - * `medialCapitalAsWordStart` Boolean - 是否结合 `wordStart`,如果匹配是大写字母开头,后面接小写字母或无字母,那么就接受这个词中匹配。接受几个其它的合成词匹配,默认为 `false`。 + * `medialCapitalAsWordStart` Boolean - (可选) 是否结合 `wordStart`,如果匹配是大写字母开头,后面接小写字母或无字母,那么就接受这个词中匹配。接受几个其它的合成词匹配,默认为 `false`。 发起请求,在网页中查找所有与 `text` 相匹配的项,并且返回一个 `Integer` 来表示这个请求用的请求 Id。这个请求结果可以通过订阅 [`found-in-page`](web-contents.md#event-found-in-page) 事件来取得。 -### `webContents.stopFindInPage(action)` +#### `contents.stopFindInPage(action)` * `action` String - 指定一个行为来接替停止 [`webContents.findInPage`] 请求。 @@ -558,47 +804,62 @@ var currentURL = win.webContents.getURL() 使用给定的 `action` 来为 `webContents` 停止任何 `findInPage` 请求。 ```javascript -webContents.on('found-in-page', function (event, result) { +const {webContents} = require('electron') +webContents.on('found-in-page', (event, result) => { if (result.finalUpdate) webContents.stopFindInPage('clearSelection') }) const requestId = webContents.findInPage('api') +console.log(requestId) ``` -### `webContents.hasServiceWorker(callback)` +#### `contents.capturePage([rect, ]callback)` + +* `rect` [Rectangle](structures/rectangle.md) (optional) - 页面被捕捉的区域 +* `callback` Function + * `image` [NativeImage](native-image.md) + +捕捉页面 `rect` 区域的快照。在完成后 `callback` 方法会通过 `callback(image)` 调用 。`image` 是 [NativeImage](native-image.md) 的实例。省略 `rect` 参数会捕捉整个页面的可视区域。 + +#### `contents.hasServiceWorker(callback)` * `callback` Function - + * `hasWorker` Boolean + 检查是否有任何 ServiceWorker 注册了,并且返回一个布尔值,来作为 `callback`响应的标识。 -### `webContents.unregisterServiceWorker(callback)` +#### `contents.unregisterServiceWorker(callback)` * `callback` Function - + * `success` Boolean + 如果存在任何 ServiceWorker,则全部注销,并且当JS承诺执行行或JS拒绝执行而失败的时候,返回一个布尔值,它标识了相应的 `callback`。 -### `webContents.print([options])` +#### `contents.print([options])` * `options` Object (可选) * `silent` Boolean - 不需要请求用户的打印设置. 默认为 `false`。 * `printBackground` Boolean - 打印背景和网页图片. 默认为 `false`。 -打印窗口的网页。当设置 `silent` 为 `false` 的时候,Electron 将使用系统默认的打印机和打印方式来打印。 +打印窗口的网页。当设置 `silent` 为 `true` 的时候,Electron 将使用系统默认的打印机和打印方式来打印。 在网页中调用 `window.print()` 和 调用 `webContents.print({silent: false, printBackground: false})`具有相同的作用。 -**注意:** 在 Windows,打印 API 依赖于 `pdf.dll`。如果你的应用不使用任何的打印,你可以安全删除 `pdf.dll` 来减少二进制文件的size。 +使用 `page-break-before: always; ` CSS 的样式将强制打印到一个新的页面. -### `webContents.printToPDF(options, callback)` +#### `contents.printToPDF(options, callback)` * `options` Object * `marginsType` Integer - 指定使用的 margin type。默认 margin 使用 0,无 margin 使用 1,最小化 margin 使用 2。 * `pageSize` String - 指定生成的PDF文件的page size. 可以是 `A3`、 - `A4`、 `A5`、 `Legal`、`Letter` 和 `Tabloid`。 + `A4`、 `A5`、 `Legal`、`Letter` 和 `Tabloid`。或者是一个包含 `height` + 和 `width` 的对象,单位是微米。 * `printBackground` Boolean - 是否打印 css 背景。 * `printSelectionOnly` Boolean - 是否只打印选中的部分。 * `landscape` Boolean - landscape 为 `true`, portrait 为 `false`。 * `callback` Function + * `error` Error + * `data` Buffer 打印窗口的网页为 pdf,使用 Chromium 预览打印的自定义设置。 @@ -615,18 +876,22 @@ const requestId = webContents.findInPage('api') } ``` +使用 `page-break-before: always; ` CSS 的样式将强制打印到一个新的页面. + +一个 `webContents.printToPDF` 的示例: + ```javascript -const BrowserWindow = require('electron').BrowserWindow +const {BrowserWindow} = require('electron') const fs = require('fs') -var win = new BrowserWindow({width: 800, height: 600}) +let win = new BrowserWindow({width: 800, height: 600}) win.loadURL('http://github.com') -win.webContents.on('did-finish-load', function () { +win.webContents.on('did-finish-load', () => { // Use default printing options - win.webContents.printToPDF({}, function (error, data) { + 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.') }) @@ -634,59 +899,61 @@ win.webContents.on('did-finish-load', function () { }) ``` -### `webContents.addWorkSpace(path)` +#### `contents.addWorkSpace(path)` * `path` String 添加指定的路径给开发者工具栏的 workspace。必须在 DevTools 创建之后使用它: ```javascript -mainWindow.webContents.on('devtools-opened', function () { - mainWindow.webContents.addWorkSpace(__dirname) +const {BrowserWindow} = require('electron') +let win = new BrowserWindow() +win.webContents.on('devtools-opened', () => { + win.webContents.addWorkSpace(__dirname) }) ``` -### `webContents.removeWorkSpace(path)` +#### `contents.removeWorkSpace(path)` * `path` String 从开发者工具栏的 workspace 删除指定的路径。 -### `webContents.openDevTools([options])` +#### `contents.openDevTools([options])` * `options` Object (可选) - * `detach` Boolean - 在一个新窗口打开开发者工具栏 + * `mode` String - 打开开发者工具的状态属性。可以为 `right`, `bottom`, `undocked`, `detach`。默认值为上一次使用时的状态。在`undocked`模式可以把工具栏放回来,`detach`模式不可以。 打开开发者工具栏。 -### `webContents.closeDevTools()` +#### `contents.closeDevTools()` 关闭开发者工具栏。 -### `webContents.isDevToolsOpened()` +#### `contents.isDevToolsOpened()` -返回布尔值,开发者工具栏是否打开。 +Returns `Boolean` - 开发者工具栏是否打开。 -### `webContents.isDevToolsFocused()` +#### `contents.isDevToolsFocused()` -返回布尔值,开发者工具栏视图是否获得焦点。 +Returns `Boolean` - 开发者工具栏视图是否获得焦点。 -### `webContents.toggleDevTools()` +#### `contents.toggleDevTools()` Toggles 开发者工具。 -### `webContents.inspectElement(x, y)` +#### `contents.inspectElement(x, y)` * `x` Integer * `y` Integer 在 (`x`, `y`) 开始检测元素。 -### `webContents.inspectServiceWorker()` +#### `contents.inspectServiceWorker()` 为 service worker 上下文打开开发者工具栏。 -### `webContents.send(channel[, arg1][, arg2][, ...])` +#### `contents.send(channel[, arg1][, arg2][, ...])` * `channel` String * `arg` (可选) @@ -695,16 +962,18 @@ Toggles 开发者工具。 渲染进程可以通过使用 `ipcRenderer` 监听 `channel` 来处理消息。 -例子,从主进程向渲染进程发送消息: +从主进程向渲染进程发送消息的示例: ```javascript // 主进程. -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!') +const {app, BrowserWindow} = require('electron') +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!') }) }) ``` @@ -714,31 +983,31 @@ app.on('ready', function () { ``` -### `webContents.enableDeviceEmulation(parameters)` +#### `contents.enableDeviceEmulation(parameters)` -`parameters` Object, properties: +`parameters` Object, 属性为: * `screenPosition` String - 指定需要模拟的屏幕 (默认 : `desktop`) - * `desktop` - * `mobile` -* `screenSize` Object - 设置模拟屏幕 size (screenPosition == mobile) + * `desktop` - 桌面屏幕模式 + * `mobile` - 手机屏幕模式 +* `screenSize` Object - 设置模拟屏幕的尺寸 (screenPosition == mobile) * `width` Integer - 设置模拟屏幕 width * `height` Integer - 设置模拟屏幕 height -* `viewPosition` Object - 在屏幕放置 view +* `viewPosition` Object - 屏幕中可视区域的位置 (screenPosition == mobile) (默认: `{x: 0, y: 0}`) * `x` Integer - 设置偏移左上角的x轴 * `y` Integer - 设置偏移左上角的y轴 -* `deviceScaleFactor` Integer - 设置设备比例因子 (如果为0,默认为原始屏幕比例) (默认: `0`) -* `viewSize` Object - 设置模拟视图 size (空表示不覆盖) +* `deviceScaleFactor` Integer - 设置设备缩放比例系数 (如果为0,默认为原始屏幕比例) (默认: `0`) +* `viewSize` Object - 设置模拟视图的尺寸 (空表示不覆盖) * `width` Integer - 设置模拟视图 width * `height` Integer - 设置模拟视图 height * `fitToView` Boolean - 如果有必要的话,是否把模拟视图按比例缩放来适应可用空间 (默认: `false`) @@ -749,32 +1018,30 @@ app.on('ready', function () { 使用给定的参数来开启设备模拟。 -### `webContents.disableDeviceEmulation()` +#### `contents.disableDeviceEmulation()` -使用 `webContents.enableDeviceEmulation` 关闭设备模拟。 +关闭模拟器,使用 `webContents.enableDeviceEmulation` 来启用。 -### `webContents.sendInputEvent(event)` +#### `contents.sendInputEvent(event)` * `event` Object * `type` String (**必需**) - 事件类型,可以是 `mouseDown`, `mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`, `mouseMove`, `keyDown`, `keyUp`, `char`. - * `modifiers` Array - 事件的 modifiers 数组, 可以是 - include `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`, + * `modifiers` String[] - 事件的 modifiers 数组, 可以包含 `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`, `middleButtonDown`, `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`. -向 page 发送一个输入 `event`。 +向页面发送一个输入 `event`。 对键盘事件来说,`event` 对象还有如下属性: -* `keyCode` String (**必需**) - 特点是将作为键盘事件发送。可用的 key codes [Accelerator](accelerator.md)。 - +* `keyCode` String (**必需**) - 将字符串作为键盘事件发送。可用的 key codes [Accelerator](accelerator.md)。 对鼠标事件来说,`event` 对象还有如下属性: -* `x` Integer (**required**) -* `y` Integer (**required**) +* `x` Integer (**必需**) +* `y` Integer (**必需**) * `button` String - button 按下, 可以是 `left`, `middle`, `right` * `globalX` Integer * `globalY` Integer @@ -793,122 +1060,151 @@ app.on('ready', function () { * `hasPreciseScrollingDeltas` Boolean * `canScroll` Boolean -### `webContents.beginFrameSubscription(callback)` - +#### `contents.beginFrameSubscription(callback)` +* `onlyDirty` Boolean (可选) - 默认值为 `false` * `callback` Function - + * `frameBuffer` Buffer + * `dirtyRect` [Rectangle](structures/rectangle.md) + 开始订阅 提交 事件和捕获数据帧,当有提交事件时,使用 `callback(frameBuffer)` 调用 `callback`。 `frameBuffer` 是一个包含原始像素数据的 `Buffer`,像素数据是按照 32bit BGRA 格式有效存储的,但是实际情况是取决于处理器的字节顺序的(大多数的处理器是存放小端序的,如果是在大端序的处理器上,数据是 32bit ARGB 格式)。 -### `webContents.endFrameSubscription()` +`dirtyRect` 脏区域是一个包含 `x, y, width, height` 属性的对象,它们描述了一个页面中的重绘区域。如果 `onlyDirty` 被设置为`true`, `frameBuffer` 将只包含重绘区域。`onlyDirty` 的默认值为 `false`. + +#### `contents.endFrameSubscription()` 停止订阅帧提交事件。 -### `webContents.savePage(fullPath, saveType, callback)` +#### `contents.startDrag(item)` + +* `item` Object + * `file` String 或 `files` Array - 要拖拽的文件(可以为多个)的路径。 + * `icon` [NativeImage](native-image.md) - 在 macOS 中图标不能为空. + +设置 `item` 作为当前拖拽操作的对象。`file` 是作为拖拽文件的绝对路径。`icon` 是拖拽时光标下面显示的图像。 + +#### `contents.savePage(fullPath, saveType, callback)` * `fullPath` String - 文件的完整路径. * `saveType` String - 指定保存类型. * `HTMLOnly` - 只保存html. * `HTMLComplete` - 保存整个 page 内容. * `MHTML` - 保存完整的 html 为 MHTML. -* `callback` Function - `function(error) {}`. +* `callback` Function - `(error) => {}`. * `error` Error -如果保存界面过程初始化成功,返回 true。 +Returns `Boolean` - 如果保存界面过程初始化成功,返回 true。 ```javascript +const {BrowserWindow} = require('electron') +let win = new BrowserWindow() + 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') }) }) ``` -## 实例属性 +#### `contents.showDefinitionForSelection()` _macOS_ + +在页面上显示搜索的弹窗。 + +#### `contents.setSize(options)` + +设置页面的大小。This is only supported for `` guest contents. + +* `options` Object + * `normal` Object (可选) - Normal size of the page. This can be used in + combination with the [`disableguestresize`](web-view-tag.md#disableguestresize) + attribute to manually resize the webview guest contents. + * `width` Integer + * `height` Integer + +#### `contents.isOffscreen()` + +Returns `Boolean` - 表明是否设置了 *offscreen rendering*. + +#### `contents.startPainting()` + +如果设置了 *offscreen rendering* 并且没有绘制,开始绘制. + +#### `contents.stopPainting()` + +如果设置了 *offscreen rendering* 并且绘制了,停止绘制. + +#### `contents.isPainting()` + +Returns `Boolean` - 如果设置了 *offscreen rendering* ,返回当前是否正在绘制. + +#### `contents.setFrameRate(fps)` + +* `fps` Integer + +如果设置了 *offscreen rendering*,设置帧频为制定数值。有效范围为1-60. + +#### `contents.getFrameRate()` + +Returns `Integer` - 如果设置了 *offscreen rendering*,返回当前的帧频 + +#### `contents.invalidate()` + +全部重新绘制整个页面的内容。 + +如果设置了*offscreen rendering* ,让页面失效并且生成一个新的`'paint'`事件 + +#### `contents.getWebRTCIPHandlingPolicy()` + +Returns `String` - Returns the WebRTC IP Handling Policy. + +#### `contents.setWebRTCIPHandlingPolicy(policy)` + +* `policy` String - Specify the WebRTC IP Handling Policy. + * `default` - Exposes user's public and local IPs. This is the default + behavior. When this policy is used, WebRTC has the right to enumerate all + interfaces and bind them to discover public interfaces. + * `default_public_interface_only` - Exposes user's public IP, but does not + expose user's local IP. When this policy is used, WebRTC should only use the + default route used by http. This doesn't expose any local addresses. + * `default_public_and_private_interfaces` - Exposes user's public and local + IPs. When this policy is used, WebRTC should only use the default route used + by http. This also exposes the associated default private address. Default + route is the route chosen by the OS on a multi-homed endpoint. + * `disable_non_proxied_udp` - Does not expose public or local IPs. When this + policy is used, WebRTC should only use TCP to contact peers or servers unless + the proxy server supports UDP. + +Setting the WebRTC IP handling policy allows you to control which IPs are +exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for +more details. + +### 实例属性 `WebContents` 对象也有下列属性: -### `webContents.session` +#### `contents.id` + +表明 WebContents 唯一标示的整数 + +#### `contents.session` 返回这个 `webContents` 使用的 [session](session.md) 对象。 -### `webContents.hostWebContents` +#### `contents.hostWebContents` -返回这个 `webContents` 的父 `webContents`。 +返回这个 `webContents` 的父 [`WebContents`](web-contents.md)。 -### `webContents.devToolsWebContents` +#### `contents.devToolsWebContents` 获取这个 `WebContents` 的开发者工具栏的 `WebContents`。 **注意:** 用户不可保存这个对象,因为当开发者工具栏关闭的时候它的值为 `null`。 -### `webContents.debugger` +#### `contents.debugger` -调试 API 为 [remote debugging protocol][rdp] 提供交替传送。 +webContents 的 [Debugger](debugger.md) 实例. -```javascript -try { - win.webContents.debugger.attach('1.1') -} catch (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('message', function (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') -``` - -#### `webContents.debugger.attach([protocolVersion])` - -* `protocolVersion` String (可选) - 请求调试协议版本。 - -添加 `webContents` 调试。 - -#### `webContents.debugger.isAttached()` - -返回一个布尔值,标识是否已经给 `webContents` 添加了调试。 - -#### `webContents.debugger.detach()` - -删除 `webContents` 调试。 - -#### `webContents.debugger.sendCommand(method[, commandParams, callback])` - -* `method` String - 方法名, 应该是由远程调试协议定义的方法。 -* `commandParams` Object (可选) - 请求参数为 JSON 对象。 -* `callback` Function (可选) - Response - * `error` Object - 错误消息,标识命令失败。 - * `result` Object - 回复在远程调试协议中由 'returns'属性定义的命令描述。 - -发送给定命令给调试目标。 - -### Event: 'detach' - -* `event` Event -* `reason` String - 拆分调试器原因。 - -在调试 session 结束时发出事件.这在 `webContents` 关闭时或 `webContents` 请求开发者工具栏时发生。 - -### Event: 'message' - -* `event` Event -* `method` String - 方法名。 -* `params` Object - 在远程调试协议中由 'parameters' 属性定义的事件参数。 - -每当调试目标发出事件时发出。 - -[rdp]: https://developer.chrome.com/devtools/docs/debugger-protocol -[`webContents.findInPage`]: web-contents.md#webcontentsfindinpagetext-options +[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent From 34a91434aac148d8562da23af5e2001a347fb223 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 1 Apr 2017 22:01:29 +0200 Subject: [PATCH 95/98] Remove extra spaces. --- atom/browser/native_window_mac.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 4cec64e1cade..d8fc4617966b 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1358,22 +1358,22 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { // they are available in the minimum SDK version if (type == "selection") { // NSVisualEffectMaterialSelection - vibrancyType = static_cast( 4); + vibrancyType = static_cast(4); } else if (type == "menu") { // NSVisualEffectMaterialMenu - vibrancyType = static_cast( 5); + vibrancyType = static_cast(5); } else if (type == "popover") { // NSVisualEffectMaterialPopover - vibrancyType = static_cast( 6); + vibrancyType = static_cast(6); } else if (type == "sidebar") { // NSVisualEffectMaterialSidebar - vibrancyType = static_cast( 7); + vibrancyType = static_cast(7); } else if (type == "medium-light") { // NSVisualEffectMaterialMediumLight - vibrancyType = static_cast( 8); + vibrancyType = static_cast(8); } else if (type == "ultra-dark") { // NSVisualEffectMaterialUltraDark - vibrancyType = static_cast( 9); + vibrancyType = static_cast(9); } } From 0989fd7a1cf694d9d324bfc31939afb10907ad5e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 08:32:16 -0700 Subject: [PATCH 96/98] Upgrade brightray to latest --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index 53aa2cfc8a40..baccc077948f 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 53aa2cfc8a40627d62bf5be757ff9dea444f80bd +Subproject commit baccc077948f504c6a6db58e855fd33938b2b625 From 257f6b142f6e726dae1f767727e7255cbc2162b0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 09:09:37 -0700 Subject: [PATCH 97/98] Add spec for remote setter not surfacing error --- spec/api-ipc-spec.js | 12 ++++++++++++ spec/fixtures/module/error-properties.js | 11 +++++++++++ 2 files changed, 23 insertions(+) create mode 100644 spec/fixtures/module/error-properties.js diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index 47f2eef21685..c5e38e83e4db 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -187,6 +187,18 @@ describe('ipc module', function () { property.property = 1127 }) + it('rethrows errors getting/setting properties', function () { + const foo = remote.require(path.join(fixtures, 'module', 'error-properties.js')) + + assert.throws(function () { + foo.bar + }, /getting error/) + + assert.throws(function () { + foo.bar = 'test' + }, /setting error/) + }) + it('can construct an object from its member', function () { var call = remote.require(path.join(fixtures, 'module', 'call.js')) var obj = new call.constructor() diff --git a/spec/fixtures/module/error-properties.js b/spec/fixtures/module/error-properties.js new file mode 100644 index 000000000000..c3a1e3b3a7f6 --- /dev/null +++ b/spec/fixtures/module/error-properties.js @@ -0,0 +1,11 @@ +class Foo { + set bar (value) { + throw new Error('setting error') + } + + get bar () { + throw new Error('getting error') + } +} + +module.exports = new Foo() From e85e483c710097a2bf890e52e398044a6d9c1673 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 09:11:06 -0700 Subject: [PATCH 98/98] Parse setting response to surface thrown errors --- lib/renderer/api/remote.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index b3d3d2ab17cc..f65d61790ace 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -139,7 +139,12 @@ const setObjectMembers = function (ref, object, metaId, members) { // Only set setter when it is writable. if (member.writable) { descriptor.set = function (value) { - ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, value) + const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, value) + // Meta will be non-null when a setter error occurred so parse it + // to a value so it gets re-thrown. + if (meta != null) { + metaToValue(meta) + } return value } }