mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
109 Commits
v16.0.0-be
...
v16.0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1ffac5969 | ||
|
|
0bb5f136f4 | ||
|
|
0027bd5979 | ||
|
|
41926c1773 | ||
|
|
bce34419b6 | ||
|
|
702645d84b | ||
|
|
facee77287 | ||
|
|
37ca29a27e | ||
|
|
03381c0281 | ||
|
|
71c8dd7028 | ||
|
|
0294075751 | ||
|
|
39bb2a4cbf | ||
|
|
d8ad2afcad | ||
|
|
9ef4825b77 | ||
|
|
6b0479b556 | ||
|
|
891374e794 | ||
|
|
de8623db8a | ||
|
|
ada1e9137b | ||
|
|
b6492686e4 | ||
|
|
0b57386492 | ||
|
|
ad1101e610 | ||
|
|
86cf473d81 | ||
|
|
26e37db25c | ||
|
|
3ddb61fc3a | ||
|
|
68a512a541 | ||
|
|
adb571bcde | ||
|
|
9183cf6a66 | ||
|
|
c5d5c28a79 | ||
|
|
59aba70e8f | ||
|
|
e640ab47fd | ||
|
|
fff7e18c70 | ||
|
|
569440962d | ||
|
|
bee9ff83dd | ||
|
|
41b7a0c9c2 | ||
|
|
cefa1bb82f | ||
|
|
eb7a897849 | ||
|
|
ac0143af8e | ||
|
|
6dc9d0629a | ||
|
|
187b009a70 | ||
|
|
040910b1d0 | ||
|
|
27a2f89b2b | ||
|
|
a3f736e655 | ||
|
|
8091d72019 | ||
|
|
8a2f487605 | ||
|
|
66dec80e48 | ||
|
|
ca946ac23e | ||
|
|
73ba0cb46b | ||
|
|
cf0b1e1b68 | ||
|
|
371a61dc59 | ||
|
|
4aef2d7cc3 | ||
|
|
ebd3360601 | ||
|
|
f1017d553d | ||
|
|
f6c16b4966 | ||
|
|
e029f65fe1 | ||
|
|
a2b79a2450 | ||
|
|
51d448c22d | ||
|
|
28230978e8 | ||
|
|
93ae6e3f73 | ||
|
|
b088673a5d | ||
|
|
a66d541471 | ||
|
|
beac90fba4 | ||
|
|
b4a6e0ad34 | ||
|
|
483d4fa603 | ||
|
|
358bffbcb0 | ||
|
|
dae224619f | ||
|
|
9110380ef6 | ||
|
|
00dff390ac | ||
|
|
16d3917334 | ||
|
|
2cc843737b | ||
|
|
fe248d310d | ||
|
|
b2ea9fd381 | ||
|
|
55a293cfaf | ||
|
|
e8ba44c632 | ||
|
|
ddab5ac3fc | ||
|
|
347f18a634 | ||
|
|
a2332646fa | ||
|
|
cdf312e16f | ||
|
|
445099073a | ||
|
|
05eb145d2b | ||
|
|
c16e94ebbf | ||
|
|
48be5c3387 | ||
|
|
9fd781073f | ||
|
|
c25edb5fdd | ||
|
|
cf6df4ae36 | ||
|
|
6729edf590 | ||
|
|
2415813313 | ||
|
|
136c539836 | ||
|
|
a76f2a07a9 | ||
|
|
8b6aecc6f0 | ||
|
|
3186a246a5 | ||
|
|
15ff515437 | ||
|
|
d3a24c24af | ||
|
|
f4a51e2adc | ||
|
|
cdc897c745 | ||
|
|
8c842552b0 | ||
|
|
e918fe6030 | ||
|
|
d9e0025429 | ||
|
|
5fc4a4768e | ||
|
|
cf54123ec6 | ||
|
|
948aa12af0 | ||
|
|
5fdf37eac9 | ||
|
|
1dcf237c8d | ||
|
|
8285172412 | ||
|
|
5735cb3cb0 | ||
|
|
1adea9e34e | ||
|
|
0cb6a2ea8a | ||
|
|
48e9e34acd | ||
|
|
1433180472 | ||
|
|
48a1117cbf |
2416
.circleci/build_config.yml
Normal file
2416
.circleci/build_config.yml
Normal file
File diff suppressed because it is too large
Load Diff
2524
.circleci/config.yml
2524
.circleci/config.yml
File diff suppressed because it is too large
Load Diff
4
BUILD.gn
4
BUILD.gn
@@ -420,7 +420,6 @@ source_set("electron_lib") {
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"chromium_src",
|
||||
".",
|
||||
"$target_gen_dir",
|
||||
|
||||
@@ -554,8 +553,9 @@ source_set("electron_lib") {
|
||||
"GLIB_DISABLE_DEPRECATION_WARNINGS",
|
||||
]
|
||||
|
||||
sources += filenames.lib_sources_nss
|
||||
sources += [
|
||||
"shell/browser/certificate_manager_model.cc",
|
||||
"shell/browser/certificate_manager_model.h",
|
||||
"shell/browser/ui/gtk/app_indicator_icon.cc",
|
||||
"shell/browser/ui/gtk/app_indicator_icon.h",
|
||||
"shell/browser/ui/gtk/app_indicator_icon_menu.cc",
|
||||
|
||||
2
DEPS
2
DEPS
@@ -15,7 +15,7 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'96.0.4664.18',
|
||||
'96.0.4664.110',
|
||||
'node_version':
|
||||
'v16.9.1',
|
||||
'nan_version':
|
||||
|
||||
@@ -1 +1 @@
|
||||
16.0.0-beta.4
|
||||
16.0.8
|
||||
@@ -15,6 +15,10 @@ static_library("chrome") {
|
||||
sources = [
|
||||
"//chrome/browser/accessibility/accessibility_ui.cc",
|
||||
"//chrome/browser/accessibility/accessibility_ui.h",
|
||||
"//chrome/browser/app_mode/app_mode_utils.cc",
|
||||
"//chrome/browser/app_mode/app_mode_utils.h",
|
||||
"//chrome/browser/browser_features.cc",
|
||||
"//chrome/browser/browser_features.h",
|
||||
"//chrome/browser/browser_process.cc",
|
||||
"//chrome/browser/browser_process.h",
|
||||
"//chrome/browser/devtools/devtools_contents_resizing_strategy.cc",
|
||||
@@ -51,6 +55,20 @@ static_library("chrome") {
|
||||
"//chrome/browser/process_singleton.h",
|
||||
"//chrome/browser/ui/browser_dialogs.cc",
|
||||
"//chrome/browser/ui/browser_dialogs.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_manager.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_manager.h",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_controller.h",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.cc",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h",
|
||||
"//chrome/browser/ui/exclusive_access/keyboard_lock_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/keyboard_lock_controller.h",
|
||||
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.h",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.cc",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper.cc",
|
||||
@@ -114,6 +132,7 @@ static_library("chrome") {
|
||||
"//components/keyed_service/content",
|
||||
"//components/paint_preview/buildflags",
|
||||
"//components/proxy_config",
|
||||
"//components/services/language_detection/public/mojom",
|
||||
"//content/public/browser",
|
||||
"//services/strings",
|
||||
]
|
||||
|
||||
@@ -59,10 +59,9 @@ an issue:
|
||||
* [Testing and Debugging](tutorial/application-debugging.md)
|
||||
* [Debugging the Main Process](tutorial/debugging-main-process.md)
|
||||
* [Debugging with Visual Studio Code](tutorial/debugging-vscode.md)
|
||||
* [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
|
||||
* [DevTools Extension](tutorial/devtools-extension.md)
|
||||
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
|
||||
* [Automated Testing](tutorial/automated-testing.md)
|
||||
* [REPL](tutorial/repl.md)
|
||||
* [Distribution](tutorial/application-distribution.md)
|
||||
* [Supported Platforms](tutorial/support.md#supported-platforms)
|
||||
|
||||
@@ -36,10 +36,10 @@ Returns:
|
||||
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the `NSUserNotification` or information from
|
||||
[`UNNotificationResponse`](structures/notification-response.md) that was used to open the
|
||||
application, if it was launched from Notification Center. You can also call
|
||||
`app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
|
||||
or information from [`UNNotificationResponse`](https://developer.apple.com/documentation/usernotifications/unnotificationresponse)
|
||||
that was used to open the application, if it was launched from Notification Center.
|
||||
You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
to get a Promise that is fulfilled when Electron is initialized.
|
||||
|
||||
### Event: 'window-all-closed'
|
||||
@@ -940,9 +940,9 @@ app.setJumpList([
|
||||
])
|
||||
```
|
||||
|
||||
### `app.requestSingleInstanceLock()`
|
||||
### `app.requestSingleInstanceLock([additionalData])`
|
||||
|
||||
* `additionalData` unknown (optional) - A JSON object containing additional data to send to the first instance.
|
||||
* `additionalData` Record<any, any> (optional) - A JSON object containing additional data to send to the first instance.
|
||||
|
||||
Returns `Boolean`
|
||||
|
||||
|
||||
@@ -15,14 +15,16 @@ Process: [Main](../glossary.md#main-process)
|
||||
|
||||
```javascript
|
||||
// In the main process.
|
||||
const { BrowserView, BrowserWindow } = require('electron')
|
||||
const { app, BrowserView, BrowserWindow } = require('electron')
|
||||
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
|
||||
const view = new BrowserView()
|
||||
win.setBrowserView(view)
|
||||
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
|
||||
view.webContents.loadURL('https://electronjs.org')
|
||||
const view = new BrowserView()
|
||||
win.setBrowserView(view)
|
||||
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
|
||||
view.webContents.loadURL('https://electronjs.org')
|
||||
})
|
||||
```
|
||||
|
||||
### `new BrowserView([options])` _Experimental_
|
||||
|
||||
@@ -559,7 +559,7 @@ Returns:
|
||||
|
||||
Emitted before the window is moved. On Windows, calling `event.preventDefault()` will prevent the window from being moved.
|
||||
|
||||
Note that this is only emitted when the window is being resized manually. Resizing the window with `setBounds`/`setSize` will not emit this event.
|
||||
Note that this is only emitted when the window is being moved manually. Moving the window with `setPosition`/`setBounds`/`center` will not emit this event.
|
||||
|
||||
#### Event: 'move'
|
||||
|
||||
@@ -999,7 +999,7 @@ APIs like `win.setSize`.
|
||||
is `true`). Default is `#FFF` (white).
|
||||
|
||||
Sets the background color of the window. See [Setting
|
||||
`backgroundColor`](#setting-backgroundcolor).
|
||||
`backgroundColor`](#setting-the-backgroundcolor-property).
|
||||
|
||||
#### `win.previewFile(path[, displayName])` _macOS_
|
||||
|
||||
@@ -1044,7 +1044,7 @@ Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `
|
||||
#### `win.getBackgroundColor()`
|
||||
|
||||
Returns `String` - Gets the background color of the window. See [Setting
|
||||
`backgroundColor`](#setting-backgroundcolor).
|
||||
`backgroundColor`](#setting-the-backgroundcolor-property).
|
||||
|
||||
#### `win.setContentBounds(bounds[, animate])`
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ Returns `Boolean` - Whether the clipboard supports the specified `format`.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const hasFormat = clipboard.has('<p>selection</p>')
|
||||
const hasFormat = clipboard.has('public/utf8-plain-text')
|
||||
console.log(hasFormat)
|
||||
// 'true' or 'false'
|
||||
```
|
||||
|
||||
@@ -102,8 +102,8 @@ has been included below for completeness:
|
||||
| `Boolean` | Simple | ✅ | ✅ | N/A |
|
||||
| `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. |
|
||||
| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type |
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context |
|
||||
| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. |
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) |
|
||||
| `Promise` | Complex | ✅ | ✅ | N/A
|
||||
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
|
||||
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
|
||||
| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. |
|
||||
|
||||
@@ -99,7 +99,7 @@ the response.
|
||||
* `expirationDate` Double (optional) - The expiration date of the cookie as the number of
|
||||
seconds since the UNIX epoch. If omitted then the cookie becomes a session
|
||||
cookie and will not be retained between sessions.
|
||||
* `sameSite` String (optional) - The [Same Site](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies) policy to apply to this cookie. Can be `unspecified`, `no_restriction`, `lax` or `strict`. Default is `no_restriction`.
|
||||
* `sameSite` String (optional) - The [Same Site](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies) policy to apply to this cookie. Can be `unspecified`, `no_restriction`, `lax` or `strict`. Default is `lax`.
|
||||
|
||||
Returns `Promise<void>` - A promise which resolves when the cookie has been set
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ Prints Chromium's internal logging to the console.
|
||||
|
||||
Setting this variable is the same as passing `--enable-logging`
|
||||
on the command line. For more info, see `--enable-logging` in [command-line
|
||||
switches](./command-line-switches.md#enable-loggingfile).
|
||||
switches](./command-line-switches.md#--enable-loggingfile).
|
||||
|
||||
### `ELECTRON_LOG_FILE`
|
||||
|
||||
@@ -130,7 +130,7 @@ Sets the file destination for Chromium's internal logging.
|
||||
|
||||
Setting this variable is the same as passing `--log-file`
|
||||
on the command line. For more info, see `--log-file` in [command-line
|
||||
switches](./command-line-switches.md#log-filepath).
|
||||
switches](./command-line-switches.md#--log-filepath).
|
||||
|
||||
### `ELECTRON_DEBUG_DRAG_REGIONS`
|
||||
|
||||
|
||||
@@ -903,8 +903,10 @@ setting with the current OS locale. This setting is persisted across restarts.
|
||||
By default Electron will download hunspell dictionaries from the Chromium CDN. If you want to override this
|
||||
behavior you can use this API to point the dictionary downloader at your own hosted version of the hunspell
|
||||
dictionaries. We publish a `hunspell_dictionaries.zip` file with each release which contains the files you need
|
||||
to host here, the file server must be **case insensitive** you must upload each file twice, once with the case it
|
||||
has in the ZIP file and once with the filename as all lower case.
|
||||
to host here.
|
||||
|
||||
The file server must be **case insensitive**. If you cannot do this, you must upload each file twice: once with
|
||||
the case it has in the ZIP file and once with the filename as all lowercase.
|
||||
|
||||
If the files present in `hunspell_dictionaries.zip` are available at `https://example.com/dictionaries/language-code.bdic`
|
||||
then you should call this api with `ses.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')`. Please
|
||||
|
||||
@@ -736,6 +736,8 @@ first available device will be selected. `callback` should be called with
|
||||
`deviceId` to be selected, passing empty string to `callback` will
|
||||
cancel the request.
|
||||
|
||||
If no event listener is added for this event, all bluetooth requests will be cancelled.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
@@ -1610,7 +1612,7 @@ app.whenReady().then(() => {
|
||||
|
||||
* `options` Object (optional)
|
||||
* `mode` String - Opens the devtools with specified dock state, can be
|
||||
`right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
|
||||
`left`, `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
|
||||
In `undocked` mode it's possible to dock back. In `detach` mode it's not.
|
||||
* `activate` Boolean (optional) - Whether to bring the opened devtools window
|
||||
to the foreground. The default is `true`.
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
`webFrame` export of the Electron module is an instance of the `WebFrame`
|
||||
class representing the top frame of the current `BrowserWindow`. Sub-frames can
|
||||
be retrieved by certain properties and methods (e.g. `webFrame.firstChild`).
|
||||
class representing the current frame. Sub-frames can be retrieved by
|
||||
certain properties and methods (e.g. `webFrame.firstChild`).
|
||||
|
||||
An example of zooming current page to 200%.
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
|
||||
`features` will be passed to any registered `webContents`'s
|
||||
`did-create-window` event handler in the `options` argument.
|
||||
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
|
||||
* When opening `about:blank`, the child window's `WebPreferences` will be copied
|
||||
from the parent window, and there is no way to override it because Chromium
|
||||
skips browser side navigation in this case.
|
||||
|
||||
To customize or cancel the creation of the window, you can optionally set an
|
||||
override handler with `webContents.setWindowOpenHandler()` from the main
|
||||
|
||||
@@ -43,8 +43,9 @@ SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\sym
|
||||
|
||||
## Using the symbol server in Visual Studio
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
## Troubleshooting: Symbols will not load
|
||||
|
||||
|
||||
BIN
docs/images/vs-options-debugging-symbols.png
Normal file
BIN
docs/images/vs-options-debugging-symbols.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/images/vs-tools-options.png
Normal file
BIN
docs/images/vs-tools-options.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -1,48 +1,7 @@
|
||||
# Accessibility
|
||||
|
||||
Making accessible applications is important and we're happy to provide
|
||||
functionality to [Devtron][devtron] and [Spectron][spectron] that gives
|
||||
developers the opportunity to make their apps better for everyone.
|
||||
|
||||
---
|
||||
|
||||
Accessibility concerns in Electron applications are similar to those of
|
||||
websites because they're both ultimately HTML. With Electron apps, however,
|
||||
you can't use the online resources for accessibility audits because your app
|
||||
doesn't have a URL to point the auditor to.
|
||||
|
||||
These features bring those auditing tools to your Electron app. You can
|
||||
choose to add audits to your tests with Spectron or use them within DevTools
|
||||
with Devtron. Read on for a summary of the tools.
|
||||
|
||||
## Spectron
|
||||
|
||||
In the testing framework Spectron, you can now audit each window and `<webview>`
|
||||
tag in your application. For example:
|
||||
|
||||
```javascript
|
||||
app.client.auditAccessibility().then((audit) => {
|
||||
if (audit.failed) {
|
||||
console.error(audit.message)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You can read more about this feature in [Spectron's documentation][spectron-a11y].
|
||||
|
||||
## Devtron
|
||||
|
||||
In Devtron, there is an accessibility tab which will allow you to audit a
|
||||
page in your app, sort and filter the results.
|
||||
|
||||
![devtron screenshot][devtron-screenshot]
|
||||
|
||||
Both of these tools are using the [Accessibility Developer Tools][a11y-devtools]
|
||||
library built by Google for Chrome. You can learn more about the accessibility
|
||||
audit rules this library uses on that [repository's wiki][a11y-devtools-wiki].
|
||||
|
||||
If you know of other great accessibility tools for Electron, add them to the
|
||||
accessibility documentation with a pull request.
|
||||
websites because they're both ultimately HTML.
|
||||
|
||||
## Manually enabling accessibility features
|
||||
|
||||
@@ -84,10 +43,6 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility");
|
||||
}
|
||||
```
|
||||
|
||||
[devtron]: https://electronjs.org/devtron
|
||||
[devtron-screenshot]: https://cloud.githubusercontent.com/assets/1305617/17156618/9f9bcd72-533f-11e6-880d-389115f40a2a.png
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
[spectron-a11y]: https://github.com/electron/spectron#accessibility-testing
|
||||
[a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology
|
||||
[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools
|
||||
[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
|
||||
|
||||
@@ -56,7 +56,7 @@ will then be your distribution to deliver to users.
|
||||
|
||||
### With an app source code archive
|
||||
|
||||
Instead of from shipping your app by copying all of its source files, you can
|
||||
Instead of shipping your app by copying all of its source files, you can
|
||||
package your app into an [asar] archive to improve the performance of reading
|
||||
files on platforms like Windows, if you are not already using a bundler such
|
||||
as Parcel or Webpack.
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
# Automated Testing with a Custom Driver
|
||||
|
||||
To write automated tests for your Electron app, you will need a way to "drive" your application. [Spectron](https://electronjs.org/spectron) is a commonly-used solution which lets you emulate user actions via [WebDriver](https://webdriver.io/). However, it's also possible to write your own custom driver using node's builtin IPC-over-STDIO. The benefit of a custom driver is that it tends to require less overhead than Spectron, and lets you expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [child_process](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js [process](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js
|
||||
// listen for IPC messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more high-level functions. Here is an example of how you can do this:
|
||||
|
||||
```js
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the app, you'd need to write a simple handler for the RPC calls:
|
||||
|
||||
```js
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your test-driver as follows:
|
||||
|
||||
```js
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
409
docs/tutorial/automated-testing.md
Normal file
409
docs/tutorial/automated-testing.md
Normal file
@@ -0,0 +1,409 @@
|
||||
# Automated Testing
|
||||
|
||||
Test automation is an efficient way of validating that your application code works as intended.
|
||||
While Electron doesn't actively maintain its own testing solution, this guide will go over a couple
|
||||
ways you can run end-to-end automated tests on your Electron app.
|
||||
|
||||
## Using the WebDriver interface
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
There are a few ways that you can set up testing using WebDriver.
|
||||
|
||||
### With WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) (WDIO) is a test automation framework that provides a
|
||||
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
|
||||
(e.g. reporter and services) that can help you put together your test setup.
|
||||
|
||||
#### Install the testrunner
|
||||
|
||||
First you need to run the WebdriverIO starter toolkit in your project root directory:
|
||||
|
||||
```sh npm2yarn
|
||||
npx wdio . --yes
|
||||
```
|
||||
|
||||
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
|
||||
|
||||
#### Connect WDIO to your Electron app
|
||||
|
||||
Update the capabilities in your configuration file to point to your Electron app binary:
|
||||
|
||||
```javascript title='wdio.conf.js'
|
||||
export.config = {
|
||||
// ...
|
||||
capabilities: [{
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Run your tests
|
||||
|
||||
To run your tests:
|
||||
|
||||
```sh
|
||||
$ npx wdio run wdio.conf.js
|
||||
```
|
||||
|
||||
### With Selenium
|
||||
|
||||
[Selenium](https://www.selenium.dev/) is a web automation framework that
|
||||
exposes bindings to WebDriver APIs in many languages. Their Node.js bindings
|
||||
are available under the `selenium-webdriver` package on NPM.
|
||||
|
||||
#### Run a ChromeDriver server
|
||||
|
||||
In order to use Selenium with Electron, you need to download the `electron-chromedriver`
|
||||
binary, and run it:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron-chromedriver
|
||||
./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later.
|
||||
|
||||
#### Connect Selenium to ChromeDriver
|
||||
|
||||
Next, install Selenium into your project:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev selenium-webdriver
|
||||
```
|
||||
|
||||
Usage of `selenium-webdriver` with Electron is the same as with
|
||||
normal websites, except that you have to manually specify how to connect
|
||||
ChromeDriver and where to find the binary of your Electron app:
|
||||
|
||||
```js title='test.js'
|
||||
const webdriver = require('selenium-webdriver')
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by ChromeDriver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Using Playwright
|
||||
|
||||
[Microsoft Playwright](https://playwright.dev) is an end-to-end testing framework built
|
||||
using browser-specific remote debugging protocols, similar to the [Puppeteer] headless
|
||||
Node.js API but geared towards end-to-end testing. Playwright has experimental Electron
|
||||
support via Electron's support for the [Chrome DevTools Protocol] (CDP).
|
||||
|
||||
### Install dependencies
|
||||
|
||||
You can install Playwright through your preferred Node.js package manager. The Playwright team
|
||||
recommends using the `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` environment variable to avoid
|
||||
unnecessary browser downloads when testing an Electron app.
|
||||
|
||||
```sh npm2yarn
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --save-dev playwright
|
||||
```
|
||||
|
||||
Playwright also comes with its own test runner, Playwright Test, which is built for end-to-end
|
||||
testing. You can also install it as a dev dependency in your project:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev @playwright/test
|
||||
```
|
||||
|
||||
:::caution Dependencies
|
||||
This tutorial was written `playwright@1.16.3` and `@playwright/test@1.16.3`. Check out
|
||||
[Playwright's releases][playwright-releases] page to learn about
|
||||
changes that might affect the code below.
|
||||
:::
|
||||
|
||||
:::info Using third-party test runners
|
||||
If you're interested in using an alternative test runner (e.g. Jest or Mocha), check out
|
||||
Playwright's [Third-Party Test Runner][playwright-test-runners] guide.
|
||||
:::
|
||||
|
||||
### Write your tests
|
||||
|
||||
Playwright launches your app in development mode through the `_electron.launch` API.
|
||||
To point this API to your Electron app, you can pass the path to your main process
|
||||
entry point (here, it is `main.js`).
|
||||
|
||||
```js {5}
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
|
||||
test('launch app', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
```
|
||||
|
||||
After that, you will access to an instance of Playwright's `ElectronApp` class. This
|
||||
is a powerful class that has access to main process modules for example:
|
||||
|
||||
```js {6-11}
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
|
||||
test('get isPackaged', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
const isPackaged = await electronApp.evaluate(async ({ app }) => {
|
||||
// This runs in Electron's main process, parameter here is always
|
||||
// the result of the require('electron') in the main app script.
|
||||
return app.isPackaged
|
||||
})
|
||||
console.log(isPackaged) // false (because we're in development mode)
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
```
|
||||
|
||||
It can also create individual [Page][playwright-page] objects from Electron BrowserWindow instances.
|
||||
For example, to grab the first BrowserWindow and save a screenshot:
|
||||
|
||||
```js {6-7}
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
|
||||
test('save screenshot', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
const window = await electronApp.firstWindow()
|
||||
await window.screenshot({ path: 'intro.png' })
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
```
|
||||
|
||||
Putting all this together using the PlayWright Test runner, let's create a `example.spec.js`
|
||||
test file with a single test and assertion:
|
||||
|
||||
```js title='example.spec.js'
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test, expect } = require('@playwright/test')
|
||||
|
||||
test('example test', async () => {
|
||||
const electronApp = await electron.launch({ args: ['.'] })
|
||||
const isPackaged = await electronApp.evaluate(async ({ app }) => {
|
||||
// This runs in Electron's main process, parameter here is always
|
||||
// the result of the require('electron') in the main app script.
|
||||
return app.isPackaged;
|
||||
});
|
||||
|
||||
expect(isPackaged).toBe(false);
|
||||
|
||||
// Wait for the first BrowserWindow to open
|
||||
// and return its Page object
|
||||
const window = await electronApp.firstWindow()
|
||||
await window.screenshot({ path: 'intro.png' })
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
});
|
||||
```
|
||||
|
||||
Then, run Playwright Test using `npx playwright test`. You should see the test pass in your
|
||||
console, and have an `intro.png` screenshot on your filesystem.
|
||||
|
||||
```console
|
||||
☁ $ npx playwright test
|
||||
|
||||
Running 1 test using 1 worker
|
||||
|
||||
✓ example.spec.js:4:1 › example test (1s)
|
||||
```
|
||||
|
||||
:::info
|
||||
Playwright Test will automatically run any files matching the `.*(test|spec)\.(js|ts|mjs)` regex.
|
||||
You can customize this match in the [Playwright Test configuration options][playwright-test-config].
|
||||
:::
|
||||
|
||||
:::tip Further reading
|
||||
Check out Playwright's documentation for the full [Electron][playwright-electron]
|
||||
and [ElectronApplication][playwright-electronapplication] class APIs.
|
||||
:::
|
||||
|
||||
## Using a custom test driver
|
||||
|
||||
It's also possible to write your own custom driver using Node.js' built-in IPC-over-STDIO.
|
||||
Custom test drivers require you to write additional app code, but have lower overhead and let you
|
||||
expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API.
|
||||
The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js title='testDriver.js'
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js
|
||||
[`process`](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js title='main.js'
|
||||
// listen for messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send a message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more
|
||||
high-level functions. Here is an example of how you can do this. Let's start by creating
|
||||
a `TestDriver` class:
|
||||
|
||||
```js title='testDriver.js'
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { TestDriver };
|
||||
```
|
||||
|
||||
In your app code, can then write a simple handler to receive RPC calls:
|
||||
|
||||
```js title='main.js'
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your `TestDriver` class with the test automation
|
||||
framework of your choosing. The following example uses
|
||||
[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest
|
||||
or Mocha would work as well:
|
||||
|
||||
```js title='test.js'
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
const { TestDriver } = require('./testDriver')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
|
||||
[chrome-driver]: https://sites.google.com/chromium.org/driver/
|
||||
[Puppeteer]: https://github.com/puppeteer/puppeteer
|
||||
[playwright-electron]: https://playwright.dev/docs/api/class-electron/
|
||||
[playwright-electronapplication]: https://playwright.dev/docs/api/class-electronapplication
|
||||
[playwright-page]: https://playwright.dev/docs/api/class-page
|
||||
[playwright-releases]: https://github.com/microsoft/playwright/releases
|
||||
[playwright-test-config]: https://playwright.dev/docs/api/class-testconfig#test-config-test-match
|
||||
[playwright-test-runners]: https://playwright.dev/docs/test-runners/
|
||||
[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/
|
||||
@@ -7,7 +7,7 @@ Special notes:
|
||||
* All dates are our goals but there may be reasons for adjusting the stable deadline, such as security bugs.
|
||||
* Take a look at the [5.0.0 Timeline blog post](https://electronjs.org/blog/electron-5-0-timeline) for info about publicizing our release dates.
|
||||
* Since Electron 6.0, we've been targeting every other Chromium version and releasing our stable on the same day as Chrome stable. You can reference Chromium's release schedule [here](https://chromiumdash.appspot.com/schedule). See [Electron's new release cadence blog post](https://www.electronjs.org/blog/12-week-cadence) for more details on our release schedule.
|
||||
* Electron 15.0 only will include a special Alpha release. Starting in Electron 16.0, we will release on an 8-week cadence. See [Electron's new 8-week cadence blog post](https://www.electronjs.org/blog/8-week-cadence) for more details.
|
||||
* Starting in Electron 16.0, we will release on an 8-week cadence. See [Electron's new 8-week cadence blog post](https://www.electronjs.org/blog/8-week-cadence) for more details.
|
||||
|
||||
| Electron | Alpha | Beta | Stable | Chrome | Node |
|
||||
| ------- | ----- | ------- | ------ | ------ | ---- |
|
||||
@@ -25,4 +25,5 @@ Special notes:
|
||||
| 13.0.0 | -- | 2021-Mar-04 | 2021-May-25 | M91 | v14.16 |
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | v14.17 |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | v16.5 |
|
||||
| 16.0.0 | -- | 2021-Sep-23 | 2021-Nov-16 | M96 | TBD |
|
||||
| 16.0.0 | 2021-Sep-23 | 2021-Oct-20 | 2021-Nov-16 | M96 | v16.9 |
|
||||
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | TBD |
|
||||
|
||||
@@ -91,7 +91,7 @@ The above configuration will download from URLs such as
|
||||
`https://npm.taobao.org/mirrors/electron/8.0.0/electron-v8.0.0-linux-x64.zip`.
|
||||
|
||||
If your mirror serves artifacts with different checksums to the official
|
||||
Electron release you may have to set `ELECTRON_USE_REMOTE_CHECKSUMS=1` to
|
||||
Electron release you may have to set `electron_use_remote_checksums=1` to
|
||||
force Electron to use the remote `SHASUMS256.txt` file to verify the checksum
|
||||
instead of the embedded checksums.
|
||||
|
||||
|
||||
@@ -56,4 +56,4 @@ problem. If not, feel free to fill out our bug report template and submit a new
|
||||
[comic]: https://www.google.com/googlebooks/chrome/
|
||||
[fiddle]: https://electronjs.org/fiddle
|
||||
[issue-tracker]: https://github.com/electron/electron/issues
|
||||
[discord]: https://discord.gg/electron
|
||||
[discord]: https://discord.gg/electronjs
|
||||
|
||||
@@ -119,7 +119,7 @@ of your project.
|
||||
|
||||
Before we can create a window for our application, we need to create the content that
|
||||
will be loaded into it. In Electron, each window displays web contents that can be loaded
|
||||
from either from a local HTML file or a remote URL.
|
||||
from either a local HTML file or a remote URL.
|
||||
|
||||
For this tutorial, you will be doing the former. Create an `index.html` file in the root
|
||||
folder of your project:
|
||||
|
||||
@@ -73,7 +73,7 @@ until the maintainers feel the maintenance burden is too high to continue doing
|
||||
* 16.x.y
|
||||
* 15.x.y
|
||||
* 14.x.y
|
||||
* 13
|
||||
* 13.x.y
|
||||
|
||||
### End-of-life
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
# Selenium and WebDriver
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
## Setting up Spectron
|
||||
|
||||
[Spectron][spectron] is the officially supported ChromeDriver testing framework
|
||||
for Electron. It is built on top of [WebdriverIO](https://webdriver.io/) and
|
||||
has helpers to access Electron APIs in your tests and bundles ChromeDriver.
|
||||
|
||||
```sh
|
||||
$ npm install --save-dev spectron
|
||||
```
|
||||
|
||||
```javascript
|
||||
// A simple test to verify a visible window is opened with a title
|
||||
const Application = require('spectron').Application
|
||||
const assert = require('assert')
|
||||
|
||||
const myApp = new Application({
|
||||
path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
|
||||
})
|
||||
|
||||
const verifyWindowIsVisibleWithTitle = async (app) => {
|
||||
await app.start()
|
||||
try {
|
||||
// Check if the window is visible
|
||||
const isVisible = await app.browserWindow.isVisible()
|
||||
// Verify the window is visible
|
||||
assert.strictEqual(isVisible, true)
|
||||
// Get the window's title
|
||||
const title = await app.client.getTitle()
|
||||
// Verify the window's title
|
||||
assert.strictEqual(title, 'My App')
|
||||
} catch (error) {
|
||||
// Log any failures
|
||||
console.error('Test failed', error.message)
|
||||
}
|
||||
// Stop the application
|
||||
await app.stop()
|
||||
}
|
||||
|
||||
verifyWindowIsVisibleWithTitle(myApp)
|
||||
```
|
||||
|
||||
## Setting up with WebDriverJs
|
||||
|
||||
[WebDriverJs](https://www.selenium.dev/selenium/docs/api/javascript/index.html) provides
|
||||
a Node package for testing with web driver, we will use it as an example.
|
||||
|
||||
### 1. Start ChromeDriver
|
||||
|
||||
First you need to download the `chromedriver` binary, and run it:
|
||||
|
||||
```sh
|
||||
$ npm install electron-chromedriver
|
||||
$ ./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later
|
||||
|
||||
### 2. Install WebDriverJS
|
||||
|
||||
```sh
|
||||
$ npm install selenium-webdriver
|
||||
```
|
||||
|
||||
### 3. Connect to ChromeDriver
|
||||
|
||||
The usage of `selenium-webdriver` with Electron is the same with
|
||||
upstream, except that you have to manually specify how to connect
|
||||
chrome driver and where to find Electron's binary:
|
||||
|
||||
```javascript
|
||||
const webdriver = require('selenium-webdriver')
|
||||
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by chrome driver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Setting up with WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) provides a Node package for testing with web
|
||||
driver.
|
||||
|
||||
### 1. Start ChromeDriver
|
||||
|
||||
First you need to download the `chromedriver` binary, and run it:
|
||||
|
||||
```sh
|
||||
$ npm install electron-chromedriver
|
||||
$ ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later
|
||||
|
||||
### 2. Install WebdriverIO
|
||||
|
||||
```sh
|
||||
$ npm install webdriverio
|
||||
```
|
||||
|
||||
### 3. Connect to chrome driver
|
||||
|
||||
```javascript
|
||||
const webdriverio = require('webdriverio')
|
||||
const options = {
|
||||
host: 'localhost', // Use localhost as chrome driver server
|
||||
port: 9515, // "9515" is the port opened by chrome driver.
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/Path-to-Your-App/electron', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const client = webdriverio.remote(options)
|
||||
|
||||
client
|
||||
.init()
|
||||
.url('http://google.com')
|
||||
.setValue('#q', 'webdriverio')
|
||||
.click('#btnG')
|
||||
.getTitle().then((title) => {
|
||||
console.log('Title was: ' + title)
|
||||
})
|
||||
.end()
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
To test your application without rebuilding Electron,
|
||||
[place](application-distribution.md)
|
||||
your app source into Electron's resource directory.
|
||||
|
||||
Alternatively, pass an argument to run with your Electron binary that points to
|
||||
your app's folder. This eliminates the need to copy-paste your app into
|
||||
Electron's resource directory.
|
||||
|
||||
[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
@@ -33,6 +33,23 @@
|
||||
{SCREEN_INDEX, plural, =1{Screen #} other{Screen #}}
|
||||
</message>
|
||||
|
||||
<!-- File Select Helper-->
|
||||
<message name="IDS_IMAGE_FILES" desc="The description of the image file extensions in the select file dialog.">
|
||||
Image Files
|
||||
</message>
|
||||
<message name="IDS_AUDIO_FILES" desc="The description of the audio file extensions in the select file dialog.">
|
||||
Audio Files
|
||||
</message>
|
||||
<message name="IDS_VIDEO_FILES" desc="The description of the video file extensions in the select file dialog.">
|
||||
Video Files
|
||||
</message>
|
||||
<message name="IDS_CUSTOM_FILES" desc="The description of the custom file extensions in the select file dialog.">
|
||||
Custom Files
|
||||
</message>
|
||||
<message name="IDS_DEFAULT_DOWNLOAD_FILENAME" desc="Default name for downloaded files when we have no idea what they could be.">
|
||||
download
|
||||
</message>
|
||||
|
||||
<!-- Picture-in-Picture -->
|
||||
<if expr="is_macosx">
|
||||
<message name="IDS_PICTURE_IN_PICTURE_TITLE_TEXT" desc="Title of the Picture-in-Picture window. This appears in the system tray and window header.">
|
||||
|
||||
@@ -675,11 +675,6 @@ filenames = {
|
||||
"shell/utility/electron_content_utility_client.h",
|
||||
]
|
||||
|
||||
lib_sources_nss = [
|
||||
"chromium_src/chrome/browser/certificate_manager_model.cc",
|
||||
"chromium_src/chrome/browser/certificate_manager_model.h",
|
||||
]
|
||||
|
||||
lib_sources_extensions = [
|
||||
"shell/browser/extensions/api/i18n/i18n_api.cc",
|
||||
"shell/browser/extensions/api/i18n/i18n_api.h",
|
||||
|
||||
@@ -669,16 +669,6 @@ WebContents.prototype._init = function () {
|
||||
postBody
|
||||
};
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
|
||||
// if attempting to use this API with the deprecated new-window event,
|
||||
// windowOpenOverriddenOptions will always return null. This ensures
|
||||
// short-term backwards compatibility until new-window is removed.
|
||||
const parsedFeatures = parseFeatures(rawFeatures);
|
||||
const overriddenFeatures: BrowserWindowConstructorOptions = {
|
||||
...parsedFeatures.options,
|
||||
webPreferences: parsedFeatures.webPreferences
|
||||
};
|
||||
windowOpenOverriddenOptions = windowOpenOverriddenOptions || overriddenFeatures;
|
||||
|
||||
if (!event.defaultPrevented) {
|
||||
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
|
||||
// Allow setting of backgroundColor as a webPreference even though
|
||||
@@ -688,9 +678,19 @@ WebContents.prototype._init = function () {
|
||||
transparent: windowOpenOverriddenOptions.transparent,
|
||||
...windowOpenOverriddenOptions.webPreferences
|
||||
} : undefined;
|
||||
this._setNextChildWebPreferences(
|
||||
makeWebPreferences({ embedder: event.sender, secureOverrideWebPreferences })
|
||||
);
|
||||
// TODO(zcbenz): The features string is parsed twice: here where it is
|
||||
// passed to C++, and in |makeBrowserWindowOptions| later where it is
|
||||
// not actually used since the WebContents is created here.
|
||||
// We should be able to remove the latter once the |nativeWindowOpen|
|
||||
// option is removed.
|
||||
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
|
||||
// Parameters should keep same with |makeBrowserWindowOptions|.
|
||||
const webPreferences = makeWebPreferences({
|
||||
embedder: event.sender,
|
||||
insecureParsedWebPreferences: parsedWebPreferences,
|
||||
secureOverrideWebPreferences
|
||||
});
|
||||
this._setNextChildWebPreferences(webPreferences);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -738,6 +738,14 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
});
|
||||
|
||||
this.on('select-bluetooth-device', (event, devices, callback) => {
|
||||
if (this.listenerCount('select-bluetooth-device') === 1) {
|
||||
// Cancel it if there are no handlers
|
||||
event.preventDefault();
|
||||
callback('');
|
||||
}
|
||||
});
|
||||
|
||||
const event = process._linkedBinding('electron_browser_event').createEmpty();
|
||||
app.emit('web-contents-created', event, this);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { webViewEvents } from '@electron/internal/common/web-view-events';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
interface GuestInstance {
|
||||
elementInstanceId: number;
|
||||
elementInstanceId?: number;
|
||||
visibilityState?: VisibilityState;
|
||||
embedder: Electron.WebContents;
|
||||
guest: Electron.WebContents;
|
||||
@@ -45,7 +45,6 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record<stri
|
||||
webSecurity: !params.disablewebsecurity,
|
||||
enableBlinkFeatures: params.blinkfeatures,
|
||||
disableBlinkFeatures: params.disableblinkfeatures,
|
||||
partition: params.partition,
|
||||
...parsedWebPreferences
|
||||
};
|
||||
|
||||
@@ -75,26 +74,27 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record<stri
|
||||
return webPreferences;
|
||||
}
|
||||
|
||||
function makeLoadURLOptions (params: Record<string, any>) {
|
||||
const opts: Electron.LoadURLOptions = {};
|
||||
if (params.httpreferrer) {
|
||||
opts.httpReferrer = params.httpreferrer;
|
||||
}
|
||||
if (params.useragent) {
|
||||
opts.userAgent = params.useragent;
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
// Create a new guest instance.
|
||||
const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
|
||||
const webPreferences = makeWebPreferences(embedder, params);
|
||||
const event = eventBinding.createWithSender(embedder);
|
||||
|
||||
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||
if (event.defaultPrevented) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const guest = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
...webPreferences,
|
||||
type: 'webview',
|
||||
partition: params.partition,
|
||||
embedder
|
||||
});
|
||||
|
||||
const guestInstanceId = guest.id;
|
||||
guestInstances.set(guestInstanceId, {
|
||||
elementInstanceId,
|
||||
guest,
|
||||
embedder
|
||||
});
|
||||
@@ -108,6 +108,9 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||
|
||||
// Init guest web view after attached.
|
||||
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
|
||||
const params = this.attachParams!;
|
||||
delete this.attachParams;
|
||||
|
||||
const previouslyAttached = this.viewInstanceId != null;
|
||||
this.viewInstanceId = params.instanceId;
|
||||
|
||||
@@ -117,14 +120,7 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||
}
|
||||
|
||||
if (params.src) {
|
||||
const opts: Electron.LoadURLOptions = {};
|
||||
if (params.httpreferrer) {
|
||||
opts.httpReferrer = params.httpreferrer;
|
||||
}
|
||||
if (params.useragent) {
|
||||
opts.userAgent = params.useragent;
|
||||
}
|
||||
this.loadURL(params.src, opts);
|
||||
this.loadURL(params.src, params.opts);
|
||||
}
|
||||
embedder.emit('did-attach-webview', event, guest);
|
||||
});
|
||||
@@ -177,25 +173,78 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||
}
|
||||
});
|
||||
|
||||
if (attachGuest(embedder, embedderFrameId, elementInstanceId, guestInstanceId, params)) {
|
||||
return guestInstanceId;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Attach the guest to an element of embedder.
|
||||
const attachGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, guestInstanceId: number, params: Record<string, any>) {
|
||||
// Destroy the old guest when attaching.
|
||||
const key = `${embedder.id}-${elementInstanceId}`;
|
||||
const oldGuestInstanceId = embedderElementsMap.get(key);
|
||||
if (oldGuestInstanceId != null) {
|
||||
// Reattachment to the same guest is just a no-op.
|
||||
if (oldGuestInstanceId === guestInstanceId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const oldGuestInstance = guestInstances.get(oldGuestInstanceId);
|
||||
if (oldGuestInstance) {
|
||||
oldGuestInstance.guest.detachFromOuterFrame();
|
||||
}
|
||||
}
|
||||
|
||||
const guestInstance = guestInstances.get(guestInstanceId);
|
||||
// If this isn't a valid guest instance then do nothing.
|
||||
if (!guestInstance) {
|
||||
console.error(new Error(`Guest attach failed: Invalid guestInstanceId ${guestInstanceId}`));
|
||||
return false;
|
||||
}
|
||||
const { guest } = guestInstance;
|
||||
if (guest.hostWebContents !== embedder) {
|
||||
console.error(new Error(`Guest attach failed: Access denied to guestInstanceId ${guestInstanceId}`));
|
||||
return false;
|
||||
}
|
||||
|
||||
const { instanceId } = params;
|
||||
|
||||
// If this guest is already attached to an element then remove it
|
||||
if (guestInstance.elementInstanceId) {
|
||||
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
|
||||
embedderElementsMap.delete(oldKey);
|
||||
|
||||
// Remove guest from embedder if moving across web views
|
||||
if (guest.viewInstanceId !== instanceId) {
|
||||
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
|
||||
guestInstance.embedder._sendInternal(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${guest.viewInstanceId}`);
|
||||
}
|
||||
}
|
||||
|
||||
const webPreferences = makeWebPreferences(embedder, params);
|
||||
|
||||
const event = eventBinding.createWithSender(embedder);
|
||||
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||
if (event.defaultPrevented) {
|
||||
if (guest.viewInstanceId == null) guest.viewInstanceId = instanceId;
|
||||
guest.destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
guest.attachParams = { instanceId, src: params.src, opts: makeLoadURLOptions(params) };
|
||||
embedderElementsMap.set(key, guestInstanceId);
|
||||
|
||||
guest.setEmbedder(embedder);
|
||||
guestInstance.embedder = embedder;
|
||||
guestInstance.elementInstanceId = elementInstanceId;
|
||||
|
||||
watchEmbedder(embedder);
|
||||
|
||||
webViewManager.addGuest(guestInstanceId, embedder, guest, webPreferences);
|
||||
guest.attachToIframe(embedder, embedderFrameId);
|
||||
|
||||
return guestInstanceId;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Remove an guest-embedder relationship.
|
||||
|
||||
@@ -217,6 +217,10 @@ function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: {
|
||||
height: 600,
|
||||
...parsedOptions,
|
||||
...overrideOptions,
|
||||
// Note that for |nativeWindowOpen: true| the WebContents is created in
|
||||
// |api::WebContents::WebContentsCreatedWithFullParams|, with prefs
|
||||
// parsed in the |-will-add-new-contents| event.
|
||||
// The |webPreferences| here is only used by |nativeWindowOpen: false|.
|
||||
webPreferences: makeWebPreferences({
|
||||
embedder,
|
||||
insecureParsedWebPreferences: parsedWebPreferences,
|
||||
|
||||
@@ -8,6 +8,7 @@ export const enum IPC_MESSAGES {
|
||||
|
||||
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
|
||||
|
||||
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
|
||||
GUEST_VIEW_INTERNAL_DISPATCH_EVENT = 'GUEST_VIEW_INTERNAL_DISPATCH_EVENT',
|
||||
|
||||
GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST',
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
export const enum IPC_MESSAGES {
|
||||
BROWSER_REQUIRE = 'REMOTE_BROWSER_REQUIRE',
|
||||
BROWSER_GET_BUILTIN = 'REMOTE_BROWSER_GET_BUILTIN',
|
||||
BROWSER_GET_GLOBAL = 'REMOTE_BROWSER_GET_GLOBAL',
|
||||
BROWSER_GET_CURRENT_WINDOW = 'REMOTE_BROWSER_GET_CURRENT_WINDOW',
|
||||
BROWSER_GET_CURRENT_WEB_CONTENTS = 'REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS',
|
||||
BROWSER_CONSTRUCTOR = 'REMOTE_BROWSER_CONSTRUCTOR',
|
||||
BROWSER_FUNCTION_CALL = 'REMOTE_BROWSER_FUNCTION_CALL',
|
||||
BROWSER_MEMBER_CONSTRUCTOR = 'REMOTE_BROWSER_MEMBER_CONSTRUCTOR',
|
||||
BROWSER_MEMBER_CALL = 'REMOTE_BROWSER_MEMBER_CALL',
|
||||
BROWSER_MEMBER_GET = 'REMOTE_BROWSER_MEMBER_GET',
|
||||
BROWSER_MEMBER_SET = 'REMOTE_BROWSER_MEMBER_SET',
|
||||
BROWSER_DEREFERENCE = 'REMOTE_BROWSER_DEREFERENCE',
|
||||
BROWSER_CONTEXT_RELEASE = 'REMOTE_BROWSER_CONTEXT_RELEASE',
|
||||
BROWSER_WRONG_CONTEXT_ERROR = 'REMOTE_BROWSER_WRONG_CONTEXT_ERROR',
|
||||
|
||||
RENDERER_CALLBACK = 'REMOTE_RENDERER_CALLBACK',
|
||||
RENDERER_RELEASE_CALLBACK = 'REMOTE_RENDERER_RELEASE_CALLBACK',
|
||||
}
|
||||
@@ -6,6 +6,7 @@ const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_fr
|
||||
|
||||
export interface GuestViewDelegate {
|
||||
dispatchEvent (eventName: string, props: Record<string, any>): void;
|
||||
reset(): void;
|
||||
}
|
||||
|
||||
const DEPRECATED_EVENTS: Record<string, string> = {
|
||||
@@ -13,6 +14,11 @@ const DEPRECATED_EVENTS: Record<string, string> = {
|
||||
} as const;
|
||||
|
||||
export function registerEvents (viewInstanceId: number, delegate: GuestViewDelegate) {
|
||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`, function () {
|
||||
delegate.reset();
|
||||
delegate.dispatchEvent('destroyed', {});
|
||||
});
|
||||
|
||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, props) {
|
||||
if (DEPRECATED_EVENTS[eventName] != null) {
|
||||
delegate.dispatchEvent(DEPRECATED_EVENTS[eventName], props);
|
||||
@@ -23,6 +29,7 @@ export function registerEvents (viewInstanceId: number, delegate: GuestViewDeleg
|
||||
}
|
||||
|
||||
export function deregisterEvents (viewInstanceId: number) {
|
||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`);
|
||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ const defineWebViewElement = (hooks: WebViewImplHooks) => {
|
||||
}
|
||||
if (!internal.elementAttached) {
|
||||
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
|
||||
dispatchEvent: internal.dispatchEvent.bind(internal)
|
||||
dispatchEvent: internal.dispatchEvent.bind(internal),
|
||||
reset: internal.reset.bind(internal)
|
||||
});
|
||||
internal.elementAttached = true;
|
||||
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();
|
||||
|
||||
@@ -25,7 +25,6 @@ export class WebViewImpl {
|
||||
public hasFocus = false
|
||||
public internalInstanceId?: number;
|
||||
public resizeObserver?: ResizeObserver;
|
||||
public userAgentOverride?: string;
|
||||
public viewInstanceId: number
|
||||
|
||||
// on* Event handlers.
|
||||
@@ -180,8 +179,7 @@ export class WebViewImpl {
|
||||
|
||||
buildParams () {
|
||||
const params: Record<string, any> = {
|
||||
instanceId: this.viewInstanceId,
|
||||
userAgentOverride: this.userAgentOverride
|
||||
instanceId: this.viewInstanceId
|
||||
};
|
||||
|
||||
for (const [attributeName, attribute] of this.attributes) {
|
||||
@@ -193,7 +191,7 @@ export class WebViewImpl {
|
||||
|
||||
attachGuestInstance (guestInstanceId: number) {
|
||||
if (guestInstanceId === -1) {
|
||||
this.dispatchEvent('destroyed');
|
||||
// Do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ if (isInstalled()) {
|
||||
const platform = process.env.npm_config_platform || process.platform;
|
||||
let arch = process.env.npm_config_arch || process.arch;
|
||||
|
||||
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64') {
|
||||
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64' &&
|
||||
process.env.npm_config_arch === undefined) {
|
||||
// When downloading for macOS ON macOS and we think we need x64 we should
|
||||
// check if we're running under rosetta and download the arm64 version if appropriate
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "16.0.0-beta.4",
|
||||
"version": "16.0.8",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
@@ -33,7 +33,7 @@
|
||||
"asar": "^3.1.0",
|
||||
"aws-sdk": "^2.727.1",
|
||||
"check-for-leaks": "^1.2.1",
|
||||
"colors": "^1.4.0",
|
||||
"colors": "1.4.0",
|
||||
"dotenv-safe": "^4.0.4",
|
||||
"dugite": "^1.103.0",
|
||||
"eslint": "^7.4.0",
|
||||
@@ -78,7 +78,7 @@
|
||||
"generate-version-json": "node script/generate-version-json.js",
|
||||
"lint": "node ./script/lint.js && npm run lint:clang-format && npm run lint:docs",
|
||||
"lint:js": "node ./script/lint.js --js",
|
||||
"lint:clang-format": "python script/run-clang-format.py -r -c chromium_src/ shell/ || (echo \"\\nCode not formatted correctly.\" && exit 1)",
|
||||
"lint:clang-format": "python script/run-clang-format.py -r -c shell/ || (echo \"\\nCode not formatted correctly.\" && exit 1)",
|
||||
"lint:clang-tidy": "ts-node ./script/run-clang-tidy.ts",
|
||||
"lint:cpp": "node ./script/lint.js --cc",
|
||||
"lint:objc": "node ./script/lint.js --objc",
|
||||
|
||||
@@ -106,6 +106,11 @@ feat_expose_raw_response_headers_from_urlloader.patch
|
||||
chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch
|
||||
process_singleton.patch
|
||||
fix_expose_decrementcapturercount_in_web_contents_impl.patch
|
||||
add_ui_scopedcliboardwriter_writeunsaferawdata.patch
|
||||
feat_add_data_parameter_to_processsingleton.patch
|
||||
mas_gate_private_enterprise_APIs
|
||||
mas_gate_private_enterprise_APIs.patch
|
||||
load_v8_snapshot_in_browser_process.patch
|
||||
fix_patch_out_permissions_checks_in_exclusive_access.patch
|
||||
fix_aspect_ratio_with_max_size.patch
|
||||
revert_do_not_display_grammar_error_if_there_it_overlaps_with_spell.patch
|
||||
fix_crash_when_saving_edited_pdf_files.patch
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Henri Torgemane <henrit@gmail.com>
|
||||
Date: Thu, 23 Sep 2021 21:30:33 -0500
|
||||
Subject: add ui::ScopedCliboardWriter::WriteUnsafeRawData
|
||||
|
||||
This restores some ability to write to the clipboard using raw formats, which
|
||||
was removed as part of the Raw Clipboard API scrubbing.
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=1217643
|
||||
|
||||
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
index 153f169d2cdef6f8a726c188283a5bc1b7395fa3..3a5d9ab8dafacafb1025e1cb8c157e8a82078424 100644
|
||||
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
@@ -212,6 +212,16 @@ void ScopedClipboardWriter::WriteData(const std::u16string& format,
|
||||
}
|
||||
}
|
||||
|
||||
+void ScopedClipboardWriter::WriteUnsafeRawData(const std::u16string& format,
|
||||
+ mojo_base::BigBuffer data) {
|
||||
+ static constexpr int kMaxRegisteredFormats = 100;
|
||||
+ if (counter_ >= kMaxRegisteredFormats)
|
||||
+ return;
|
||||
+ counter_++;
|
||||
+ platform_representations_.push_back(
|
||||
+ {base::UTF16ToUTF8(format), std::move(data)});
|
||||
+}
|
||||
+
|
||||
void ScopedClipboardWriter::Reset() {
|
||||
objects_.clear();
|
||||
platform_representations_.clear();
|
||||
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
index 879acd4f6f0101a6da3af58d78eeda877ea41a4a..4d4149b6aa34c7073804994cb1c03368830c736d 100644
|
||||
--- a/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
@@ -80,6 +80,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter {
|
||||
// This is only used to write custom format data.
|
||||
void WriteData(const std::u16string& format, mojo_base::BigBuffer data);
|
||||
|
||||
+ // write raw (non-pickled) data to the clipboard
|
||||
+ void WriteUnsafeRawData(const std::u16string& format,
|
||||
+ mojo_base::BigBuffer data);
|
||||
+
|
||||
void WriteImage(const SkBitmap& bitmap);
|
||||
|
||||
// Mark the data to be written as confidential.
|
||||
@@ -46,10 +46,10 @@ index 5016aa8bcbcc0c8db3e8e42b04ccef3552adda8b..21e92b783a9c9af54fb81174dddbc4a5
|
||||
}
|
||||
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index 4d70bcd96b49741114dadc6aabd653ed816f734a..5c813abcaaed1ba65d2865cddd4e219b2ead327e 100644
|
||||
index 3eb5f8189665090c95ba3f7c08c34b23062c7bf0..d2ed026101c464a03f7775034a8b2d3cfce8bb45 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -5499,7 +5499,6 @@ test("unit_tests") {
|
||||
@@ -5501,7 +5501,6 @@ test("unit_tests") {
|
||||
assert(toolkit_views)
|
||||
sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
|
||||
deps += [
|
||||
@@ -57,7 +57,7 @@ index 4d70bcd96b49741114dadc6aabd653ed816f734a..5c813abcaaed1ba65d2865cddd4e219b
|
||||
"//chrome/browser:chrome_process_finder",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner:public",
|
||||
@@ -5512,6 +5511,12 @@ test("unit_tests") {
|
||||
@@ -5514,6 +5513,12 @@ test("unit_tests") {
|
||||
"//components/chrome_cleaner/public/proto",
|
||||
"//ui/events/devices:test_support",
|
||||
]
|
||||
@@ -70,7 +70,7 @@ index 4d70bcd96b49741114dadc6aabd653ed816f734a..5c813abcaaed1ba65d2865cddd4e219b
|
||||
}
|
||||
|
||||
# TODO(crbug.com/931218): Ninja cannot handle certain characters appearing
|
||||
@@ -6109,7 +6114,6 @@ test("unit_tests") {
|
||||
@@ -6111,7 +6116,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
@@ -78,7 +78,7 @@ index 4d70bcd96b49741114dadc6aabd653ed816f734a..5c813abcaaed1ba65d2865cddd4e219b
|
||||
"//chrome/browser:cart_db_content_proto",
|
||||
"//chrome/browser:coupon_db_content_proto",
|
||||
"//chrome/browser/media/router:test_support",
|
||||
@@ -6149,6 +6153,9 @@ test("unit_tests") {
|
||||
@@ -6151,6 +6155,9 @@ test("unit_tests") {
|
||||
"//ui/native_theme:test_support",
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings",
|
||||
]
|
||||
|
||||
@@ -9,10 +9,10 @@ potentially prevent a window from being created.
|
||||
TODO(loc): this patch is currently broken.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 10c5c18955e585b688d25975f599a1ca92e661e3..cd911b2bf4bfd2a636d297cb00e43ad44ce4f1de 100644
|
||||
index 193bfd1abc5f9d97f79ded22617f1a9e110175fc..b68c5ee5bd719e15d952a48ff4bc8ef0046e361a 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -6503,6 +6503,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
@@ -6504,6 +6504,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
last_committed_origin_, params->window_container_type,
|
||||
params->target_url, params->referrer.To<Referrer>(),
|
||||
params->frame_name, params->disposition, *params->features,
|
||||
|
||||
@@ -9,7 +9,7 @@ we're running with contextIsolation enabled, we should be falling back
|
||||
to Blink's logic. This will be upstreamed in some form.
|
||||
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
|
||||
index f98a55b4afb91fba1db30a30fe76051539afd763..1c8d2fa6fe8978085b81b11443b8f8957edb6599 100644
|
||||
index 1e107193f25f1e76c9cf5d6df4241e4975b4f5f2..054166bbc2d8c6fd7bc62712a9765cc521d6d858 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
|
||||
@@ -448,7 +448,7 @@ CodeGenerationCheckCallbackInMainThread(v8::Local<v8::Context> context,
|
||||
|
||||
@@ -52,7 +52,7 @@ index 98cc4e039ba2b5a467175b15650a7b8ef38e8249..f5aea6a5916b9aa56ee7b81a8de97dc4
|
||||
const Source& GetSource(int index) const override;
|
||||
DesktopMediaList::Type GetMediaListType() const override;
|
||||
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
index c899b52ef01d2c9ea16b281a2b7c4d37f175fa36..a5fc476a52215eba33193012629ab1f73d679c88 100644
|
||||
index c899b52ef01d2c9ea16b281a2b7c4d37f175fa36..f752163d4e1951b2f79c7cc1cb4db51c0965472e 100644
|
||||
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
@@ -16,7 +16,7 @@
|
||||
@@ -72,12 +72,15 @@ index c899b52ef01d2c9ea16b281a2b7c4d37f175fa36..a5fc476a52215eba33193012629ab1f7
|
||||
const base::Feature kWindowCaptureMacV2{"WindowCaptureMacV2",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT};
|
||||
#endif
|
||||
@@ -427,6 +428,8 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows(
|
||||
@@ -427,6 +428,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows(
|
||||
FROM_HERE, base::BindOnce(&Worker::RefreshThumbnails,
|
||||
base::Unretained(worker_.get()),
|
||||
std::move(native_ids), thumbnail_size_));
|
||||
+ } else {
|
||||
+ OnRefreshComplete();
|
||||
+#if defined(USE_AURA)
|
||||
+ pending_native_thumbnail_capture_ = true;
|
||||
+#endif
|
||||
+ UpdateNativeThumbnailsFinished();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,10 +61,10 @@ index eec994c4252f17d9c9c41e66d5dae6509ed98a18..e538c9b76da4d4435e10cd3848438446
|
||||
#if defined(OS_WIN)
|
||||
bool EscapeVirtualization(const base::FilePath& user_data_dir);
|
||||
diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
|
||||
index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565a330b509 100644
|
||||
index 3dffe87e6a561826e7f90bce9727d830ce1c99be..495ca6c58970cdd3c19946cc1507efedd488afbc 100644
|
||||
--- a/chrome/browser/process_singleton_posix.cc
|
||||
+++ b/chrome/browser/process_singleton_posix.cc
|
||||
@@ -567,6 +567,7 @@ class ProcessSingleton::LinuxWatcher
|
||||
@@ -626,6 +626,7 @@ class ProcessSingleton::LinuxWatcher
|
||||
// |reader| is for sending back ACK message.
|
||||
void HandleMessage(const std::string& current_dir,
|
||||
const std::vector<std::string>& argv,
|
||||
@@ -72,7 +72,7 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
SocketReader* reader);
|
||||
|
||||
private:
|
||||
@@ -621,13 +622,16 @@ void ProcessSingleton::LinuxWatcher::StartListening(int socket) {
|
||||
@@ -680,13 +681,16 @@ void ProcessSingleton::LinuxWatcher::StartListening(int socket) {
|
||||
}
|
||||
|
||||
void ProcessSingleton::LinuxWatcher::HandleMessage(
|
||||
@@ -91,7 +91,7 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
// Send back "ACK" message to prevent the client process from starting up.
|
||||
reader->FinishWithACK(kACKToken, base::size(kACKToken) - 1);
|
||||
} else {
|
||||
@@ -675,7 +679,8 @@ void ProcessSingleton::LinuxWatcher::SocketReader::
|
||||
@@ -734,7 +738,8 @@ void ProcessSingleton::LinuxWatcher::SocketReader::
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
const size_t kMinMessageLength = base::size(kStartToken) + 4;
|
||||
if (bytes_read_ < kMinMessageLength) {
|
||||
buf_[bytes_read_] = 0;
|
||||
@@ -705,10 +710,25 @@ void ProcessSingleton::LinuxWatcher::SocketReader::
|
||||
@@ -764,10 +769,28 @@ void ProcessSingleton::LinuxWatcher::SocketReader::
|
||||
tokens.erase(tokens.begin());
|
||||
tokens.erase(tokens.begin());
|
||||
|
||||
@@ -110,13 +110,16 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
+ std::vector<std::string> command_line(tokens.begin() + 1, tokens.begin() + 1 + num_args);
|
||||
+
|
||||
+ std::vector<const uint8_t> additional_data;
|
||||
+ if (tokens.size() == 3 + num_args) {
|
||||
+ if (tokens.size() >= 3 + num_args) {
|
||||
+ size_t additional_data_size;
|
||||
+ base::StringToSizeT(tokens[1 + num_args], &additional_data_size);
|
||||
+ std::string remaining_args = base::JoinString(
|
||||
+ base::make_span(tokens.begin() + 2 + num_args, tokens.end()),
|
||||
+ std::string(1, kTokenDelimiter));
|
||||
+ const uint8_t* additional_data_bits =
|
||||
+ reinterpret_cast<const uint8_t*>(tokens[2 + num_args].c_str());
|
||||
+ additional_data = std::vector<const uint8_t>(additional_data_bits,
|
||||
+ additional_data_bits + additional_data_size);
|
||||
+ reinterpret_cast<const uint8_t*>(remaining_args.c_str());
|
||||
+ additional_data = std::vector<const uint8_t>(
|
||||
+ additional_data_bits, additional_data_bits + additional_data_size);
|
||||
+ }
|
||||
+
|
||||
// Return to the UI thread to handle opening a new browser tab.
|
||||
@@ -128,7 +131,7 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
fd_watch_controller_.reset();
|
||||
|
||||
// LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader
|
||||
@@ -737,8 +757,10 @@ void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK(
|
||||
@@ -796,8 +819,10 @@ void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK(
|
||||
//
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const base::FilePath& user_data_dir,
|
||||
@@ -139,7 +142,7 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
current_pid_(base::GetCurrentProcId()),
|
||||
watcher_(new LinuxWatcher(this)) {
|
||||
socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
|
||||
@@ -855,7 +877,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
@@ -914,7 +939,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
sizeof(socket_timeout));
|
||||
|
||||
// Found another process, prepare our command line
|
||||
@@ -149,7 +152,7 @@ index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565
|
||||
std::string to_send(kStartToken);
|
||||
to_send.push_back(kTokenDelimiter);
|
||||
|
||||
@@ -865,11 +888,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
@@ -924,11 +950,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
to_send.append(current_dir.value());
|
||||
|
||||
const std::vector<std::string>& argv = cmd_line.argv();
|
||||
|
||||
@@ -103,10 +103,10 @@ index cea1fb864ab46b4b0eabf1db11a0392d6cd575c1..df033f65d50b088778268827e506963a
|
||||
string mime_type;
|
||||
|
||||
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
|
||||
index 502003e72febe3fda800a8fd028fcfe29b876685..5b4193082d69cb9c0f904df9a9781b02bb3d2369 100644
|
||||
index 136427ff144f7ce23674f2b18e7deac5f5a5c8dd..94212b48f0a31de898f351c824b289c8c8e4dfad 100644
|
||||
--- a/services/network/url_loader.cc
|
||||
+++ b/services/network/url_loader.cc
|
||||
@@ -497,6 +497,7 @@ URLLoader::URLLoader(
|
||||
@@ -526,6 +526,7 @@ URLLoader::URLLoader(
|
||||
peer_closed_handle_watcher_(FROM_HERE,
|
||||
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
|
||||
base::SequencedTaskRunnerHandle::Get()),
|
||||
@@ -114,7 +114,7 @@ index 502003e72febe3fda800a8fd028fcfe29b876685..5b4193082d69cb9c0f904df9a9781b02
|
||||
devtools_request_id_(request.devtools_request_id),
|
||||
request_mode_(request.mode),
|
||||
request_credentials_mode_(request.credentials_mode),
|
||||
@@ -640,7 +641,7 @@ URLLoader::URLLoader(
|
||||
@@ -669,7 +670,7 @@ URLLoader::URLLoader(
|
||||
url_request_->SetRequestHeadersCallback(base::BindRepeating(
|
||||
&URLLoader::SetRawRequestHeadersAndNotify, base::Unretained(this)));
|
||||
|
||||
@@ -123,7 +123,7 @@ index 502003e72febe3fda800a8fd028fcfe29b876685..5b4193082d69cb9c0f904df9a9781b02
|
||||
url_request_->SetResponseHeadersCallback(base::BindRepeating(
|
||||
&URLLoader::SetRawResponseHeaders, base::Unretained(this)));
|
||||
}
|
||||
@@ -1269,6 +1270,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
|
||||
@@ -1299,6 +1300,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
|
||||
response_ = network::mojom::URLResponseHead::New();
|
||||
PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
|
||||
options_, response_.get());
|
||||
@@ -144,10 +144,10 @@ index 502003e72febe3fda800a8fd028fcfe29b876685..5b4193082d69cb9c0f904df9a9781b02
|
||||
// Parse and remove the Trust Tokens response headers, if any are expected,
|
||||
// potentially failing the request if an error occurs.
|
||||
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
|
||||
index d7f278d52db72d18fb779cf409ce8d70c9e32a17..d7e168a184df19d429db2cdc1db40651cb136d68 100644
|
||||
index f40ab2d8823e0b7f71b9ea7932d258022518e632..a36ab764380d542b060979763d20dbf65e1925b5 100644
|
||||
--- a/services/network/url_loader.h
|
||||
+++ b/services/network/url_loader.h
|
||||
@@ -472,6 +472,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
|
||||
@@ -497,6 +497,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
|
||||
std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
|
||||
resource_scheduler_request_handle_;
|
||||
|
||||
|
||||
38
patches/chromium/fix_aspect_ratio_with_max_size.patch
Normal file
38
patches/chromium/fix_aspect_ratio_with_max_size.patch
Normal file
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cezary Kulakowski <cezary@openfin.co>
|
||||
Date: Tue, 11 May 2021 11:14:06 +0200
|
||||
Subject: fix: fix aspect ratio when max width/height is set
|
||||
|
||||
Add the native frame border size to the minimum and maximum size if
|
||||
the view reports its size as the client size. It allows to enlarge
|
||||
window to proper values when aspect ratio and max width/height are
|
||||
set. It also fixes DCHECK which was triggered when user tried to
|
||||
enlarge window above dimensions set during creation of the
|
||||
BrowserWindow.
|
||||
|
||||
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
|
||||
index a235cab941ec583a8dc9cb5e4105c2d7baae02df..f7c1232b0893c366aeeb77e6df0bbd275b6f7bd4 100644
|
||||
--- a/ui/views/win/hwnd_message_handler.cc
|
||||
+++ b/ui/views/win/hwnd_message_handler.cc
|
||||
@@ -3569,6 +3569,21 @@ void HWNDMessageHandler::SizeWindowToAspectRatio(UINT param,
|
||||
delegate_->GetMinMaxSize(&min_window_size, &max_window_size);
|
||||
min_window_size = delegate_->DIPToScreenSize(min_window_size);
|
||||
max_window_size = delegate_->DIPToScreenSize(max_window_size);
|
||||
+ // Add the native frame border size to the minimum and maximum size if the
|
||||
+ // view reports its size as the client size.
|
||||
+ if (delegate_->WidgetSizeIsClientSize()) {
|
||||
+ RECT client_rect, rect;
|
||||
+ GetClientRect(hwnd(), &client_rect);
|
||||
+ GetWindowRect(hwnd(), &rect);
|
||||
+ CR_DEFLATE_RECT(&rect, &client_rect);
|
||||
+ min_window_size.Enlarge(rect.right - rect.left,
|
||||
+ rect.bottom - rect.top);
|
||||
+ // Either axis may be zero, so enlarge them independently.
|
||||
+ if (max_window_size.width())
|
||||
+ max_window_size.Enlarge(rect.right - rect.left, 0);
|
||||
+ if (max_window_size.height())
|
||||
+ max_window_size.Enlarge(0, rect.bottom - rect.top);
|
||||
+ }
|
||||
gfx::SizeRectToAspectRatio(GetWindowResizeEdge(param), aspect_ratio_.value(),
|
||||
min_window_size, max_window_size, window_rect);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 17 Jan 2022 23:47:54 +0100
|
||||
Subject: fix: crash when saving edited PDF files
|
||||
|
||||
This commit fixes a crash that persists any time a user attempts to
|
||||
download an edited PDF. This was happening because the logic flow for
|
||||
downloading of any edited PDF triggers a call to
|
||||
chrome.fileSystem.chooseEntry, which we do not support and which
|
||||
therefore causes unmapped page access crashes.
|
||||
|
||||
This patch can be removed should we choose to support chrome.fileSystem
|
||||
or support it enough to fix the crash.
|
||||
|
||||
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
|
||||
index 64308b73b70940187451f0475e4717def9f89cce..1888061bb7a5a6ae778d701aa554191288f20c87 100644
|
||||
--- a/chrome/browser/resources/pdf/pdf_viewer.js
|
||||
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
|
||||
@@ -976,25 +976,12 @@ export class PDFViewerElement extends PDFViewerBaseElement {
|
||||
dataArray = [result.dataToSave];
|
||||
}
|
||||
|
||||
+ const a = document.createElement('a');
|
||||
+ a.download = this.attachments_[index].name;
|
||||
const blob = new Blob(dataArray);
|
||||
- const fileName = this.attachments_[index].name;
|
||||
- chrome.fileSystem.chooseEntry(
|
||||
- {type: 'saveFile', suggestedName: fileName}, entry => {
|
||||
- if (chrome.runtime.lastError) {
|
||||
- if (chrome.runtime.lastError.message !== 'User cancelled') {
|
||||
- console.error(
|
||||
- 'chrome.fileSystem.chooseEntry failed: ' +
|
||||
- chrome.runtime.lastError.message);
|
||||
- }
|
||||
- return;
|
||||
- }
|
||||
- entry.createWriter(writer => {
|
||||
- writer.write(blob);
|
||||
- // Unblock closing the window now that the user has saved
|
||||
- // successfully.
|
||||
- chrome.mimeHandlerPrivate.setShowBeforeUnloadDialog(false);
|
||||
- });
|
||||
- });
|
||||
+ a.href = URL.createObjectURL(blob);
|
||||
+ a.click();
|
||||
+ URL.revokeObjectURL(a.href);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1122,29 +1109,12 @@ export class PDFViewerElement extends PDFViewerBaseElement {
|
||||
fileName = fileName + '.pdf';
|
||||
}
|
||||
|
||||
- chrome.fileSystem.chooseEntry(
|
||||
- {
|
||||
- type: 'saveFile',
|
||||
- accepts: [{description: '*.pdf', extensions: ['pdf']}],
|
||||
- suggestedName: fileName
|
||||
- },
|
||||
- entry => {
|
||||
- if (chrome.runtime.lastError) {
|
||||
- if (chrome.runtime.lastError.message !== 'User cancelled') {
|
||||
- console.error(
|
||||
- 'chrome.fileSystem.chooseEntry failed: ' +
|
||||
- chrome.runtime.lastError.message);
|
||||
- }
|
||||
- return;
|
||||
- }
|
||||
- entry.createWriter(writer => {
|
||||
- writer.write(
|
||||
- new Blob([result.dataToSave], {type: 'application/pdf'}));
|
||||
- // Unblock closing the window now that the user has saved
|
||||
- // successfully.
|
||||
- chrome.mimeHandlerPrivate.setShowBeforeUnloadDialog(false);
|
||||
- });
|
||||
- });
|
||||
+ const a = document.createElement('a');
|
||||
+ a.download = fileName;
|
||||
+ const blob = new Blob([result.dataToSave], {type: 'application/pdf'});
|
||||
+ a.href = URL.createObjectURL(blob);
|
||||
+ a.click();
|
||||
+ URL.revokeObjectURL(a.href);
|
||||
|
||||
// <if expr="enable_ink">
|
||||
// Saving in Annotation mode is destructive: crbug.com/919364
|
||||
@@ -59,67 +59,45 @@ index 554930bc33d87ee88a9bcc5f0cf17cef09c27ef0..8df4f91d3db453afb9f73bcaeb82c919
|
||||
// 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 5938f75742b793868638e693a9a8c8dc686dfc46..1263d679a5174beb960265989c370dd4a58ae7b4 100644
|
||||
index 5938f75742b793868638e693a9a8c8dc686dfc46..7f30f3fdd2c63612232e31c331b26b17ad729efb 100644
|
||||
--- a/content/browser/media/media_keys_listener_manager_impl.cc
|
||||
+++ b/content/browser/media/media_keys_listener_manager_impl.cc
|
||||
@@ -231,18 +231,24 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() {
|
||||
media::AudioManager::GetGlobalAppName());
|
||||
@@ -55,7 +55,12 @@ bool MediaKeysListenerManagerImpl::StartWatchingMediaKey(
|
||||
CanActiveMediaSessionControllerReceiveEvents();
|
||||
|
||||
// Tell the underlying MediaKeysListener to listen for the key.
|
||||
- if (should_start_watching && media_keys_listener_ &&
|
||||
+ if (
|
||||
+#if defined(OS_MAC)
|
||||
+ !media_key_handling_enabled_ &&
|
||||
+#endif // defined(OS_MAC)
|
||||
+ should_start_watching &&
|
||||
+ media_keys_listener_ &&
|
||||
!media_keys_listener_->StartWatchingMediaKey(key_code)) {
|
||||
return false;
|
||||
}
|
||||
@@ -232,18 +237,18 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() {
|
||||
#endif
|
||||
|
||||
- if (system_media_controls_) {
|
||||
- system_media_controls_->AddObserver(this);
|
||||
- system_media_controls_notifier_ =
|
||||
- std::make_unique<SystemMediaControlsNotifier>(
|
||||
- system_media_controls_.get());
|
||||
if (system_media_controls_) {
|
||||
+ // This is required for proper functioning of MediaMetadata.
|
||||
system_media_controls_->AddObserver(this);
|
||||
system_media_controls_notifier_ =
|
||||
std::make_unique<SystemMediaControlsNotifier>(
|
||||
system_media_controls_.get());
|
||||
- } else {
|
||||
- // If we can't access system media controls, then directly listen for media
|
||||
- // key keypresses instead.
|
||||
+ // This is required for proper functioning of MediaMetadata.
|
||||
+ system_media_controls_->AddObserver(this);
|
||||
+ system_media_controls_notifier_ =
|
||||
+ std::make_unique<SystemMediaControlsNotifier>(
|
||||
+ system_media_controls_.get());
|
||||
+
|
||||
+ // Directly listen for media key keypresses when using GlobalShortcuts.
|
||||
+#if defined(OS_MACOS)
|
||||
+ auto scope = media_key_handling_enabled_ ?
|
||||
+ ui::MediaKeysListener::Scope::kGlobal :
|
||||
+ ui::MediaKeysListener::Scope::kGlobalRequiresAccessibility;
|
||||
media_keys_listener_ = ui::MediaKeysListener::Create(
|
||||
- media_keys_listener_ = ui::MediaKeysListener::Create(
|
||||
- this, ui::MediaKeysListener::Scope::kGlobal);
|
||||
- DCHECK(media_keys_listener_);
|
||||
- }
|
||||
+ this, scope);
|
||||
+#else
|
||||
}
|
||||
|
||||
+ // Directly listen for media key keypresses when using GlobalShortcuts.
|
||||
+ media_keys_listener_ = ui::MediaKeysListener::Create(
|
||||
+ this, ui::MediaKeysListener::Scope::kGlobal);
|
||||
+#endif
|
||||
+ DCHECK(media_keys_listener_);
|
||||
|
||||
+
|
||||
EnsureAuxiliaryServices();
|
||||
}
|
||||
diff --git a/ui/base/accelerators/media_keys_listener.h b/ui/base/accelerators/media_keys_listener.h
|
||||
index c2b03328c0e508995bdc135031500783f500ceba..1b6b14dc2999c99445cef6ffc04d49a7c1728a54 100644
|
||||
--- a/ui/base/accelerators/media_keys_listener.h
|
||||
+++ b/ui/base/accelerators/media_keys_listener.h
|
||||
@@ -20,6 +20,7 @@ class Accelerator;
|
||||
class COMPONENT_EXPORT(UI_BASE) MediaKeysListener {
|
||||
public:
|
||||
enum class Scope {
|
||||
+ kGlobalRequiresAccessibility, // Listener works whenever application in focus or not but requires accessibility permissions on macOS
|
||||
kGlobal, // Listener works whenever application in focus or not.
|
||||
kFocused, // Listener only works whan application has focus.
|
||||
};
|
||||
diff --git a/ui/base/accelerators/media_keys_listener_win.cc b/ui/base/accelerators/media_keys_listener_win.cc
|
||||
index 6c63a88cbb13cfcc9a8ba652554839275ae1ee04..1643eafc094dce77e4ba8752cd02e1ae6c488b56 100644
|
||||
--- a/ui/base/accelerators/media_keys_listener_win.cc
|
||||
+++ b/ui/base/accelerators/media_keys_listener_win.cc
|
||||
@@ -13,7 +13,7 @@ std::unique_ptr<MediaKeysListener> MediaKeysListener::Create(
|
||||
MediaKeysListener::Scope scope) {
|
||||
DCHECK(delegate);
|
||||
|
||||
- if (scope == Scope::kGlobal) {
|
||||
+ if (scope == Scope::kGlobal || scope == Scope::kGlobalRequiresAccessibility) {
|
||||
// We should never have more than one global media keys listener.
|
||||
if (!GlobalMediaKeysListenerWin::has_instance())
|
||||
return std::make_unique<GlobalMediaKeysListenerWin>(delegate);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 25 Oct 2021 21:45:57 +0200
|
||||
Subject: fix: patch out permissions checks in exclusive_access
|
||||
|
||||
This patch is necessary in order to properly enable
|
||||
navigator.keyboard.{(un)?lock}() functionality. We don't have a concept
|
||||
of PermissionManager nor of a Profile, so this would not affect usage of
|
||||
the API.
|
||||
|
||||
We might consider potentially using our own permissions handler,
|
||||
but it's not strictly necessary for this API to work to spec.
|
||||
|
||||
Profile check has been upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3247196
|
||||
|
||||
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
index e9c8a4a4bb7334682ceeec05b3a3e872de0192ab..861307591f3721c398c454126cb5a9be9a5e9764 100644
|
||||
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
@@ -368,13 +368,9 @@ void FullscreenController::EnterFullscreenModeInternal(
|
||||
// Do not enter fullscreen mode if disallowed by pref. This prevents the user
|
||||
// from manually entering fullscreen mode and also disables kiosk mode on
|
||||
// desktop platforms.
|
||||
- if (!exclusive_access_manager()
|
||||
- ->context()
|
||||
- ->GetProfile()
|
||||
- ->GetPrefs()
|
||||
- ->GetBoolean(prefs::kFullscreenAllowed)) {
|
||||
+ auto* profile = exclusive_access_manager()->context()->GetProfile();
|
||||
+ if (!profile || !profile->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed))
|
||||
return;
|
||||
- }
|
||||
#endif
|
||||
|
||||
toggled_into_fullscreen_ = true;
|
||||
@@ -387,6 +383,7 @@ void FullscreenController::EnterFullscreenModeInternal(
|
||||
url = extension_caused_fullscreen_;
|
||||
}
|
||||
|
||||
+#if 0
|
||||
if (display_id != display::kInvalidDisplayId) {
|
||||
// Check, but do not prompt, for permission to request a specific screen.
|
||||
// Sites generally need permission to get the display id in the first place.
|
||||
@@ -400,6 +397,7 @@ void FullscreenController::EnterFullscreenModeInternal(
|
||||
display_id = display::kInvalidDisplayId;
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (option == BROWSER)
|
||||
base::RecordAction(base::UserMetricsAction("ToggleFullscreen"));
|
||||
@@ -6,10 +6,10 @@ Subject: frame_host_manager.patch
|
||||
Allows embedder to intercept site instances created by chromium.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
index 8d4a43dc12b06f5a39129acb5477a02844e74366..4d45e8ddeb90383dd7fe1e941c5868a72822cbe9 100644
|
||||
index d4a74c24605e1fc4e723f7252052cd123a8303b9..54772fce1a4204f545cecdd0e51c5a62b41bb14d 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
@@ -3070,6 +3070,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||
@@ -3078,6 +3078,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||
request->ResetStateForSiteInstanceChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ index 0282b3c04cf0281820b716d0991af5ac4d6304de..ad0da68df963cc0872dc545ef525128f
|
||||
// is concerned.
|
||||
@property(nonatomic, readonly) NSString* subrole;
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
|
||||
index 06e0766c6023768dc88f4d7deb28b1960c594ebb..980b855b6c52bdc39bf9e79e2b1618bd5d31c0cb 100644
|
||||
index 37530717d17ea339635bc390cf47e4adf601fff4..6281d3f75d34a13f35b69be6f8be952b422b544d 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
|
||||
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
|
||||
@@ -206,6 +206,7 @@
|
||||
@@ -391,7 +391,7 @@ index 06e0766c6023768dc88f4d7deb28b1960c594ebb..980b855b6c52bdc39bf9e79e2b1618bd
|
||||
if ([attribute
|
||||
isEqualToString:
|
||||
NSAccessibilityUIElementForTextMarkerParameterizedAttribute]) {
|
||||
@@ -3231,6 +3262,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute
|
||||
@@ -3233,6 +3264,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute
|
||||
|
||||
return CreateTextMarker(root->CreateTextPositionAt(index));
|
||||
}
|
||||
@@ -399,7 +399,7 @@ index 06e0766c6023768dc88f4d7deb28b1960c594ebb..980b855b6c52bdc39bf9e79e2b1618bd
|
||||
|
||||
if ([attribute isEqualToString:
|
||||
NSAccessibilityBoundsForRangeParameterizedAttribute]) {
|
||||
@@ -3261,6 +3293,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute
|
||||
@@ -3263,6 +3295,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ index 06e0766c6023768dc88f4d7deb28b1960c594ebb..980b855b6c52bdc39bf9e79e2b1618bd
|
||||
if ([attribute
|
||||
isEqualToString:
|
||||
NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute]) {
|
||||
@@ -3380,6 +3413,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute
|
||||
@@ -3382,6 +3415,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute
|
||||
|
||||
return @(child->GetIndexInParent());
|
||||
}
|
||||
@@ -415,7 +415,7 @@ index 06e0766c6023768dc88f4d7deb28b1960c594ebb..980b855b6c52bdc39bf9e79e2b1618bd
|
||||
|
||||
return nil;
|
||||
}
|
||||
@@ -3946,6 +3980,7 @@ - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
|
||||
@@ -3948,6 +3982,7 @@ - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
|
||||
->AsTextSelectionPosition()));
|
||||
}
|
||||
}
|
||||
@@ -423,7 +423,7 @@ index 06e0766c6023768dc88f4d7deb28b1960c594ebb..980b855b6c52bdc39bf9e79e2b1618bd
|
||||
if ([attribute
|
||||
isEqualToString:NSAccessibilitySelectedTextMarkerRangeAttribute]) {
|
||||
BrowserAccessibility::AXRange range = CreateRangeFromTextMarkerRange(value);
|
||||
@@ -3956,6 +3991,7 @@ - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
|
||||
@@ -3958,6 +3993,7 @@ - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
|
||||
range.anchor()->AsTextSelectionPosition(),
|
||||
range.focus()->AsTextSelectionPosition()));
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ index 51ebcb4ae399018d3fd8566656596a7ef1f148af..5f2b807fc364131f4c3e6a1646ec522d
|
||||
// Tells the RenderFrame to switch the CSS to print media type, render every
|
||||
// requested page using the print preview document's frame/node, and then
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
|
||||
index c16d8984805619f1f1382e1e5b932771fcc0f44b..7fe61be3b6139c73768d80bf9e8b6c8d4e38bb3b 100644
|
||||
index c16d8984805619f1f1382e1e5b932771fcc0f44b..01c18d78221bbb7fa26638d778d4a7d33264d129 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.cc
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.cc
|
||||
@@ -38,6 +38,7 @@
|
||||
@@ -547,18 +547,52 @@ index c16d8984805619f1f1382e1e5b932771fcc0f44b..7fe61be3b6139c73768d80bf9e8b6c8d
|
||||
// Check if |this| is still valid.
|
||||
if (!self)
|
||||
return;
|
||||
@@ -2173,7 +2188,9 @@ void PrintRenderFrameHelper::IPCProcessed() {
|
||||
@@ -2173,36 +2188,51 @@ void PrintRenderFrameHelper::IPCProcessed() {
|
||||
}
|
||||
}
|
||||
|
||||
-bool PrintRenderFrameHelper::InitPrintSettings(bool fit_to_paper_size) {
|
||||
- mojom::PrintPagesParams settings;
|
||||
- settings.params = mojom::PrintParams::New();
|
||||
- GetPrintManagerHost()->GetDefaultPrintSettings(&settings.params);
|
||||
+bool PrintRenderFrameHelper::InitPrintSettings(
|
||||
+ bool fit_to_paper_size,
|
||||
+ const base::DictionaryValue& new_settings) {
|
||||
mojom::PrintPagesParams settings;
|
||||
settings.params = mojom::PrintParams::New();
|
||||
GetPrintManagerHost()->GetDefaultPrintSettings(&settings.params);
|
||||
@@ -2197,12 +2214,14 @@ bool PrintRenderFrameHelper::InitPrintSettings(bool fit_to_paper_size) {
|
||||
+ mojom::PrintPagesParamsPtr settings;
|
||||
+
|
||||
+ if (new_settings.DictEmpty()) {
|
||||
+ settings = mojom::PrintPagesParams::New();
|
||||
+ settings->params = mojom::PrintParams::New();
|
||||
+ GetPrintManagerHost()->GetDefaultPrintSettings(&settings->params);
|
||||
+ } else {
|
||||
+ bool canceled = false;
|
||||
+ int cookie =
|
||||
+ print_pages_params_ ? print_pages_params_->params->document_cookie : 0;
|
||||
+ GetPrintManagerHost()->UpdatePrintSettings(cookie, new_settings.Clone(), &settings, &canceled);
|
||||
+ if (canceled)
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
// Check if the printer returned any settings, if the settings is empty, we
|
||||
// can safely assume there are no printer drivers configured. So we safely
|
||||
// terminate.
|
||||
bool result = true;
|
||||
- if (!PrintMsg_Print_Params_IsValid(*settings.params))
|
||||
+ if (!PrintMsg_Print_Params_IsValid(*settings->params))
|
||||
result = false;
|
||||
|
||||
// Reset to default values.
|
||||
ignore_css_margins_ = false;
|
||||
- settings.pages.clear();
|
||||
+ settings->pages.clear();
|
||||
|
||||
- settings.params->print_scaling_option =
|
||||
+ settings->params->print_scaling_option =
|
||||
fit_to_paper_size ? mojom::PrintScalingOption::kFitToPrintableArea
|
||||
: mojom::PrintScalingOption::kSourceSize;
|
||||
|
||||
- SetPrintPagesParams(settings);
|
||||
+ SetPrintPagesParams(*settings);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -577,7 +611,7 @@ index c16d8984805619f1f1382e1e5b932771fcc0f44b..7fe61be3b6139c73768d80bf9e8b6c8d
|
||||
notify_browser_of_print_failure_ = false;
|
||||
GetPrintManagerHost()->ShowInvalidPrinterSettingsError();
|
||||
return false;
|
||||
@@ -2573,18 +2592,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
|
||||
@@ -2573,18 +2603,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
|
||||
}
|
||||
|
||||
bool PrintRenderFrameHelper::CheckForCancel() {
|
||||
|
||||
@@ -76,10 +76,10 @@ index 0d7c1db6489d95a40c66808c3f838b0740e46ff6..eec994c4252f17d9c9c41e66d5dae650
|
||||
|
||||
#if defined(OS_MAC)
|
||||
diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
|
||||
index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf7c97f009 100644
|
||||
index f9f5a2a2240b8249f81e9fe95209ef651a09e88e..3dffe87e6a561826e7f90bce9727d830ce1c99be 100644
|
||||
--- a/chrome/browser/process_singleton_posix.cc
|
||||
+++ b/chrome/browser/process_singleton_posix.cc
|
||||
@@ -80,6 +80,7 @@
|
||||
@@ -82,6 +82,7 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@@ -87,7 +87,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
@@ -95,9 +96,11 @@
|
||||
@@ -97,9 +98,11 @@
|
||||
#include "net/base/network_interfaces.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
@@ -99,7 +99,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
|
||||
#if defined(TOOLKIT_VIEWS) && \
|
||||
(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
|
||||
@@ -289,6 +292,9 @@ bool SymlinkPath(const base::FilePath& target, const base::FilePath& path) {
|
||||
@@ -348,6 +351,9 @@ bool SymlinkPath(const base::FilePath& target, const base::FilePath& path) {
|
||||
bool DisplayProfileInUseError(const base::FilePath& lock_path,
|
||||
const std::string& hostname,
|
||||
int pid) {
|
||||
@@ -109,7 +109,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
std::u16string error = l10n_util::GetStringFUTF16(
|
||||
IDS_PROFILE_IN_USE_POSIX, base::NumberToString16(pid),
|
||||
base::ASCIIToUTF16(hostname));
|
||||
@@ -308,6 +314,7 @@ bool DisplayProfileInUseError(const base::FilePath& lock_path,
|
||||
@@ -367,6 +373,7 @@ bool DisplayProfileInUseError(const base::FilePath& lock_path,
|
||||
|
||||
NOTREACHED();
|
||||
return false;
|
||||
@@ -117,7 +117,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
}
|
||||
|
||||
bool IsChromeProcess(pid_t pid) {
|
||||
@@ -348,6 +355,21 @@ bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) {
|
||||
@@ -407,6 +414,21 @@ bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) {
|
||||
return (cookie == ReadLink(path));
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
bool ConnectSocket(ScopedSocket* socket,
|
||||
const base::FilePath& socket_path,
|
||||
const base::FilePath& cookie_path) {
|
||||
@@ -729,6 +751,10 @@ ProcessSingleton::ProcessSingleton(
|
||||
@@ -788,6 +810,10 @@ ProcessSingleton::ProcessSingleton(
|
||||
|
||||
ProcessSingleton::~ProcessSingleton() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
@@ -150,7 +150,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
}
|
||||
|
||||
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
|
||||
@@ -897,6 +923,20 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
|
||||
@@ -956,6 +982,20 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
|
||||
base::Seconds(kTimeoutInSeconds));
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
ProcessSingleton::NotifyResult
|
||||
ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
|
||||
const base::CommandLine& command_line,
|
||||
@@ -999,14 +1039,32 @@ bool ProcessSingleton::Create() {
|
||||
@@ -1055,14 +1095,32 @@ bool ProcessSingleton::Create() {
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf
|
||||
// Check that the directory was created with the correct permissions.
|
||||
int dir_mode = 0;
|
||||
CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) &&
|
||||
@@ -1046,10 +1104,13 @@ bool ProcessSingleton::Create() {
|
||||
@@ -1105,10 +1163,13 @@ bool ProcessSingleton::Create() {
|
||||
if (listen(sock, 5) < 0)
|
||||
NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: render_widget_host_view_base.patch
|
||||
... something to do with OSR? and maybe <webview> as well? terrifying.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
|
||||
index 9cddf7c7ba6c91b9800e04dbb2ff3f1553c64c5f..33ec9c904798ea316029bc86c8889b191e4eb6ed 100644
|
||||
index 97e76d6be1ccfcd26470bb6383d81d1b49f6c026..d7bcd8dabe2fe606568f238ba1aa8aa0b5b81270 100644
|
||||
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
|
||||
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
|
||||
@@ -666,6 +666,13 @@ bool RenderWidgetHostViewBase::ScreenRectIsUnstableFor(
|
||||
@@ -673,6 +673,13 @@ bool RenderWidgetHostViewBase::ScreenRectIsUnstableFor(
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Harrelson <chrishtr@chromium.org>
|
||||
Date: Wed, 1 Dec 2021 04:29:48 +0000
|
||||
Subject: Revert "Do not display grammar error if there it overlaps with spell
|
||||
check error"
|
||||
|
||||
This reverts commit 4f6e94d8d4e491c1119b447fe530450684ea701e.
|
||||
|
||||
Reason for revert: Caused performance issue 1271918.
|
||||
|
||||
Bug: 1271918
|
||||
|
||||
Original change's description:
|
||||
> Do not display grammar error if there it overlaps with spell check error
|
||||
>
|
||||
> Bug: 1249351
|
||||
> Change-Id: I8022f095e0d4e3dcc446205269faf87d0a8e8793
|
||||
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3159841
|
||||
> Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
|
||||
> Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
|
||||
> Commit-Queue: Jing Wang <jiwan@chromium.org>
|
||||
> Cr-Commit-Position: refs/heads/main@{#923692}
|
||||
|
||||
Bug: 1249351
|
||||
Change-Id: Ib348bcd087b39d933d4b00eb123cbc7ae8bb3507
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3309944
|
||||
Commit-Queue: Koji Ishii <kojii@chromium.org>
|
||||
Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
|
||||
Reviewed-by: Koji Ishii <kojii@chromium.org>
|
||||
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
|
||||
Reviewed-by: Jing Wang <jiwan@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#946860}
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
index 7955f2cb725ef4c011bbbce74820d98783d56a0c..fc2c236b8bb9c29cd720225bf14a014f61b01181 100644
|
||||
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
@@ -1627,18 +1627,10 @@ bool RenderWidgetHostViewAura::AddGrammarFragments(
|
||||
if (!input_handler || fragments.empty())
|
||||
return false;
|
||||
|
||||
- if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
|
||||
- return false;
|
||||
-
|
||||
unsigned max_fragment_end = 0;
|
||||
std::vector<::ui::ImeTextSpan> ime_text_spans;
|
||||
ime_text_spans.reserve(fragments.size());
|
||||
- bool conflict_with_spellcheck = false;
|
||||
for (auto& fragment : fragments) {
|
||||
- if (text_input_manager_->OverlapsWithSpellCheckMarker(fragment.range)) {
|
||||
- conflict_with_spellcheck = true;
|
||||
- break;
|
||||
- }
|
||||
ui::ImeTextSpan ui_ime_text_span;
|
||||
ui_ime_text_span.type = ui::ImeTextSpan::Type::kGrammarSuggestion;
|
||||
ui_ime_text_span.start_offset = fragment.range.start();
|
||||
@@ -1653,10 +1645,6 @@ bool RenderWidgetHostViewAura::AddGrammarFragments(
|
||||
max_fragment_end = fragment.range.end();
|
||||
}
|
||||
}
|
||||
-
|
||||
- if (conflict_with_spellcheck)
|
||||
- return false;
|
||||
-
|
||||
input_handler->AddImeTextSpansToExistingText(0, max_fragment_end,
|
||||
ime_text_spans);
|
||||
|
||||
diff --git a/content/browser/renderer_host/text_input_manager.cc b/content/browser/renderer_host/text_input_manager.cc
|
||||
index 9ad91a5388016e8c61e33fa6e411bf81193c363f..48b3b030604e93fa398ae0a076dd3ca817867172 100644
|
||||
--- a/content/browser/renderer_host/text_input_manager.cc
|
||||
+++ b/content/browser/renderer_host/text_input_manager.cc
|
||||
@@ -110,25 +110,6 @@ absl::optional<ui::GrammarFragment> TextInputManager::GetGrammarFragment(
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
-bool TextInputManager::OverlapsWithSpellCheckMarker(
|
||||
- const gfx::Range range) const {
|
||||
- if (!active_view_)
|
||||
- return false;
|
||||
-
|
||||
- for (const auto& ime_text_span_info :
|
||||
- text_input_state_map_.at(active_view_)->ime_text_spans_info) {
|
||||
- if (ime_text_span_info->span.type ==
|
||||
- ui::ImeTextSpan::Type::kMisspellingSuggestion) {
|
||||
- auto span_range = gfx::Range(ime_text_span_info->span.start_offset,
|
||||
- ime_text_span_info->span.end_offset);
|
||||
- if (span_range.Intersects(range)) {
|
||||
- return true;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- return false;
|
||||
-}
|
||||
-
|
||||
const TextInputManager::SelectionRegion* TextInputManager::GetSelectionRegion(
|
||||
RenderWidgetHostViewBase* view) const {
|
||||
DCHECK(!view || IsRegistered(view));
|
||||
diff --git a/content/browser/renderer_host/text_input_manager.h b/content/browser/renderer_host/text_input_manager.h
|
||||
index 3897bfb1fcddb3fc654cad6908b2b71f996742f9..7ae1cca25a32277596e525750db3e0ede324ca85 100644
|
||||
--- a/content/browser/renderer_host/text_input_manager.h
|
||||
+++ b/content/browser/renderer_host/text_input_manager.h
|
||||
@@ -164,10 +164,6 @@ class CONTENT_EXPORT TextInputManager {
|
||||
absl::optional<ui::GrammarFragment> GetGrammarFragment(
|
||||
gfx::Range range) const;
|
||||
|
||||
- // Returns if the given |range| is overlapping with any existing spellcheck
|
||||
- // markers.
|
||||
- bool OverlapsWithSpellCheckMarker(const gfx::Range range) const;
|
||||
-
|
||||
// Returns the selection bounds information for |view|. If |view| == nullptr,
|
||||
// it will return the corresponding information for |active_view_| or nullptr
|
||||
// if there are no active views.
|
||||
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
|
||||
index dff8822003328b8d2b0579c6558547e27a847ff3..42e47ac1c4e96ac24f9820dc719bf88b6f83cf71 100644
|
||||
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
|
||||
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
|
||||
@@ -1848,44 +1848,30 @@ WebVector<ui::ImeTextSpan> InputMethodController::GetImeTextSpans() const {
|
||||
const HeapVector<std::pair<Member<const Text>, Member<DocumentMarker>>>&
|
||||
node_marker_pairs = GetDocument().Markers().MarkersIntersectingRange(
|
||||
ToEphemeralRangeInFlatTree(range),
|
||||
- DocumentMarker::MarkerTypes::Suggestion().Add(
|
||||
- DocumentMarker::MarkerTypes::Spelling()));
|
||||
+ DocumentMarker::MarkerTypes::Suggestion());
|
||||
|
||||
for (const std::pair<Member<const Text>, Member<DocumentMarker>>&
|
||||
node_marker_pair : node_marker_pairs) {
|
||||
- DocumentMarker* marker = node_marker_pair.second.Get();
|
||||
- const Text* node = node_marker_pair.first;
|
||||
- const EphemeralRange& marker_ephemeral_range =
|
||||
- EphemeralRange(Position(node, marker->StartOffset()),
|
||||
- Position(node, marker->EndOffset()));
|
||||
- const PlainTextRange& marker_plain_text_range =
|
||||
- cached_text_input_info_.GetPlainTextRange(marker_ephemeral_range);
|
||||
-
|
||||
- if (DocumentMarker::MarkerTypes::Spelling().Contains(
|
||||
- node_marker_pair.second.Get()->GetType())) {
|
||||
+ SuggestionMarker* marker =
|
||||
+ To<SuggestionMarker>(node_marker_pair.second.Get());
|
||||
+ ImeTextSpan::Type type =
|
||||
+ ConvertSuggestionMarkerType(marker->GetSuggestionType());
|
||||
+ if (ShouldGetImeTextSpans(type)) {
|
||||
+ const Text* node = node_marker_pair.first;
|
||||
+ const EphemeralRange& marker_ephemeral_range =
|
||||
+ EphemeralRange(Position(node, marker->StartOffset()),
|
||||
+ Position(node, marker->EndOffset()));
|
||||
+ const PlainTextRange& marker_plain_text_range =
|
||||
+ cached_text_input_info_.GetPlainTextRange(marker_ephemeral_range);
|
||||
+
|
||||
ime_text_spans.emplace_back(
|
||||
- ImeTextSpan(ImeTextSpan::Type::kMisspellingSuggestion,
|
||||
- marker_plain_text_range.Start(),
|
||||
+ ImeTextSpan(type, marker_plain_text_range.Start(),
|
||||
marker_plain_text_range.End(), Color::kTransparent,
|
||||
ImeTextSpanThickness::kNone,
|
||||
ImeTextSpanUnderlineStyle::kNone, Color::kTransparent,
|
||||
- Color::kTransparent)
|
||||
+ Color::kTransparent, Color::kTransparent, false, false,
|
||||
+ marker->Suggestions())
|
||||
.ToUiImeTextSpan());
|
||||
- } else {
|
||||
- SuggestionMarker* suggestion_marker =
|
||||
- To<SuggestionMarker>(node_marker_pair.second.Get());
|
||||
- ImeTextSpan::Type type =
|
||||
- ConvertSuggestionMarkerType(suggestion_marker->GetSuggestionType());
|
||||
- if (ShouldGetImeTextSpans(type)) {
|
||||
- ime_text_spans.emplace_back(
|
||||
- ImeTextSpan(type, marker_plain_text_range.Start(),
|
||||
- marker_plain_text_range.End(), Color::kTransparent,
|
||||
- ImeTextSpanThickness::kNone,
|
||||
- ImeTextSpanUnderlineStyle::kNone, Color::kTransparent,
|
||||
- Color::kTransparent, Color::kTransparent, false, false,
|
||||
- suggestion_marker->Suggestions())
|
||||
- .ToUiImeTextSpan());
|
||||
- }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
|
||||
index e15e2c2cb61f110cfd68e593a87e8b3024e45de7..a86b50fce11f06466a13d62696050b456d9f2c81 100644
|
||||
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
|
||||
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
|
||||
@@ -208,8 +208,8 @@ TEST_F(InputMethodControllerTest, AddImeTextSpansToExistingText) {
|
||||
}
|
||||
|
||||
TEST_F(InputMethodControllerTest, GetImeTextSpans) {
|
||||
- Element* div = InsertHTMLElement(
|
||||
- "<div id='sample' contenteditable>hello world</div>", "sample");
|
||||
+ InsertHTMLElement("<div id='sample' contenteditable>hello world</div>",
|
||||
+ "sample");
|
||||
ImeTextSpan span1 = ImeTextSpan(ImeTextSpan::Type::kAutocorrect, 0, 5,
|
||||
Color(255, 0, 0), ImeTextSpanThickness::kThin,
|
||||
ImeTextSpanUnderlineStyle::kSolid, 0, 0);
|
||||
@@ -226,31 +226,22 @@ TEST_F(InputMethodControllerTest, GetImeTextSpans) {
|
||||
|
||||
Controller().AddImeTextSpansToExistingText({span1, span2, span3, span4}, 0,
|
||||
10);
|
||||
- GetFrame().GetDocument()->Markers().AddSpellingMarker(
|
||||
- PlainTextRange(4, 6).CreateRange(*div));
|
||||
Controller().SetEditableSelectionOffsets(PlainTextRange(1, 1));
|
||||
|
||||
const WebVector<ui::ImeTextSpan>& ime_text_spans =
|
||||
Controller().TextInputInfo().ime_text_spans;
|
||||
|
||||
- EXPECT_EQ(3u, ime_text_spans.size());
|
||||
-
|
||||
- EXPECT_EQ(4u, ime_text_spans[0].start_offset);
|
||||
- EXPECT_EQ(6u, ime_text_spans[0].end_offset);
|
||||
- EXPECT_EQ(ui::ImeTextSpan::Type::kMisspellingSuggestion,
|
||||
- ime_text_spans[0].type);
|
||||
+ EXPECT_EQ(2u, ime_text_spans.size());
|
||||
+ EXPECT_EQ(0u, ime_text_spans[0].start_offset);
|
||||
+ EXPECT_EQ(5u, ime_text_spans[0].end_offset);
|
||||
+ EXPECT_EQ(ui::ImeTextSpan::Type::kAutocorrect, ime_text_spans[0].type);
|
||||
EXPECT_EQ(0u, ime_text_spans[0].suggestions.size());
|
||||
|
||||
- EXPECT_EQ(0u, ime_text_spans[1].start_offset);
|
||||
- EXPECT_EQ(5u, ime_text_spans[1].end_offset);
|
||||
- EXPECT_EQ(ui::ImeTextSpan::Type::kAutocorrect, ime_text_spans[1].type);
|
||||
- EXPECT_EQ(0u, ime_text_spans[1].suggestions.size());
|
||||
-
|
||||
- EXPECT_EQ(6u, ime_text_spans[2].start_offset);
|
||||
- EXPECT_EQ(8u, ime_text_spans[2].end_offset);
|
||||
- EXPECT_EQ(ui::ImeTextSpan::Type::kGrammarSuggestion, ime_text_spans[2].type);
|
||||
- EXPECT_EQ(1u, ime_text_spans[2].suggestions.size());
|
||||
- EXPECT_EQ("fake_suggestion", ime_text_spans[2].suggestions[0]);
|
||||
+ EXPECT_EQ(6u, ime_text_spans[1].start_offset);
|
||||
+ EXPECT_EQ(8u, ime_text_spans[1].end_offset);
|
||||
+ EXPECT_EQ(ui::ImeTextSpan::Type::kGrammarSuggestion, ime_text_spans[1].type);
|
||||
+ EXPECT_EQ(1u, ime_text_spans[1].suggestions.size());
|
||||
+ EXPECT_EQ("fake_suggestion", ime_text_spans[1].suggestions[0]);
|
||||
}
|
||||
|
||||
TEST_F(InputMethodControllerTest, SetCompositionAfterEmoji) {
|
||||
@@ -14,10 +14,10 @@ Note that we also need to manually update embedder's
|
||||
`api::WebContents::IsFullscreenForTabOrPending` value.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index cd911b2bf4bfd2a636d297cb00e43ad44ce4f1de..a20c7b50fcdf838a64d7b86e6c4c3f254ce95e13 100644
|
||||
index b68c5ee5bd719e15d952a48ff4bc8ef0046e361a..44c089d82fc91462ea986ec63e124ce0cd59e7b7 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -5906,6 +5906,15 @@ void RenderFrameHostImpl::EnterFullscreen(
|
||||
@@ -5907,6 +5907,15 @@ void RenderFrameHostImpl::EnterFullscreen(
|
||||
notified_instances.insert(parent_site_instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,3 +26,7 @@ fix_readbarrier_undefined_symbol_error_on_woa_arm64.patch
|
||||
fix_-wunreachable-code-return.patch
|
||||
fix_crash_creating_private_key_with_unsupported_algorithm.patch
|
||||
fix_event_with_invalid_timestamp_in_trace_log.patch
|
||||
test_fix_test-datetime-change-notify_after_daylight_change.patch
|
||||
test_add_fixture_trim_option.patch
|
||||
fix_crash_caused_by_gethostnamew_on_windows_7.patch
|
||||
fix_don_t_create_console_window_when_creating_process.patch
|
||||
|
||||
@@ -8,7 +8,7 @@ modules from being used in the renderer process. This should be upstreamed as
|
||||
a customizable error message.
|
||||
|
||||
diff --git a/src/node_binding.cc b/src/node_binding.cc
|
||||
index 8b8389ae53608afedc9cc0ad2a6c8461b7aa893e..e79ddab7d73c6297ef1dc74b2a0ce469bf49e37c 100644
|
||||
index 8b8389ae53608afedc9cc0ad2a6c8461b7aa893e..58aa43010c9d5282955a11c786b5029b0618d2f0 100644
|
||||
--- a/src/node_binding.cc
|
||||
+++ b/src/node_binding.cc
|
||||
@@ -4,6 +4,7 @@
|
||||
@@ -27,7 +27,7 @@ index 8b8389ae53608afedc9cc0ad2a6c8461b7aa893e..e79ddab7d73c6297ef1dc74b2a0ce469
|
||||
+ char errmsg[1024];
|
||||
+ snprintf(errmsg,
|
||||
+ sizeof(errmsg),
|
||||
+ "Loading non-context-aware native module in renderer: '%s', but app.allowRendererProcessReuse is true. See https://github.com/electron/electron/issues/18397.",
|
||||
+ "Loading non-context-aware native module in renderer: '%s'. See https://github.com/electron/electron/issues/18397.",
|
||||
+ *filename);
|
||||
+ env->ThrowError(errmsg);
|
||||
return false;
|
||||
|
||||
234
patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch
Normal file
234
patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch
Normal file
@@ -0,0 +1,234 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Fri, 12 Nov 2021 17:25:37 +0900
|
||||
Subject: fix: crash caused by GetHostNameW on Windows 7
|
||||
|
||||
Backported from https://github.com/libuv/libuv/pull/3285.
|
||||
|
||||
diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
|
||||
index 88602c7ee8623f16f87398cf3ffd1f71555fc1a0..5ffde08e1aed041c4da679156ed10f7e54bfc386 100644
|
||||
--- a/deps/uv/src/win/util.c
|
||||
+++ b/deps/uv/src/win/util.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <windows.h>
|
||||
+#include <svcguid.h>
|
||||
/* clang-format on */
|
||||
#include <userenv.h>
|
||||
#include <math.h>
|
||||
@@ -56,6 +57,10 @@
|
||||
/* The number of nanoseconds in one second. */
|
||||
#define UV__NANOSEC 1000000000
|
||||
|
||||
+/* Local buffer size for WSAQUERYSETW data inside uv__gethostnamew_nt60
|
||||
+ sizeof(WSAQUERYSETW) + 512 = 632 bytes to match GetHostNameW behavior */
|
||||
+#define WSAQ_LOCAL_BUF_LEN (sizeof(WSAQUERYSETW) + 512)
|
||||
+
|
||||
/* Max user name length, from iphlpapi.h */
|
||||
#ifndef UNLEN
|
||||
# define UNLEN 256
|
||||
@@ -72,6 +77,11 @@ static CRITICAL_SECTION process_title_lock;
|
||||
/* Frequency of the high-resolution clock. */
|
||||
static uint64_t hrtime_frequency_ = 0;
|
||||
|
||||
+/* Parameters for WSAQUERYSETW inside uv__gethostnamew_nt60 */
|
||||
+static GUID guid_host_name = SVCID_HOSTNAME;
|
||||
+static AFPROTOCOLS af_protocols[2] = { {AF_INET, IPPROTO_UDP},
|
||||
+ {AF_INET, IPPROTO_TCP} };
|
||||
+
|
||||
|
||||
/*
|
||||
* One-time initialization code for functionality defined in util.c.
|
||||
@@ -1663,6 +1673,125 @@ int uv_os_unsetenv(const char* name) {
|
||||
}
|
||||
|
||||
|
||||
+static int WSAAPI uv__gethostnamew_nt60(PWSTR name, int name_len) {
|
||||
+ int result_len;
|
||||
+ int error_code = NO_ERROR;
|
||||
+
|
||||
+ /* WSALookupService stuff
|
||||
+ * Avoid dynamic memory allocation if possible */
|
||||
+ CHAR local_buf[WSAQ_LOCAL_BUF_LEN];
|
||||
+ DWORD dwlen = WSAQ_LOCAL_BUF_LEN;
|
||||
+ WSAQUERYSETW* pwsaq;
|
||||
+ /* hostname returned from WSALookupService stage */
|
||||
+ WCHAR* result_name = NULL;
|
||||
+ /* WSALookupService handle */
|
||||
+ HANDLE hlookup;
|
||||
+ /* Fallback to heap allocation if stack buffer is too small */
|
||||
+ WSAQUERYSETW* heap_data = NULL;
|
||||
+
|
||||
+ /* check input */
|
||||
+ if (name == NULL) {
|
||||
+ error_code = WSAEFAULT;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Stage 1: Check environment variable
|
||||
+ * _CLUSTER_NETWORK_NAME_ len == ComputeName(NETBIOS) len.
|
||||
+ * i.e 15 characters + null.
|
||||
+ * It overrides the actual hostname, so application can
|
||||
+ * work when network name and computer name are different
|
||||
+ */
|
||||
+ result_len = GetEnvironmentVariableW(L"_CLUSTER_NETWORK_NAME_",
|
||||
+ name,
|
||||
+ name_len);
|
||||
+ if (result_len != 0) {
|
||||
+ if (result_len > name_len) {
|
||||
+ error_code = WSAEFAULT;
|
||||
+ }
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* Stage 2: Do normal lookup through WSALookupServiceLookup */
|
||||
+ pwsaq = (WSAQUERYSETW*) local_buf;
|
||||
+ memset(pwsaq, 0, sizeof(*pwsaq));
|
||||
+ pwsaq->dwSize = sizeof(*pwsaq);
|
||||
+ pwsaq->lpszServiceInstanceName = NULL;
|
||||
+ pwsaq->lpServiceClassId = &guid_host_name;
|
||||
+ pwsaq->dwNameSpace = NS_ALL;
|
||||
+ pwsaq->lpafpProtocols = &af_protocols[0];
|
||||
+ pwsaq->dwNumberOfProtocols = 2;
|
||||
+
|
||||
+ error_code = WSALookupServiceBeginW(pwsaq, LUP_RETURN_NAME, &hlookup);
|
||||
+ if (error_code == NO_ERROR) {
|
||||
+ /* Try stack allocation first */
|
||||
+ error_code = WSALookupServiceNextW(hlookup, 0, &dwlen, pwsaq);
|
||||
+ if (error_code == NO_ERROR) {
|
||||
+ result_name = pwsaq->lpszServiceInstanceName;
|
||||
+ } else {
|
||||
+ error_code = WSAGetLastError();
|
||||
+
|
||||
+ if (error_code == WSAEFAULT) {
|
||||
+ /* Should never happen */
|
||||
+ assert(sizeof(CHAR) * dwlen >= sizeof(WSAQUERYSETW));
|
||||
+
|
||||
+ /* Fallback to the heap allocation */
|
||||
+ heap_data = uv__malloc(sizeof(CHAR) * (size_t) dwlen);
|
||||
+ if (heap_data != NULL) {
|
||||
+ error_code = WSALookupServiceNextW(hlookup, 0, &dwlen, heap_data);
|
||||
+ if (error_code == NO_ERROR) {
|
||||
+ result_name = heap_data->lpszServiceInstanceName;
|
||||
+ } else {
|
||||
+ error_code = WSAGetLastError();
|
||||
+ }
|
||||
+ } else {
|
||||
+ error_code = WSA_NOT_ENOUGH_MEMORY;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ WSALookupServiceEnd(hlookup);
|
||||
+
|
||||
+ if (error_code != NO_ERROR) {
|
||||
+ WSASetLastError(error_code);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (result_name != NULL) {
|
||||
+ size_t wlen = wcslen(result_name) + 1;
|
||||
+
|
||||
+ if (wlen <= (size_t) name_len) {
|
||||
+ wmemcpy(name, result_name, wlen);
|
||||
+ } else {
|
||||
+ error_code = WSAEFAULT;
|
||||
+ }
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* Stage 3: If WSALookupServiceLookup fails, fallback to GetComputerName */
|
||||
+ result_len = name_len;
|
||||
+ /* Reset error code */
|
||||
+ error_code = NO_ERROR;
|
||||
+
|
||||
+ if (GetComputerNameW(name, (PDWORD)&result_len) == FALSE) {
|
||||
+ error_code = WSAENETDOWN;
|
||||
+ if (result_len >= name_len) {
|
||||
+ error_code = WSAEFAULT;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+cleanup:
|
||||
+ uv__free(heap_data);
|
||||
+
|
||||
+ if (error_code == NO_ERROR) {
|
||||
+ return NO_ERROR;
|
||||
+ } else {
|
||||
+ WSASetLastError(error_code);
|
||||
+ return SOCKET_ERROR;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
WCHAR buf[UV_MAXHOSTNAMESIZE];
|
||||
size_t len;
|
||||
@@ -1674,7 +1803,9 @@ int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
|
||||
uv__once_init(); /* Initialize winsock */
|
||||
|
||||
- if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
|
||||
+ sGetHostNameW gethostnamew =
|
||||
+ pGetHostNameW == NULL ? uv__gethostnamew_nt60 : pGetHostNameW;
|
||||
+ if (gethostnamew(buf, UV_MAXHOSTNAMESIZE) != 0)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
|
||||
diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c
|
||||
index bb86ec8ceac8ba3fccd02b292aca7ddfab38e187..9d6effb10ddd1801f7411ee71a70575b7072ab7d 100644
|
||||
--- a/deps/uv/src/win/winapi.c
|
||||
+++ b/deps/uv/src/win/winapi.c
|
||||
@@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
/* User32.dll function pointer */
|
||||
sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
+/* ws2_32.dll function pointer */
|
||||
+sGetHostNameW pGetHostNameW;
|
||||
|
||||
void uv_winapi_init(void) {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE powrprof_module;
|
||||
HMODULE user32_module;
|
||||
HMODULE kernel32_module;
|
||||
+ HMODULE ws2_32_module;;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@@ -134,4 +137,10 @@ void uv_winapi_init(void) {
|
||||
pSetWinEventHook = (sSetWinEventHook)
|
||||
GetProcAddress(user32_module, "SetWinEventHook");
|
||||
}
|
||||
+
|
||||
+ ws2_32_module = LoadLibraryA("ws2_32.dll");
|
||||
+ if (ws2_32_module != NULL) {
|
||||
+ pGetHostNameW = (sGetHostNameW)
|
||||
+ GetProcAddress(ws2_32_module, "GetHostNameW");
|
||||
+ }
|
||||
}
|
||||
diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h
|
||||
index 0b66b5634bca88cec65b1bf0c0193986f5ddd542..5951717ab9e21db274f956c44410cc03c1617eaf 100644
|
||||
--- a/deps/uv/src/win/winapi.h
|
||||
+++ b/deps/uv/src/win/winapi.h
|
||||
@@ -4739,6 +4739,11 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS {
|
||||
# define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
|
||||
#endif
|
||||
|
||||
+/* From winsock2.h */
|
||||
+typedef int (WSAAPI *sGetHostNameW)
|
||||
+ (PWSTR name,
|
||||
+ int namelen);
|
||||
+
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlGetVersion pRtlGetVersion;
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
@@ -4759,4 +4764,7 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
|
||||
/* User32.dll function pointer */
|
||||
extern sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
+/* ws2_32.dll function pointer */
|
||||
+extern sGetHostNameW pGetHostNameW;
|
||||
+
|
||||
#endif /* UV_WIN_WINAPI_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Raymond Zhao <raymondzhao@microsoft.com>
|
||||
Date: Tue, 4 Jan 2022 16:11:41 -0800
|
||||
Subject: fix: Don't create console window when creating process
|
||||
|
||||
This patch prevents console windows from being created during
|
||||
execSync calls, or spawnSync calls where shell is true. Otherwise,
|
||||
Windows users will see command prompts pop up for those calls.
|
||||
|
||||
The patch has been upstreamed at https://github.com/nodejs/node/pull/41412.
|
||||
|
||||
diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc
|
||||
index 1141aceae984fba6ed07cd272a79d4007b9b03fe..afd08519d7f8974adff4060513f6160519a0b6b3 100644
|
||||
--- a/src/spawn_sync.cc
|
||||
+++ b/src/spawn_sync.cc
|
||||
@@ -810,6 +810,9 @@ Maybe<int> SyncProcessRunner::ParseOptions(Local<Value> js_value) {
|
||||
if (js_win_hide->BooleanValue(isolate))
|
||||
uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE;
|
||||
|
||||
+ if (env()->hide_console_windows())
|
||||
+ uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE;
|
||||
+
|
||||
Local<Value> js_wva =
|
||||
js_options->Get(context, env()->windows_verbatim_arguments_string())
|
||||
.ToLocalChecked();
|
||||
49
patches/node/test_add_fixture_trim_option.patch
Normal file
49
patches/node/test_add_fixture_trim_option.patch
Normal file
@@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 8 Nov 2021 15:52:17 +0100
|
||||
Subject: test: add fixture trim option
|
||||
|
||||
Fixes a spec failure originating with a strict requirement in BoringSSL
|
||||
that base64 strings be evenly divisible by 4 in their implementation of
|
||||
`NETSCAPE_SPKI_b64_decode`.
|
||||
|
||||
Fixes that issue by trimming the newlines out of the file.
|
||||
|
||||
Upstreamed at https://github.com/nodejs/node/pull/40757.
|
||||
|
||||
diff --git a/test/common/fixtures.js b/test/common/fixtures.js
|
||||
index e5e1d887df525e493989a4aa8df6952a0e5b6c47..2da8aeb6a694e4b45d76bc3908284783d83f6755 100644
|
||||
--- a/test/common/fixtures.js
|
||||
+++ b/test/common/fixtures.js
|
||||
@@ -15,8 +15,13 @@ function readFixtureSync(args, enc) {
|
||||
return fs.readFileSync(fixturesPath(args), enc);
|
||||
}
|
||||
|
||||
-function readFixtureKey(name, enc) {
|
||||
- return fs.readFileSync(fixturesPath('keys', name), enc);
|
||||
+function readFixtureKey(name, enc, trim) {
|
||||
+ let result = fs.readFileSync(fixturesPath('keys', name), enc);
|
||||
+ if (trim) {
|
||||
+ result = Buffer.from(result.toString().trim(), 'utf8');
|
||||
+ }
|
||||
+
|
||||
+ return result;
|
||||
}
|
||||
|
||||
function readFixtureKeys(enc, ...names) {
|
||||
diff --git a/test/parallel/test-crypto-certificate.js b/test/parallel/test-crypto-certificate.js
|
||||
index 4a5f1f149fe6c739f7f1d2ee17df6e61a942d621..a21fbff81c840da29034cb07ae2bd711cfe78b0a 100644
|
||||
--- a/test/parallel/test-crypto-certificate.js
|
||||
+++ b/test/parallel/test-crypto-certificate.js
|
||||
@@ -30,9 +30,9 @@ const { Certificate } = crypto;
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
// Test Certificates
|
||||
-const spkacValid = fixtures.readKey('rsa_spkac.spkac');
|
||||
+const spkacValid = fixtures.readKey('rsa_spkac.spkac', null, true);
|
||||
const spkacChallenge = 'this-is-a-challenge';
|
||||
-const spkacFail = fixtures.readKey('rsa_spkac_invalid.spkac');
|
||||
+const spkacFail = fixtures.readKey('rsa_spkac_invalid.spkac', null, true);
|
||||
const spkacPublicPem = fixtures.readKey('rsa_public.pem');
|
||||
|
||||
function copyArrayBuffer(buf) {
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Rybak <rybak.piotr@yahoo.com>
|
||||
Date: Sun, 31 Oct 2021 17:58:09 +0900
|
||||
Subject: test: fix test-datetime-change-notify after daylight change
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add standard timezone name for Dublin without daylight saving
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/40684
|
||||
Reviewed-By: Michaël Zasso <targos@protonmail.com>
|
||||
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
|
||||
Reviewed-By: Voltrex <mohammadkeyvanzade94@gmail.com>
|
||||
(cherry picked from commit 747ef34fb0c9c1f2924ab1b79ea000c87e67a8eb)
|
||||
|
||||
diff --git a/test/parallel/test-datetime-change-notify.js b/test/parallel/test-datetime-change-notify.js
|
||||
index 9cd6d7abfd898ac6781b04422362a6b459b7dc2c..01843511907077857be22c9bc7e7f8568fc677d1 100644
|
||||
--- a/test/parallel/test-datetime-change-notify.js
|
||||
+++ b/test/parallel/test-datetime-change-notify.js
|
||||
@@ -18,15 +18,15 @@ const cases = [
|
||||
},
|
||||
{
|
||||
timeZone: 'America/New_York',
|
||||
- expected: /Eastern (Standard|Daylight) Time/,
|
||||
+ expected: /Eastern (?:Standard|Daylight) Time/,
|
||||
},
|
||||
{
|
||||
timeZone: 'America/Los_Angeles',
|
||||
- expected: /Pacific (Standard|Daylight) Time/,
|
||||
+ expected: /Pacific (?:Standard|Daylight) Time/,
|
||||
},
|
||||
{
|
||||
timeZone: 'Europe/Dublin',
|
||||
- expected: /Irish/,
|
||||
+ expected: /Irish Standard Time|Greenwich Mean Time/,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -6,7 +6,7 @@ Subject: dcheck.patch
|
||||
https://github.com/auchenberg/volkswagen
|
||||
|
||||
diff --git a/src/api/api.cc b/src/api/api.cc
|
||||
index f79d0482ed3f1b42e60e09b4ad07749f9dbdadf0..f87db8a84efc661aad15781f2f949901e5befc17 100644
|
||||
index 93fa70ae1bb1dfd4b55f0e18cb22d764278dfbd2..c163170190dd8d9a72fc921ff062143d48681b5a 100644
|
||||
--- a/src/api/api.cc
|
||||
+++ b/src/api/api.cc
|
||||
@@ -8907,7 +8907,7 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
|
||||
|
||||
@@ -17,10 +17,10 @@ def run_node_configure(target_cpu):
|
||||
# Enabled in Chromium's V8.
|
||||
if target_cpu == 'arm64' or target_cpu == 'x64':
|
||||
args += ['--experimental-enable-pointer-compression']
|
||||
# Work around "No acceptable ASM compiler found" error on some Windows
|
||||
# machines, it breaks nothing since Electron does not use OpenSSL.
|
||||
if sys.platform == 'win32':
|
||||
args += ['--openssl-no-asm']
|
||||
|
||||
# Work around "No acceptable ASM compiler found" error on some System,
|
||||
# it breaks nothing since Electron does not use OpenSSL.
|
||||
args += ['--openssl-no-asm']
|
||||
subprocess.check_call([sys.executable, configure] + args)
|
||||
|
||||
def read_node_config_gypi():
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
@@ -14,14 +14,15 @@ PLATFORM = {
|
||||
}[sys.platform]
|
||||
|
||||
LINUX_BINARIES = [
|
||||
'electron',
|
||||
'chrome-sandbox',
|
||||
'libffmpeg.so',
|
||||
'libGLESv2.so',
|
||||
'crashpad_handler',
|
||||
'electron',
|
||||
'libEGL.so',
|
||||
'swiftshader/libGLESv2.so',
|
||||
'swiftshader/libEGL.so',
|
||||
'libGLESv2.so',
|
||||
'libffmpeg.so',
|
||||
'libvk_swiftshader.so'
|
||||
'swiftshader/libEGL.so',
|
||||
'swiftshader/libGLESv2.so',
|
||||
]
|
||||
|
||||
verbose_mode = False
|
||||
|
||||
@@ -229,6 +229,14 @@ def remove_patch_filename(patch):
|
||||
force_keep_next_line = l.startswith('Subject: ')
|
||||
|
||||
|
||||
def to_utf8(patch):
|
||||
"""Python 2/3 compatibility: unicode has been renamed to str in Python3"""
|
||||
if sys.version_info[0] >= 3:
|
||||
return str(patch, "utf-8")
|
||||
else:
|
||||
return unicode(patch, "utf-8")
|
||||
|
||||
|
||||
def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
if patch_range is None:
|
||||
patch_range, num_patches = guess_base_commit(repo)
|
||||
@@ -250,7 +258,7 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
for patch in patches:
|
||||
filename = get_file_name(patch)
|
||||
filepath = posixpath.join(out_dir, filename)
|
||||
existing_patch = unicode(io.open(filepath, 'rb').read(), "utf-8")
|
||||
existing_patch = to_utf8(io.open(filepath, 'rb').read())
|
||||
formatted_patch = join_patch(patch)
|
||||
if formatted_patch != existing_patch:
|
||||
bad_patches.append(filename)
|
||||
|
||||
@@ -14,10 +14,6 @@ const DEPOT_TOOLS = path.resolve(SOURCE_ROOT, '..', 'third_party', 'depot_tools'
|
||||
|
||||
const IGNORELIST = new Set([
|
||||
['shell', 'browser', 'resources', 'win', 'resource.h'],
|
||||
['shell', 'browser', 'notifications', 'mac', 'notification_center_delegate.h'],
|
||||
['shell', 'browser', 'ui', 'cocoa', 'event_dispatching_window.h'],
|
||||
['shell', 'browser', 'ui', 'cocoa', 'NSColor+Hex.h'],
|
||||
['shell', 'browser', 'ui', 'cocoa', 'NSString+ANSI.h'],
|
||||
['shell', 'common', 'node_includes.h'],
|
||||
['spec', 'static', 'jquery-2.0.3.min.js'],
|
||||
['spec', 'ts-smoke', 'electron', 'main.ts'],
|
||||
@@ -81,7 +77,7 @@ const LINTERS = [{
|
||||
}, {
|
||||
key: 'objc',
|
||||
roots: ['shell'],
|
||||
test: filename => filename.endsWith('.mm'),
|
||||
test: filename => filename.endsWith('.mm') || (filename.endsWith('.h') && isObjCHeader(filename)),
|
||||
run: (opts, filenames) => {
|
||||
if (opts.fix) {
|
||||
spawnAndCheckExitCode('python', ['script/run-clang-format.py', '--fix', ...filenames]);
|
||||
@@ -89,12 +85,13 @@ const LINTERS = [{
|
||||
spawnAndCheckExitCode('python', ['script/run-clang-format.py', ...filenames]);
|
||||
}
|
||||
const filter = [
|
||||
'-readability/braces',
|
||||
'-readability/casting',
|
||||
'-whitespace/braces',
|
||||
'-whitespace/indent',
|
||||
'-whitespace/parens'
|
||||
];
|
||||
cpplint(['--extensions=mm', `--filter=${filter.join(',')}`, ...filenames]);
|
||||
cpplint(['--extensions=mm,h', `--filter=${filter.join(',')}`, ...filenames]);
|
||||
}
|
||||
}, {
|
||||
key: 'python',
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"parallel/test-crypto-aes-wrap",
|
||||
"parallel/test-crypto-async-sign-verify",
|
||||
"parallel/test-crypto-authenticated-stream",
|
||||
"parallel/test-crypto-certificate",
|
||||
"parallel/test-crypto-des3-wrap",
|
||||
"parallel/test-crypto-dh-stateless",
|
||||
"parallel/test-crypto-ecb",
|
||||
|
||||
@@ -59,11 +59,7 @@ async function circleCIcall (targetBranch, workflowName, options) {
|
||||
console.log(`Triggering CircleCI to run build job: ${workflowName} on branch: ${targetBranch} with release flag.`);
|
||||
const buildRequest = {
|
||||
branch: targetBranch,
|
||||
parameters: {
|
||||
'run-lint': false,
|
||||
'run-build-linux': false,
|
||||
'run-build-mac': false
|
||||
}
|
||||
parameters: {}
|
||||
};
|
||||
if (options.ghRelease) {
|
||||
buildRequest.parameters['upload-to-s3'] = '0';
|
||||
@@ -114,8 +110,9 @@ async function getCircleCIWorkflowId (pipelineId) {
|
||||
switch (pipelineInfo.state) {
|
||||
case 'created': {
|
||||
const workflows = await circleCIRequest(`${pipelineInfoUrl}/workflow`, 'GET');
|
||||
if (workflows.items.length === 1) {
|
||||
workflowId = workflows.items[0].id;
|
||||
// The logic below expects two workflow.items: publish [0] & setup [1]
|
||||
if (workflows.items.length === 2) {
|
||||
workflowId = workflows.items.find(item => item.name.includes('publish')).id;
|
||||
break;
|
||||
}
|
||||
console.log('Unxpected number of workflows, response was:', pipelineInfo);
|
||||
|
||||
@@ -127,11 +127,7 @@ bool ElectronPathProvider(int key, base::FilePath* result) {
|
||||
case DIR_CRASH_DUMPS:
|
||||
if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
|
||||
return false;
|
||||
#if defined(OS_MAC) || defined(OS_WIN)
|
||||
cur = cur.Append(FILE_PATH_LITERAL("Crashpad"));
|
||||
#else
|
||||
cur = cur.Append(FILE_PATH_LITERAL("Crash Reports"));
|
||||
#endif
|
||||
create_dir = true;
|
||||
break;
|
||||
case chrome::DIR_APP_DICTIONARIES:
|
||||
|
||||
@@ -210,8 +210,11 @@ int NodeMain(int argc, char* argv[]) {
|
||||
isolate_data = node::CreateIsolateData(isolate, loop, gin_env.platform());
|
||||
CHECK_NE(nullptr, isolate_data);
|
||||
|
||||
env = node::CreateEnvironment(isolate_data, gin_env.context(),
|
||||
result.args, result.exec_args);
|
||||
uint64_t flags = node::EnvironmentFlags::kDefaultFlags |
|
||||
node::EnvironmentFlags::kHideConsoleWindows;
|
||||
env = node::CreateEnvironment(
|
||||
isolate_data, gin_env.context(), result.args, result.exec_args,
|
||||
static_cast<node::EnvironmentFlags::Flags>(flags));
|
||||
CHECK_NE(nullptr, env);
|
||||
|
||||
node::IsolateSettings is;
|
||||
|
||||
@@ -1054,11 +1054,14 @@ std::string App::GetLocaleCountryCode() {
|
||||
CFLocaleRef locale = CFLocaleCopyCurrent();
|
||||
CFStringRef value = CFStringRef(
|
||||
static_cast<CFTypeRef>(CFLocaleGetValue(locale, kCFLocaleCountryCode)));
|
||||
const CFIndex kCStringSize = 128;
|
||||
char temporaryCString[kCStringSize] = {0};
|
||||
CFStringGetCString(value, temporaryCString, kCStringSize,
|
||||
kCFStringEncodingUTF8);
|
||||
region = temporaryCString;
|
||||
if (value != nil) {
|
||||
char temporaryCString[3];
|
||||
const CFIndex kCStringSize = sizeof(temporaryCString);
|
||||
if (CFStringGetCString(value, temporaryCString, kCStringSize,
|
||||
kCFStringEncodingUTF8)) {
|
||||
region = temporaryCString;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const char* locale_ptr = setlocale(LC_TIME, nullptr);
|
||||
if (!locale_ptr)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
|
||||
#if defined(USE_NSS_CERTS)
|
||||
#include "chrome/browser/certificate_manager_model.h"
|
||||
#include "shell/browser/certificate_manager_model.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
@@ -768,18 +768,16 @@ void BaseWindow::AddBrowserView(v8::Local<v8::Value> value) {
|
||||
gin::ConvertFromV8(isolate(), value, &browser_view)) {
|
||||
auto get_that_view = browser_views_.find(browser_view->ID());
|
||||
if (get_that_view == browser_views_.end()) {
|
||||
if (browser_view->web_contents()) {
|
||||
// If we're reparenting a BrowserView, ensure that it's detached from
|
||||
// its previous owner window.
|
||||
auto* owner_window = browser_view->web_contents()->owner_window();
|
||||
if (owner_window && owner_window != window_.get()) {
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
}
|
||||
|
||||
window_->AddBrowserView(browser_view->view());
|
||||
browser_view->web_contents()->SetOwnerWindow(window_.get());
|
||||
// If we're reparenting a BrowserView, ensure that it's detached from
|
||||
// its previous owner window.
|
||||
auto* owner_window = browser_view->owner_window();
|
||||
if (owner_window && owner_window != window_.get()) {
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
browser_view->SetOwnerWindow(nullptr);
|
||||
}
|
||||
|
||||
window_->AddBrowserView(browser_view->view());
|
||||
browser_view->SetOwnerWindow(window_.get());
|
||||
browser_views_[browser_view->ID()].Reset(isolate(), value);
|
||||
}
|
||||
}
|
||||
@@ -791,10 +789,8 @@ void BaseWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
|
||||
gin::ConvertFromV8(isolate(), value, &browser_view)) {
|
||||
auto get_that_view = browser_views_.find(browser_view->ID());
|
||||
if (get_that_view != browser_views_.end()) {
|
||||
if (browser_view->web_contents()) {
|
||||
window_->RemoveBrowserView(browser_view->view());
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
}
|
||||
window_->RemoveBrowserView(browser_view->view());
|
||||
browser_view->SetOwnerWindow(nullptr);
|
||||
(*get_that_view).second.Reset(isolate(), value);
|
||||
browser_views_.erase(get_that_view);
|
||||
}
|
||||
@@ -806,9 +802,7 @@ void BaseWindow::SetTopBrowserView(v8::Local<v8::Value> value,
|
||||
gin::Handle<BrowserView> browser_view;
|
||||
if (value->IsObject() &&
|
||||
gin::ConvertFromV8(isolate(), value, &browser_view)) {
|
||||
if (!browser_view->web_contents())
|
||||
return;
|
||||
auto* owner_window = browser_view->web_contents()->owner_window();
|
||||
auto* owner_window = browser_view->owner_window();
|
||||
auto get_that_view = browser_views_.find(browser_view->ID());
|
||||
if (get_that_view == browser_views_.end() ||
|
||||
(owner_window && owner_window != window_.get())) {
|
||||
@@ -860,10 +854,10 @@ void BaseWindow::SetVisibleOnAllWorkspaces(bool visible,
|
||||
gin_helper::Dictionary options;
|
||||
bool visibleOnFullScreen = false;
|
||||
bool skipTransformProcessType = false;
|
||||
args->GetNext(&options) &&
|
||||
options.Get("visibleOnFullScreen", &visibleOnFullScreen);
|
||||
args->GetNext(&options) &&
|
||||
options.Get("skipTransformProcessType", &skipTransformProcessType);
|
||||
if (args->GetNext(&options)) {
|
||||
options.Get("visibleOnFullScreen", &visibleOnFullScreen);
|
||||
options.Get("skipTransformProcessType", &skipTransformProcessType);
|
||||
}
|
||||
return window_->SetVisibleOnAllWorkspaces(visible, visibleOnFullScreen,
|
||||
skipTransformProcessType);
|
||||
}
|
||||
@@ -1137,12 +1131,10 @@ void BaseWindow::ResetBrowserViews() {
|
||||
!browser_view.IsEmpty()) {
|
||||
// There's a chance that the BrowserView may have been reparented - only
|
||||
// reset if the owner window is *this* window.
|
||||
if (browser_view->web_contents()) {
|
||||
auto* owner_window = browser_view->web_contents()->owner_window();
|
||||
if (owner_window && owner_window == window_.get()) {
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
}
|
||||
auto* owner_window = browser_view->owner_window();
|
||||
if (owner_window && owner_window == window_.get()) {
|
||||
browser_view->SetOwnerWindow(nullptr);
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,10 +99,18 @@ BrowserView::BrowserView(gin::Arguments* args,
|
||||
NativeBrowserView::Create(api_web_contents_->inspectable_web_contents()));
|
||||
}
|
||||
|
||||
void BrowserView::SetOwnerWindow(NativeWindow* window) {
|
||||
// Ensure WebContents and BrowserView owner windows are in sync.
|
||||
if (web_contents())
|
||||
web_contents()->SetOwnerWindow(window);
|
||||
|
||||
owner_window_ = window ? window->GetWeakPtr() : nullptr;
|
||||
}
|
||||
|
||||
BrowserView::~BrowserView() {
|
||||
if (api_web_contents_) { // destroy() called without closing WebContents
|
||||
api_web_contents_->RemoveObserver(this);
|
||||
api_web_contents_->Destroy();
|
||||
if (web_contents()) { // destroy() called without closing WebContents
|
||||
web_contents()->RemoveObserver(this);
|
||||
web_contents()->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +156,11 @@ gfx::Rect BrowserView::GetBounds() {
|
||||
|
||||
void BrowserView::SetBackgroundColor(const std::string& color_name) {
|
||||
view_->SetBackgroundColor(ParseHexColor(color_name));
|
||||
|
||||
if (web_contents()) {
|
||||
auto* wc = web_contents()->web_contents();
|
||||
wc->SetPageBaseBackgroundColor(ParseHexColor(color_name));
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> BrowserView::GetWebContents(v8::Isolate* isolate) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/browser/extended_web_contents_observer.h"
|
||||
#include "shell/browser/native_browser_view.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/common/api/api.mojom.h"
|
||||
#include "shell/common/gin_helper/constructible.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
@@ -52,6 +53,10 @@ class BrowserView : public gin::Wrappable<BrowserView>,
|
||||
WebContents* web_contents() const { return api_web_contents_; }
|
||||
NativeBrowserView* view() const { return view_.get(); }
|
||||
|
||||
NativeWindow* owner_window() const { return owner_window_.get(); }
|
||||
|
||||
void SetOwnerWindow(NativeWindow* window);
|
||||
|
||||
int32_t ID() const { return id_; }
|
||||
|
||||
protected:
|
||||
@@ -76,6 +81,7 @@ class BrowserView : public gin::Wrappable<BrowserView>,
|
||||
class WebContents* api_web_contents_ = nullptr;
|
||||
|
||||
std::unique_ptr<NativeBrowserView> view_;
|
||||
base::WeakPtr<NativeWindow> owner_window_;
|
||||
|
||||
int32_t id_;
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
||||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
// Already closed by renderer.
|
||||
if (!web_contents())
|
||||
if (!web_contents() || !api_web_contents_)
|
||||
return;
|
||||
|
||||
// Required to make beforeunload handler work.
|
||||
@@ -373,8 +373,11 @@ void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
|
||||
SkColor color = ParseHexColor(color_name);
|
||||
web_contents()->SetPageBaseBackgroundColor(color);
|
||||
auto* rwhv = web_contents()->GetRenderWidgetHostView();
|
||||
if (rwhv)
|
||||
if (rwhv) {
|
||||
rwhv->SetBackgroundColor(color);
|
||||
static_cast<content::RenderWidgetHostViewBase*>(rwhv)
|
||||
->SetContentBackgroundColor(color);
|
||||
}
|
||||
// Also update the web preferences object otherwise the view will be reset on
|
||||
// the next load URL call
|
||||
if (api_web_contents_) {
|
||||
|
||||
@@ -192,7 +192,7 @@ std::string InclusionStatusToString(net::CookieInclusionStatus status) {
|
||||
std::string StringToCookieSameSite(const std::string* str_ptr,
|
||||
net::CookieSameSite* same_site) {
|
||||
if (!str_ptr) {
|
||||
*same_site = net::CookieSameSite::NO_RESTRICTION;
|
||||
*same_site = net::CookieSameSite::LAX_MODE;
|
||||
return "";
|
||||
}
|
||||
const std::string& str = *str_ptr;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
|
||||
#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
@@ -598,6 +599,12 @@ bool IsDevToolsFileSystemAdded(content::WebContents* web_contents,
|
||||
return file_system_paths.find(file_system_path) != file_system_paths.end();
|
||||
}
|
||||
|
||||
void SetBackgroundColor(content::RenderWidgetHostView* rwhv, SkColor color) {
|
||||
rwhv->SetBackgroundColor(color);
|
||||
static_cast<content::RenderWidgetHostViewBase*>(rwhv)
|
||||
->SetContentBackgroundColor(color);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
@@ -628,6 +635,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -666,6 +674,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -686,6 +695,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
: id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -976,8 +986,7 @@ void WebContents::DeleteThisIfAlive() {
|
||||
void WebContents::Destroy() {
|
||||
// The content::WebContents should be destroyed asyncronously when possible
|
||||
// as user may choose to destroy WebContents during an event of it.
|
||||
if (Browser::Get()->is_shutting_down() || IsGuest() ||
|
||||
type_ == Type::kBrowserView) {
|
||||
if (Browser::Get()->is_shutting_down() || IsGuest()) {
|
||||
DeleteThisIfAlive();
|
||||
} else {
|
||||
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
|
||||
@@ -1250,6 +1259,40 @@ void WebContents::ContentsZoomChange(bool zoom_in) {
|
||||
Emit("zoom-changed", zoom_in ? "in" : "out");
|
||||
}
|
||||
|
||||
Profile* WebContents::GetProfile() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WebContents::IsFullscreen() const {
|
||||
return owner_window_ && owner_window_->IsFullscreen();
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreen(const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
const int64_t display_id) {}
|
||||
|
||||
void WebContents::ExitFullscreen() {}
|
||||
|
||||
void WebContents::UpdateExclusiveAccessExitBubbleContent(
|
||||
const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,
|
||||
bool force_update) {}
|
||||
|
||||
void WebContents::OnExclusiveAccessUserInput() {}
|
||||
|
||||
content::WebContents* WebContents::GetActiveWebContents() {
|
||||
return web_contents();
|
||||
}
|
||||
|
||||
bool WebContents::CanUserExitFullscreen() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebContents::IsExclusiveAccessBubbleDisplayed() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const blink::mojom::FullscreenOptions& options) {
|
||||
@@ -1260,6 +1303,8 @@ void WebContents::EnterFullscreenModeForTab(
|
||||
base::BindRepeating(&WebContents::OnEnterFullscreenModeForTab,
|
||||
base::Unretained(this), requesting_frame, options);
|
||||
permission_helper->RequestFullscreenPermission(callback);
|
||||
exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab(
|
||||
requesting_frame, options.display_id);
|
||||
}
|
||||
|
||||
void WebContents::OnEnterFullscreenModeForTab(
|
||||
@@ -1296,6 +1341,9 @@ void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
// `chrome/browser/ui/exclusive_access/fullscreen_controller.cc`.
|
||||
source->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
|
||||
}
|
||||
|
||||
exclusive_access_manager_->fullscreen_controller()->ExitFullscreenModeForTab(
|
||||
source);
|
||||
}
|
||||
|
||||
void WebContents::RendererUnresponsive(
|
||||
@@ -1344,6 +1392,18 @@ void WebContents::FindReply(content::WebContents* web_contents,
|
||||
Emit("found-in-page", result.GetHandle());
|
||||
}
|
||||
|
||||
void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
|
||||
bool esc_key_locked) {
|
||||
exclusive_access_manager_->keyboard_lock_controller()->RequestKeyboardLock(
|
||||
web_contents, esc_key_locked);
|
||||
}
|
||||
|
||||
void WebContents::CancelKeyboardLockRequest(
|
||||
content::WebContents* web_contents) {
|
||||
exclusive_access_manager_->keyboard_lock_controller()
|
||||
->CancelKeyboardLockRequest(web_contents);
|
||||
}
|
||||
|
||||
bool WebContents::CheckMediaAccessPermission(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const GURL& security_origin,
|
||||
@@ -1399,9 +1459,11 @@ void WebContents::HandleNewRenderFrame(
|
||||
// Set the background color of RenderWidgetHostView.
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
||||
if (web_preferences) {
|
||||
absl::optional<SkColor> color = web_preferences->GetBackgroundColor();
|
||||
bool guest = IsGuest() || type_ == Type::kBrowserView;
|
||||
absl::optional<SkColor> color =
|
||||
guest ? SK_ColorTRANSPARENT : web_preferences->GetBackgroundColor();
|
||||
web_contents()->SetPageBaseBackgroundColor(color);
|
||||
rwhv->SetBackgroundColor(color.value_or(SK_ColorWHITE));
|
||||
SetBackgroundColor(rwhv, color.value_or(SK_ColorWHITE));
|
||||
}
|
||||
|
||||
if (!background_throttling_)
|
||||
@@ -1417,6 +1479,15 @@ void WebContents::HandleNewRenderFrame(
|
||||
web_frame->Connect();
|
||||
}
|
||||
|
||||
void WebContents::OnBackgroundColorChanged() {
|
||||
absl::optional<SkColor> color = web_contents()->GetBackgroundColor();
|
||||
if (color.has_value()) {
|
||||
auto* const view = web_contents()->GetRenderWidgetHostView();
|
||||
static_cast<content::RenderWidgetHostViewBase*>(view)
|
||||
->SetContentBackgroundColor(color.value());
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::RenderFrameCreated(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
HandleNewRenderFrame(render_frame_host);
|
||||
@@ -3973,9 +4044,11 @@ gin::Handle<WebContents> WebContents::CreateFromWebPreferences(
|
||||
absl::optional<SkColor> color =
|
||||
existing_preferences->GetBackgroundColor();
|
||||
web_contents->web_contents()->SetPageBaseBackgroundColor(color);
|
||||
// Because web preferences don't recognize transparency,
|
||||
// only set rwhv background color if a color exists
|
||||
auto* rwhv = web_contents->web_contents()->GetRenderWidgetHostView();
|
||||
if (rwhv)
|
||||
rwhv->SetBackgroundColor(color.value_or(SK_ColorWHITE));
|
||||
if (rwhv && color.has_value())
|
||||
SetBackgroundColor(rwhv, color.value());
|
||||
}
|
||||
} else {
|
||||
// Create one if not.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "base/observer_list_types.h"
|
||||
#include "chrome/browser/devtools/devtools_eye_dropper.h"
|
||||
#include "chrome/browser/devtools/devtools_file_system_indexer.h"
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" // nogncheck
|
||||
#include "content/common/cursors/webcursor.h"
|
||||
#include "content/common/frame.mojom.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
@@ -74,6 +75,8 @@ namespace gin {
|
||||
class Arguments;
|
||||
}
|
||||
|
||||
class ExclusiveAccessManager;
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronBrowserContext;
|
||||
@@ -98,7 +101,8 @@ using DevicePermissionMap = std::map<
|
||||
std::map<url::Origin, std::vector<std::unique_ptr<base::Value>>>>>;
|
||||
|
||||
// Wrapper around the content::WebContents.
|
||||
class WebContents : public gin::Wrappable<WebContents>,
|
||||
class WebContents : public ExclusiveAccessContext,
|
||||
public gin::Wrappable<WebContents>,
|
||||
public gin_helper::EventEmitterMixin<WebContents>,
|
||||
public gin_helper::Constructible<WebContents>,
|
||||
public gin_helper::Pinnable<WebContents>,
|
||||
@@ -548,6 +552,9 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
const gfx::Rect& selection_rect,
|
||||
int active_match_ordinal,
|
||||
bool final_update) override;
|
||||
void RequestKeyboardLock(content::WebContents* web_contents,
|
||||
bool esc_key_locked) override;
|
||||
void CancelKeyboardLockRequest(content::WebContents* web_contents) override;
|
||||
bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& security_origin,
|
||||
blink::mojom::MediaStreamType type) override;
|
||||
@@ -567,6 +574,7 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
// content::WebContentsObserver:
|
||||
void BeforeUnloadFired(bool proceed,
|
||||
const base::TimeTicks& proceed_time) override;
|
||||
void OnBackgroundColorChanged() override;
|
||||
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
|
||||
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
|
||||
void RenderFrameHostChanged(content::RenderFrameHost* old_host,
|
||||
@@ -646,6 +654,24 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const base::FilePath& path) override;
|
||||
|
||||
// ExclusiveAccessContext:
|
||||
Profile* GetProfile() override;
|
||||
bool IsFullscreen() const override;
|
||||
void EnterFullscreen(const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
const int64_t display_id) override;
|
||||
void ExitFullscreen() override;
|
||||
void UpdateExclusiveAccessExitBubbleContent(
|
||||
const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,
|
||||
bool force_update) override;
|
||||
void OnExclusiveAccessUserInput() override;
|
||||
content::WebContents* GetActiveWebContents() override;
|
||||
bool CanUserExitFullscreen() const override;
|
||||
bool IsExclusiveAccessBubbleDisplayed() const override;
|
||||
|
||||
bool IsFullscreenForTabOrPending(const content::WebContents* source) override;
|
||||
blink::SecurityStyle GetSecurityStyle(
|
||||
content::WebContents* web_contents,
|
||||
@@ -759,6 +785,8 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
|
||||
scoped_refptr<DevToolsFileSystemIndexer> devtools_file_system_indexer_;
|
||||
|
||||
std::unique_ptr<ExclusiveAccessManager> exclusive_access_manager_;
|
||||
|
||||
std::unique_ptr<DevToolsEyeDropper> eye_dropper_;
|
||||
|
||||
ElectronBrowserContext* browser_context_;
|
||||
|
||||
@@ -210,7 +210,7 @@ void WebFrameMain::PostMessage(v8::Isolate* isolate,
|
||||
}
|
||||
|
||||
std::vector<gin::Handle<MessagePort>> wrapped_ports;
|
||||
if (transfer) {
|
||||
if (transfer && !transfer.value()->IsUndefined()) {
|
||||
if (!gin::ConvertFromV8(isolate, *transfer, &wrapped_ports)) {
|
||||
isolate->ThrowException(v8::Exception::Error(
|
||||
gin::StringToV8(isolate, "Invalid value for transfer")));
|
||||
|
||||
@@ -133,8 +133,10 @@ v8::Local<v8::Value> HttpResponseHeadersToV8(
|
||||
net::HttpContentDisposition header(value, std::string());
|
||||
std::string decodedFilename =
|
||||
header.is_attachment() ? " attachment" : " inline";
|
||||
decodedFilename += "; filename=" + header.filename();
|
||||
value = decodedFilename;
|
||||
// The filename must be encased in double quotes for serialization
|
||||
// to happen correctly.
|
||||
std::string filename = "\"" + header.filename() + "\"";
|
||||
value = decodedFilename + "; filename=" + filename;
|
||||
}
|
||||
if (!values)
|
||||
values = response_headers.SetKey(key, base::ListValue());
|
||||
|
||||
@@ -28,6 +28,10 @@ void AddGuest(int guest_instance_id,
|
||||
electron::WebContentsZoomController::FromWebContents(guest_web_contents)
|
||||
->SetDefaultZoomFactor(zoom_factor);
|
||||
}
|
||||
|
||||
WebContentsPreferences::From(guest_web_contents)->Merge(options);
|
||||
// Trigger re-calculation of webkit prefs.
|
||||
guest_web_contents->NotifyPreferencesChanged();
|
||||
}
|
||||
|
||||
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
|
||||
|
||||
@@ -66,7 +66,7 @@ bool GetProtocolLaunchPath(gin::Arguments* args, std::wstring* exe) {
|
||||
// Read in optional args arg
|
||||
std::vector<std::wstring> launch_args;
|
||||
if (args->GetNext(&launch_args) && !launch_args.empty())
|
||||
*exe = base::StringPrintf(L"\"%ls\" %ls \"%%1\"", exe->c_str(),
|
||||
*exe = base::StringPrintf(L"\"%ls\" \"%ls\" \"%%1\"", exe->c_str(),
|
||||
base::JoinString(launch_args, L" ").c_str());
|
||||
else
|
||||
*exe = base::StringPrintf(L"\"%ls\" \"%%1\"", exe->c_str());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/certificate_manager_model.h"
|
||||
#include "shell/browser/certificate_manager_model.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
|
||||
#define CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
|
||||
#ifndef SHELL_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
|
||||
#define SHELL_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -112,4 +112,4 @@ class CertificateManagerModel {
|
||||
DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
|
||||
#endif // SHELL_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "chrome/common/chrome_version.h"
|
||||
#include "components/net_log/chrome_net_log.h"
|
||||
#include "components/network_hints/common/network_hints.mojom.h"
|
||||
#include "content/browser/keyboard_lock/keyboard_lock_service_impl.h" // nogncheck
|
||||
#include "content/browser/site_instance_impl.h" // nogncheck
|
||||
#include "content/public/browser/browser_main_runner.h"
|
||||
#include "content/public/browser/browser_ppapi_host.h"
|
||||
@@ -558,7 +559,11 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
|
||||
enable_crash_reporter = breakpad::IsCrashReporterEnabled();
|
||||
}
|
||||
|
||||
if (enable_crash_reporter) {
|
||||
// Zygote Process gets booted before any JS runs, accessing GetClientId
|
||||
// will end up touching DIR_USER_DATA path provider and this will
|
||||
// configure default value because app.name from browser_init has
|
||||
// not run yet.
|
||||
if (enable_crash_reporter && process_type != ::switches::kZygoteProcess) {
|
||||
std::string switch_value =
|
||||
api::crash_reporter::GetClientId() + ",no_channel";
|
||||
command_line->AppendSwitchASCII(::switches::kEnableCrashReporter,
|
||||
@@ -1572,6 +1577,8 @@ void ElectronBrowserClient::RegisterBrowserInterfaceBindersForFrame(
|
||||
base::BindRepeating(&badging::BadgeManager::BindFrameReceiver));
|
||||
map->Add<electron::mojom::ElectronBrowser>(
|
||||
base::BindRepeating(&BindElectronBrowser));
|
||||
map->Add<blink::mojom::KeyboardLockService>(base::BindRepeating(
|
||||
&content::KeyboardLockServiceImpl::CreateMojoService));
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
map->Add<extensions::mime_handler::MimeHandlerService>(
|
||||
base::BindRepeating(&BindMimeHandlerService));
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "chrome/browser/platform_util.h"
|
||||
#include "chrome/browser/ui/browser_dialogs.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
@@ -33,6 +32,7 @@
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "electron/grit/electron_resources.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "services/device/public/cpp/hid/hid_switches.h"
|
||||
#include "shell/browser/hid/hid_chooser_context.h"
|
||||
#include "shell/browser/hid/hid_chooser_context_factory.h"
|
||||
#include "shell/browser/hid/hid_chooser_controller.h"
|
||||
@@ -103,7 +105,8 @@ const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
|
||||
}
|
||||
|
||||
bool ElectronHidDelegate::IsFidoAllowedForOrigin(const url::Origin& origin) {
|
||||
return false;
|
||||
return base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kDisableHidBlocklist);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnDeviceAdded(
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_MAC_ELECTRON_APPLICATION_H_
|
||||
#define SHELL_BROWSER_MAC_ELECTRON_APPLICATION_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/mac/scoped_sending_event.h"
|
||||
@@ -45,3 +48,5 @@
|
||||
withUserInfo:(NSDictionary*)userInfo;
|
||||
|
||||
@end
|
||||
|
||||
#endif // SHELL_BROWSER_MAC_ELECTRON_APPLICATION_H_
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_MAC_ELECTRON_APPLICATION_DELEGATE_H_
|
||||
#define SHELL_BROWSER_MAC_ELECTRON_APPLICATION_DELEGATE_H_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "shell/browser/ui/cocoa/electron_menu_controller.h"
|
||||
@@ -15,3 +18,5 @@
|
||||
- (void)setApplicationDockMenu:(electron::ElectronMenuModel*)model;
|
||||
|
||||
@end
|
||||
|
||||
#endif // SHELL_BROWSER_MAC_ELECTRON_APPLICATION_DELEGATE_H_
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user