Merge remote-tracking branch 'origin/master' into roller/chromium/master
This commit is contained in:
commit
39e3576c48
68 changed files with 578 additions and 182 deletions
|
@ -230,6 +230,18 @@ step-maybe-notify-slack-success: &step-maybe-notify-slack-success
|
|||
fi
|
||||
when: on_success
|
||||
|
||||
step-maybe-cleanup-arm64-mac: &step-maybe-cleanup-arm64-mac
|
||||
run:
|
||||
name: Cleanup after testing
|
||||
command: |
|
||||
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
|
||||
killall Electron || echo "No Electron processes left running"
|
||||
killall Safari || echo "No Safari processes left running"
|
||||
rm -rf ~/Library/Application\ Support/Electron*
|
||||
rm -rf ~/Library/Application\ Support/electron*
|
||||
fi
|
||||
when: always
|
||||
|
||||
step-checkout-electron: &step-checkout-electron
|
||||
checkout:
|
||||
path: src/electron
|
||||
|
@ -1340,6 +1352,8 @@ steps-tests: &steps-tests
|
|||
|
||||
- *step-maybe-notify-slack-failure
|
||||
|
||||
- *step-maybe-cleanup-arm64-mac
|
||||
|
||||
steps-test-nan: &steps-test-nan
|
||||
steps:
|
||||
- attach_workspace:
|
||||
|
|
|
@ -1 +1 @@
|
|||
14.0.0-nightly.20210315
|
||||
14.0.0-nightly.20210323
|
|
@ -267,7 +267,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||
be the absolute file path to the script.
|
||||
When node integration is turned off, the preload script can reintroduce
|
||||
Node global symbols back to the global scope. See example
|
||||
[here](process.md#event-loaded).
|
||||
[here](context-bridge.md#exposing-node-global-symbols).
|
||||
* `sandbox` Boolean (optional) - If set, this will sandbox the renderer
|
||||
associated with the window, making it compatible with the Chromium
|
||||
OS-level sandbox and disabling the Node.js engine. This is not the same as
|
||||
|
@ -1316,6 +1316,8 @@ The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and
|
|||
|
||||
* `message` Integer
|
||||
* `callback` Function
|
||||
* `wParam` any - The `wParam` provided to the WndProc
|
||||
* `lParam` any - The `lParam` provided to the WndProc
|
||||
|
||||
Hooks a windows message. The `callback` is called when
|
||||
the message is received in the WndProc.
|
||||
|
|
|
@ -33,7 +33,7 @@ page you load in your renderer executes code in this world.
|
|||
|
||||
### Isolated World
|
||||
|
||||
When `contextIsolation` is enabled in your `webPreferences`, your `preload` scripts run in an
|
||||
When `contextIsolation` is enabled in your `webPreferences` (this is the default behavior since Electron 12.0.0), your `preload` scripts run in an
|
||||
"Isolated World". You can read more about context isolation and what it affects in the
|
||||
[security](../tutorial/security.md#3-enable-context-isolation-for-remote-content) docs.
|
||||
|
||||
|
@ -110,3 +110,22 @@ has been included below for completeness:
|
|||
| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped |
|
||||
|
||||
If the type you care about is not in the above table, it is probably not supported.
|
||||
|
||||
### Exposing Node Global Symbols
|
||||
|
||||
The `contextBridge` can be used by the preload script to give your renderer access to Node APIs.
|
||||
The table of supported types described above also applies to Node APIs that you expose through `contextBridge`.
|
||||
Please note that many Node APIs grant access to local system resources.
|
||||
Be very cautious about which globals and APIs you expose to untrusted remote content.
|
||||
|
||||
```javascript
|
||||
const { contextBridge } = require('electron')
|
||||
const crypto = require('crypto')
|
||||
contextBridge.exposeInMainWorld('nodeCrypto', {
|
||||
sha256sum (data) {
|
||||
const hash = crypto.createHash('sha256')
|
||||
hash.update(data)
|
||||
return hash.digest('hex')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
|
|
@ -77,7 +77,8 @@ The `crashReporter` module has the following methods:
|
|||
### `crashReporter.start(options)`
|
||||
|
||||
* `options` Object
|
||||
* `submitURL` String - URL that crash reports will be sent to as POST.
|
||||
* `submitURL` String (optional) - URL that crash reports will be sent to as
|
||||
POST. Required unless `uploadToServer` is `false`.
|
||||
* `productName` String (optional) - Defaults to `app.name`.
|
||||
* `companyName` String (optional) _Deprecated_ - Deprecated alias for
|
||||
`{ globalExtra: { _companyName: ... } }`.
|
||||
|
|
|
@ -30,11 +30,13 @@ In sandboxed renderers the `process` object contains only a subset of the APIs:
|
|||
* `arch`
|
||||
* `platform`
|
||||
* `sandboxed`
|
||||
* `contextIsolated`
|
||||
* `type`
|
||||
* `version`
|
||||
* `versions`
|
||||
* `mas`
|
||||
* `windowsStore`
|
||||
* `contextId`
|
||||
|
||||
## Events
|
||||
|
||||
|
@ -43,19 +45,6 @@ In sandboxed renderers the `process` object contains only a subset of the APIs:
|
|||
Emitted when Electron has loaded its internal initialization script and is
|
||||
beginning to load the web page or the main script.
|
||||
|
||||
It can be used by the preload script to add removed Node global symbols back to
|
||||
the global scope when node integration is turned off:
|
||||
|
||||
```javascript
|
||||
// preload.js
|
||||
const _setImmediate = setImmediate
|
||||
const _clearImmediate = clearImmediate
|
||||
process.once('loaded', () => {
|
||||
global.setImmediate = _setImmediate
|
||||
global.clearImmediate = _clearImmediate
|
||||
})
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
### `process.defaultApp` _Readonly_
|
||||
|
@ -93,6 +82,11 @@ A `String` representing the path to the resources directory.
|
|||
A `Boolean`. When the renderer process is sandboxed, this property is `true`,
|
||||
otherwise it is `undefined`.
|
||||
|
||||
### `process.contextIsolated` _Readonly_
|
||||
|
||||
A `Boolean` that indicates whether the current renderer context has `contextIsolation` enabled.
|
||||
It is `undefined` in the main process.
|
||||
|
||||
### `process.throwDeprecation`
|
||||
|
||||
A `Boolean` that controls whether or not deprecation warnings will be thrown as
|
||||
|
@ -133,6 +127,13 @@ A `String` representing Electron's version string.
|
|||
A `Boolean`. If the app is running as a Windows Store app (appx), this property is `true`,
|
||||
for otherwise it is `undefined`.
|
||||
|
||||
### `process.contextId` _Readonly_
|
||||
|
||||
A `String` (optional) representing a globally unique ID of the current JavaScript context.
|
||||
Each frame has its own JavaScript context. When contextIsolation is enabled, the isolated
|
||||
world also has a separate JavaScript context.
|
||||
This property is only available in the renderer process.
|
||||
|
||||
## Methods
|
||||
|
||||
The `process` object has the following methods:
|
||||
|
|
|
@ -33,8 +33,7 @@ contributing, and more. Please use the issue tracker for bugs only!
|
|||
To submit a bug report:
|
||||
|
||||
When opening a new issue in the [`electron/electron` issue tracker](https://github.com/electron/electron/issues/new/choose), users
|
||||
will be presented with [a template](https://github.com/electron/electron/blob/master/.github/ISSUE_TEMPLATE/Bug_report.md)
|
||||
that should be filled in.
|
||||
will be presented with a template that should be filled in.
|
||||
|
||||
If you believe that you have found a bug in Electron, please fill out the template
|
||||
to the best of your ability.
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
We are using Node.js <span id="node-version"></span>,
|
||||
Chromium <span id="chrome-version"></span>,
|
||||
and Electron <span id="electron-version"></span>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
|
@ -21,8 +29,3 @@ app.on('window-all-closed', () => {
|
|||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
|
11
docs/fiddles/quick-start/preload.js
Normal file
11
docs/fiddles/quick-start/preload.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const replaceText = (selector, text) => {
|
||||
const element = document.getElementById(selector)
|
||||
if (element) element.innerText = text
|
||||
}
|
||||
|
||||
for (const type of ['chrome', 'node', 'electron']) {
|
||||
replaceText(`${type}-version`, process.versions[type])
|
||||
}
|
||||
})
|
||||
|
|
@ -32,6 +32,7 @@ From a development perspective, an Electron application is essentially a Node.js
|
|||
my-electron-app/
|
||||
├── package.json
|
||||
├── main.js
|
||||
├── preload.js
|
||||
└── index.html
|
||||
```
|
||||
|
||||
|
@ -55,45 +56,49 @@ The main script may look as follows:
|
|||
|
||||
```javascript fiddle='docs/fiddles/quick-start'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### What is going on above?
|
||||
|
||||
1. Line 1: First, you import the `app` and `BrowserWindow` modules of the `electron` package to be able to manage your application's lifecycle events, as well as create and control browser windows.
|
||||
2. Line 3: After that, you define a function that creates a [new browser window](../api/browser-window.md#new-browserwindowoptions) with node integration enabled, loads `index.html` file into this window (line 12, we will discuss the file later).
|
||||
3. Line 15: You create a new browser window by invoking the `createWindow` function once the Electron application [is initialized](../api/app.md#appwhenready).
|
||||
4. Line 17: You add a new listener that tries to quit the application when it no longer has any open windows. This listener is a no-op on macOS due to the operating system's [window management behavior](https://support.apple.com/en-ca/guide/mac-help/mchlp2469/mac).
|
||||
5. Line 23: You add a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
|
||||
2. Line 2: Second, you import the `path` package which provides utility functions for file paths.
|
||||
3. Line 4: After that, you define a function that creates a [new browser window](../api/browser-window.md#new-browserwindowoptions) with a preload script, loads `index.html` file into this window (line 13, we will discuss the file later).
|
||||
4. Line 16: You create a new browser window by invoking the `createWindow` function once the Electron application [is initialized](../api/app.md#appwhenready).
|
||||
5. Line 18: You add a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
|
||||
6. Line 25: You add a new listener that tries to quit the application when it no longer has any open windows. This listener is a no-op on macOS due to the operating system's [window management behavior](https://support.apple.com/en-ca/guide/mac-help/mchlp2469/mac).
|
||||
|
||||
#### Create a web page
|
||||
|
||||
This is the web page you want to display once the application is initialized. This web page represents the Renderer process. You can create multiple browser windows, where each window uses its own independent Renderer. Each window can optionally be granted with full access to Node.js API through the `nodeIntegration` preference.
|
||||
This is the web page you want to display once the application is initialized. This web page represents the Renderer process. You can create multiple browser windows, where each window uses its own independent Renderer. You can optionally grant access to additional Node.js APIs by exposing them from your preload script.
|
||||
|
||||
The `index.html` page looks as follows:
|
||||
|
||||
|
@ -108,14 +113,38 @@ The `index.html` page looks as follows:
|
|||
<body style="background: white;">
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
We are using Node.js <span id="node-version"></span>,
|
||||
Chromium <span id="chrome-version"></span>,
|
||||
and Electron <span id="electron-version"></span>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### Define a preload script
|
||||
|
||||
Your preload script acts as a bridge between Node.js and your web page. It allows you to expose specific APIs and behaviors to your web page rather than insecurely exposing the entire Node.js API. In this example we will use the preload script to read version information from the `process` object and update the web page with that info.
|
||||
|
||||
```javascript fiddle='docs/fiddles/quick-start'
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const replaceText = (selector, text) => {
|
||||
const element = document.getElementById(selector)
|
||||
if (element) element.innerText = text
|
||||
}
|
||||
|
||||
for (const type of ['chrome', 'node', 'electron']) {
|
||||
replaceText(`${type}-version`, process.versions[type])
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### What's going on above?
|
||||
|
||||
1. On line 1: First you define an event listener that tells you when the web page has loaded
|
||||
2. On line 2: Second you define a utility function used to set the text of the placeholders in the `index.html`
|
||||
3. On line 7: Next you loop through the list of components whose version you want to display
|
||||
4. On line 8: Finally, you call `replaceText` to look up the version placeholders in `index.html` and set their text value to the values from `process.versions`
|
||||
|
||||
#### Modify your package.json file
|
||||
|
||||
Your Electron application uses the `package.json` file as the main entry point (as any other Node.js application). The main script of your application is `main.js`, so modify the `package.json` file accordingly:
|
||||
|
@ -283,7 +312,7 @@ ipcRenderer.invoke('perform-action', ...args)
|
|||
|
||||
##### Node.js API
|
||||
|
||||
> NOTE: To access the Node.js API from the Renderer process, you need to set the `nodeIntegration` preference to `true`.
|
||||
> NOTE: To access the Node.js API from the Renderer process, you need to set the `nodeIntegration` preference to `true` and the `contextIsolation` preference to `false`. Please note that access to the Node.js API in any renderer that loads remote content is not recommended for [security reasons](../tutorial/security.md#2-do-not-enable-nodejs-integration-for-remote-content).
|
||||
|
||||
Electron exposes full access to Node.js API and its modules both in the Main and the Renderer processes. For example, you can read all the files from the root directory:
|
||||
|
||||
|
|
|
@ -86,12 +86,12 @@ const driver = new webdriver.Builder()
|
|||
// The "9515" is the port opened by chrome driver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
chromeOptions: {
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('electron')
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
|
||||
driver.get('http://www.google.com')
|
||||
|
|
|
@ -10,13 +10,13 @@ class CrashReporter {
|
|||
extra = {},
|
||||
globalExtra = {},
|
||||
ignoreSystemCrashHandler = false,
|
||||
submitURL,
|
||||
submitURL = '',
|
||||
uploadToServer = true,
|
||||
rateLimit = false,
|
||||
compress = true
|
||||
} = options || {};
|
||||
|
||||
if (submitURL == null) throw new Error('submitURL is a required option to crashReporter.start');
|
||||
if (uploadToServer && !submitURL) throw new Error('submitURL must be specified when uploadToServer is true');
|
||||
|
||||
if (!compress && uploadToServer) {
|
||||
deprecate.log('Sending uncompressed crash reports is deprecated and will be removed in a future version of Electron. Set { compress: true } to opt-in to the new behavior. Crash reports will be uploaded gzipped, which most crash reporting servers support.');
|
||||
|
|
|
@ -94,6 +94,7 @@ const defaultPrintingSetting = {
|
|||
pagesPerSheet: 1,
|
||||
isFirstRequest: false,
|
||||
previewUIID: 0,
|
||||
// True, if the document source is modifiable. e.g. HTML and not PDF.
|
||||
previewModifiable: true,
|
||||
printToPDF: true,
|
||||
deviceName: 'Save as PDF',
|
||||
|
|
|
@ -39,6 +39,10 @@ require('@electron/internal/common/init');
|
|||
// The global variable will be used by ipc for event dispatching
|
||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
// Expose process.contextId
|
||||
const contextId = v8Util.getHiddenValue<string>(global, 'contextId');
|
||||
Object.defineProperty(process, 'contextId', { enumerable: true, value: contextId });
|
||||
|
||||
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal');
|
||||
const ipcRenderer = require('@electron/internal/renderer/api/ipc-renderer').default;
|
||||
|
||||
|
|
|
@ -89,6 +89,10 @@ Object.defineProperty(preloadProcess, 'noDeprecation', {
|
|||
}
|
||||
});
|
||||
|
||||
// Expose process.contextId
|
||||
const contextId = v8Util.getHiddenValue<string>(global, 'contextId');
|
||||
Object.defineProperty(preloadProcess, 'contextId', { enumerable: true, value: contextId });
|
||||
|
||||
process.on('loaded', () => (preloadProcess as events.EventEmitter).emit('loaded'));
|
||||
process.on('exit', () => (preloadProcess as events.EventEmitter).emit('exit'));
|
||||
(process as events.EventEmitter).on('document-start', () => (preloadProcess as events.EventEmitter).emit('document-start'));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "electron",
|
||||
"version": "14.0.0-nightly.20210315",
|
||||
"version": "14.0.0-nightly.20210323",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
|
26
shell/browser/api/content_tracing.idl
Normal file
26
shell/browser/api/content_tracing.idl
Normal file
|
@ -0,0 +1,26 @@
|
|||
enum RecordingMode { "record-until-full", "record-continuously", "record-as-much-as-possible", "trace-to-console" };
|
||||
|
||||
dictionary TraceConfig {
|
||||
Recordingmode recording_mode;
|
||||
unsigned long trace_buffer_size_in_kb;
|
||||
unsigned long trace_buffer_size_in_events;
|
||||
boolean enable_argument_filter;
|
||||
sequence<DOMString> included_categories;
|
||||
sequence<DOMString> excluded_categories;
|
||||
sequence<unsigned short> included_process_ids;
|
||||
sequence<DOMString> histogram_names;
|
||||
object memory_dump_config;
|
||||
};
|
||||
|
||||
dictionary TraceCategoriesAndOptions {
|
||||
DOMString categoryFilter;
|
||||
DOMString traceOptions;
|
||||
};
|
||||
|
||||
interface ContentTracing {
|
||||
Promise<sequence<DOMString>> getCategories();
|
||||
Promise<void> startRecording(TraceConfig config);
|
||||
Promise<void> startRecording(TraceCategoriesAndOptions categoriesAndOptions);
|
||||
Promise<DOMString> stopRecording(optional DOMString resultFilePath);
|
||||
Promise<TraceBufferUsage> getTraceBufferUsage();
|
||||
};
|
|
@ -1114,6 +1114,8 @@ int32_t BaseWindow::GetID() const {
|
|||
}
|
||||
|
||||
void BaseWindow::ResetBrowserViews() {
|
||||
v8::HandleScope scope(isolate());
|
||||
|
||||
for (auto& item : browser_views_) {
|
||||
gin::Handle<BrowserView> browser_view;
|
||||
if (gin::ConvertFromV8(isolate(),
|
||||
|
|
|
@ -162,6 +162,9 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
|||
v8::Locker locker(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
|
||||
|
||||
Unpin();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -195,12 +198,19 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
|||
v8::Locker locker(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onfinished", captured_sources_);
|
||||
|
||||
Unpin();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<DesktopCapturer> DesktopCapturer::Create(v8::Isolate* isolate) {
|
||||
return gin::CreateHandle(isolate, new DesktopCapturer(isolate));
|
||||
auto handle = gin::CreateHandle(isolate, new DesktopCapturer(isolate));
|
||||
|
||||
// Keep reference alive until capturing has finished.
|
||||
handle->Pin(isolate);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
gin::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder(
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
|
||||
#include "gin/handle.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/common/gin_helper/pinnable.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
class DesktopCapturer : public gin::Wrappable<DesktopCapturer>,
|
||||
public gin_helper::Pinnable<DesktopCapturer>,
|
||||
public DesktopMediaListObserver {
|
||||
public:
|
||||
struct Source {
|
||||
|
|
|
@ -88,7 +88,7 @@ void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
|
|||
}
|
||||
|
||||
// If no preferred item is specified, try to show all of the menu items.
|
||||
if (!positioning_item) {
|
||||
if (!item) {
|
||||
CGFloat windowBottom = CGRectGetMinY([view window].frame);
|
||||
CGFloat lowestMenuPoint = windowBottom + position.y - [menu size].height;
|
||||
CGFloat screenBottom = CGRectGetMinY([view window].screen.frame);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "base/command_line.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "content/common/url_schemes.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "shell/browser/browser.h"
|
||||
|
@ -124,6 +125,13 @@ void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
|||
}
|
||||
if (custom_scheme.options.allowServiceWorkers) {
|
||||
service_worker_schemes.push_back(custom_scheme.scheme);
|
||||
// There is no API to add service worker scheme, but there is an API to
|
||||
// return const reference to the schemes vector.
|
||||
// If in future the API is changed to return a copy instead of reference,
|
||||
// the compilation will fail, and we should add a patch at that time.
|
||||
auto& mutable_schemes = const_cast<std::vector<std::string>&>(
|
||||
content::GetServiceWorkerSchemes());
|
||||
mutable_schemes.push_back(custom_scheme.scheme);
|
||||
}
|
||||
if (custom_scheme.options.stream) {
|
||||
g_streaming_schemes.push_back(custom_scheme.scheme);
|
||||
|
|
|
@ -915,6 +915,7 @@ WebContents::~WebContents() {
|
|||
return;
|
||||
}
|
||||
|
||||
inspectable_web_contents_->GetView()->SetDelegate(nullptr);
|
||||
if (guest_delegate_)
|
||||
guest_delegate_->WillDestroy();
|
||||
|
||||
|
@ -1761,6 +1762,7 @@ void WebContents::DevToolsOpened() {
|
|||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
DCHECK(inspectable_web_contents_);
|
||||
DCHECK(inspectable_web_contents_->GetDevToolsWebContents());
|
||||
auto handle = FromOrCreate(
|
||||
isolate, inspectable_web_contents_->GetDevToolsWebContents());
|
||||
devtools_web_contents_.Reset(isolate, handle.ToV8());
|
||||
|
|
|
@ -1363,22 +1363,26 @@ void ElectronBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
|||
int render_process_id,
|
||||
int render_frame_id,
|
||||
NonNetworkURLLoaderFactoryMap* factories) {
|
||||
content::RenderFrameHost* frame_host =
|
||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||
content::WebContents* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(frame_host);
|
||||
auto* render_process_host =
|
||||
content::RenderProcessHost::FromID(render_process_id);
|
||||
DCHECK(render_process_host);
|
||||
if (!render_process_host || !render_process_host->GetBrowserContext())
|
||||
return;
|
||||
|
||||
ProtocolRegistry::FromBrowserContext(render_process_host->GetBrowserContext())
|
||||
->RegisterURLLoaderFactories(URLLoaderFactoryType::kDocumentSubResource,
|
||||
factories);
|
||||
|
||||
if (web_contents) {
|
||||
ProtocolRegistry::FromBrowserContext(web_contents->GetBrowserContext())
|
||||
->RegisterURLLoaderFactories(URLLoaderFactoryType::kDocumentSubResource,
|
||||
factories);
|
||||
}
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
|
||||
render_frame_id);
|
||||
if (factory)
|
||||
factories->emplace(extensions::kExtensionScheme, std::move(factory));
|
||||
|
||||
content::RenderFrameHost* frame_host =
|
||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||
content::WebContents* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(frame_host);
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
|
|
|
@ -317,8 +317,9 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
|
|||
const auto window_content_view_height = NSHeight(window_content_view.bounds);
|
||||
for (const auto& rect : drag_exclude_rects) {
|
||||
const auto x = rect.x() + offset.x();
|
||||
const auto y = window_content_view_height - rect.bottom() + offset.y();
|
||||
const auto y = window_content_view_height - (rect.bottom() + offset.y());
|
||||
const auto exclude_rect = NSMakeRect(x, y, rect.width(), rect.height());
|
||||
|
||||
const auto drag_region_view_exclude_rect =
|
||||
[window_content_view convertRect:exclude_rect toView:drag_region_view];
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void SetTrafficLightPosition(base::Optional<gfx::Point> position) = 0;
|
||||
virtual base::Optional<gfx::Point> GetTrafficLightPosition() const = 0;
|
||||
virtual void RedrawTrafficLights() = 0;
|
||||
virtual void UpdateFrame() = 0;
|
||||
#endif
|
||||
|
||||
// Touchbar API
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "ui/display/display_observer.h"
|
||||
#include "ui/native_theme/native_theme_observer.h"
|
||||
#include "ui/views/controls/native/native_view_host.h"
|
||||
|
||||
|
@ -27,7 +28,9 @@ namespace electron {
|
|||
|
||||
class RootViewMac;
|
||||
|
||||
class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
|
||||
class NativeWindowMac : public NativeWindow,
|
||||
public ui::NativeThemeObserver,
|
||||
public display::DisplayObserver {
|
||||
public:
|
||||
NativeWindowMac(const gin_helper::Dictionary& options, NativeWindow* parent);
|
||||
~NativeWindowMac() override;
|
||||
|
@ -124,6 +127,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
|
|||
void SetTrafficLightPosition(base::Optional<gfx::Point> position) override;
|
||||
base::Optional<gfx::Point> GetTrafficLightPosition() const override;
|
||||
void RedrawTrafficLights() override;
|
||||
void UpdateFrame() override;
|
||||
void SetTouchBar(
|
||||
std::vector<gin_helper::PersistentDictionary> items) override;
|
||||
void RefreshTouchBarItem(const std::string& item_id) override;
|
||||
|
@ -188,6 +192,10 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
|
|||
// ui::NativeThemeObserver:
|
||||
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
|
||||
|
||||
// display::DisplayObserver:
|
||||
void OnDisplayMetricsChanged(const display::Display& display,
|
||||
uint32_t changed_metrics) override;
|
||||
|
||||
private:
|
||||
// Add custom layers to the content view.
|
||||
void AddContentViewLayers();
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "shell/common/process_util.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "third_party/webrtc/modules/desktop_capture/mac/window_list_utils.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/gfx/skia_util.h"
|
||||
#include "ui/gl/gpu_switching_manager.h"
|
||||
#include "ui/views/background.h"
|
||||
|
@ -258,6 +259,7 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
|||
NativeWindow* parent)
|
||||
: NativeWindow(options, parent), root_view_(new RootViewMac(this)) {
|
||||
ui::NativeTheme::GetInstanceForNativeUi()->AddObserver(this);
|
||||
display::Screen::GetScreen()->AddObserver(this);
|
||||
|
||||
int width = 800, height = 600;
|
||||
options.Get(options::kWidth, &width);
|
||||
|
@ -882,6 +884,17 @@ void NativeWindowMac::SetExcludedFromShownWindowsMenu(bool excluded) {
|
|||
[window setExcludedFromWindowsMenu:excluded];
|
||||
}
|
||||
|
||||
void NativeWindowMac::OnDisplayMetricsChanged(const display::Display& display,
|
||||
uint32_t changed_metrics) {
|
||||
// We only want to force screen recalibration if we're in simpleFullscreen
|
||||
// mode.
|
||||
if (!is_simple_fullscreen_)
|
||||
return;
|
||||
|
||||
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&NativeWindow::UpdateFrame, GetWeakPtr()));
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
|
||||
NSWindow* window = GetNativeWindow().GetNativeNSWindow();
|
||||
|
||||
|
@ -1396,6 +1409,13 @@ void NativeWindowMac::RedrawTrafficLights() {
|
|||
[buttons_view_ setNeedsDisplayForButtons];
|
||||
}
|
||||
|
||||
// In simpleFullScreen mode, update the frame for new bounds.
|
||||
void NativeWindowMac::UpdateFrame() {
|
||||
NSWindow* window = GetNativeWindow().GetNativeNSWindow();
|
||||
NSRect fullscreenFrame = [window.screen frame];
|
||||
[window setFrame:fullscreenFrame display:YES animate:YES];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetTouchBar(
|
||||
std::vector<gin_helper::PersistentDictionary> items) {
|
||||
if (@available(macOS 10.12.2, *)) {
|
||||
|
@ -1551,6 +1571,7 @@ void NativeWindowMac::NotifyWindowWillLeaveFullScreen() {
|
|||
void NativeWindowMac::Cleanup() {
|
||||
DCHECK(!IsClosed());
|
||||
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
|
||||
display::Screen::GetScreen()->RemoveObserver(this);
|
||||
[NSEvent removeMonitor:wheel_event_monitor_];
|
||||
}
|
||||
|
||||
|
|
|
@ -50,8 +50,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 14,0,0,20210315
|
||||
PRODUCTVERSION 14,0,0,20210315
|
||||
FILEVERSION 14,0,0,20210323
|
||||
PRODUCTVERSION 14,0,0,20210323
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
|
|
@ -201,12 +201,6 @@ class InspectableWebContents
|
|||
void AddDevToolsExtensionsToClient();
|
||||
#endif
|
||||
|
||||
bool frontend_loaded_ = false;
|
||||
scoped_refptr<content::DevToolsAgentHost> agent_host_;
|
||||
std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
|
||||
std::unique_ptr<DevToolsEmbedderMessageDispatcher>
|
||||
embedder_message_dispatcher_;
|
||||
|
||||
DevToolsContentsResizingStrategy contents_resizing_strategy_;
|
||||
gfx::Rect devtools_bounds_;
|
||||
bool can_dock_ = true;
|
||||
|
@ -228,6 +222,12 @@ class InspectableWebContents
|
|||
bool is_guest_;
|
||||
std::unique_ptr<InspectableWebContentsView> view_;
|
||||
|
||||
bool frontend_loaded_ = false;
|
||||
scoped_refptr<content::DevToolsAgentHost> agent_host_;
|
||||
std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
|
||||
std::unique_ptr<DevToolsEmbedderMessageDispatcher>
|
||||
embedder_message_dispatcher_;
|
||||
|
||||
class NetworkResourceLoader;
|
||||
std::set<std::unique_ptr<NetworkResourceLoader>, base::UniquePtrComparator>
|
||||
loaders_;
|
||||
|
|
|
@ -363,21 +363,22 @@ void NodeBindings::Initialize() {
|
|||
// Parse and set Node.js cli flags.
|
||||
SetNodeCliFlags();
|
||||
|
||||
// pass non-null program name to argv so it doesn't crash
|
||||
// trying to index into a nullptr
|
||||
int argc = 1;
|
||||
int exec_argc = 0;
|
||||
const char* prog_name = "electron";
|
||||
const char** argv = &prog_name;
|
||||
const char** exec_argv = nullptr;
|
||||
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
SetNodeOptions(env.get());
|
||||
|
||||
// TODO(codebytere): this is going to be deprecated in the near future
|
||||
// in favor of Init(std::vector<std::string>* argv,
|
||||
// std::vector<std::string>* exec_argv)
|
||||
node::Init(&argc, argv, &exec_argc, &exec_argv);
|
||||
std::vector<std::string> argv = {"electron"};
|
||||
std::vector<std::string> exec_argv;
|
||||
std::vector<std::string> errors;
|
||||
|
||||
int exit_code = node::InitializeNodeWithArgs(&argv, &exec_argv, &errors);
|
||||
|
||||
for (const std::string& error : errors) {
|
||||
fprintf(stderr, "%s: %s\n", argv[0].c_str(), error.c_str());
|
||||
}
|
||||
|
||||
if (exit_code != 0) {
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// uv_init overrides error mode to suppress the default crash dialog, bring
|
||||
|
@ -533,15 +534,13 @@ void NodeBindings::LoadEnvironment(node::Environment* env) {
|
|||
void NodeBindings::PrepareMessageLoop() {
|
||||
#if !defined(OS_WIN)
|
||||
int handle = uv_backend_fd(uv_loop_);
|
||||
#else
|
||||
HANDLE handle = uv_loop_->iocp;
|
||||
#endif
|
||||
|
||||
// If the backend fd hasn't changed, don't proceed.
|
||||
if (handle == handle_)
|
||||
return;
|
||||
|
||||
handle_ = handle;
|
||||
#endif
|
||||
|
||||
// Add dummy handle for libuv, otherwise libuv would quit when there is
|
||||
// nothing to do.
|
||||
|
|
|
@ -159,9 +159,7 @@ class NodeBindings {
|
|||
// Isolate data used in creating the environment
|
||||
node::IsolateData* isolate_data_ = nullptr;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
HANDLE handle_;
|
||||
#else
|
||||
#if !defined(OS_WIN)
|
||||
int handle_ = -1;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "base/win/windows_version.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "shell/common/electron_paths.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "url/gurl.h"
|
||||
|
@ -241,7 +242,8 @@ std::string OpenExternalOnWorkerThread(
|
|||
// Quote the input scheme to be sure that the command does not have
|
||||
// parameters unexpected by the external program. This url should already
|
||||
// have been escaped.
|
||||
std::wstring escaped_url = L"\"" + base::UTF8ToWide(url.spec()) + L"\"";
|
||||
std::wstring escaped_url =
|
||||
L"\"" + base::UTF8ToWide(net::EscapeExternalHandlerValue(url.spec())) +
|
||||
std::wstring working_dir = options.working_dir.value();
|
||||
|
||||
if (reinterpret_cast<ULONG_PTR>(
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/feature_list.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
|
@ -25,6 +26,12 @@
|
|||
#include "third_party/blink/public/web/web_element.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
|
||||
namespace features {
|
||||
|
||||
const base::Feature kContextBridgeMutability{"ContextBridgeMutability",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT};
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
@ -554,6 +561,12 @@ void ExposeAPIInMainWorld(v8::Isolate* isolate,
|
|||
if (maybe_proxy.IsEmpty())
|
||||
return;
|
||||
auto proxy = maybe_proxy.ToLocalChecked();
|
||||
|
||||
if (base::FeatureList::IsEnabled(features::kContextBridgeMutability)) {
|
||||
global.Set(key, proxy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (proxy->IsObject() && !proxy->IsTypedArray() &&
|
||||
!DeepFreeze(v8::Local<v8::Object>::Cast(proxy), main_context))
|
||||
return;
|
||||
|
|
|
@ -146,9 +146,8 @@ void ElectronRendererClient::DidCreateScriptContext(
|
|||
|
||||
// Add Electron extended APIs.
|
||||
electron_bindings_->BindTo(env->isolate(), env->process_object());
|
||||
AddRenderBindings(env->isolate(), env->process_object());
|
||||
gin_helper::Dictionary process_dict(env->isolate(), env->process_object());
|
||||
process_dict.SetReadOnly("isMainFrame", render_frame->IsMainFrame());
|
||||
BindProcess(env->isolate(), &process_dict, render_frame);
|
||||
|
||||
// Load everything.
|
||||
node_bindings_->LoadEnvironment(env);
|
||||
|
|
|
@ -131,7 +131,7 @@ ElectronSandboxedRendererClient::~ElectronSandboxedRendererClient() = default;
|
|||
void ElectronSandboxedRendererClient::InitializeBindings(
|
||||
v8::Local<v8::Object> binding,
|
||||
v8::Local<v8::Context> context,
|
||||
bool is_main_frame) {
|
||||
content::RenderFrame* render_frame) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary b(isolate, binding);
|
||||
b.SetMethod("get", GetBinding);
|
||||
|
@ -141,13 +141,13 @@ void ElectronSandboxedRendererClient::InitializeBindings(
|
|||
b.Set("process", process);
|
||||
|
||||
ElectronBindings::BindProcess(isolate, &process, metrics_.get());
|
||||
BindProcess(isolate, &process, render_frame);
|
||||
|
||||
process.SetMethod("uptime", Uptime);
|
||||
process.Set("argv", base::CommandLine::ForCurrentProcess()->argv());
|
||||
process.SetReadOnly("pid", base::GetCurrentProcId());
|
||||
process.SetReadOnly("sandboxed", true);
|
||||
process.SetReadOnly("type", "renderer");
|
||||
process.SetReadOnly("isMainFrame", is_main_frame);
|
||||
}
|
||||
|
||||
void ElectronSandboxedRendererClient::RenderFrameCreated(
|
||||
|
@ -218,8 +218,7 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
|
|||
// argument.
|
||||
auto* isolate = context->GetIsolate();
|
||||
auto binding = v8::Object::New(isolate);
|
||||
InitializeBindings(binding, context, render_frame->IsMainFrame());
|
||||
AddRenderBindings(isolate, binding);
|
||||
InitializeBindings(binding, context, render_frame);
|
||||
|
||||
std::vector<v8::Local<v8::String>> sandbox_preload_bundle_params = {
|
||||
node::FIXED_ONE_BYTE_STRING(isolate, "binding")};
|
||||
|
|
|
@ -21,7 +21,7 @@ class ElectronSandboxedRendererClient : public RendererClientBase {
|
|||
|
||||
void InitializeBindings(v8::Local<v8::Object> binding,
|
||||
v8::Local<v8::Context> context,
|
||||
bool is_main_frame);
|
||||
content::RenderFrame* render_frame);
|
||||
// electron::RendererClientBase:
|
||||
void DidCreateScriptContext(v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) override;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
#include "extensions/common/constants.h"
|
||||
#include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h"
|
||||
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
|
||||
namespace electron {
|
||||
|
@ -50,6 +51,20 @@ bool PrintRenderFrameHelperDelegate::IsPrintPreviewEnabled() {
|
|||
|
||||
bool PrintRenderFrameHelperDelegate::OverridePrint(
|
||||
blink::WebLocalFrame* frame) {
|
||||
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
auto* post_message_support =
|
||||
extensions::PostMessageSupport::FromWebLocalFrame(frame);
|
||||
if (post_message_support) {
|
||||
// This message is handled in chrome/browser/resources/pdf/pdf_viewer.js and
|
||||
// instructs the PDF plugin to print. This is to make window.print() on a
|
||||
// PDF plugin document correctly print the PDF. See
|
||||
// https://crbug.com/448720.
|
||||
base::DictionaryValue message;
|
||||
message.SetString("type", "print");
|
||||
post_message_support->PostMessageFromValue(message);
|
||||
return true;
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,9 +137,13 @@ void RendererClientBase::DidCreateScriptContext(
|
|||
global.SetHidden("contextId", context_id);
|
||||
}
|
||||
|
||||
void RendererClientBase::AddRenderBindings(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> binding_object) {}
|
||||
void RendererClientBase::BindProcess(v8::Isolate* isolate,
|
||||
gin_helper::Dictionary* process,
|
||||
content::RenderFrame* render_frame) {
|
||||
process->SetReadOnly("isMainFrame", render_frame->IsMainFrame());
|
||||
process->SetReadOnly("contextIsolated",
|
||||
render_frame->GetBlinkPreferences().context_isolation);
|
||||
}
|
||||
|
||||
void RendererClientBase::RenderThreadStarted() {
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "content/public/renderer/content_renderer_client.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "printing/buildflags/buildflags.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
// In SHARED_INTERMEDIATE_DIR.
|
||||
#include "widevine_cdm_version.h" // NOLINT(build/include_directory)
|
||||
|
@ -92,8 +93,9 @@ class RendererClientBase : public content::ContentRendererClient
|
|||
#endif
|
||||
|
||||
protected:
|
||||
void AddRenderBindings(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> binding_object);
|
||||
void BindProcess(v8::Isolate* isolate,
|
||||
gin_helper::Dictionary* process,
|
||||
content::RenderFrame* render_frame);
|
||||
|
||||
// content::ContentRendererClient:
|
||||
void RenderThreadStarted() override;
|
||||
|
|
|
@ -143,7 +143,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('app.exit(exitCode)', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('app.exit(exitCode)', () => {
|
||||
let appProcess: cp.ChildProcess | null = null;
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -209,7 +210,7 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// TODO(jeremy): figure out why these tests time out under ASan
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('app.requestSingleInstanceLock', () => {
|
||||
it('prevents the second launch of app', async function () {
|
||||
this.timeout(120000);
|
||||
|
@ -252,7 +253,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('app.relaunch', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('app.relaunch', () => {
|
||||
let server: net.Server | null = null;
|
||||
const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-app-relaunch' : '/tmp/electron-app-relaunch';
|
||||
|
||||
|
@ -852,7 +854,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getAppPath', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('getAppPath', () => {
|
||||
it('works for directories with package.json', async () => {
|
||||
const { appPath } = await runTestApp('app-path');
|
||||
expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path'));
|
||||
|
@ -1128,13 +1131,7 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('app launch through uri', () => {
|
||||
before(function () {
|
||||
if (process.platform !== 'win32') {
|
||||
this.skip();
|
||||
}
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'win32')('app launch through uri', () => {
|
||||
it('does not launch for argument following a URL', async () => {
|
||||
const appPath = path.join(fixturesPath, 'api', 'quit-app');
|
||||
// App should exit with non 123 code.
|
||||
|
@ -1334,7 +1331,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('sandbox options', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('sandbox options', () => {
|
||||
let appProcess: cp.ChildProcess = null as any;
|
||||
let server: net.Server = null as any;
|
||||
const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-mixed-sandbox' : '/tmp/electron-mixed-sandbox';
|
||||
|
@ -1375,8 +1373,7 @@ describe('app module', () => {
|
|||
});
|
||||
|
||||
describe('when app.enableSandbox() is called', () => {
|
||||
// TODO(jeremy): figure out why this times out under ASan
|
||||
ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
|
||||
it('adds --enable-sandbox to all renderer processes', done => {
|
||||
const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
|
||||
appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox']);
|
||||
|
||||
|
@ -1401,8 +1398,7 @@ describe('app module', () => {
|
|||
});
|
||||
|
||||
describe('when the app is launched with --enable-sandbox', () => {
|
||||
// TODO(jeremy): figure out why this times out under ASan
|
||||
ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
|
||||
it('adds --enable-sandbox to all renderer processes', done => {
|
||||
const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
|
||||
appProcess = cp.spawn(process.execPath, [appPath, '--enable-sandbox']);
|
||||
|
||||
|
@ -1561,7 +1557,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('commandLine.hasSwitch (existing argv)', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('commandLine.hasSwitch (existing argv)', () => {
|
||||
it('returns true when present', async () => {
|
||||
const { hasSwitch } = await runTestApp('command-line', '--foobar');
|
||||
expect(hasSwitch).to.equal(true);
|
||||
|
@ -1589,7 +1586,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('commandLine.getSwitchValue (existing argv)', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('commandLine.getSwitchValue (existing argv)', () => {
|
||||
it('returns the value when present', async () => {
|
||||
const { getSwitchValue } = await runTestApp('command-line', '--foobar=test');
|
||||
expect(getSwitchValue).to.equal('test');
|
||||
|
@ -1616,7 +1614,8 @@ describe('app module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('default behavior', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('default behavior', () => {
|
||||
describe('application menu', () => {
|
||||
it('creates the default menu if the app does not set it', async () => {
|
||||
const result = await runTestApp('default-menu');
|
||||
|
|
|
@ -2487,9 +2487,11 @@ describe('BrowserWindow module', () => {
|
|||
expect(test.env).to.deep.equal(process.env);
|
||||
expect(test.execPath).to.equal(process.helperExecPath);
|
||||
expect(test.sandboxed).to.be.true('sandboxed');
|
||||
expect(test.contextIsolated).to.be.false('contextIsolated');
|
||||
expect(test.type).to.equal('renderer');
|
||||
expect(test.version).to.equal(process.version);
|
||||
expect(test.versions).to.deep.equal(process.versions);
|
||||
expect(test.contextId).to.be.a('string');
|
||||
|
||||
if (process.platform === 'linux' && test.osSandbox) {
|
||||
expect(test.creationTime).to.be.null('creation time');
|
||||
|
@ -4304,6 +4306,19 @@ describe('BrowserWindow module', () => {
|
|||
const [, data] = await p;
|
||||
expect(data.pageContext.openedLocation).to.equal('about:blank');
|
||||
});
|
||||
it('reports process.contextIsolated', async () => {
|
||||
const iw = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
preload: path.join(fixtures, 'api', 'isolated-process.js')
|
||||
}
|
||||
});
|
||||
const p = emittedOnce(ipcMain, 'context-isolation');
|
||||
iw.loadURL('about:blank');
|
||||
const [, contextIsolation] = await p;
|
||||
expect(contextIsolation).to.be.true('contextIsolation');
|
||||
});
|
||||
});
|
||||
|
||||
describe('reloading with allowRendererProcessReuse enabled', () => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import * as fs from 'fs-extra';
|
|||
import * as http from 'http';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
import { closeWindow } from './window-helpers';
|
||||
import { emittedOnce } from './events-helpers';
|
||||
|
@ -1165,3 +1166,31 @@ describe('contextBridge', () => {
|
|||
generateTests(true);
|
||||
generateTests(false);
|
||||
});
|
||||
|
||||
describe('ContextBridgeMutability', () => {
|
||||
it('should not make properties unwriteable and read-only if ContextBridgeMutability is on', async () => {
|
||||
const appPath = path.join(fixturesPath, 'context-bridge-mutability');
|
||||
const appProcess = cp.spawn(process.execPath, ['--enable-logging', '--enable-features=ContextBridgeMutability', appPath]);
|
||||
|
||||
let output = '';
|
||||
appProcess.stdout.on('data', data => { output += data; });
|
||||
await emittedOnce(appProcess, 'exit');
|
||||
|
||||
expect(output).to.include('some-modified-text');
|
||||
expect(output).to.include('obj-modified-prop');
|
||||
expect(output).to.include('1,2,5,3,4');
|
||||
});
|
||||
|
||||
it('should make properties unwriteable and read-only if ContextBridgeMutability is off', async () => {
|
||||
const appPath = path.join(fixturesPath, 'context-bridge-mutability');
|
||||
const appProcess = cp.spawn(process.execPath, ['--enable-logging', appPath]);
|
||||
|
||||
let output = '';
|
||||
appProcess.stdout.on('data', data => { output += data; });
|
||||
await emittedOnce(appProcess, 'exit');
|
||||
|
||||
expect(output).to.include('some-text');
|
||||
expect(output).to.include('obj-prop');
|
||||
expect(output).to.include('1,2,3,4');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -361,7 +361,13 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
|
|||
it('requires that the submitURL option be specified', () => {
|
||||
expect(() => {
|
||||
crashReporter.start({} as any);
|
||||
}).to.throw('submitURL is a required option to crashReporter.start');
|
||||
}).to.throw('submitURL must be specified when uploadToServer is true');
|
||||
});
|
||||
|
||||
it('allows the submitURL option to be omitted when uploadToServer is false', () => {
|
||||
expect(() => {
|
||||
crashReporter.start({ uploadToServer: false } as any);
|
||||
}).not.to.throw();
|
||||
});
|
||||
|
||||
it('can be called twice', async () => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { expect } from 'chai';
|
||||
import { v4 } from 'uuid';
|
||||
import { protocol, webContents, WebContents, session, BrowserWindow, ipcMain } from 'electron/main';
|
||||
import { AddressInfo } from 'net';
|
||||
import * as ChildProcess from 'child_process';
|
||||
|
@ -704,7 +705,7 @@ describe('protocol module', () => {
|
|||
});
|
||||
|
||||
describe('protocol.registerSchemeAsPrivileged', () => {
|
||||
// TODO(jeremy): figure out why this times out under ASan
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifit(!process.env.IS_ASAN)('does not crash on exit', async () => {
|
||||
const appPath = path.join(__dirname, 'fixtures', 'api', 'custom-protocol-shutdown.js');
|
||||
const appProcess = ChildProcess.spawn(process.execPath, ['--enable-logging', appPath]);
|
||||
|
@ -724,6 +725,36 @@ describe('protocol module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('protocol.registerSchemesAsPrivileged allowServiceWorkers', () => {
|
||||
const { serviceWorkerScheme } = global as any;
|
||||
protocol.registerStringProtocol(serviceWorkerScheme, (request, cb) => {
|
||||
if (request.url.endsWith('.js')) {
|
||||
cb({
|
||||
mimeType: 'text/javascript',
|
||||
charset: 'utf-8',
|
||||
data: 'console.log("Loaded")'
|
||||
});
|
||||
} else {
|
||||
cb({
|
||||
mimeType: 'text/html',
|
||||
charset: 'utf-8',
|
||||
data: '<!DOCTYPE html>'
|
||||
});
|
||||
}
|
||||
});
|
||||
after(() => protocol.unregisterProtocol(serviceWorkerScheme));
|
||||
|
||||
it('should fail when registering invalid service worker', async () => {
|
||||
await contents.loadURL(`${serviceWorkerScheme}://${v4()}.com`);
|
||||
await expect(contents.executeJavaScript(`navigator.serviceWorker.register('${v4()}.notjs', {scope: './'})`)).to.be.rejected();
|
||||
});
|
||||
|
||||
it('should be able to register service worker for custom scheme', async () => {
|
||||
await contents.loadURL(`${serviceWorkerScheme}://${v4()}.com`);
|
||||
await contents.executeJavaScript(`navigator.serviceWorker.register('${v4()}.js', {scope: './'})`);
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('protocol.registerSchemesAsPrivileged standard', () => {
|
||||
const standardScheme = (global as any).standardScheme;
|
||||
const origin = `${standardScheme}://fake-host`;
|
||||
|
|
|
@ -3,7 +3,6 @@ import { AddressInfo } from 'net';
|
|||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as http from 'http';
|
||||
import * as ChildProcess from 'child_process';
|
||||
import { BrowserWindow, ipcMain, webContents, session, WebContents, app } from 'electron/main';
|
||||
import { clipboard } from 'electron/common';
|
||||
import { emittedOnce } from './events-helpers';
|
||||
|
@ -1268,16 +1267,6 @@ describe('webContents module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('create()', () => {
|
||||
it('does not crash on exit', async () => {
|
||||
const appPath = path.join(fixturesPath, 'api', 'leak-exit-webcontents.js');
|
||||
const electronPath = process.execPath;
|
||||
const appProcess = ChildProcess.spawn(electronPath, [appPath]);
|
||||
const [code] = await emittedOnce(appProcess, 'close');
|
||||
expect(code).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
const crashPrefs = [
|
||||
{
|
||||
nodeIntegration: true
|
||||
|
@ -2016,13 +2005,6 @@ describe('webContents module', () => {
|
|||
});
|
||||
contents.loadURL('about:blank').then(() => contents.forcefullyCrashRenderer());
|
||||
});
|
||||
|
||||
it('does not crash main process when quiting in it', async () => {
|
||||
const appPath = path.join(mainFixturesPath, 'apps', 'quit', 'main.js');
|
||||
const appProcess = ChildProcess.spawn(process.execPath, [appPath]);
|
||||
const [code] = await emittedOnce(appProcess, 'close');
|
||||
expect(code).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('emits a cancelable event before creating a child webcontents', async () => {
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
import { expect } from 'chai';
|
||||
import * as ChildProcess from 'child_process';
|
||||
import * as path from 'path';
|
||||
import { emittedOnce } from './events-helpers';
|
||||
import { closeWindow } from './window-helpers';
|
||||
|
||||
import { BaseWindow, WebContentsView } from 'electron/main';
|
||||
|
@ -15,22 +11,6 @@ describe('WebContentsView', () => {
|
|||
w.setContentView(new WebContentsView({}));
|
||||
});
|
||||
|
||||
describe('new WebContentsView()', () => {
|
||||
it('does not crash on exit', async () => {
|
||||
const appPath = path.join(__dirname, 'fixtures', 'api', 'leak-exit-webcontentsview.js');
|
||||
const electronPath = process.execPath;
|
||||
const appProcess = ChildProcess.spawn(electronPath, ['--enable-logging', appPath]);
|
||||
let output = '';
|
||||
appProcess.stdout.on('data', data => { output += data; });
|
||||
appProcess.stderr.on('data', data => { output += data; });
|
||||
const [code] = await emittedOnce(appProcess, 'exit');
|
||||
if (code !== 0) {
|
||||
console.log(code, output);
|
||||
}
|
||||
expect(code).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
function triggerGCByAllocation () {
|
||||
const arr = [];
|
||||
for (let i = 0; i < 1000000; i++) {
|
||||
|
|
|
@ -18,8 +18,6 @@ const features = process._linkedBinding('electron_common_features');
|
|||
|
||||
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures');
|
||||
|
||||
const isAsan = process.env.IS_ASAN;
|
||||
|
||||
describe('reporting api', () => {
|
||||
// TODO(nornagon): this started failing a lot on CI. Figure out why and fix
|
||||
// it.
|
||||
|
@ -298,7 +296,8 @@ describe('web security', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('command line switches', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('command line switches', () => {
|
||||
let appProcess: ChildProcess.ChildProcessWithoutNullStreams | undefined;
|
||||
afterEach(() => {
|
||||
if (appProcess && !appProcess.killed) {
|
||||
|
@ -343,8 +342,7 @@ describe('command line switches', () => {
|
|||
ifit(process.platform === 'linux')('should not change LC_ALL when --lang is not set', async () => testLocale('', lcAll, true));
|
||||
});
|
||||
|
||||
// TODO(nornagon): figure out why these tests fail under ASan.
|
||||
ifdescribe(!isAsan)('--remote-debugging-pipe switch', () => {
|
||||
describe('--remote-debugging-pipe switch', () => {
|
||||
it('should expose CDP via pipe', async () => {
|
||||
const electronPath = process.execPath;
|
||||
appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe'], {
|
||||
|
@ -386,8 +384,7 @@ describe('command line switches', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// TODO(nornagon): figure out why these tests fail under ASan.
|
||||
ifdescribe(!isAsan)('--remote-debugging-port switch', () => {
|
||||
describe('--remote-debugging-port switch', () => {
|
||||
it('should display the discovery page', (done) => {
|
||||
const electronPath = process.execPath;
|
||||
let output = '';
|
||||
|
|
|
@ -2,6 +2,7 @@ import { expect } from 'chai';
|
|||
import * as cp from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ifdescribe } from './spec-helpers';
|
||||
|
||||
const fixturePath = path.resolve(__dirname, 'fixtures', 'crash-cases');
|
||||
|
||||
|
@ -30,7 +31,8 @@ const runFixtureAndEnsureCleanExit = (args: string[]) => {
|
|||
});
|
||||
};
|
||||
|
||||
describe('crash cases', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('crash cases', () => {
|
||||
afterEach(() => {
|
||||
for (const child of children) {
|
||||
child.kill();
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
<script>
|
||||
try {
|
||||
window.str = 'some-modified-text';
|
||||
window.obj.prop = 'obj-modified-prop';
|
||||
window.arr.splice(2, 0, 5);
|
||||
} catch (e) { }
|
||||
console.log(window.str);
|
||||
console.log(window.obj.prop);
|
||||
console.log(window.arr);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,20 @@
|
|||
const { app, BrowserWindow } = require('electron');
|
||||
const path = require('path');
|
||||
|
||||
let win;
|
||||
app.whenReady().then(function () {
|
||||
win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
});
|
||||
|
||||
win.loadFile('index.html');
|
||||
|
||||
win.webContents.on('console-message', (event, level, message) => {
|
||||
console.log(message);
|
||||
});
|
||||
|
||||
win.webContents.on('did-finish-load', () => app.quit());
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "context-bridge-mutability",
|
||||
"main": "main.js"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
contextBridge.exposeInMainWorld('str', 'some-text');
|
||||
contextBridge.exposeInMainWorld('obj', { prop: 'obj-prop' });
|
||||
contextBridge.exposeInMainWorld('arr', [1, 2, 3, 4]);
|
13
spec-main/fixtures/apps/libuv-hang/index.html
Normal file
13
spec-main/fixtures/apps/libuv-hang/index.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
36
spec-main/fixtures/apps/libuv-hang/main.js
Normal file
36
spec-main/fixtures/apps/libuv-hang/main.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
const { app, BrowserWindow, ipcMain } = require('electron');
|
||||
const path = require('path');
|
||||
|
||||
async function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
});
|
||||
|
||||
await mainWindow.loadFile('index.html');
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let count = 0;
|
||||
ipcMain.handle('reload-successful', () => {
|
||||
if (count === 2) {
|
||||
app.quit();
|
||||
} else {
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
});
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
16
spec-main/fixtures/apps/libuv-hang/preload.js
Normal file
16
spec-main/fixtures/apps/libuv-hang/preload.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
contextBridge.exposeInMainWorld('api', {
|
||||
ipcRenderer,
|
||||
run: async () => {
|
||||
const { promises: fs } = require('fs');
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const list = await fs.readdir('.', { withFileTypes: true });
|
||||
for (const file of list) {
|
||||
if (file.isFile()) {
|
||||
await fs.readFile(file.name, 'utf-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
8
spec-main/fixtures/apps/libuv-hang/renderer.js
Normal file
8
spec-main/fixtures/apps/libuv-hang/renderer.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
const count = localStorage.getItem('count');
|
||||
|
||||
const { run, ipcRenderer } = window.api;
|
||||
|
||||
run().then(async () => {
|
||||
const count = await ipcRenderer.invoke('reload-successful');
|
||||
if (count < 3) location.reload();
|
||||
}).catch(console.log);
|
|
@ -40,9 +40,11 @@
|
|||
arch: process.arch,
|
||||
platform: process.platform,
|
||||
sandboxed: process.sandboxed,
|
||||
contextIsolated: process.contextIsolated,
|
||||
type: process.type,
|
||||
version: process.version,
|
||||
versions: process.versions
|
||||
versions: process.versions,
|
||||
contextId: process.contextId
|
||||
};
|
||||
}
|
||||
} else if (location.href !== 'about:blank') {
|
||||
|
|
|
@ -34,9 +34,11 @@ app.commandLine.appendSwitch('use-fake-device-for-media-stream');
|
|||
|
||||
global.standardScheme = 'app';
|
||||
global.zoomScheme = 'zoom';
|
||||
global.serviceWorkerScheme = 'sw';
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: global.standardScheme, privileges: { standard: true, secure: true, stream: false } },
|
||||
{ scheme: global.zoomScheme, privileges: { standard: true, secure: true } },
|
||||
{ scheme: global.serviceWorkerScheme, privileges: { allowServiceWorkers: true, standard: true, secure: true } },
|
||||
{ scheme: 'cors-blob', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'cors', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'no-cors', privileges: { supportFetchAPI: true } },
|
||||
|
|
|
@ -7,6 +7,7 @@ import { ifdescribe, ifit } from './spec-helpers';
|
|||
import { webContents, WebContents } from 'electron/main';
|
||||
|
||||
const features = process._linkedBinding('electron_common_features');
|
||||
const mainFixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
|
||||
describe('node feature', () => {
|
||||
const fixtures = path.join(__dirname, '..', 'spec', 'fixtures');
|
||||
|
@ -22,6 +23,16 @@ describe('node feature', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('does not hang when using the fs module in the renderer process', async () => {
|
||||
const appPath = path.join(mainFixturesPath, 'apps', 'libuv-hang', 'main.js');
|
||||
const appProcess = childProcess.spawn(process.execPath, [appPath], {
|
||||
cwd: path.join(mainFixturesPath, 'apps', 'libuv-hang'),
|
||||
stdio: 'inherit'
|
||||
});
|
||||
const [code] = await emittedOnce(appProcess, 'close');
|
||||
expect(code).to.equal(0);
|
||||
});
|
||||
|
||||
describe('contexts', () => {
|
||||
describe('setTimeout called under Chromium event loop in browser process', () => {
|
||||
it('Can be scheduled in time', (done) => {
|
||||
|
@ -123,11 +134,12 @@ describe('node feature', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Node.js cli flags', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(features.isRunAsNodeEnabled() && !process.env.IS_ASAN)('Node.js cli flags', () => {
|
||||
let child: childProcess.ChildProcessWithoutNullStreams;
|
||||
let exitPromise: Promise<any[]>;
|
||||
|
||||
ifit(features.isRunAsNodeEnabled())('Prohibits crypto-related flags in ELECTRON_RUN_AS_NODE mode', (done) => {
|
||||
it('Prohibits crypto-related flags in ELECTRON_RUN_AS_NODE mode', (done) => {
|
||||
after(async () => {
|
||||
const [code, signal] = await exitPromise;
|
||||
expect(signal).to.equal(null);
|
||||
|
@ -165,7 +177,8 @@ describe('node feature', () => {
|
|||
});
|
||||
});
|
||||
|
||||
ifdescribe(features.isRunAsNodeEnabled())('inspector', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifdescribe(features.isRunAsNodeEnabled() && !process.env.IS_ASAN)('inspector', () => {
|
||||
let child: childProcess.ChildProcessWithoutNullStreams;
|
||||
let exitPromise: Promise<any[]>;
|
||||
|
||||
|
@ -242,9 +255,8 @@ describe('node feature', () => {
|
|||
}
|
||||
});
|
||||
|
||||
// IPC Electron child process not supported on Windows
|
||||
// TODO(jeremy): figure out why this times out under ASan
|
||||
ifit(process.platform !== 'win32' && !process.env.IS_ASAN)('does not crash when quitting with the inspector connected', function (done) {
|
||||
// IPC Electron child process not supported on Windows.
|
||||
ifit(process.platform !== 'win32')('does not crash when quitting with the inspector connected', function (done) {
|
||||
child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], {
|
||||
stdio: ['ipc']
|
||||
}) as childProcess.ChildProcessWithoutNullStreams;
|
||||
|
@ -304,7 +316,8 @@ describe('node feature', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('Can find a module using a package.json main field', () => {
|
||||
// Running child app under ASan might receive SIGKILL because of OOM.
|
||||
ifit(!process.env.IS_ASAN)('Can find a module using a package.json main field', () => {
|
||||
const result = childProcess.spawnSync(process.execPath, [path.resolve(fixtures, 'api', 'electron-main-module', 'app.asar')]);
|
||||
expect(result.status).to.equal(0);
|
||||
});
|
||||
|
|
|
@ -9,7 +9,11 @@ import { ifit, ifdescribe, delay } from './spec-helpers';
|
|||
const features = process._linkedBinding('electron_common_features');
|
||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', () => {
|
||||
ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () {
|
||||
// TODO(zcbenz): Spellchecker loads really slow on ASan, we should provide
|
||||
// a small testing dictionary to make the tests load faster.
|
||||
this.timeout((process.env.IS_ASAN ? 700 : 20) * 1000);
|
||||
|
||||
let w: BrowserWindow;
|
||||
|
||||
async function rightClick () {
|
||||
|
@ -28,7 +32,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', () => {
|
|||
// to detect spellchecker is to keep checking with a busy loop.
|
||||
async function rightClickUntil (fn: (params: Electron.ContextMenuParams) => boolean) {
|
||||
const now = Date.now();
|
||||
const timeout = 10 * 1000;
|
||||
const timeout = (process.env.IS_ASAN ? 600 : 10) * 1000;
|
||||
let contextMenuParams = await rightClick();
|
||||
while (!fn(contextMenuParams) && (Date.now() - now < timeout)) {
|
||||
await delay(100);
|
||||
|
|
|
@ -3,6 +3,7 @@ import * as url from 'url';
|
|||
import { BrowserWindow, session, ipcMain, app, WebContents } from 'electron/main';
|
||||
import { closeAllWindows } from './window-helpers';
|
||||
import { emittedOnce, emittedUntil } from './events-helpers';
|
||||
import { ifdescribe } from './spec-helpers';
|
||||
import { expect } from 'chai';
|
||||
|
||||
async function loadWebView (w: WebContents, attributes: Record<string, string>, openDevTools: boolean = false): Promise<void> {
|
||||
|
@ -25,7 +26,8 @@ async function loadWebView (w: WebContents, attributes: Record<string, string>,
|
|||
`);
|
||||
}
|
||||
|
||||
describe('<webview> tag', function () {
|
||||
// The render process of webview might receive SIGKILL because of OOM.
|
||||
ifdescribe(!process.env.IS_ASAN)('<webview> tag', function () {
|
||||
const fixtures = path.join(__dirname, '..', 'spec', 'fixtures');
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
|
|
|
@ -115,4 +115,10 @@ describe('process module', () => {
|
|||
expect(success).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('process.contextId', () => {
|
||||
it('is a string', () => {
|
||||
expect(process.contextId).to.be.a('string');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
3
spec/fixtures/api/isolated-process.js
vendored
Normal file
3
spec/fixtures/api/isolated-process.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
const { ipcRenderer } = require('electron');
|
||||
|
||||
ipcRenderer.send('context-isolation', process.contextIsolated);
|
Loading…
Add table
Reference in a new issue