mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
17 Commits
v40.0.0-ni
...
v40.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1ca9a8d55 | ||
|
|
38e491689a | ||
|
|
6e2be00f0f | ||
|
|
497b5a68a4 | ||
|
|
715808ecbe | ||
|
|
01cab978f7 | ||
|
|
7cb1552614 | ||
|
|
49c37b4daa | ||
|
|
37a115b8fd | ||
|
|
e7e29ea876 | ||
|
|
b40a4befd4 | ||
|
|
61a7303531 | ||
|
|
6f9cd718c4 | ||
|
|
a95180e080 | ||
|
|
d4a5fdc8fc | ||
|
|
3a7c6dd4a5 | ||
|
|
26e886c517 |
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@@ -50,6 +50,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5
|
||||
uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) (non-sandboxed only)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to call this API from a renderer process with context isolation enabled,
|
||||
> place the API call in your preload script and
|
||||
> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the
|
||||
> [`contextBridge`](context-bridge.md) API.
|
||||
|
||||
On Linux, there is also a `selection` clipboard. To manipulate it
|
||||
you need to pass `selection` to each method:
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to call this API from a renderer process with context isolation enabled,
|
||||
> place the API call in your preload script and
|
||||
> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the
|
||||
> [`contextBridge`](context-bridge.md) API.
|
||||
|
||||
The following is an example of setting up Electron to automatically submit
|
||||
crash reports to a remote server:
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@ changes:
|
||||
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to call this API from a renderer process with context isolation enabled,
|
||||
> place the API call in your preload script and
|
||||
> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the
|
||||
> [`contextBridge`](context-bridge.md) API.
|
||||
|
||||
The `ipcRenderer` module is an [EventEmitter][event-emitter]. It provides a few
|
||||
methods so you can send synchronous and asynchronous messages from the render
|
||||
process (web page) to the main process. You can also receive replies from the
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to call this API from a renderer process with context isolation enabled,
|
||||
> place the API call in your preload script and
|
||||
> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the
|
||||
> [`contextBridge`](context-bridge.md) API.
|
||||
|
||||
The `nativeImage` module provides a unified interface for manipulating
|
||||
system images. These can be handy if you want to provide multiple scaled
|
||||
versions of the same icon or take advantage of macOS [template images][template-image].
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to call this API from a renderer process with context isolation enabled,
|
||||
> place the API call in your preload script and
|
||||
> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the
|
||||
> [`contextBridge`](context-bridge.md) API.
|
||||
|
||||
`webFrame` export of the Electron module is an instance of the `WebFrame`
|
||||
class representing the current frame. Sub-frames can be retrieved by
|
||||
certain properties and methods (e.g. `webFrame.firstChild`).
|
||||
@@ -139,7 +145,7 @@ by its key, which is returned from `webFrame.insertCSS(css)`.
|
||||
|
||||
Inserts `text` to the focused element.
|
||||
|
||||
### `webFrame.executeJavaScript(code[, userGesture, callback])`
|
||||
### `webFrame.executeJavaScript(code[, userGesture][, callback])`
|
||||
|
||||
* `code` string
|
||||
* `userGesture` boolean (optional) - Default is `false`.
|
||||
@@ -160,7 +166,7 @@ In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||
this limitation.
|
||||
|
||||
### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])`
|
||||
### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture][, callback])`
|
||||
|
||||
* `worldId` Integer - The ID of the world to run the javascript
|
||||
in, `0` is the default main world (where content runs), `999` is the
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to call this API from a renderer process with context isolation enabled,
|
||||
> place the API call in your preload script and
|
||||
> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the
|
||||
> [`contextBridge`](context-bridge.md) API.
|
||||
|
||||
## Methods
|
||||
|
||||
The `webUtils` module has the following methods:
|
||||
@@ -17,11 +23,27 @@ Returns `string` - The file system path that this `File` object points to. In th
|
||||
This method superseded the previous augmentation to the `File` object with the `path` property. An example is included below.
|
||||
|
||||
```js @ts-nocheck
|
||||
// Before
|
||||
const oldPath = document.querySelector('input').files[0].path
|
||||
|
||||
// After
|
||||
const { webUtils } = require('electron')
|
||||
|
||||
const newPath = webUtils.getPathForFile(document.querySelector('input').files[0])
|
||||
// Before (renderer)
|
||||
const oldPath = document.querySelector('input[type=file]').files[0].path
|
||||
```
|
||||
|
||||
```js @ts-nocheck
|
||||
// After
|
||||
|
||||
// Renderer:
|
||||
|
||||
const file = document.querySelector('input[type=file]').files[0]
|
||||
electronApi.doSomethingWithFile(file)
|
||||
|
||||
// Preload script:
|
||||
|
||||
const { contextBridge, webUtils } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronApi', {
|
||||
doSomethingWithFile (file) {
|
||||
const path = webUtils.getPathForFile(file)
|
||||
// Do something with the path, e.g., send it over IPC to the main process.
|
||||
// It's best not to expose the full file path to the web content if possible.
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -39,8 +39,8 @@ consider using `webContents.setWindowOpenHandler` to customize the
|
||||
BrowserWindow creation.
|
||||
|
||||
A subset of [`WebPreferences`](structures/web-preferences.md) can be set directly,
|
||||
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`,
|
||||
`javascript`, `contextIsolation`, and `webviewTag`.
|
||||
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `javascript`,
|
||||
`contextIsolation`, and `webviewTag`.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
@@ -64,13 +64,10 @@ flipFuses(
|
||||
)
|
||||
```
|
||||
|
||||
:::tip Fuses in Electron Forge
|
||||
|
||||
With Electron Forge, you can configure your app's fuses with
|
||||
[@electron-forge/plugin-fuses](https://www.electronforge.io/config/plugins/fuses)
|
||||
in your Forge configuration file.
|
||||
|
||||
:::
|
||||
> [!TIP]
|
||||
> With Electron Forge, you can configure your app's fuses with
|
||||
> [@electron-forge/plugin-fuses](https://www.electronforge.io/config/plugins/fuses)
|
||||
> in your Forge configuration file.
|
||||
|
||||
## Providing the header hash
|
||||
|
||||
@@ -109,7 +106,7 @@ Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of th
|
||||
The `@electron/asar` package exposes a `getRawHeader` method whose result can then be hashed to generate this value
|
||||
(e.g. using the [`node:crypto`](https://nodejs.org/api/crypto.html) module).
|
||||
|
||||
### Windows
|
||||
#### Windows
|
||||
|
||||
When packaging for Windows, you must populate a valid [resource](https://learn.microsoft.com/en-us/windows/win32/menurc/resources)
|
||||
entry of type `Integrity` and name `ElectronAsar`. The value of this resource should be a JSON encoded dictionary
|
||||
@@ -125,9 +122,6 @@ in the form included below:
|
||||
]
|
||||
```
|
||||
|
||||
:::info
|
||||
|
||||
For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts)
|
||||
in the Electron Packager code.
|
||||
|
||||
:::
|
||||
> [!NOTE]
|
||||
> For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts)
|
||||
> in the Electron Packager code.
|
||||
|
||||
@@ -629,8 +629,6 @@ filenames = {
|
||||
"shell/common/gin_converters/usb_device_info_converter.h",
|
||||
"shell/common/gin_converters/value_converter.cc",
|
||||
"shell/common/gin_converters/value_converter.h",
|
||||
"shell/common/gin_helper/arguments.cc",
|
||||
"shell/common/gin_helper/arguments.h",
|
||||
"shell/common/gin_helper/callback.cc",
|
||||
"shell/common/gin_helper/callback.h",
|
||||
"shell/common/gin_helper/cleaned_up_at_exit.cc",
|
||||
|
||||
@@ -141,3 +141,4 @@ chore_add_electron_objects_to_wrappablepointertag.patch
|
||||
chore_expose_isolate_parameter_in_script_lifecycle_observers.patch
|
||||
revert_partial_remove_unused_prehandlemouseevent.patch
|
||||
allow_electron_to_depend_on_components_os_crypt_sync.patch
|
||||
disable_nsautofillheuristiccontroller_on_macos_26.patch
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Perry <perryuwang@tencent.com>
|
||||
Date: Wed, 24 Sep 2025 09:56:23 -0700
|
||||
Subject: Disable NSAutoFillHeuristicController on macOS 26
|
||||
|
||||
The reason for this issue is that NSAutoFillHeuristicController is
|
||||
enabled by default on macOS 26. In pages with <input> tags, browser
|
||||
process sends synchronized IPC messages to renderer process. At this
|
||||
point, if the renderer process also sends synchronized IPC messages to
|
||||
the browser process, it will cause a deadlock.
|
||||
|
||||
This bug can be reproduced on many websites. From the perspective of
|
||||
user experience, we should first disable this feature on macOS 26.
|
||||
|
||||
Bug: 446070423, 446481994
|
||||
Change-Id: I2d3855648980a22678548e373756fc156e28ecd7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6965487
|
||||
Reviewed-by: Mark Mentovai <mark@chromium.org>
|
||||
Commit-Queue: Mark Mentovai <mark@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1520058}
|
||||
|
||||
diff --git a/content/app/mac_init.mm b/content/app/mac_init.mm
|
||||
index 603c25a1bd4a11b9dbe57ac6add81647302e63be..963f45a8936850b59013390faf7890bc4215f2d9 100644
|
||||
--- a/content/app/mac_init.mm
|
||||
+++ b/content/app/mac_init.mm
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
+#include "base/mac/mac_util.h"
|
||||
#include "content/common/mac/system_policy.h"
|
||||
|
||||
namespace content {
|
||||
@@ -29,6 +30,19 @@ void InitializeMac() {
|
||||
@"NSAppSleepDisabled" : @YES,
|
||||
}];
|
||||
|
||||
+ if (base::mac::MacOSVersion() >= 26'00'00) {
|
||||
+ [NSUserDefaults.standardUserDefaults registerDefaults:@{
|
||||
+ // Disable NSAutoFillHeuristicController on macOS 26. On macOS 26, the
|
||||
+ // browser process sends synchronized IPC messages to the renderer process
|
||||
+ // on pages with <input> tags. At this point, if the renderer process
|
||||
+ // sends a synchronized IPC message to the browser process, it will cause
|
||||
+ // a deadlock.
|
||||
+ // https://crbug.com/446070423
|
||||
+ // https://crbug.com/446481994
|
||||
+ @"NSAutoFillHeuristicControllerEnabled" : @NO,
|
||||
+ }];
|
||||
+ }
|
||||
+
|
||||
SetSystemPolicyCrashKeys();
|
||||
}
|
||||
|
||||
@@ -210,8 +210,10 @@ function assetsForVersion (version: string, validatingRelease: boolean) {
|
||||
const cloudStoreFilePaths = (version: string) => [
|
||||
`iojs-${version}-headers.tar.gz`,
|
||||
`iojs-${version}.tar.gz`,
|
||||
`node-${version}-headers.tar.gz`,
|
||||
`node-${version}.tar.gz`,
|
||||
'node.lib',
|
||||
'arm64/node.lib',
|
||||
'x64/node.lib',
|
||||
'win-x64/iojs.lib',
|
||||
'win-x86/iojs.lib',
|
||||
@@ -219,7 +221,6 @@ const cloudStoreFilePaths = (version: string) => [
|
||||
'win-x64/node.lib',
|
||||
'win-x86/node.lib',
|
||||
'win-arm64/node.lib',
|
||||
'arm64/node.lib',
|
||||
'SHASUMS.txt',
|
||||
'SHASUMS256.txt'
|
||||
];
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
#include "base/apple/bundle_locations.h"
|
||||
#include "base/base_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/debug/leak_annotations.h"
|
||||
#include "base/debug/stack_trace.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/metrics/field_trial.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/cstring_view.h"
|
||||
#include "base/strings/string_number_conversions.cc"
|
||||
@@ -419,6 +421,11 @@ std::optional<int> ElectronMainDelegate::PreBrowserMain() {
|
||||
// This is initialized early because the service manager reads some feature
|
||||
// flags and we need to make sure the feature list is initialized before the
|
||||
// service manager reads the features.
|
||||
if (!base::FieldTrialList::GetInstance()) {
|
||||
base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList();
|
||||
ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list);
|
||||
std::ignore = leaked_field_trial_list;
|
||||
}
|
||||
InitializeFeatureList();
|
||||
// Initialize mojo core as soon as we have a valid feature list
|
||||
content::InitializeMojoCore();
|
||||
|
||||
@@ -870,28 +870,33 @@ void App::SetAppPath(const base::FilePath& app_path) {
|
||||
app_path_ = app_path;
|
||||
}
|
||||
|
||||
#if !BUILDFLAG(IS_MAC)
|
||||
void App::SetAppLogsPath(gin_helper::ErrorThrower thrower,
|
||||
std::optional<base::FilePath> custom_path) {
|
||||
if (custom_path.has_value()) {
|
||||
if (!custom_path->IsAbsolute()) {
|
||||
thrower.ThrowError("Path must be absolute");
|
||||
return;
|
||||
}
|
||||
{
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
base::PathService::Override(DIR_APP_LOGS, custom_path.value());
|
||||
}
|
||||
} else {
|
||||
base::FilePath path;
|
||||
if (base::PathService::Get(chrome::DIR_USER_DATA, &path)) {
|
||||
path = path.Append(base::FilePath::FromUTF8Unsafe("logs"));
|
||||
{
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
base::PathService::Override(DIR_APP_LOGS, path);
|
||||
}
|
||||
}
|
||||
void App::SetAppLogsPath(gin::Arguments* const args) {
|
||||
base::FilePath path;
|
||||
|
||||
// if caller provided a path, it must be absolute
|
||||
if (args->GetNext(&path) && !path.IsAbsolute()) {
|
||||
args->ThrowTypeError("Path must be absolute");
|
||||
return;
|
||||
}
|
||||
|
||||
// if caller did not provide a path, then use a default one
|
||||
if (path.empty()) {
|
||||
path = GetDefaultAppLogPath();
|
||||
}
|
||||
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
base::PathService::Override(DIR_APP_LOGS, path);
|
||||
}
|
||||
|
||||
#if !BUILDFLAG(IS_MAC)
|
||||
// static
|
||||
// default to `${DIR_USER_DATA}/logs`
|
||||
base::FilePath App::GetDefaultAppLogPath() {
|
||||
base::FilePath path;
|
||||
if (base::PathService::Get(chrome::DIR_USER_DATA, &path)) {
|
||||
path = path.Append(base::FilePath::FromUTF8Unsafe("logs"));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -178,6 +178,8 @@ class App final : public gin::Wrappable<App>,
|
||||
const content::ChildProcessTerminationInfo& info) override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static base::FilePath GetDefaultAppLogPath();
|
||||
|
||||
void BrowserChildProcessCrashedOrKilled(
|
||||
const content::ChildProcessData& data,
|
||||
const content::ChildProcessTerminationInfo& info);
|
||||
@@ -190,8 +192,7 @@ class App final : public gin::Wrappable<App>,
|
||||
const std::string& name = std::string());
|
||||
void ChildProcessDisconnected(content::ChildProcessId pid);
|
||||
|
||||
void SetAppLogsPath(gin_helper::ErrorThrower thrower,
|
||||
std::optional<base::FilePath> custom_path);
|
||||
void SetAppLogsPath(gin::Arguments* args);
|
||||
|
||||
// Get/Set the pre-defined path in PathService.
|
||||
base::FilePath GetPath(gin_helper::ErrorThrower thrower,
|
||||
|
||||
@@ -17,30 +17,14 @@
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
void App::SetAppLogsPath(gin_helper::ErrorThrower thrower,
|
||||
std::optional<base::FilePath> custom_path) {
|
||||
if (custom_path.has_value()) {
|
||||
if (!custom_path->IsAbsolute()) {
|
||||
thrower.ThrowError("Path must be absolute");
|
||||
return;
|
||||
}
|
||||
{
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
base::PathService::Override(DIR_APP_LOGS, custom_path.value());
|
||||
}
|
||||
} else {
|
||||
NSString* bundle_name =
|
||||
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
NSString* logs_path =
|
||||
[NSString stringWithFormat:@"Library/Logs/%@", bundle_name];
|
||||
NSString* library_path =
|
||||
[NSHomeDirectory() stringByAppendingPathComponent:logs_path];
|
||||
{
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
base::PathService::Override(DIR_APP_LOGS,
|
||||
base::FilePath([library_path UTF8String]));
|
||||
}
|
||||
}
|
||||
base::FilePath App::GetDefaultAppLogPath() {
|
||||
NSString* bundle_name =
|
||||
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
NSString* logs_path =
|
||||
[NSString stringWithFormat:@"Library/Logs/%@", bundle_name];
|
||||
NSString* library_path =
|
||||
[NSHomeDirectory() stringByAppendingPathComponent:logs_path];
|
||||
return base::FilePath{[library_path UTF8String]};
|
||||
}
|
||||
|
||||
void App::SetActivationPolicy(gin_helper::ErrorThrower thrower,
|
||||
|
||||
@@ -98,8 +98,8 @@ void StopTracing(gin_helper::Promise<base::FilePath> promise,
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> StopRecording(gin_helper::Arguments* args) {
|
||||
gin_helper::Promise<base::FilePath> promise(args->isolate());
|
||||
v8::Local<v8::Promise> StopRecording(gin::Arguments* const args) {
|
||||
gin_helper::Promise<base::FilePath> promise{args->isolate()};
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
base::FilePath path;
|
||||
|
||||
@@ -153,36 +153,37 @@ v8::Local<v8::Function> WebContentsView::GetConstructor(v8::Isolate* isolate) {
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::WrappableBase* WebContentsView::New(gin_helper::Arguments* args) {
|
||||
gin_helper::WrappableBase* WebContentsView::New(gin::Arguments* const args) {
|
||||
v8::Isolate* const isolate = args->isolate();
|
||||
gin_helper::Dictionary web_preferences;
|
||||
v8::Local<v8::Value> existing_web_contents_value;
|
||||
{
|
||||
v8::Local<v8::Value> options_value;
|
||||
if (args->GetNext(&options_value)) {
|
||||
gin_helper::Dictionary options;
|
||||
if (!gin::ConvertFromV8(args->isolate(), options_value, &options)) {
|
||||
args->ThrowError("options must be an object");
|
||||
if (!gin::ConvertFromV8(isolate, options_value, &options)) {
|
||||
args->ThrowTypeError("options must be an object");
|
||||
return nullptr;
|
||||
}
|
||||
v8::Local<v8::Value> web_preferences_value;
|
||||
if (options.Get("webPreferences", &web_preferences_value)) {
|
||||
if (!gin::ConvertFromV8(args->isolate(), web_preferences_value,
|
||||
if (!gin::ConvertFromV8(isolate, web_preferences_value,
|
||||
&web_preferences)) {
|
||||
args->ThrowError("options.webPreferences must be an object");
|
||||
args->ThrowTypeError("options.webPreferences must be an object");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.Get("webContents", &existing_web_contents_value)) {
|
||||
gin_helper::Handle<WebContents> existing_web_contents;
|
||||
if (!gin::ConvertFromV8(args->isolate(), existing_web_contents_value,
|
||||
if (!gin::ConvertFromV8(isolate, existing_web_contents_value,
|
||||
&existing_web_contents)) {
|
||||
args->ThrowError("options.webContents must be a WebContents");
|
||||
args->ThrowTypeError("options.webContents must be a WebContents");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (existing_web_contents->owner_window() != nullptr) {
|
||||
args->ThrowError(
|
||||
args->ThrowTypeError(
|
||||
"options.webContents is already attached to a window");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -191,7 +192,7 @@ gin_helper::WrappableBase* WebContentsView::New(gin_helper::Arguments* args) {
|
||||
}
|
||||
|
||||
if (web_preferences.IsEmpty())
|
||||
web_preferences = gin_helper::Dictionary::CreateEmpty(args->isolate());
|
||||
web_preferences = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
if (!web_preferences.Has(options::kShow))
|
||||
web_preferences.Set(options::kShow, false);
|
||||
|
||||
@@ -200,10 +201,10 @@ gin_helper::WrappableBase* WebContentsView::New(gin_helper::Arguments* args) {
|
||||
}
|
||||
|
||||
auto web_contents =
|
||||
WebContents::CreateFromWebPreferences(args->isolate(), web_preferences);
|
||||
WebContents::CreateFromWebPreferences(isolate, web_preferences);
|
||||
|
||||
// Constructor call.
|
||||
auto* view = new WebContentsView(args->isolate(), web_contents);
|
||||
auto* view = new WebContentsView{isolate, web_contents};
|
||||
view->InitWithArgs(args);
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class WebContentsView : public View,
|
||||
void OnViewRemovedFromWidget(views::View* view) override;
|
||||
|
||||
private:
|
||||
static gin_helper::WrappableBase* New(gin_helper::Arguments* args);
|
||||
static gin_helper::WrappableBase* New(gin::Arguments* args);
|
||||
|
||||
void ApplyBorderRadius();
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void ImageView::SetImage(const gfx::Image& image) {
|
||||
}
|
||||
|
||||
// static
|
||||
gin_helper::WrappableBase* ImageView::New(gin_helper::Arguments* args) {
|
||||
gin_helper::WrappableBase* ImageView::New(gin::Arguments* const args) {
|
||||
// Constructor call.
|
||||
auto* view = new ImageView();
|
||||
view->InitWithArgs(args);
|
||||
|
||||
@@ -13,8 +13,11 @@ namespace gfx {
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace gin_helper {
|
||||
namespace gin {
|
||||
class Arguments;
|
||||
} // namespace gin
|
||||
|
||||
namespace gin_helper {
|
||||
class WrappableBase;
|
||||
} // namespace gin_helper
|
||||
|
||||
@@ -22,7 +25,7 @@ namespace electron::api {
|
||||
|
||||
class ImageView : public View {
|
||||
public:
|
||||
static gin_helper::WrappableBase* New(gin_helper::Arguments* args);
|
||||
static gin_helper::WrappableBase* New(gin::Arguments* args);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "shell/browser/browser_observer.h"
|
||||
#include "shell/browser/electron_browser_main_parts.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "shell/common/application_info.h"
|
||||
#include "shell/common/gin_converters/login_item_settings_converter.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
#include "shell/common/thread_restrictions.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "base/command_line.h"
|
||||
#include "base/feature_list.h"
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "base/metrics/field_trial.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/run_loop.h"
|
||||
@@ -206,7 +205,6 @@ int ElectronBrowserMainParts::GetExitCode() const {
|
||||
}
|
||||
|
||||
int ElectronBrowserMainParts::PreEarlyInitialization() {
|
||||
field_trial_list_ = std::make_unique<base::FieldTrialList>();
|
||||
#if BUILDFLAG(IS_POSIX)
|
||||
HandleSIGCHLD();
|
||||
#endif
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
class BrowserProcessImpl;
|
||||
class IconManager;
|
||||
|
||||
namespace base {
|
||||
class FieldTrialList;
|
||||
}
|
||||
|
||||
namespace display {
|
||||
class Screen;
|
||||
class ScopedNativeScreen;
|
||||
@@ -171,7 +167,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
|
||||
std::unique_ptr<Browser> browser_;
|
||||
|
||||
std::unique_ptr<IconManager> icon_manager_;
|
||||
std::unique_ptr<base::FieldTrialList> field_trial_list_;
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
std::unique_ptr<ElectronExtensionsClient> extensions_client_;
|
||||
|
||||
@@ -1333,7 +1333,6 @@ void NativeWindowMac::UpdateVibrancyRadii(bool fullscreen) {
|
||||
maskImage.capInsets = NSEdgeInsetsMake(radius, radius, radius, radius);
|
||||
maskImage.resizingMode = NSImageResizingModeStretch;
|
||||
[vibrantView setMaskImage:maskImage];
|
||||
[window_ setCornerMask:maskImage];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "shell/common/electron_constants.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
|
||||
@@ -31,15 +31,15 @@ namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetWindowBorderAndCaptionColor(HWND hwnd, COLORREF color) {
|
||||
if (base::win::GetVersion() < base::win::Version::WIN11)
|
||||
return;
|
||||
void SetWindowBorderAndCaptionColor(HWND hwnd, COLORREF color, bool has_frame) {
|
||||
HRESULT result;
|
||||
if (has_frame) {
|
||||
result =
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &color, sizeof(color));
|
||||
|
||||
HRESULT result =
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &color, sizeof(color));
|
||||
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to set caption color";
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to set caption color";
|
||||
}
|
||||
|
||||
result =
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
|
||||
@@ -509,7 +509,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
||||
WINDOWPLACEMENT wp;
|
||||
wp.length = sizeof(WINDOWPLACEMENT);
|
||||
|
||||
if (GetWindowPlacement(GetAcceleratedWidget(), &wp)) {
|
||||
if (GetWindowPlacement(GetAcceleratedWidget(), &wp) && !was_snapped_) {
|
||||
last_normal_placement_bounds_ = gfx::Rect(wp.rcNormalPosition);
|
||||
}
|
||||
|
||||
@@ -518,11 +518,9 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
||||
if (w_param == SIZE_MAXIMIZED &&
|
||||
last_window_state_ != ui::mojom::WindowShowState::kMaximized) {
|
||||
if (last_window_state_ == ui::mojom::WindowShowState::kMinimized) {
|
||||
if (was_snapped_) {
|
||||
SetRoundedCorners(false);
|
||||
was_snapped_ = false;
|
||||
}
|
||||
NotifyWindowRestore();
|
||||
if (was_snapped_)
|
||||
was_snapped_ = false;
|
||||
}
|
||||
last_window_state_ = ui::mojom::WindowShowState::kMaximized;
|
||||
NotifyWindowMaximize();
|
||||
@@ -545,12 +543,10 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
||||
last_window_state_ = ui::mojom::WindowShowState::kFullscreen;
|
||||
NotifyWindowEnterFullScreen();
|
||||
} else {
|
||||
if (was_snapped_) {
|
||||
SetRoundedCorners(false);
|
||||
was_snapped_ = false;
|
||||
}
|
||||
last_window_state_ = ui::mojom::WindowShowState::kNormal;
|
||||
NotifyWindowRestore();
|
||||
if (was_snapped_)
|
||||
was_snapped_ = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -595,7 +591,8 @@ void NativeWindowViews::UpdateWindowAccentColor(bool active) {
|
||||
}
|
||||
|
||||
COLORREF final_color = border_color.value_or(DWMWA_COLOR_DEFAULT);
|
||||
SetWindowBorderAndCaptionColor(GetAcceleratedWidget(), final_color);
|
||||
SetWindowBorderAndCaptionColor(GetAcceleratedWidget(), final_color,
|
||||
has_frame());
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetAccentColor(
|
||||
|
||||
@@ -40,7 +40,6 @@ class ElectronNativeWindowObserver;
|
||||
@property BOOL disableAutoHideCursor;
|
||||
@property BOOL disableKeyOrMainWindow;
|
||||
@property(nonatomic, retain) NSVisualEffectView* vibrantView;
|
||||
@property(nonatomic, retain) NSImage* cornerMask;
|
||||
- (id)initWithShell:(electron::NativeWindowMac*)shell
|
||||
styleMask:(NSUInteger)styleMask;
|
||||
- (void)cleanup;
|
||||
@@ -48,7 +47,6 @@ class ElectronNativeWindowObserver;
|
||||
- (id)accessibilityFocusedUIElement;
|
||||
- (NSRect)originalContentRectForFrameRect:(NSRect)frameRect;
|
||||
- (BOOL)toggleFullScreenMode:(id)sender;
|
||||
- (NSImage*)_cornerMask;
|
||||
- (void)disableHeadlessMode;
|
||||
@end
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ int ScopedDisableResize::disable_resize_ = 0;
|
||||
} // namespace electron
|
||||
|
||||
@interface NSWindow (PrivateAPI)
|
||||
- (NSImage*)_cornerMask;
|
||||
- (int64_t)_resizeDirectionForMouseLocation:(CGPoint)location;
|
||||
@end
|
||||
|
||||
@@ -123,7 +122,6 @@ void SwizzleSwipeWithEvent(NSView* view, SEL swiz_selector) {
|
||||
@synthesize disableAutoHideCursor;
|
||||
@synthesize disableKeyOrMainWindow;
|
||||
@synthesize vibrantView;
|
||||
@synthesize cornerMask;
|
||||
|
||||
- (id)initWithShell:(electron::NativeWindowMac*)shell
|
||||
styleMask:(NSUInteger)styleMask {
|
||||
@@ -308,16 +306,6 @@ void SwizzleSwipeWithEvent(NSView* view, SEL swiz_selector) {
|
||||
return [super validateUserInterfaceItem:item];
|
||||
}
|
||||
|
||||
// By overriding this built-in method the corners of the vibrant view (if set)
|
||||
// will be smooth.
|
||||
- (NSImage*)_cornerMask {
|
||||
if (self.vibrantView != nil) {
|
||||
return [self cornerMask];
|
||||
} else {
|
||||
return [super _cornerMask];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)disableHeadlessMode {
|
||||
if (shell_) {
|
||||
// We initialize the window in headless mode to allow painting before it is
|
||||
|
||||
@@ -191,13 +191,15 @@ class Archive : public node::ObjectWrap {
|
||||
static void SplitPath(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto* isolate = args.GetIsolate();
|
||||
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
args.GetReturnValue().Set(dict.GetHandle());
|
||||
|
||||
base::FilePath path;
|
||||
if (!gin::ConvertFromV8(isolate, args[0], &path)) {
|
||||
args.GetReturnValue().Set(v8::False(isolate));
|
||||
dict.Set("isAsar", false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
base::FilePath asar_path, file_path;
|
||||
if (asar::GetAsarArchivePath(path, &asar_path, &file_path, true)) {
|
||||
dict.Set("isAsar", true);
|
||||
@@ -206,7 +208,6 @@ static void SplitPath(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
} else {
|
||||
dict.Set("isAsar", false);
|
||||
}
|
||||
args.GetReturnValue().Set(dict.GetHandle());
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
|
||||
@@ -29,7 +29,7 @@ base::CommandLine::StringType GetSwitchValue(gin_helper::ErrorThrower thrower,
|
||||
}
|
||||
|
||||
void AppendSwitch(const std::string& switch_string,
|
||||
gin_helper::Arguments* args) {
|
||||
gin::Arguments* const args) {
|
||||
auto switch_str = base::ToLowerASCII(switch_string);
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (base::EndsWith(switch_string, "-path",
|
||||
|
||||
@@ -55,7 +55,8 @@ void OnOpenFinished(gin_helper::Promise<void> promise,
|
||||
promise.RejectWithErrorMessage(error);
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> OpenExternal(const GURL& url, gin::Arguments* args) {
|
||||
v8::Local<v8::Promise> OpenExternal(const GURL& url,
|
||||
gin::Arguments* const args) {
|
||||
gin_helper::Promise<void> promise(args->isolate());
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
@@ -108,7 +109,7 @@ v8::Local<v8::Promise> TrashItem(v8::Isolate* isolate,
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
|
||||
bool WriteShortcutLink(const base::FilePath& shortcut_path,
|
||||
gin_helper::Arguments* args) {
|
||||
gin::Arguments* const args) {
|
||||
base::win::ShortcutOperation operation =
|
||||
base::win::ShortcutOperation::kCreateAlways;
|
||||
args->GetNext(&operation);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "shell/common/application_info.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/locker.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "shell/common/heap_snapshot.h"
|
||||
@@ -163,11 +164,11 @@ v8::Local<v8::Value> ElectronBindings::GetCreationTime(v8::Isolate* isolate) {
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> ElectronBindings::GetSystemMemoryInfo(
|
||||
v8::Isolate* isolate,
|
||||
gin_helper::Arguments* args) {
|
||||
v8::Isolate* const isolate) {
|
||||
base::SystemMemoryInfo mem_info;
|
||||
if (!base::GetSystemMemoryInfo(&mem_info)) {
|
||||
args->ThrowError("Unable to retrieve system memory information");
|
||||
gin_helper::ErrorThrower{isolate}.ThrowError(
|
||||
"Unable to retrieve system memory information");
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ class FilePath;
|
||||
}
|
||||
|
||||
namespace gin_helper {
|
||||
class Arguments;
|
||||
class Dictionary;
|
||||
template <typename T>
|
||||
class Promise;
|
||||
@@ -67,8 +66,7 @@ class ElectronBindings {
|
||||
static void Hang();
|
||||
static v8::Local<v8::Value> GetHeapStatistics(v8::Isolate* isolate);
|
||||
static v8::Local<v8::Value> GetCreationTime(v8::Isolate* isolate);
|
||||
static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
|
||||
gin_helper::Arguments* args);
|
||||
static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate);
|
||||
static v8::Local<v8::Promise> GetProcessMemoryInfo(v8::Isolate* isolate);
|
||||
static v8::Local<v8::Value> GetBlinkMemoryInfo(v8::Isolate* isolate);
|
||||
static v8::Local<v8::Value> GetCPUUsage(base::ProcessMetrics* metrics,
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
// functionality that the PDF Viewer needs from outside the PDF plugin. This API
|
||||
// is exclusively for the PDF Viewer.
|
||||
namespace pdfViewerPrivate {
|
||||
// Must match `SaveRequestType` in `pdf/mojom/pdf.mojom` and
|
||||
// `tools/typescript/definitions/pdf_viewer_private.d.ts`.
|
||||
enum SaveRequestType {
|
||||
ANNOTATION,
|
||||
ORIGINAL,
|
||||
EDITED,
|
||||
SEARCHIFIED
|
||||
};
|
||||
|
||||
// Nearly identical to mimeHandlerPrivate.StreamInfo, but without a mime type
|
||||
// nor a response header field. Those fields are unused by the PDF viewer.
|
||||
dictionary StreamInfo {
|
||||
@@ -52,6 +61,13 @@ namespace pdfViewerPrivate {
|
||||
DOMString url,
|
||||
IsAllowedLocalFileAccessCallback callback);
|
||||
|
||||
// Sends a request to save the PDF to Google Drive if `saveRequestType` is
|
||||
// set. Otherwise, if `saveRequestType` is not set, the default action is
|
||||
// to cancel the existing upload.
|
||||
static void saveToDrive(
|
||||
optional SaveRequestType saveRequestType,
|
||||
optional VoidCallback callback);
|
||||
|
||||
// Sets the current tab title to `title` for a full-page PDF.
|
||||
static void setPdfDocumentTitle(
|
||||
DOMString title,
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE.chromium file.
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
|
||||
#include "v8/include/v8-exception.h"
|
||||
|
||||
namespace gin_helper {
|
||||
|
||||
void Arguments::ThrowError() const {
|
||||
// Gin advances |next_| counter when conversion fails while we do not, so we
|
||||
// have to manually advance the counter here to make gin report error with the
|
||||
// correct index.
|
||||
const_cast<Arguments*>(this)->Skip();
|
||||
gin::Arguments::ThrowError();
|
||||
}
|
||||
|
||||
void Arguments::ThrowError(const std::string_view message) const {
|
||||
isolate()->ThrowException(
|
||||
v8::Exception::Error(gin::StringToV8(isolate(), message)));
|
||||
}
|
||||
|
||||
} // namespace gin_helper
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE.chromium file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_ARGUMENTS_H_
|
||||
#define ELECTRON_SHELL_COMMON_GIN_HELPER_ARGUMENTS_H_
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "gin/arguments.h"
|
||||
|
||||
namespace gin_helper {
|
||||
|
||||
// Provides additional APIs to the gin::Arguments class.
|
||||
class Arguments : public gin::Arguments {
|
||||
public:
|
||||
// Get the next argument, if conversion to T fails then state is unchanged.
|
||||
//
|
||||
// This is difference from gin::Arguments::GetNext which always advances the
|
||||
// |next_| counter no matter whether the conversion succeeds.
|
||||
template <typename T>
|
||||
bool GetNext(T* out) {
|
||||
v8::Local<v8::Value> val = PeekNext();
|
||||
if (val.IsEmpty())
|
||||
return false;
|
||||
if (!gin::ConvertFromV8(isolate(), val, out))
|
||||
return false;
|
||||
Skip();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gin always returns true when converting V8 value to boolean, we do not want
|
||||
// this behavior when parsing parameters.
|
||||
bool GetNext(bool* out) {
|
||||
v8::Local<v8::Value> val = PeekNext();
|
||||
if (val.IsEmpty() || !val->IsBoolean())
|
||||
return false;
|
||||
*out = val->BooleanValue(isolate());
|
||||
Skip();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Throw error with custom error message.
|
||||
void ThrowError() const;
|
||||
void ThrowError(std::string_view message) const;
|
||||
|
||||
private:
|
||||
// MUST NOT ADD ANY DATA MEMBER.
|
||||
};
|
||||
|
||||
} // namespace gin_helper
|
||||
|
||||
#endif // ELECTRON_SHELL_COMMON_GIN_HELPER_ARGUMENTS_H_
|
||||
@@ -40,7 +40,7 @@ class GinArgumentsToTuple {
|
||||
// Invoke a callback with arguments extracted from `args`.
|
||||
template <typename... Types>
|
||||
WrappableBase* InvokeFactory(
|
||||
gin::Arguments* args,
|
||||
gin::Arguments* const args,
|
||||
const base::RepeatingCallback<WrappableBase*(Types...)>& callback) {
|
||||
auto [ok, tup] = GinArgumentsToTuple<Types...>::GetArgs(args);
|
||||
if (!ok)
|
||||
@@ -52,10 +52,10 @@ WrappableBase* InvokeFactory(
|
||||
|
||||
template <typename Sig>
|
||||
void InvokeNew(const base::RepeatingCallback<Sig>& factory,
|
||||
v8::Isolate* isolate,
|
||||
gin_helper::Arguments* args) {
|
||||
v8::Isolate* const isolate,
|
||||
gin::Arguments* const args) {
|
||||
if (!args->IsConstructCall()) {
|
||||
args->ThrowError("Requires constructor call");
|
||||
args->ThrowTypeError("Requires constructor call");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "gin/per_isolate_data.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
#include "shell/common/gin_helper/destroyable.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
#include "v8/include/v8-context.h"
|
||||
@@ -154,15 +153,6 @@ inline bool GetNextArgument(gin::Arguments* args,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Electron-specific GetNextArgument that supports the gin_helper::Arguments.
|
||||
inline bool GetNextArgument(gin::Arguments* args,
|
||||
const InvokerOptions& invoker_options,
|
||||
bool is_first,
|
||||
gin_helper::Arguments** result) {
|
||||
*result = static_cast<gin_helper::Arguments*>(args);
|
||||
return true;
|
||||
}
|
||||
|
||||
// For advanced use cases, we allow callers to request the unparsed Arguments
|
||||
// object and poke around in it directly.
|
||||
inline bool GetNextArgument(gin::Arguments* args,
|
||||
|
||||
@@ -48,7 +48,7 @@ v8::Local<v8::Object> WrappableBase::GetWrapper() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void WrappableBase::InitWithArgs(gin::Arguments* args) {
|
||||
void WrappableBase::InitWithArgs(const gin::Arguments* const args) {
|
||||
v8::Local<v8::Object> holder;
|
||||
args->GetHolder(&holder);
|
||||
InitWith(args->isolate(), holder);
|
||||
|
||||
@@ -51,7 +51,7 @@ class WrappableBase {
|
||||
virtual void InitWith(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
|
||||
|
||||
// Helper to init with arguments.
|
||||
void InitWithArgs(gin::Arguments* args);
|
||||
void InitWithArgs(const gin::Arguments* args);
|
||||
|
||||
v8::Global<v8::Object> wrapper_; // Weak
|
||||
|
||||
|
||||
@@ -739,14 +739,13 @@ void ExposeAPI(v8::Isolate* isolate,
|
||||
v8::Isolate* target_isolate,
|
||||
v8::Local<v8::Context> target_context,
|
||||
const std::string& key,
|
||||
v8::Local<v8::Value> api,
|
||||
gin_helper::Arguments* args) {
|
||||
v8::Local<v8::Value> api) {
|
||||
DCHECK(!target_context.IsEmpty());
|
||||
v8::Context::Scope target_context_scope(target_context);
|
||||
gin_helper::Dictionary global(target_isolate, target_context->Global());
|
||||
|
||||
if (global.Has(key)) {
|
||||
args->ThrowError(
|
||||
gin_helper::ErrorThrower{isolate}.ThrowError(
|
||||
"Cannot bind an API on top of an existing property on the window "
|
||||
"object");
|
||||
return;
|
||||
@@ -813,8 +812,7 @@ v8::MaybeLocal<v8::Context> GetTargetContext(v8::Isolate* isolate,
|
||||
void ExposeAPIInWorld(v8::Isolate* isolate,
|
||||
const int world_id,
|
||||
const std::string& key,
|
||||
v8::Local<v8::Value> api,
|
||||
gin_helper::Arguments* args) {
|
||||
v8::Local<v8::Value> api) {
|
||||
TRACE_EVENT2("electron", "ContextBridge::ExposeAPIInWorld", "key", key,
|
||||
"worldId", world_id);
|
||||
v8::Local<v8::Context> source_context = isolate->GetCurrentContext();
|
||||
@@ -825,8 +823,7 @@ void ExposeAPIInWorld(v8::Isolate* isolate,
|
||||
if (maybe_target_context.IsEmpty() || !target_isolate)
|
||||
return;
|
||||
v8::Local<v8::Context> target_context = maybe_target_context.ToLocalChecked();
|
||||
ExposeAPI(isolate, source_context, target_isolate, target_context, key, api,
|
||||
args);
|
||||
ExposeAPI(isolate, source_context, target_isolate, target_context, key, api);
|
||||
}
|
||||
|
||||
gin_helper::Dictionary TraceKeyPath(const gin_helper::Dictionary& start,
|
||||
@@ -923,24 +920,23 @@ bool OverrideGlobalPropertyFromIsolatedWorld(
|
||||
}
|
||||
|
||||
// Serialize script to be executed in the given world.
|
||||
v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* const isolate,
|
||||
const int world_id,
|
||||
gin_helper::Arguments* args) {
|
||||
gin::Arguments* const args) {
|
||||
// Get context of caller
|
||||
v8::Local<v8::Context> source_context = isolate->GetCurrentContext();
|
||||
|
||||
// Get execution script argument
|
||||
gin_helper::Dictionary exec_script;
|
||||
if (args->Length() >= 1 && !args->GetNext(&exec_script)) {
|
||||
gin_helper::ErrorThrower(args->isolate()).ThrowError("Invalid script");
|
||||
args->ThrowTypeError("Invalid script");
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
// Get "func" from execution script
|
||||
v8::Local<v8::Function> func;
|
||||
if (!exec_script.Get("func", &func)) {
|
||||
gin_helper::ErrorThrower(isolate).ThrowError(
|
||||
"Function 'func' is required in script");
|
||||
args->ThrowTypeError("Function 'func' is required in script");
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
@@ -949,7 +945,7 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> args_value;
|
||||
if (exec_script.Get("args", &args_value)) {
|
||||
if (!args_value->IsArray()) {
|
||||
gin_helper::ErrorThrower(isolate).ThrowError("'args' must be an array");
|
||||
args->ThrowTypeError("'args' must be an array");
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
args_array = args_value.As<v8::Array>();
|
||||
@@ -961,7 +957,7 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate,
|
||||
v8::Local<v8::String> serialized_function;
|
||||
if (!func->FunctionProtoToString(isolate->GetCurrentContext())
|
||||
.ToLocal(&serialized_function)) {
|
||||
gin_helper::ErrorThrower(isolate).ThrowError(
|
||||
gin_helper::ErrorThrower{isolate}.ThrowError(
|
||||
"Failed to serialize function");
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/render_frame_observer.h"
|
||||
#include "content/public/renderer/render_frame_visitor.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "services/service_manager/public/cpp/interface_provider.h"
|
||||
#include "shell/common/api/api.mojom.h"
|
||||
@@ -637,12 +638,11 @@ class WebFrameRenderer final
|
||||
return !context->GetContentSecurityPolicy()->ShouldCheckEval();
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* gin_args,
|
||||
// webFrame.executeJavaScript(code[, userGesture][, callback])
|
||||
v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* const args,
|
||||
const std::u16string& code) {
|
||||
gin_helper::Arguments* args = static_cast<gin_helper::Arguments*>(gin_args);
|
||||
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
v8::Isolate* const isolate = args->isolate();
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise{isolate};
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
content::RenderFrame* render_frame;
|
||||
@@ -655,10 +655,14 @@ class WebFrameRenderer final
|
||||
const blink::WebScriptSource source{blink::WebString::FromUTF16(code)};
|
||||
|
||||
bool has_user_gesture = false;
|
||||
args->GetNext(&has_user_gesture);
|
||||
if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsBoolean()) {
|
||||
args->GetNext(&has_user_gesture);
|
||||
}
|
||||
|
||||
ScriptExecutionCallback::CompletionCallback completion_callback;
|
||||
args->GetNext(&completion_callback);
|
||||
if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsFunction()) {
|
||||
args->GetNext(&completion_callback);
|
||||
}
|
||||
|
||||
auto* self = new ScriptExecutionCallback(std::move(promise),
|
||||
std::move(completion_callback));
|
||||
@@ -679,14 +683,14 @@ class WebFrameRenderer final
|
||||
return handle;
|
||||
}
|
||||
|
||||
// executeJavaScriptInIsolatedWorld(
|
||||
// worldId, scripts[, userGesture][, callback])
|
||||
v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
||||
gin::Arguments* gin_args,
|
||||
int world_id,
|
||||
gin::Arguments* const args,
|
||||
const int world_id,
|
||||
const std::vector<gin_helper::Dictionary>& scripts) {
|
||||
gin_helper::Arguments* args = static_cast<gin_helper::Arguments*>(gin_args);
|
||||
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
v8::Isolate* const isolate = args->isolate();
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise{isolate};
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
content::RenderFrame* render_frame;
|
||||
@@ -698,10 +702,14 @@ class WebFrameRenderer final
|
||||
}
|
||||
|
||||
bool has_user_gesture = false;
|
||||
args->GetNext(&has_user_gesture);
|
||||
if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsBoolean()) {
|
||||
args->GetNext(&has_user_gesture);
|
||||
}
|
||||
|
||||
ScriptExecutionCallback::CompletionCallback completion_callback;
|
||||
args->GetNext(&completion_callback);
|
||||
if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsFunction()) {
|
||||
args->GetNext(&completion_callback);
|
||||
}
|
||||
|
||||
std::vector<blink::WebScriptSource> sources;
|
||||
sources.reserve(scripts.size());
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "electron/shell/renderer/electron_ipc_native.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "shell/common/gin_converters/blink_converter.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
@@ -45,10 +47,9 @@ void InvokeIpcCallback(v8::Isolate* const isolate,
|
||||
|
||||
// Only set up the node::CallbackScope if there's a node environment.
|
||||
// Sandboxed renderers don't have a node environment.
|
||||
std::unique_ptr<node::CallbackScope> callback_scope;
|
||||
if (node::Environment::GetCurrent(context)) {
|
||||
callback_scope = std::make_unique<node::CallbackScope>(
|
||||
isolate, ipcNative, node::async_context{0, 0});
|
||||
std::optional<node::CallbackScope> callback_scope;
|
||||
if (auto* env = node::Environment::GetCurrent(context)) {
|
||||
callback_scope.emplace(env, ipcNative, node::async_context{0, 0});
|
||||
}
|
||||
|
||||
auto callback_key = gin::ConvertToV8(isolate, callback_name)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "base/process/process.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "v8/include/v8-context.h"
|
||||
@@ -34,20 +33,19 @@ v8::Local<v8::Object> GetBindingCache(v8::Isolate* isolate) {
|
||||
|
||||
// adapted from node.cc
|
||||
v8::Local<v8::Value> GetBinding(v8::Isolate* isolate,
|
||||
v8::Local<v8::String> key,
|
||||
gin_helper::Arguments* margs) {
|
||||
v8::Local<v8::String> key) {
|
||||
v8::Local<v8::Object> exports;
|
||||
std::string binding_key = gin::V8ToString(isolate, key);
|
||||
const std::string binding_key = gin::V8ToString(isolate, key);
|
||||
gin_helper::Dictionary cache(isolate, GetBindingCache(isolate));
|
||||
|
||||
if (cache.Get(binding_key, &exports)) {
|
||||
return exports;
|
||||
}
|
||||
|
||||
auto* mod = node::binding::get_linked_module(binding_key.c_str());
|
||||
|
||||
auto* const mod = node::binding::get_linked_module(binding_key.c_str());
|
||||
if (!mod) {
|
||||
margs->ThrowError(base::StrCat({"No such binding: ", binding_key}));
|
||||
gin_helper::ErrorThrower{isolate}.ThrowError(
|
||||
base::StrCat({"No such binding: ", binding_key}));
|
||||
return exports;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@ class Arguments;
|
||||
namespace electron::preload_utils {
|
||||
|
||||
v8::Local<v8::Value> GetBinding(v8::Isolate* isolate,
|
||||
v8::Local<v8::String> key,
|
||||
gin_helper::Arguments* margs);
|
||||
v8::Local<v8::String> key);
|
||||
|
||||
v8::Local<v8::Value> CreatePreloadScript(v8::Isolate* isolate,
|
||||
v8::Local<v8::String> source);
|
||||
|
||||
Reference in New Issue
Block a user