Compare commits

...

18 Commits

Author SHA1 Message Date
Shelley Vohr
2b83114b75 spec: fix failing occlusion test on WOA 2024-02-11 22:52:24 +01:00
Charles Kerr
cee51785e1 refactor: inline simple getters, pt . 2 (#41254)
* refactor: inline AutofillPopup::line_count()

refactor: inline AutofillPopup::value_at()

refactor: inline AutofillPopup::label_at()

* refactor: inline NativeWindow::aspect_ratio()

refactor: inline NativeWindow::aspect_ratio_extra_size()

* refactor: inline BrowserProcessImpl::linux_storage_backend()

* refactor: inline ElectronMenuModel::sharing_item()

* refactor: inline Browser::badge_count()

* refactor: inline WebContents::is_guest()

refactor: inline InspectableWebContents::is_guest()

* refactor: inline InspectableWebContents::dev_tool_bounds()

* refactor: inline WebContents::type()
2024-02-09 10:29:14 +01:00
Charles Kerr
b253d52faf build: export matching patches (#41174)
* build: make patches/config.json an array of objects

This file was previously an object of patch_dir keys to repo values;
Now is an array of objects containing `patch_dir` and `repo` properties.
This makes other per-target properties (e.g. `grep`) possible.

* build: include Note metadata when exporting patches

* build: support keyword filtering in export_patches()

* build: add optional `--grep` arg to git-export-patches script

* build: update export_all_patches to understand new config file

* fixup! build: update export_all_patches to understand new config file

chore: make lint happy

* fixup! build: make patches/config.json an array of objects

chore: fix oops

* refactor: remove support for the old file format

There is more code using config.json than I thought, so the
effort-to-reward of supporting the old format is not worth it.

* build: update apply_all_patches to understand new config file

* build: update lint.js to understand new config file

* build: update patches-mtime-cache.py to understand new config file

* fixup! build: update apply_all_patches to understand new config file

fix: oops

* fixup! build: update apply_all_patches to understand new config file

fix minor syntax wart

* fixup! build: support keyword filtering in export_patches()

refactor: use idiomatic python

* refactor: warn if config.json has an invalid repo
2024-02-08 13:47:59 -05:00
github-actions[bot]
4d060afc98 build: update appveyor image to latest version (#41206)
Co-authored-by: jkleinsc <jkleinsc@users.noreply.github.com>
2024-02-08 15:01:05 +01:00
Shelley Vohr
8eb580e79a docs: note EXIF data unsupported in nativeImage (#41261)
* docs: note EXIF data unsupported in nativeImage

* Update docs/api/native-image.md

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

---------

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2024-02-08 14:59:46 +01:00
Bogdan Cerovac
42087e306c fix: add language to html in quick-start.md (#41225)
Add language to html in quick-start.md

We must define language in HTML for different reasons (accessibility++)
2024-02-08 10:27:50 +09:00
Milan Burda
2ea569e0d2 docs: fix docs/api/base-window.md (#41240)
* docs: fix docs/api/base-window.md

* Update docs/api/base-window.md

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

---------

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2024-02-08 10:13:48 +09:00
Felix Rieseberg
4367c5ad9e docs: Properly document runAsNode utility process option (#41255)
* docs: Properly document runAsNode utility process option

* Update docs/api/utility-process.md

Co-authored-by: Charles Kerr <charles@charleskerr.com>

---------

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-02-06 15:54:36 -08:00
Cheng Zhao
92c5ff30a7 build: add flag for setting vendor version (#41247) 2024-02-06 14:23:17 -08:00
Charles Kerr
5686f88bd2 refactor: KeyWeakMap cleanup (#41242)
* refactor: make KeyWeakMap::KeyObject private

* perf: avoid redundant map lookup

* refactor: remove unused KeyWeakMap::Has()

* refactor: make KeyWeakMap dtor nonvirtual

no inheritance used, so no need for virtual dtor?

* chore: fix KeyWeakMap code comment

* refactor: use if statement in KeyWeakMap::Get()

* refactor: use better variable names in KeyWeakMap::Values()
2024-02-06 09:18:05 -06:00
Shelley Vohr
768ece6b54 feat: add BrowserWindow.isOccluded() (#38982)
feat: add BrowserWindow.isOccluded()
2024-02-06 11:30:35 +01:00
Charles Kerr
08236f7a9e refactor: remove deprecated BrowserContext::ResourceContext (#41221)
* refactor: remove ResourceContext* arg from GetNSSCertDatabaseForResourceContext()

* refactor: remove ResourceContext* arg from CertificateManagerModel::GetCertDBOnIOThread()

* refactor: remove BrowserContext* arg from CertificateManagerModel::Create()

* refactor: remove unused forward declarations

* refactor: rename method to GetNSSCertDatabase()

* fixup! refactor: remove BrowserContext* arg from CertificateManagerModel::Create()

chore: remove unneeded line
2024-02-05 18:12:34 -06:00
Shelley Vohr
5dfa9e3317 fix: original-fs import replacement (#41209)
fix: original-fs import replacement
2024-02-05 09:51:04 +01:00
wujinli
fb888a6989 fix: crash problem with message_port close event (#41201)
When worker_thread shutdown, it will destory context and close
message_port. In this case, it should not dispatch close event.
Because it forbid script running during NotifyContextDestroyed in
ContextLifecycleNotifier.
Now chromium has implemented close_event and will not crash,
so we remove the patch with #22532 and add one test.
2024-02-05 16:38:30 +09:00
marekharanczyk
398ca2a019 fix: make sure invalid URL loads promises are fulfilled. (#41194)
* fix: make sure invalid URL loads promisses are fulfilled.

* fixup! fix: make sure invalid URL loads promisses are fulfilled.
2024-02-05 16:36:51 +09:00
Milan Burda
dac29f9949 refactor: type-safe module imports / requires (#41192) 2024-02-05 16:36:28 +09:00
Kilian Valkhof
3ec04fd449 docs: add note about fuses to our security documentation (#41210)
* Add note about fuses to our security documentation

Additionally, add the missing #18 to the ToC.

* lint issues for security.md

* Update docs/tutorial/security.md

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

* move reference links to bottom of security.md

---------

Co-authored-by: Felix Rieseberg <fr@makenotion.com>
2024-02-02 17:28:36 -06:00
Charles Kerr
2ebaebb603 refactor: replace use of deprecated base::JSONWriter::WriteJson() (#41215)
* refactor: use base::WriteJson() in ListValueToNSArray()

refactor: use base::WriteJson() in DictionaryValueToNSDictionary()

* refactor: use base::WriteJson() in Debugger::SendCommand()

* refactor: use base::WriteJson() in ScriptingExecuteScriptFunction::Run()

* refactor: use base::WriteJson() in HandleAccessibilityRequestCallback()
2024-02-02 12:25:58 -06:00
67 changed files with 467 additions and 320 deletions

View File

@@ -29,7 +29,7 @@
version: 1.0.{build}
build_cloud: electronhq-16-core
image: e-123.0.6264.0
image: e-123.0.6272.0
environment:
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
ELECTRON_OUT_DIR: Default

View File

@@ -29,7 +29,7 @@
version: 1.0.{build}
build_cloud: electronhq-16-core
image: e-123.0.6264.0
image: e-123.0.6272.0
environment:
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
ELECTRON_OUT_DIR: Default

View File

@@ -14,4 +14,15 @@ buildflag_header("buildflags") {
"ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker",
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
]
if (electron_vendor_version != "") {
result = string_split(electron_vendor_version, ":")
flags += [
"HAS_VENDOR_VERSION=true",
"VENDOR_VERSION_NAME=\"${result[0]}\"",
"VENDOR_VERSION_VALUE=\"${result[1]}\"",
]
} else {
flags += [ "HAS_VENDOR_VERSION=false" ]
}
}

View File

@@ -21,4 +21,10 @@ declare_args() {
# Packagers and vendor builders should set this in gn args to avoid running
# the script that reads git tag.
override_electron_version = ""
# Define an extra item that will show in process.versions, the value must
# be in the format of "key:value".
# Packagers and vendor builders can set this in gn args to attach extra info
# about the build in the binary.
electron_vendor_version = ""
}

View File

@@ -345,6 +345,10 @@ A `Integer` property representing the unique ID of the window. Each ID is unique
A `View` property for the content view of the window.
#### `win.tabbingIdentifier` _macOS_ _Readonly_
A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set.
#### `win.autoHideMenuBar`
A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key.
@@ -519,7 +523,7 @@ Hides the window.
#### `win.isVisible()`
Returns `boolean` - Whether the window is visible to the user.
Returns `boolean` - Whether the window is visible to the user in the foreground of the app.
#### `win.isModal()`
@@ -557,6 +561,8 @@ Returns `boolean` - Whether the window is minimized.
Sets whether the window should be in fullscreen mode.
**Note:** On macOS, fullscreen transitions take place asynchronously. If further actions depend on the fullscreen state, use the ['enter-full-screen'](base-window.md#event-enter-full-screen) or ['leave-full-screen'](base-window.md#event-leave-full-screen) events.
#### `win.isFullScreen()`
Returns `boolean` - Whether the window is in fullscreen mode.
@@ -669,10 +675,14 @@ win.setBounds({ width: 100 })
console.log(win.getBounds())
```
**Note:** On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray.
#### `win.getBounds()`
Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`.
**Note:** On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`.
#### `win.getBackgroundColor()`
Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format.
@@ -903,8 +913,8 @@ window.
* `offsetX` Float (optional)
Changes the attachment point for sheets on macOS. By default, sheets are
attached just below the window frame, but you may want to offset them. For
example:
attached just below the window frame, but you may want to display them beneath
a HTML-rendered toolbar. For example:
```js
const { BaseWindow } = require('electron')
@@ -1289,6 +1299,10 @@ tabs in the window.
Selects the next tab when native tabs are enabled and there are other
tabs in the window.
#### `win.showAllTabs()` _macOS_
Shows or hides the tab overview when native tabs are enabled.
#### `win.mergeAllWindows()` _macOS_
Merges all windows into one window with multiple tabs when native tabs
@@ -1312,15 +1326,26 @@ Adds a window as a tab on this window, after the tab for the window instance.
#### `win.setVibrancy(type)` _macOS_
* `type` string | null - Can be `appearance-based`, `light`, `dark`, `titlebar`,
`selection`, `menu`, `popover`, `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See
* `type` string | null - Can be `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. See
the [macOS documentation][vibrancy-docs] for more details.
Adds a vibrancy effect to the window. Passing `null` or an empty string
will remove the vibrancy effect on the window.
Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been
deprecated and will be removed in an upcoming version of macOS.
#### `win.setBackgroundMaterial(material)` _Windows_
* `material` string
* `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default.
* `none` - Don't draw any system backdrop.
* `mica` - Draw the backdrop material effect corresponding to a long-lived window.
* `acrylic` - Draw the backdrop material effect corresponding to a transient window.
* `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar.
This method sets the browser window's system-drawn background material, including behind the non-client area.
See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details.
**Note:** This method is only supported on Windows 11 22H2 and up.
#### `win.setWindowButtonPosition(position)` _macOS_
@@ -1334,25 +1359,6 @@ Passing `null` will reset the position to default.
Returns `Point | null` - The custom position for the traffic light buttons in
frameless window, `null` will be returned when there is no custom position.
#### `win.setTrafficLightPosition(position)` _macOS_ _Deprecated_
* `position` [Point](structures/point.md)
Set a custom position for the traffic light buttons in frameless window.
Passing `{ x: 0, y: 0 }` will reset the position to default.
> **Note**
> This function is deprecated. Use [setWindowButtonPosition](#winsetwindowbuttonpositionposition-macos) instead.
#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_
Returns `Point` - The custom position for the traffic light buttons in
frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom
position.
> **Note**
> This function is deprecated. Use [getWindowButtonPosition](#wingetwindowbuttonposition-macos) instead.
#### `win.setTouchBar(touchBar)` _macOS_
* `touchBar` TouchBar | null

View File

@@ -644,6 +644,14 @@ Shows the window but doesn't focus on it.
Hides the window.
#### `win.isOccluded()`
Returns `boolean` - Whether the window is covered by other windows.
On macOS, a `BrowserWindow` is occluded if the entire window is obscured by other windows. A completely transparent window may also be considered non-occluded. See [docs](https://developer.apple.com/documentation/appkit/nswindowocclusionstate?language=objc) for more details.
On Windows and Linux, a window is occluded if it or one of its descendants is visible, and all visible windows have their bounds completely covered by fully opaque windows. A window is considered "fully opaque" if it is visible, it is not transparent, and its combined opacity is 1. See [Chromium Source](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:ui/aura/window.h;l=124-151;drc=7d2d8ccab2b68fbbfc5e1611d45bd4ecf87090b8) for more details.
#### `win.isVisible()`
Returns `boolean` - Whether the window is visible to the user in the foreground of the app.
@@ -744,16 +752,16 @@ Examples of valid `backgroundColor` values:
* #ffffff (RGB)
* #ffffffff (ARGB)
* RGB
* rgb\((\[\d]+),\s*(\[\d]+),\s*(\[\d]+)\)
* `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)`
* e.g. rgb(255, 255, 255)
* RGBA
* rgba\((\[\d]+),\s*(\[\d]+),\s*(\[\d]+),\s*(\[\d.]+)\)
* `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)`
* e.g. rgba(255, 255, 255, 1.0)
* HSL
* hsl\((-?\[\d.]+),\s*(\[\d.]+)%,\s*(\[\d.]+)%\)
* `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)`
* e.g. hsl(200, 20%, 50%)
* HSLA
* hsla\((-?\[\d.]+),\s*(\[\d.]+)%,\s*(\[\d.]+)%,\s*(\[\d.]+)\)
* `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)`
* e.g. hsla(200, 20%, 50%, 0.5)
* Color name
* Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148)

View File

@@ -51,6 +51,13 @@ Check the _Size requirements_ section in [this article][icons].
[icons]: https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-icons
:::note
EXIF metadata is currently not supported and will not be taken into account during
image encoding and decoding.
:::
## High Resolution Image
On platforms that have high-DPI support such as Apple Retina displays, you can

View File

@@ -21,12 +21,11 @@ Process: [Main](../glossary.md#main-process)<br />
of the child process. Default is `inherit`.
String value can be one of `pipe`, `ignore`, `inherit`, for more details on these values you can refer to
[stdio][] documentation from Node.js. Currently this option only supports configuring `stdout` and
`stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` is not supported; `stdin` will
always be ignored.
`stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` to any property other than `ignore` is not supported and will result in an error.
For example, the supported values will be processed as following:
* `pipe`: equivalent to \['ignore', 'pipe', 'pipe'] (the default)
* `pipe`: equivalent to \['ignore', 'pipe', 'pipe']
* `ignore`: equivalent to \['ignore', 'ignore', 'ignore']
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit']
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit'] (the default)
* `serviceName` string (optional) - Name of the process that will appear in `name` property of
[`ProcessMetric`](structures/process-metric.md) returned by [`app.getAppMetrics`](app.md#appgetappmetrics)
and [`child-process-gone` event of `app`](app.md#event-child-process-gone).

View File

@@ -15,7 +15,7 @@ Fuses are the solution to this problem, at a high level they are "magic bits" in
**Default:** Enabled
**@electron/fuses:** `FuseV1Options.RunAsNode`
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function.
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function. Instead, we recommend that you use [Utility Processes](../api/utility-process.md), which work for many use cases where you need a standalone Node.js process (like a Sqlite server process or similar scenarios).
### `cookieEncryption`

View File

@@ -126,7 +126,7 @@ folder of your project:
```html
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
@@ -420,9 +420,8 @@ window.addEventListener('DOMContentLoaded', () => {
```html
<!--index.html-->
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->

View File

@@ -114,6 +114,8 @@ You should at least follow these steps to improve the security of your applicati
15. [Do not use `shell.openExternal` with untrusted content](#15-do-not-use-shellopenexternal-with-untrusted-content)
16. [Use a current version of Electron](#16-use-a-current-version-of-electron)
17. [Validate the `sender` of all IPC messages](#17-validate-the-sender-of-all-ipc-messages)
18. [Avoid usage of the `file://` protocol and prefer usage of custom protocols](#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols)
19. [Check which fuses you can change](#19-check-which-fuses-you-can-change)
To automate the detection of misconfigurations and insecure patterns, it is
possible to use
@@ -780,6 +782,28 @@ set of files.
Follow the [`protocol.handle`](../api/protocol.md#protocolhandlescheme-handler) examples to
learn how to serve files / content from a custom protocol.
### 19. Check which fuses you can change
Electron ships with a number of options that can be useful but a large portion of
applications probably don't need. In order to avoid having to build your own version of
Electron, these can be turned off or on using [Fuses](./fuses.md).
#### Why?
Some fuses, like `runAsNode` and `nodeCliInspect`, allow the application to behave differently
when run from the command line using specific environment variables or CLI arguments. These
can be used to execute commands on the device through your application.
This can let external scripts run commands that they potentially would not be allowed to, but
that your application might have the rights for.
#### How?
We've made a module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make
flipping these fuses easy. Check out the README of that module for more details on usage and
potential error cases, and refer to
[How do I flip the fuses?](./fuses.md#how-do-i-flip-the-fuses) in our documentation.
[breaking-changes]: ../breaking-changes.md
[browser-window]: ../api/browser-window.md
[webview-tag]: ../api/webview-tag.md

View File

@@ -366,11 +366,6 @@ WebContents.prototype.loadURL = function (url, options) {
resolveAndCleanup();
}
};
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
if (!error && isMainFrame) {
error = { errorCode, errorDescription, url: validatedURL };
}
};
let navigationStarted = false;
let browserInitiatedInPageNavigation = false;
@@ -392,6 +387,14 @@ WebContents.prototype.loadURL = function (url, options) {
navigationStarted = true;
}
};
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
if (!error && isMainFrame) {
error = { errorCode, errorDescription, url: validatedURL };
}
if (!navigationStarted && isMainFrame) {
finishListener();
}
};
const stopLoadingListener = () => {
// By the time we get here, either 'finish' or 'fail' should have fired
// if the navigation occurred. However, in some situations (e.g. when

View File

@@ -3,6 +3,8 @@ import * as fs from 'fs';
import * as path from 'path';
import type * as defaultMenuModule from '@electron/internal/browser/default-menu';
import type * as url from 'url';
import type * as v8 from 'v8';
const Module = require('module') as NodeJS.ModuleInternal;
@@ -132,7 +134,7 @@ if (packageJson.desktopName != null) {
// Set v8 flags, deliberately lazy load so that apps that do not use this
// feature do not pay the price
if (packageJson.v8Flags != null) {
require('v8').setFlagsFromString(packageJson.v8Flags);
(require('v8') as typeof v8).setFlagsFromString(packageJson.v8Flags);
}
app.setAppPath(packagePath);
@@ -199,7 +201,7 @@ if (packagePath) {
// Finally load app's main.js and transfer control to C++.
if ((packageJson.type === 'module' && !mainStartupScript.endsWith('.cjs')) || mainStartupScript.endsWith('.mjs')) {
const { loadESM } = __non_webpack_require__('internal/process/esm_loader');
const main = require('url').pathToFileURL(path.join(packagePath, mainStartupScript));
const main = (require('url') as typeof url).pathToFileURL(path.join(packagePath, mainStartupScript));
loadESM(async (esmLoader: any) => {
try {
await esmLoader.import(main.toString(), undefined, Object.create(null));

View File

@@ -1,6 +1,7 @@
import * as util from 'util';
import type * as stream from 'stream';
const timers = require('timers');
import timers = require('timers');
type AnyFn = (...args: any[]) => any
@@ -62,7 +63,7 @@ if (process.type === 'browser' ||
if (process.platform === 'win32') {
// Always returns EOF for stdin stream.
const { Readable } = require('stream');
const { Readable } = require('stream') as typeof stream;
const stdin = new Readable();
stdin.push(null);
Object.defineProperty(process, 'stdin', {

View File

@@ -2,7 +2,9 @@ import { Buffer } from 'buffer';
import { constants } from 'fs';
import * as path from 'path';
import * as util from 'util';
import type * as Crypto from 'crypto';
import type * as os from 'os';
const asar = process._linkedBinding('electron_common_asar');
@@ -255,7 +257,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
if (!process.env.ELECTRON_LOG_ASAR_READS) return;
if (!logFDs.has(asarPath)) {
const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`;
const logPath = path.join(require('os').tmpdir(), logFilename);
const logPath = path.join((require('os') as typeof os).tmpdir(), logFilename);
logFDs.set(asarPath, fs.openSync(logPath, 'a'));
}
fs.writeSync(logFDs.get(asarPath), `${offset}: ${filePath}\n`);

View File

@@ -1,4 +1,5 @@
import * as events from 'events';
import { setImmediate, clearImmediate } from 'timers';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
@@ -126,7 +127,6 @@ function runPreloadScript (preloadSrc: string) {
// eval in window scope
const preloadFn = binding.createPreloadScript(preloadWrapperSrc);
const { setImmediate, clearImmediate } = require('timers');
const exports = {};
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate, exports, { exports });

View File

@@ -47,7 +47,6 @@ feat_add_support_for_overriding_the_base_spellchecker_download_url.patch
feat_enable_offscreen_rendering_with_viz_compositor.patch
gpu_notify_when_dxdiag_request_fails.patch
feat_allow_embedders_to_add_observers_on_created_hunspell.patch
feat_add_onclose_to_messageport.patch
allow_in-process_windows_to_have_different_web_prefs.patch
refactor_expose_cursor_changes_to_the_webcontentsobserver.patch
crash_allow_setting_more_options.patch

View File

@@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jeremy Apthorp <nornagon@nornagon.net>
Date: Wed, 4 Mar 2020 11:18:03 -0800
Subject: feat: add onclose to MessagePort
This adds the 'onclose' event to MessagePort. Can be removed once
https://bugs.chromium.org/p/chromium/issues/detail?id=1495616 is fixed.
diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc
index 2e0961fd8c0bc8f9a2a7c124693033eb234928bd..5c54705e3c1766553e9cba13142345485ca44578 100644
--- a/third_party/blink/renderer/core/messaging/message_port.cc
+++ b/third_party/blink/renderer/core/messaging/message_port.cc
@@ -195,6 +195,7 @@ void MessagePort::close() {
Entangle(pipe.TakePort0(), nullptr);
}
closed_ = true;
+ DispatchEvent(*Event::Create(event_type_names::kClose));
}
void MessagePort::OnConnectionError() {
diff --git a/third_party/blink/renderer/core/messaging/message_port.idl b/third_party/blink/renderer/core/messaging/message_port.idl
index 9df43655b569428a6abc54341b4b0023e159f99b..3f1f181d9b8a66997136f870f55c97c08294b6eb 100644
--- a/third_party/blink/renderer/core/messaging/message_port.idl
+++ b/third_party/blink/renderer/core/messaging/message_port.idl
@@ -40,5 +40,5 @@
// event handlers
attribute EventHandler onmessage;
attribute EventHandler onmessageerror;
- [RuntimeEnabled=MessagePortCloseEvent] attribute EventHandler onclose;
+ attribute EventHandler onclose;
};

View File

@@ -1,27 +1,15 @@
{
"src/electron/patches/chromium": "src",
"src/electron/patches/boringssl": "src/third_party/boringssl/src",
"src/electron/patches/devtools_frontend": "src/third_party/devtools-frontend/src",
"src/electron/patches/ffmpeg": "src/third_party/ffmpeg",
"src/electron/patches/v8": "src/v8",
"src/electron/patches/node": "src/third_party/electron_node",
"src/electron/patches/nan": "src/third_party/nan",
"src/electron/patches/perfetto": "src/third_party/perfetto",
"src/electron/patches/squirrel.mac": "src/third_party/squirrel.mac",
"src/electron/patches/Mantle": "src/third_party/squirrel.mac/vendor/Mantle",
"src/electron/patches/ReactiveObjC": "src/third_party/squirrel.mac/vendor/ReactiveObjC",
"src/electron/patches/webrtc": "src/third_party/webrtc",
"src/electron/patches/reclient-configs": "src/third_party/engflow-reclient-configs"
}
[
{ "patch_dir": "src/electron/patches/chromium", "repo": "src" },
{ "patch_dir": "src/electron/patches/boringssl", "repo": "src/third_party/boringssl/src" },
{ "patch_dir": "src/electron/patches/devtools_frontend", "repo": "src/third_party/devtools-frontend/src" },
{ "patch_dir": "src/electron/patches/ffmpeg", "repo": "src/third_party/ffmpeg" },
{ "patch_dir": "src/electron/patches/v8", "repo": "src/v8" },
{ "patch_dir": "src/electron/patches/node", "repo": "src/third_party/electron_node" },
{ "patch_dir": "src/electron/patches/nan", "repo": "src/third_party/nan" },
{ "patch_dir": "src/electron/patches/perfetto", "repo": "src/third_party/perfetto" },
{ "patch_dir": "src/electron/patches/squirrel.mac", "repo": "src/third_party/squirrel.mac" },
{ "patch_dir": "src/electron/patches/Mantle", "repo": "src/third_party/squirrel.mac/vendor/Mantle" },
{ "patch_dir": "src/electron/patches/ReactiveObjC", "repo": "src/third_party/squirrel.mac/vendor/ReactiveObjC" },
{ "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
{ "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" }
]

View File

@@ -2312,10 +2312,10 @@ index 0000000000000000000000000000000000000000..7848ddb1841b6d4f36e9376c73564eb4
+ f.write('\n')
diff --git a/tools/generate_original_fs.py b/tools/generate_original_fs.py
new file mode 100644
index 0000000000000000000000000000000000000000..98d569e6ba6d85a29a215a8f9ce3c1f6a9bd655e
index 0000000000000000000000000000000000000000..a6cdf33f2c0bcca4d7b4eacaa407f1ac5bdcb5cb
--- /dev/null
+++ b/tools/generate_original_fs.py
@@ -0,0 +1,18 @@
@@ -0,0 +1,19 @@
+import os
+import sys
+
@@ -2332,8 +2332,9 @@ index 0000000000000000000000000000000000000000..98d569e6ba6d85a29a215a8f9ce3c1f6
+ original_f.write(contents)
+
+ with open(os.path.join(out_dir, original_fs_file), 'w') as transformed_f:
+ transformed_contents = contents.replace('internal/fs/', 'internal/original-fs/')
+ transformed_contents = contents.replace('internal/fs/', 'internal/original-fs/').replace('require(\'fs', 'require(\'original-fs')
+ transformed_f.write(transformed_contents)
+
diff --git a/tools/install.py b/tools/install.py
index 11616e1bcac5308020eb68fdb811bfb86cb14dd5..74b01f8352021f1105c080dbbf8bb29121a13501 100755
--- a/tools/install.py

View File

@@ -3,19 +3,30 @@
import argparse
import json
import os
import warnings
from lib import git
from lib.patches import patch_from_dir
THREEWAY = "ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES" in os.environ
def apply_patches(dirs):
threeway = os.environ.get("ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES")
for patch_dir, repo in dirs.items():
if os.path.exists(repo):
git.import_patches(repo=repo, patch_data=patch_from_dir(patch_dir),
threeway=threeway is not None,
committer_name="Electron Scripts", committer_email="scripts@electron")
def apply_patches(target):
repo = target.get('repo')
if not os.path.exists(repo):
warnings.warn('repo not found: %s' % repo)
return
patch_dir = target.get('patch_dir')
git.import_patches(
committer_email="scripts@electron",
committer_name="Electron Scripts",
patch_data=patch_from_dir(patch_dir),
repo=repo,
threeway=THREEWAY,
)
def apply_config(config):
for target in config:
apply_patches(target)
def parse_args():
parser = argparse.ArgumentParser(description='Apply Electron patches')
@@ -26,9 +37,8 @@ def parse_args():
def main():
configs = parse_args().config
for config_json in configs:
apply_patches(json.load(config_json))
for config_json in parse_args().config:
apply_config(json.load(config_json))
if __name__ == '__main__':

View File

@@ -3,14 +3,27 @@
import argparse
import json
import os
import warnings
from lib import git
def export_patches(dirs, dry_run):
for patch_dir, repo in dirs.items():
if os.path.exists(repo):
git.export_patches(repo=repo, out_dir=patch_dir, dry_run=dry_run)
def export_patches(target, dry_run):
repo = target.get('repo')
if not os.path.exists(repo):
warnings.warn('repo not found: %s' % repo)
return
git.export_patches(
dry_run=dry_run,
grep=target.get('grep'),
out_dir=target.get('patch_dir'),
repo=repo
)
def export_config(config, dry_run):
for target in config:
export_patches(target, dry_run)
def parse_args():
@@ -28,7 +41,7 @@ def main():
configs = parse_args().config
dry_run = parse_args().dry_run
for config_json in configs:
export_patches(json.load(config_json), dry_run)
export_config(json.load(config_json), dry_run)
if __name__ == '__main__':

View File

@@ -10,13 +10,15 @@ def main(argv):
parser.add_argument("-o", "--output",
help="directory into which exported patches will be written",
required=True)
parser.add_argument("--grep",
help="only export patches matching a keyword")
parser.add_argument("patch_range",
nargs='?',
help="range of patches to export. Defaults to all commits since the "
"most recent tag or remote branch.")
args = parser.parse_args(argv)
git.export_patches('.', args.output, patch_range=args.patch_range)
git.export_patches('.', args.output, patch_range=args.patch_range, grep=args.grep)
if __name__ == '__main__':

View File

@@ -149,6 +149,7 @@ def format_patch(repo, since):
'format-patch',
'--keep-subject',
'--no-stat',
'--notes',
'--stdout',
# Per RFC 3676 the signature is separated from the body by a line with
@@ -181,6 +182,16 @@ def split_patches(patch_data):
patches[-1].append(line)
return patches
def filter_patches(patches, key):
"""Return patches that include the specified key"""
if key is None:
return patches
matches = []
for patch in patches:
if any(key in line for line in patch):
matches.append(patch)
continue
return matches
def munge_subject_to_filename(subject):
"""Derive a suitable filename from a commit's subject"""
@@ -227,7 +238,7 @@ def remove_patch_filename(patch):
force_keep_next_line = l.startswith('Subject: ')
def export_patches(repo, out_dir, patch_range=None, dry_run=False):
def export_patches(repo, out_dir, patch_range=None, dry_run=False, grep=None):
if not os.path.exists(repo):
sys.stderr.write(
"Skipping patches in {} because it does not exist.\n".format(repo)
@@ -239,6 +250,8 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False):
num_patches, repo, patch_range[0:7]))
patch_data = format_patch(repo, patch_range)
patches = split_patches(patch_data)
if grep:
patches = filter_patches(patches, grep)
try:
os.mkdir(out_dir)

View File

@@ -201,10 +201,9 @@ const LINTERS = [{
process.exit(1);
}
const config = JSON.parse(fs.readFileSync(patchesConfig, 'utf8'));
for (const key of Object.keys(config)) {
for (const target of JSON.parse(fs.readFileSync(patchesConfig, 'utf8'))) {
// The directory the config points to should exist
const targetPatchesDir = path.resolve(__dirname, '../../..', key);
const targetPatchesDir = path.resolve(__dirname, '../../..', target.patch_dir);
if (!fs.existsSync(targetPatchesDir)) {
console.error(`target patch directory: "${targetPatchesDir}" does not exist`);
process.exit(1);

View File

@@ -12,7 +12,9 @@ from lib.patches import patch_from_dir
def patched_file_paths(patches_config):
for patch_dir, repo in patches_config.items():
for target in patches_config:
patch_dir = target.get('patch_dir')
repo = target.get('repo')
for line in patch_from_dir(patch_dir).split("\n"):
if line.startswith("+++"):
yield posixpath.join(repo, line[6:])

View File

@@ -1228,13 +1228,10 @@ void App::ImportCertificate(gin_helper::ErrorThrower thrower,
return;
}
auto* browser_context = ElectronBrowserContext::From("", false);
if (!certificate_manager_model_) {
CertificateManagerModel::Create(
browser_context,
base::BindOnce(&App::OnCertificateManagerModelCreated,
base::Unretained(this), std::move(options),
std::move(callback)));
CertificateManagerModel::Create(base::BindOnce(
&App::OnCertificateManagerModelCreated, base::Unretained(this),
std::move(options), std::move(callback)));
return;
}
@@ -1684,7 +1681,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
.SetMethod("setBadgeCount",
base::BindRepeating(&Browser::SetBadgeCount, browser))
.SetMethod("getBadgeCount",
base::BindRepeating(&Browser::GetBadgeCount, browser))
base::BindRepeating(&Browser::badge_count, browser))
.SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
.SetMethod("setLoginItemSettings",
base::BindRepeating(&Browser::SetLoginItemSettings, browser))

View File

@@ -355,6 +355,10 @@ bool BaseWindow::IsVisible() const {
return window_->IsVisible();
}
bool BaseWindow::IsOccluded() const {
return window_->IsOccluded();
}
bool BaseWindow::IsEnabled() const {
return window_->IsEnabled();
}
@@ -1086,6 +1090,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("showInactive", &BaseWindow::ShowInactive)
.SetMethod("hide", &BaseWindow::Hide)
.SetMethod("isVisible", &BaseWindow::IsVisible)
.SetMethod("isOccluded", &BaseWindow::IsOccluded)
.SetMethod("isEnabled", &BaseWindow::IsEnabled)
.SetMethod("setEnabled", &BaseWindow::SetEnabled)
.SetMethod("maximize", &BaseWindow::Maximize)

View File

@@ -98,6 +98,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
void ShowInactive();
void Hide();
bool IsVisible() const;
bool IsOccluded() const;
bool IsEnabled() const;
void SetEnabled(bool enable);
void Maximize();

View File

@@ -159,8 +159,7 @@ v8::Local<v8::Promise> Debugger::SendCommand(gin::Arguments* args) {
request.Set("sessionId", session_id);
}
std::string json_args;
base::JSONWriter::Write(request, &json_args);
const auto json_args = base::WriteJson(request).value_or("");
agent_host_->DispatchProtocolMessage(
this, base::as_bytes(base::make_span(json_args)));

View File

@@ -31,7 +31,7 @@ bool IsEncryptionAvailable() {
return OSCrypt::IsEncryptionAvailable() ||
(use_password_v10 &&
static_cast<BrowserProcessImpl*>(g_browser_process)
->GetLinuxStorageBackend() == "basic_text");
->linux_storage_backend() == "basic_text");
#else
return OSCrypt::IsEncryptionAvailable();
#endif
@@ -46,7 +46,7 @@ std::string GetSelectedLinuxBackend() {
if (!Browser::Get()->is_ready())
return "unknown";
return static_cast<BrowserProcessImpl*>(g_browser_process)
->GetLinuxStorageBackend();
->linux_storage_backend();
}
#endif

View File

@@ -852,7 +852,7 @@ WebContents::WebContents(v8::Isolate* isolate,
session_.Reset(isolate, session.ToV8());
std::unique_ptr<content::WebContents> web_contents;
if (IsGuest()) {
if (is_guest()) {
scoped_refptr<content::SiteInstance> site_instance =
content::SiteInstance::CreateForURL(session->browser_context(),
GURL("chrome-guest://fake-host"));
@@ -922,7 +922,7 @@ void WebContents::InitWithSessionAndOptions(
const gin_helper::Dictionary& options) {
Observe(owned_web_contents.get());
InitWithWebContents(std::move(owned_web_contents), session->browser_context(),
IsGuest());
is_guest());
inspectable_web_contents_->GetView()->SetDelegate(this);
@@ -982,7 +982,7 @@ void WebContents::InitWithSessionAndOptions(
SetUserAgent(GetBrowserContext()->GetUserAgent());
if (IsGuest()) {
if (is_guest()) {
NativeWindow* owner_window = nullptr;
if (embedder_) {
// New WebContents's owner_window is the embedder's owner_window.
@@ -1017,7 +1017,7 @@ void WebContents::InitWithExtensionView(v8::Isolate* isolate,
// Allow toggling DevTools for background pages
Observe(web_contents);
InitWithWebContents(std::unique_ptr<content::WebContents>(web_contents),
GetBrowserContext(), IsGuest());
GetBrowserContext(), is_guest());
inspectable_web_contents_->GetView()->SetDelegate(this);
}
#endif
@@ -1066,7 +1066,7 @@ WebContents::~WebContents() {
// For guest view based on OOPIF, the WebContents is released by the embedder
// frame, and we need to clear the reference to the memory.
bool not_owned_by_this = IsGuest() && attached_;
bool not_owned_by_this = is_guest() && attached_;
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// And background pages are owned by extensions::ExtensionHost.
if (type_ == Type::kBackgroundPage)
@@ -1096,7 +1096,7 @@ void WebContents::DeleteThisIfAlive() {
void WebContents::Destroy() {
// The content::WebContents should be destroyed asynchronously when possible
// as user may choose to destroy WebContents during an event of it.
if (Browser::Get()->is_shutting_down() || IsGuest()) {
if (Browser::Get()->is_shutting_down() || is_guest()) {
DeleteThisIfAlive();
} else {
content::GetUIThreadTaskRunner({})->PostTask(
@@ -2155,7 +2155,7 @@ void WebContents::DidFinishNavigation(
Emit("did-navigate", url, http_response_code, http_status_text);
}
}
if (IsGuest())
if (is_guest())
Emit("load-commit", url, is_main_frame);
} else {
auto url = navigation_handle->GetURL();
@@ -2374,10 +2374,6 @@ base::ProcessId WebContents::GetOSProcessID() const {
return base::GetProcId(process_handle);
}
WebContents::Type WebContents::GetType() const {
return type_;
}
bool WebContents::Equal(const WebContents* web_contents) const {
return ID() == web_contents->ID();
}
@@ -3371,7 +3367,7 @@ bool WebContents::IsFocused() const {
if (!view)
return false;
if (GetType() != Type::kBackgroundPage) {
if (type() != Type::kBackgroundPage) {
auto* window = web_contents()->GetNativeView()->GetToplevelWindow();
if (window && !window->IsVisible())
return false;
@@ -3567,10 +3563,6 @@ void WebContents::OnCursorChanged(const ui::Cursor& cursor) {
}
}
bool WebContents::IsGuest() const {
return type_ == Type::kWebView;
}
void WebContents::AttachToIframe(content::WebContents* embedder_web_contents,
int embedder_frame_id) {
attached_ = true;
@@ -3782,7 +3774,7 @@ void WebContents::SetImageAnimationPolicy(const std::string& new_policy) {
}
void WebContents::SetBackgroundColor(std::optional<SkColor> maybe_color) {
SkColor color = maybe_color.value_or((IsGuest() && guest_transparent_) ||
SkColor color = maybe_color.value_or((is_guest() && guest_transparent_) ||
type_ == Type::kBrowserView
? SK_ColorTRANSPARENT
: SK_ColorWHITE);
@@ -4304,7 +4296,7 @@ void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
}
// Make sure all child webviews quit html fullscreen.
if (!fullscreen && !IsGuest()) {
if (!fullscreen && !is_guest()) {
auto* manager = WebViewManager::GetWebViewManager(web_contents());
manager->ForEachGuest(web_contents(), [&](content::WebContents* guest) {
WebContents* api_web_contents = WebContents::From(guest);
@@ -4416,7 +4408,7 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
.SetMethod("getZoomLevel", &WebContents::GetZoomLevel)
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::GetType)
.SetMethod("getType", &WebContents::type)
.SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)

View File

@@ -173,7 +173,7 @@ class WebContents : public ExclusiveAccessContext,
void SetBackgroundThrottling(bool allowed);
int GetProcessID() const;
base::ProcessId GetOSProcessID() const;
Type GetType() const;
[[nodiscard]] Type type() const { return type_; }
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const gin_helper::Dictionary& options);
void Reload();
@@ -292,7 +292,7 @@ class WebContents : public ExclusiveAccessContext,
v8::Local<v8::Promise> CapturePage(gin::Arguments* args);
// Methods for creating <webview>.
bool IsGuest() const;
[[nodiscard]] bool is_guest() const { return type_ == Type::kWebView; }
void AttachToIframe(content::WebContents* embedder_web_contents,
int embedder_frame_id);
void DetachFromOuterFrame();

View File

@@ -24,7 +24,7 @@ bool WebContents::IsFocused() const {
if (!view)
return false;
if (GetType() != Type::kBackgroundPage) {
if (type() != Type::kBackgroundPage) {
auto window = [web_contents()->GetNativeView().GetNativeNSView() window];
// On Mac the render widget host view does not lose focus when the window
// loses focus so check if the top level window is the key window.

View File

@@ -159,10 +159,6 @@ void Browser::SetName(const std::string& name) {
OverriddenApplicationName() = name;
}
int Browser::GetBadgeCount() {
return badge_count_;
}
bool Browser::OpenFile(const std::string& file_path) {
bool prevent_default = false;
for (BrowserObserver& observer : observers_)

View File

@@ -110,7 +110,7 @@ class Browser : public WindowListObserver {
// Set/Get the badge count.
bool SetBadgeCount(std::optional<int> count);
int GetBadgeCount();
[[nodiscard]] int badge_count() const { return badge_count_; }
#if BUILDFLAG(IS_WIN)
struct LaunchItem {

View File

@@ -340,10 +340,6 @@ void BrowserProcessImpl::SetLinuxStorageBackend(
break;
}
}
const std::string& BrowserProcessImpl::GetLinuxStorageBackend() const {
return selected_linux_storage_backend_;
}
#endif // BUILDFLAG(IS_LINUX)
void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {

View File

@@ -59,7 +59,9 @@ class BrowserProcessImpl : public BrowserProcess {
#if BUILDFLAG(IS_LINUX)
void SetLinuxStorageBackend(os_crypt::SelectedLinuxBackend selected_backend);
const std::string& GetLinuxStorageBackend() const;
[[nodiscard]] const std::string& linux_storage_backend() const {
return selected_linux_storage_backend_;
}
#endif
void EndSession() override {}

View File

@@ -7,9 +7,7 @@
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_context.h"
#include "base/memory/ptr_util.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h"
@@ -25,8 +23,7 @@ namespace {
net::NSSCertDatabase* g_nss_cert_database = nullptr;
net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
content::ResourceContext* context,
net::NSSCertDatabase* GetNSSCertDatabase(
base::OnceCallback<void(net::NSSCertDatabase*)> callback) {
// This initialization is not thread safe. This CHECK ensures that this code
// is only run on a single thread.
@@ -57,7 +54,7 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
// \--------------------------------------v
// CertificateManagerModel::GetCertDBOnIOThread
// |
// GetNSSCertDatabaseForResourceContext
// GetNSSCertDatabase
// |
// CertificateManagerModel::DidGetCertDBOnIOThread
// v--------------------------------------/
@@ -68,12 +65,10 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
// callback
// static
void CertificateManagerModel::Create(content::BrowserContext* browser_context,
CreationCallback callback) {
void CertificateManagerModel::Create(CreationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread,
browser_context->GetResourceContext(),
std::move(callback)));
}
@@ -151,16 +146,14 @@ void CertificateManagerModel::DidGetCertDBOnIOThread(
}
// static
void CertificateManagerModel::GetCertDBOnIOThread(
content::ResourceContext* context,
CreationCallback callback) {
void CertificateManagerModel::GetCertDBOnIOThread(CreationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto split_callback = base::SplitOnceCallback(base::BindOnce(
&CertificateManagerModel::DidGetCertDBOnIOThread, std::move(callback)));
net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
context, std::move(split_callback.first));
net::NSSCertDatabase* cert_db =
GetNSSCertDatabase(std::move(split_callback.first));
// If the NSS database was already available, |cert_db| is non-null and
// |did_get_cert_db_callback| has not been called. Call it explicitly.

View File

@@ -13,11 +13,6 @@
#include "base/memory/ref_counted.h"
#include "net/cert/nss_cert_database.h"
namespace content {
class BrowserContext;
class ResourceContext;
} // namespace content
// CertificateManagerModel provides the data to be displayed in the certificate
// manager dialog, and processes changes from the view.
class CertificateManagerModel {
@@ -26,10 +21,8 @@ class CertificateManagerModel {
base::OnceCallback<void(std::unique_ptr<CertificateManagerModel>)>;
// Creates a CertificateManagerModel. The model will be passed to the callback
// when it is ready. The caller must ensure the model does not outlive the
// |browser_context|.
static void Create(content::BrowserContext* browser_context,
CreationCallback callback);
// when it is ready.
static void Create(CreationCallback callback);
// disable copy
CertificateManagerModel(const CertificateManagerModel&) = delete;
@@ -105,8 +98,7 @@ class CertificateManagerModel {
CreationCallback callback);
static void DidGetCertDBOnIOThread(CreationCallback callback,
net::NSSCertDatabase* cert_db);
static void GetCertDBOnIOThread(content::ResourceContext* context,
CreationCallback callback);
static void GetCertDBOnIOThread(CreationCallback callback);
raw_ptr<net::NSSCertDatabase> cert_db_;
// Whether the certificate database has a public slot associated with the

View File

@@ -631,10 +631,11 @@ ExtensionFunction::ResponseAction ScriptingExecuteScriptFunction::Run() {
std::vector<std::string> string_args;
string_args.reserve(injection_.args->size());
for (const auto& arg : *injection_.args) {
std::string json;
if (!base::JSONWriter::Write(arg, &json))
if (auto json = base::WriteJson(arg)) {
string_args.push_back(std::move(*json));
} else {
return RespondNow(Error("Unserializable argument passed."));
string_args.push_back(std::move(json));
}
}
args_expression = base::JoinString(string_args, ",");
}

View File

@@ -13,10 +13,10 @@
namespace electron {
NSArray* ListValueToNSArray(const base::Value::List& value) {
std::string json;
if (!base::JSONWriter::Write(base::ValueView{value}, &json))
const auto json = base::WriteJson(value);
if (!json.has_value())
return nil;
NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()];
NSData* jsonData = [NSData dataWithBytes:json->data() length:json->size()];
id obj = [NSJSONSerialization JSONObjectWithData:jsonData
options:0
error:nil];
@@ -56,10 +56,10 @@ base::Value::List NSArrayToValue(NSArray* arr) {
}
NSDictionary* DictionaryValueToNSDictionary(const base::Value::Dict& value) {
std::string json;
if (!base::JSONWriter::Write(base::ValueView{value}, &json))
const auto json = base::WriteJson(value);
if (!json.has_value())
return nil;
NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()];
NSData* jsonData = [NSData dataWithBytes:json->data() length:json->size()];
id obj = [NSJSONSerialization JSONObjectWithData:jsonData
options:0
error:nil];

View File

@@ -520,14 +520,6 @@ bool NativeWindow::IsMenuBarVisible() const {
return true;
}
double NativeWindow::GetAspectRatio() const {
return aspect_ratio_;
}
gfx::Size NativeWindow::GetAspectRatioExtraSize() const {
return aspect_ratio_extraSize_;
}
void NativeWindow::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
aspect_ratio_ = aspect_ratio;

View File

@@ -87,6 +87,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void Show() = 0;
virtual void ShowInactive() = 0;
virtual void Hide() = 0;
virtual bool IsOccluded() const = 0;
virtual bool IsVisible() const = 0;
virtual bool IsEnabled() const = 0;
virtual void SetEnabled(bool enable) = 0;
@@ -263,8 +264,10 @@ class NativeWindow : public base::SupportsUserData,
virtual bool IsMenuBarVisible() const;
// Set the aspect ratio when resizing window.
double GetAspectRatio() const;
gfx::Size GetAspectRatioExtraSize() const;
[[nodiscard]] double aspect_ratio() const { return aspect_ratio_; }
[[nodiscard]] gfx::Size aspect_ratio_extra_size() const {
return aspect_ratio_extraSize_;
}
virtual void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
// File preview APIs.

View File

@@ -44,6 +44,7 @@ class NativeWindowMac : public NativeWindow,
void Show() override;
void ShowInactive() override;
void Hide() override;
bool IsOccluded() const override;
bool IsVisible() const override;
bool IsEnabled() const override;
void SetEnabled(bool enable) override;

View File

@@ -561,9 +561,12 @@ void NativeWindowMac::Hide() {
[window_ orderOut:nil];
}
bool NativeWindowMac::IsOccluded() const {
return !([window_ occlusionState] & NSWindowOcclusionStateVisible);
}
bool NativeWindowMac::IsVisible() const {
bool occluded = [window_ occlusionState] == NSWindowOcclusionStateVisible;
return [window_ isVisible] && !occluded && !IsMinimized();
return [window_ isVisible] && !IsMinimized();
}
bool NativeWindowMac::IsEnabled() const {
@@ -638,7 +641,7 @@ bool NativeWindowMac::IsMaximized() const {
if (HasStyleMask(NSWindowStyleMaskResizable) != 0)
return [window_ isZoomed];
NSRect rectScreen = GetAspectRatio() > 0.0
NSRect rectScreen = aspect_ratio() > 0.0
? default_frame_for_zoom()
: [[NSScreen mainScreen] visibleFrame];

View File

@@ -562,6 +562,14 @@ void NativeWindowViews::Hide() {
#endif
}
bool NativeWindowViews::IsOccluded() const {
if (!GetNativeWindow())
return false;
auto occlusion_state =
GetNativeWindow()->GetHost()->GetNativeWindowOcclusionState();
return occlusion_state == aura::Window::OcclusionState::OCCLUDED;
}
bool NativeWindowViews::IsVisible() const {
#if BUILDFLAG(IS_WIN)
// widget()->IsVisible() calls ::IsWindowVisible, which returns non-zero if a

View File

@@ -56,6 +56,7 @@ class NativeWindowViews : public NativeWindow,
void Hide() override;
bool IsVisible() const override;
bool IsEnabled() const override;
bool IsOccluded() const override;
void SetEnabled(bool enable) override;
void Maximize() override;
void Unmaximize() override;

View File

@@ -231,7 +231,7 @@ void AutofillPopup::SetItems(const std::vector<std::u16string>& values,
void AutofillPopup::AcceptSuggestion(int index) {
mojo::AssociatedRemote<mojom::ElectronAutofillAgent> autofill_agent;
frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(&autofill_agent);
autofill_agent->AcceptDataListSuggestion(GetValueAt(index));
autofill_agent->AcceptDataListSuggestion(value_at(index));
}
void AutofillPopup::UpdatePopupBounds() {
@@ -272,11 +272,10 @@ int AutofillPopup::GetDesiredPopupWidth() {
int popup_width = element_bounds_.width();
for (size_t i = 0; i < values_.size(); ++i) {
int row_size =
kEndPadding + 2 * kPopupBorderThickness +
gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) +
gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i));
if (!GetLabelAt(i).empty())
int row_size = kEndPadding + 2 * kPopupBorderThickness +
gfx::GetStringWidth(value_at(i), GetValueFontListForRow(i)) +
gfx::GetStringWidth(label_at(i), GetLabelFontListForRow(i));
if (!label_at(i).empty())
row_size += kNamePadding + kEndPadding;
popup_width = std::max(popup_width, row_size);
@@ -307,18 +306,6 @@ ui::ColorId AutofillPopup::GetBackgroundColorIDForRow(int index) const {
: ui::kColorResultsTableNormalBackground;
}
int AutofillPopup::GetLineCount() {
return values_.size();
}
std::u16string AutofillPopup::GetValueAt(int i) {
return values_.at(i);
}
std::u16string AutofillPopup::GetLabelAt(int i) {
return labels_.at(i);
}
int AutofillPopup::LineFromY(int y) const {
int current_height = kPopupBorderThickness;

View File

@@ -57,9 +57,9 @@ class AutofillPopup : public views::ViewObserver {
const gfx::FontList& GetLabelFontListForRow(int index) const;
ui::ColorId GetBackgroundColorIDForRow(int index) const;
int GetLineCount();
std::u16string GetValueAt(int i);
std::u16string GetLabelAt(int i);
int line_count() const { return values_.size(); }
const std::u16string& value_at(int i) const { return values_.at(i); }
const std::u16string& label_at(int i) const { return labels_.at(i); }
int LineFromY(int y) const;
int selected_index_;

View File

@@ -27,7 +27,7 @@
devtools_is_first_responder_ = NO;
attached_to_window_ = NO;
if (inspectableWebContentsView_->inspectable_web_contents()->IsGuest()) {
if (inspectableWebContentsView_->inspectable_web_contents()->is_guest()) {
fake_view_ = [[NSView alloc] init];
[fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:fake_view_];

View File

@@ -493,8 +493,8 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
if (menu_)
return menu_;
if (model_ && model_->GetSharingItem()) {
NSMenu* menu = [self createShareMenuForItem:*model_->GetSharingItem()];
if (model_ && model_->sharing_item()) {
NSMenu* menu = [self createShareMenuForItem:*model_->sharing_item()];
menu_ = menu;
} else {
menu_ = [[NSMenu alloc] initWithTitle:@""];

View File

@@ -76,7 +76,7 @@ using FullScreenTransitionState =
- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
defaultFrame:(NSRect)frame {
if (!shell_->zoom_to_page_width()) {
if (shell_->GetAspectRatio() > 0.0)
if (shell_->aspect_ratio() > 0.0)
shell_->set_default_frame_for_zoom(frame);
return frame;
}
@@ -104,7 +104,7 @@ using FullScreenTransitionState =
// Set the width. Don't touch y or height.
frame.size.width = zoomed_width;
if (shell_->GetAspectRatio() > 0.0)
if (shell_->aspect_ratio() > 0.0)
shell_->set_default_frame_for_zoom(frame);
return frame;
@@ -139,13 +139,12 @@ using FullScreenTransitionState =
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
double aspectRatio = shell_->GetAspectRatio();
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
if (aspectRatio > 0.0) {
gfx::Size windowSize = shell_->GetSize();
gfx::Size contentSize = shell_->GetContentSize();
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
if (const double aspectRatio = shell_->aspect_ratio(); aspectRatio > 0.0) {
const gfx::Size windowSize = shell_->GetSize();
const gfx::Size contentSize = shell_->GetContentSize();
const gfx::Size extraSize = shell_->aspect_ratio_extra_size();
double titleBarHeight = windowSize.height() - contentSize.height();
double extraWidthPlusFrame =

View File

@@ -99,11 +99,6 @@ bool ElectronMenuModel::GetSharingItemAt(size_t index,
void ElectronMenuModel::SetSharingItem(SharingItem item) {
sharing_item_.emplace(std::move(item));
}
const std::optional<ElectronMenuModel::SharingItem>&
ElectronMenuModel::GetSharingItem() const {
return sharing_item_;
}
#endif
void ElectronMenuModel::MenuWillClose() {

View File

@@ -98,7 +98,10 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
bool GetSharingItemAt(size_t index, SharingItem* item) const;
// Set/Get the SharingItem of this menu.
void SetSharingItem(SharingItem item);
const std::optional<SharingItem>& GetSharingItem() const;
[[nodiscard]] const std::optional<SharingItem>& sharing_item() const {
return sharing_item_;
}
#endif
// ui::SimpleMenuModel:

View File

@@ -384,10 +384,6 @@ InspectableWebContentsDelegate* InspectableWebContents::GetDelegate() const {
return delegate_;
}
bool InspectableWebContents::IsGuest() const {
return is_guest_;
}
void InspectableWebContents::ReleaseWebContents() {
web_contents_.release();
WebContentsDestroyed();
@@ -454,7 +450,7 @@ void InspectableWebContents::CloseDevTools() {
managed_devtools_web_contents_.reset();
}
embedder_message_dispatcher_.reset();
if (!IsGuest())
if (!is_guest())
web_contents_->Focus();
}
}
@@ -516,10 +512,6 @@ void InspectableWebContents::CallClientFunction(
std::move(arguments), std::move(cb));
}
gfx::Rect InspectableWebContents::GetDevToolsBounds() const {
return devtools_bounds_;
}
void InspectableWebContents::SaveDevToolsBounds(const gfx::Rect& bounds) {
pref_service_->Set(kDevToolsBoundsPref,
base::Value{RectToDictionary(bounds)});

View File

@@ -55,7 +55,7 @@ class InspectableWebContents
void SetDelegate(InspectableWebContentsDelegate* delegate);
InspectableWebContentsDelegate* GetDelegate() const;
bool IsGuest() const;
[[nodiscard]] bool is_guest() const { return is_guest_; }
void ReleaseWebContents();
void SetDevToolsWebContents(content::WebContents* devtools);
void SetDockState(const std::string& state);
@@ -76,7 +76,9 @@ class InspectableWebContents
void InspectElement(int x, int y);
// Return the last position and size of devtools window.
gfx::Rect GetDevToolsBounds() const;
[[nodiscard]] const gfx::Rect& dev_tools_bounds() const {
return devtools_bounds_;
}
void SaveDevToolsBounds(const gfx::Rect& bounds);
// Return the last set zoom level of devtools window.

View File

@@ -124,7 +124,7 @@ void AutofillPopupView::OnSuggestionsChanged() {
return;
CreateChildViews();
if (popup_->GetLineCount() == 0) {
if (popup_->line_count() == 0) {
popup_->Hide();
return;
}
@@ -177,28 +177,28 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas,
int x_align_left = value_rect.x();
const int value_width = gfx::GetStringWidth(
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index));
popup_->value_at(index), popup_->GetValueFontListForRow(index));
int value_x_align_left = x_align_left;
value_x_align_left =
is_rtl ? value_rect.right() - value_width : value_rect.x();
canvas->DrawStringRectWithFlags(
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index),
popup_->value_at(index), popup_->GetValueFontListForRow(index),
GetColorProvider()->GetColor(ui::kColorResultsTableNormalText),
gfx::Rect(value_x_align_left, value_rect.y(), value_width,
value_rect.height()),
text_align);
// Draw the label text, if one exists.
if (!popup_->GetLabelAt(index).empty()) {
const int label_width = gfx::GetStringWidth(
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index));
if (auto const& label = popup_->label_at(index); !label.empty()) {
const int label_width =
gfx::GetStringWidth(label, popup_->GetLabelFontListForRow(index));
int label_x_align_left = x_align_left;
label_x_align_left =
is_rtl ? value_rect.x() : value_rect.right() - label_width;
canvas->DrawStringRectWithFlags(
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index),
label, popup_->GetLabelFontListForRow(index),
GetColorProvider()->GetColor(ui::kColorResultsTableDimmedText),
gfx::Rect(label_x_align_left, entry_rect.y(), label_width,
entry_rect.height()),
@@ -212,8 +212,8 @@ void AutofillPopupView::CreateChildViews() {
RemoveAllChildViews();
for (int i = 0; i < popup_->GetLineCount(); ++i) {
auto* child_view = new AutofillPopupChildView(popup_->GetValueAt(i));
for (int i = 0; i < popup_->line_count(); ++i) {
auto* child_view = new AutofillPopupChildView(popup_->value_at(i));
child_view->set_drag_controller(this);
AddChildView(child_view);
}
@@ -234,8 +234,7 @@ void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() {
}
void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
if (!popup_ ||
static_cast<size_t>(popup_->GetLineCount()) != children().size())
if (!popup_ || static_cast<size_t>(popup_->line_count()) != children().size())
return;
gfx::Canvas* draw_canvas = canvas;
SkBitmap bitmap;
@@ -252,7 +251,7 @@ void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
GetColorProvider()->GetColor(ui::kColorResultsTableNormalBackground));
OnPaintBorder(draw_canvas);
for (int i = 0; i < popup_->GetLineCount(); ++i) {
for (int i = 0; i < popup_->line_count(); ++i) {
gfx::Rect line_rect = popup_->GetRowBounds(i);
DrawAutofillEntry(draw_canvas, i, line_rect);
@@ -381,7 +380,7 @@ bool AutofillPopupView::HandleKeyPressEvent(
SetSelectedLine(0);
return true;
case ui::VKEY_NEXT: // Page down.
SetSelectedLine(popup_->GetLineCount() - 1);
SetSelectedLine(popup_->line_count() - 1);
return true;
case ui::VKEY_ESCAPE:
popup_->Hide();
@@ -421,7 +420,7 @@ void AutofillPopupView::AcceptSuggestion(int index) {
}
bool AutofillPopupView::AcceptSelectedLine() {
if (!selected_line_ || selected_line_.value() >= popup_->GetLineCount())
if (!selected_line_ || selected_line_.value() >= popup_->line_count())
return false;
AcceptSuggestion(selected_line_.value());
@@ -441,7 +440,7 @@ void AutofillPopupView::SetSelectedLine(std::optional<int> selected_line) {
return;
if (selected_line_ == selected_line)
return;
if (selected_line && selected_line.value() >= popup_->GetLineCount())
if (selected_line && selected_line.value() >= popup_->line_count())
return;
auto previous_selected_line(selected_line_);
@@ -461,7 +460,7 @@ void AutofillPopupView::SelectNextLine() {
return;
int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0;
if (new_selected_line >= popup_->GetLineCount())
if (new_selected_line >= popup_->line_count())
new_selected_line = 0;
SetSelectedLine(new_selected_line);
@@ -473,7 +472,7 @@ void AutofillPopupView::SelectPreviousLine() {
int new_selected_line = selected_line_.value_or(0) - 1;
if (new_selected_line < 0)
new_selected_line = popup_->GetLineCount() - 1;
new_selected_line = popup_->line_count() - 1;
SetSelectedLine(new_selected_line);
}

View File

@@ -83,7 +83,7 @@ InspectableWebContentsViewViews::InspectableWebContentsViewViews(
: InspectableWebContentsView(inspectable_web_contents),
devtools_web_view_(new views::WebView(nullptr)),
title_(u"Developer Tools") {
if (!inspectable_web_contents_->IsGuest() &&
if (!inspectable_web_contents_->is_guest() &&
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
auto* contents_web_view = new views::WebView(nullptr);
contents_web_view->SetWebContents(
@@ -116,8 +116,7 @@ void InspectableWebContentsViewViews::ShowDevTools(bool activate) {
if (devtools_window_) {
devtools_window_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_window_->SetBounds(
inspectable_web_contents()->GetDevToolsBounds());
devtools_window_->SetBounds(inspectable_web_contents()->dev_tools_bounds());
if (activate) {
devtools_window_->Show();
} else {
@@ -182,7 +181,7 @@ void InspectableWebContentsViewViews::SetIsDocked(bool docked, bool activate) {
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = devtools_window_delegate_;
params.bounds = inspectable_web_contents()->GetDevToolsBounds();
params.bounds = inspectable_web_contents()->dev_tools_bounds();
#if BUILDFLAG(IS_LINUX)
params.wm_role_name = "devtools";

View File

@@ -295,11 +295,8 @@ void HandleAccessibilityRequestCallback(
data.Set(kBrowsersField, std::move(window_list));
std::string json_string;
base::JSONWriter::Write(data, &json_string);
std::move(callback).Run(
base::MakeRefCounted<base::RefCountedString>(std::move(json_string)));
std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
base::WriteJson(data).value_or("")));
}
} // namespace

View File

@@ -107,7 +107,7 @@ class TrackableObject : public TrackableObjectBase, public EventEmitter<T> {
// Removes this instance from the weak map.
void RemoveFromWeakMap() {
if (weak_map_ && weak_map_->Has(weak_map_id()))
if (weak_map_)
weak_map_->Remove(weak_map_id());
}

View File

@@ -9,24 +9,17 @@
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "v8/include/v8.h"
namespace electron {
// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer.
// Like ES6's WeakMap, with a K key and Weak Pointer value.
template <typename K>
class KeyWeakMap {
public:
// Records the key and self, used by SetWeak.
struct KeyObject {
K key;
raw_ptr<KeyWeakMap> self;
};
KeyWeakMap() {}
virtual ~KeyWeakMap() {
~KeyWeakMap() {
for (auto& p : map_)
p.second.second.ClearWeak();
}
@@ -45,23 +38,19 @@ class KeyWeakMap {
// Gets the object from WeakMap by its |key|.
v8::MaybeLocal<v8::Object> Get(v8::Isolate* isolate, const K& key) {
auto iter = map_.find(key);
if (iter == map_.end())
return v8::MaybeLocal<v8::Object>();
else
if (auto iter = map_.find(key); iter != map_.end())
return v8::Local<v8::Object>::New(isolate, iter->second.second);
return {};
}
// Whether there is an object with |key| in this WeakMap.
constexpr bool Has(const K& key) const { return base::Contains(map_, key); }
// Returns all objects.
std::vector<v8::Local<v8::Object>> Values(v8::Isolate* isolate) const {
std::vector<v8::Local<v8::Object>> keys;
keys.reserve(map_.size());
std::vector<v8::Local<v8::Object>> values;
values.reserve(map_.size());
for (const auto& it : map_)
keys.emplace_back(v8::Local<v8::Object>::New(isolate, it.second.second));
return keys;
values.emplace_back(
v8::Local<v8::Object>::New(isolate, it.second.second));
return values;
}
// Remove object with |key| in the WeakMap.
@@ -75,6 +64,12 @@ class KeyWeakMap {
}
private:
// Records the key and self, used by SetWeak.
struct KeyObject {
K key;
raw_ptr<KeyWeakMap> self;
};
static void OnObjectGC(
const v8::WeakCallbackInfo<typename KeyWeakMap<K>::KeyObject>& data) {
KeyWeakMap<K>::KeyObject* key_object = data.GetParameter();

View File

@@ -942,6 +942,10 @@ void OnNodePreload(node::Environment* env,
if (dict.Get("versions", &versions)) {
versions.SetReadOnly(ELECTRON_PROJECT_NAME, ELECTRON_VERSION_STRING);
versions.SetReadOnly("chrome", CHROME_VERSION_STRING);
#if BUILDFLAG(HAS_VENDOR_VERSION)
versions.SetReadOnly(BUILDFLAG(VENDOR_VERSION_NAME),
BUILDFLAG(VENDOR_VERSION_VALUE));
#endif
}
// Execute lib/node/init.ts.

View File

@@ -4164,6 +4164,68 @@ describe('BrowserWindow module', () => {
});
});
describe('BrowserWindow.isOccluded()', () => {
afterEach(closeAllWindows);
it('returns false for a visible window', async () => {
const w = new BrowserWindow({ show: false });
const shown = once(w, 'show');
w.show();
await shown;
expect(w.isOccluded()).to.be.false('window is occluded');
});
it('returns false when the window is only partially obscured', async () => {
const w1 = new BrowserWindow({ x: 250, y: 250, width: 400, height: 400 });
const w2 = new BrowserWindow({ show: false, x: 200, y: 200, width: 500, height: 500 });
const focused = once(w2, 'focus');
w2.show();
await focused;
await setTimeout(2000);
console.log(w1.getBounds(), w2.getBounds());
expect(w1.isOccluded()).to.be.true('window is not occluded');
const pos = w2.getPosition();
const move = once(w2, 'move');
w2.setPosition(pos[0] - 100, pos[1]);
await move;
await setTimeout(2000);
console.log(w1.getBounds(), w2.getBounds());
expect(w1.isOccluded()).to.be.false('window is occluded');
});
// FIXME: this test fails on Linux CI due to windowing issues.
ifit(process.platform !== 'linux')('returns false for a visible window covered by a transparent window', async () => {
const w1 = new BrowserWindow({ width: 200, height: 200 });
const w2 = new BrowserWindow({ show: false, transparent: true, frame: false });
const focused = once(w2, 'focus');
w2.show();
await focused;
await setTimeout(1000);
expect(w1.isOccluded()).to.be.false('window is occluded');
});
it('returns true for an obscured window', async () => {
const w1 = new BrowserWindow({ x: 200, y: 200, width: 200, height: 200 });
const w2 = new BrowserWindow({ show: false, x: 100, y: 100, width: 800, height: 800 });
const focused = once(w2, 'focus');
w2.show();
await focused;
await setTimeout(2000);
console.log(w1.getBounds(), w2.getBounds());
expect(w1.isOccluded()).to.be.true('visible window');
});
});
// TODO(codebytere): figure out how to make these pass in CI on Windows.
ifdescribe(process.platform !== 'win32')('document.visibilityState/hidden', () => {
afterEach(closeAllWindows);

View File

@@ -345,6 +345,59 @@ describe('ipc module', () => {
}})()`);
});
});
describe('when context destroyed', () => {
it('does not crash', async () => {
let count = 0;
const server = http.createServer((req, res) => {
switch (req.url) {
case '/index.html':
res.setHeader('content-type', 'text/html');
res.statusCode = 200;
count = count + 1;
res.end(`
<title>Hello${count}</title>
<script>
var sharedWorker = new SharedWorker('worker.js');
sharedWorker.port.addEventListener('close', function(event) {
console.log('close event', event.data);
});
</script>`);
break;
case '/worker.js':
res.setHeader('content-type', 'application/javascript; charset=UTF-8');
res.statusCode = 200;
res.end(`
self.addEventListener('connect', function(event) {
var port = event.ports[0];
port.addEventListener('message', function(event) {
console.log('Message from main:', event.data);
port.postMessage('Hello from SharedWorker!');
});
});`);
break;
default:
throw new Error(`unsupported endpoint: ${req.url}`);
}
});
const { port } = await listen(server);
defer(() => {
server.close();
});
const w = new BrowserWindow({ show: false });
await w.loadURL(`http://localhost:${port}/index.html`);
expect(w.webContents.getTitle()).to.equal('Hello1');
// Before the fix, it would crash if reloaded, but now it doesn't
await w.loadURL(`http://localhost:${port}/index.html`);
expect(w.webContents.getTitle()).to.equal('Hello2');
// const crashEvent = emittedOnce(w.webContents, 'render-process-gone');
// await crashEvent;
});
});
});
describe('MessageChannelMain', () => {

View File

@@ -519,6 +519,10 @@ describe('webContents module', () => {
await expect(w.loadURL('file:non-existent')).to.eventually.be.rejected();
await expect(w.loadURL('file:non-existent')).to.eventually.be.rejected();
});
it('invalid URL load rejects', async () => {
await expect(w.loadURL('invalidURL')).to.eventually.be.rejected();
});
});
describe('getFocusedWebContents() API', () => {

View File

@@ -1528,7 +1528,7 @@ describe('asar package', function () {
originalFs.createReadStream(path.join(asarDir, 'a.asar'));
});
itremote('can recursively delete a directory with an asar file in itremote', () => {
itremote('can recursively delete a directory with an asar file in itremote using rmdirSync', () => {
const deleteDir = path.join(asarDir, 'deleteme');
fs.mkdirSync(deleteDir);
@@ -1538,6 +1538,16 @@ describe('asar package', function () {
expect(fs.existsSync(deleteDir)).to.be.false();
});
itremote('can recursively delete a directory with an asar file in itremote using promises.rmdir', async () => {
const deleteDir = path.join(asarDir, 'deleteme');
fs.mkdirSync(deleteDir);
const originalFs = require('original-fs');
await originalFs.promises.rmdir(deleteDir, { recursive: true });
expect(fs.existsSync(deleteDir)).to.be.false();
});
itremote('has the same APIs as fs', function () {
expect(Object.keys(require('node:fs'))).to.deep.equal(Object.keys(require('original-fs')));
expect(Object.keys(require('node:fs').promises)).to.deep.equal(Object.keys(require('original-fs').promises));