зеркало из https://github.com/electron/electron.git
feat: add webContents.setWindowOpenHandler API (#24517)
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
This commit is contained in:
Родитель
6b222a2d8a
Коммит
0b85fdf26c
|
@ -14,7 +14,7 @@
|
|||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"args": "after-used",
|
||||
"ignoreRestSiblings": false
|
||||
"ignoreRestSiblings": true
|
||||
}],
|
||||
"prefer-const": ["error", {
|
||||
"destructuring": "all"
|
||||
|
|
|
@ -134,7 +134,7 @@ Returns:
|
|||
|
||||
Emitted when page receives favicon urls.
|
||||
|
||||
#### Event: 'new-window'
|
||||
#### Event: 'new-window' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
|
@ -155,6 +155,8 @@ Returns:
|
|||
be set. If no post data is to be sent, the value will be `null`. Only defined
|
||||
when the window is being created by a form that set `target=_blank`.
|
||||
|
||||
Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
|
||||
Emitted when the page requests to open a new window for a `url`. It could be
|
||||
requested by `window.open` or an external link like `<a target='_blank'>`.
|
||||
|
||||
|
@ -189,6 +191,39 @@ myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition
|
|||
})
|
||||
```
|
||||
|
||||
#### Event: 'did-create-window'
|
||||
|
||||
Returns:
|
||||
* `window` BrowserWindow
|
||||
* `details` Object
|
||||
* `url` String - URL for the created window.
|
||||
* `frameName` String - Name given to the created window in the
|
||||
`window.open()` call.
|
||||
* `options` BrowserWindowConstructorOptions - The options used to create the
|
||||
BrowserWindow. They are merged in increasing precedence: options inherited
|
||||
from the parent, parsed options from the `features` string from
|
||||
`window.open()`, and options given by
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
Unrecognized options are not filtered out.
|
||||
* `additionalFeatures` String[] - The non-standard features (features not
|
||||
handled Chromium or Electron) _Deprecated_
|
||||
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
|
||||
passed to the new window. May or may not result in the `Referer` header
|
||||
being sent, depending on the referrer policy.
|
||||
* `postBody` [PostBody](structures/post-body.md) (optional) - The post data
|
||||
that will be sent to the new window, along with the appropriate headers
|
||||
that will be set. If no post data is to be sent, the value will be `null`.
|
||||
Only defined when the window is being created by a form that set
|
||||
`target=_blank`.
|
||||
* `disposition` String - Can be `default`, `foreground-tab`,
|
||||
`background-tab`, `new-window`, `save-to-disk` and `other`.
|
||||
|
||||
Emitted _after_ successful creation of a window via `window.open` in the renderer.
|
||||
Not emitted if the creation of the window is canceled from
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
|
||||
See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `webContents.setWindowOpenHandler`.
|
||||
|
||||
#### Event: 'will-navigate'
|
||||
|
||||
Returns:
|
||||
|
@ -1123,6 +1158,22 @@ Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
|
|||
|
||||
Ignore application menu shortcuts while this web contents is focused.
|
||||
|
||||
#### `contents.setWindowOpenHandler(handler)`
|
||||
|
||||
* `handler` Function<{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
|
||||
* `details` Object
|
||||
* `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
|
||||
* `frameName` String - Name of the window provided in `window.open()`
|
||||
* `features` String - Comma separated list of window features provided to `window.open()`.
|
||||
Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
|
||||
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
|
||||
Returning an unrecognized value such as a null, undefined, or an object
|
||||
without a recognized 'action' value will result in a console error and have
|
||||
the same effect as returning `{action: 'deny'}`.
|
||||
|
||||
Called before creating a window when `window.open()` is called from the
|
||||
renderer. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`.
|
||||
|
||||
#### `contents.setAudioMuted(muted)`
|
||||
|
||||
* `muted` Boolean
|
||||
|
|
|
@ -1,18 +1,34 @@
|
|||
# `window.open` Function
|
||||
# Opening windows from the renderer
|
||||
|
||||
> Open a new window and load a URL.
|
||||
There are several ways to control how windows are created from trusted or
|
||||
untrusted content within a renderer. Windows can be created from the renderer in two ways:
|
||||
|
||||
When `window.open` is called to create a new window in a web page, a new instance
|
||||
of [`BrowserWindow`](browser-window.md) will be created for the `url` and a proxy will be returned
|
||||
to `window.open` to let the page have limited control over it.
|
||||
- clicking on links or submitting forms adorned with `target=_blank`
|
||||
- JavaScript calling `window.open()`
|
||||
|
||||
The proxy has limited standard functionality implemented to be
|
||||
compatible with traditional web pages. For full control of the new window
|
||||
you should create a `BrowserWindow` directly.
|
||||
In non-sandboxed renderers, or when `nativeWindowOpen` is false (the default), this results in the creation of a
|
||||
[`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper around
|
||||
`BrowserWindow`.
|
||||
|
||||
The newly created `BrowserWindow` will inherit the parent window's options by
|
||||
default. To override inherited options you can set them in the `features`
|
||||
string.
|
||||
However, when the `sandbox` (or directly, `nativeWindowOpen`) option is set, a
|
||||
`Window` instance is created, as you'd expect in the browser. For same-origin
|
||||
content, the new window is created within the same process, enabling the parent
|
||||
to access the child window directly. This can be very useful for app sub-windows that act
|
||||
as preference panels, or similar, as the parent can render to the sub-window
|
||||
directly, as if it were a `div` in the parent.
|
||||
|
||||
Electron pairs this native Chrome `Window` with a BrowserWindow under the hood.
|
||||
You can take advantage of all the customization available when creating a
|
||||
BrowserWindow in the main process by using `webContents.setWindowOpenHandler()`
|
||||
for renderer-created windows.
|
||||
|
||||
BrowserWindow constructor options are set by, in increasing precedence
|
||||
order: options inherited from the parent, parsed options
|
||||
from the `features` string from `window.open()`, security-related webPreferences
|
||||
inherited from the parent, and options given by
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
Note that `webContents.setWindowOpenHandler` has final say and full privilege
|
||||
because it is invoked in the main process.
|
||||
|
||||
### `window.open(url[, frameName][, features])`
|
||||
|
||||
|
@ -20,16 +36,22 @@ string.
|
|||
* `frameName` String (optional)
|
||||
* `features` String (optional)
|
||||
|
||||
Returns [`BrowserWindowProxy`](browser-window-proxy.md) - Creates a new window
|
||||
and returns an instance of `BrowserWindowProxy` class.
|
||||
Returns [`BrowserWindowProxy`](browser-window-proxy.md) | [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window)
|
||||
|
||||
The `features` string follows the format of standard browser, but each feature
|
||||
has to be a field of `BrowserWindow`'s options. These are the features you can set via `features` string: `zoomFactor`, `nodeIntegration`, `preload`, `javascript`, `contextIsolation`, `webviewTag`.
|
||||
`features` is a comma-separated key-value list, following the standard format of
|
||||
the browser. Electron will parse `BrowserWindowConstructorOptions` out of this
|
||||
list where possible, for convenience. For full control and better ergonomics,
|
||||
consider using `webContents.setWindowOpenHandler` to customize the
|
||||
BrowserWindow creation.
|
||||
|
||||
A subset of `WebPreferences` can be set directly,
|
||||
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`,
|
||||
`javascript`, `contextIsolation`, and `webviewTag`.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
window.open('https://github.com', '_blank', 'nodeIntegration=no')
|
||||
window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIntegration=no')
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
@ -41,60 +63,74 @@ window.open('https://github.com', '_blank', 'nodeIntegration=no')
|
|||
* JavaScript will always be disabled in the opened `window` if it is disabled on
|
||||
the parent window.
|
||||
* Non-standard features (that are not handled by Chromium or Electron) given in
|
||||
`features` will be passed to any registered `webContent`'s `new-window` event
|
||||
handler in the `additionalFeatures` argument.
|
||||
`features` will be passed to any registered `webContents`'s
|
||||
`did-create-window` event handler in the `additionalFeatures` argument.
|
||||
|
||||
### `window.opener.postMessage(message, targetOrigin)`
|
||||
To customize or cancel the creation of the window, you can optionally set an
|
||||
override handler with `webContents.setWindowOpenHandler()` from the main
|
||||
process. Returning `false` cancels the window, while returning an object sets
|
||||
the `BrowserWindowConstructorOptions` used when creating the window. Note that
|
||||
this is more powerful than passing options through the feature string, as the
|
||||
renderer has more limited privileges in deciding security preferences than the
|
||||
main process.
|
||||
|
||||
* `message` String
|
||||
* `targetOrigin` String
|
||||
|
||||
Sends a message to the parent window with the specified origin or `*` for no
|
||||
origin preference.
|
||||
|
||||
### Using Chrome's `window.open()` implementation
|
||||
|
||||
If you want to use Chrome's built-in `window.open()` implementation, set
|
||||
`nativeWindowOpen` to `true` in the `webPreferences` options object.
|
||||
|
||||
Native `window.open()` allows synchronous access to opened windows so it is
|
||||
convenient choice if you need to open a dialog or a preferences window.
|
||||
|
||||
This option can also be set on `<webview>` tags as well:
|
||||
|
||||
```html
|
||||
<webview webpreferences="nativeWindowOpen=yes"></webview>
|
||||
```
|
||||
|
||||
The creation of the `BrowserWindow` is customizable via `WebContents`'s
|
||||
`new-window` event.
|
||||
### `BrowserWindowProxy` example
|
||||
|
||||
```javascript
|
||||
// main process
|
||||
|
||||
// main.js
|
||||
const mainWindow = new BrowserWindow()
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (url.startsWith('https://github.com/')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('did-create-window', (childWindow) => {
|
||||
// For example...
|
||||
childWindow.webContents('will-navigate', (e) => {
|
||||
e.preventDefault()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// renderer.js
|
||||
const windowProxy = window.open('https://github.com/', null, 'minimizable=false')
|
||||
windowProxy.postMessage('hi', '*')
|
||||
```
|
||||
|
||||
### Native `Window` example
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true
|
||||
}
|
||||
})
|
||||
mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
|
||||
if (frameName === 'modal') {
|
||||
// open window as modal
|
||||
event.preventDefault()
|
||||
Object.assign(options, {
|
||||
modal: true,
|
||||
parent: mainWindow,
|
||||
width: 100,
|
||||
height: 100
|
||||
})
|
||||
event.newGuest = new BrowserWindow(options)
|
||||
|
||||
// In this example, only windows with the `about:blank` url will be created.
|
||||
// All other urls will be blocked.
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (url === 'about:blank') {
|
||||
return {
|
||||
frame: false,
|
||||
fullscreenable: false,
|
||||
backgroundColor: 'black',
|
||||
webPreferences: {
|
||||
preload: 'my-child-window-preload-script.js'
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// renderer process (mainWindow)
|
||||
const modal = window.open('', 'modal')
|
||||
modal.document.write('<h1>Hello</h1>')
|
||||
const childWindow = window.open('', 'modal')
|
||||
childWindow.document.write('<h1>Hello</h1>')
|
||||
```
|
||||
|
|
|
@ -611,22 +611,29 @@ windows at runtime.
|
|||
|
||||
### How?
|
||||
|
||||
[`webContents`][web-contents] will emit the [`new-window`][new-window] event
|
||||
before creating new windows. That event will be passed, amongst other
|
||||
parameters, the `url` the window was requested to open and the options used to
|
||||
create it. We recommend that you use the event to scrutinize the creation of
|
||||
windows, limiting it to only what you need.
|
||||
[`webContents`][web-contents] will delegate to its [window open
|
||||
handler][window-open-handler] before creating new windows. The handler will
|
||||
receive, amongst other parameters, the `url` the window was requested to open
|
||||
and the options used to create it. We recommend that you register a handler to
|
||||
monitor the creation of windows, and deny any unexpected window creation.
|
||||
|
||||
```js
|
||||
const { shell } = require('electron')
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
contents.on('new-window', async (event, navigationUrl) => {
|
||||
contents.setWindowOpenHandler(({ url }) => {
|
||||
// In this example, we'll ask the operating system
|
||||
// to open this event's url in the default browser.
|
||||
event.preventDefault()
|
||||
//
|
||||
// See the following item for considerations regarding what
|
||||
// URLs should be allowed through to shell.openExternal.
|
||||
if (isSafeForExternalOpen(url)) {
|
||||
setImmediate(() => {
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
|
||||
await shell.openExternal(navigationUrl)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
})
|
||||
```
|
||||
|
@ -811,7 +818,7 @@ which potential security issues are not as widely known.
|
|||
[browser-view]: ../api/browser-view.md
|
||||
[webview-tag]: ../api/webview-tag.md
|
||||
[web-contents]: ../api/web-contents.md
|
||||
[new-window]: ../api/web-contents.md#event-new-window
|
||||
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandler-handler
|
||||
[will-navigate]: ../api/web-contents.md#event-will-navigate
|
||||
[open-external]: ../api/shell.md#shellopenexternalurl-options
|
||||
[sandbox]: ../api/sandbox-option.md
|
||||
|
|
|
@ -237,6 +237,7 @@ auto_filenames = {
|
|||
"lib/browser/devtools.ts",
|
||||
"lib/browser/guest-view-manager.ts",
|
||||
"lib/browser/guest-window-manager.ts",
|
||||
"lib/browser/guest-window-proxy.ts",
|
||||
"lib/browser/init.ts",
|
||||
"lib/browser/ipc-main-impl.ts",
|
||||
"lib/browser/ipc-main-internal-utils.ts",
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { app, ipcMain, session, deprecate } from 'electron/main';
|
||||
import type { MenuItem, MenuItemConstructorOptions } from 'electron/main';
|
||||
import { app, ipcMain, session, deprecate, BrowserWindowConstructorOptions } from 'electron/main';
|
||||
import type { MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main';
|
||||
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
import { internalWindowOpen } from '@electron/internal/browser/guest-window-manager';
|
||||
import { openGuestWindow, makeWebPreferences } from '@electron/internal/browser/guest-window-manager';
|
||||
import { NavigationController } from '@electron/internal/browser/navigation-controller';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
import { parseFeatures } from '@electron/internal/common/parse-features-string';
|
||||
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
|
@ -21,6 +20,8 @@ const getNextId = function () {
|
|||
return ++nextId;
|
||||
};
|
||||
|
||||
type PostData = LoadURLOptions['postData']
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
type MediaSize = {
|
||||
name: string,
|
||||
|
@ -439,6 +440,40 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
|||
}));
|
||||
};
|
||||
|
||||
WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'allow'} | {action: 'deny', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})) {
|
||||
this._windowOpenHandler = handler;
|
||||
};
|
||||
|
||||
WebContents.prototype._callWindowOpenHandler = function (event: any, url: string, frameName: string, rawFeatures: string): BrowserWindowConstructorOptions | null {
|
||||
if (!this._windowOpenHandler) {
|
||||
return null;
|
||||
}
|
||||
const response = this._windowOpenHandler({ url, frameName, features: rawFeatures });
|
||||
|
||||
if (typeof response !== 'object') {
|
||||
event.preventDefault();
|
||||
console.error(`The window open handler response must be an object, but was instead of type '${typeof response}'.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response === null) {
|
||||
event.preventDefault();
|
||||
console.error('The window open handler response must be an object, but was instead null.');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.action === 'deny') {
|
||||
event.preventDefault();
|
||||
return null;
|
||||
} else if (response.action === 'allow') {
|
||||
if (typeof response.overrideBrowserWindowOptions === 'object' && response.overrideBrowserWindowOptions !== null) { return response.overrideBrowserWindowOptions; } else { return {}; }
|
||||
} else {
|
||||
event.preventDefault();
|
||||
console.error('The window open handler response must be an object with an \'action\' property of \'allow\' or \'deny\'.');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const addReplyToEvent = (event: any) => {
|
||||
event.reply = (...args: any[]) => {
|
||||
event.sender.sendToFrame(event.frameId, ...args);
|
||||
|
@ -490,6 +525,8 @@ WebContents.prototype._init = function () {
|
|||
this.getActiveIndex = navigationController.getActiveIndex.bind(navigationController);
|
||||
this.length = navigationController.length.bind(navigationController);
|
||||
|
||||
this._windowOpenHandler = null;
|
||||
|
||||
// Every remote callback from renderer process would add a listener to the
|
||||
// render-view-deleted event, so ignore the listeners warning.
|
||||
this.setMaxListeners(0);
|
||||
|
@ -570,43 +607,67 @@ WebContents.prototype._init = function () {
|
|||
if (this.getType() !== 'remote') {
|
||||
// Make new windows requested by links behave like "window.open".
|
||||
this.on('-new-window' as any, (event: any, url: string, frameName: string, disposition: string,
|
||||
rawFeatures: string, referrer: string, postData: Electron.UploadRawData[]) => {
|
||||
const { options, webPreferences, additionalFeatures } = parseFeatures(rawFeatures);
|
||||
const mergedOptions = {
|
||||
show: true,
|
||||
width: 800,
|
||||
height: 600,
|
||||
title: frameName,
|
||||
webPreferences,
|
||||
...options
|
||||
};
|
||||
rawFeatures: string, referrer: any, postData: PostData) => {
|
||||
openGuestWindow({
|
||||
event,
|
||||
embedder: event.sender,
|
||||
disposition,
|
||||
referrer,
|
||||
postData,
|
||||
overrideBrowserWindowOptions: {},
|
||||
windowOpenArgs: {
|
||||
url,
|
||||
frameName,
|
||||
features: rawFeatures
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
internalWindowOpen(event, url, referrer, frameName, disposition, mergedOptions, additionalFeatures, postData);
|
||||
let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
|
||||
this.on('-will-add-new-contents' as any, (event: any, url: string, frameName: string, rawFeatures: string) => {
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, url, frameName, rawFeatures);
|
||||
if (!event.defaultPrevented) {
|
||||
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
|
||||
// Allow setting of backgroundColor as a webPreference even though
|
||||
// it's technically a BrowserWindowConstructorOptions option because
|
||||
// we need to access it in the renderer at init time.
|
||||
backgroundColor: windowOpenOverriddenOptions.backgroundColor,
|
||||
...windowOpenOverriddenOptions.webPreferences
|
||||
} : undefined;
|
||||
this._setNextChildWebPreferences(
|
||||
makeWebPreferences({ embedder: event.sender, secureOverrideWebPreferences })
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Create a new browser window for the native implementation of
|
||||
// "window.open", used in sandbox and nativeWindowOpen mode.
|
||||
this.on('-add-new-contents' as any, (event: any, webContents: Electron.WebContents, disposition: string,
|
||||
userGesture: boolean, left: number, top: number, width: number, height: number, url: string, frameName: string,
|
||||
referrer: string, rawFeatures: string, postData: Electron.UploadRawData[]) => {
|
||||
_userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string,
|
||||
referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => {
|
||||
const overriddenOptions = windowOpenOverriddenOptions || undefined;
|
||||
windowOpenOverriddenOptions = null;
|
||||
|
||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||
disposition !== 'background-tab')) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const { options, webPreferences, additionalFeatures } = parseFeatures(rawFeatures);
|
||||
const mergedOptions = {
|
||||
show: true,
|
||||
width: 800,
|
||||
height: 600,
|
||||
webContents,
|
||||
title: frameName,
|
||||
webPreferences,
|
||||
...options
|
||||
};
|
||||
|
||||
internalWindowOpen(event, url, referrer, frameName, disposition, mergedOptions, additionalFeatures, postData);
|
||||
openGuestWindow({
|
||||
event,
|
||||
embedder: event.sender,
|
||||
guest: webContents,
|
||||
overrideBrowserWindowOptions: overriddenOptions,
|
||||
disposition,
|
||||
referrer,
|
||||
postData,
|
||||
windowOpenArgs: {
|
||||
url,
|
||||
frameName,
|
||||
features: rawFeatures
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const prefs = this.getWebPreferences() || {};
|
||||
|
|
|
@ -1,360 +1,300 @@
|
|||
import * as electron from 'electron/main';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
/**
|
||||
* Create and minimally track guest windows at the direction of the renderer
|
||||
* (via window.open). Here, "guest" roughly means "child" — it's not necessarily
|
||||
* emblematic of its process status; both in-process (same-origin
|
||||
* nativeWindowOpen) and out-of-process (cross-origin nativeWindowOpen and
|
||||
* BrowserWindowProxy) are created here. "Embedder" roughly means "parent."
|
||||
*/
|
||||
import { BrowserWindow } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, Referrer, WebContents, LoadURLOptions } from 'electron/main';
|
||||
import { parseFeatures } from '@electron/internal/common/parse-features-string';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { isSameOrigin } = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
const { BrowserWindow } = electron;
|
||||
const hasProp = {}.hasOwnProperty;
|
||||
const frameToGuest = new Map<string, Electron.BrowserWindow>();
|
||||
|
||||
// Security options that child windows will always inherit from parent windows
|
||||
const inheritedWebPreferences = new Map([
|
||||
['contextIsolation', true],
|
||||
['javascript', false],
|
||||
['nativeWindowOpen', true],
|
||||
['nodeIntegration', false],
|
||||
['enableRemoteModule', false],
|
||||
['sandbox', true],
|
||||
['webviewTag', false],
|
||||
['nodeIntegrationInSubFrames', false],
|
||||
['enableWebSQL', false]
|
||||
]);
|
||||
|
||||
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
||||
const mergeOptions = function (child: Record<string, any>, parent: Record<string, any>, visited?: Set<Record<string, any>>) {
|
||||
// Check for circular reference.
|
||||
if (visited == null) visited = new Set();
|
||||
if (visited.has(parent)) return;
|
||||
|
||||
visited.add(parent);
|
||||
for (const key in parent) {
|
||||
if (key === 'type') continue;
|
||||
if (!hasProp.call(parent, key)) continue;
|
||||
if (key in child && key !== 'webPreferences') continue;
|
||||
|
||||
const value = parent[key];
|
||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||
child[key] = mergeOptions(child[key] || {}, value, visited);
|
||||
} else {
|
||||
child[key] = value;
|
||||
}
|
||||
}
|
||||
visited.delete(parent);
|
||||
|
||||
return child;
|
||||
};
|
||||
|
||||
// Merge |options| with the |embedder|'s window's options.
|
||||
const mergeBrowserWindowOptions = function (embedder: Electron.WebContents, options: Record<string, any>) {
|
||||
if (options.webPreferences == null) {
|
||||
options.webPreferences = {};
|
||||
}
|
||||
if (embedder.browserWindowOptions != null) {
|
||||
let parentOptions = embedder.browserWindowOptions;
|
||||
|
||||
// if parent's visibility is available, that overrides 'show' flag (#12125)
|
||||
const win = BrowserWindow.fromWebContents(embedder);
|
||||
if (win != null) {
|
||||
parentOptions = {
|
||||
...win.getBounds(),
|
||||
...embedder.browserWindowOptions,
|
||||
show: win.isVisible()
|
||||
};
|
||||
}
|
||||
|
||||
// Inherit the original options if it is a BrowserWindow.
|
||||
mergeOptions(options, parentOptions);
|
||||
} else {
|
||||
// Or only inherit webPreferences if it is a webview.
|
||||
mergeOptions(options.webPreferences, embedder.getLastWebPreferences());
|
||||
}
|
||||
|
||||
// Inherit certain option values from parent window
|
||||
const webPreferences = embedder.getLastWebPreferences();
|
||||
for (const [name, value] of inheritedWebPreferences) {
|
||||
if ((webPreferences as any)[name] === value) {
|
||||
options.webPreferences[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!webPreferences.nativeWindowOpen) {
|
||||
// Sets correct openerId here to give correct options to 'new-window' event handler
|
||||
options.webPreferences.openerId = embedder.id;
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
const MULTIPART_CONTENT_TYPE = 'multipart/form-data';
|
||||
const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded';
|
||||
function makeContentTypeHeader ({ contentType, boundary }: { contentType: string, boundary?: string }) {
|
||||
const header = `content-type: ${contentType};`;
|
||||
if (contentType === MULTIPART_CONTENT_TYPE) {
|
||||
return `${header} boundary=${boundary}`;
|
||||
}
|
||||
return header;
|
||||
type PostData = LoadURLOptions['postData']
|
||||
export type WindowOpenArgs = {
|
||||
url: string,
|
||||
frameName: string,
|
||||
features: string,
|
||||
}
|
||||
|
||||
// Figure out appropriate headers for post data.
|
||||
const parseContentTypeFormat = function (postData: Electron.UploadRawData[]) {
|
||||
if (postData.length) {
|
||||
// For multipart forms, the first element will start with the boundary
|
||||
// notice, which looks something like `------WebKitFormBoundary12345678`
|
||||
// Note, this regex would fail when submitting a urlencoded form with an
|
||||
// input attribute of name="--theKey", but, uhh, don't do that?
|
||||
const postDataFront = postData[0].bytes.toString();
|
||||
const boundary = /^--.*[^-\r\n]/.exec(postDataFront);
|
||||
if (boundary) {
|
||||
return {
|
||||
boundary: boundary[0].substr(2),
|
||||
contentType: MULTIPART_CONTENT_TYPE
|
||||
};
|
||||
}
|
||||
}
|
||||
// Either the form submission didn't contain any inputs (the postData array
|
||||
// was empty), or we couldn't find the boundary and thus we can assume this is
|
||||
// a key=value style form.
|
||||
return {
|
||||
contentType: URL_ENCODED_CONTENT_TYPE
|
||||
};
|
||||
};
|
||||
const frameNamesToWindow = new Map<string, BrowserWindow>();
|
||||
const registerFrameNameToGuestWindow = (name: string, win: BrowserWindow) => frameNamesToWindow.set(name, win);
|
||||
const unregisterFrameName = (name: string) => frameNamesToWindow.delete(name);
|
||||
const getGuestWindowByFrameName = (name: string) => frameNamesToWindow.get(name);
|
||||
|
||||
// Setup a new guest with |embedder|
|
||||
const setupGuest = function (embedder: Electron.WebContents, frameName: string, guest: Electron.BrowserWindow) {
|
||||
// When |embedder| is destroyed we should also destroy attached guest, and if
|
||||
// guest is closed by user then we should prevent |embedder| from double
|
||||
// closing guest.
|
||||
const guestId = guest.webContents.id;
|
||||
/**
|
||||
* `openGuestWindow` is called for both implementations of window.open
|
||||
* (BrowserWindowProxy and nativeWindowOpen) to create and setup event handling
|
||||
* for the new window.
|
||||
*
|
||||
* Until its removal in 12.0.0, the `new-window` event is fired, allowing the
|
||||
* user to preventDefault() on the passed event (which ends up calling
|
||||
* DestroyWebContents in the nativeWindowOpen code path).
|
||||
*/
|
||||
export function openGuestWindow ({ event, embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs }: {
|
||||
event: { sender: WebContents, defaultPrevented: boolean },
|
||||
embedder: WebContents,
|
||||
guest?: WebContents,
|
||||
referrer: Referrer,
|
||||
disposition: string,
|
||||
postData?: PostData,
|
||||
overrideBrowserWindowOptions?: BrowserWindowConstructorOptions,
|
||||
windowOpenArgs: WindowOpenArgs,
|
||||
}): BrowserWindow | undefined {
|
||||
const { url, frameName, features } = windowOpenArgs;
|
||||
const isNativeWindowOpen = !!guest;
|
||||
const { options: browserWindowOptions, additionalFeatures } = makeBrowserWindowOptions({
|
||||
embedder,
|
||||
features,
|
||||
frameName,
|
||||
overrideOptions: overrideBrowserWindowOptions
|
||||
});
|
||||
|
||||
const didCancelEvent = emitDeprecatedNewWindowEvent({
|
||||
event,
|
||||
embedder,
|
||||
guest,
|
||||
browserWindowOptions,
|
||||
windowOpenArgs,
|
||||
additionalFeatures,
|
||||
disposition,
|
||||
referrer
|
||||
});
|
||||
if (didCancelEvent) return;
|
||||
|
||||
// To spec, subsequent window.open calls with the same frame name (`target` in
|
||||
// spec parlance) will reuse the previous window.
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#apis-for-creating-and-navigating-browsing-contexts-by-name
|
||||
const existingWindow = getGuestWindowByFrameName(frameName);
|
||||
if (existingWindow) {
|
||||
existingWindow.loadURL(url);
|
||||
return existingWindow;
|
||||
}
|
||||
|
||||
const window = new BrowserWindow({
|
||||
webContents: guest,
|
||||
...browserWindowOptions
|
||||
});
|
||||
if (!isNativeWindowOpen) {
|
||||
// We should only call `loadURL` if the webContents was constructed by us in
|
||||
// the case of BrowserWindowProxy (non-sandboxed, nativeWindowOpen: false),
|
||||
// as navigating to the url when creating the window from an existing
|
||||
// webContents is not necessary (it will navigate there anyway).
|
||||
window.loadURL(url, {
|
||||
httpReferrer: referrer,
|
||||
...(postData && {
|
||||
postData,
|
||||
extraHeaders: formatPostDataHeaders(postData)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleWindowLifecycleEvents({ embedder, frameName, guest: window });
|
||||
|
||||
embedder.emit('did-create-window', window, { url, frameName, options: browserWindowOptions, disposition, additionalFeatures, referrer, postData });
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the relationship between embedder window and guest window. When the
|
||||
* guest is destroyed, notify the embedder. When the embedder is destroyed, so
|
||||
* too is the guest destroyed; this is Electron convention and isn't based in
|
||||
* browser behavior.
|
||||
*/
|
||||
const handleWindowLifecycleEvents = function ({ embedder, guest, frameName }: {
|
||||
embedder: WebContents,
|
||||
guest: BrowserWindow,
|
||||
frameName: string
|
||||
}) {
|
||||
const closedByEmbedder = function () {
|
||||
guest.removeListener('closed', closedByUser);
|
||||
guest.destroy();
|
||||
};
|
||||
|
||||
const cachedGuestId = guest.webContents.id;
|
||||
const closedByUser = function () {
|
||||
embedder._sendInternal(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_CLOSED}_${guestId}`);
|
||||
embedder._sendInternal(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_CLOSED}_${cachedGuestId}`);
|
||||
embedder.removeListener('current-render-view-deleted' as any, closedByEmbedder);
|
||||
};
|
||||
embedder.once('current-render-view-deleted' as any, closedByEmbedder);
|
||||
guest.once('closed', closedByUser);
|
||||
|
||||
if (frameName) {
|
||||
frameToGuest.set(frameName, guest);
|
||||
guest.frameName = frameName;
|
||||
registerFrameNameToGuestWindow(frameName, guest);
|
||||
guest.once('closed', function () {
|
||||
frameToGuest.delete(frameName);
|
||||
unregisterFrameName(frameName);
|
||||
});
|
||||
}
|
||||
return guestId;
|
||||
};
|
||||
|
||||
// Create a new guest created by |embedder| with |options|.
|
||||
const createGuest = function (embedder: Electron.webContents, url: string, referrer: string | Electron.Referrer,
|
||||
frameName: string, options: Record<string, any>, postData?: Electron.UploadRawData[]) {
|
||||
let guest = frameToGuest.get(frameName);
|
||||
if (frameName && (guest != null)) {
|
||||
guest.loadURL(url);
|
||||
return guest.webContents.id;
|
||||
}
|
||||
|
||||
// Remember the embedder window's id.
|
||||
if (options.webPreferences == null) {
|
||||
options.webPreferences = {};
|
||||
}
|
||||
|
||||
guest = new BrowserWindow(options);
|
||||
if (!options.webContents) {
|
||||
// We should not call `loadURL` if the window was constructed from an
|
||||
// existing webContents (window.open in a sandboxed renderer).
|
||||
//
|
||||
// Navigating to the url when creating the window from an existing
|
||||
// webContents is not necessary (it will navigate there anyway).
|
||||
const loadOptions: Electron.LoadURLOptions = {
|
||||
httpReferrer: referrer
|
||||
};
|
||||
if (postData != null) {
|
||||
loadOptions.postData = postData;
|
||||
loadOptions.extraHeaders = makeContentTypeHeader(parseContentTypeFormat(postData));
|
||||
}
|
||||
guest.loadURL(url, loadOptions);
|
||||
}
|
||||
|
||||
return setupGuest(embedder, frameName, guest);
|
||||
};
|
||||
|
||||
const getGuestWindow = function (guestContents: Electron.WebContents) {
|
||||
let guestWindow = BrowserWindow.fromWebContents(guestContents);
|
||||
if (guestWindow == null) {
|
||||
const hostContents = guestContents.hostWebContents;
|
||||
if (hostContents != null) {
|
||||
guestWindow = BrowserWindow.fromWebContents(hostContents);
|
||||
}
|
||||
}
|
||||
if (!guestWindow) {
|
||||
throw new Error('getGuestWindow failed');
|
||||
}
|
||||
return guestWindow;
|
||||
};
|
||||
|
||||
const isChildWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
|
||||
return target.getLastWebPreferences().openerId === sender.id;
|
||||
};
|
||||
|
||||
const isRelatedWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
|
||||
return isChildWindow(sender, target) || isChildWindow(target, sender);
|
||||
};
|
||||
|
||||
const isScriptableWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
|
||||
return isRelatedWindow(sender, target) && isSameOrigin(sender.getURL(), target.getURL());
|
||||
};
|
||||
|
||||
const isNodeIntegrationEnabled = function (sender: Electron.WebContents) {
|
||||
return sender.getLastWebPreferences().nodeIntegration === true;
|
||||
};
|
||||
|
||||
// Checks whether |sender| can access the |target|:
|
||||
const canAccessWindow = function (sender: Electron.WebContents, target: Electron.WebContents) {
|
||||
return isChildWindow(sender, target) ||
|
||||
isScriptableWindow(sender, target) ||
|
||||
isNodeIntegrationEnabled(sender);
|
||||
};
|
||||
|
||||
// Routed window.open messages with raw options
|
||||
ipcMainInternal.on(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN, (event, url: string, frameName: string, features: string) => {
|
||||
// This should only be allowed for senders that have nativeWindowOpen: false
|
||||
const lastWebPreferences = event.sender.getLastWebPreferences();
|
||||
if (lastWebPreferences.nativeWindowOpen || lastWebPreferences.sandbox) {
|
||||
event.returnValue = null;
|
||||
throw new Error(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN} denied: expected native window.open`);
|
||||
}
|
||||
if (url == null || url === '') url = 'about:blank';
|
||||
if (frameName == null) frameName = '';
|
||||
if (features == null) features = '';
|
||||
|
||||
const disposition = 'new-window';
|
||||
const { options, webPreferences, additionalFeatures } = parseFeatures(features);
|
||||
if (!options.title) options.title = frameName;
|
||||
(options as Electron.BrowserWindowConstructorOptions).webPreferences = webPreferences;
|
||||
|
||||
const referrer: Electron.Referrer = { url: '', policy: 'default' };
|
||||
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures);
|
||||
});
|
||||
|
||||
// Routed window.open messages with fully parsed options
|
||||
export function internalWindowOpen (event: ElectronInternal.IpcMainInternalEvent, url: string, referrer: string | Electron.Referrer,
|
||||
frameName: string, disposition: string, options: Record<string, any>, additionalFeatures: string[], postData?: Electron.UploadRawData[]) {
|
||||
options = mergeBrowserWindowOptions(event.sender, options);
|
||||
/**
|
||||
* Deprecated in favor of `webContents.setWindowOpenHandler` and
|
||||
* `did-create-window` in 11.0.0. Will be removed in 12.0.0.
|
||||
*/
|
||||
function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, browserWindowOptions, additionalFeatures, disposition, referrer, postData }: {
|
||||
event: { sender: WebContents, defaultPrevented: boolean },
|
||||
embedder: WebContents,
|
||||
guest?: WebContents,
|
||||
windowOpenArgs: WindowOpenArgs,
|
||||
browserWindowOptions: BrowserWindowConstructorOptions,
|
||||
additionalFeatures: string[]
|
||||
disposition: string,
|
||||
referrer: Referrer,
|
||||
postData?: PostData,
|
||||
}): boolean {
|
||||
const { url, frameName } = windowOpenArgs;
|
||||
const isWebViewWithPopupsDisabled = embedder.getType() === 'webview' && (embedder as any).getLastWebPreferences().disablePopups;
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
...parseContentTypeFormat(postData)
|
||||
headers: formatPostDataHeaders(postData)
|
||||
} : null;
|
||||
|
||||
event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer, postBody);
|
||||
const { newGuest } = event as unknown as { newGuest: Electron.BrowserWindow };
|
||||
if ((event.sender.getType() === 'webview' && event.sender.getLastWebPreferences().disablePopups) || event.defaultPrevented) {
|
||||
if (newGuest != null) {
|
||||
if (options.webContents === newGuest.webContents) {
|
||||
// the webContents is not changed, so set defaultPrevented to false to
|
||||
embedder.emit(
|
||||
'new-window',
|
||||
event,
|
||||
url,
|
||||
frameName,
|
||||
disposition,
|
||||
{
|
||||
...browserWindowOptions,
|
||||
webContents: guest
|
||||
},
|
||||
additionalFeatures,
|
||||
referrer,
|
||||
postBody
|
||||
);
|
||||
|
||||
const { newGuest } = event as any;
|
||||
if (isWebViewWithPopupsDisabled) return true;
|
||||
if (event.defaultPrevented) {
|
||||
if (newGuest) {
|
||||
if (guest === newGuest.webContents) {
|
||||
// The webContents is not changed, so set defaultPrevented to false to
|
||||
// stop the callers of this event from destroying the webContents.
|
||||
(event as any).defaultPrevented = false;
|
||||
}
|
||||
event.returnValue = setupGuest(event.sender, frameName, newGuest);
|
||||
} else {
|
||||
event.returnValue = null;
|
||||
|
||||
handleWindowLifecycleEvents({
|
||||
embedder: event.sender,
|
||||
guest: newGuest,
|
||||
frameName
|
||||
});
|
||||
}
|
||||
} else {
|
||||
event.returnValue = createGuest(event.sender, url, referrer, frameName, options, postData);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const makeSafeHandler = function<Event> (handler: (event: Event, guestContents: Electron.webContents, ...args: any[]) => any) {
|
||||
return (event: Event, guestId: number, ...args: any[]) => {
|
||||
// Access webContents via electron to prevent circular require.
|
||||
const guestContents = electron.webContents.fromId(guestId);
|
||||
if (!guestContents) {
|
||||
throw new Error(`Invalid guestId: ${guestId}`);
|
||||
// Security options that child windows will always inherit from parent windows
|
||||
const securityWebPreferences: { [key: string]: boolean } = {
|
||||
contextIsolation: true,
|
||||
javascript: false,
|
||||
nativeWindowOpen: true,
|
||||
nodeIntegration: false,
|
||||
enableRemoteModule: false,
|
||||
sandbox: true,
|
||||
webviewTag: false,
|
||||
nodeIntegrationInSubFrames: false,
|
||||
enableWebSQL: false
|
||||
};
|
||||
|
||||
function makeBrowserWindowOptions ({ embedder, features, frameName, overrideOptions, useDeprecatedBehaviorForBareValues = true, useDeprecatedBehaviorForOptionInheritance = true }: {
|
||||
embedder: WebContents,
|
||||
features: string,
|
||||
frameName: string,
|
||||
overrideOptions?: BrowserWindowConstructorOptions,
|
||||
useDeprecatedBehaviorForBareValues?: boolean
|
||||
useDeprecatedBehaviorForOptionInheritance?: boolean
|
||||
}) {
|
||||
const { options: parsedOptions, webPreferences: parsedWebPreferences, additionalFeatures } = parseFeatures(features, useDeprecatedBehaviorForBareValues);
|
||||
|
||||
const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder);
|
||||
|
||||
return {
|
||||
additionalFeatures,
|
||||
options: {
|
||||
...(useDeprecatedBehaviorForOptionInheritance && deprecatedInheritedOptions),
|
||||
show: true,
|
||||
title: frameName,
|
||||
width: 800,
|
||||
height: 600,
|
||||
...parsedOptions,
|
||||
...overrideOptions,
|
||||
webPreferences: makeWebPreferences({ embedder, insecureParsedWebPreferences: parsedWebPreferences, secureOverrideWebPreferences: overrideOptions && overrideOptions.webPreferences, useDeprecatedBehaviorForOptionInheritance: true })
|
||||
}
|
||||
|
||||
return handler(event, guestContents, ...args);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const handleMessage = function (channel: string, handler: (event: Electron.IpcMainInvokeEvent, guestContents: Electron.webContents, ...args: any[]) => any) {
|
||||
ipcMainInternal.handle(channel, makeSafeHandler(handler));
|
||||
};
|
||||
export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {}, insecureParsedWebPreferences: parsedWebPreferences = {}, useDeprecatedBehaviorForOptionInheritance = true }: {
|
||||
embedder: WebContents,
|
||||
insecureParsedWebPreferences?: ReturnType<typeof parseFeatures>['webPreferences'],
|
||||
// Note that override preferences are considered elevated, and should only be
|
||||
// sourced from the main process, as they override security defaults. If you
|
||||
// have unvetted prefs, use parsedWebPreferences.
|
||||
secureOverrideWebPreferences?: BrowserWindowConstructorOptions['webPreferences'],
|
||||
useDeprecatedBehaviorForBareValues?: boolean
|
||||
useDeprecatedBehaviorForOptionInheritance?: boolean
|
||||
}) {
|
||||
const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder);
|
||||
const parentWebPreferences = (embedder as any).getLastWebPreferences();
|
||||
const securityWebPreferencesFromParent = Object.keys(securityWebPreferences).reduce((map, key) => {
|
||||
if (securityWebPreferences[key] === parentWebPreferences[key]) {
|
||||
map[key] = parentWebPreferences[key];
|
||||
}
|
||||
return map;
|
||||
}, {} as any);
|
||||
const openerId = parentWebPreferences.nativeWindowOpen ? null : embedder.id;
|
||||
|
||||
const handleMessageSync = function (channel: string, handler: (event: ElectronInternal.IpcMainInternalEvent, guestContents: Electron.webContents, ...args: any[]) => any) {
|
||||
ipcMainUtils.handleSync(channel, makeSafeHandler(handler));
|
||||
};
|
||||
return {
|
||||
...(useDeprecatedBehaviorForOptionInheritance && deprecatedInheritedOptions ? deprecatedInheritedOptions.webPreferences : null),
|
||||
...parsedWebPreferences,
|
||||
// Note that order is key here, we want to disallow the renderer's
|
||||
// ability to change important security options but allow main (via
|
||||
// setWindowOpenHandler) to change them.
|
||||
...securityWebPreferencesFromParent,
|
||||
...secureOverrideWebPreferences,
|
||||
// Sets correct openerId here to give correct options to 'new-window' event handler
|
||||
// TODO: Figure out another way to pass this?
|
||||
openerId
|
||||
};
|
||||
}
|
||||
|
||||
const securityCheck = function (contents: Electron.WebContents, guestContents: Electron.WebContents, check: (sender: Electron.WebContents, target: Electron.WebContents) => boolean) {
|
||||
if (!check(contents, guestContents)) {
|
||||
console.error(`Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}`);
|
||||
throw new Error(`Access denied to guestId: ${guestContents.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const windowMethods = new Set([
|
||||
'destroy',
|
||||
'focus',
|
||||
'blur'
|
||||
]);
|
||||
|
||||
handleMessage(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_METHOD, (event, guestContents, method: string, ...args: any[]) => {
|
||||
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||
|
||||
if (!windowMethods.has(method)) {
|
||||
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
/**
|
||||
* Current Electron behavior is to inherit all options from the parent window.
|
||||
* In practical use, this is kind of annoying because consumers have to know
|
||||
* about the parent window's preferences in order to unset them and makes child
|
||||
* windows even more of an anomaly. In 11.0.0 we will remove this behavior and
|
||||
* only critical security preferences will be inherited by default.
|
||||
*/
|
||||
function getDeprecatedInheritedOptions (embedder: WebContents) {
|
||||
if (!(embedder as any).browserWindowOptions) {
|
||||
// If it's a webview, return just the webPreferences.
|
||||
return {
|
||||
webPreferences: (embedder as any).getLastWebPreferences()
|
||||
};
|
||||
}
|
||||
|
||||
return (getGuestWindow(guestContents) as any)[method](...args);
|
||||
});
|
||||
const { type, show, ...inheritableOptions } = (embedder as any).browserWindowOptions;
|
||||
return inheritableOptions;
|
||||
}
|
||||
|
||||
handleMessage(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE, (event, guestContents, message, targetOrigin, sourceOrigin) => {
|
||||
if (targetOrigin == null) {
|
||||
targetOrigin = '*';
|
||||
function formatPostDataHeaders (postData: any) {
|
||||
if (!postData) return;
|
||||
|
||||
let extraHeaders = 'content-type: application/x-www-form-urlencoded';
|
||||
|
||||
if (postData.length > 0) {
|
||||
const postDataFront = postData[0].bytes.toString();
|
||||
const boundary = /^--.*[^-\r\n]/.exec(
|
||||
postDataFront
|
||||
);
|
||||
if (boundary != null) {
|
||||
extraHeaders = `content-type: multipart/form-data; boundary=${boundary[0].substr(
|
||||
2
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// The W3C does not seem to have word on how postMessage should work when the
|
||||
// origins do not match, so we do not do |canAccessWindow| check here since
|
||||
// postMessage across origins is useful and not harmful.
|
||||
securityCheck(event.sender, guestContents, isRelatedWindow);
|
||||
|
||||
if (targetOrigin === '*' || isSameOrigin(guestContents.getURL(), targetOrigin)) {
|
||||
const sourceId = event.sender.id;
|
||||
guestContents._sendInternal(IPC_MESSAGES.GUEST_WINDOW_POSTMESSAGE, sourceId, message, sourceOrigin);
|
||||
}
|
||||
});
|
||||
|
||||
const webContentsMethodsAsync = new Set([
|
||||
'loadURL',
|
||||
'executeJavaScript',
|
||||
'print'
|
||||
]);
|
||||
|
||||
handleMessage(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, (event, guestContents, method: string, ...args: any[]) => {
|
||||
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||
|
||||
if (!webContentsMethodsAsync.has(method)) {
|
||||
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
}
|
||||
|
||||
return (guestContents as any)[method](...args);
|
||||
});
|
||||
|
||||
const webContentsMethodsSync = new Set([
|
||||
'getURL'
|
||||
]);
|
||||
|
||||
handleMessageSync(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, (event, guestContents, method: string, ...args: any[]) => {
|
||||
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||
|
||||
if (!webContentsMethodsSync.has(method)) {
|
||||
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
}
|
||||
|
||||
return (guestContents as any)[method](...args);
|
||||
});
|
||||
return extraHeaders;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
/**
|
||||
* Manage guest windows when using the default BrowserWindowProxy version of the
|
||||
* renderer's window.open (i.e. nativeWindowOpen off). This module mostly
|
||||
* consists of marshaling IPC requests from the BrowserWindowProxy to the
|
||||
* WebContents.
|
||||
*/
|
||||
import { webContents, BrowserWindow } from 'electron/main';
|
||||
import type { WebContents } from 'electron/main';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
import { openGuestWindow } from '@electron/internal/browser/guest-window-manager';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { isSameOrigin } = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
const getGuestWindow = function (guestContents: WebContents) {
|
||||
let guestWindow = BrowserWindow.fromWebContents(guestContents);
|
||||
if (guestWindow == null) {
|
||||
const hostContents = guestContents.hostWebContents;
|
||||
if (hostContents != null) {
|
||||
guestWindow = BrowserWindow.fromWebContents(hostContents);
|
||||
}
|
||||
}
|
||||
if (!guestWindow) {
|
||||
throw new Error('getGuestWindow failed');
|
||||
}
|
||||
return guestWindow;
|
||||
};
|
||||
|
||||
const isChildWindow = function (sender: WebContents, target: WebContents) {
|
||||
return (target as any).getLastWebPreferences().openerId === sender.id;
|
||||
};
|
||||
|
||||
const isRelatedWindow = function (sender: WebContents, target: WebContents) {
|
||||
return isChildWindow(sender, target) || isChildWindow(target, sender);
|
||||
};
|
||||
|
||||
const isScriptableWindow = function (sender: WebContents, target: WebContents) {
|
||||
return (
|
||||
isRelatedWindow(sender, target) &&
|
||||
isSameOrigin(sender.getURL(), target.getURL())
|
||||
);
|
||||
};
|
||||
|
||||
const isNodeIntegrationEnabled = function (sender: WebContents) {
|
||||
return (sender as any).getLastWebPreferences().nodeIntegration === true;
|
||||
};
|
||||
|
||||
// Checks whether |sender| can access the |target|:
|
||||
const canAccessWindow = function (sender: WebContents, target: WebContents) {
|
||||
return (
|
||||
isChildWindow(sender, target) ||
|
||||
isScriptableWindow(sender, target) ||
|
||||
isNodeIntegrationEnabled(sender)
|
||||
);
|
||||
};
|
||||
|
||||
// Routed window.open messages with raw options
|
||||
ipcMainInternal.on(
|
||||
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN,
|
||||
(
|
||||
event,
|
||||
url: string,
|
||||
frameName: string,
|
||||
features: string
|
||||
) => {
|
||||
// This should only be allowed for senders that have nativeWindowOpen: false
|
||||
const lastWebPreferences = (event.sender as any).getLastWebPreferences();
|
||||
if (lastWebPreferences.nativeWindowOpen || lastWebPreferences.sandbox) {
|
||||
(event as any).returnValue = null;
|
||||
throw new Error(
|
||||
'GUEST_WINDOW_MANAGER_WINDOW_OPEN denied: expected native window.open'
|
||||
);
|
||||
}
|
||||
|
||||
const browserWindowOptions = (event.sender as any)._callWindowOpenHandler(event, url, frameName, features);
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
const guest = openGuestWindow({
|
||||
event,
|
||||
embedder: event.sender,
|
||||
referrer: { url: '', policy: 'default' },
|
||||
disposition: 'new-window',
|
||||
overrideBrowserWindowOptions: browserWindowOptions,
|
||||
windowOpenArgs: {
|
||||
url: url || 'about:blank',
|
||||
frameName: frameName || '',
|
||||
features: features || ''
|
||||
}
|
||||
});
|
||||
|
||||
(event as any).returnValue = guest ? guest.webContents.id : null;
|
||||
}
|
||||
);
|
||||
|
||||
type IpcHandler<T, Event> = (event: Event, guestContents: Electron.WebContents, ...args: any[]) => T;
|
||||
const makeSafeHandler = function<T, Event> (handler: IpcHandler<T, Event>) {
|
||||
return (event: Event, guestId: number, ...args: any[]) => {
|
||||
// Access webContents via electron to prevent circular require.
|
||||
const guestContents = webContents.fromId(guestId);
|
||||
if (!guestContents) {
|
||||
throw new Error(`Invalid guestId: ${guestId}`);
|
||||
}
|
||||
|
||||
return handler(event, guestContents as Electron.WebContents, ...args);
|
||||
};
|
||||
};
|
||||
|
||||
const handleMessage = function (channel: string, handler: IpcHandler<any, Electron.IpcMainInvokeEvent>) {
|
||||
ipcMainInternal.handle(channel, makeSafeHandler(handler));
|
||||
};
|
||||
|
||||
const handleMessageSync = function (channel: string, handler: IpcHandler<any, ElectronInternal.IpcMainInternalEvent>) {
|
||||
ipcMainUtils.handleSync(channel, makeSafeHandler(handler));
|
||||
};
|
||||
|
||||
type ContentsCheck = (contents: WebContents, guestContents: WebContents) => boolean;
|
||||
const securityCheck = function (contents: WebContents, guestContents: WebContents, check: ContentsCheck) {
|
||||
if (!check(contents, guestContents)) {
|
||||
console.error(
|
||||
`Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}`
|
||||
);
|
||||
throw new Error(`Access denied to guestId: ${guestContents.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const windowMethods = new Set(['destroy', 'focus', 'blur']);
|
||||
|
||||
handleMessage(
|
||||
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_METHOD,
|
||||
(event, guestContents, method, ...args) => {
|
||||
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||
|
||||
if (!windowMethods.has(method)) {
|
||||
console.error(
|
||||
`Blocked ${event.sender.getURL()} from calling method: ${method}`
|
||||
);
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
}
|
||||
|
||||
return (getGuestWindow(guestContents) as any)[method](...args);
|
||||
}
|
||||
);
|
||||
|
||||
handleMessage(
|
||||
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE,
|
||||
(event, guestContents, message, targetOrigin, sourceOrigin) => {
|
||||
if (targetOrigin == null) {
|
||||
targetOrigin = '*';
|
||||
}
|
||||
|
||||
// The W3C does not seem to have word on how postMessage should work when the
|
||||
// origins do not match, so we do not do |canAccessWindow| check here since
|
||||
// postMessage across origins is useful and not harmful.
|
||||
securityCheck(event.sender, guestContents, isRelatedWindow);
|
||||
|
||||
if (
|
||||
targetOrigin === '*' ||
|
||||
isSameOrigin(guestContents.getURL(), targetOrigin)
|
||||
) {
|
||||
const sourceId = event.sender.id;
|
||||
guestContents._sendInternal(
|
||||
IPC_MESSAGES.GUEST_WINDOW_POSTMESSAGE,
|
||||
sourceId,
|
||||
message,
|
||||
sourceOrigin
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const webContentsMethodsAsync = new Set([
|
||||
'loadURL',
|
||||
'executeJavaScript',
|
||||
'print'
|
||||
]);
|
||||
|
||||
handleMessage(
|
||||
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD,
|
||||
(event, guestContents, method, ...args) => {
|
||||
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||
|
||||
if (!webContentsMethodsAsync.has(method)) {
|
||||
console.error(
|
||||
`Blocked ${event.sender.getURL()} from calling method: ${method}`
|
||||
);
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
}
|
||||
|
||||
return (guestContents as any)[method](...args);
|
||||
}
|
||||
);
|
||||
|
||||
const webContentsMethodsSync = new Set(['getURL']);
|
||||
|
||||
handleMessageSync(
|
||||
IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD,
|
||||
(event, guestContents, method, ...args) => {
|
||||
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||
|
||||
if (!webContentsMethodsSync.has(method)) {
|
||||
console.error(
|
||||
`Blocked ${event.sender.getURL()} from calling method: ${method}`
|
||||
);
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
}
|
||||
|
||||
return (guestContents as any)[method](...args);
|
||||
}
|
||||
);
|
|
@ -76,7 +76,7 @@ require('@electron/internal/browser/rpc-server');
|
|||
|
||||
// Load the guest view manager.
|
||||
require('@electron/internal/browser/guest-view-manager');
|
||||
require('@electron/internal/browser/guest-window-manager');
|
||||
require('@electron/internal/browser/guest-window-proxy');
|
||||
|
||||
// Now we try to load app's package.json.
|
||||
let packagePath = null;
|
||||
|
|
|
@ -123,11 +123,13 @@ export class NavigationController extends EventEmitter {
|
|||
this.webContents.removeListener('did-fail-load', failListener);
|
||||
this.webContents.removeListener('did-start-navigation', navigationListener);
|
||||
this.webContents.removeListener('did-stop-loading', stopLoadingListener);
|
||||
this.webContents.removeListener('destroyed', stopLoadingListener);
|
||||
};
|
||||
this.webContents.on('did-finish-load', finishListener);
|
||||
this.webContents.on('did-fail-load', failListener);
|
||||
this.webContents.on('did-start-navigation', navigationListener);
|
||||
this.webContents.on('did-stop-loading', stopLoadingListener);
|
||||
this.webContents.on('destroyed', stopLoadingListener);
|
||||
});
|
||||
// Add a no-op rejection handler to silence the unhandled rejection error.
|
||||
p.catch(() => {});
|
||||
|
|
|
@ -81,7 +81,7 @@ type AllowedWebPreference = (typeof allowedWebPreferences)[number];
|
|||
/**
|
||||
* Parses a feature string that has the format used in window.open().
|
||||
*
|
||||
* `useSoonToBeDeprecatedBehaviorForBareKeys` — In the html spec, windowFeatures keys
|
||||
* `useSoonToBeDeprecatedBehaviorForBareKeys` - In the html spec, windowFeatures keys
|
||||
* without values are interpreted as `true`. Previous versions of Electron did
|
||||
* not respect this. In order to not break any applications, this will be
|
||||
* flipped in the next major version.
|
||||
|
@ -103,7 +103,7 @@ export function parseFeatures (
|
|||
if (parsed.top !== undefined) parsed.y = parsed.top;
|
||||
|
||||
return {
|
||||
options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'> & { [key: string]: CoercedValue },
|
||||
options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'>,
|
||||
webPreferences,
|
||||
additionalFeatures: bareKeys
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
|
||||
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
|
||||
const binding = process._linkedBinding('electron_renderer_context_bridge');
|
||||
|
||||
const contextIsolationEnabled = hasSwitch('context-isolation');
|
||||
const contextIsolationEnabled = getWebPreference(window, 'contextIsolation');
|
||||
|
||||
const checkContextIsolationEnabled = () => {
|
||||
if (!contextIsolationEnabled) throw new Error('contextBridge API can only be used when contextIsolation is enabled');
|
||||
|
|
|
@ -55,31 +55,33 @@ webFrameInit();
|
|||
|
||||
// Process command line arguments.
|
||||
const { hasSwitch, getSwitchValue } = process._linkedBinding('electron_common_command_line');
|
||||
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
|
||||
|
||||
const parseOption = function<T> (
|
||||
name: string, defaultValue: T, converter?: (value: string) => T
|
||||
const parseOption = function<TDefault> (
|
||||
name: string, defaultValue: TDefault, converter?: (value: string) => any
|
||||
) {
|
||||
return hasSwitch(name)
|
||||
const value = getWebPreference(window, name);
|
||||
return value
|
||||
? (
|
||||
converter
|
||||
? converter(getSwitchValue(name))
|
||||
: getSwitchValue(name)
|
||||
? converter(value)
|
||||
: value
|
||||
)
|
||||
: defaultValue;
|
||||
};
|
||||
|
||||
const contextIsolation = hasSwitch('context-isolation');
|
||||
const nodeIntegration = hasSwitch('node-integration');
|
||||
const webviewTag = hasSwitch('webview-tag');
|
||||
const isHiddenPage = hasSwitch('hidden-page');
|
||||
const usesNativeWindowOpen = hasSwitch('native-window-open');
|
||||
const rendererProcessReuseEnabled = hasSwitch('disable-electron-site-instance-overrides');
|
||||
const contextIsolation = getWebPreference(window, 'contextIsolation');
|
||||
const nodeIntegration = getWebPreference(window, 'nodeIntegration');
|
||||
const webviewTag = getWebPreference(window, 'webviewTag');
|
||||
const isHiddenPage = getWebPreference(window, 'hiddenPage');
|
||||
const usesNativeWindowOpen = getWebPreference(window, 'nativeWindowOpen');
|
||||
const rendererProcessReuseEnabled = getWebPreference(window, 'disableElectronSiteInstanceOverrides');
|
||||
|
||||
const preloadScript = parseOption('preload', null);
|
||||
const preloadScripts = parseOption('preload-scripts', [], value => value.split(path.delimiter)) as string[];
|
||||
const appPath = parseOption('app-path', null);
|
||||
const guestInstanceId = parseOption('guest-instance-id', null, value => parseInt(value));
|
||||
const openerId = parseOption('opener-id', null, value => parseInt(value));
|
||||
const preloadScripts = parseOption('preloadScripts', []);
|
||||
const guestInstanceId = parseOption('guestInstanceId', null, value => parseInt(value));
|
||||
const openerId = parseOption('openerId', null, value => parseInt(value));
|
||||
const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null;
|
||||
|
||||
// The webContents preload script is loaded after the session preload scripts.
|
||||
if (preloadScript) {
|
||||
|
|
|
@ -114,6 +114,7 @@ function preloadRequire (module: string) {
|
|||
|
||||
// Process command line arguments.
|
||||
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
|
||||
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
|
||||
|
||||
// Similar to nodes --expose-internals flag, this exposes _linkedBinding so
|
||||
// that tests can call it to get access to some test only bindings
|
||||
|
@ -121,9 +122,9 @@ if (hasSwitch('unsafely-expose-electron-internals-for-testing')) {
|
|||
preloadProcess._linkedBinding = process._linkedBinding;
|
||||
}
|
||||
|
||||
const contextIsolation = hasSwitch('context-isolation');
|
||||
const isHiddenPage = hasSwitch('hidden-page');
|
||||
const rendererProcessReuseEnabled = hasSwitch('disable-electron-site-instance-overrides');
|
||||
const contextIsolation = getWebPreference(window, 'contextIsolation');
|
||||
const isHiddenPage = getWebPreference(window, 'hiddenPage');
|
||||
const rendererProcessReuseEnabled = getWebPreference(window, 'disableElectronSiteInstanceOverrides');
|
||||
const usesNativeWindowOpen = true;
|
||||
|
||||
switch (window.location.protocol) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
"@electron/docs-parser": "^0.10.0",
|
||||
"@electron/docs-parser": "^0.10.1",
|
||||
"@electron/typescript-definitions": "^8.8.0",
|
||||
"@octokit/auth-app": "^2.10.0",
|
||||
"@octokit/rest": "^18.0.3",
|
||||
|
@ -148,4 +148,4 @@
|
|||
"@types/temp": "^0.8.34",
|
||||
"aws-sdk": "^2.727.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ feat_allow_embedders_to_add_observers_on_created_hunspell.patch
|
|||
feat_add_onclose_to_messageport.patch
|
||||
web_contents.patch
|
||||
ui_gtk_public_header.patch
|
||||
allow_in_process_windows_to_have_different_web_prefs.patch
|
||||
refactor_expose_cursor_changes_to_the_webcontentsobserver.patch
|
||||
crash_allow_setting_more_options.patch
|
||||
breakpad_treat_node_processes_as_browser_processes.patch
|
||||
|
@ -97,6 +98,7 @@ remove_some_deps_that_do_not_work_on_arm64.patch
|
|||
fix_check_issecureeventinputenabled_in_constructor_before_setting.patch
|
||||
skip_atk_toolchain_check.patch
|
||||
worker_feat_add_hook_to_notify_script_ready.patch
|
||||
chore_provide_iswebcontentscreationoverridden_with_full_params.patch
|
||||
fix_properly_honor_printing_page_ranges.patch
|
||||
fix_use_electron_generated_resources.patch
|
||||
chore_expose_v8_initialization_isolate_callbacks.patch
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Locascio <andy@slack-corp.com>
|
||||
Date: Wed, 6 May 2020 16:37:54 -0700
|
||||
Subject: allow in-process windows to have different web prefs
|
||||
|
||||
Allow earlier access to newly created WebContents so that we can change
|
||||
WebPreferences of in-process child windows, rather than relying on
|
||||
process-level command line switches, as before.
|
||||
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
index 1e51bb68df930c44e165b32c8c03b99986792209..9535330e3e7a3c4621e96eadbf90f4da2bf2daf0 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
@@ -143,6 +143,29 @@ WebPreferences::WebPreferences()
|
||||
navigate_on_drag_drop(true),
|
||||
v8_cache_options(blink::mojom::V8CacheOptions::kDefault),
|
||||
record_whole_document(false),
|
||||
+
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ disable_electron_site_instance_overrides(),
|
||||
+ background_color(base::EmptyString()),
|
||||
+ opener_id(0),
|
||||
+ context_isolation(false),
|
||||
+ enable_remote_module(false),
|
||||
+ world_safe_execute_javascript(false),
|
||||
+ guest_instance_id(0),
|
||||
+ hidden_page(false),
|
||||
+ offscreen(false),
|
||||
+ preload(base::FilePath::StringType()),
|
||||
+ native_window_open(false),
|
||||
+ node_integration(false),
|
||||
+ node_integration_in_worker(false),
|
||||
+ node_leakage_in_renderers(false),
|
||||
+ node_integration_in_sub_frames(false),
|
||||
+ enable_spellcheck(false),
|
||||
+ enable_plugins(false),
|
||||
+ enable_websql(false),
|
||||
+ webview_tag(false),
|
||||
+ // End Electron-specific WebPreferences.
|
||||
+
|
||||
cookie_enabled(true),
|
||||
accelerated_video_decode_enabled(false),
|
||||
animation_policy(
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
index 912c1bf5919bc657a4903d3fbca60c1013aa9d98..b3759ab22c071ad94062f6c3f7c24920ba3cde47 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
@@ -144,6 +144,11 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
!data.ReadCursiveFontFamilyMap(&out->cursive_font_family_map) ||
|
||||
!data.ReadFantasyFontFamilyMap(&out->fantasy_font_family_map) ||
|
||||
!data.ReadPictographFontFamilyMap(&out->pictograph_font_family_map) ||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ !data.ReadPreloads(&out->preloads) ||
|
||||
+ !data.ReadBackgroundColor(&out->background_color) ||
|
||||
+ !data.ReadPreload(&out->preload) ||
|
||||
+ // End Electron-specific WebPreferences.
|
||||
!data.ReadLazyFrameLoadingDistanceThresholdsPx(
|
||||
&out->lazy_frame_loading_distance_thresholds_px) ||
|
||||
!data.ReadLazyImageLoadingDistanceThresholdsPx(
|
||||
@@ -267,6 +272,27 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
out->navigate_on_drag_drop = data.navigate_on_drag_drop();
|
||||
out->v8_cache_options = data.v8_cache_options();
|
||||
out->record_whole_document = data.record_whole_document();
|
||||
+
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ out->disable_electron_site_instance_overrides = data.disable_electron_site_instance_overrides();
|
||||
+ out->opener_id = data.opener_id();
|
||||
+ out->context_isolation = data.context_isolation();
|
||||
+ out->enable_remote_module = data.enable_remote_module();
|
||||
+ out->world_safe_execute_javascript = data.world_safe_execute_javascript();
|
||||
+ out->guest_instance_id = data.guest_instance_id();
|
||||
+ out->hidden_page = data.hidden_page();
|
||||
+ out->offscreen = data.offscreen();
|
||||
+ out->native_window_open = data.native_window_open();
|
||||
+ out->node_integration = data.node_integration();
|
||||
+ out->node_integration_in_worker = data.node_integration_in_worker();
|
||||
+ out->node_leakage_in_renderers = data.node_leakage_in_renderers();
|
||||
+ out->node_integration_in_sub_frames = data.node_integration_in_sub_frames();
|
||||
+ out->enable_spellcheck = data.enable_spellcheck();
|
||||
+ out->enable_plugins = data.enable_plugins();
|
||||
+ out->enable_websql = data.enable_websql();
|
||||
+ out->webview_tag = data.webview_tag();
|
||||
+ // End Electron-specific WebPreferences.
|
||||
+
|
||||
out->cookie_enabled = data.cookie_enabled();
|
||||
out->accelerated_video_decode_enabled =
|
||||
data.accelerated_video_decode_enabled();
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
index 81e4729f540ff272a43c77045187fe3d4bde3ea0..3a2c60f7616f724d3a0399f7fe8becae60d6ae88 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
+#include "base/files/file_path.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
@@ -154,6 +155,29 @@ struct BLINK_COMMON_EXPORT WebPreferences {
|
||||
blink::mojom::V8CacheOptions v8_cache_options;
|
||||
bool record_whole_document;
|
||||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ std::vector<base::FilePath> preloads;
|
||||
+ bool disable_electron_site_instance_overrides;
|
||||
+ std::string background_color;
|
||||
+ int opener_id;
|
||||
+ bool context_isolation;
|
||||
+ bool enable_remote_module;
|
||||
+ bool world_safe_execute_javascript;
|
||||
+ int guest_instance_id;
|
||||
+ bool hidden_page;
|
||||
+ bool offscreen;
|
||||
+ base::FilePath preload;
|
||||
+ bool native_window_open;
|
||||
+ bool node_integration;
|
||||
+ bool node_integration_in_worker;
|
||||
+ bool node_leakage_in_renderers;
|
||||
+ bool node_integration_in_sub_frames;
|
||||
+ bool enable_spellcheck;
|
||||
+ bool enable_plugins;
|
||||
+ bool enable_websql;
|
||||
+ bool webview_tag;
|
||||
+ // End Electron-specific WebPreferences.
|
||||
+
|
||||
// This flags corresponds to a Page's Settings' setCookieEnabled state. It
|
||||
// only controls whether or not the "document.cookie" field is properly
|
||||
// connected to the backing store, for instance if you wanted to be able to
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
index 74b22fbaad5c8ae911dca4b26bbfffd8e9079856..decef06a6d0cda2da8aa3c88d589dbff75ff369e 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
@@ -6,6 +6,7 @@
|
||||
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_WEB_PREFERENCES_WEB_PREFERENCES_MOJOM_TRAITS_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
+#include "mojo/public/cpp/base/file_path_mojom_traits.h"
|
||||
#include "mojo/public/cpp/bindings/struct_traits.h"
|
||||
#include "net/nqe/effective_connection_type.h"
|
||||
#include "third_party/blink/public/common/common_export.h"
|
||||
@@ -452,6 +453,88 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
return r.record_whole_document;
|
||||
}
|
||||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ static const std::vector<base::FilePath>& preloads(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.preloads;
|
||||
+ }
|
||||
+
|
||||
+ static bool disable_electron_site_instance_overrides(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.disable_electron_site_instance_overrides;
|
||||
+ }
|
||||
+
|
||||
+ static const std::string& background_color(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.background_color;
|
||||
+ }
|
||||
+
|
||||
+ static int opener_id(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.opener_id;
|
||||
+ }
|
||||
+
|
||||
+ static bool context_isolation(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.context_isolation;
|
||||
+ }
|
||||
+
|
||||
+ static bool enable_remote_module(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.enable_remote_module;
|
||||
+ }
|
||||
+
|
||||
+ static bool world_safe_execute_javascript(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.world_safe_execute_javascript;
|
||||
+ }
|
||||
+
|
||||
+ static int guest_instance_id(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.guest_instance_id;
|
||||
+ }
|
||||
+
|
||||
+ static bool hidden_page(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.hidden_page;
|
||||
+ }
|
||||
+
|
||||
+ static bool offscreen(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.offscreen;
|
||||
+ }
|
||||
+
|
||||
+ static const base::FilePath& preload(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.preload;
|
||||
+ }
|
||||
+
|
||||
+ static bool native_window_open(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.native_window_open;
|
||||
+ }
|
||||
+
|
||||
+ static bool node_integration(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.node_integration;
|
||||
+ }
|
||||
+
|
||||
+ static bool node_integration_in_worker(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.node_integration_in_worker;
|
||||
+ }
|
||||
+
|
||||
+ static bool node_leakage_in_renderers(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.node_leakage_in_renderers;
|
||||
+ }
|
||||
+
|
||||
+ static bool node_integration_in_sub_frames(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.node_integration_in_sub_frames;
|
||||
+ }
|
||||
+
|
||||
+ static bool enable_spellcheck(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.enable_spellcheck;
|
||||
+ }
|
||||
+
|
||||
+ static bool enable_plugins(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.enable_plugins;
|
||||
+ }
|
||||
+
|
||||
+ static bool enable_websql(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.enable_websql;
|
||||
+ }
|
||||
+
|
||||
+ static bool webview_tag(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.webview_tag;
|
||||
+ }
|
||||
+ // End Electron-specific WebPreferences.
|
||||
+
|
||||
static bool cookie_enabled(const blink::web_pref::WebPreferences& r) {
|
||||
return r.cookie_enabled;
|
||||
}
|
||||
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
index ac1099c8fb923184a014bf9cbaa35c496cf85cd9..688ea93b1d067555b7b48165ba7a33625f9d597f 100644
|
||||
--- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
+++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
@@ -8,6 +8,7 @@ import "third_party/blink/public/mojom/css/preferred_color_scheme.mojom";
|
||||
import "third_party/blink/public/mojom/v8_cache_options.mojom";
|
||||
import "url/mojom/url.mojom";
|
||||
import "mojo/public/mojom/base/string16.mojom";
|
||||
+import "mojo/public/mojom/base/file_path.mojom";
|
||||
|
||||
enum PointerType {
|
||||
kPointerFirstType = 1, // 1 << 0
|
||||
@@ -202,6 +203,29 @@ struct WebPreferences {
|
||||
V8CacheOptions v8_cache_options;
|
||||
bool record_whole_document;
|
||||
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ array<mojo_base.mojom.FilePath> preloads;
|
||||
+ bool disable_electron_site_instance_overrides;
|
||||
+ string background_color;
|
||||
+ int32 opener_id;
|
||||
+ bool context_isolation;
|
||||
+ bool enable_remote_module;
|
||||
+ bool world_safe_execute_javascript;
|
||||
+ int32 guest_instance_id;
|
||||
+ bool hidden_page;
|
||||
+ bool offscreen;
|
||||
+ mojo_base.mojom.FilePath preload;
|
||||
+ bool native_window_open;
|
||||
+ bool node_integration;
|
||||
+ bool node_integration_in_worker;
|
||||
+ bool node_leakage_in_renderers;
|
||||
+ bool node_integration_in_sub_frames;
|
||||
+ bool enable_spellcheck;
|
||||
+ bool enable_plugins;
|
||||
+ bool enable_websql;
|
||||
+ bool webview_tag;
|
||||
+ // End Electron-specific WebPreferences.
|
||||
+
|
||||
// This flags corresponds to a Page's Settings' setCookieEnabled state. It
|
||||
// only controls whether or not the "document.cookie" field is properly
|
||||
// connected to the backing store, for instance if you wanted to be able to
|
||||
@@ -428,4 +452,4 @@ struct WebPreferences {
|
||||
// Whether touch input can trigger HTML drag-and-drop operations. The
|
||||
// default value depends on the platform.
|
||||
bool touch_drag_drop_enabled;
|
||||
-};
|
||||
\ No newline at end of file
|
||||
+};
|
|
@ -21,22 +21,37 @@ index 365d0d8cf45c664160048a7a9606907cb5414292..dd52048e922904826c5b31d13f17dfc9
|
|||
&no_javascript_access);
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 962cd0fb5a428530cd9e2f8e689f2d09bc95ce1b..e099a6cc44e73da8b24603fd86b72139f0735fb2 100644
|
||||
index 962cd0fb5a428530cd9e2f8e689f2d09bc95ce1b..ea458219bd182bd9ff21b203c282e7d0738049dd 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3624,9 +3624,9 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
|
||||
@@ -3582,6 +3582,14 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
|
||||
}
|
||||
auto* new_contents_impl = new_contents.get();
|
||||
|
||||
if (delegate_) {
|
||||
- delegate_->WebContentsCreated(this, render_process_id,
|
||||
- opener->GetRoutingID(), params.frame_name,
|
||||
- params.target_url, new_contents_impl);
|
||||
+ // Call this earlier than Chrome to associate the web preferences with the
|
||||
+ // WebContents before the view gets created.
|
||||
+ if (delegate_) {
|
||||
+ delegate_->WebContentsCreatedWithFullParams(this, render_process_id,
|
||||
+ opener->GetRoutingID(),
|
||||
+ params, new_contents_impl);
|
||||
+ }
|
||||
+
|
||||
new_contents_impl->GetController().SetSessionStorageNamespace(
|
||||
partition_id, session_storage_namespace);
|
||||
|
||||
@@ -3623,12 +3631,6 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
|
||||
AddDestructionObserver(new_contents_impl);
|
||||
}
|
||||
|
||||
- if (delegate_) {
|
||||
- delegate_->WebContentsCreated(this, render_process_id,
|
||||
- opener->GetRoutingID(), params.frame_name,
|
||||
- params.target_url, new_contents_impl);
|
||||
- }
|
||||
-
|
||||
observers_.ForEachObserver([&](WebContentsObserver* observer) {
|
||||
observer->DidOpenRequestedURL(new_contents_impl, opener, params.target_url,
|
||||
params.referrer.To<Referrer>(),
|
||||
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
|
||||
index 703c4611691b72380423576eebdadcd23e6ae913..2be0f93b7ea3791bb776158795a44aa7422e19ac 100644
|
||||
--- a/content/common/frame.mojom
|
||||
|
|
|
@ -0,0 +1,433 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Locascio <andy@slack-corp.com>
|
||||
Date: Wed, 9 Sep 2020 16:56:06 -0700
|
||||
Subject: chore: provide IsWebContentsCreationOverridden with full params
|
||||
|
||||
Pending upstream patch, this gives us fuller access to the window.open params
|
||||
so that we will be able to decide whether to cancel it or not.
|
||||
|
||||
diff --git a/chrome/browser/android/document/document_web_contents_delegate.cc b/chrome/browser/android/document/document_web_contents_delegate.cc
|
||||
index 0e90487923c57c0570e73ef0f0e8c5acc2576932..fcdc88233b2277f3b37a2a2b0bdee7d71b721bf8 100644
|
||||
--- a/chrome/browser/android/document/document_web_contents_delegate.cc
|
||||
+++ b/chrome/browser/android/document/document_web_contents_delegate.cc
|
||||
@@ -46,8 +46,7 @@ bool DocumentWebContentsDelegate::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
NOTREACHED();
|
||||
return true;
|
||||
}
|
||||
diff --git a/chrome/browser/android/document/document_web_contents_delegate.h b/chrome/browser/android/document/document_web_contents_delegate.h
|
||||
index 5b4d70991e19edcdfee731c56251932bf43e535f..fe1977c5e6ce0f5b30e8be529b9efa51785db57f 100644
|
||||
--- a/chrome/browser/android/document/document_web_contents_delegate.h
|
||||
+++ b/chrome/browser/android/document/document_web_contents_delegate.h
|
||||
@@ -41,8 +41,7 @@ class DocumentWebContentsDelegate
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_ANDROID_DOCUMENT_DOCUMENT_WEB_CONTENTS_DELEGATE_H_
|
||||
diff --git a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
|
||||
index a52c550f1aeadcdb36948078ed5fec24838c3da8..4aaddf84c0b3574218df5bdea77a72967271d5a8 100644
|
||||
--- a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
|
||||
+++ b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
|
||||
@@ -123,8 +123,7 @@ class DriveWebContentsManager : public content::WebContentsObserver,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
content::WebContents* CreateCustomWebContents(
|
||||
content::RenderFrameHost* opener,
|
||||
content::SiteInstance* source_site_instance,
|
||||
@@ -234,15 +233,14 @@ bool DriveWebContentsManager::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
if (window_container_type == content::mojom::WindowContainerType::NORMAL)
|
||||
return false;
|
||||
|
||||
// Check that the target URL is for the Drive app.
|
||||
const extensions::Extension* extension =
|
||||
extensions::ExtensionRegistry::Get(profile_)
|
||||
- ->enabled_extensions().GetAppByURL(target_url);
|
||||
+ ->enabled_extensions().GetAppByURL(params.target_url);
|
||||
|
||||
return extension && extension->id() == app_id_;
|
||||
}
|
||||
diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc
|
||||
index aba8e2273c98d2dc9a01a698f8de187056b3ce01..5141b4d1a711416f4dfc030838b9cf22e7613f8b 100644
|
||||
--- a/chrome/browser/media/offscreen_tab.cc
|
||||
+++ b/chrome/browser/media/offscreen_tab.cc
|
||||
@@ -282,8 +282,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
// Disallow creating separate WebContentses. The WebContents implementation
|
||||
// uses this to spawn new windows/tabs, which is also not allowed for
|
||||
// offscreen tabs.
|
||||
diff --git a/chrome/browser/media/offscreen_tab.h b/chrome/browser/media/offscreen_tab.h
|
||||
index fb09bf2c5d22e3838575403b53867d0021e13b67..36e7982bbcc7c8b50bb2942ada39862bad4bbc22 100644
|
||||
--- a/chrome/browser/media/offscreen_tab.h
|
||||
+++ b/chrome/browser/media/offscreen_tab.h
|
||||
@@ -106,8 +106,7 @@ class OffscreenTab final : public ProfileObserver,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) final;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
void EnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const blink::mojom::FullscreenOptions& options) final;
|
||||
diff --git a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc
|
||||
index 672d5d41e33178ed6c6f62156e69b1adaf099fe8..4c0f8db8a9c40c34df8abfa89d88b0ceaef76392 100644
|
||||
--- a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc
|
||||
+++ b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.cc
|
||||
@@ -77,10 +77,9 @@ bool AssistantWebViewImpl::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
if (params_.suppress_navigation) {
|
||||
- NotifyDidSuppressNavigation(target_url,
|
||||
+ NotifyDidSuppressNavigation(params.target_url,
|
||||
WindowOpenDisposition::NEW_FOREGROUND_TAB,
|
||||
/*from_user_gesture=*/true);
|
||||
return true;
|
||||
diff --git a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h
|
||||
index 07014765f33bdddebcc5bc32a2713d6523faf394..f866f69f9c810d89f1a0e9e4952293f66804602a 100644
|
||||
--- a/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h
|
||||
+++ b/chrome/browser/ui/ash/assistant/assistant_web_view_impl.h
|
||||
@@ -48,8 +48,7 @@ class AssistantWebViewImpl : public ash::AssistantWebView,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
content::WebContents* OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
|
||||
index 3d9b343765bdca5723a94e00db1426308a641a50..57afd89cb06ff255f126c7f7784f10e7689cefe3 100644
|
||||
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
|
||||
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
|
||||
@@ -64,8 +64,7 @@ class ChromeKeyboardContentsDelegate : public content::WebContentsDelegate,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override {
|
||||
+ const mojom::CreateNewWindowParams& params) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
|
||||
index 30a8f5eeaedb9bc186faabca645917bc53e7f041..8e7316a1255f9de8f3374b7ed99a8c8f42701b43 100644
|
||||
--- a/chrome/browser/ui/browser.cc
|
||||
+++ b/chrome/browser/ui/browser.cc
|
||||
@@ -1818,12 +1818,11 @@ bool Browser::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
return window_container_type ==
|
||||
content::mojom::WindowContainerType::BACKGROUND &&
|
||||
ShouldCreateBackgroundContents(source_site_instance, opener_url,
|
||||
- frame_name);
|
||||
+ params->frame_name);
|
||||
}
|
||||
|
||||
WebContents* Browser::CreateCustomWebContents(
|
||||
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
|
||||
index 79cde7e1b913e91a15405a0ae1cd7e97fa11971e..b5f00b336b0e15e675f8ce03997343f24b5b0e51 100644
|
||||
--- a/chrome/browser/ui/browser.h
|
||||
+++ b/chrome/browser/ui/browser.h
|
||||
@@ -769,8 +769,7 @@ class Browser : public TabStripModelObserver,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
content::WebContents* CreateCustomWebContents(
|
||||
content::RenderFrameHost* opener,
|
||||
content::SiteInstance* source_site_instance,
|
||||
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc b/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
|
||||
index 41177655d0608837ff7af7b944f22b1e657c68f6..6068228781eb1dabe1890f9121a3f86df4f6ac52 100644
|
||||
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
|
||||
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.cc
|
||||
@@ -201,8 +201,7 @@ bool PresentationReceiverWindowController::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
// Disallow creating separate WebContentses. The WebContents implementation
|
||||
// uses this to spawn new windows/tabs, which is also not allowed for
|
||||
// local presentations.
|
||||
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
|
||||
index 058ec72442d59989c4d6df4a7c791ecfeff0ef99..f7c8c2139382cb2e290c561624291afe647383cf 100644
|
||||
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
|
||||
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
|
||||
@@ -99,8 +99,7 @@ class PresentationReceiverWindowController final
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
|
||||
// The profile used for the presentation.
|
||||
Profile* otr_profile_;
|
||||
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
|
||||
index 420803e98b1dde758dc72ba5a481f0b7cbde836b..633353c180aa748c2d80eb07412bfd0ffcf07ae3 100644
|
||||
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
|
||||
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
|
||||
@@ -167,14 +167,13 @@ bool WebContentsDelegateAndroid::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
JNIEnv* env = AttachCurrentThread();
|
||||
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
|
||||
if (obj.is_null())
|
||||
return false;
|
||||
ScopedJavaLocalRef<jstring> java_url =
|
||||
- ConvertUTF8ToJavaString(env, target_url.spec());
|
||||
+ ConvertUTF8ToJavaString(env, params.target_url.spec());
|
||||
return !Java_WebContentsDelegateAndroid_shouldCreateWebContents(env, obj,
|
||||
java_url);
|
||||
}
|
||||
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h
|
||||
index fdd6866f595974f5a38e288a48b1e386a33c54d1..653981ffa4f58e727b2d7a2631f6213e3790c39f 100644
|
||||
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.h
|
||||
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
|
||||
@@ -78,8 +78,7 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate {
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
void CloseContents(content::WebContents* source) override;
|
||||
void SetContentsBounds(content::WebContents* source,
|
||||
const gfx::Rect& bounds) override;
|
||||
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.cc b/components/offline_pages/content/background_loader/background_loader_contents.cc
|
||||
index 53fad64f87a952fd0d7398958288ecde259b57bf..0b8359b6179bf16e58978e5f3e51a911ad3d0a3f 100644
|
||||
--- a/components/offline_pages/content/background_loader/background_loader_contents.cc
|
||||
+++ b/components/offline_pages/content/background_loader/background_loader_contents.cc
|
||||
@@ -80,8 +80,7 @@ bool BackgroundLoaderContents::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
// Background pages should not create other webcontents/tabs.
|
||||
return true;
|
||||
}
|
||||
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.h b/components/offline_pages/content/background_loader/background_loader_contents.h
|
||||
index c5c5a7b63b5b3b62a9517cbef3ae23ce57a3c89c..4f1b7e88d6d2ae89a60311c8aeb1fceea87f2b02 100644
|
||||
--- a/components/offline_pages/content/background_loader/background_loader_contents.h
|
||||
+++ b/components/offline_pages/content/background_loader/background_loader_contents.h
|
||||
@@ -60,8 +60,7 @@ class BackgroundLoaderContents : public content::WebContentsDelegate {
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
|
||||
void AddNewContents(content::WebContents* source,
|
||||
std::unique_ptr<content::WebContents> new_contents,
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 2a80aaa5d4421bf2b3a46cc1674256944b33a1fa..409c300c3831bb3fd3f0a019fb6e85bd866a705a 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3543,8 +3543,7 @@ RenderFrameHostDelegate* WebContentsImpl::CreateNewWindow(
|
||||
|
||||
if (delegate_ && delegate_->IsWebContentsCreationOverridden(
|
||||
source_site_instance, params.window_container_type,
|
||||
- opener->GetLastCommittedURL(), params.frame_name,
|
||||
- params.target_url)) {
|
||||
+ opener->GetLastCommittedURL(), params)) {
|
||||
return static_cast<WebContentsImpl*>(delegate_->CreateCustomWebContents(
|
||||
opener, source_site_instance, is_new_browsing_instance,
|
||||
opener->GetLastCommittedURL(), params.frame_name, params.target_url,
|
||||
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
|
||||
index b0513d20bd48fe8ffe8398b5387e13545749c508..7ce75c95771cc0053db01ec5318a68624bae9f4d 100644
|
||||
--- a/content/public/browser/web_contents_delegate.cc
|
||||
+++ b/content/public/browser/web_contents_delegate.cc
|
||||
@@ -134,8 +134,7 @@ bool WebContentsDelegate::IsWebContentsCreationOverridden(
|
||||
SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
|
||||
index 94f576a6d52731f92c65adb958be5ca0a3391d4c..33359363fa18364d254aab5360f4c952f358bd17 100644
|
||||
--- a/content/public/browser/web_contents_delegate.h
|
||||
+++ b/content/public/browser/web_contents_delegate.h
|
||||
@@ -317,8 +317,7 @@ class CONTENT_EXPORT WebContentsDelegate {
|
||||
SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url);
|
||||
+ const mojom::CreateNewWindowParams& params);
|
||||
|
||||
// Allow delegate to creates a custom WebContents when
|
||||
// WebContents::CreateNewWindow() is called. This function is only called
|
||||
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
|
||||
index bda659c7a464a58413e7eb33a897065268ab3fc6..29950878aca7f1518265561dea79b78d82230982 100644
|
||||
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc
|
||||
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
|
||||
@@ -212,8 +212,7 @@ bool ExtensionOptionsGuest::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const content::mojom::CreateNewWindowParams& params) {
|
||||
// This method handles opening links from within the guest. Since this guest
|
||||
// view is used for displaying embedded extension options, we want any
|
||||
// external links to be opened in a new tab, not in a new guest view so we
|
||||
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h
|
||||
index 97273c32a05acf325fd0de22c4f79c1746aa23bc..4b357acd069387963347d35d82371b955147893f 100644
|
||||
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.h
|
||||
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h
|
||||
@@ -55,8 +55,7 @@ class ExtensionOptionsGuest
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) final;
|
||||
+ const content::mojom::CreateNewWindowParams& params) final;
|
||||
content::WebContents* CreateCustomWebContents(
|
||||
content::RenderFrameHost* opener,
|
||||
content::SiteInstance* source_site_instance,
|
||||
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
|
||||
index 998d6d0c481fd49ff3a8a852e05347179f80b276..6ce9f2e9e8031d9abf03da7e656f221ce0912790 100644
|
||||
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
|
||||
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
|
||||
@@ -380,8 +380,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const content::mojom::CreateNewWindowParams& params) {
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
|
||||
index a7f0b19a8ab9bac6f1315ebd715d8e1b134edfe1..cbe2912d4ab2d9015396bbddf7836e106d0bff8b 100644
|
||||
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
|
||||
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
|
||||
@@ -155,8 +155,7 @@ class MimeHandlerViewGuest
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const content::mojom::CreateNewWindowParams& params) override;
|
||||
content::WebContents* CreateCustomWebContents(
|
||||
content::RenderFrameHost* opener,
|
||||
content::SiteInstance* source_site_instance,
|
||||
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
|
||||
index 32a8e39b23bdf962b88eba3a40346febfbac298a..bc120621e1df1921651f3323650a8644ff688933 100644
|
||||
--- a/fuchsia/engine/browser/frame_impl.cc
|
||||
+++ b/fuchsia/engine/browser/frame_impl.cc
|
||||
@@ -346,8 +346,7 @@ bool FrameImpl::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const mojom::CreateNewWindowParams& params) {
|
||||
// Specify a generous upper bound for unacknowledged popup windows, so that we
|
||||
// can catch bad client behavior while not interfering with normal operation.
|
||||
constexpr size_t kMaxPendingWebContentsCount = 10;
|
||||
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
|
||||
index 7027e5ee119d52ce9a43a1901beb18a81161512c..f20f7b169b10f68b8e0a3115a058378c6058e229 100644
|
||||
--- a/fuchsia/engine/browser/frame_impl.h
|
||||
+++ b/fuchsia/engine/browser/frame_impl.h
|
||||
@@ -198,8 +198,7 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const mojom::CreateNewWindowParams& params) override;
|
||||
void WebContentsCreated(content::WebContents* source_contents,
|
||||
int opener_render_process_id,
|
||||
int opener_render_frame_id,
|
||||
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
|
||||
index ebe323930ac3298b182c08e6b78c635e785ea4fa..5c1846d948cd6394252a8c94790aa3094f8c9c33 100644
|
||||
--- a/headless/lib/browser/headless_web_contents_impl.cc
|
||||
+++ b/headless/lib/browser/headless_web_contents_impl.cc
|
||||
@@ -164,8 +164,7 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate {
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override {
|
||||
+ const mojom::CreateNewWindowParams& params) override {
|
||||
return headless_web_contents_->browser_context()
|
||||
->options()
|
||||
->block_new_web_contents();
|
||||
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
|
||||
index 39a58363e717a0b9d71b7e3ca26578f81f8fb453..4372cf1e383ef3884048fb2a06c72888abcac9e3 100644
|
||||
--- a/ui/views/controls/webview/web_dialog_view.cc
|
||||
+++ b/ui/views/controls/webview/web_dialog_view.cc
|
||||
@@ -427,8 +427,7 @@ bool WebDialogView::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) {
|
||||
+ const content::mojom::CreateNewWindowParams& params) {
|
||||
if (delegate_)
|
||||
return delegate_->HandleShouldOverrideWebContentsCreation();
|
||||
return false;
|
||||
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h
|
||||
index 97142bc886e1bbf05871fb6603342ed0cd15dcf8..94206bb4674e696093a5cfc027281254c3bf37ff 100644
|
||||
--- a/ui/views/controls/webview/web_dialog_view.h
|
||||
+++ b/ui/views/controls/webview/web_dialog_view.h
|
||||
@@ -153,8 +153,7 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
- const std::string& frame_name,
|
||||
- const GURL& target_url) override;
|
||||
+ const content::mojom::CreateNewWindowParams& params) override;
|
||||
void RequestMediaAccessPermission(
|
||||
content::WebContents* web_contents,
|
||||
const content::MediaStreamRequest& request,
|
|
@ -13,7 +13,7 @@ This patch can be removed once app.allowRendererProcessReuse is forced
|
|||
to true as then Chromiums assumptions around processes become correct.
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index e099a6cc44e73da8b24603fd86b72139f0735fb2..2f207fda8afb44901d2027cb2ec1da1de826521f 100644
|
||||
index ea458219bd182bd9ff21b203c282e7d0738049dd..1455dfcae9e1ded39d351f6569919f0c313e3de5 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3012,11 +3012,13 @@ bool WebContentsImpl::HandleMouseEvent(const blink::WebMouseEvent& event) {
|
||||
|
|
|
@ -43,10 +43,10 @@ index ffe62ea1114943d1535a806fa515122c47072372..f5f851e4852b045555d5832b7ec72be9
|
|||
|
||||
void RenderWidgetHostImpl::OnCursorVisibilityStateChanged(bool is_visible) {
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 22cba415650311acd16750e7ad0956ca71aa75e8..eff997916d5dd833d66d3fa9738dee1fe55075f8 100644
|
||||
index 37d02e3c950bdb0a1e0f9ef20be71c24fdbde10d..2a80aaa5d4421bf2b3a46cc1674256944b33a1fa 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -4123,6 +4123,12 @@ bool WebContentsImpl::OnUpdateDragCursor() {
|
||||
@@ -4125,6 +4125,12 @@ bool WebContentsImpl::OnUpdateDragCursor() {
|
||||
browser_plugin_embedder_->OnUpdateDragCursor();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ is needed for OSR.
|
|||
Originally landed in https://github.com/electron/libchromiumcontent/pull/226.
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 2f207fda8afb44901d2027cb2ec1da1de826521f..22cba415650311acd16750e7ad0956ca71aa75e8 100644
|
||||
index 1455dfcae9e1ded39d351f6569919f0c313e3de5..37d02e3c950bdb0a1e0f9ef20be71c24fdbde10d 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -2744,6 +2744,12 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
|
||||
|
|
|
@ -784,14 +784,13 @@ void Session::CreateInterruptedDownload(const gin_helper::Dictionary& options) {
|
|||
length, last_modified, etag, base::Time::FromDoubleT(start_time)));
|
||||
}
|
||||
|
||||
void Session::SetPreloads(
|
||||
const std::vector<base::FilePath::StringType>& preloads) {
|
||||
void Session::SetPreloads(const std::vector<base::FilePath>& preloads) {
|
||||
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
|
||||
DCHECK(prefs);
|
||||
prefs->set_preloads(preloads);
|
||||
}
|
||||
|
||||
std::vector<base::FilePath::StringType> Session::GetPreloads() const {
|
||||
std::vector<base::FilePath> Session::GetPreloads() const {
|
||||
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
|
||||
DCHECK(prefs);
|
||||
return prefs->preloads();
|
||||
|
|
|
@ -115,8 +115,8 @@ class Session : public gin::Wrappable<Session>,
|
|||
const std::string& uuid);
|
||||
void DownloadURL(const GURL& url);
|
||||
void CreateInterruptedDownload(const gin_helper::Dictionary& options);
|
||||
void SetPreloads(const std::vector<base::FilePath::StringType>& preloads);
|
||||
std::vector<base::FilePath::StringType> GetPreloads() const;
|
||||
void SetPreloads(const std::vector<base::FilePath>& preloads);
|
||||
std::vector<base::FilePath> GetPreloads() const;
|
||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
|
||||
v8::Local<v8::Value> ServiceWorkerContext(v8::Isolate* isolate);
|
||||
|
|
|
@ -639,7 +639,11 @@ void WebContents::InitWithSessionAndOptions(
|
|||
prefs->caret_blink_interval = *interval;
|
||||
|
||||
// Save the preferences in C++.
|
||||
new WebContentsPreferences(web_contents(), options);
|
||||
// If there's already a WebContentsPreferences object, we created it as part
|
||||
// of the webContents.setWindowOpenHandler path, so don't overwrite it.
|
||||
if (!WebContentsPreferences::From(web_contents())) {
|
||||
new WebContentsPreferences(web_contents(), options);
|
||||
}
|
||||
// Trigger re-calculation of webkit prefs.
|
||||
web_contents()->NotifyPreferencesChanged();
|
||||
|
||||
|
@ -778,18 +782,44 @@ void WebContents::WebContentsCreatedWithFullParams(
|
|||
tracker->referrer = params.referrer.To<content::Referrer>();
|
||||
tracker->raw_features = params.raw_features;
|
||||
tracker->body = params.body;
|
||||
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
gin_helper::Dictionary dict;
|
||||
gin::ConvertFromV8(isolate, pending_child_web_preferences_.Get(isolate),
|
||||
&dict);
|
||||
pending_child_web_preferences_.Reset();
|
||||
|
||||
// Associate the preferences passed in via `setWindowOpenHandler` with the
|
||||
// content::WebContents that was just created for the child window. These
|
||||
// preferences will be picked up by the RenderWidgetHost via its call to the
|
||||
// delegate's OverrideWebkitPrefs.
|
||||
new WebContentsPreferences(new_contents, dict);
|
||||
}
|
||||
|
||||
bool WebContents::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
const std::string& frame_name,
|
||||
const GURL& target_url) {
|
||||
if (Emit("-will-add-new-contents", target_url, frame_name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
const content::mojom::CreateNewWindowParams& params) {
|
||||
bool default_prevented = Emit("-will-add-new-contents", params.target_url,
|
||||
params.frame_name, params.raw_features);
|
||||
// If the app prevented the default, redirect to CreateCustomWebContents,
|
||||
// which always returns nullptr, which will result in the window open being
|
||||
// prevented (window.open() will return null in the renderer).
|
||||
return default_prevented;
|
||||
}
|
||||
|
||||
void WebContents::SetNextChildWebPreferences(
|
||||
const gin_helper::Dictionary preferences) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
// Store these prefs for when Chrome calls WebContentsCreatedWithFullParams
|
||||
// with the new child contents.
|
||||
pending_child_web_preferences_.Reset(isolate, preferences.GetHandle());
|
||||
}
|
||||
|
||||
content::WebContents* WebContents::CreateCustomWebContents(
|
||||
|
@ -1076,7 +1106,7 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
|
|||
if (web_contents()->GetRenderViewHost() == render_view_host) {
|
||||
// When the RVH that has been deleted is the current RVH it means that the
|
||||
// the web contents are being closed. This is communicated by this event.
|
||||
// Currently tracked by guest-window-manager.js to destroy the
|
||||
// Currently tracked by guest-window-manager.ts to destroy the
|
||||
// BrowserWindow.
|
||||
Emit("current-render-view-deleted",
|
||||
render_view_host->GetProcess()->GetID());
|
||||
|
@ -2738,11 +2768,11 @@ void WebContents::DoGetZoomLevel(DoGetZoomLevelCallback callback) {
|
|||
std::move(callback).Run(GetZoomLevel());
|
||||
}
|
||||
|
||||
std::vector<base::FilePath::StringType> WebContents::GetPreloadPaths() const {
|
||||
std::vector<base::FilePath> WebContents::GetPreloadPaths() const {
|
||||
auto result = SessionPreferences::GetValidPreloads(GetBrowserContext());
|
||||
|
||||
if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
|
||||
base::FilePath::StringType preload;
|
||||
base::FilePath preload;
|
||||
if (web_preferences->GetPreloadPath(&preload)) {
|
||||
result.emplace_back(preload);
|
||||
}
|
||||
|
@ -3017,6 +3047,8 @@ v8::Local<v8::ObjectTemplate> WebContents::FillObjectTemplate(
|
|||
.SetMethod("_getPrinters", &WebContents::GetPrinterList)
|
||||
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
|
||||
#endif
|
||||
.SetMethod("_setNextChildWebPreferences",
|
||||
&WebContents::SetNextChildWebPreferences)
|
||||
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
|
||||
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
|
||||
.SetMethod("showDefinitionForSelection",
|
||||
|
|
|
@ -252,6 +252,8 @@ class WebContents : public gin::Wrappable<WebContents>,
|
|||
v8::Local<v8::Promise> PrintToPDF(base::DictionaryValue settings);
|
||||
#endif
|
||||
|
||||
void SetNextChildWebPreferences(const gin_helper::Dictionary);
|
||||
|
||||
// DevTools workspace api.
|
||||
void AddWorkSpace(gin::Arguments* args, const base::FilePath& path);
|
||||
void RemoveWorkSpace(gin::Arguments* args, const base::FilePath& path);
|
||||
|
@ -354,7 +356,7 @@ class WebContents : public gin::Wrappable<WebContents>,
|
|||
const scoped_refptr<network::ResourceRequestBody>& body);
|
||||
|
||||
// Returns the preload script path of current WebContents.
|
||||
std::vector<base::FilePath::StringType> GetPreloadPaths() const;
|
||||
std::vector<base::FilePath> GetPreloadPaths() const;
|
||||
|
||||
// Returns the web preferences of current WebContents.
|
||||
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate) const;
|
||||
|
@ -456,8 +458,7 @@ class WebContents : public gin::Wrappable<WebContents>,
|
|||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
const std::string& frame_name,
|
||||
const GURL& target_url) override;
|
||||
const content::mojom::CreateNewWindowParams& params) override;
|
||||
content::WebContents* CreateCustomWebContents(
|
||||
content::RenderFrameHost* opener,
|
||||
content::SiteInstance* source_site_instance,
|
||||
|
@ -679,6 +680,8 @@ class WebContents : public gin::Wrappable<WebContents>,
|
|||
// Observers of this WebContents.
|
||||
base::ObserverList<ExtendedWebContentsObserver> observers_;
|
||||
|
||||
v8::Global<v8::Value> pending_child_web_preferences_;
|
||||
|
||||
bool initially_shown_ = true;
|
||||
|
||||
service_manager::BinderRegistryWithArgs<content::RenderFrameHost*> registry_;
|
||||
|
|
|
@ -225,12 +225,6 @@ void BindNetworkHintsHandler(
|
|||
NetworkHintsHandlerImpl::Create(frame_host, std::move(receiver));
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(";");
|
||||
#else
|
||||
const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(":");
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
// Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions
|
||||
// below. Extension, and isolated apps require different privileges to be
|
||||
|
@ -610,13 +604,21 @@ void ElectronBrowserClient::OverrideWebkitPrefs(
|
|||
? blink::mojom::PreferredColorScheme::kDark
|
||||
: blink::mojom::PreferredColorScheme::kLight;
|
||||
|
||||
auto* web_contents = content::WebContents::FromRenderViewHost(host);
|
||||
auto preloads =
|
||||
SessionPreferences::GetValidPreloads(web_contents->GetBrowserContext());
|
||||
if (!preloads.empty())
|
||||
prefs->preloads = preloads;
|
||||
if (CanUseCustomSiteInstance())
|
||||
prefs->disable_electron_site_instance_overrides = true;
|
||||
|
||||
SetFontDefaults(prefs);
|
||||
|
||||
// Custom preferences of guest page.
|
||||
auto* web_contents = content::WebContents::FromRenderViewHost(host);
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
||||
if (web_preferences)
|
||||
if (web_preferences) {
|
||||
web_preferences->OverrideWebkitPrefs(prefs);
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronBrowserClient::SetCanUseCustomSiteInstance(bool should_disable) {
|
||||
|
@ -803,16 +805,6 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
|
|||
if (web_preferences)
|
||||
web_preferences->AppendCommandLineSwitches(
|
||||
command_line, IsRendererSubFrame(process_id));
|
||||
auto preloads = SessionPreferences::GetValidPreloads(
|
||||
web_contents->GetBrowserContext());
|
||||
if (!preloads.empty())
|
||||
command_line->AppendSwitchNative(
|
||||
switches::kPreloadScripts,
|
||||
base::JoinString(preloads, kPathDelimiter));
|
||||
if (CanUseCustomSiteInstance()) {
|
||||
command_line->AppendSwitch(
|
||||
switches::kDisableElectronSiteInstanceOverrides);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ template <typename T>
|
|||
class EventEmitterMixin {
|
||||
public:
|
||||
// this.emit(name, new Event(), args...);
|
||||
// Returns true if event.preventDefault() was called during processing.
|
||||
template <typename... Args>
|
||||
bool Emit(base::StringPiece name, Args&&... args) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
|
|
|
@ -25,13 +25,13 @@ SessionPreferences* SessionPreferences::FromBrowserContext(
|
|||
}
|
||||
|
||||
// static
|
||||
std::vector<base::FilePath::StringType> SessionPreferences::GetValidPreloads(
|
||||
std::vector<base::FilePath> SessionPreferences::GetValidPreloads(
|
||||
content::BrowserContext* context) {
|
||||
std::vector<base::FilePath::StringType> result;
|
||||
std::vector<base::FilePath> result;
|
||||
|
||||
if (auto* self = FromBrowserContext(context)) {
|
||||
for (const auto& preload : self->preloads()) {
|
||||
if (base::FilePath(preload).IsAbsolute()) {
|
||||
if (preload.IsAbsolute()) {
|
||||
result.emplace_back(preload);
|
||||
} else {
|
||||
LOG(ERROR) << "preload script must have absolute path: " << preload;
|
||||
|
|
|
@ -17,24 +17,22 @@ class SessionPreferences : public base::SupportsUserData::Data {
|
|||
public:
|
||||
static SessionPreferences* FromBrowserContext(
|
||||
content::BrowserContext* context);
|
||||
static std::vector<base::FilePath::StringType> GetValidPreloads(
|
||||
static std::vector<base::FilePath> GetValidPreloads(
|
||||
content::BrowserContext* context);
|
||||
|
||||
explicit SessionPreferences(content::BrowserContext* context);
|
||||
~SessionPreferences() override;
|
||||
|
||||
void set_preloads(const std::vector<base::FilePath::StringType>& preloads) {
|
||||
void set_preloads(const std::vector<base::FilePath>& preloads) {
|
||||
preloads_ = preloads;
|
||||
}
|
||||
const std::vector<base::FilePath::StringType>& preloads() const {
|
||||
return preloads_;
|
||||
}
|
||||
const std::vector<base::FilePath>& preloads() const { return preloads_; }
|
||||
|
||||
private:
|
||||
// The user data key.
|
||||
static int kLocatorKey;
|
||||
|
||||
std::vector<base::FilePath::StringType> preloads_;
|
||||
std::vector<base::FilePath> preloads_;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
|
|
@ -241,22 +241,22 @@ bool WebContentsPreferences::GetPreference(base::StringPiece name,
|
|||
return GetAsString(&preference_, name, value);
|
||||
}
|
||||
|
||||
bool WebContentsPreferences::GetPreloadPath(
|
||||
base::FilePath::StringType* path) const {
|
||||
bool WebContentsPreferences::GetPreloadPath(base::FilePath* path) const {
|
||||
DCHECK(path);
|
||||
base::FilePath::StringType preload;
|
||||
if (GetAsString(&preference_, options::kPreloadScript, &preload)) {
|
||||
if (base::FilePath(preload).IsAbsolute()) {
|
||||
base::FilePath::StringType preload_path;
|
||||
if (GetAsString(&preference_, options::kPreloadScript, &preload_path)) {
|
||||
base::FilePath preload(preload_path);
|
||||
if (preload.IsAbsolute()) {
|
||||
*path = std::move(preload);
|
||||
return true;
|
||||
} else {
|
||||
LOG(ERROR) << "preload script must have absolute path.";
|
||||
}
|
||||
} else if (GetAsString(&preference_, options::kPreloadURL, &preload)) {
|
||||
} else if (GetAsString(&preference_, options::kPreloadURL, &preload_path)) {
|
||||
// Translate to file path if there is "preload-url" option.
|
||||
base::FilePath preload_path;
|
||||
if (net::FileURLToFilePath(GURL(preload), &preload_path)) {
|
||||
*path = std::move(preload_path.value());
|
||||
base::FilePath preload;
|
||||
if (net::FileURLToFilePath(GURL(preload_path), &preload)) {
|
||||
*path = std::move(preload);
|
||||
return true;
|
||||
} else {
|
||||
LOG(ERROR) << "preload url must be file:// protocol.";
|
||||
|
@ -287,36 +287,16 @@ WebContentsPreferences* WebContentsPreferences::From(
|
|||
void WebContentsPreferences::AppendCommandLineSwitches(
|
||||
base::CommandLine* command_line,
|
||||
bool is_subframe) {
|
||||
// Check if plugins are enabled.
|
||||
if (IsEnabled(options::kPlugins))
|
||||
command_line->AppendSwitch(switches::kEnablePlugins);
|
||||
|
||||
// Experimental flags.
|
||||
if (IsEnabled(options::kExperimentalFeatures))
|
||||
command_line->AppendSwitch(
|
||||
::switches::kEnableExperimentalWebPlatformFeatures);
|
||||
|
||||
// Check if we have node integration specified.
|
||||
if (IsEnabled(options::kNodeIntegration))
|
||||
command_line->AppendSwitch(switches::kNodeIntegration);
|
||||
|
||||
// Whether to enable node integration in Worker.
|
||||
if (IsEnabled(options::kNodeIntegrationInWorker))
|
||||
command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
|
||||
|
||||
// Check if webview tag creation is enabled, default to nodeIntegration value.
|
||||
if (IsEnabled(options::kWebviewTag))
|
||||
command_line->AppendSwitch(switches::kWebviewTag);
|
||||
|
||||
// Sandbox can be enabled for renderer processes hosting cross-origin frames
|
||||
// unless nodeIntegrationInSubFrames is enabled
|
||||
bool can_sandbox_frame =
|
||||
is_subframe && !IsEnabled(options::kNodeIntegrationInSubFrames);
|
||||
|
||||
// If the `sandbox` option was passed to the BrowserWindow's webPreferences,
|
||||
// pass `--enable-sandbox` to the renderer so it won't have any node.js
|
||||
// integration. Otherwise disable Chromium sandbox, unless app.enableSandbox()
|
||||
// was called.
|
||||
if (IsEnabled(options::kSandbox) || can_sandbox_frame) {
|
||||
command_line->AppendSwitch(switches::kEnableSandbox);
|
||||
} else if (!command_line->HasSwitch(switches::kEnableSandbox)) {
|
||||
|
@ -324,15 +304,6 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
|||
command_line->AppendSwitch(::switches::kNoZygote);
|
||||
}
|
||||
|
||||
// Check if nativeWindowOpen is enabled.
|
||||
if (IsEnabled(options::kNativeWindowOpen))
|
||||
command_line->AppendSwitch(switches::kNativeWindowOpen);
|
||||
|
||||
// The preload script.
|
||||
base::FilePath::StringType preload;
|
||||
if (GetPreloadPath(&preload))
|
||||
command_line->AppendSwitchNative(switches::kPreloadScript, preload);
|
||||
|
||||
// Custom args for renderer process
|
||||
auto* customArgs =
|
||||
preference_.FindKeyOfType(options::kCustomArgs, base::Value::Type::LIST);
|
||||
|
@ -343,46 +314,13 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
|||
}
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
// Whether to enable the remote module
|
||||
if (IsEnabled(options::kEnableRemoteModule, false))
|
||||
command_line->AppendSwitch(switches::kEnableRemoteModule);
|
||||
#endif
|
||||
|
||||
// Run Electron APIs and preload script in isolated world
|
||||
if (IsEnabled(options::kContextIsolation))
|
||||
command_line->AppendSwitch(switches::kContextIsolation);
|
||||
|
||||
if (IsEnabled(options::kWorldSafeExecuteJavaScript))
|
||||
command_line->AppendSwitch(switches::kWorldSafeExecuteJavaScript);
|
||||
|
||||
// --background-color.
|
||||
std::string s;
|
||||
if (GetAsString(&preference_, options::kBackgroundColor, &s)) {
|
||||
command_line->AppendSwitchASCII(switches::kBackgroundColor, s);
|
||||
} else if (!IsEnabled(options::kOffscreen)) {
|
||||
// For non-OSR WebContents, we expect to have white background, see
|
||||
// https://github.com/electron/electron/issues/13764 for more.
|
||||
command_line->AppendSwitchASCII(switches::kBackgroundColor, "#fff");
|
||||
}
|
||||
|
||||
// --offscreen
|
||||
// TODO(loc): Offscreen is duplicated in WebPreferences because it's needed
|
||||
// earlier than we can get WebPreferences at the moment.
|
||||
if (IsEnabled(options::kOffscreen)) {
|
||||
command_line->AppendSwitch(options::kOffscreen);
|
||||
}
|
||||
|
||||
// --guest-instance-id, which is used to identify guest WebContents.
|
||||
int guest_instance_id = 0;
|
||||
if (GetAsInteger(&preference_, options::kGuestInstanceID, &guest_instance_id))
|
||||
command_line->AppendSwitchASCII(switches::kGuestInstanceID,
|
||||
base::NumberToString(guest_instance_id));
|
||||
|
||||
// Pass the opener's window id.
|
||||
int opener_id;
|
||||
if (GetAsInteger(&preference_, options::kOpenerID, &opener_id))
|
||||
command_line->AppendSwitchASCII(switches::kOpenerID,
|
||||
base::NumberToString(opener_id));
|
||||
|
||||
#if defined(OS_MAC)
|
||||
// Enable scroll bounce.
|
||||
if (IsEnabled(options::kScrollBounce))
|
||||
|
@ -402,6 +340,7 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
|||
}
|
||||
}
|
||||
|
||||
std::string s;
|
||||
// Enable blink features.
|
||||
if (GetAsString(&preference_, options::kEnableBlinkFeatures, &s))
|
||||
command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures, s);
|
||||
|
@ -410,39 +349,8 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
|||
if (GetAsString(&preference_, options::kDisableBlinkFeatures, &s))
|
||||
command_line->AppendSwitchASCII(::switches::kDisableBlinkFeatures, s);
|
||||
|
||||
if (guest_instance_id) {
|
||||
// Webview `document.visibilityState` tracks window visibility so we need
|
||||
// to let it know if the window happens to be hidden right now.
|
||||
auto* manager = WebViewManager::GetWebViewManager(web_contents_);
|
||||
if (manager) {
|
||||
auto* embedder = manager->GetEmbedder(guest_instance_id);
|
||||
if (embedder) {
|
||||
auto* relay = NativeWindowRelay::FromWebContents(embedder);
|
||||
if (relay) {
|
||||
auto* window = relay->GetNativeWindow();
|
||||
if (window) {
|
||||
const bool visible = window->IsVisible() && !window->IsMinimized();
|
||||
if (!visible) {
|
||||
command_line->AppendSwitch(switches::kHiddenPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsEnabled(options::kNodeIntegrationInSubFrames))
|
||||
command_line->AppendSwitch(switches::kNodeIntegrationInSubFrames);
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
if (IsEnabled(options::kSpellcheck)) {
|
||||
command_line->AppendSwitch(switches::kEnableSpellcheck);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Whether to allow the WebSQL api
|
||||
if (IsEnabled(options::kEnableWebSQL))
|
||||
command_line->AppendSwitch(switches::kEnableWebSQL);
|
||||
if (IsEnabled(options::kNodeIntegrationInWorker))
|
||||
command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
|
||||
|
||||
// We are appending args to a webContents so let's save the current state
|
||||
// of our preferences object so that during the lifetime of the WebContents
|
||||
|
@ -507,6 +415,87 @@ void WebContentsPreferences::OverrideWebkitPrefs(
|
|||
if (GetAsString(&preference_, "defaultEncoding", &encoding))
|
||||
prefs->default_encoding = encoding;
|
||||
|
||||
// --background-color.
|
||||
std::string color;
|
||||
if (GetAsString(&preference_, options::kBackgroundColor, &color)) {
|
||||
prefs->background_color = color;
|
||||
} else if (!IsEnabled(options::kOffscreen)) {
|
||||
prefs->background_color = "#fff";
|
||||
}
|
||||
|
||||
// Pass the opener's window id.
|
||||
int opener_id;
|
||||
if (GetAsInteger(&preference_, options::kOpenerID, &opener_id))
|
||||
prefs->opener_id = opener_id;
|
||||
|
||||
// Run Electron APIs and preload script in isolated world
|
||||
prefs->context_isolation = IsEnabled(options::kContextIsolation);
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
// Whether to enable the remote module
|
||||
prefs->enable_remote_module = IsEnabled(options::kEnableRemoteModule, false);
|
||||
#endif
|
||||
|
||||
prefs->world_safe_execute_javascript =
|
||||
IsEnabled(options::kWorldSafeExecuteJavaScript);
|
||||
|
||||
int guest_instance_id = 0;
|
||||
if (GetAsInteger(&preference_, options::kGuestInstanceID, &guest_instance_id))
|
||||
prefs->guest_instance_id = guest_instance_id;
|
||||
|
||||
prefs->hidden_page = false;
|
||||
if (guest_instance_id) {
|
||||
// Webview `document.visibilityState` tracks window visibility so we need
|
||||
// to let it know if the window happens to be hidden right now.
|
||||
auto* manager = WebViewManager::GetWebViewManager(web_contents_);
|
||||
if (manager) {
|
||||
auto* embedder = manager->GetEmbedder(guest_instance_id);
|
||||
if (embedder) {
|
||||
auto* relay = NativeWindowRelay::FromWebContents(embedder);
|
||||
if (relay) {
|
||||
auto* window = relay->GetNativeWindow();
|
||||
if (window) {
|
||||
const bool visible = window->IsVisible() && !window->IsMinimized();
|
||||
if (!visible) {
|
||||
prefs->hidden_page = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prefs->offscreen = IsEnabled(options::kOffscreen);
|
||||
|
||||
// The preload script.
|
||||
GetPreloadPath(&prefs->preload);
|
||||
|
||||
// Check if nativeWindowOpen is enabled.
|
||||
prefs->native_window_open = IsEnabled(options::kNativeWindowOpen);
|
||||
|
||||
// Check if we have node integration specified.
|
||||
prefs->node_integration = IsEnabled(options::kNodeIntegration);
|
||||
|
||||
// Whether to enable node integration in Worker.
|
||||
prefs->node_integration_in_worker =
|
||||
IsEnabled(options::kNodeIntegrationInWorker);
|
||||
|
||||
prefs->node_integration_in_sub_frames =
|
||||
IsEnabled(options::kNodeIntegrationInSubFrames);
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
prefs->enable_spellcheck = IsEnabled(options::kSpellcheck);
|
||||
#endif
|
||||
|
||||
// Check if plugins are enabled.
|
||||
prefs->enable_plugins = IsEnabled(options::kPlugins);
|
||||
|
||||
// Check if webview tag creation is enabled, default to nodeIntegration value.
|
||||
prefs->webview_tag = IsEnabled(options::kWebviewTag);
|
||||
|
||||
// Whether to allow the WebSQL api
|
||||
prefs->enable_websql = IsEnabled(options::kEnableWebSQL);
|
||||
|
||||
std::string v8_cache_options;
|
||||
if (GetAsString(&preference_, "v8CacheOptions", &v8_cache_options)) {
|
||||
if (v8_cache_options == "none") {
|
||||
|
|
|
@ -59,7 +59,7 @@ class WebContentsPreferences
|
|||
bool GetPreference(base::StringPiece name, std::string* value) const;
|
||||
|
||||
// Returns the preload script path.
|
||||
bool GetPreloadPath(base::FilePath::StringType* path) const;
|
||||
bool GetPreloadPath(base::FilePath* path) const;
|
||||
|
||||
// Returns the web preferences.
|
||||
base::Value* preference() { return &preference_; }
|
||||
|
|
|
@ -40,6 +40,10 @@ void WebViewGuestDelegate::AttachToIframe(
|
|||
|
||||
content::WebContents* guest_web_contents = api_web_contents_->web_contents();
|
||||
|
||||
// Force a refresh of the webPreferences so that OverrideWebkitPrefs runs on
|
||||
// the new web contents before the renderer process initializes.
|
||||
// guest_web_contents->NotifyPreferencesChanged();
|
||||
|
||||
// Attach this inner WebContents |guest_web_contents| to the outer
|
||||
// WebContents |embedder_web_contents|. The outer WebContents's
|
||||
// frame |embedder_frame| hosts the inner WebContents.
|
||||
|
|
|
@ -109,6 +109,8 @@ const char kZoomFactor[] = "zoomFactor";
|
|||
// Script that will be loaded by guest WebContents before other scripts.
|
||||
const char kPreloadScript[] = "preload";
|
||||
|
||||
const char kPreloadScripts[] = "preloadScripts";
|
||||
|
||||
// Like --preload, but the passed argument is an URL.
|
||||
const char kPreloadURL[] = "preloadURL";
|
||||
|
||||
|
@ -181,6 +183,11 @@ const char kWebGL[] = "webgl";
|
|||
// navigation.
|
||||
const char kNavigateOnDragDrop[] = "navigateOnDragDrop";
|
||||
|
||||
const char kDisableElectronSiteInstanceOverrides[] =
|
||||
"disableElectronSiteInstanceOverrides";
|
||||
const char kEnableNodeLeakageInRenderers[] = "enableNodeLeakageInRenderers";
|
||||
const char kHiddenPage[] = "hiddenPage";
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
const char kSpellcheck[] = "spellcheck";
|
||||
#endif
|
||||
|
@ -200,9 +207,6 @@ namespace switches {
|
|||
// Enable chromium sandbox.
|
||||
const char kEnableSandbox[] = "enable-sandbox";
|
||||
|
||||
// Enable plugins.
|
||||
const char kEnablePlugins[] = "enable-plugins";
|
||||
|
||||
// Ppapi Flash path.
|
||||
const char kPpapiFlashPath[] = "ppapi-flash-path";
|
||||
|
||||
|
@ -242,33 +246,11 @@ const char kAppPath[] = "app-path";
|
|||
const char kEnableApiFilteringLogging[] = "enable-api-filtering-logging";
|
||||
|
||||
// The command line switch versions of the options.
|
||||
const char kBackgroundColor[] = "background-color";
|
||||
const char kPreloadScript[] = "preload";
|
||||
const char kPreloadScripts[] = "preload-scripts";
|
||||
const char kNodeIntegration[] = "node-integration";
|
||||
const char kContextIsolation[] = "context-isolation";
|
||||
const char kWorldSafeExecuteJavaScript[] = "world-safe-execute-javascript";
|
||||
const char kGuestInstanceID[] = "guest-instance-id";
|
||||
const char kOpenerID[] = "opener-id";
|
||||
const char kScrollBounce[] = "scroll-bounce";
|
||||
const char kHiddenPage[] = "hidden-page";
|
||||
const char kNativeWindowOpen[] = "native-window-open";
|
||||
const char kWebviewTag[] = "webview-tag";
|
||||
const char kDisableElectronSiteInstanceOverrides[] =
|
||||
"disable-electron-site-instance-overrides";
|
||||
const char kEnableNodeLeakageInRenderers[] = "enable-node-leakage-in-renderers";
|
||||
|
||||
// Command switch passed to renderer process to control nodeIntegration.
|
||||
const char kNodeIntegrationInWorker[] = "node-integration-in-worker";
|
||||
|
||||
// Command switch passed to renderer process to control whether node
|
||||
// environments will be created in sub-frames.
|
||||
const char kNodeIntegrationInSubFrames[] = "node-integration-in-subframes";
|
||||
|
||||
// Command switch passed to render process to control whether WebSQL api
|
||||
// is allowed.
|
||||
const char kEnableWebSQL[] = "enable-websql";
|
||||
|
||||
// Widevine options
|
||||
// Path to Widevine CDM binaries.
|
||||
const char kWidevineCdmPath[] = "widevine-cdm-path";
|
||||
|
@ -294,16 +276,10 @@ const char kEnableAuthNegotiatePort[] = "enable-auth-negotiate-port";
|
|||
// If set, NTLM v2 is disabled for POSIX platforms.
|
||||
const char kDisableNTLMv2[] = "disable-ntlm-v2";
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
const char kEnableSpellcheck[] = "enable-spellcheck";
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
const char kEnableRemoteModule[] = "enable-remote-module";
|
||||
#endif
|
||||
|
||||
const char kGlobalCrashKeys[] = "global-crash-keys";
|
||||
|
||||
const char kEnableWebSQL[] = "enable-websql";
|
||||
|
||||
} // namespace switches
|
||||
|
||||
} // namespace electron
|
||||
|
|
|
@ -60,6 +60,7 @@ extern const char kTrafficLightPosition[];
|
|||
// WebPreferences.
|
||||
extern const char kZoomFactor[];
|
||||
extern const char kPreloadScript[];
|
||||
extern const char kPreloadScripts[];
|
||||
extern const char kPreloadURL[];
|
||||
extern const char kNodeIntegration[];
|
||||
extern const char kContextIsolation[];
|
||||
|
@ -89,6 +90,10 @@ extern const char kNavigateOnDragDrop[];
|
|||
extern const char kEnableWebSQL[];
|
||||
extern const char kEnablePreferredSizeMode[];
|
||||
|
||||
extern const char kDisableElectronSiteInstanceOverrides[];
|
||||
extern const char kEnableNodeLeakageInRenderers[];
|
||||
extern const char kHiddenPage[];
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
extern const char kSpellcheck[];
|
||||
#endif
|
||||
|
@ -104,7 +109,6 @@ extern const char kEnableRemoteModule[];
|
|||
namespace switches {
|
||||
|
||||
extern const char kEnableSandbox[];
|
||||
extern const char kEnablePlugins[];
|
||||
extern const char kPpapiFlashPath[];
|
||||
extern const char kPpapiFlashVersion[];
|
||||
extern const char kDisableHttpCache[];
|
||||
|
@ -119,23 +123,8 @@ extern const char kAppUserModelId[];
|
|||
extern const char kAppPath[];
|
||||
extern const char kEnableApiFilteringLogging[];
|
||||
|
||||
extern const char kBackgroundColor[];
|
||||
extern const char kPreloadScript[];
|
||||
extern const char kPreloadScripts[];
|
||||
extern const char kNodeIntegration[];
|
||||
extern const char kContextIsolation[];
|
||||
extern const char kWorldSafeExecuteJavaScript[];
|
||||
extern const char kGuestInstanceID[];
|
||||
extern const char kOpenerID[];
|
||||
extern const char kScrollBounce[];
|
||||
extern const char kHiddenPage[];
|
||||
extern const char kNativeWindowOpen[];
|
||||
extern const char kNodeIntegrationInWorker[];
|
||||
extern const char kWebviewTag[];
|
||||
extern const char kNodeIntegrationInSubFrames[];
|
||||
extern const char kDisableElectronSiteInstanceOverrides[];
|
||||
extern const char kEnableNodeLeakageInRenderers[];
|
||||
extern const char kEnableWebSQL[];
|
||||
|
||||
extern const char kWidevineCdmPath[];
|
||||
extern const char kWidevineCdmVersion[];
|
||||
|
@ -147,16 +136,9 @@ extern const char kAuthNegotiateDelegateWhitelist[];
|
|||
extern const char kEnableAuthNegotiatePort[];
|
||||
extern const char kDisableNTLMv2[];
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
extern const char kEnableSpellcheck[];
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
extern const char kEnableRemoteModule[];
|
||||
#endif
|
||||
|
||||
extern const char kGlobalCrashKeys[];
|
||||
|
||||
extern const char kEnableWebSQL[];
|
||||
} // namespace switches
|
||||
|
||||
} // namespace electron
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "shell/common/api/api.mojom.h"
|
||||
#include "shell/common/gin_converters/blink_converter.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include "shell/renderer/electron_renderer_client.h"
|
||||
#include "third_party/blink/public/common/page/page_zoom.h"
|
||||
#include "third_party/blink/public/common/web_cache/web_cache_resource_type_stats.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/platform/web_cache.h"
|
||||
#include "third_party/blink/public/platform/web_isolated_world_info.h"
|
||||
#include "third_party/blink/public/web/web_custom_element.h"
|
||||
|
@ -395,6 +397,65 @@ double GetZoomFactor(gin_helper::ErrorThrower thrower,
|
|||
return blink::PageZoomLevelToZoomFactor(zoom_level);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> GetWebPreference(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> window,
|
||||
std::string pref_name) {
|
||||
content::RenderFrame* render_frame = GetRenderFrame(window);
|
||||
const auto& prefs = render_frame->GetBlinkPreferences();
|
||||
|
||||
if (pref_name == options::kPreloadScripts) {
|
||||
return gin::ConvertToV8(isolate, prefs.preloads);
|
||||
} else if (pref_name == options::kDisableElectronSiteInstanceOverrides) {
|
||||
return gin::ConvertToV8(isolate,
|
||||
prefs.disable_electron_site_instance_overrides);
|
||||
} else if (pref_name == options::kBackgroundColor) {
|
||||
return gin::ConvertToV8(isolate, prefs.background_color);
|
||||
} else if (pref_name == options::kOpenerID) {
|
||||
// NOTE: openerId is internal-only.
|
||||
return gin::ConvertToV8(isolate, prefs.opener_id);
|
||||
} else if (pref_name == options::kContextIsolation) {
|
||||
return gin::ConvertToV8(isolate, prefs.context_isolation);
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
} else if (pref_name == options::kEnableRemoteModule) {
|
||||
return gin::ConvertToV8(isolate, prefs.enable_remote_module);
|
||||
#endif
|
||||
} else if (pref_name == options::kWorldSafeExecuteJavaScript) {
|
||||
return gin::ConvertToV8(isolate, prefs.world_safe_execute_javascript);
|
||||
} else if (pref_name == options::kGuestInstanceID) {
|
||||
// NOTE: guestInstanceId is internal-only.
|
||||
return gin::ConvertToV8(isolate, prefs.guest_instance_id);
|
||||
} else if (pref_name == options::kHiddenPage) {
|
||||
// NOTE: hiddenPage is internal-only.
|
||||
return gin::ConvertToV8(isolate, prefs.hidden_page);
|
||||
} else if (pref_name == options::kOffscreen) {
|
||||
return gin::ConvertToV8(isolate, prefs.offscreen);
|
||||
} else if (pref_name == options::kPreloadScript) {
|
||||
return gin::ConvertToV8(isolate, prefs.preload.value());
|
||||
} else if (pref_name == options::kNativeWindowOpen) {
|
||||
return gin::ConvertToV8(isolate, prefs.native_window_open);
|
||||
} else if (pref_name == options::kNodeIntegration) {
|
||||
return gin::ConvertToV8(isolate, prefs.node_integration);
|
||||
} else if (pref_name == options::kNodeIntegrationInWorker) {
|
||||
return gin::ConvertToV8(isolate, prefs.node_integration_in_worker);
|
||||
} else if (pref_name == options::kEnableNodeLeakageInRenderers) {
|
||||
// NOTE: enableNodeLeakageInRenderers is internal-only.
|
||||
return gin::ConvertToV8(isolate, prefs.node_leakage_in_renderers);
|
||||
} else if (pref_name == options::kNodeIntegrationInSubFrames) {
|
||||
return gin::ConvertToV8(isolate, true);
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
} else if (pref_name == options::kSpellcheck) {
|
||||
return gin::ConvertToV8(isolate, prefs.enable_spellcheck);
|
||||
#endif
|
||||
} else if (pref_name == options::kPlugins) {
|
||||
return gin::ConvertToV8(isolate, prefs.enable_plugins);
|
||||
} else if (pref_name == options::kEnableWebSQL) {
|
||||
return gin::ConvertToV8(isolate, prefs.enable_websql);
|
||||
} else if (pref_name == options::kWebviewTag) {
|
||||
return gin::ConvertToV8(isolate, prefs.webview_tag);
|
||||
}
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
void SetVisualZoomLevelLimits(gin_helper::ErrorThrower thrower,
|
||||
v8::Local<v8::Value> window,
|
||||
double min_level,
|
||||
|
@ -574,13 +635,13 @@ v8::Local<v8::Promise> ExecuteJavaScript(gin_helper::Arguments* args,
|
|||
ScriptExecutionCallback::CompletionCallback completion_callback;
|
||||
args->GetNext(&completion_callback);
|
||||
|
||||
bool world_safe_exec_js = base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kWorldSafeExecuteJavaScript);
|
||||
auto& prefs = render_frame->GetBlinkPreferences();
|
||||
|
||||
render_frame->GetWebFrame()->RequestExecuteScriptAndReturnValue(
|
||||
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
|
||||
has_user_gesture,
|
||||
new ScriptExecutionCallback(std::move(promise), world_safe_exec_js,
|
||||
new ScriptExecutionCallback(std::move(promise),
|
||||
prefs.world_safe_execute_javascript,
|
||||
std::move(completion_callback)));
|
||||
|
||||
return handle;
|
||||
|
@ -640,8 +701,7 @@ v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
|||
blink::WebURL(GURL(url)), start_line));
|
||||
}
|
||||
|
||||
bool world_safe_exec_js = base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kWorldSafeExecuteJavaScript);
|
||||
auto& prefs = render_frame->GetBlinkPreferences();
|
||||
|
||||
// Debugging tip: if you see a crash stack trace beginning from this call,
|
||||
// then it is very likely that some exception happened when executing the
|
||||
|
@ -649,7 +709,8 @@ v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
|||
render_frame->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
|
||||
world_id, &sources.front(), sources.size(), has_user_gesture,
|
||||
scriptExecutionType,
|
||||
new ScriptExecutionCallback(std::move(promise), world_safe_exec_js,
|
||||
new ScriptExecutionCallback(std::move(promise),
|
||||
prefs.world_safe_execute_javascript,
|
||||
std::move(completion_callback)));
|
||||
|
||||
return handle;
|
||||
|
@ -852,6 +913,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
dict.SetMethod("allowGuestViewElementDefinition",
|
||||
&AllowGuestViewElementDefinition);
|
||||
dict.SetMethod("getWebFrameId", &GetWebFrameId);
|
||||
dict.SetMethod("getWebPreference", &GetWebPreference);
|
||||
dict.SetMethod("setSpellCheckProvider", &SetSpellCheckProvider);
|
||||
dict.SetMethod("insertText", &InsertText);
|
||||
dict.SetMethod("insertCSS", &InsertCSS);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "base/command_line.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/platform/url_conversion.h"
|
||||
#include "third_party/blink/public/platform/web_security_origin.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
|
@ -23,8 +24,10 @@ ContentSettingsObserver::~ContentSettingsObserver() = default;
|
|||
|
||||
bool ContentSettingsObserver::AllowStorageAccessSync(StorageType storage_type) {
|
||||
if (storage_type == StorageType::kDatabase &&
|
||||
!base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableWebSQL)) {
|
||||
// Command line support is still relevant for extensions.
|
||||
!(base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableWebSQL) ||
|
||||
render_frame()->GetBlinkPreferences().enable_websql)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "services/service_manager/public/cpp/interface_provider.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/world_ids.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/platform/web_isolated_world_info.h"
|
||||
#include "third_party/blink/public/web/blink.h"
|
||||
#include "third_party/blink/public/web/web_document.h"
|
||||
|
@ -64,21 +65,18 @@ void ElectronRenderFrameObserver::DidInstallConditionalFeatures(
|
|||
if (ShouldNotifyClient(world_id))
|
||||
renderer_client_->DidCreateScriptContext(context, render_frame_);
|
||||
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
bool use_context_isolation = renderer_client_->isolated_world();
|
||||
auto prefs = render_frame_->GetBlinkPreferences();
|
||||
bool use_context_isolation = prefs.context_isolation;
|
||||
// This logic matches the EXPLAINED logic in electron_renderer_client.cc
|
||||
// to avoid explaining it twice go check that implementation in
|
||||
// DidCreateScriptContext();
|
||||
bool is_main_world = IsMainWorld(world_id);
|
||||
bool is_main_frame = render_frame_->IsMainFrame();
|
||||
bool reuse_renderer_processes_enabled =
|
||||
command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides);
|
||||
bool is_not_opened =
|
||||
!render_frame_->GetWebFrame()->Opener() ||
|
||||
command_line->HasSwitch(switches::kEnableNodeLeakageInRenderers);
|
||||
bool allow_node_in_sub_frames =
|
||||
command_line->HasSwitch(switches::kNodeIntegrationInSubFrames);
|
||||
prefs.disable_electron_site_instance_overrides;
|
||||
bool is_not_opened = !render_frame_->GetWebFrame()->Opener() ||
|
||||
prefs.node_leakage_in_renderers;
|
||||
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
|
||||
bool should_create_isolated_context =
|
||||
use_context_isolation && is_main_world &&
|
||||
(is_main_frame || allow_node_in_sub_frames) &&
|
||||
|
@ -163,10 +161,9 @@ bool ElectronRenderFrameObserver::IsIsolatedWorld(int world_id) {
|
|||
}
|
||||
|
||||
bool ElectronRenderFrameObserver::ShouldNotifyClient(int world_id) {
|
||||
bool allow_node_in_sub_frames =
|
||||
base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kNodeIntegrationInSubFrames);
|
||||
if (renderer_client_->isolated_world() &&
|
||||
auto prefs = render_frame_->GetBlinkPreferences();
|
||||
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
|
||||
if (prefs.context_isolation &&
|
||||
(render_frame_->IsMainFrame() || allow_node_in_sub_frames))
|
||||
return IsIsolatedWorld(world_id);
|
||||
else
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "shell/common/options_switches.h"
|
||||
#include "shell/renderer/electron_render_frame_observer.h"
|
||||
#include "shell/renderer/web_worker_observer.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/web/web_document.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
|
||||
|
@ -91,17 +92,15 @@ void ElectronRendererClient::DidCreateScriptContext(
|
|||
// TODO(zcbenz): Do not create Node environment if node integration is not
|
||||
// enabled.
|
||||
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
// Only load node if we are a main frame or a devtools extension
|
||||
// unless node support has been explicitly enabled for sub frames
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
bool reuse_renderer_processes_enabled =
|
||||
command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides);
|
||||
prefs.disable_electron_site_instance_overrides;
|
||||
// Consider the window not "opened" if it does not have an Opener, or if a
|
||||
// user has manually opted in to leaking node in the renderer
|
||||
bool is_not_opened =
|
||||
!render_frame->GetWebFrame()->Opener() ||
|
||||
command_line->HasSwitch(switches::kEnableNodeLeakageInRenderers);
|
||||
!render_frame->GetWebFrame()->Opener() || prefs.node_leakage_in_renderers;
|
||||
// Consider this the main frame if it is both a Main Frame and it wasn't
|
||||
// opened. We allow an opened main frame to have node if renderer process
|
||||
// reuse is enabled as that will correctly free node environments prevent a
|
||||
|
@ -109,8 +108,7 @@ void ElectronRendererClient::DidCreateScriptContext(
|
|||
bool is_main_frame = render_frame->IsMainFrame() &&
|
||||
(is_not_opened || reuse_renderer_processes_enabled);
|
||||
bool is_devtools = IsDevToolsExtension(render_frame);
|
||||
bool allow_node_in_subframes =
|
||||
command_line->HasSwitch(switches::kNodeIntegrationInSubFrames);
|
||||
bool allow_node_in_subframes = prefs.node_integration_in_sub_frames;
|
||||
bool should_load_node =
|
||||
(is_main_frame || is_devtools || allow_node_in_subframes) &&
|
||||
!IsWebViewFrame(renderer_context, render_frame);
|
||||
|
@ -186,10 +184,9 @@ void ElectronRendererClient::WillReleaseScriptContext(
|
|||
// for existing users.
|
||||
// We also do this if we have disable electron site instance overrides to
|
||||
// avoid memory leaks
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (command_line->HasSwitch(switches::kNodeIntegrationInSubFrames) ||
|
||||
command_line->HasSwitch(
|
||||
switches::kDisableElectronSiteInstanceOverrides)) {
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
if (prefs.node_integration_in_sub_frames ||
|
||||
prefs.disable_electron_site_instance_overrides) {
|
||||
node::FreeEnvironment(env);
|
||||
if (env == node_bindings_->uv_env())
|
||||
node::FreeIsolateData(node_bindings_->isolate_data());
|
||||
|
@ -213,6 +210,8 @@ bool ElectronRendererClient::ShouldFork(blink::WebLocalFrame* frame,
|
|||
|
||||
void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
|
||||
v8::Local<v8::Context> context) {
|
||||
// TODO(loc): Note that this will not be correct for in-process child windows
|
||||
// with webPreferences that have a different value for nodeIntegrationInWorker
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kNodeIntegrationInWorker)) {
|
||||
WebWorkerObserver::GetCurrent()->WorkerScriptReadyForEvaluation(context);
|
||||
|
@ -221,6 +220,8 @@ void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
|
|||
|
||||
void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
|
||||
v8::Local<v8::Context> context) {
|
||||
// TODO(loc): Note that this will not be correct for in-process child windows
|
||||
// with webPreferences that have a different value for nodeIntegrationInWorker
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kNodeIntegrationInWorker)) {
|
||||
WebWorkerObserver::GetCurrent()->ContextWillDestroy(context);
|
||||
|
@ -230,8 +231,9 @@ void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
|
|||
void ElectronRendererClient::SetupMainWorldOverrides(
|
||||
v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) {
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
// We only need to run the isolated bundle if webview is enabled
|
||||
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWebviewTag))
|
||||
if (!prefs.webview_tag)
|
||||
return;
|
||||
// Setup window overrides in the main world context
|
||||
// Wrap the bundle into a function that receives the isolatedWorld as
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "shell/common/node_util.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/renderer/electron_render_frame_observer.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/web/blink.h"
|
||||
#include "third_party/blink/public/web/web_document.h"
|
||||
#include "third_party/electron_node/src/node_binding.h"
|
||||
|
@ -198,8 +199,7 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
|
|||
bool is_devtools =
|
||||
IsDevTools(render_frame) || IsDevToolsExtension(render_frame);
|
||||
bool allow_node_in_sub_frames =
|
||||
base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kNodeIntegrationInSubFrames);
|
||||
render_frame->GetBlinkPreferences().node_integration_in_sub_frames;
|
||||
bool should_load_preload =
|
||||
(is_main_frame || is_devtools || allow_node_in_sub_frames) &&
|
||||
!IsWebViewFrame(context, render_frame);
|
||||
|
@ -232,8 +232,9 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
|
|||
void ElectronSandboxedRendererClient::SetupMainWorldOverrides(
|
||||
v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) {
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
// We only need to run the isolated bundle if webview is enabled
|
||||
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWebviewTag))
|
||||
if (!prefs.webview_tag)
|
||||
return;
|
||||
|
||||
// Setup window overrides in the main world context
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "shell/renderer/electron_api_service_impl.h"
|
||||
#include "shell/renderer/electron_autofill_agent.h"
|
||||
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/web/blink.h"
|
||||
#include "third_party/blink/public/web/web_custom_element.h" // NOLINT(build/include_alpha)
|
||||
#include "third_party/blink/public/web/web_frame_widget.h"
|
||||
|
@ -112,8 +113,6 @@ RendererClientBase::RendererClientBase() {
|
|||
ParseSchemesCLISwitch(command_line, switches::kStreamingSchemes);
|
||||
for (const std::string& scheme : streaming_schemes_list)
|
||||
media::AddStreamingScheme(scheme.c_str());
|
||||
isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kContextIsolation);
|
||||
// We rely on the unique process host id which is notified to the
|
||||
// renderer process via command line switch from the content layer,
|
||||
// if this switch is removed from the content layer for some reason,
|
||||
|
@ -135,9 +134,8 @@ void RendererClientBase::DidCreateScriptContext(
|
|||
global.SetHidden("contextId", context_id);
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
bool enableRemoteModule =
|
||||
command_line->HasSwitch(switches::kEnableRemoteModule);
|
||||
render_frame->GetBlinkPreferences().enable_remote_module;
|
||||
global.SetHidden("enableRemoteModule", enableRemoteModule);
|
||||
#endif
|
||||
}
|
||||
|
@ -153,6 +151,8 @@ void RendererClientBase::RenderThreadStarted() {
|
|||
// On macOS, popup menus are rendered by the main process by default.
|
||||
// This causes problems in OSR, since when the popup is rendered separately,
|
||||
// it won't be captured in the rendered image.
|
||||
// TODO(loc): This will be wrong for in-process child windows, as this
|
||||
// function won't run again for them.
|
||||
if (command_line->HasSwitch(options::kOffscreen)) {
|
||||
blink::WebView::SetUseExternalPopupMenus(false);
|
||||
}
|
||||
|
@ -177,8 +177,7 @@ void RendererClientBase::RenderThreadStarted() {
|
|||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
if (command_line->HasSwitch(switches::kEnableSpellcheck))
|
||||
spellcheck_ = std::make_unique<SpellCheck>(this);
|
||||
spellcheck_ = std::make_unique<SpellCheck>(this);
|
||||
#endif
|
||||
|
||||
blink::WebCustomElement::AddEmbedderCustomElementName("webview");
|
||||
|
@ -274,11 +273,11 @@ void RendererClientBase::RenderFrameCreated(
|
|||
if (render_frame->IsMainFrame() && render_view) {
|
||||
blink::WebView* webview = render_view->GetWebView();
|
||||
if (webview) {
|
||||
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview.
|
||||
auto prefs = render_frame->GetBlinkPreferences();
|
||||
if (prefs.guest_instance_id) { // webview.
|
||||
webview->SetBaseBackgroundColor(SK_ColorTRANSPARENT);
|
||||
} else { // normal window.
|
||||
std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor);
|
||||
std::string name = prefs.background_color;
|
||||
SkColor color =
|
||||
name.empty() ? SK_ColorTRANSPARENT : ParseHexColor(name);
|
||||
webview->SetBaseBackgroundColor(color);
|
||||
|
@ -300,8 +299,7 @@ void RendererClientBase::RenderFrameCreated(
|
|||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (command_line->HasSwitch(switches::kEnableSpellcheck))
|
||||
if (render_frame->GetBlinkPreferences().enable_spellcheck)
|
||||
new SpellCheckProvider(render_frame, spellcheck_.get(), this);
|
||||
#endif
|
||||
}
|
||||
|
@ -330,12 +328,11 @@ bool RendererClientBase::OverrideCreatePlugin(
|
|||
content::RenderFrame* render_frame,
|
||||
const blink::WebPluginParams& params,
|
||||
blink::WebPlugin** plugin) {
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (params.mime_type.Utf8() == content::kBrowserPluginMimeType ||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
params.mime_type.Utf8() == kPdfPluginMimeType ||
|
||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
command_line->HasSwitch(switches::kEnablePlugins))
|
||||
render_frame->GetBlinkPreferences().enable_plugins)
|
||||
return false;
|
||||
|
||||
*plugin = nullptr;
|
||||
|
@ -444,7 +441,9 @@ void RendererClientBase::RunScriptsAtDocumentEnd(
|
|||
v8::Local<v8::Context> RendererClientBase::GetContext(
|
||||
blink::WebLocalFrame* frame,
|
||||
v8::Isolate* isolate) const {
|
||||
if (isolated_world())
|
||||
auto* render_frame = content::RenderFrame::FromWebFrame(frame);
|
||||
DCHECK(render_frame);
|
||||
if (render_frame && render_frame->GetBlinkPreferences().context_isolation)
|
||||
return frame->WorldScriptContext(isolate, WorldIDs::ISOLATED_WORLD_ID);
|
||||
else
|
||||
return frame->MainWorldScriptContext();
|
||||
|
|
|
@ -79,7 +79,6 @@ class RendererClientBase : public content::ContentRendererClient
|
|||
|
||||
std::unique_ptr<blink::WebPrescientNetworking> CreatePrescientNetworking(
|
||||
content::RenderFrame* render_frame) override;
|
||||
bool isolated_world() const { return isolated_world_; }
|
||||
|
||||
// Get the context that the Electron API is running in.
|
||||
v8::Local<v8::Context> GetContext(blink::WebLocalFrame* frame,
|
||||
|
@ -143,7 +142,6 @@ class RendererClientBase : public content::ContentRendererClient
|
|||
#if defined(WIDEVINE_CDM_AVAILABLE)
|
||||
ChromeKeySystemsProvider key_systems_provider_;
|
||||
#endif
|
||||
bool isolated_world_;
|
||||
std::string renderer_client_id_;
|
||||
// An increasing ID used for identifying an V8 context in this process.
|
||||
int64_t next_context_id_ = 0;
|
||||
|
|
|
@ -225,16 +225,16 @@ describe('BrowserView module', () => {
|
|||
});
|
||||
|
||||
describe('window.open()', () => {
|
||||
it('works in BrowserView', async () => {
|
||||
it('works in BrowserView', (done) => {
|
||||
view = new BrowserView();
|
||||
w.setBrowserView(view);
|
||||
const newWindow = emittedOnce(view.webContents, 'new-window');
|
||||
view.webContents.once('new-window', event => event.preventDefault());
|
||||
view.webContents.setWindowOpenHandler(({ url, frameName }) => {
|
||||
expect(url).to.equal('http://host/');
|
||||
expect(frameName).to.equal('host');
|
||||
done();
|
||||
return { action: 'deny' };
|
||||
});
|
||||
view.webContents.loadFile(path.join(fixtures, 'pages', 'window-open.html'));
|
||||
const [, url, frameName,,, additionalFeatures] = await newWindow;
|
||||
expect(url).to.equal('http://host/');
|
||||
expect(frameName).to.equal('host');
|
||||
expect(additionalFeatures[0]).to.equal('this-is-not-a-standard-feature');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -114,7 +114,7 @@ describe('BrowserWindow with affinity module', () => {
|
|||
]);
|
||||
await closeWindow(w, { assertNotWindows: false });
|
||||
});
|
||||
it('disables node integration when first window is false', async () => {
|
||||
it('allows nodeIntegration to enable in second window with the same affinity', async () => {
|
||||
const [, w1] = await Promise.all([
|
||||
testNodeIntegration(false),
|
||||
createWindowWithWebPrefs({
|
||||
|
@ -124,7 +124,7 @@ describe('BrowserWindow with affinity module', () => {
|
|||
})
|
||||
]);
|
||||
const [, w2] = await Promise.all([
|
||||
testNodeIntegration(false),
|
||||
testNodeIntegration(true),
|
||||
createWindowWithWebPrefs({
|
||||
affinity: affinityWithNodeTrue,
|
||||
preload,
|
||||
|
@ -149,7 +149,7 @@ describe('BrowserWindow with affinity module', () => {
|
|||
await closeWindow(w, { assertNotWindows: false });
|
||||
});
|
||||
|
||||
it('enables node integration when first window is true', async () => {
|
||||
it('allows nodeIntegration to disable in second window with the same affinity', async () => {
|
||||
const [, w1] = await Promise.all([
|
||||
testNodeIntegration(true),
|
||||
createWindowWithWebPrefs({
|
||||
|
@ -159,7 +159,7 @@ describe('BrowserWindow with affinity module', () => {
|
|||
})
|
||||
]);
|
||||
const [, w2] = await Promise.all([
|
||||
testNodeIntegration(true),
|
||||
testNodeIntegration(false),
|
||||
createWindowWithWebPrefs({
|
||||
affinity: affinityWithNodeFalse,
|
||||
preload,
|
||||
|
|
|
@ -2175,20 +2175,27 @@ describe('BrowserWindow module', () => {
|
|||
|
||||
it('should open windows in same domain with cross-scripting enabled', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
show: true,
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
preload
|
||||
}
|
||||
});
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preload;
|
||||
});
|
||||
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
const htmlPath = path.join(__dirname, 'fixtures', 'api', 'sandbox.html?window-open');
|
||||
const pageUrl = 'file://' + htmlPath;
|
||||
const answer = emittedOnce(ipcMain, 'answer');
|
||||
w.loadURL(pageUrl);
|
||||
const [, url, frameName, , options] = await emittedOnce(w.webContents, 'new-window');
|
||||
const [, { url, frameName, options }] = await emittedOnce(w.webContents, 'did-create-window');
|
||||
const expectedUrl = process.platform === 'win32'
|
||||
? 'file:///' + htmlPath.replace(/\\/g, '/')
|
||||
: pageUrl;
|
||||
|
@ -2202,16 +2209,22 @@ describe('BrowserWindow module', () => {
|
|||
|
||||
it('should open windows in another domain with cross-scripting disabled', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
show: true,
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
preload
|
||||
}
|
||||
});
|
||||
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preload;
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
w.loadFile(
|
||||
path.join(__dirname, 'fixtures', 'api', 'sandbox.html'),
|
||||
{ search: 'window-open-external' }
|
||||
|
@ -2267,12 +2280,10 @@ describe('BrowserWindow module', () => {
|
|||
});
|
||||
|
||||
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preloadPath;
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload: preloadPath } } }));
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
|
||||
const [, args] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(args).to.include('--enable-sandbox');
|
||||
const [, { argv }] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(argv).to.include('--enable-sandbox');
|
||||
});
|
||||
|
||||
it('should open windows with the options configured via new-window event listeners', async () => {
|
||||
|
@ -2284,11 +2295,7 @@ describe('BrowserWindow module', () => {
|
|||
});
|
||||
|
||||
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preloadPath;
|
||||
const prefs = options.webPreferences as any;
|
||||
prefs.foo = 'bar';
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload: preloadPath, foo: 'bar' } } }));
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
|
||||
const [[, childWebContents]] = await Promise.all([
|
||||
emittedOnce(app, 'web-contents-created'),
|
||||
|
@ -2307,11 +2314,13 @@ describe('BrowserWindow module', () => {
|
|||
}
|
||||
});
|
||||
let childWc: WebContents | null = null;
|
||||
w.webContents.on('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preload;
|
||||
childWc = (options as any).webContents;
|
||||
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload } } }));
|
||||
|
||||
w.webContents.on('did-create-window', (win) => {
|
||||
childWc = win.webContents;
|
||||
expect(w.webContents).to.not.equal(childWc);
|
||||
});
|
||||
|
||||
ipcMain.once('parent-ready', function (event) {
|
||||
expect(event.sender).to.equal(w.webContents, 'sender should be the parent');
|
||||
event.sender.send('verified');
|
||||
|
@ -2438,9 +2447,7 @@ describe('BrowserWindow module', () => {
|
|||
enableRemoteModule: true
|
||||
}
|
||||
});
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preload;
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload } } }));
|
||||
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'reload-remote-child' });
|
||||
|
||||
|
@ -2602,20 +2609,30 @@ describe('BrowserWindow module', () => {
|
|||
});
|
||||
it('should inherit the nativeWindowOpen setting in opened windows', async () => {
|
||||
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preloadPath;
|
||||
});
|
||||
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload: preloadPath
|
||||
}
|
||||
}
|
||||
}));
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
|
||||
const [, args] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(args).to.include('--native-window-open');
|
||||
const [, { nativeWindowOpen }] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(nativeWindowOpen).to.be.true();
|
||||
});
|
||||
it('should open windows with the options configured via new-window event listeners', async () => {
|
||||
const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js');
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preloadPath;
|
||||
const prefs = options.webPreferences! as any;
|
||||
prefs.foo = 'bar';
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload: preloadPath,
|
||||
foo: 'bar'
|
||||
}
|
||||
}
|
||||
}));
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
|
||||
const [[, childWebContents]] = await Promise.all([
|
||||
emittedOnce(app, 'web-contents-created'),
|
||||
|
@ -2655,13 +2672,19 @@ describe('BrowserWindow module', () => {
|
|||
}
|
||||
});
|
||||
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = path.join(fixtures, 'api', 'window-open-preload.js');
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload: path.join(fixtures, 'api', 'window-open-preload.js')
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
w.loadFile(path.join(fixtures, 'api', 'window-open-location-open.html'));
|
||||
const [, args, typeofProcess] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(args).not.to.include('--node-integration');
|
||||
expect(args).to.include('--native-window-open');
|
||||
const [, { nodeIntegration, nativeWindowOpen, typeofProcess }] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(nodeIntegration).to.be.false();
|
||||
expect(nativeWindowOpen).to.be.true();
|
||||
expect(typeofProcess).to.eql('undefined');
|
||||
});
|
||||
|
||||
|
@ -2675,11 +2698,16 @@ describe('BrowserWindow module', () => {
|
|||
}
|
||||
});
|
||||
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = path.join(fixtures, 'api', 'window-open-preload.js');
|
||||
});
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload: path.join(fixtures, 'api', 'window-open-preload.js')
|
||||
}
|
||||
}
|
||||
}));
|
||||
w.loadFile(path.join(fixtures, 'api', 'window-open-location-open.html'));
|
||||
const [, , , windowOpenerIsNull] = await emittedOnce(ipcMain, 'answer');
|
||||
const [, { windowOpenerIsNull }] = await emittedOnce(ipcMain, 'answer');
|
||||
expect(windowOpenerIsNull).to.be.false('window.opener is null');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -82,15 +82,19 @@ describe('window.postMessage', () => {
|
|||
await closeAllWindows();
|
||||
});
|
||||
|
||||
it('sets the source and origin correctly', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
|
||||
w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`);
|
||||
const [, message] = await emittedOnce(ipcMain, 'complete');
|
||||
expect(message.data).to.equal('testing');
|
||||
expect(message.origin).to.equal('file://');
|
||||
expect(message.sourceEqualsOpener).to.equal(true);
|
||||
expect(message.eventOrigin).to.equal('file://');
|
||||
});
|
||||
for (const nativeWindowOpen of [true, false]) {
|
||||
describe(`when nativeWindowOpen: ${nativeWindowOpen}`, () => {
|
||||
it('sets the source and origin correctly', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen } });
|
||||
w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`);
|
||||
const [, message] = await emittedOnce(ipcMain, 'complete');
|
||||
expect(message.data).to.equal('testing');
|
||||
expect(message.origin).to.equal('file://');
|
||||
expect(message.sourceEqualsOpener).to.equal(true);
|
||||
expect(message.eventOrigin).to.equal('file://');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('focus handling', () => {
|
||||
|
@ -620,7 +624,7 @@ describe('chromium features', () => {
|
|||
|
||||
describe('window.open', () => {
|
||||
for (const show of [true, false]) {
|
||||
it(`inherits parent visibility over parent {show=${show}} option`, async () => {
|
||||
it(`shows the child regardless of parent visibility when parent {show=${show}}`, async () => {
|
||||
const w = new BrowserWindow({ show });
|
||||
|
||||
// toggle visibility
|
||||
|
@ -635,7 +639,7 @@ describe('chromium features', () => {
|
|||
const newWindow = emittedOnce(w.webContents, 'new-window');
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'window-open.html'));
|
||||
const [,,,, options] = await newWindow;
|
||||
expect(options.show).to.equal(w.isVisible());
|
||||
expect(options.show).to.equal(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -671,35 +675,6 @@ describe('chromium features', () => {
|
|||
expect(preferences.javascript).to.be.false();
|
||||
});
|
||||
|
||||
it('handles cycles when merging the parent options into the child options', async () => {
|
||||
const foo = {} as any;
|
||||
foo.bar = foo;
|
||||
foo.baz = {
|
||||
hello: {
|
||||
world: true
|
||||
}
|
||||
};
|
||||
foo.baz2 = foo.baz;
|
||||
const w = new BrowserWindow({ show: false, foo: foo } as any);
|
||||
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'window-open.html'));
|
||||
const [,,,, options] = await emittedOnce(w.webContents, 'new-window');
|
||||
expect(options.show).to.be.false();
|
||||
expect((options as any).foo).to.deep.equal({
|
||||
bar: undefined,
|
||||
baz: {
|
||||
hello: {
|
||||
world: true
|
||||
}
|
||||
},
|
||||
baz2: {
|
||||
hello: {
|
||||
world: true
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('defines a window.location getter', async () => {
|
||||
let targetURL: string;
|
||||
if (process.platform === 'win32') {
|
||||
|
@ -925,10 +900,15 @@ describe('chromium features', () => {
|
|||
for (const sandboxPopup of [false, true]) {
|
||||
const description = `when parent=${s(parent)} opens child=${s(child)} with nodeIntegration=${nodeIntegration} nativeWindowOpen=${nativeWindowOpen} sandboxPopup=${sandboxPopup}, child should ${openerAccessible ? '' : 'not '}be able to access opener`;
|
||||
it(description, async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen } });
|
||||
w.webContents.once('new-window', (e, url, frameName, disposition, options) => {
|
||||
options!.webPreferences!.sandbox = sandboxPopup;
|
||||
});
|
||||
const w = new BrowserWindow({ show: true, webPreferences: { nodeIntegration: true, nativeWindowOpen } });
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
sandbox: sandboxPopup
|
||||
}
|
||||
}
|
||||
}));
|
||||
await w.loadURL(parent);
|
||||
const childOpenerLocation = await w.webContents.executeJavaScript(`new Promise(resolve => {
|
||||
window.addEventListener('message', function f(e) {
|
||||
|
|
|
@ -2,33 +2,33 @@
|
|||
[
|
||||
"top=5,left=10,resizable=no",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"returnValue": "placeholder-guest-contents-id"
|
||||
"sender": "[WebContents]"
|
||||
},
|
||||
"about:blank",
|
||||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"webContents": "[WebContents]",
|
||||
"title": "frame name",
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false,
|
||||
"webPreferences": {
|
||||
"nativeWindowOpen": true,
|
||||
"sandbox": true,
|
||||
"backgroundColor": "blue",
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": null
|
||||
},
|
||||
"show": true,
|
||||
"height": 600,
|
||||
"top": 5,
|
||||
"left": 10,
|
||||
"resizable": false,
|
||||
"x": 10,
|
||||
"y": 5,
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -40,32 +40,32 @@
|
|||
[
|
||||
"zoomFactor=2,resizable=0,x=0,y=10",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"returnValue": "placeholder-guest-contents-id"
|
||||
"sender": "[WebContents]"
|
||||
},
|
||||
"about:blank",
|
||||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"webContents": "[WebContents]",
|
||||
"title": "frame name",
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false,
|
||||
"webPreferences": {
|
||||
"zoomFactor": "2",
|
||||
"nativeWindowOpen": true,
|
||||
"sandbox": true,
|
||||
"backgroundColor": "blue",
|
||||
"zoomFactor": "2",
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": null
|
||||
},
|
||||
"show": true,
|
||||
"height": 600,
|
||||
"resizable": false,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -77,30 +77,30 @@
|
|||
[
|
||||
"backgroundColor=gray,webPreferences=0,x=100,y=100",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"returnValue": "placeholder-guest-contents-id"
|
||||
"sender": "[WebContents]"
|
||||
},
|
||||
"about:blank",
|
||||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"webContents": "[WebContents]",
|
||||
"title": "frame name",
|
||||
"backgroundColor": "gray",
|
||||
"focusable": false,
|
||||
"webPreferences": {
|
||||
"nativeWindowOpen": true,
|
||||
"sandbox": true,
|
||||
"backgroundColor": "gray",
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": null
|
||||
},
|
||||
"backgroundColor": "gray",
|
||||
"show": true,
|
||||
"height": 600,
|
||||
"x": 100,
|
||||
"y": 100,
|
||||
"focusable": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -112,30 +112,30 @@
|
|||
[
|
||||
"x=50,y=20,title=sup",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"returnValue": "placeholder-guest-contents-id"
|
||||
"sender": "[WebContents]"
|
||||
},
|
||||
"about:blank",
|
||||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"webContents": "[WebContents]",
|
||||
"title": "sup",
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false,
|
||||
"webPreferences": {
|
||||
"nativeWindowOpen": true,
|
||||
"sandbox": true,
|
||||
"backgroundColor": "blue",
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": null
|
||||
},
|
||||
"show": true,
|
||||
"height": 600,
|
||||
"x": 50,
|
||||
"y": 20,
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -147,32 +147,32 @@
|
|||
[
|
||||
"show=false,top=1,left=1",
|
||||
{
|
||||
"sender": "[WebContents]",
|
||||
"returnValue": "placeholder-guest-contents-id"
|
||||
"sender": "[WebContents]"
|
||||
},
|
||||
"about:blank",
|
||||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": false,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"webContents": "[WebContents]",
|
||||
"title": "frame name",
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false,
|
||||
"webPreferences": {
|
||||
"nativeWindowOpen": true,
|
||||
"sandbox": true,
|
||||
"backgroundColor": "blue",
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": null
|
||||
},
|
||||
"show": false,
|
||||
"height": 600,
|
||||
"top": 1,
|
||||
"left": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"backgroundColor": "blue",
|
||||
"focusable": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
|
|
@ -9,21 +9,22 @@
|
|||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"title": "frame name",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"top": 5,
|
||||
"left": 10,
|
||||
"resizable": false,
|
||||
"x": 10,
|
||||
"y": 5,
|
||||
"title": "frame name",
|
||||
"webPreferences": {
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": "placeholder-opener-id"
|
||||
},
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"show": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -42,10 +43,13 @@
|
|||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"title": "frame name",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": false,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"title": "frame name",
|
||||
"webPreferences": {
|
||||
"zoomFactor": "2",
|
||||
"nodeIntegration": false,
|
||||
|
@ -53,9 +57,7 @@
|
|||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": "placeholder-opener-id"
|
||||
},
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"show": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -74,6 +76,10 @@
|
|||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"title": "frame name",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"backgroundColor": "gray",
|
||||
"webPreferences": {
|
||||
"nodeIntegration": false,
|
||||
|
@ -84,10 +90,7 @@
|
|||
},
|
||||
"x": 100,
|
||||
"y": 100,
|
||||
"title": "frame name",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"show": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -106,18 +109,19 @@
|
|||
"frame name",
|
||||
"new-window",
|
||||
{
|
||||
"show": true,
|
||||
"title": "sup",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"x": 50,
|
||||
"y": 20,
|
||||
"title": "sup",
|
||||
"webPreferences": {
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": "placeholder-opener-id"
|
||||
},
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"show": false
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
@ -137,19 +141,20 @@
|
|||
"new-window",
|
||||
{
|
||||
"show": false,
|
||||
"title": "frame name",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"top": 1,
|
||||
"left": 1,
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"title": "frame name",
|
||||
"webPreferences": {
|
||||
"nodeIntegration": false,
|
||||
"webviewTag": false,
|
||||
"nodeIntegrationInSubFrames": false,
|
||||
"openerId": "placeholder-opener-id"
|
||||
},
|
||||
"width": 800,
|
||||
"height": 600
|
||||
"webContents": "[WebContents]"
|
||||
},
|
||||
[],
|
||||
{
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import { BrowserWindow } from 'electron';
|
||||
import { writeFileSync, readFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import { expect } from 'chai';
|
||||
import { expect, assert } from 'chai';
|
||||
import { closeAllWindows } from './window-helpers';
|
||||
const { emittedOnce } = require('./events-helpers');
|
||||
|
||||
function genSnapshot (browserWindow: BrowserWindow, features: string) {
|
||||
return new Promise((resolve) => {
|
||||
browserWindow.webContents.on('new-window', (...args: any[]) => {
|
||||
resolve([features, ...args]);
|
||||
});
|
||||
browserWindow.webContents.executeJavaScript(`window.open('about:blank', 'frame name', '${features}')`);
|
||||
browserWindow.webContents.executeJavaScript(`window.open('about:blank', 'frame name', '${features}') && true`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -52,7 +53,7 @@ describe('new-window event', () => {
|
|||
beforeEach((done) => {
|
||||
browserWindow = new BrowserWindow(browserWindowOptions);
|
||||
browserWindow.loadURL('about:blank');
|
||||
browserWindow.on('ready-to-show', () => done());
|
||||
browserWindow.on('ready-to-show', () => { done(); });
|
||||
});
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
|
@ -86,6 +87,100 @@ describe('new-window event', () => {
|
|||
}
|
||||
});
|
||||
|
||||
describe('webContents.setWindowOpenHandler', () => {
|
||||
const testConfig = {
|
||||
native: {
|
||||
browserWindowOptions: {
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true
|
||||
}
|
||||
}
|
||||
},
|
||||
proxy: {
|
||||
browserWindowOptions: {
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const testName of Object.keys(testConfig) as (keyof typeof testConfig)[]) {
|
||||
let browserWindow: BrowserWindow;
|
||||
const { browserWindowOptions } = testConfig[testName];
|
||||
|
||||
describe(testName, () => {
|
||||
beforeEach((done) => {
|
||||
browserWindow = new BrowserWindow(browserWindowOptions);
|
||||
browserWindow.loadURL('about:blank');
|
||||
browserWindow.on('ready-to-show', () => { browserWindow.show(); done(); });
|
||||
});
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('does not fire window creation events if an override returns action: deny', (done) => {
|
||||
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }));
|
||||
browserWindow.webContents.on('new-window', () => {
|
||||
assert.fail('new-window should not to be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.on('did-create-window', () => {
|
||||
assert.fail('did-create-window should not to be called with an overridden window.open');
|
||||
});
|
||||
|
||||
browserWindow.webContents.executeJavaScript("window.open('about:blank') && true");
|
||||
|
||||
setTimeout(() => {
|
||||
done();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
it('fires handler with correct params', (done) => {
|
||||
const testFrameName = 'test-frame-name';
|
||||
const testFeatures = 'top=10&left=10&something-unknown';
|
||||
const testUrl = 'app://does-not-exist/';
|
||||
browserWindow.webContents.setWindowOpenHandler(({ url, frameName, features }) => {
|
||||
expect(url).to.equal(testUrl);
|
||||
expect(frameName).to.equal(testFrameName);
|
||||
expect(features).to.equal(testFeatures);
|
||||
done();
|
||||
return { action: 'deny' };
|
||||
});
|
||||
|
||||
browserWindow.webContents.executeJavaScript(`window.open('${testUrl}', '${testFrameName}', '${testFeatures}') && true`);
|
||||
});
|
||||
|
||||
it('does fire window creation events if an override returns action: allow', async () => {
|
||||
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' }));
|
||||
|
||||
setImmediate(() => {
|
||||
browserWindow.webContents.executeJavaScript("window.open('about:blank') && true");
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
emittedOnce(browserWindow.webContents, 'did-create-window'),
|
||||
emittedOnce(browserWindow.webContents, 'new-window')
|
||||
]);
|
||||
});
|
||||
|
||||
it('can change webPreferences of child windows', (done) => {
|
||||
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } }));
|
||||
|
||||
browserWindow.webContents.on('did-create-window', async (childWindow) => {
|
||||
await childWindow.webContents.executeJavaScript("document.write('hello')");
|
||||
const size = await childWindow.webContents.executeJavaScript("getComputedStyle(document.querySelector('body')).fontSize");
|
||||
expect(size).to.equal('30px');
|
||||
done();
|
||||
});
|
||||
|
||||
browserWindow.webContents.executeJavaScript("window.open('about:blank') && true");
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function stringifySnapshots (snapshots: any, pretty = false) {
|
||||
return JSON.stringify(snapshots, (key, value) => {
|
||||
if (['sender', 'webContents'].includes(key)) {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
const { ipcRenderer } = require('electron');
|
||||
const { ipcRenderer, webFrame } = require('electron');
|
||||
|
||||
ipcRenderer.send('answer', process.argv);
|
||||
ipcRenderer.send('answer', {
|
||||
nativeWindowOpen: webFrame.getWebPreference('nativeWindowOpen'),
|
||||
argv: process.argv
|
||||
});
|
||||
window.close();
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
const { ipcRenderer } = require('electron');
|
||||
const { ipcRenderer, webFrame } = require('electron');
|
||||
|
||||
setImmediate(function () {
|
||||
if (window.location.toString() === 'bar://page/') {
|
||||
const windowOpenerIsNull = window.opener == null;
|
||||
ipcRenderer.send('answer', process.argv, typeof global.process, windowOpenerIsNull);
|
||||
ipcRenderer.send('answer', {
|
||||
nativeWindowOpen: webFrame.getWebPreference('nativeWindowOpen'),
|
||||
nodeIntegration: webFrame.getWebPreference('nodeIntegration'),
|
||||
sandbox: webFrame.getWebPreference('sandbox'),
|
||||
typeofProcess: typeof global.process,
|
||||
windowOpenerIsNull
|
||||
});
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
const {ipcRenderer} = require('electron')
|
||||
ipcRenderer.send('pong', document.visibilityState, document.hidden)
|
||||
document.addEventListener('visibilitychange', function () {
|
||||
ipcRenderer.send('pong', document.visibilityState, document.hidden)
|
||||
setTimeout(() => {
|
||||
ipcRenderer.send('pong', document.visibilityState, document.hidden)
|
||||
}, 500);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
|
Двоичный файл не отображается.
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
declare var internalBinding: any;
|
||||
declare var nodeProcess: any;
|
||||
declare var isolatedWorld: any;
|
||||
|
@ -45,8 +46,8 @@ declare namespace NodeJS {
|
|||
clearWeaklyTrackedValues(): void;
|
||||
getWeaklyTrackedValues(): any[];
|
||||
addRemoteObjectRef(contextId: string, id: number): void;
|
||||
isSameOrigin(a: string, b: string): boolean;
|
||||
triggerFatalErrorForTesting(): void;
|
||||
isSameOrigin(left: string, right: string): boolean;
|
||||
}
|
||||
|
||||
interface EnvironmentBinding {
|
||||
|
@ -118,7 +119,7 @@ declare namespace NodeJS {
|
|||
session?: Electron.Session;
|
||||
partition?: string;
|
||||
referrer?: string;
|
||||
}
|
||||
};
|
||||
type ResponseHead = {
|
||||
statusCode: number;
|
||||
statusMessage: string;
|
||||
|
|
|
@ -64,6 +64,9 @@ declare namespace Electron {
|
|||
equal(other: WebContents): boolean;
|
||||
_initiallyShown: boolean;
|
||||
browserWindowOptions: BrowserWindowConstructorOptions;
|
||||
_windowOpenHandler: ((opts: {url: string, frameName: string, features: string}) => any) | null;
|
||||
_callWindowOpenHandler(event: any, url: string, frameName: string, rawFeatures: string): Electron.BrowserWindowConstructorOptions | null;
|
||||
_setNextChildWebPreferences(prefs: Partial<Electron.BrowserWindowConstructorOptions['webPreferences']> & Pick<Electron.BrowserWindowConstructorOptions, 'backgroundColor'>): void;
|
||||
_send(internal: boolean, sendToAll: boolean, channel: string, args: any): boolean;
|
||||
_sendToFrame(internal: boolean, sendToAll: boolean, frameId: number, channel: string, args: any): boolean;
|
||||
_sendToFrameInternal(frameId: number, channel: string, ...args: any[]): boolean;
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
esutils "^2.0.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@electron/docs-parser@^0.10.0":
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.10.0.tgz#cc399f3847c37a38af8c13c711dc57eb07e21994"
|
||||
integrity sha512-dNUNsW3tC5VWyWDD6awxDsA0Wc91PVaG4KmSBnqQmXE7bNjnEFE1hf5TaH0KOmJq1KMyQ2rbp7rrrvqRoLKP1Q==
|
||||
"@electron/docs-parser@^0.10.1":
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.10.1.tgz#aa5911c4ef2ec237d7a126111019ec45058088db"
|
||||
integrity sha512-gDKGfc4ilPsKGCCyCCU20iJnHRV3QPYthOocgfAnzm5lOANssxLjl4KeN/DO8nTmKX/BmFsf+XGNa4Penq0L8A==
|
||||
dependencies:
|
||||
"@types/markdown-it" "^0.0.9"
|
||||
chai "^4.2.0"
|
||||
|
|
Загрузка…
Ссылка в новой задаче