diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 49ae2ccc9e679..e1b801e28d07d 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -19.0.0-nightly.20220308 \ No newline at end of file +19.0.0-nightly.20220318 \ No newline at end of file diff --git a/build/profile_toolchain.py b/build/profile_toolchain.py index d8874dded572b..4251315e0a16a 100755 --- a/build/profile_toolchain.py +++ b/build/profile_toolchain.py @@ -1,9 +1,12 @@ -from __future__ import with_statement +from __future__ import unicode_literals + import contextlib import sys import os import optparse import json +import re +import subprocess sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__))) @@ -33,36 +36,56 @@ def calculate_hash(root): return CalculateHash('.', None) def windows_installed_software(): - import win32com.client - strComputer = "." - objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator") - objSWbemServices = objWMIService.ConnectServer(strComputer, "root\cimv2") - colItems = objSWbemServices.ExecQuery("Select * from Win32_Product") - items = [] - - for objItem in colItems: - item = {} - if objItem.Caption: - item['caption'] = objItem.Caption - if objItem.Caption: - item['description'] = objItem.Description - if objItem.InstallDate: - item['install_date'] = objItem.InstallDate - if objItem.InstallDate2: - item['install_date_2'] = objItem.InstallDate2 - if objItem.InstallLocation: - item['install_location'] = objItem.InstallLocation - if objItem.Name: - item['name'] = objItem.Name - if objItem.SKUNumber: - item['sku_number'] = objItem.SKUNumber - if objItem.Vendor: - item['vendor'] = objItem.Vendor - if objItem.Version: - item['version'] = objItem.Version - items.append(item) - - return items + powershell_command = [ + "Get-CimInstance", + "-Namespace", + "root\cimv2", + "-Class", + "Win32_product", + "|", + "Select", + "vendor,", + "description,", + "@{l='install_location';e='InstallLocation'},", + "@{l='install_date';e='InstallDate'},", + "@{l='install_date_2';e='InstallDate2'},", + "caption,", + "version,", + "name,", + "@{l='sku_number';e='SKUNumber'}", + "|", + "ConvertTo-Json", + ] + + proc = subprocess.Popen( + ["powershell.exe", "-Command", "-"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8")) + + if proc.returncode != 0: + raise RuntimeError("Failed to get list of installed software") + + # On AppVeyor there's other output related to PSReadline, + # so grab only the JSON output and ignore everything else + json_match = re.match( + r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL + ) + + if not json_match: + raise RuntimeError( + "Couldn't find JSON output for list of installed software" + ) + + # Filter out missing keys + return list( + map( + lambda info: {k: info[k] for k in info if info[k]}, + json.loads(json_match.group(1)), + ) + ) def windows_profile(): @@ -89,7 +112,7 @@ def windows_profile(): def main(options): if sys.platform == 'win32': - with open(options.output_json, 'wb') as f: + with open(options.output_json, 'w') as f: json.dump(windows_profile(), f) else: raise OSError("Unsupported OS") diff --git a/docs/api/app.md b/docs/api/app.md index 60eb2ee7785c2..b8c4780b22853 100755 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -714,7 +714,7 @@ Overrides the current application's name. ### `app.getLocale()` Returns `string` - The current application locale, fetched using Chromium's `l10n_util` library. -Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/master:ui/base/l10n/l10n_util.cc). +Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc). To set the locale, you'll want to use a command line switch at app startup, which may be found [here](command-line-switches.md). @@ -1093,7 +1093,7 @@ Activation policy types: Imports the certificate in pkcs12 format into the platform certificate store. `callback` is called with the `result` of import operation, a value of `0` -indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). +indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). ### `app.configureHostResolver(options)` diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index bc407ede48021..768d27284104e 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -146,7 +146,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `useContentSize` boolean (optional) - The `width` and `height` would be used as web page's size, which means the actual window's size will include window frame's size and be slightly larger. Default is `false`. - * `center` boolean (optional) - Show window in the center of the screen. + * `center` boolean (optional) - Show window in the center of the screen. Default is `false`. * `minWidth` Integer (optional) - Window's minimum width. Default is `0`. * `minHeight` Integer (optional) - Window's minimum height. Default is `0`. * `maxWidth` Integer (optional) - Window's maximum width. Default is no limit. diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 12f1ce1157e5b..81410a281816f 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -185,7 +185,7 @@ the first write will throw an error. If the passed value is not a `string`, its Certain headers are restricted from being set by apps. These headers are listed below. More information on restricted headers can be found in -[Chromium's header utils](https://source.chromium.org/chromium/chromium/src/+/master:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). +[Chromium's header utils](https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). * `Content-Length` * `Host` diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index f395379c063fa..d628b0549c1dd 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -274,8 +274,8 @@ By default inspector websocket url is available in stderr and under /json/list e [ready]: app.md#event-ready [play-silent-audio]: https://github.com/atom/atom/pull/9485/files [debugging-main-process]: ../tutorial/debugging-main-process.md -[logging]: https://source.chromium.org/chromium/chromium/src/+/master:base/logging.h +[logging]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h [node-cli]: https://nodejs.org/api/cli.html [play-silent-audio]: https://github.com/atom/atom/pull/9485/files [ready]: app.md#event-ready -[severities]: https://source.chromium.org/chromium/chromium/src/+/master:base/logging.h?q=logging::LogSeverity&ss=chromium +[severities]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h?q=logging::LogSeverity&ss=chromium diff --git a/docs/api/content-tracing.md b/docs/api/content-tracing.md index 91e3ca43a2560..ec8e3f7979701 100644 --- a/docs/api/content-tracing.md +++ b/docs/api/content-tracing.md @@ -36,7 +36,7 @@ Returns `Promise` - resolves with an array of category groups once all Get a set of category groups. The category groups can change as new code paths are reached. See also the [list of built-in tracing -categories](https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/builtin_categories.h). +categories](https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h). > **NOTE:** Electron adds a non-default tracing category called `"electron"`. > This category can be used to capture Electron-specific tracing events. diff --git a/docs/api/process.md b/docs/api/process.md index 194619e01c0ab..4573899912997 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -178,7 +178,6 @@ Returns an object with V8 heap statistics. Note that all statistics are reported Returns `Object`: * `allocated` Integer - Size of all allocated objects in Kilobytes. -* `marked` Integer - Size of all marked objects in Kilobytes. * `total` Integer - Total allocated space in Kilobytes. Returns an object with Blink memory information. diff --git a/docs/api/session.md b/docs/api/session.md index 2517fd178d2e0..5dc29aba9b6d7 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -567,7 +567,7 @@ the original network configuration. * `errorCode` Integer - Error code. * `callback` Function * `verificationResult` Integer - Value can be one of certificate error codes - from [here](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). + from [here](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). Apart from the certificate error codes, the following special codes can be used. * `0` - Indicates success and disables Certificate Transparency verification. * `-2` - Indicates failure. @@ -868,6 +868,20 @@ this session just before normal `preload` scripts run. Returns `string[]` an array of paths to preload scripts that have been registered. +#### `ses.setCodeCachePath(path)` + +* `path` String - Absolute path to store the v8 generated JS code cache from the renderer. + +Sets the directory to store the generated JS [code cache](https://v8.dev/blog/code-caching-for-devs) for this session. The directory is not required to be created by the user before this call, the runtime will create if it does not exist otherwise will use the existing directory. If directory cannot be created, then code cache will not be used and all operations related to code cache will fail silently inside the runtime. By default, the directory will be `Code Cache` under the +respective user data folder. + +#### `ses.clearCodeCaches(options)` + +* `options` Object + * `urls` String[] (optional) - An array of url corresponding to the resource whose generated code cache needs to be removed. If the list is empty then all entries in the cache directory will be removed. + +Returns `Promise` - resolves when the code cache clear operation is complete. + #### `ses.setSpellCheckerEnabled(enable)` * `enable` boolean diff --git a/docs/api/structures/protocol-response.md b/docs/api/structures/protocol-response.md index a20873ebb3b46..21a863240fabb 100644 --- a/docs/api/structures/protocol-response.md +++ b/docs/api/structures/protocol-response.md @@ -31,4 +31,4 @@ * `uploadData` [ProtocolResponseUploadData](protocol-response-upload-data.md) (optional) - The data used as upload data. This is only used for URL responses when `method` is `"POST"`. -[net-error]: https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h +[net-error]: https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h diff --git a/docs/api/structures/trace-config.md b/docs/api/structures/trace-config.md index d5b3795f228fd..4160b7121ca57 100644 --- a/docs/api/structures/trace-config.md +++ b/docs/api/structures/trace-config.md @@ -8,7 +8,7 @@ * `enable_argument_filter` boolean (optional) - if true, filter event data according to a specific list of events that have been manually vetted to not include any PII. See [the implementation in - Chromium][trace_event_args_whitelist.cc] for specifics. + Chromium][trace_event_args_allowlist.cc] for specifics. * `included_categories` string[] (optional) - a list of tracing categories to include. Can include glob-like patterns using `*` at the end of the category name. See [tracing categories][] for the list of categories. @@ -45,7 +45,7 @@ An example TraceConfig that roughly matches what Chrome DevTools records: } ``` -[tracing categories]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/builtin_categories.h -[memory-infra docs]: https://chromium.googlesource.com/chromium/src/+/master/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way -[trace_event_args_whitelist.cc]: https://chromium.googlesource.com/chromium/src/+/master/services/tracing/public/cpp/trace_event_args_whitelist.cc +[tracing categories]: https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h +[memory-infra docs]: https://chromium.googlesource.com/chromium/src/+/main/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way +[trace_event_args_allowlist.cc]: https://chromium.googlesource.com/chromium/src/+/main/services/tracing/public/cpp/trace_event_args_allowlist.cc [histogram]: https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index d4a1233c5976a..bdfa225332567 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -35,7 +35,7 @@ for all windows, webviews, opened devtools, and devtools extension background pa ### `webContents.getFocusedWebContents()` -Returns `WebContents` - The web contents that is focused in this application, otherwise +Returns `WebContents` | null - The web contents that is focused in this application, otherwise returns `null`. ### `webContents.fromId(id)` @@ -92,7 +92,7 @@ Returns: * `frameRoutingId` Integer This event is like `did-finish-load` but emitted when the load failed. -The full list of error codes and their meaning is available [here](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). +The full list of error codes and their meaning is available [here](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). #### Event: 'did-fail-provisional-load' @@ -820,9 +820,6 @@ This event can be used to configure `webPreferences` for the `webContents` of a `` before it's loaded, and provides the ability to set settings that can't be set via `` attributes. -**Note:** The specified `preload` script option will appear as `preloadURL` -(not `preload`) in the `webPreferences` object emitted with this event. - #### Event: 'did-attach-webview' Returns: diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 9384fe2c98613..b59d98c54cb60 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -110,9 +110,11 @@ webFrame.setSpellCheckProvider('en-US', { }) ``` -### `webFrame.insertCSS(css)` +#### `webFrame.insertCSS(css[, options])` -* `css` string - CSS source code. +* `css` string +* `options` Object (optional) + * `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'. Returns `string` - A key for the inserted CSS that can later be used to remove the CSS via `webFrame.removeInsertedCSS(key)`. diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index fd90e8b5d5660..c2eab361cfd94 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -158,9 +158,6 @@ When the guest page doesn't have node integration this script will still have access to all Node APIs, but global objects injected by Node will be deleted after this script has finished executing. -**Note:** This option will appear as `preloadURL` (not `preload`) in -the `webPreferences` specified to the `will-attach-webview` event. - ### `httpreferrer` ```html diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index e603146d0372e..6d561f87bd75e 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -12,6 +12,25 @@ This document uses the following convention to categorize breaking changes: * **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. * **Removed:** An API or feature was removed, and is no longer supported by Electron. +## Planned Breaking API Changes (20.0) + +### Default Changed: renderers without `nodeIntegration: true` are sandboxed by default + +Previously, renderers that specified a preload script defaulted to being +unsandboxed. This meant that by default, preload scripts had access to Node.js. +In Electron 20, this default has changed. Beginning in Electron 20, renderers +will be sandboxed by default, unless `nodeIntegration: true` or `sandbox: false` +is specified. + +If your preload scripts do not depend on Node, no action is needed. If your +preload scripts _do_ depend on Node, either refactor them to remove Node usage +from the renderer, or explicitly specify `sandbox: false` for the relevant +renderers. + +## Planned Breaking API Changes (19.0) + +*None (yet)* + ## Planned Breaking API Changes (18.0) ### Removed: `nativeWindowOpen` diff --git a/docs/development/build-instructions-gn.md b/docs/development/build-instructions-gn.md index 70b5c48ed857c..cd955743df3b9 100644 --- a/docs/development/build-instructions-gn.md +++ b/docs/development/build-instructions-gn.md @@ -196,12 +196,12 @@ If you test other combinations and find them to work, please update this documen See the GN reference for allowable values of [`target_os`][target_os values] and [`target_cpu`][target_cpu values]. -[target_os values]: https://gn.googlesource.com/gn/+/master/docs/reference.md#built_in-predefined-variables-target_os_the-desired-operating-system-for-the-build-possible-values -[target_cpu values]: https://gn.googlesource.com/gn/+/master/docs/reference.md#built_in-predefined-variables-target_cpu_the-desired-cpu-architecture-for-the-build-possible-values +[target_os values]: https://gn.googlesource.com/gn/+/main/docs/reference.md#built_in-predefined-variables-target_os_the-desired-operating-system-for-the-build-possible-values +[target_cpu values]: https://gn.googlesource.com/gn/+/main/docs/reference.md#built_in-predefined-variables-target_cpu_the-desired-cpu-architecture-for-the-build-possible-values #### Windows on Arm (experimental) -To cross-compile for Windows on Arm, [follow Chromium's guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/master/docs/windows_build_instructions.md#Visual-Studio) to get the necessary dependencies, SDK and libraries, then build with `ELECTRON_BUILDING_WOA=1` in your environment before running `gclient sync`. +To cross-compile for Windows on Arm, [follow Chromium's guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/windows_build_instructions.md#Visual-Studio) to get the necessary dependencies, SDK and libraries, then build with `ELECTRON_BUILDING_WOA=1` in your environment before running `gclient sync`. ```bat set ELECTRON_BUILDING_WOA=1 diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 49e436197d851..b827a713784b2 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -9,7 +9,7 @@ Follow the guidelines below for building **Electron itself** on Windows, for the * Windows 10 / Server 2012 R2 or higher * Visual Studio 2017 15.7.2 or higher - [download VS 2019 Community Edition for free](https://www.visualstudio.com/vs/) - * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio + * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio components are required. * If your Visual Studio is installed in a directory other than the default, you'll need to set a few environment variables to point the toolchains to your installation path. diff --git a/docs/fiddles/ipc/pattern-3/renderer.js b/docs/fiddles/ipc/pattern-3/renderer.js index 3b184add08ba2..04fd4bca890a3 100644 --- a/docs/fiddles/ipc/pattern-3/renderer.js +++ b/docs/fiddles/ipc/pattern-3/renderer.js @@ -4,5 +4,5 @@ window.electronAPI.handleCounter((event, value) => { const oldValue = Number(counter.innerText) const newValue = oldValue + value counter.innerText = newValue - event.reply('counter-value', newValue) + event.sender.send('counter-value', newValue) }) diff --git a/docs/glossary.md b/docs/glossary.md index a4bfa2a96071f..893c598c52b80 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -91,7 +91,7 @@ An IPC system for communicating intra- or inter-process, and that's important because Chrome is keen on being able to split its work into separate processes or not, depending on memory pressures etc. -See https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md +See https://chromium.googlesource.com/chromium/src/+/main/mojo/README.md See also: [IPC](#ipc) diff --git a/docs/images/message-notification-renderer.png b/docs/images/message-notification-renderer.png deleted file mode 100644 index 87c8a876a2b4f..0000000000000 Binary files a/docs/images/message-notification-renderer.png and /dev/null differ diff --git a/docs/images/online-event-detection.png b/docs/images/online-event-detection.png deleted file mode 100644 index 4f16489a7271c..0000000000000 Binary files a/docs/images/online-event-detection.png and /dev/null differ diff --git a/docs/images/tutorial-release-schedule.svg b/docs/images/tutorial-release-schedule.svg deleted file mode 100644 index 6fa6539167894..0000000000000 --- a/docs/images/tutorial-release-schedule.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - master - - - - - 2.0 - - v2.0.0-beta0 - - v2.0.0 - - - - - 2.1 - - v2.1.0-beta0 - - v2.1.0-beta1 - - v2.1.0 - - - - - 3.0 - - v3.0.0-beta0 - - v3.0.0 - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - - feature - - - - feature - - - - feature - - - - - chromiumupdate - - - - ~1 week - - - - ~1 week - - - - ~1 week - - - - \ No newline at end of file diff --git a/docs/tutorial/ipc.md b/docs/tutorial/ipc.md index 0189e0db7e806..5d3fc2ffec29b 100644 --- a/docs/tutorial/ipc.md +++ b/docs/tutorial/ipc.md @@ -379,7 +379,7 @@ module that uses the `webContents.send` API to send an IPC message from the main target renderer. ```javascript {11-26} title='main.js (Main Process)' -const {app, BrowserWindow, Menu} = require('electron') +const {app, BrowserWindow, Menu, ipcMain} = require('electron') const path = require('path') function createWindow () { @@ -519,7 +519,7 @@ window.electronAPI.onUpdateCounter((event, value) => { const oldValue = Number(counter.innerText) const newValue = oldValue + value counter.innerText = newValue - event.reply('counter-value', newValue) + event.sender.send('counter-value', newValue) }) ``` diff --git a/docs/tutorial/process-model.md b/docs/tutorial/process-model.md index 6b7737ec50b84..bfbb941486f55 100644 --- a/docs/tutorial/process-model.md +++ b/docs/tutorial/process-model.md @@ -40,7 +40,7 @@ to `require` modules and use all of Node.js APIs. ### Window management -The main process' primary purpose is to create and manage application windows with the +The primary purpose of the main process is to create and manage application windows with the [`BrowserWindow`][browser-window] module. Each instance of the `BrowserWindow` class creates an application window that loads diff --git a/docs/tutorial/sandbox.md b/docs/tutorial/sandbox.md index 0eb955c5da75f..db71727efb6cc 100644 --- a/docs/tutorial/sandbox.md +++ b/docs/tutorial/sandbox.md @@ -157,7 +157,7 @@ versions of Electron, we do not make a guarantee that every fix will be backported. Your best chance at staying secure is to be on the latest stable version of Electron. -[sandbox]: https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md +[sandbox]: https://chromium.googlesource.com/chromium/src/+/main/docs/design/sandbox.md [issue-28466]: https://github.com/electron/electron/issues/28466 [browser-window]: ../api/browser-window.md [enable-sandbox]: ../api/app.md#appenablesandbox diff --git a/docs/tutorial/security.md b/docs/tutorial/security.md index 688dda5a68961..d267a61a47d00 100644 --- a/docs/tutorial/security.md +++ b/docs/tutorial/security.md @@ -562,7 +562,6 @@ app.on('web-contents-created', (event, contents) => { contents.on('will-attach-webview', (event, webPreferences, params) => { // Strip away preload scripts if unused or verify their location is legitimate delete webPreferences.preload - delete webPreferences.preloadURL // Disable Node.js integration webPreferences.nodeIntegration = false diff --git a/filenames.gni b/filenames.gni index 8e6da3eb657f4..eae36f790483d 100644 --- a/filenames.gni +++ b/filenames.gni @@ -350,6 +350,8 @@ filenames = { "shell/browser/child_web_contents_tracker.h", "shell/browser/cookie_change_notifier.cc", "shell/browser/cookie_change_notifier.h", + "shell/browser/electron_api_ipc_handler_impl.cc", + "shell/browser/electron_api_ipc_handler_impl.h", "shell/browser/electron_autofill_driver.cc", "shell/browser/electron_autofill_driver.h", "shell/browser/electron_autofill_driver_factory.cc", @@ -358,8 +360,6 @@ filenames = { "shell/browser/electron_browser_client.h", "shell/browser/electron_browser_context.cc", "shell/browser/electron_browser_context.h", - "shell/browser/electron_browser_handler_impl.cc", - "shell/browser/electron_browser_handler_impl.h", "shell/browser/electron_browser_main_parts.cc", "shell/browser/electron_browser_main_parts.h", "shell/browser/electron_download_manager_delegate.cc", @@ -376,6 +376,8 @@ filenames = { "shell/browser/electron_quota_permission_context.h", "shell/browser/electron_speech_recognition_manager_delegate.cc", "shell/browser/electron_speech_recognition_manager_delegate.h", + "shell/browser/electron_web_contents_utility_handler_impl.cc", + "shell/browser/electron_web_contents_utility_handler_impl.h", "shell/browser/electron_web_ui_controller_factory.cc", "shell/browser/electron_web_ui_controller_factory.h", "shell/browser/event_emitter_mixin.cc", diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index 4e2cd4acbda74..a8abf03fa6360 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -1,4 +1,4 @@ -import { app, ipcMain, session, webFrameMain } from 'electron/main'; +import { app, ipcMain, session, webFrameMain, deprecate } from 'electron/main'; import type { BrowserWindowConstructorOptions, LoadURLOptions } from 'electron/main'; import * as url from 'url'; @@ -570,6 +570,10 @@ const loggingEnabled = () => { // Add JavaScript wrappers for WebContents class. WebContents.prototype._init = function () { + const prefs = this.getLastWebPreferences() || {}; + if (!prefs.nodeIntegration && prefs.preload != null && prefs.sandbox == null) { + deprecate.log('The default sandbox option for windows without nodeIntegration is changing. Presently, by default, when a window has a preload script, it defaults to being unsandboxed. In Electron 20, this default will be changing, and all windows that have nodeIntegration: false (which is the default) will be sandboxed by default. If your preload script doesn\'t use Node, no action is needed. If your preload script does use Node, either refactor it to move Node usage to the main process, or specify sandbox: false in your WebPreferences.'); + } // Read off the ID at construction time, so that it's accessible even after // the underlying C++ WebContents is destroyed. const id = this.id; diff --git a/lib/browser/guest-view-manager.ts b/lib/browser/guest-view-manager.ts index c973586e807d5..c9c4585de28e4 100644 --- a/lib/browser/guest-view-manager.ts +++ b/lib/browser/guest-view-manager.ts @@ -15,6 +15,7 @@ interface GuestInstance { const webViewManager = process._linkedBinding('electron_browser_web_view_manager'); const eventBinding = process._linkedBinding('electron_browser_event'); +const netBinding = process._linkedBinding('electron_browser_net'); const supportedWebViewEvents = Object.keys(webViewEvents); @@ -49,7 +50,7 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record additional_data, + const NotificationAckCallback& ack_callback)>; - #if defined(OS_WIN) + #if BUILDFLAG(IS_WIN) ProcessSingleton(const std::string& program_name, const base::FilePath& user_data_dir, + const base::span additional_data, @@ -96,7 +96,7 @@ index 8f94cc300b58e8a94b6ca155aa3cf370bcb948d8..4340376f323d24e5e2c5897a81c6a9eb // Return true if the given pid is one of our child processes. // Assumes that the current pid is the root of all pids of the current diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc -index 47e60bfd8239d4a2e292b835c49132bdbb751555..9861a884a15e79b36833e6df58897141acdc6718 100644 +index 7d3a441bdb64268ed5fbfa7bf589fb35a2fd1b75..b23c16fde275fdba559abb1f30e42f65ddbfc332 100644 --- a/chrome/browser/process_singleton_posix.cc +++ b/chrome/browser/process_singleton_posix.cc @@ -148,7 +148,7 @@ const char kACKToken[] = "ACK"; diff --git a/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch b/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch index d2675bfa80b29..231ad6fe4f48e 100644 --- a/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch +++ b/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch @@ -226,10 +226,10 @@ index a480befb5d8db36e7e281d5033aeef0bea83d220..4e54acc897d08c87bccc3b44f68634e2 diff --git a/components/viz/service/display_embedder/software_output_device_proxy.cc b/components/viz/service/display_embedder/software_output_device_proxy.cc new file mode 100644 -index 0000000000000000000000000000000000000000..4efea02f80f8b6818291321a7c63f0f4815a5b98 +index 0000000000000000000000000000000000000000..88aba74877a6490e08e357266b1ce8461b5b6dff --- /dev/null +++ b/components/viz/service/display_embedder/software_output_device_proxy.cc -@@ -0,0 +1,157 @@ +@@ -0,0 +1,158 @@ +// Copyright 2014 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 file. @@ -239,6 +239,7 @@ index 0000000000000000000000000000000000000000..4efea02f80f8b6818291321a7c63f0f4 +#include "base/memory/unsafe_shared_memory_region.h" +#include "base/threading/thread_checker.h" +#include "base/trace_event/trace_event.h" ++#include "build/build_config.h" +#include "components/viz/common/resources/resource_sizes.h" +#include "components/viz/service/display_embedder/output_device_backing.h" +#include "mojo/public/cpp/system/platform_handle.h" @@ -247,7 +248,7 @@ index 0000000000000000000000000000000000000000..4efea02f80f8b6818291321a7c63f0f4 +#include "third_party/skia/include/core/SkCanvas.h" +#include "ui/gfx/skia_util.h" + -+#if defined(OS_WIN) ++#if BUILDFLAG(IS_WIN) +#include "skia/ext/skia_utils_win.h" +#include "ui/gfx/gdi_util.h" +#include "ui/gfx/win/hwnd_util.h" @@ -389,10 +390,10 @@ index 0000000000000000000000000000000000000000..4efea02f80f8b6818291321a7c63f0f4 +} // namespace viz diff --git a/components/viz/service/display_embedder/software_output_device_proxy.h b/components/viz/service/display_embedder/software_output_device_proxy.h new file mode 100644 -index 0000000000000000000000000000000000000000..fbc517e164d9bf33256c1ecbe86e31744375097e +index 0000000000000000000000000000000000000000..a80258d6165e45a3c3d2b551158ff7d2a5778a7c --- /dev/null +++ b/components/viz/service/display_embedder/software_output_device_proxy.h -@@ -0,0 +1,92 @@ +@@ -0,0 +1,93 @@ +// Copyright 2014 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 file. @@ -400,20 +401,21 @@ index 0000000000000000000000000000000000000000..fbc517e164d9bf33256c1ecbe86e3174 +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ + -+#if defined(OS_WIN) -+#include -+#endif -+ +#include + +#include "base/memory/shared_memory_mapping.h" +#include "base/threading/thread_checker.h" ++#include "build/build_config.h" +#include "components/viz/host/host_display_client.h" +#include "components/viz/service/display/software_output_device.h" +#include "components/viz/service/viz_service_export.h" +#include "services/viz/privileged/mojom/compositing/display_private.mojom.h" +#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h" + ++#if BUILDFLAG(IS_WIN) ++#include ++#endif ++ +namespace viz { + +// Shared base class for SoftwareOutputDevice implementations. diff --git a/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch b/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch index 2986f58de269f..7460a09ea3beb 100644 --- a/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch +++ b/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch @@ -59,7 +59,7 @@ index ad366d0fd4c3a637d75a102ab56984f0d01bfc04..d63eb133fd4bab1ea309bb8c742acf88 // true if register successfully, or false if 1) the specificied |accelerator| // has been registered by another caller or other native applications, or diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc -index ac923f436cbdd6ded0629da4e4c659d94258e55b..7e603dd5bad2a60b1bd7d9df569a10e838d797bc 100644 +index ac923f436cbdd6ded0629da4e4c659d94258e55b..43f9531075bcef87de8e60f24071f49fe4cd0891 100644 --- a/content/browser/media/media_keys_listener_manager_impl.cc +++ b/content/browser/media/media_keys_listener_manager_impl.cc @@ -55,7 +55,12 @@ bool MediaKeysListenerManagerImpl::StartWatchingMediaKey( @@ -68,9 +68,9 @@ index ac923f436cbdd6ded0629da4e4c659d94258e55b..7e603dd5bad2a60b1bd7d9df569a10e8 // Tell the underlying MediaKeysListener to listen for the key. - if (should_start_watching && media_keys_listener_ && + if ( -+#if defined(OS_MAC) ++#if BUILDFLAG(IS_MAC) + !media_key_handling_enabled_ && -+#endif // defined(OS_MAC) ++#endif // BUILDFLAG(IS_MAC) + should_start_watching && + media_keys_listener_ && !media_keys_listener_->StartWatchingMediaKey(key_code)) { diff --git a/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch b/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch new file mode 100644 index 0000000000000..86a3c0fbc97be --- /dev/null +++ b/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: clavin +Date: Fri, 11 Feb 2022 15:05:42 -0700 +Subject: fix: non-client mouse tracking and message bubbling on windows + +It is not known why, but for some reason calling |DefWindowProc| on the parent +window handle causes a WM_NCMOUSELEAVE (non-client mouse exit) message to be +sent to the parent window, even though |TrackMouseEvent| is never called on it. + +This patch also adds some boilerplate for properly tracking non-client mouse +messages in the legacy window handle layer. + +These conditions are regularly hit with WCO-enabled windows on Windows. + +diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc +index 4a894ef70eeb1d8489049aef552c9bae4f24ae62..f5049d730a850f2947023f976b25fb772e42107a 100644 +--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc ++++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc +@@ -288,12 +288,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, + WPARAM w_param, + LPARAM l_param, + BOOL& handled) { +- if (message == WM_MOUSEMOVE) { ++ if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE) { + if (!mouse_tracking_enabled_) { + mouse_tracking_enabled_ = true; + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); +- tme.dwFlags = TME_LEAVE; ++ tme.dwFlags = message == WM_NCMOUSEMOVE ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE; + tme.hwndTrack = hwnd(); + tme.dwHoverTime = 0; + TrackMouseEvent(&tme); +@@ -319,12 +319,11 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, + message, w_param, l_param, &msg_handled); + handled = msg_handled; + // If the parent did not handle non client mouse messages, we call +- // DefWindowProc on the message with the parent window handle. This +- // ensures that WM_SYSCOMMAND is generated for the parent and we are +- // out of the picture. ++ // DefWindowProc on the message. This ensures that WM_SYSCOMMAND is ++ // generated. + if (!handled && + (message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) { +- ret = ::DefWindowProc(GetParent(), message, w_param, l_param); ++ ret = ::DefWindowProc(hwnd(), message, w_param, l_param); + handled = TRUE; + } + } +diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h +index 79dffd981f4d461f30bd3796cfba1457eda3a89d..ae378ce95f90989fd0e74c38b57f5f7dc0a1ee29 100644 +--- a/content/browser/renderer_host/legacy_render_widget_host_win.h ++++ b/content/browser/renderer_host/legacy_render_widget_host_win.h +@@ -105,6 +105,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND + MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest) + MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, + OnMouseRange) ++ MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave) + MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize) + MESSAGE_HANDLER_EX(WM_SIZE, OnSize) + MESSAGE_HANDLER_EX(WM_DESTROY, OnDestroy) diff --git a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch index d4aaf27702eea..d524259dd9428 100644 --- a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch +++ b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch @@ -7,7 +7,7 @@ This adds a callback from the network service that's used to implement session.setCertificateVerifyCallback. diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..ca62a13420aa9c114c00054bbe1215f96285a4e9 100644 +index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..20373c0e86852446569c401c4a993512cb388fc7 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc @@ -126,6 +126,11 @@ @@ -22,12 +22,38 @@ index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..ca62a13420aa9c114c00054bbe1215f9 #if BUILDFLAG(IS_CT_SUPPORTED) #include "components/certificate_transparency/chrome_ct_policy_enforcer.h" #include "components/certificate_transparency/chrome_require_ct_delegate.h" -@@ -433,6 +438,79 @@ bool GetFullDataFilePath( +@@ -433,6 +438,91 @@ bool GetFullDataFilePath( } // namespace +class RemoteCertVerifier : public net::CertVerifier { + public: ++ class Request : public net::CertVerifier::Request { ++ public: ++ Request() {} ++ ~Request() override = default; ++ void OnRemoteResponse( ++ const RequestParams& params, ++ net::CertVerifyResult* verify_result, ++ int error_from_upstream, ++ net::CompletionOnceCallback callback, ++ int error_from_client, ++ const net::CertVerifyResult& verify_result_from_client) { ++ if (error_from_client == net::ERR_ABORTED) { ++ // use the default ++ std::move(callback).Run(error_from_upstream); ++ } else { ++ // use the override ++ verify_result->Reset(); ++ verify_result->verified_cert = verify_result_from_client.verified_cert; ++ std::move(callback).Run(error_from_client); ++ } ++ } ++ base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } ++ private: ++ base::WeakPtrFactory weak_factory_{this}; ++ }; ++ + RemoteCertVerifier(std::unique_ptr upstream): upstream_(std::move(upstream)) { + } + ~RemoteCertVerifier() override = default; @@ -44,20 +70,14 @@ index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..ca62a13420aa9c114c00054bbe1215f9 + int Verify(const RequestParams& params, + net::CertVerifyResult* verify_result, + net::CompletionOnceCallback callback, -+ std::unique_ptr* out_req, ++ std::unique_ptr* out_req, + const net::NetLogWithSource& net_log) override { + out_req->reset(); + + net::CompletionOnceCallback callback2 = base::BindOnce( + &RemoteCertVerifier::OnRequestFinished, base::Unretained(this), -+ params, std::move(callback), verify_result); -+ int result = upstream_->Verify(params, verify_result, -+ std::move(callback2), out_req, net_log); -+ if (result != net::ERR_IO_PENDING) { -+ // Synchronous completion -+ } -+ -+ return result; ++ params, std::move(callback), verify_result, out_req); ++ return upstream_->Verify(params, verify_result, std::move(callback2), out_req, net_log); + } + + @@ -65,35 +85,27 @@ index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..ca62a13420aa9c114c00054bbe1215f9 + upstream_->SetConfig(config); + } + -+ void OnRequestFinished(const RequestParams& params, net::CompletionOnceCallback callback, net::CertVerifyResult* verify_result, int error) { ++ void OnRequestFinished(const RequestParams& params, ++ net::CompletionOnceCallback callback, ++ net::CertVerifyResult* verify_result, ++ std::unique_ptr* out_req, ++ int error) { + if (client_.is_bound()) { ++ // We take a weak pointer to the request because deletion of the request ++ // is what signals cancellation. Thus if the request is cancelled, the ++ // callback won't be called, thus avoiding UAF, because |verify_result| ++ // is freed when the request is cancelled. ++ *out_req = std::make_unique(); ++ base::WeakPtr weak_req = static_cast(out_req->get())->GetWeakPtr(); + client_->Verify(error, *verify_result, params.certificate(), + params.hostname(), params.flags(), params.ocsp_response(), -+ base::BindOnce(&RemoteCertVerifier::OnRemoteResponse, -+ base::Unretained(this), params, verify_result, error, -+ std::move(callback))); ++ base::BindOnce(&Request::OnRemoteResponse, ++ weak_req, params, verify_result, error, std::move(callback))); + } else { + std::move(callback).Run(error); + } + } + -+ void OnRemoteResponse( -+ const RequestParams& params, -+ net::CertVerifyResult* verify_result, -+ int error, -+ net::CompletionOnceCallback callback, -+ int error2, -+ const net::CertVerifyResult& verify_result2) { -+ if (error2 == net::ERR_ABORTED) { -+ // use the default -+ std::move(callback).Run(error); -+ } else { -+ // use the override -+ verify_result->Reset(); -+ verify_result->verified_cert = verify_result2.verified_cert; -+ std::move(callback).Run(error2); -+ } -+ } + private: + std::unique_ptr upstream_; + mojo::Remote client_; @@ -102,7 +114,7 @@ index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..ca62a13420aa9c114c00054bbe1215f9 constexpr uint32_t NetworkContext::kMaxOutstandingRequestsPerProcess; NetworkContext::PendingCertVerify::PendingCertVerify() = default; -@@ -671,6 +749,13 @@ void NetworkContext::SetClient( +@@ -671,6 +761,13 @@ void NetworkContext::SetClient( client_.Bind(std::move(client)); } @@ -116,7 +128,7 @@ index 8ff62f92ed6efdbfc18db53db3c5bb59c1acfe34..ca62a13420aa9c114c00054bbe1215f9 void NetworkContext::CreateURLLoaderFactory( mojo::PendingReceiver receiver, mojom::URLLoaderFactoryParamsPtr params) { -@@ -2226,6 +2311,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( +@@ -2226,6 +2323,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( std::move(cert_verifier)); cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_); #endif // BUILDFLAG(IS_CHROMEOS) diff --git a/patches/chromium/process_singleton.patch b/patches/chromium/process_singleton.patch index 58d5bc201d4af..565c00742ba81 100644 --- a/patches/chromium/process_singleton.patch +++ b/patches/chromium/process_singleton.patch @@ -24,14 +24,14 @@ This patch adds a few changes to the Chromium code: before the browser thread is ready. diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h -index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..8f94cc300b58e8a94b6ca155aa3cf370bcb948d8 100644 +index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..5a64220aaf1309832dc0ad543e353de67fe0a779 100644 --- a/chrome/browser/process_singleton.h +++ b/chrome/browser/process_singleton.h @@ -102,12 +102,19 @@ class ProcessSingleton { base::RepeatingCallback; -+#if defined(OS_WIN) ++#if BUILDFLAG(IS_WIN) + ProcessSingleton(const std::string& program_name, + const base::FilePath& user_data_dir, + bool is_sandboxed, @@ -75,7 +75,7 @@ index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..8f94cc300b58e8a94b6ca155aa3cf370 #if BUILDFLAG(IS_MAC) diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc -index c9f26ea2d2ea16484d416fdce095ec1b8b885991..47e60bfd8239d4a2e292b835c49132bdbb751555 100644 +index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35a2fd1b75 100644 --- a/chrome/browser/process_singleton_posix.cc +++ b/chrome/browser/process_singleton_posix.cc @@ -53,6 +53,7 @@ @@ -129,7 +129,7 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..47e60bfd8239d4a2e292b835c49132bd } +bool IsAppSandboxed() { -+#if defined(OS_MAC) ++#if BUILDFLAG(IS_MAC) + // NB: There is no sane API for this, we have to just guess by + // reading tea leaves + base::FilePath home_dir; @@ -140,7 +140,7 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..47e60bfd8239d4a2e292b835c49132bd + return home_dir.value().find("Library/Containers") != std::string::npos; +#else + return false; -+#endif // defined(OS_MAC) ++#endif // BUILDFLAG(IS_MAC) +} + bool ConnectSocket(ScopedSocket* socket, diff --git a/patches/chromium/remove_incorrect_width_height_adjustments.patch b/patches/chromium/remove_incorrect_width_height_adjustments.patch new file mode 100644 index 0000000000000..4fce52ba6e282 --- /dev/null +++ b/patches/chromium/remove_incorrect_width_height_adjustments.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bruce Dawson +Date: Mon, 28 Feb 2022 19:07:41 +0000 +Subject: Remove incorrect width/height adjustments + +In late 2016 a change which fixed some problems around window sizing +when attaching or detaching additional displays was landed, which fixed +some genuine bugs. Unfortunately it included a subtraction of 1 from the +width and height of the Chrome window. I couldn't find any discussion of +this size adjustment and I think that it was just a misunderstanding of +how window rectangles work (inclusive versus exclusive extents). + +This size adjustment causes non-maximized Chrome windows to shrink every +time a monitor is added or removed. The problematic commit was found +by the bug-filer through a bisect of more than four years of Chrome +history - I'm just landing the fix that they suggested. + +Bug: 1300415 +Change-Id: Ief124f584a91aa9cc3f10704b0cc1e83356dea5b +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3492658 +Reviewed-by: Allen Bauer +Commit-Queue: Bruce Dawson +Cr-Commit-Position: refs/heads/main@{#975872} + +diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc +index 264a9109e42c23e9be6bf7269b3cfee2634b61e4..86f06d2a2c9588a2210a9f78f47e73f1b7c5e329 100644 +--- a/ui/views/win/hwnd_message_handler.cc ++++ b/ui/views/win/hwnd_message_handler.cc +@@ -2834,8 +2834,8 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { + // (Win+Shift+Arrows). See crbug.com/656001. + window_rect.left = window_pos->x; + window_rect.top = window_pos->y; +- window_rect.right = window_pos->x + window_pos->cx - 1; +- window_rect.bottom = window_pos->y + window_pos->cy - 1; ++ window_rect.right = window_pos->x + window_pos->cx; ++ window_rect.bottom = window_pos->y + window_pos->cy; + } + + HMONITOR monitor; diff --git a/patches/node/.patches b/patches/node/.patches index 0346bf4bde829..7a36ac8cbf7a6 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -32,3 +32,4 @@ darwin_remove_eprototype_error_workaround_3405.patch darwin_translate_eprototype_to_econnreset_3413.patch darwin_bump_minimum_supported_version_to_10_15_3406.patch fix_failing_node_js_test_on_outdated.patch +be_compatible_with_cppgc.patch diff --git a/patches/node/be_compatible_with_cppgc.patch b/patches/node/be_compatible_with_cppgc.patch new file mode 100644 index 0000000000000..3bbc3ce0bde16 --- /dev/null +++ b/patches/node/be_compatible_with_cppgc.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Rose +Date: Fri, 11 Mar 2022 11:17:29 -0800 +Subject: be compatible with cppgc + +This fixes a crash that happens sporadically when Node is used in the same V8 +Isolate as Blink. For example: + +# +# Fatal error in ../../v8/src/objects/js-objects-inl.h, line 306 +# Debug check failed: static_cast(index) < static_cast(GetEmbedderFieldCount()) (1 vs. 1). +# +# +# +#FailureMessage Object: 0x7ffee46fd1c0 +0 Electron Framework 0x00000001181c78d9 base::debug::CollectStackTrace(void**, unsigned long) + 9 +1 Electron Framework 0x00000001180ea633 base::debug::StackTrace::StackTrace() + 19 +2 Electron Framework 0x000000011a04decd gin::(anonymous namespace)::PrintStackTrace() + 45 +3 Electron Framework 0x0000000119a9b416 V8_Fatal(char const*, int, char const*, ...) + 326 +4 Electron Framework 0x0000000119a9aeb5 v8::base::(anonymous namespace)::DefaultDcheckHandler(char const*, int, char const*) + 21 +5 Electron Framework 0x000000011530763f v8::internal::JSObject::GetEmbedderFieldOffset(int) + 207 +6 Electron Framework 0x00000001155f68e6 v8::internal::LocalEmbedderHeapTracer::EmbedderWriteBarrier(v8::internal::Heap*, v8::internal::JSObject) + 150 +7 Electron Framework 0x00000001152cd34f v8::Object::SetAlignedPointerInInternalField(int, void*) + 639 +8 Electron Framework 0x000000011d18df35 node::BaseObject::BaseObject(node::Environment*, v8::Local) + 101 +9 Electron Framework 0x000000011d347b6e node::crypto::DiffieHellman::DiffieHellman(node::Environment*, v8::Local) + 14 +10 Electron Framework 0x000000011d348413 node::crypto::DiffieHellman::New(v8::FunctionCallbackInfo const&) + 147 +[...] + +This crash happens because this V8 isolate has cppgc enabled. When cppgc is +enabled, V8 assumes that the first embedder field is a "type" pointer, the +first 16 bits of which are the embedder ID. Node did not adhere to this +requirement. Sometimes--mostly, even--this worked _by accident_. If the first +field in the BaseObject was a pointer to a bit of memory that happened to +contain the two-byte little-endian value 0x0001, however, V8 would take that to +mean that the object was a Blink object[1], and attempt to read the pointer in +the second embedder slot, which would result in a CHECK. + +This change adds an "embedder id" pointer as the first embedder field in all +Node-managed objects. This ensures that cppgc will always skip over Node +objects. + +This patch should be upstreamed to Node. + +[1]: https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=20;drc=5a758a97032f0b656c3c36a3497560762495501a + +See also: https://source.chromium.org/chromium/chromium/src/+/main:v8/include/v8-cppgc.h;l=70-76;drc=5a758a97032f0b656c3c36a3497560762495501a + +diff --git a/src/base_object-inl.h b/src/base_object-inl.h +index bb1e8d4b46bce3bf08f730ac5d43f7113d17ae39..6da0669943fc6465ffc47a1c8c3dadfea6beb1c9 100644 +--- a/src/base_object-inl.h ++++ b/src/base_object-inl.h +@@ -32,10 +32,21 @@ + + namespace node { + ++namespace { ++// This just has to be different from the Chromium ones: ++// https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=18-23;drc=5a758a97032f0b656c3c36a3497560762495501a ++// Otherwise, when Node is loaded in an isolate which uses cppgc, cppgc will ++// misinterpret the data stored in the embedder fields and try to garbage ++// collect them. ++static uint16_t kNodeEmbedderId = 0x90de; ++} ++ + BaseObject::BaseObject(Environment* env, v8::Local object) + : persistent_handle_(env->isolate(), object), env_(env) { + CHECK_EQ(false, object.IsEmpty()); +- CHECK_GT(object->InternalFieldCount(), 0); ++ CHECK_GT(object->InternalFieldCount(), BaseObject::kSlot); ++ object->SetAlignedPointerInInternalField(BaseObject::kWrapperType, ++ &kNodeEmbedderId); + object->SetAlignedPointerInInternalField( + BaseObject::kSlot, + static_cast(this)); +@@ -151,7 +162,8 @@ bool BaseObject::IsWeakOrDetached() const { + void BaseObject::LazilyInitializedJSTemplateConstructor( + const v8::FunctionCallbackInfo& args) { + DCHECK(args.IsConstructCall()); +- DCHECK_GT(args.This()->InternalFieldCount(), 0); ++ DCHECK_GT(args.This()->InternalFieldCount(), BaseObject::kSlot); ++ args.This()->SetAlignedPointerInInternalField(BaseObject::kWrapperType, &kNodeEmbedderId); + args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr); + } + +diff --git a/src/base_object.h b/src/base_object.h +index d46a0f216009c63f45c440fc352b54d1ac4a08d8..81913c0d7762bf499ee19aaa3b63b986ca370bb4 100644 +--- a/src/base_object.h ++++ b/src/base_object.h +@@ -40,7 +40,7 @@ class TransferData; + + class BaseObject : public MemoryRetainer { + public: +- enum InternalFields { kSlot, kInternalFieldCount }; ++ enum InternalFields { kWrapperType, kSlot, kInternalFieldCount }; + + // Associates this object with `object`. It uses the 0th internal field for + // that, and in particular aborts if there is no such field. diff --git a/shell/app/electron_main_mac.cc b/shell/app/electron_main_mac.cc index 6180a4d80bb22..c0f9576fff7fe 100644 --- a/shell/app/electron_main_mac.cc +++ b/shell/app/electron_main_mac.cc @@ -20,7 +20,7 @@ namespace { -bool IsEnvSet(const char* name) { +[[maybe_unused]] bool IsEnvSet(const char* name) { char* indicator = getenv(name); return indicator && indicator[0] != '\0'; } diff --git a/shell/app/electron_main_win.cc b/shell/app/electron_main_win.cc index 38f654e5f047f..2be51c27b2478 100644 --- a/shell/app/electron_main_win.cc +++ b/shell/app/electron_main_win.cc @@ -44,7 +44,7 @@ namespace { const char kUserDataDir[] = "user-data-dir"; const char kProcessType[] = "type"; -bool IsEnvSet(const char* name) { +[[maybe_unused]] bool IsEnvSet(const char* name) { size_t required_size; getenv_s(&required_size, nullptr, 0, name); return required_size != 0; diff --git a/shell/browser/api/electron_api_net.cc b/shell/browser/api/electron_api_net.cc index 564fe440d604a..cf84a4b8a7137 100644 --- a/shell/browser/api/electron_api_net.cc +++ b/shell/browser/api/electron_api_net.cc @@ -5,11 +5,15 @@ #include #include "gin/handle.h" +#include "net/base/filename_util.h" #include "net/base/network_change_notifier.h" #include "net/http/http_util.h" #include "services/network/public/cpp/features.h" #include "shell/browser/api/electron_api_url_loader.h" +#include "shell/common/gin_converters/file_path_converter.h" +#include "shell/common/gin_converters/gurl_converter.h" #include "shell/common/gin_helper/dictionary.h" +#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" @@ -28,6 +32,14 @@ bool IsValidHeaderValue(std::string header_value) { return net::HttpUtil::IsValidHeaderValue(header_value); } +base::FilePath FileURLToFilePath(v8::Isolate* isolate, const GURL& url) { + base::FilePath path; + if (!net::FileURLToFilePath(url, &path)) + gin_helper::ErrorThrower(isolate).ThrowError( + "Failed to convert URL to file path"); + return path; +} + using electron::api::SimpleURLLoaderWrapper; void Initialize(v8::Local exports, @@ -41,6 +53,7 @@ void Initialize(v8::Local exports, dict.SetMethod("isValidHeaderName", &IsValidHeaderName); dict.SetMethod("isValidHeaderValue", &IsValidHeaderValue); dict.SetMethod("createURLLoader", &SimpleURLLoaderWrapper::Create); + dict.SetMethod("fileURLToFilePath", &FileURLToFilePath); } } // namespace diff --git a/shell/browser/api/electron_api_session.cc b/shell/browser/api/electron_api_session.cc index d0a0d4c408e92..ac6b38cdb58f4 100644 --- a/shell/browser/api/electron_api_session.cc +++ b/shell/browser/api/electron_api_session.cc @@ -28,6 +28,7 @@ #include "components/proxy_config/proxy_config_dictionary.h" #include "components/proxy_config/proxy_config_pref_names.h" #include "components/proxy_config/proxy_prefs.h" +#include "content/browser/code_cache/generated_code_cache_context.h" // nogncheck #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_item_utils.h" @@ -976,6 +977,45 @@ v8::Local Session::GetPath(v8::Isolate* isolate) { return gin::ConvertToV8(isolate, browser_context_->GetPath()); } +void Session::SetCodeCachePath(gin::Arguments* args) { + base::FilePath code_cache_path; + auto* storage_partition = browser_context_->GetDefaultStoragePartition(); + auto* code_cache_context = storage_partition->GetGeneratedCodeCacheContext(); + if (code_cache_context) { + if (!args->GetNext(&code_cache_path) || !code_cache_path.IsAbsolute()) { + args->ThrowTypeError( + "Absolute path must be provided to store code cache."); + return; + } + code_cache_context->Initialize( + code_cache_path, 0 /* allows disk_cache to choose the size */); + } +} + +v8::Local Session::ClearCodeCaches( + const gin_helper::Dictionary& options) { + auto* isolate = JavascriptEnvironment::GetIsolate(); + gin_helper::Promise promise(isolate); + v8::Local handle = promise.GetHandle(); + + std::set url_list; + base::RepeatingCallback url_matcher = base::NullCallback(); + if (options.Get("urls", &url_list) && !url_list.empty()) { + url_matcher = base::BindRepeating( + [](const std::set& url_list, const GURL& url) { + return base::Contains(url_list, url); + }, + url_list); + } + + browser_context_->GetDefaultStoragePartition()->ClearCodeCaches( + base::Time(), base::Time::Max(), url_matcher, + base::BindOnce(gin_helper::Promise::ResolvePromise, + std::move(promise))); + + return handle; +} + #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) base::Value Session::GetSpellCheckerLanguages() { return browser_context_->prefs() @@ -1203,6 +1243,8 @@ gin::ObjectTemplateBuilder Session::GetObjectTemplateBuilder( .SetMethod("preconnect", &Session::Preconnect) .SetMethod("closeAllConnections", &Session::CloseAllConnections) .SetMethod("getStoragePath", &Session::GetPath) + .SetMethod("setCodeCachePath", &Session::SetCodeCachePath) + .SetMethod("clearCodeCaches", &Session::ClearCodeCaches) .SetProperty("cookies", &Session::Cookies) .SetProperty("netLog", &Session::NetLog) .SetProperty("protocol", &Session::Protocol) diff --git a/shell/browser/api/electron_api_session.h b/shell/browser/api/electron_api_session.h index aedf234d38a58..e9b69380dfaf9 100644 --- a/shell/browser/api/electron_api_session.h +++ b/shell/browser/api/electron_api_session.h @@ -127,6 +127,8 @@ class Session : public gin::Wrappable, void Preconnect(const gin_helper::Dictionary& options, gin::Arguments* args); v8::Local CloseAllConnections(); v8::Local GetPath(v8::Isolate* isolate); + void SetCodeCachePath(gin::Arguments* args); + v8::Local ClearCodeCaches(const gin_helper::Dictionary& options); #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) base::Value GetSpellCheckerLanguages(); void SetSpellCheckerLanguages(gin_helper::ErrorThrower thrower, diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 0da1f050e7695..f6d275e8f4c3b 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -1751,7 +1751,7 @@ void WebContents::Message(bool internal, // webContents.emit('-ipc-message', new Event(), internal, channel, // arguments); EmitWithSender("-ipc-message", render_frame_host, - electron::mojom::ElectronBrowser::InvokeCallback(), internal, + electron::mojom::ElectronApiIPC::InvokeCallback(), internal, channel, std::move(arguments)); } @@ -1759,7 +1759,7 @@ void WebContents::Invoke( bool internal, const std::string& channel, blink::CloneableMessage arguments, - electron::mojom::ElectronBrowser::InvokeCallback callback, + electron::mojom::ElectronApiIPC::InvokeCallback callback, content::RenderFrameHost* render_frame_host) { TRACE_EVENT1("electron", "WebContents::Invoke", "channel", channel); // webContents.emit('-ipc-invoke', new Event(), internal, channel, arguments); @@ -1785,7 +1785,7 @@ void WebContents::ReceivePostMessage( v8::Local message_value = electron::DeserializeV8Value(isolate, message); EmitWithSender("-ipc-ports", render_frame_host, - electron::mojom::ElectronBrowser::InvokeCallback(), false, + electron::mojom::ElectronApiIPC::InvokeCallback(), false, channel, message_value, std::move(wrapped_ports)); } @@ -1793,7 +1793,7 @@ void WebContents::MessageSync( bool internal, const std::string& channel, blink::CloneableMessage arguments, - electron::mojom::ElectronBrowser::MessageSyncCallback callback, + electron::mojom::ElectronApiIPC::MessageSyncCallback callback, content::RenderFrameHost* render_frame_host) { TRACE_EVENT1("electron", "WebContents::MessageSync", "channel", channel); // webContents.emit('-ipc-message-sync', new Event(sender, message), internal, @@ -1831,7 +1831,7 @@ void WebContents::MessageHost(const std::string& channel, TRACE_EVENT1("electron", "WebContents::MessageHost", "channel", channel); // webContents.emit('ipc-message-host', new Event(), channel, args); EmitWithSender("ipc-message-host", render_frame_host, - electron::mojom::ElectronBrowser::InvokeCallback(), channel, + electron::mojom::ElectronApiIPC::InvokeCallback(), channel, std::move(arguments)); } @@ -3270,7 +3270,8 @@ void WebContents::SetTemporaryZoomLevel(double level) { } void WebContents::DoGetZoomLevel( - electron::mojom::ElectronBrowser::DoGetZoomLevelCallback callback) { + electron::mojom::ElectronWebContentsUtility::DoGetZoomLevelCallback + callback) { std::move(callback).Run(GetZoomLevel()); } diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index b034167631fa3..996c90cbbbc39 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -355,7 +355,7 @@ class WebContents : public ExclusiveAccessContext, template bool EmitWithSender(base::StringPiece name, content::RenderFrameHost* sender, - electron::mojom::ElectronBrowser::InvokeCallback callback, + electron::mojom::ElectronApiIPC::InvokeCallback callback, Args&&... args) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); @@ -399,7 +399,7 @@ class WebContents : public ExclusiveAccessContext, fullscreen_frame_ = rfh; } - // mojom::ElectronBrowser + // mojom::ElectronApiIPC void Message(bool internal, const std::string& channel, blink::CloneableMessage arguments, @@ -407,9 +407,8 @@ class WebContents : public ExclusiveAccessContext, void Invoke(bool internal, const std::string& channel, blink::CloneableMessage arguments, - electron::mojom::ElectronBrowser::InvokeCallback callback, + electron::mojom::ElectronApiIPC::InvokeCallback callback, content::RenderFrameHost* render_frame_host); - void OnFirstNonEmptyLayout(content::RenderFrameHost* render_frame_host); void ReceivePostMessage(const std::string& channel, blink::TransferableMessage message, content::RenderFrameHost* render_frame_host); @@ -417,7 +416,7 @@ class WebContents : public ExclusiveAccessContext, bool internal, const std::string& channel, blink::CloneableMessage arguments, - electron::mojom::ElectronBrowser::MessageSyncCallback callback, + electron::mojom::ElectronApiIPC::MessageSyncCallback callback, content::RenderFrameHost* render_frame_host); void MessageTo(int32_t web_contents_id, const std::string& channel, @@ -425,10 +424,15 @@ class WebContents : public ExclusiveAccessContext, void MessageHost(const std::string& channel, blink::CloneableMessage arguments, content::RenderFrameHost* render_frame_host); + + // mojom::ElectronWebContentsUtility + void OnFirstNonEmptyLayout(content::RenderFrameHost* render_frame_host); void UpdateDraggableRegions(std::vector regions); void SetTemporaryZoomLevel(double level); void DoGetZoomLevel( - electron::mojom::ElectronBrowser::DoGetZoomLevelCallback callback); + electron::mojom::ElectronWebContentsUtility::DoGetZoomLevelCallback + callback); + void SetImageAnimationPolicy(const std::string& new_policy); // Grants |origin| access to |device|. diff --git a/shell/browser/api/event.h b/shell/browser/api/event.h index 4a09575896e11..a9e4dec39e9d8 100644 --- a/shell/browser/api/event.h +++ b/shell/browser/api/event.h @@ -13,7 +13,7 @@ namespace gin_helper { class Event : public gin::Wrappable { public: - using InvokeCallback = electron::mojom::ElectronBrowser::InvokeCallback; + using InvokeCallback = electron::mojom::ElectronApiIPC::InvokeCallback; static gin::WrapperInfo kWrapperInfo; diff --git a/shell/browser/electron_api_ipc_handler_impl.cc b/shell/browser/electron_api_ipc_handler_impl.cc new file mode 100644 index 0000000000000..5a13fda3629e9 --- /dev/null +++ b/shell/browser/electron_api_ipc_handler_impl.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2022 Slack Technologies, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/electron_api_ipc_handler_impl.h" + +#include + +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" + +namespace electron { +ElectronApiIPCHandlerImpl::ElectronApiIPCHandlerImpl( + content::RenderFrameHost* frame_host, + mojo::PendingAssociatedReceiver receiver) + : render_process_id_(frame_host->GetProcess()->GetID()), + render_frame_id_(frame_host->GetRoutingID()) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(frame_host); + DCHECK(web_contents); + content::WebContentsObserver::Observe(web_contents); + + receiver_.Bind(std::move(receiver)); + receiver_.set_disconnect_handler(base::BindOnce( + &ElectronApiIPCHandlerImpl::OnConnectionError, GetWeakPtr())); +} + +ElectronApiIPCHandlerImpl::~ElectronApiIPCHandlerImpl() = default; + +void ElectronApiIPCHandlerImpl::WebContentsDestroyed() { + delete this; +} + +void ElectronApiIPCHandlerImpl::OnConnectionError() { + delete this; +} + +void ElectronApiIPCHandlerImpl::Message(bool internal, + const std::string& channel, + blink::CloneableMessage arguments) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->Message(internal, channel, std::move(arguments), + GetRenderFrameHost()); + } +} +void ElectronApiIPCHandlerImpl::Invoke(bool internal, + const std::string& channel, + blink::CloneableMessage arguments, + InvokeCallback callback) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->Invoke(internal, channel, std::move(arguments), + std::move(callback), GetRenderFrameHost()); + } +} + +void ElectronApiIPCHandlerImpl::ReceivePostMessage( + const std::string& channel, + blink::TransferableMessage message) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->ReceivePostMessage(channel, std::move(message), + GetRenderFrameHost()); + } +} + +void ElectronApiIPCHandlerImpl::MessageSync(bool internal, + const std::string& channel, + blink::CloneableMessage arguments, + MessageSyncCallback callback) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->MessageSync(internal, channel, std::move(arguments), + std::move(callback), GetRenderFrameHost()); + } +} + +void ElectronApiIPCHandlerImpl::MessageTo(int32_t web_contents_id, + const std::string& channel, + blink::CloneableMessage arguments) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->MessageTo(web_contents_id, channel, std::move(arguments)); + } +} + +void ElectronApiIPCHandlerImpl::MessageHost(const std::string& channel, + blink::CloneableMessage arguments) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->MessageHost(channel, std::move(arguments), + GetRenderFrameHost()); + } +} + +content::RenderFrameHost* ElectronApiIPCHandlerImpl::GetRenderFrameHost() { + return content::RenderFrameHost::FromID(render_process_id_, render_frame_id_); +} + +// static +void ElectronApiIPCHandlerImpl::Create( + content::RenderFrameHost* frame_host, + mojo::PendingAssociatedReceiver receiver) { + new ElectronApiIPCHandlerImpl(frame_host, std::move(receiver)); +} +} // namespace electron diff --git a/shell/browser/electron_browser_handler_impl.h b/shell/browser/electron_api_ipc_handler_impl.h similarity index 58% rename from shell/browser/electron_browser_handler_impl.h rename to shell/browser/electron_api_ipc_handler_impl.h index fea3f11907d1d..7cddf88bedc4a 100644 --- a/shell/browser/electron_browser_handler_impl.h +++ b/shell/browser/electron_api_ipc_handler_impl.h @@ -1,9 +1,9 @@ -// Copyright (c) 2019 Slack Technologies, Inc. +// Copyright (c) 2022 Slack Technologies, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#ifndef ELECTRON_SHELL_BROWSER_ELECTRON_BROWSER_HANDLER_IMPL_H_ -#define ELECTRON_SHELL_BROWSER_ELECTRON_BROWSER_HANDLER_IMPL_H_ +#ifndef ELECTRON_SHELL_BROWSER_ELECTRON_API_IPC_HANDLER_IMPL_H_ +#define ELECTRON_SHELL_BROWSER_ELECTRON_API_IPC_HANDLER_IMPL_H_ #include #include @@ -18,23 +18,23 @@ class RenderFrameHost; } namespace electron { -class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser, - public content::WebContentsObserver { +class ElectronApiIPCHandlerImpl : public mojom::ElectronApiIPC, + public content::WebContentsObserver { public: - explicit ElectronBrowserHandlerImpl( + explicit ElectronApiIPCHandlerImpl( content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver receiver); + mojo::PendingAssociatedReceiver receiver); static void Create( content::RenderFrameHost* frame_host, - mojo::PendingAssociatedReceiver receiver); + mojo::PendingAssociatedReceiver receiver); // disable copy - ElectronBrowserHandlerImpl(const ElectronBrowserHandlerImpl&) = delete; - ElectronBrowserHandlerImpl& operator=(const ElectronBrowserHandlerImpl&) = + ElectronApiIPCHandlerImpl(const ElectronApiIPCHandlerImpl&) = delete; + ElectronApiIPCHandlerImpl& operator=(const ElectronApiIPCHandlerImpl&) = delete; - // mojom::ElectronBrowser: + // mojom::ElectronApiIPC: void Message(bool internal, const std::string& channel, blink::CloneableMessage arguments) override; @@ -42,7 +42,6 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser, const std::string& channel, blink::CloneableMessage arguments, InvokeCallback callback) override; - void OnFirstNonEmptyLayout() override; void ReceivePostMessage(const std::string& channel, blink::TransferableMessage message) override; void MessageSync(bool internal, @@ -54,17 +53,13 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser, blink::CloneableMessage arguments) override; void MessageHost(const std::string& channel, blink::CloneableMessage arguments) override; - void UpdateDraggableRegions( - std::vector regions) override; - void SetTemporaryZoomLevel(double level) override; - void DoGetZoomLevel(DoGetZoomLevelCallback callback) override; - base::WeakPtr GetWeakPtr() { + base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } private: - ~ElectronBrowserHandlerImpl() override; + ~ElectronApiIPCHandlerImpl() override; // content::WebContentsObserver: void WebContentsDestroyed() override; @@ -76,9 +71,9 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser, const int render_process_id_; const int render_frame_id_; - mojo::AssociatedReceiver receiver_{this}; + mojo::AssociatedReceiver receiver_{this}; - base::WeakPtrFactory weak_factory_{this}; + base::WeakPtrFactory weak_factory_{this}; }; } // namespace electron -#endif // ELECTRON_SHELL_BROWSER_ELECTRON_BROWSER_HANDLER_IMPL_H_ +#endif // ELECTRON_SHELL_BROWSER_ELECTRON_API_IPC_HANDLER_IMPL_H_ diff --git a/shell/browser/electron_browser_client.cc b/shell/browser/electron_browser_client.cc index 096dcabb56c4f..50fff944a3af3 100644 --- a/shell/browser/electron_browser_client.cc +++ b/shell/browser/electron_browser_client.cc @@ -21,6 +21,7 @@ #include "base/no_destructor.h" #include "base/path_service.h" #include "base/stl_util.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -63,6 +64,8 @@ #include "printing/buildflags/buildflags.h" #include "services/device/public/cpp/geolocation/location_provider.h" #include "services/network/public/cpp/features.h" +#include "services/network/public/cpp/is_potentially_trustworthy.h" +#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/resource_request_body.h" #include "services/network/public/cpp/self_deleting_url_loader_factory.h" #include "shell/app/electron_crash_reporter_client.h" @@ -74,13 +77,14 @@ #include "shell/browser/api/electron_api_web_request.h" #include "shell/browser/badging/badge_manager.h" #include "shell/browser/child_web_contents_tracker.h" +#include "shell/browser/electron_api_ipc_handler_impl.h" #include "shell/browser/electron_autofill_driver_factory.h" #include "shell/browser/electron_browser_context.h" -#include "shell/browser/electron_browser_handler_impl.h" #include "shell/browser/electron_browser_main_parts.h" #include "shell/browser/electron_navigation_throttle.h" #include "shell/browser/electron_quota_permission_context.h" #include "shell/browser/electron_speech_recognition_manager_delegate.h" +#include "shell/browser/electron_web_contents_utility_handler_impl.h" #include "shell/browser/font_defaults.h" #include "shell/browser/javascript_environment.h" #include "shell/browser/media/media_capture_devices_dispatcher.h" @@ -361,6 +365,21 @@ int GetCrashSignalFD(const base::CommandLine& command_line) { } #endif // BUILDFLAG(IS_LINUX) +void MaybeAppendSecureOriginsAllowlistSwitch(base::CommandLine* cmdline) { + // |allowlist| combines pref/policy + cmdline switch in the browser process. + // For renderer and utility (e.g. NetworkService) processes the switch is the + // only available source, so below the combined (pref/policy + cmdline) + // allowlist of secure origins is injected into |cmdline| for these other + // processes. + std::vector allowlist = + network::SecureOriginAllowlist::GetInstance().GetCurrentAllowlist(); + if (!allowlist.empty()) { + cmdline->AppendSwitchASCII( + network::switches::kUnsafelyTreatInsecureOriginAsSecure, + base::JoinString(allowlist, ",")); + } +} + } // namespace // static @@ -602,6 +621,10 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches( command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(), kCommonSwitchNames, base::size(kCommonSwitchNames)); + if (process_type == ::switches::kUtilityProcess || + content::RenderProcessHost::FromID(process_id)) { + MaybeAppendSecureOriginsAllowlistSwitch(command_line); + } } if (process_type == ::switches::kRendererProcess) { @@ -1493,14 +1516,33 @@ void ElectronBrowserClient:: render_frame_host, // NOLINT(runtime/references) blink::AssociatedInterfaceRegistry& associated_registry) { // NOLINT(runtime/references) + auto* contents = + content::WebContents::FromRenderFrameHost(&render_frame_host); + if (contents) { + auto* prefs = WebContentsPreferences::From(contents); + if (render_frame_host.GetFrameTreeNodeId() == + contents->GetMainFrame()->GetFrameTreeNodeId() || + (prefs && prefs->AllowsNodeIntegrationInSubFrames())) { + associated_registry.AddInterface(base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver + receiver) { + ElectronApiIPCHandlerImpl::Create(render_frame_host, + std::move(receiver)); + }, + &render_frame_host)); + } + } + associated_registry.AddInterface(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver - receiver) { - ElectronBrowserHandlerImpl::Create(render_frame_host, - std::move(receiver)); + mojo::PendingAssociatedReceiver< + electron::mojom::ElectronWebContentsUtility> receiver) { + ElectronWebContentsUtilityHandlerImpl::Create(render_frame_host, + std::move(receiver)); }, &render_frame_host)); + associated_registry.AddInterface(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, mojo::PendingAssociatedReceiver diff --git a/shell/browser/electron_browser_handler_impl.cc b/shell/browser/electron_browser_handler_impl.cc deleted file mode 100644 index e66968b0cb132..0000000000000 --- a/shell/browser/electron_browser_handler_impl.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2019 Slack Technologies, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "shell/browser/electron_browser_handler_impl.h" - -#include - -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_process_host.h" -#include "mojo/public/cpp/bindings/self_owned_receiver.h" - -namespace electron { -ElectronBrowserHandlerImpl::ElectronBrowserHandlerImpl( - content::RenderFrameHost* frame_host, - mojo::PendingAssociatedReceiver receiver) - : render_process_id_(frame_host->GetProcess()->GetID()), - render_frame_id_(frame_host->GetRoutingID()) { - content::WebContents* web_contents = - content::WebContents::FromRenderFrameHost(frame_host); - DCHECK(web_contents); - content::WebContentsObserver::Observe(web_contents); - - receiver_.Bind(std::move(receiver)); - receiver_.set_disconnect_handler(base::BindOnce( - &ElectronBrowserHandlerImpl::OnConnectionError, GetWeakPtr())); -} - -ElectronBrowserHandlerImpl::~ElectronBrowserHandlerImpl() = default; - -void ElectronBrowserHandlerImpl::WebContentsDestroyed() { - delete this; -} - -void ElectronBrowserHandlerImpl::OnConnectionError() { - delete this; -} - -void ElectronBrowserHandlerImpl::Message(bool internal, - const std::string& channel, - blink::CloneableMessage arguments) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->Message(internal, channel, std::move(arguments), - GetRenderFrameHost()); - } -} -void ElectronBrowserHandlerImpl::Invoke(bool internal, - const std::string& channel, - blink::CloneableMessage arguments, - InvokeCallback callback) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->Invoke(internal, channel, std::move(arguments), - std::move(callback), GetRenderFrameHost()); - } -} - -void ElectronBrowserHandlerImpl::OnFirstNonEmptyLayout() { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->OnFirstNonEmptyLayout(GetRenderFrameHost()); - } -} - -void ElectronBrowserHandlerImpl::ReceivePostMessage( - const std::string& channel, - blink::TransferableMessage message) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->ReceivePostMessage(channel, std::move(message), - GetRenderFrameHost()); - } -} - -void ElectronBrowserHandlerImpl::MessageSync(bool internal, - const std::string& channel, - blink::CloneableMessage arguments, - MessageSyncCallback callback) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->MessageSync(internal, channel, std::move(arguments), - std::move(callback), GetRenderFrameHost()); - } -} - -void ElectronBrowserHandlerImpl::MessageTo(int32_t web_contents_id, - const std::string& channel, - blink::CloneableMessage arguments) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->MessageTo(web_contents_id, channel, std::move(arguments)); - } -} - -void ElectronBrowserHandlerImpl::MessageHost( - const std::string& channel, - blink::CloneableMessage arguments) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->MessageHost(channel, std::move(arguments), - GetRenderFrameHost()); - } -} - -void ElectronBrowserHandlerImpl::UpdateDraggableRegions( - std::vector regions) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->UpdateDraggableRegions(std::move(regions)); - } -} - -void ElectronBrowserHandlerImpl::SetTemporaryZoomLevel(double level) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->SetTemporaryZoomLevel(level); - } -} - -void ElectronBrowserHandlerImpl::DoGetZoomLevel( - DoGetZoomLevelCallback callback) { - api::WebContents* api_web_contents = api::WebContents::From(web_contents()); - if (api_web_contents) { - api_web_contents->DoGetZoomLevel(std::move(callback)); - } -} - -content::RenderFrameHost* ElectronBrowserHandlerImpl::GetRenderFrameHost() { - return content::RenderFrameHost::FromID(render_process_id_, render_frame_id_); -} - -// static -void ElectronBrowserHandlerImpl::Create( - content::RenderFrameHost* frame_host, - mojo::PendingAssociatedReceiver receiver) { - new ElectronBrowserHandlerImpl(frame_host, std::move(receiver)); -} -} // namespace electron diff --git a/shell/browser/electron_web_contents_utility_handler_impl.cc b/shell/browser/electron_web_contents_utility_handler_impl.cc new file mode 100644 index 0000000000000..807dcdbdf9cc1 --- /dev/null +++ b/shell/browser/electron_web_contents_utility_handler_impl.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2022 Slack Technologies, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/electron_web_contents_utility_handler_impl.h" + +#include + +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" + +namespace electron { +ElectronWebContentsUtilityHandlerImpl::ElectronWebContentsUtilityHandlerImpl( + content::RenderFrameHost* frame_host, + mojo::PendingAssociatedReceiver receiver) + : render_process_id_(frame_host->GetProcess()->GetID()), + render_frame_id_(frame_host->GetRoutingID()) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(frame_host); + DCHECK(web_contents); + content::WebContentsObserver::Observe(web_contents); + + receiver_.Bind(std::move(receiver)); + receiver_.set_disconnect_handler(base::BindOnce( + &ElectronWebContentsUtilityHandlerImpl::OnConnectionError, GetWeakPtr())); +} + +ElectronWebContentsUtilityHandlerImpl:: + ~ElectronWebContentsUtilityHandlerImpl() = default; + +void ElectronWebContentsUtilityHandlerImpl::WebContentsDestroyed() { + delete this; +} + +void ElectronWebContentsUtilityHandlerImpl::OnConnectionError() { + delete this; +} + +void ElectronWebContentsUtilityHandlerImpl::OnFirstNonEmptyLayout() { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->OnFirstNonEmptyLayout(GetRenderFrameHost()); + } +} + +void ElectronWebContentsUtilityHandlerImpl::UpdateDraggableRegions( + std::vector regions) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->UpdateDraggableRegions(std::move(regions)); + } +} + +void ElectronWebContentsUtilityHandlerImpl::SetTemporaryZoomLevel( + double level) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->SetTemporaryZoomLevel(level); + } +} + +void ElectronWebContentsUtilityHandlerImpl::DoGetZoomLevel( + DoGetZoomLevelCallback callback) { + api::WebContents* api_web_contents = api::WebContents::From(web_contents()); + if (api_web_contents) { + api_web_contents->DoGetZoomLevel(std::move(callback)); + } +} + +content::RenderFrameHost* +ElectronWebContentsUtilityHandlerImpl::GetRenderFrameHost() { + return content::RenderFrameHost::FromID(render_process_id_, render_frame_id_); +} + +// static +void ElectronWebContentsUtilityHandlerImpl::Create( + content::RenderFrameHost* frame_host, + mojo::PendingAssociatedReceiver + receiver) { + new ElectronWebContentsUtilityHandlerImpl(frame_host, std::move(receiver)); +} +} // namespace electron diff --git a/shell/browser/electron_web_contents_utility_handler_impl.h b/shell/browser/electron_web_contents_utility_handler_impl.h new file mode 100644 index 0000000000000..30a9baa40f835 --- /dev/null +++ b/shell/browser/electron_web_contents_utility_handler_impl.h @@ -0,0 +1,71 @@ +// Copyright (c) 2022 Slack Technologies, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_BROWSER_ELECTRON_WEB_CONTENTS_UTILITY_HANDLER_IMPL_H_ +#define ELECTRON_SHELL_BROWSER_ELECTRON_WEB_CONTENTS_UTILITY_HANDLER_IMPL_H_ + +#include +#include + +#include "base/memory/weak_ptr.h" +#include "content/public/browser/web_contents_observer.h" +#include "electron/shell/common/api/api.mojom.h" +#include "shell/browser/api/electron_api_web_contents.h" + +namespace content { +class RenderFrameHost; +} + +namespace electron { +class ElectronWebContentsUtilityHandlerImpl + : public mojom::ElectronWebContentsUtility, + public content::WebContentsObserver { + public: + explicit ElectronWebContentsUtilityHandlerImpl( + content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver + receiver); + + static void Create( + content::RenderFrameHost* frame_host, + mojo::PendingAssociatedReceiver + receiver); + + // disable copy + ElectronWebContentsUtilityHandlerImpl( + const ElectronWebContentsUtilityHandlerImpl&) = delete; + ElectronWebContentsUtilityHandlerImpl& operator=( + const ElectronWebContentsUtilityHandlerImpl&) = delete; + + // mojom::ElectronWebContentsUtility: + void OnFirstNonEmptyLayout() override; + void UpdateDraggableRegions( + std::vector regions) override; + void SetTemporaryZoomLevel(double level) override; + void DoGetZoomLevel(DoGetZoomLevelCallback callback) override; + + base::WeakPtr GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + private: + ~ElectronWebContentsUtilityHandlerImpl() override; + + // content::WebContentsObserver: + void WebContentsDestroyed() override; + + void OnConnectionError(); + + content::RenderFrameHost* GetRenderFrameHost(); + + const int render_process_id_; + const int render_frame_id_; + + mojo::AssociatedReceiver receiver_{this}; + + base::WeakPtrFactory weak_factory_{ + this}; +}; +} // namespace electron +#endif // ELECTRON_SHELL_BROWSER_ELECTRON_WEB_CONTENTS_UTILITY_HANDLER_IMPL_H_ diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 2d3d866fa71dc..a5c58964016c3 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -580,11 +580,13 @@ void NativeWindowViews::SetEnabledInternal(bool enable) { #if BUILDFLAG(IS_LINUX) void NativeWindowViews::Maximize() { - if (IsVisible()) + if (IsVisible()) { widget()->Maximize(); - else + } else { widget()->native_widget_private()->Show(ui::SHOW_STATE_MAXIMIZED, gfx::Rect()); + NotifyWindowShow(); + } } #endif diff --git a/shell/browser/native_window_views_win.cc b/shell/browser/native_window_views_win.cc index ab336f2e29866..01d88048af794 100644 --- a/shell/browser/native_window_views_win.cc +++ b/shell/browser/native_window_views_win.cc @@ -178,12 +178,13 @@ HHOOK NativeWindowViews::mouse_hook_ = NULL; void NativeWindowViews::Maximize() { // Only use Maximize() when window is NOT transparent style if (!transparent()) { - if (IsVisible()) + if (IsVisible()) { widget()->Maximize(); - else + } else { widget()->native_widget_private()->Show(ui::SHOW_STATE_MAXIMIZED, gfx::Rect()); - return; + NotifyWindowShow(); + } } else { restore_bounds_ = GetBounds(); auto display = display::Screen::GetScreen()->GetDisplayNearestWindow( diff --git a/shell/browser/net/system_network_context_manager.cc b/shell/browser/net/system_network_context_manager.cc index d1f474d59ead7..de3989ad88678 100644 --- a/shell/browser/net/system_network_context_manager.cc +++ b/shell/browser/net/system_network_context_manager.cc @@ -288,6 +288,10 @@ void SystemNetworkContextManager::OnNetworkServiceCreated( base::FeatureList::IsEnabled(features::kAsyncDns), default_secure_dns_mode, doh_config, additional_dns_query_types_enabled); + // Initializes first party sets component + // CL: https://chromium-review.googlesource.com/c/chromium/src/+/3449280 + content::GetNetworkService()->SetFirstPartySets(base::File()); + std::string app_name = electron::Browser::Get()->GetName(); #if BUILDFLAG(IS_MAC) KeychainPassword::GetServiceName() = app_name + " Safe Storage"; diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index 8d84f50990408..14ba8ce3ae702 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 19,0,0,20220308 - PRODUCTVERSION 19,0,0,20220308 + FILEVERSION 19,0,0,20220318 + PRODUCTVERSION 19,0,0,20220318 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm index e4b797a001a1e..3f86dca5158e5 100644 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm +++ b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm @@ -266,6 +266,8 @@ - (void)viewDidBecomeFirstResponder:(NSNotification*)notification { inspectableWebContentsView_->inspectable_web_contents(); DCHECK(inspectable_web_contents); auto* webContents = inspectable_web_contents->GetWebContents(); + if (!webContents) + return; auto* webContentsView = webContents->GetNativeView().GetNativeNSView(); NSView* view = [notification object]; diff --git a/shell/browser/ui/inspectable_web_contents.cc b/shell/browser/ui/inspectable_web_contents.cc index b7e939c35d45f..4779ee6c77f1e 100644 --- a/shell/browser/ui/inspectable_web_contents.cc +++ b/shell/browser/ui/inspectable_web_contents.cc @@ -86,13 +86,6 @@ const char kChromeUIDevToolsRemoteFrontendPath[] = "serve_file"; const char kDevToolsBoundsPref[] = "electron.devtools.bounds"; const char kDevToolsZoomPref[] = "electron.devtools.zoom"; const char kDevToolsPreferences[] = "electron.devtools.preferences"; -const char kDevToolsSyncPreferences[] = "electron.devtools.sync_preferences"; -const char kDevToolsSyncedPreferencesSyncEnabled[] = - "electron.devtools.synced_preferences_sync_enabled"; -const char kDevToolsSyncedPreferencesSyncDisabled[] = - "electron.devtools.synced_preferences_sync_disabled"; -const char kSyncDevToolsPreferencesFrontendName[] = "electron.sync_preferences"; -const bool kSyncDevToolsPreferencesDefault = false; const char kFrontendHostId[] = "id"; const char kFrontendHostMethod[] = "method"; @@ -175,6 +168,10 @@ GURL GetDevToolsURL(bool can_dock) { return GURL(url_string); } +void OnOpenItemComplete(const base::FilePath& path, const std::string& result) { + platform_util::ShowItemInFolder(path); +} + constexpr base::TimeDelta kInitialBackoffDelay = base::Milliseconds(250); constexpr base::TimeDelta kMaxBackoffDelay = base::Seconds(10); @@ -342,10 +339,6 @@ void InspectableWebContents::RegisterPrefs(PrefRegistrySimple* registry) { RectToDictionary(gfx::Rect(0, 0, 800, 600))); registry->RegisterDoublePref(kDevToolsZoomPref, 0.); registry->RegisterDictionaryPref(kDevToolsPreferences); - registry->RegisterDictionaryPref(kDevToolsSyncedPreferencesSyncEnabled); - registry->RegisterDictionaryPref(kDevToolsSyncedPreferencesSyncDisabled); - registry->RegisterBooleanPref(kDevToolsSyncPreferences, - kSyncDevToolsPreferencesDefault); } InspectableWebContents::InspectableWebContents( @@ -737,9 +730,8 @@ void InspectableWebContents::ShowItemInFolder( return; base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); - - // Pass empty callback here; we can ignore errors - platform_util::OpenPath(path, platform_util::OpenCallback()); + platform_util::OpenPath(path.DirName(), + base::BindOnce(&OnOpenItemComplete, path)); } void InspectableWebContents::SaveToFile(const std::string& url, @@ -864,85 +856,19 @@ void InspectableWebContents::SendJsonRequest(DispatchCallback callback, std::move(callback).Run(nullptr); } -void InspectableWebContents::RegisterPreference( - const std::string& name, - const RegisterOptions& options) { - // kSyncDevToolsPreferenceFrontendName is not stored in any of the relevant - // dictionaries. Skip registration. - if (name == kSyncDevToolsPreferencesFrontendName) - return; - - if (options.sync_mode == RegisterOptions::SyncMode::kSync) { - synced_setting_names_.insert(name); - } - - // Setting might have had a different sync status in the past. Move the - // setting to the correct dictionary. - const char* dictionary_to_remove_from = - options.sync_mode == RegisterOptions::SyncMode::kSync - ? kDevToolsPreferences - : GetDictionaryNameForSyncedPrefs(); - const std::string* settings_value = - pref_service_->GetDictionary(dictionary_to_remove_from) - ->FindStringKey(name); - if (!settings_value) { - return; - } - - const char* dictionary_to_insert_into = - GetDictionaryNameForSettingsName(name); - // Settings already moved to the synced dictionary on a different device have - // precedence. - const std::string* already_synced_value = - pref_service_->GetDictionary(dictionary_to_insert_into) - ->FindStringKey(name); - if (dictionary_to_insert_into == kDevToolsPreferences || - !already_synced_value) { - DictionaryPrefUpdate insert_update(pref_service_, - dictionary_to_insert_into); - insert_update.Get()->SetKey(name, base::Value(*settings_value)); - } - - DictionaryPrefUpdate remove_update(pref_service_, dictionary_to_remove_from); - remove_update.Get()->RemoveKey(name); -} - void InspectableWebContents::GetPreferences(DispatchCallback callback) { - base::Value settings(base::Value::Type::DICTIONARY); - settings.SetBoolKey(kSyncDevToolsPreferencesFrontendName, - pref_service_->GetBoolean(kDevToolsSyncPreferences)); - settings.MergeDictionary(pref_service_->GetDictionary(kDevToolsPreferences)); - settings.MergeDictionary( - pref_service_->GetDictionary(GetDictionaryNameForSyncedPrefs())); - - std::move(callback).Run(&settings); + const base::Value* prefs = pref_service_->GetDictionary(kDevToolsPreferences); + std::move(callback).Run(prefs); } void InspectableWebContents::GetPreference(DispatchCallback callback, const std::string& name) { - // Handle kSyncDevToolsPreferencesFrontendName - if (name == kSyncDevToolsPreferencesFrontendName) { - base::Value pref = - base::Value(pref_service_->GetBoolean(kDevToolsSyncPreferences)); - std::move(callback).Run(&pref); - return; - } - - // Check dev tools prefs if (auto* pref = pref_service_->GetDictionary(kDevToolsPreferences)->FindKey(name)) { std::move(callback).Run(pref); return; } - // Check synced prefs - if (auto* pref = - pref_service_->GetDictionary(GetDictionaryNameForSyncedPrefs()) - ->FindKey(name)) { - std::move(callback).Run(pref); - return; - } - // Pref wasn't found, return an empty value base::Value no_pref; std::move(callback).Run(&no_pref); @@ -950,41 +876,21 @@ void InspectableWebContents::GetPreference(DispatchCallback callback, void InspectableWebContents::SetPreference(const std::string& name, const std::string& value) { - if (name == kSyncDevToolsPreferencesFrontendName) { - pref_service_->SetBoolean(kDevToolsSyncPreferences, value == "true"); - return; - } - DictionaryPrefUpdate update(pref_service_, - GetDictionaryNameForSettingsName(name)); + DictionaryPrefUpdate update(pref_service_, kDevToolsPreferences); update.Get()->SetKey(name, base::Value(value)); } void InspectableWebContents::RemovePreference(const std::string& name) { - if (name == kSyncDevToolsPreferencesFrontendName) { - pref_service_->SetBoolean(kDevToolsSyncPreferences, - kSyncDevToolsPreferencesDefault); - return; - } - DictionaryPrefUpdate update(pref_service_, - GetDictionaryNameForSettingsName(name)); + DictionaryPrefUpdate update(pref_service_, kDevToolsPreferences); update.Get()->RemoveKey(name); } void InspectableWebContents::ClearPreferences() { - pref_service_->SetBoolean(kDevToolsSyncPreferences, - kSyncDevToolsPreferencesDefault); DictionaryPrefUpdate unsynced_update(pref_service_, kDevToolsPreferences); unsynced_update.Get()->DictClear(); - DictionaryPrefUpdate sync_enabled_update( - pref_service_, kDevToolsSyncedPreferencesSyncEnabled); - sync_enabled_update.Get()->DictClear(); - DictionaryPrefUpdate sync_disabled_update( - pref_service_, kDevToolsSyncedPreferencesSyncDisabled); - sync_disabled_update.Get()->DictClear(); } void InspectableWebContents::GetSyncInformation(DispatchCallback callback) { - // TODO(anyone): do we want devtool syncing in Electron? base::Value result(base::Value::Type::DICTIONARY); result.SetBoolKey("isSyncActive", false); std::move(callback).Run(&result); @@ -1169,18 +1075,4 @@ void InspectableWebContents::SendMessageAck(int request_id, CallClientFunction("DevToolsAPI.embedderMessageAck", &id_value, arg, nullptr); } -const char* InspectableWebContents::GetDictionaryNameForSettingsName( - const std::string& name) const { - return synced_setting_names_.contains(name) - ? kDevToolsSyncedPreferencesSyncEnabled - : kDevToolsPreferences; -} - -const char* InspectableWebContents::GetDictionaryNameForSyncedPrefs() const { - const bool isDevToolsSyncEnabled = - pref_service_->GetBoolean(kDevToolsSyncPreferences); - return isDevToolsSyncEnabled ? kDevToolsSyncedPreferencesSyncEnabled - : kDevToolsSyncedPreferencesSyncDisabled; -} - } // namespace electron diff --git a/shell/browser/ui/inspectable_web_contents.h b/shell/browser/ui/inspectable_web_contents.h index ba50d83b8aef4..bfc6cbae896d5 100644 --- a/shell/browser/ui/inspectable_web_contents.h +++ b/shell/browser/ui/inspectable_web_contents.h @@ -140,7 +140,7 @@ class InspectableWebContents const std::string& browser_id, const std::string& url) override; void RegisterPreference(const std::string& name, - const RegisterOptions& options) override; + const RegisterOptions& options) override {} void GetPreferences(DispatchCallback callback) override; void GetPreference(DispatchCallback callback, const std::string& name) override; @@ -198,9 +198,6 @@ class InspectableWebContents void SendMessageAck(int request_id, const base::Value* arg1); - const char* GetDictionaryNameForSettingsName(const std::string& name) const; - const char* GetDictionaryNameForSyncedPrefs() const; - #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) void AddDevToolsExtensionsToClient(); #endif diff --git a/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc b/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc index 3600e273ea73b..2e4e5bc9502e4 100644 --- a/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc +++ b/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc @@ -99,21 +99,4 @@ bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets( return false; } -bool ElectronDesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) { - // Call the default implementation of this method to get the event to its - // proper handler. - bool handled = views::DesktopWindowTreeHostWin::HandleMouseEvent(event); - - // On WCO-enabled windows, we need to mark non-client mouse moved events as - // handled so they don't incorrectly propogate back to the OS. - if (native_window_view_->IsWindowControlsOverlayEnabled() && - event->type() == ui::ET_MOUSE_MOVED && - (event->flags() & ui::EF_IS_NON_CLIENT) != 0) { - event->SetHandled(); - handled = true; - } - - return handled; -} - } // namespace electron diff --git a/shell/browser/ui/win/electron_desktop_window_tree_host_win.h b/shell/browser/ui/win/electron_desktop_window_tree_host_win.h index 8c7be1175a193..3fd831aae1ed0 100644 --- a/shell/browser/ui/win/electron_desktop_window_tree_host_win.h +++ b/shell/browser/ui/win/electron_desktop_window_tree_host_win.h @@ -36,7 +36,6 @@ class ElectronDesktopWindowTreeHostWin bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override; bool GetClientAreaInsets(gfx::Insets* insets, HMONITOR monitor) const override; - bool HandleMouseEvent(ui::MouseEvent* event) override; private: NativeWindowViews* native_window_view_; // weak ref diff --git a/shell/browser/web_contents_preferences.cc b/shell/browser/web_contents_preferences.cc index e54772a0bfce2..c7bdcbf362241 100644 --- a/shell/browser/web_contents_preferences.cc +++ b/shell/browser/web_contents_preferences.cc @@ -258,15 +258,6 @@ void WebContentsPreferences::Merge( } else { LOG(ERROR) << "preload script must have absolute path."; } - } else if (web_preferences.Get(options::kPreloadURL, &preload_url_str)) { - // Translate to file path if there is "preload-url" option. - base::FilePath preload; - GURL preload_url(preload_url_str); - if (net::FileURLToFilePath(preload_url, &preload)) { - preload_path_ = preload; - } else { - LOG(ERROR) << "preload url must be file:// protocol."; - } } std::string type; diff --git a/shell/browser/web_contents_preferences.h b/shell/browser/web_contents_preferences.h index 912540ac0aad0..544bc54a80e46 100644 --- a/shell/browser/web_contents_preferences.h +++ b/shell/browser/web_contents_preferences.h @@ -71,6 +71,9 @@ class WebContentsPreferences bool ShouldDisableHtmlFullscreenWindowResize() const { return disable_html_fullscreen_window_resize_; } + bool AllowsNodeIntegrationInSubFrames() const { + return node_integration_in_sub_frames_; + } bool ShouldDisableDialogs() const { return disable_dialogs_; } bool ShouldUseSafeDialogs() const { return safe_dialogs_; } bool GetSafeDialogsMessage(std::string* message) const; diff --git a/shell/common/api/api.mojom b/shell/common/api/api.mojom index 1206b5858a183..4515b82ac48d0 100644 --- a/shell/common/api/api.mojom +++ b/shell/common/api/api.mojom @@ -31,7 +31,21 @@ struct DraggableRegion { gfx.mojom.Rect bounds; }; -interface ElectronBrowser { +interface ElectronWebContentsUtility { + // Informs underlying WebContents that first non-empty layout was performed + // by compositor. + OnFirstNonEmptyLayout(); + + UpdateDraggableRegions( + array regions); + + SetTemporaryZoomLevel(double zoom_level); + + [Sync] + DoGetZoomLevel() => (double result); +}; + +interface ElectronApiIPC { // Emits an event on |channel| from the ipcMain JavaScript object in the main // process. Message( @@ -46,10 +60,6 @@ interface ElectronBrowser { string channel, blink.mojom.CloneableMessage arguments) => (blink.mojom.CloneableMessage result); - // Informs underlying WebContents that first non-empty layout was performed - // by compositor. - OnFirstNonEmptyLayout(); - ReceivePostMessage(string channel, blink.mojom.TransferableMessage message); // Emits an event on |channel| from the ipcMain JavaScript object in the main @@ -70,12 +80,4 @@ interface ElectronBrowser { MessageHost( string channel, blink.mojom.CloneableMessage arguments); - - UpdateDraggableRegions( - array regions); - - SetTemporaryZoomLevel(double zoom_level); - - [Sync] - DoGetZoomLevel() => (double result); }; diff --git a/shell/common/api/electron_api_native_image.cc b/shell/common/api/electron_api_native_image.cc index 3543a13585509..0dbda357a755c 100644 --- a/shell/common/api/electron_api_native_image.cc +++ b/shell/common/api/electron_api_native_image.cc @@ -109,7 +109,7 @@ base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) { NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) : image_(image), isolate_(isolate) { - AdjustAmountOfExternalAllocatedMemory(true); + UpdateExternalAllocatedMemoryUsage(); } #if BUILDFLAG(IS_WIN) @@ -120,22 +120,27 @@ NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path) electron::util::ReadImageSkiaFromICO(&image_skia, GetHICON(256)); image_ = gfx::Image(image_skia); - AdjustAmountOfExternalAllocatedMemory(true); + UpdateExternalAllocatedMemoryUsage(); } #endif NativeImage::~NativeImage() { - AdjustAmountOfExternalAllocatedMemory(false); + isolate_->AdjustAmountOfExternalAllocatedMemory(-memory_usage_); } -void NativeImage::AdjustAmountOfExternalAllocatedMemory(bool add) { +void NativeImage::UpdateExternalAllocatedMemoryUsage() { + int32_t new_memory_usage = 0; + if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) { auto* const image_skia = image_.ToImageSkia(); if (!image_skia->isNull()) { - int64_t size = image_skia->bitmap()->computeByteSize(); - isolate_->AdjustAmountOfExternalAllocatedMemory(add ? size : -size); + new_memory_usage = image_skia->bitmap()->computeByteSize(); } } + + isolate_->AdjustAmountOfExternalAllocatedMemory(new_memory_usage - + memory_usage_); + memory_usage_ = new_memory_usage; } // static diff --git a/shell/common/api/electron_api_native_image.h b/shell/common/api/electron_api_native_image.h index a322631f9cfe2..7be02ad27b7af 100644 --- a/shell/common/api/electron_api_native_image.h +++ b/shell/common/api/electron_api_native_image.h @@ -121,7 +121,7 @@ class NativeImage : public gin::Wrappable { float GetAspectRatio(const absl::optional scale_factor); void AddRepresentation(const gin_helper::Dictionary& options); - void AdjustAmountOfExternalAllocatedMemory(bool add); + void UpdateExternalAllocatedMemoryUsage(); // Mark the image as template image. void SetTemplateImage(bool setAsTemplate); @@ -136,6 +136,7 @@ class NativeImage : public gin::Wrappable { gfx::Image image_; v8::Isolate* isolate_; + int32_t memory_usage_ = 0; }; } // namespace api diff --git a/shell/common/gin_helper/event_emitter.cc b/shell/common/gin_helper/event_emitter.cc index 8779c05507ba1..32a3e4b1b8183 100644 --- a/shell/common/gin_helper/event_emitter.cc +++ b/shell/common/gin_helper/event_emitter.cc @@ -54,7 +54,7 @@ v8::Local CreateNativeEvent( v8::Isolate* isolate, v8::Local sender, content::RenderFrameHost* frame, - electron::mojom::ElectronBrowser::MessageSyncCallback callback) { + electron::mojom::ElectronApiIPC::MessageSyncCallback callback) { v8::Local event; if (frame && callback) { gin::Handle native_event = Event::Create(isolate); diff --git a/shell/common/gin_helper/event_emitter.h b/shell/common/gin_helper/event_emitter.h index a69b595551ffb..90af3f7478df4 100644 --- a/shell/common/gin_helper/event_emitter.h +++ b/shell/common/gin_helper/event_emitter.h @@ -29,7 +29,7 @@ v8::Local CreateNativeEvent( v8::Isolate* isolate, v8::Local sender, content::RenderFrameHost* frame, - electron::mojom::ElectronBrowser::MessageSyncCallback callback); + electron::mojom::ElectronApiIPC::MessageSyncCallback callback); } // namespace internal diff --git a/shell/common/gin_helper/trackable_object.h b/shell/common/gin_helper/trackable_object.h index 309e412e8a6f6..7f5b45c75fbcb 100644 --- a/shell/common/gin_helper/trackable_object.h +++ b/shell/common/gin_helper/trackable_object.h @@ -117,11 +117,11 @@ class TrackableObject : public TrackableObjectBase, public EventEmitter { ~TrackableObject() override { RemoveFromWeakMap(); } void InitWith(v8::Isolate* isolate, v8::Local wrapper) override { - gin_helper::WrappableBase::InitWith(isolate, wrapper); if (!weak_map_) { weak_map_ = new electron::KeyWeakMap; } weak_map_->Set(isolate, weak_map_id_, wrapper); + gin_helper::WrappableBase::InitWith(isolate, wrapper); } private: diff --git a/shell/common/options_switches.cc b/shell/common/options_switches.cc index 5ae559c437eb9..94ffb637ff124 100644 --- a/shell/common/options_switches.cc +++ b/shell/common/options_switches.cc @@ -120,9 +120,6 @@ const char kPreloadScript[] = "preload"; const char kPreloadScripts[] = "preloadScripts"; -// Like --preload, but the passed argument is an URL. -const char kPreloadURL[] = "preloadURL"; - // Enable the node integration. const char kNodeIntegration[] = "nodeIntegration"; diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h index cfe8a4a191ccc..d8f4819067911 100644 --- a/shell/common/options_switches.h +++ b/shell/common/options_switches.h @@ -66,7 +66,6 @@ extern const char kOverlayHeight[]; extern const char kZoomFactor[]; extern const char kPreloadScript[]; extern const char kPreloadScripts[]; -extern const char kPreloadURL[]; extern const char kNodeIntegration[]; extern const char kContextIsolation[]; extern const char kExperimentalFeatures[]; diff --git a/shell/renderer/api/electron_api_ipc_renderer.cc b/shell/renderer/api/electron_api_ipc_renderer.cc index 6b4f2698a968a..6f24ed17c4a3d 100644 --- a/shell/renderer/api/electron_api_ipc_renderer.cc +++ b/shell/renderer/api/electron_api_ipc_renderer.cc @@ -60,16 +60,16 @@ class IPCRenderer : public gin::Wrappable, weak_context_.SetWeak(); render_frame->GetRemoteAssociatedInterfaces()->GetInterface( - &electron_browser_remote_); + &electron_ipc_remote_); } - void OnDestruct() override { electron_browser_remote_.reset(); } + void OnDestruct() override { electron_ipc_remote_.reset(); } void WillReleaseScriptContext(v8::Local context, int32_t world_id) override { if (weak_context_.IsEmpty() || weak_context_.Get(context->GetIsolate()) == context) - electron_browser_remote_.reset(); + electron_ipc_remote_.reset(); } // gin::Wrappable: @@ -92,7 +92,7 @@ class IPCRenderer : public gin::Wrappable, bool internal, const std::string& channel, v8::Local arguments) { - if (!electron_browser_remote_) { + if (!electron_ipc_remote_) { thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError); return; } @@ -100,7 +100,7 @@ class IPCRenderer : public gin::Wrappable, if (!electron::SerializeV8Value(isolate, arguments, &message)) { return; } - electron_browser_remote_->Message(internal, channel, std::move(message)); + electron_ipc_remote_->Message(internal, channel, std::move(message)); } v8::Local Invoke(v8::Isolate* isolate, @@ -108,7 +108,7 @@ class IPCRenderer : public gin::Wrappable, bool internal, const std::string& channel, v8::Local arguments) { - if (!electron_browser_remote_) { + if (!electron_ipc_remote_) { thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError); return v8::Local(); } @@ -119,7 +119,7 @@ class IPCRenderer : public gin::Wrappable, gin_helper::Promise p(isolate); auto handle = p.GetHandle(); - electron_browser_remote_->Invoke( + electron_ipc_remote_->Invoke( internal, channel, std::move(message), base::BindOnce( [](gin_helper::Promise p, @@ -134,7 +134,7 @@ class IPCRenderer : public gin::Wrappable, const std::string& channel, v8::Local message_value, absl::optional> transfer) { - if (!electron_browser_remote_) { + if (!electron_ipc_remote_) { thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError); return; } @@ -166,8 +166,8 @@ class IPCRenderer : public gin::Wrappable, } transferable_message.ports = std::move(ports); - electron_browser_remote_->ReceivePostMessage( - channel, std::move(transferable_message)); + electron_ipc_remote_->ReceivePostMessage(channel, + std::move(transferable_message)); } void SendTo(v8::Isolate* isolate, @@ -175,7 +175,7 @@ class IPCRenderer : public gin::Wrappable, int32_t web_contents_id, const std::string& channel, v8::Local arguments) { - if (!electron_browser_remote_) { + if (!electron_ipc_remote_) { thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError); return; } @@ -183,15 +183,15 @@ class IPCRenderer : public gin::Wrappable, if (!electron::SerializeV8Value(isolate, arguments, &message)) { return; } - electron_browser_remote_->MessageTo(web_contents_id, channel, - std::move(message)); + electron_ipc_remote_->MessageTo(web_contents_id, channel, + std::move(message)); } void SendToHost(v8::Isolate* isolate, gin_helper::ErrorThrower thrower, const std::string& channel, v8::Local arguments) { - if (!electron_browser_remote_) { + if (!electron_ipc_remote_) { thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError); return; } @@ -199,7 +199,7 @@ class IPCRenderer : public gin::Wrappable, if (!electron::SerializeV8Value(isolate, arguments, &message)) { return; } - electron_browser_remote_->MessageHost(channel, std::move(message)); + electron_ipc_remote_->MessageHost(channel, std::move(message)); } v8::Local SendSync(v8::Isolate* isolate, @@ -207,7 +207,7 @@ class IPCRenderer : public gin::Wrappable, bool internal, const std::string& channel, v8::Local arguments) { - if (!electron_browser_remote_) { + if (!electron_ipc_remote_) { thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError); return v8::Local(); } @@ -217,14 +217,13 @@ class IPCRenderer : public gin::Wrappable, } blink::CloneableMessage result; - electron_browser_remote_->MessageSync(internal, channel, std::move(message), - &result); + electron_ipc_remote_->MessageSync(internal, channel, std::move(message), + &result); return electron::DeserializeV8Value(isolate, result); } v8::Global weak_context_; - mojo::AssociatedRemote - electron_browser_remote_; + mojo::AssociatedRemote electron_ipc_remote_; }; gin::WrapperInfo IPCRenderer::kWrapperInfo = {gin::kEmbedderNativeGin}; diff --git a/shell/renderer/api/electron_api_web_frame.cc b/shell/renderer/api/electron_api_web_frame.cc index 25d2b5433b680..6ec08e583da96 100644 --- a/shell/renderer/api/electron_api_web_frame.cc +++ b/shell/renderer/api/electron_api_web_frame.cc @@ -453,10 +453,11 @@ class WebFrameRenderer : public gin::Wrappable, if (!MaybeGetRenderFrame(isolate, "setZoomLevel", &render_frame)) return; - mojo::AssociatedRemote browser_remote; + mojo::AssociatedRemote + web_contents_utility_remote; render_frame->GetRemoteAssociatedInterfaces()->GetInterface( - &browser_remote); - browser_remote->SetTemporaryZoomLevel(level); + &web_contents_utility_remote); + web_contents_utility_remote->SetTemporaryZoomLevel(level); } double GetZoomLevel(v8::Isolate* isolate) { @@ -465,10 +466,11 @@ class WebFrameRenderer : public gin::Wrappable, if (!MaybeGetRenderFrame(isolate, "getZoomLevel", &render_frame)) return result; - mojo::AssociatedRemote browser_remote; + mojo::AssociatedRemote + web_contents_utility_remote; render_frame->GetRemoteAssociatedInterfaces()->GetInterface( - &browser_remote); - browser_remote->DoGetZoomLevel(&result); + &web_contents_utility_remote); + web_contents_utility_remote->DoGetZoomLevel(&result); return result; } diff --git a/shell/renderer/electron_render_frame_observer.cc b/shell/renderer/electron_render_frame_observer.cc index 4c763315f3539..2c22d1fceb62b 100644 --- a/shell/renderer/electron_render_frame_observer.cc +++ b/shell/renderer/electron_render_frame_observer.cc @@ -149,9 +149,11 @@ void ElectronRenderFrameObserver::DraggableRegionsChanged() { regions.push_back(std::move(region)); } - mojo::AssociatedRemote browser_remote; - render_frame_->GetRemoteAssociatedInterfaces()->GetInterface(&browser_remote); - browser_remote->UpdateDraggableRegions(std::move(regions)); + mojo::AssociatedRemote + web_contents_utility_remote; + render_frame_->GetRemoteAssociatedInterfaces()->GetInterface( + &web_contents_utility_remote); + web_contents_utility_remote->UpdateDraggableRegions(std::move(regions)); } void ElectronRenderFrameObserver::WillReleaseScriptContext( @@ -168,10 +170,11 @@ void ElectronRenderFrameObserver::OnDestruct() { void ElectronRenderFrameObserver::DidMeaningfulLayout( blink::WebMeaningfulLayout layout_type) { if (layout_type == blink::WebMeaningfulLayout::kVisuallyNonEmpty) { - mojo::AssociatedRemote browser_remote; + mojo::AssociatedRemote + web_contents_utility_remote; render_frame_->GetRemoteAssociatedInterfaces()->GetInterface( - &browser_remote); - browser_remote->OnFirstNonEmptyLayout(); + &web_contents_utility_remote); + web_contents_utility_remote->OnFirstNonEmptyLayout(); } } diff --git a/shell/renderer/electron_renderer_client.cc b/shell/renderer/electron_renderer_client.cc index 050732551da77..08276425938f3 100644 --- a/shell/renderer/electron_renderer_client.cc +++ b/shell/renderer/electron_renderer_client.cc @@ -151,18 +151,24 @@ void ElectronRendererClient::WillReleaseScriptContext( if (env == node_bindings_->uv_env()) node_bindings_->set_uv_env(nullptr); - // Destroy the node environment. We only do this if node support has been - // enabled for sub-frames to avoid a change-of-behavior / introduce crashes - // for existing users. - // We also do this if we have disable electron site instance overrides to - // avoid memory leaks - gin_helper::MicrotasksScope microtasks_scope(env->isolate()); + // Destroying the node environment will also run the uv loop, + // Node.js expects `kExplicit` microtasks policy and will run microtasks + // checkpoints after every call into JavaScript. Since we use a different + // policy in the renderer - switch to `kExplicit` and then drop back to the + // previous policy value. + v8::Isolate* isolate = context->GetIsolate(); + auto old_policy = isolate->GetMicrotasksPolicy(); + DCHECK_EQ(v8::MicrotasksScope::GetCurrentDepth(isolate), 0); + isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); + node::FreeEnvironment(env); if (node_bindings_->uv_env() == nullptr) { node::FreeIsolateData(node_bindings_->isolate_data()); node_bindings_->set_isolate_data(nullptr); } + isolate->SetMicrotasksPolicy(old_policy); + // ElectronBindings is tracking node environments. electron_bindings_->EnvironmentDestroyed(env); } diff --git a/shell/renderer/web_worker_observer.cc b/shell/renderer/web_worker_observer.cc index 287be9ead13f0..ca929bf9e4bb9 100644 --- a/shell/renderer/web_worker_observer.cc +++ b/shell/renderer/web_worker_observer.cc @@ -37,8 +37,13 @@ WebWorkerObserver::WebWorkerObserver() WebWorkerObserver::~WebWorkerObserver() { lazy_tls.Pointer()->Set(nullptr); - gin_helper::MicrotasksScope microtasks_scope( - node_bindings_->uv_env()->isolate()); + // Destroying the node environment will also run the uv loop, + // Node.js expects `kExplicit` microtasks policy and will run microtasks + // checkpoints after every call into JavaScript. Since we use a different + // policy in the renderer - switch to `kExplicit` + v8::Isolate* isolate = node_bindings_->uv_env()->isolate(); + DCHECK_EQ(v8::MicrotasksScope::GetCurrentDepth(isolate), 0); + isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); node::FreeEnvironment(node_bindings_->uv_env()); node::FreeIsolateData(node_bindings_->isolate_data()); } diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts index 1e9405e0aa3c8..89ff468ec5202 100644 --- a/spec-main/api-browser-window-spec.ts +++ b/spec-main/api-browser-window-spec.ts @@ -1816,6 +1816,18 @@ describe('BrowserWindow module', () => { expect(BrowserWindow.fromWebContents(webviewContents)!.id).to.equal(w.id); await p; }); + + it('is usable immediately on browser-window-created', async () => { + const w = new BrowserWindow({ show: false }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript('window.open(""); null'); + const [win, winFromWebContents] = await new Promise((resolve) => { + app.once('browser-window-created', (e, win) => { + resolve([win, BrowserWindow.fromWebContents(win.webContents)]); + }); + }); + expect(winFromWebContents).to.equal(win); + }); }); describe('BrowserWindow.openDevTools()', () => { @@ -3526,6 +3538,29 @@ describe('BrowserWindow module', () => { }); }); + // TODO(dsanders11): Enable once maximize event works on Linux again on CI + ifdescribe(process.platform !== 'linux')('BrowserWindow.maximize()', () => { + afterEach(closeAllWindows); + // TODO(dsanders11): Disabled on macOS, see https://github.com/electron/electron/issues/32947 + ifit(process.platform !== 'darwin')('should show the window if it is not currently shown', async () => { + const w = new BrowserWindow({ show: false }); + const hidden = emittedOnce(w, 'hide'); + const shown = emittedOnce(w, 'show'); + const maximize = emittedOnce(w, 'maximize'); + expect(w.isVisible()).to.be.false('visible'); + w.maximize(); + await maximize; + expect(w.isVisible()).to.be.true('visible'); + // Even if the window is already maximized + w.hide(); + await hidden; + expect(w.isVisible()).to.be.false('visible'); + w.maximize(); + await shown; // Ensure a 'show' event happens when it becomes visible + expect(w.isVisible()).to.be.true('visible'); + }); + }); + describe('BrowserWindow.unmaximize()', () => { afterEach(closeAllWindows); it('should restore the previous window position', () => { diff --git a/spec-main/api-session-spec.ts b/spec-main/api-session-spec.ts index 223d826d7eb84..f504d0db6d464 100644 --- a/spec-main/api-session-spec.ts +++ b/spec-main/api-session-spec.ts @@ -1121,6 +1121,20 @@ describe('session module', () => { }); }); + describe('session.setCodeCachePath()', () => { + it('throws when relative or empty path is provided', () => { + expect(() => { + session.defaultSession.setCodeCachePath('../fixtures'); + }).to.throw('Absolute path must be provided to store code cache.'); + expect(() => { + session.defaultSession.setCodeCachePath(''); + }).to.throw('Absolute path must be provided to store code cache.'); + expect(() => { + session.defaultSession.setCodeCachePath(path.join(app.getPath('userData'), 'test-code-cache')); + }).to.not.throw(); + }); + }); + describe('ses.setSSLConfig()', () => { it('can disable cipher suites', async () => { const ses = session.fromPartition('' + Math.random()); diff --git a/spec-main/fixtures/crash-cases/fs-promises-renderer-crash/index.html b/spec-main/fixtures/crash-cases/fs-promises-renderer-crash/index.html new file mode 100644 index 0000000000000..9721dac6ed821 --- /dev/null +++ b/spec-main/fixtures/crash-cases/fs-promises-renderer-crash/index.html @@ -0,0 +1,17 @@ + + + + + diff --git a/spec-main/fixtures/crash-cases/fs-promises-renderer-crash/index.js b/spec-main/fixtures/crash-cases/fs-promises-renderer-crash/index.js new file mode 100644 index 0000000000000..4c74ba39f74d6 --- /dev/null +++ b/spec-main/fixtures/crash-cases/fs-promises-renderer-crash/index.js @@ -0,0 +1,28 @@ +const { app, BrowserWindow, ipcMain } = require('electron'); +const path = require('path'); + +app.whenReady().then(() => { + let reloadCount = 0; + const win = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + } + }); + + win.loadFile('index.html'); + + win.webContents.on('render-process-gone', () => { + process.exit(1); + }); + + win.webContents.on('did-finish-load', () => { + if (reloadCount > 2) { + setImmediate(() => app.quit()); + } else { + reloadCount += 1; + win.webContents.send('reload', path.join(__dirname, '..', '..', 'cat.pdf')); + } + }); +}); diff --git a/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp b/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp index 00beb974c1a72..7e2438f5006d2 100644 --- a/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp +++ b/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp @@ -1,2 +1 @@ -extern "C" -void foo() { } \ No newline at end of file +extern "C" void foo() {} \ No newline at end of file diff --git a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp b/spec-main/fixtures/native-addon/uv-dlopen/main.cpp index 4d34850a6254c..5edef8a0ea627 100644 --- a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp +++ b/spec-main/fixtures/native-addon/uv-dlopen/main.cpp @@ -8,22 +8,26 @@ napi_value TestLoadLibrary(napi_env env, napi_callback_info info) { napi_value argv; napi_status status; status = napi_get_cb_info(env, info, &argc, &argv, NULL, NULL); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); char lib_path[256]; status = napi_get_value_string_utf8(env, argv, lib_path, 256, NULL); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); uv_lib_t lib; auto uv_status = uv_dlopen(lib_path, &lib); if (uv_status == 0) { napi_value result; status = napi_get_boolean(env, true, &result); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); return result; } else { status = napi_throw_error(env, NULL, uv_dlerror(&lib)); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); } } diff --git a/spec/static/main.js b/spec/static/main.js index 28ec06f524cc7..675c90fb42a9f 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -155,7 +155,6 @@ ipcMain.on('disable-preload-on-next-will-attach-webview', (event, id) => { event.sender.once('will-attach-webview', (event, webPreferences, params) => { params.src = `file://${path.join(__dirname, '..', 'fixtures', 'pages', 'webview-stripped-preload.html')}`; delete webPreferences.preload; - delete webPreferences.preloadURL; }); }); diff --git a/typings/internal-ambient.d.ts b/typings/internal-ambient.d.ts index 92d707c8edacc..c3b73935a2999 100644 --- a/typings/internal-ambient.d.ts +++ b/typings/internal-ambient.d.ts @@ -222,6 +222,7 @@ declare namespace NodeJS { isOnline(): boolean; isValidHeaderName: (headerName: string) => boolean; isValidHeaderValue: (headerValue: string) => boolean; + fileURLToFilePath: (url: string) => string; Net: any; net: any; createURLLoader(options: CreateURLLoaderOptions): URLLoader; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index a0d645440652f..49568925fa80b 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -97,7 +97,6 @@ declare namespace Electron { interface WebPreferences { disablePopups?: boolean; - preloadURL?: string; embedder?: Electron.WebContents; type?: 'backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'; }