mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1f0ed1ecd | ||
|
|
570db18ef2 | ||
|
|
43b9988c57 | ||
|
|
b740cd2202 | ||
|
|
592430f918 | ||
|
|
3445fbf7dc | ||
|
|
df5ff97144 | ||
|
|
3bb800ce04 | ||
|
|
413fbcfa18 | ||
|
|
8877087e51 | ||
|
|
275eecdfcb | ||
|
|
6ecf43c8c4 | ||
|
|
aec62a9874 | ||
|
|
291b4f9980 | ||
|
|
a841bd195c | ||
|
|
4a5a18f003 | ||
|
|
5c29d3b533 | ||
|
|
e0172c45f0 | ||
|
|
3fa9826b8b | ||
|
|
e262b5040a | ||
|
|
e5eafc8ee9 | ||
|
|
2bcf583bcf | ||
|
|
c50d0e49c1 | ||
|
|
26c5cc2801 | ||
|
|
fb5822af43 | ||
|
|
97626aeac8 | ||
|
|
b8d136aeea | ||
|
|
eed55d5923 | ||
|
|
ef4d98ac7f | ||
|
|
8ae9c5c7cf | ||
|
|
1631fc9b0c | ||
|
|
cc0848a86e | ||
|
|
c7a2b32c5a | ||
|
|
18cfdb1c82 | ||
|
|
1105931d0a | ||
|
|
234309497e | ||
|
|
6fa2ab2edd | ||
|
|
527c767107 | ||
|
|
15468432c8 | ||
|
|
af34655cb7 | ||
|
|
111b737ae4 | ||
|
|
e33df2c7b6 | ||
|
|
f30018b4b0 | ||
|
|
795200a838 | ||
|
|
64d4e5969f | ||
|
|
be670059a6 | ||
|
|
5d64c42801 | ||
|
|
5b81463423 | ||
|
|
92df786066 | ||
|
|
59aaa65381 | ||
|
|
715ffe4e51 | ||
|
|
51bb0ad36d | ||
|
|
4636dfe68e | ||
|
|
e3f6b2b082 | ||
|
|
968db9285f | ||
|
|
19f8ea37a5 | ||
|
|
99eb8ac059 | ||
|
|
3bcdc276e1 | ||
|
|
85dad8fb18 | ||
|
|
5f60640ddc | ||
|
|
f9e6e6eff9 | ||
|
|
7695f3f1ee | ||
|
|
3492077f33 | ||
|
|
0933c6796c | ||
|
|
137f45750f | ||
|
|
a0175137fb | ||
|
|
90eee5f909 | ||
|
|
a09dada8e4 |
@@ -324,7 +324,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
node -e "require('./src/utils/goma.js').ensure()"
|
||||
third_party/goma/goma_ctl.py ensure_start
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
cd ..
|
||||
|
||||
@@ -1 +1 @@
|
||||
11.2.2
|
||||
11.4.0
|
||||
@@ -93,6 +93,6 @@ steps:
|
||||
condition: always()
|
||||
|
||||
- powershell: |
|
||||
Remove-Item -path $env:APPDATA/Electron* -Recurse
|
||||
Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore
|
||||
displayName: 'Delete user app data directories'
|
||||
condition: always()
|
||||
|
||||
@@ -390,7 +390,7 @@ which contains more information about why the render process disappeared. It
|
||||
isn't always because it crashed. The `killed` boolean can be replaced by
|
||||
checking `reason === 'killed'` when you switch to that event.
|
||||
|
||||
#### Event: 'render-process-gone'
|
||||
### Event: 'render-process-gone'
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -409,7 +409,7 @@ Returns:
|
||||
Emitted when the renderer process unexpectedly disappears. This is normally
|
||||
because it was crashed or killed.
|
||||
|
||||
#### Event: 'child-process-gone'
|
||||
### Event: 'child-process-gone'
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -502,7 +502,7 @@ Returns:
|
||||
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will make it return empty sources.
|
||||
|
||||
### Event: 'remote-require'
|
||||
### Event: 'remote-require' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -514,7 +514,7 @@ Emitted when `remote.require()` is called in the renderer process of `webContent
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-global'
|
||||
### Event: 'remote-get-global' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -526,7 +526,7 @@ Emitted when `remote.getGlobal()` is called in the renderer process of `webConte
|
||||
Calling `event.preventDefault()` will prevent the global from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-builtin'
|
||||
### Event: 'remote-get-builtin' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -538,7 +538,7 @@ Emitted when `remote.getBuiltin()` is called in the renderer process of `webCont
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-current-window'
|
||||
### Event: 'remote-get-current-window' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -549,7 +549,7 @@ Emitted when `remote.getCurrentWindow()` is called in the renderer process of `w
|
||||
Calling `event.preventDefault()` will prevent the object from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
### Event: 'remote-get-current-web-contents'
|
||||
### Event: 'remote-get-current-web-contents' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@ Process: [Main](../glossary.md#main-process)
|
||||
// In the main process.
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
// Or use `remote` from the renderer process.
|
||||
// const { BrowserWindow } = require('electron').remote
|
||||
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
|
||||
// Load a remote URL
|
||||
@@ -733,7 +730,7 @@ The method will also not return if the extension's manifest is missing or incomp
|
||||
is emitted.
|
||||
|
||||
**Note:** This method is deprecated. Instead, use
|
||||
[`ses.loadExtension(path)`](session.md#sesloadextensionpath).
|
||||
[`ses.loadExtension(path)`](session.md#sesloadextensionpath-options).
|
||||
|
||||
#### `BrowserWindow.removeExtension(name)` _Deprecated_
|
||||
|
||||
@@ -775,7 +772,7 @@ The method will also not return if the extension's manifest is missing or incomp
|
||||
is emitted.
|
||||
|
||||
**Note:** This method is deprecated. Instead, use
|
||||
[`ses.loadExtension(path)`](session.md#sesloadextensionpath).
|
||||
[`ses.loadExtension(path)`](session.md#sesloadextensionpath-options).
|
||||
|
||||
#### `BrowserWindow.removeDevToolsExtension(name)` _Deprecated_
|
||||
|
||||
@@ -1444,7 +1441,7 @@ Returns `Boolean` - Whether the window's document has been edited.
|
||||
|
||||
Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
|
||||
|
||||
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
||||
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty.
|
||||
|
||||
#### `win.loadURL(url[, options])`
|
||||
|
||||
@@ -1852,6 +1849,13 @@ Replacement API for setBrowserView supporting work with multi browser views.
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md)
|
||||
|
||||
#### `win.setTopBrowserView(browserView)` _Experimental_
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md)
|
||||
|
||||
Raises `browserView` above other `BrowserView`s attached to `win`.
|
||||
Throws an error if `browserView` is not attached to `win`.
|
||||
|
||||
#### `win.getBrowserViews()` _Experimental_
|
||||
|
||||
Returns `BrowserView[]` - an array of all BrowserViews that have been attached
|
||||
|
||||
@@ -45,6 +45,8 @@ The following events are available on instances of `Cookies`:
|
||||
|
||||
#### Event: 'changed'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `cookie` [Cookie](structures/cookie.md) - The cookie that was changed.
|
||||
* `cause` String - The cause of the change with one of the following values:
|
||||
|
||||
@@ -11,14 +11,6 @@ const { dialog } = require('electron')
|
||||
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
|
||||
```
|
||||
|
||||
The Dialog is opened from Electron's main thread. If you want to use the dialog
|
||||
object from a renderer process, remember to access it using the remote:
|
||||
|
||||
```javascript
|
||||
const { dialog } = require('electron').remote
|
||||
console.log(dialog)
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
The `dialog` module has the following methods:
|
||||
|
||||
@@ -15,7 +15,7 @@ extension capabilities.
|
||||
|
||||
Electron only supports loading unpacked extensions (i.e., `.crx` files do not
|
||||
work). Extensions are installed per-`session`. To load an extension, call
|
||||
[`ses.loadExtension`](session.md#sesloadextensionpath):
|
||||
[`ses.loadExtension`](session.md#sesloadextensionpath-options):
|
||||
|
||||
```js
|
||||
const { session } = require('electron')
|
||||
|
||||
@@ -112,13 +112,19 @@ optional parameter can be used to forward mouse move messages to the web page,
|
||||
allowing events such as `mouseleave` to be emitted:
|
||||
|
||||
```javascript
|
||||
const win = require('electron').remote.getCurrentWindow()
|
||||
const { ipcRenderer } = require('electron')
|
||||
const el = document.getElementById('clickThroughElement')
|
||||
el.addEventListener('mouseenter', () => {
|
||||
win.setIgnoreMouseEvents(true, { forward: true })
|
||||
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
|
||||
})
|
||||
el.addEventListener('mouseleave', () => {
|
||||
win.setIgnoreMouseEvents(false)
|
||||
ipcRenderer.send('set-ignore-mouse-events', false)
|
||||
})
|
||||
|
||||
// Main process
|
||||
const { ipcMain } = require('electron')
|
||||
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
|
||||
BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -22,8 +22,10 @@ Sets `menu` as the application menu on macOS. On Windows and Linux, the
|
||||
Also on Windows and Linux, you can use a `&` in the top-level item name to
|
||||
indicate which letter should get a generated accelerator. For example, using
|
||||
`&File` for the file menu would result in a generated `Alt-F` accelerator that
|
||||
opens the associated menu. The indicated character in the button label gets an
|
||||
underline. The `&` character is not displayed on the button label.
|
||||
opens the associated menu. The indicated character in the button label then gets an
|
||||
underline, and the `&` character is not displayed on the button label.
|
||||
|
||||
In order to escape the `&` character in an item name, add a proceeding `&`. For example, `&&File` would result in `&File` displayed on the button label.
|
||||
|
||||
Passing `null` will suppress the default menu. On Windows and Linux,
|
||||
this has the additional effect of removing the menu bar from the window.
|
||||
@@ -141,13 +143,7 @@ can have a submenu.
|
||||
|
||||
## Examples
|
||||
|
||||
The `Menu` class is only available in the main process, but you can also use it
|
||||
in the render process via the [`remote`](remote.md) module.
|
||||
|
||||
### Main process
|
||||
|
||||
An example of creating the application menu in the main process with the
|
||||
simple template API:
|
||||
An example of creating the application menu with the simple template API:
|
||||
|
||||
```javascript
|
||||
const { app, Menu } = require('electron')
|
||||
@@ -257,26 +253,36 @@ Menu.setApplicationMenu(menu)
|
||||
|
||||
### Render process
|
||||
|
||||
Below is an example of creating a menu dynamically in a web page
|
||||
(render process) by using the [`remote`](remote.md) module, and showing it when
|
||||
the user right clicks the page:
|
||||
To create menus initiated by the renderer process, send the required
|
||||
information to the main process using IPC and have the main process display the
|
||||
menu on behalf of the renderer.
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
<script>
|
||||
const { remote } = require('electron')
|
||||
const { Menu, MenuItem } = remote
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({ label: 'MenuItem1', click() { console.log('item 1 clicked') } }))
|
||||
menu.append(new MenuItem({ type: 'separator' }))
|
||||
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }))
|
||||
Below is an example of showing a menu when the user right clicks the page:
|
||||
|
||||
```js
|
||||
// renderer
|
||||
window.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
menu.popup({ window: remote.getCurrentWindow() })
|
||||
}, false)
|
||||
</script>
|
||||
ipcRenderer.send('show-context-menu')
|
||||
})
|
||||
|
||||
ipcRenderer.on('context-menu-command', (e, command) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// main
|
||||
ipcMain.on('show-context-menu', (event) => {
|
||||
const template = [
|
||||
{
|
||||
label: 'Menu Item 1',
|
||||
click: () => { event.sender.send('context-menu-command', 'menu-item-1') }
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: 'Menu Item 2', type: 'checkbox', checked: true }
|
||||
]
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
menu.popup(BrowserWindow.fromWebContents(event.sender))
|
||||
})
|
||||
```
|
||||
|
||||
## Notes on macOS Application Menu
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
## Modernization
|
||||
|
||||
The Electron team is currently undergoing an initiative to modernize our API in a few concrete ways. These include: updating our modules to use idiomatic JS properties instead of separate `getPropertyX` and `setpropertyX`, converting callbacks to promises, and removing some other anti-patterns present in our APIs. The current status of the Promise initiative can be tracked in the [promisification](promisification.md) tracking file.
|
||||
|
||||
As we work to perform these updates, we seek to create the least disruptive amount of change at any given time, so as many changes as possible will be introduced in a backward compatible manner and deprecated after enough time has passed to give users a chance to upgrade their API calls.
|
||||
|
||||
This document and its child documents will be updated to reflect the latest status of our API changes.
|
||||
|
||||
* [Promisification](promisification.md)
|
||||
* [Property Updates](property-updates.md)
|
||||
@@ -1,42 +0,0 @@
|
||||
## Promisification
|
||||
|
||||
The Electron team recently underwent an initiative to convert callback-based APIs to Promise-based ones. See converted functions below:
|
||||
|
||||
- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
||||
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
||||
- [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript)
|
||||
- [contents.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#printToPDF)
|
||||
- [contents.savePage(fullPath, saveType, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#savePage)
|
||||
- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
||||
- [contentTracing.startRecording(options, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#startRecording)
|
||||
- [contentTracing.stopRecording(resultFilePath, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#stopRecording)
|
||||
- [contentTracing.getTraceBufferUsage(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getTraceBufferUsage)
|
||||
- [cookies.flushStore(callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#flushStore)
|
||||
- [cookies.get(filter, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#get)
|
||||
- [cookies.remove(url, name, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#remove)
|
||||
- [cookies.set(details, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#set)
|
||||
- [debugger.sendCommand(method[, commandParams, callback])](https://github.com/electron/electron/blob/master/docs/api/debugger.md#sendCommand)
|
||||
- [desktopCapturer.getSources(options, callback)](https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md#getSources)
|
||||
- [dialog.showOpenDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showOpenDialog)
|
||||
- [dialog.showSaveDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showSaveDialog)
|
||||
- [inAppPurchase.purchaseProduct(productID, quantity, callback)](https://github.com/electron/electron/blob/master/docs/api/in-app-purchase.md#purchaseProduct)
|
||||
- [inAppPurchase.getProducts(productIDs, callback)](https://github.com/electron/electron/blob/master/docs/api/in-app-purchase.md#getProducts)
|
||||
- [dialog.showMessageBox([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showMessageBox)
|
||||
- [dialog.showCertificateTrustDialog([browserWindow, ]options, callback)](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showCertificateTrustDialog)
|
||||
- [netLog.stopLogging([callback])](https://github.com/electron/electron/blob/master/docs/api/net-log.md#stopLogging)
|
||||
- [protocol.isProtocolHandled(scheme, callback)](https://github.com/electron/electron/blob/master/docs/api/protocol.md#isProtocolHandled)
|
||||
- [ses.clearHostResolverCache([callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearHostResolverCache)
|
||||
- [ses.clearStorageData([options, callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearStorageData)
|
||||
- [ses.setProxy(config, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#setProxy)
|
||||
- [ses.resolveProxy(url, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#resolveProxy)
|
||||
- [ses.getCacheSize(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getCacheSize)
|
||||
- [ses.clearAuthCache(options[, callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearAuthCache)
|
||||
- [ses.clearCache(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#clearCache)
|
||||
- [ses.getBlobData(identifier, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getBlobData)
|
||||
- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal)
|
||||
- [webFrame.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScript)
|
||||
- [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld)
|
||||
- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
||||
- [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript)
|
||||
- [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF)
|
||||
- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
||||
@@ -1,41 +0,0 @@
|
||||
## Property Updates
|
||||
|
||||
The Electron team is currently undergoing an initiative to convert separate getter and setter functions in Electron to bespoke properties with `get` and `set` functionality. During this transition period, both the new properties and old getters and setters of these functions will work correctly and be documented.
|
||||
|
||||
## Candidates
|
||||
|
||||
* `BrowserWindow`
|
||||
* `menubarVisible`
|
||||
* `crashReporter` module
|
||||
* `uploadToServer`
|
||||
* `webFrame` modules
|
||||
* `zoomFactor`
|
||||
* `zoomLevel`
|
||||
* `audioMuted`
|
||||
* `<webview>`
|
||||
* `zoomFactor`
|
||||
* `zoomLevel`
|
||||
* `audioMuted`
|
||||
|
||||
## Converted Properties
|
||||
|
||||
* `app` module
|
||||
* `accessibilitySupport`
|
||||
* `applicationMenu`
|
||||
* `badgeCount`
|
||||
* `name`
|
||||
* `DownloadItem` class
|
||||
* `savePath`
|
||||
* `BrowserWindow` module
|
||||
* `autohideMenuBar`
|
||||
* `resizable`
|
||||
* `maximizable`
|
||||
* `minimizable`
|
||||
* `fullscreenable`
|
||||
* `movable`
|
||||
* `closable`
|
||||
* `backgroundThrottling`
|
||||
* `NativeImage`
|
||||
* `isMacTemplateImage`
|
||||
* `SystemPreferences` module
|
||||
* `appLevelAppearance`
|
||||
@@ -88,26 +88,17 @@ and preload.js:
|
||||
|
||||
```js
|
||||
// This file is loaded whenever a javascript context is created. It runs in a
|
||||
// private scope that can access a subset of Electron renderer APIs. We must be
|
||||
// careful to not leak any objects into the global scope!
|
||||
const { ipcRenderer, remote } = require('electron')
|
||||
const fs = remote.require('fs')
|
||||
|
||||
// read a configuration file using the `fs` module
|
||||
const buf = fs.readFileSync('allowed-popup-urls.json')
|
||||
const allowedUrls = JSON.parse(buf.toString('utf8'))
|
||||
// private scope that can access a subset of Electron renderer APIs. Without
|
||||
// contextIsolation enabled, it's possible to accidentally leak privileged
|
||||
// globals like ipcRenderer to web content.
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const defaultWindowOpen = window.open
|
||||
|
||||
function customWindowOpen (url, ...args) {
|
||||
if (allowedUrls.indexOf(url) === -1) {
|
||||
ipcRenderer.sendSync('blocked-popup-notification', location.origin, url)
|
||||
return null
|
||||
}
|
||||
return defaultWindowOpen(url, ...args)
|
||||
window.open = function customWindowOpen (url, ...args) {
|
||||
ipcRenderer.send('report-window-open', location.origin, url, args)
|
||||
return defaultWindowOpen(url + '?from_electron=1', ...args)
|
||||
}
|
||||
|
||||
window.open = customWindowOpen
|
||||
```
|
||||
|
||||
Important things to notice in the preload script:
|
||||
@@ -115,8 +106,6 @@ Important things to notice in the preload script:
|
||||
- Even though the sandboxed renderer doesn't have Node.js running, it still has
|
||||
access to a limited node-like environment: `Buffer`, `process`, `setImmediate`,
|
||||
`clearImmediate` and `require` are available.
|
||||
- The preload script can indirectly access all APIs from the main process through the
|
||||
`remote` and `ipcRenderer` modules.
|
||||
- The preload script must be contained in a single script, but it is possible to have
|
||||
complex preload code composed with multiple modules by using a tool like
|
||||
webpack or browserify. An example of using browserify is below.
|
||||
@@ -144,15 +133,12 @@ following modules:
|
||||
- `desktopCapturer`
|
||||
- `ipcRenderer`
|
||||
- `nativeImage`
|
||||
- `remote`
|
||||
- `webFrame`
|
||||
- `events`
|
||||
- `timers`
|
||||
- `url`
|
||||
|
||||
More may be added as needed to expose more Electron APIs in the sandbox, but any
|
||||
module in the main process can already be used through
|
||||
`electron.remote.require`.
|
||||
More may be added as needed to expose more Electron APIs in the sandbox.
|
||||
|
||||
## Rendering untrusted content
|
||||
|
||||
|
||||
@@ -568,9 +568,13 @@ will not work on non-persistent (in-memory) sessions.
|
||||
|
||||
**Note:** On macOS and Windows 10 this word will be removed from the OS custom dictionary as well
|
||||
|
||||
#### `ses.loadExtension(path)`
|
||||
#### `ses.loadExtension(path[, options])`
|
||||
|
||||
* `path` String - Path to a directory containing an unpacked Chrome extension
|
||||
* `options` Object (optional)
|
||||
* `allowFileAccess` Boolean - Whether to allow the extension to read local files over `file://`
|
||||
protocol and inject content scripts into `file://` pages. This is required e.g. for loading
|
||||
devtools extensions on `file://` URLs. Defaults to false.
|
||||
|
||||
Returns `Promise<Extension>` - resolves when the extension is loaded.
|
||||
|
||||
@@ -593,7 +597,11 @@ const { app, session } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
app.on('ready', async () => {
|
||||
await session.defaultSession.loadExtension(path.join(__dirname, 'react-devtools'))
|
||||
await session.defaultSession.loadExtension(
|
||||
path.join(__dirname, 'react-devtools'),
|
||||
// allowFileAccess is required to load the devtools extension on file:// URLs.
|
||||
{ allowFileAccess: true }
|
||||
)
|
||||
// Note that in order to use the React DevTools extension, you'll need to
|
||||
// download and unzip a copy of the extension.
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@ the [native modules](../tutorial/using-native-node-modules.md)).
|
||||
Electron also provides some extra built-in modules for developing native
|
||||
desktop applications. Some modules are only available in the main process, some
|
||||
are only available in the renderer process (web page), and some can be used in
|
||||
both processes.
|
||||
either process type.
|
||||
|
||||
The basic rule is: if a module is [GUI][gui] or low-level system related, then
|
||||
it should be only available in the main process. You need to be familiar with
|
||||
@@ -29,15 +29,15 @@ app.whenReady().then(() => {
|
||||
```
|
||||
|
||||
The renderer process is no different than a normal web page, except for the
|
||||
extra ability to use node modules:
|
||||
extra ability to use node modules if `nodeIntegration` is enabled:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
const { app } = require('electron').remote
|
||||
console.log(app.getVersion())
|
||||
const fs = require('fs')
|
||||
console.log(fs.readFileSync(__filename, 'utf8'))
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -785,7 +785,7 @@ Returns:
|
||||
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will make it return empty sources.
|
||||
|
||||
#### Event: 'remote-require'
|
||||
#### Event: 'remote-require' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -796,7 +796,7 @@ Emitted when `remote.require()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-global'
|
||||
#### Event: 'remote-get-global' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -807,7 +807,7 @@ Emitted when `remote.getGlobal()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the global from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-builtin'
|
||||
#### Event: 'remote-get-builtin' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -818,7 +818,7 @@ Emitted when `remote.getBuiltin()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the module from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-current-window'
|
||||
#### Event: 'remote-get-current-window' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -828,7 +828,7 @@ Emitted when `remote.getCurrentWindow()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will prevent the object from being returned.
|
||||
Custom value can be returned by setting `event.returnValue`.
|
||||
|
||||
#### Event: 'remote-get-current-web-contents'
|
||||
#### Event: 'remote-get-current-web-contents' _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -1482,7 +1482,7 @@ An example of showing devtools in a `<webview>` tag:
|
||||
<webview id="browser" src="https://github.com"></webview>
|
||||
<webview id="devtools" src="about:blank"></webview>
|
||||
<script>
|
||||
const { webContents } = require('electron').remote
|
||||
const { ipcRenderer } = require('electron')
|
||||
const emittedOnce = (element, eventName) => new Promise(resolve => {
|
||||
element.addEventListener(eventName, event => resolve(event), { once: true })
|
||||
})
|
||||
@@ -1491,16 +1491,26 @@ An example of showing devtools in a `<webview>` tag:
|
||||
const browserReady = emittedOnce(browserView, 'dom-ready')
|
||||
const devtoolsReady = emittedOnce(devtoolsView, 'dom-ready')
|
||||
Promise.all([browserReady, devtoolsReady]).then(() => {
|
||||
const browser = webContents.fromId(browserView.getWebContentsId())
|
||||
const devtools = webContents.fromId(devtoolsView.getWebContentsId())
|
||||
browser.setDevToolsWebContents(devtools)
|
||||
browser.openDevTools()
|
||||
const targetId = browserView.getWebContentsId()
|
||||
const devtoolsId = devtoolsView.getWebContentsId()
|
||||
ipcRenderer.send('open-devtools', targetId, devtoolsId)
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const { ipcMain, webContents } = require('electron')
|
||||
ipcMain.on('open-devtools', (event, targetContentsId, devtoolsContentsId) => {
|
||||
const target = webContents.fromId(targetContentsId)
|
||||
const devtools = webContents.fromId(devtoolsContentsId)
|
||||
target.setDevToolsWebContents(devtools)
|
||||
target.openDevTools()
|
||||
})
|
||||
```
|
||||
|
||||
An example of showing devtools in a `BrowserWindow`:
|
||||
|
||||
```js
|
||||
|
||||
@@ -137,7 +137,7 @@ This option is disabled by default in the guest page.
|
||||
```
|
||||
|
||||
A `Boolean`. When this attribute is `false` the guest page in `webview` will not have access
|
||||
to the [`remote`](remote.md) module. The remote module is available by default.
|
||||
to the [`remote`](remote.md) module. The remote module is unavailable by default.
|
||||
|
||||
### `plugins`
|
||||
|
||||
|
||||
@@ -519,6 +519,55 @@ Note that `webkitdirectory` no longer exposes the path to the selected folder.
|
||||
If you require the path to the selected folder rather than the folder contents,
|
||||
see the `dialog.showOpenDialog` API ([link](https://github.com/electron/electron/blob/master/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options)).
|
||||
|
||||
### API Changed: Callback-based versions of promisified APIs
|
||||
|
||||
Electron 5 and Electron 6 introduced Promise-based versions of existing
|
||||
asynchronous APIs and deprecated their older, callback-based counterparts.
|
||||
In Electron 7, all deprecated callback-based APIs are now removed.
|
||||
|
||||
These functions now only return Promises:
|
||||
|
||||
* `app.getFileIcon()` [#15742](https://github.com/electron/electron/pull/15742)
|
||||
* `app.dock.show()` [#16904](https://github.com/electron/electron/pull/16904)
|
||||
* `contentTracing.getCategories()` [#16583](https://github.com/electron/electron/pull/16583)
|
||||
* `contentTracing.getTraceBufferUsage()` [#16600](https://github.com/electron/electron/pull/16600)
|
||||
* `contentTracing.startRecording()` [#16584](https://github.com/electron/electron/pull/16584)
|
||||
* `contentTracing.stopRecording()` [#16584](https://github.com/electron/electron/pull/16584)
|
||||
* `contents.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312)
|
||||
* `cookies.flushStore()` [#16464](https://github.com/electron/electron/pull/16464)
|
||||
* `cookies.get()` [#16464](https://github.com/electron/electron/pull/16464)
|
||||
* `cookies.remove()` [#16464](https://github.com/electron/electron/pull/16464)
|
||||
* `cookies.set()` [#16464](https://github.com/electron/electron/pull/16464)
|
||||
* `debugger.sendCommand()` [#16861](https://github.com/electron/electron/pull/16861)
|
||||
* `dialog.showCertificateTrustDialog()` [#17181](https://github.com/electron/electron/pull/17181)
|
||||
* `inAppPurchase.getProducts()` [#17355](https://github.com/electron/electron/pull/17355)
|
||||
* `inAppPurchase.purchaseProduct()`[#17355](https://github.com/electron/electron/pull/17355)
|
||||
* `netLog.stopLogging()` [#16862](https://github.com/electron/electron/pull/16862)
|
||||
* `session.clearAuthCache()` [#17259](https://github.com/electron/electron/pull/17259)
|
||||
* `session.clearCache()` [#17185](https://github.com/electron/electron/pull/17185)
|
||||
* `session.clearHostResolverCache()` [#17229](https://github.com/electron/electron/pull/17229)
|
||||
* `session.clearStorageData()` [#17249](https://github.com/electron/electron/pull/17249)
|
||||
* `session.getBlobData()` [#17303](https://github.com/electron/electron/pull/17303)
|
||||
* `session.getCacheSize()` [#17185](https://github.com/electron/electron/pull/17185)
|
||||
* `session.resolveProxy()` [#17222](https://github.com/electron/electron/pull/17222)
|
||||
* `session.setProxy()` [#17222](https://github.com/electron/electron/pull/17222)
|
||||
* `shell.openExternal()` [#16176](https://github.com/electron/electron/pull/16176)
|
||||
* `webContents.loadFile()` [#15855](https://github.com/electron/electron/pull/15855)
|
||||
* `webContents.loadURL()` [#15855](https://github.com/electron/electron/pull/15855)
|
||||
* `webContents.hasServiceWorker()` [#16535](https://github.com/electron/electron/pull/16535)
|
||||
* `webContents.printToPDF()` [#16795](https://github.com/electron/electron/pull/16795)
|
||||
* `webContents.savePage()` [#16742](https://github.com/electron/electron/pull/16742)
|
||||
* `webFrame.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312)
|
||||
* `webFrame.executeJavaScriptInIsolatedWorld()` [#17312](https://github.com/electron/electron/pull/17312)
|
||||
* `webviewTag.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312)
|
||||
* `win.capturePage()` [#15743](https://github.com/electron/electron/pull/15743)
|
||||
|
||||
These functions now have two forms, synchronous and Promise-based asynchronous:
|
||||
|
||||
* `dialog.showMessageBox()`/`dialog.showMessageBoxSync()` [#17298](https://github.com/electron/electron/pull/17298)
|
||||
* `dialog.showOpenDialog()`/`dialog.showOpenDialogSync()` [#16973](https://github.com/electron/electron/pull/16973)
|
||||
* `dialog.showSaveDialog()`/`dialog.showSaveDialogSync()` [#17054](https://github.com/electron/electron/pull/17054)
|
||||
|
||||
## Planned Breaking API Changes (6.0)
|
||||
|
||||
### API Changed: `win.setMenu(null)` is now `win.removeMenu()`
|
||||
@@ -530,19 +579,6 @@ win.setMenu(null)
|
||||
win.removeMenu()
|
||||
```
|
||||
|
||||
### API Changed: `contentTracing.getTraceBufferUsage()` is now a promise
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
contentTracing.getTraceBufferUsage((percentage, value) => {
|
||||
// do something
|
||||
})
|
||||
// Replace with
|
||||
contentTracing.getTraceBufferUsage().then(infoObject => {
|
||||
// infoObject has percentage and value fields
|
||||
})
|
||||
```
|
||||
|
||||
### API Changed: `electron.screen` in the renderer process should be accessed via `remote`
|
||||
|
||||
```js
|
||||
@@ -679,6 +715,31 @@ webFrame.setSpellCheckProvider('en-US', {
|
||||
})
|
||||
```
|
||||
|
||||
### API Changed: `webContents.getZoomLevel` and `webContents.getZoomFactor` are now synchronous
|
||||
|
||||
`webContents.getZoomLevel` and `webContents.getZoomFactor` no longer take callback parameters,
|
||||
instead directly returning their number values.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
webContents.getZoomLevel((level) => {
|
||||
console.log(level)
|
||||
})
|
||||
// Replace with
|
||||
const level = webContents.getZoomLevel()
|
||||
console.log(level)
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
webContents.getZoomFactor((factor) => {
|
||||
console.log(factor)
|
||||
})
|
||||
// Replace with
|
||||
const factor = webContents.getZoomFactor()
|
||||
console.log(factor)
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (4.0)
|
||||
|
||||
The following list includes the breaking API changes made in Electron 4.0.
|
||||
|
||||
@@ -69,8 +69,7 @@ way of figuring out which is which.
|
||||
### Which Process Should I Attach to?
|
||||
|
||||
Code executed within the main process (that is, code found in or eventually run
|
||||
by your main JavaScript file) as well as code called using the remote
|
||||
(`require('electron').remote`) will run inside the main process, while other
|
||||
by your main JavaScript file) will run inside the main process, while other
|
||||
code will execute inside its respective renderer process.
|
||||
|
||||
You can be attached to multiple programs when you are debugging, but only one
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const { BrowserWindow, app } = require('electron')
|
||||
const { BrowserWindow, app, screen, ipcMain } = require('electron')
|
||||
|
||||
let mainWindow = null
|
||||
|
||||
ipcMain.handle('get-screen-size', () => {
|
||||
return screen.getPrimaryDisplay().workAreaSize
|
||||
})
|
||||
|
||||
function createWindow () {
|
||||
const windowOptions = {
|
||||
width: 600,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const { desktopCapturer } = require('electron')
|
||||
const { screen, shell } = require('electron').remote
|
||||
const { desktopCapturer, shell, ipcRenderer } = require('electron')
|
||||
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
@@ -8,9 +7,9 @@ const path = require('path')
|
||||
const screenshot = document.getElementById('screen-shot')
|
||||
const screenshotMsg = document.getElementById('screenshot-path')
|
||||
|
||||
screenshot.addEventListener('click', (event) => {
|
||||
screenshot.addEventListener('click', async (event) => {
|
||||
screenshotMsg.textContent = 'Gathering screens...'
|
||||
const thumbSize = determineScreenShotSize()
|
||||
const thumbSize = await determineScreenShotSize()
|
||||
const options = { types: ['screen'], thumbnailSize: thumbSize }
|
||||
|
||||
desktopCapturer.getSources(options, (error, sources) => {
|
||||
@@ -33,8 +32,8 @@ screenshot.addEventListener('click', (event) => {
|
||||
})
|
||||
})
|
||||
|
||||
function determineScreenShotSize () {
|
||||
const screenSize = screen.getPrimaryDisplay().workAreaSize
|
||||
async function determineScreenShotSize () {
|
||||
const screenSize = await ipcRenderer.invoke('get-screen-size')
|
||||
const maxDimension = Math.max(screenSize.width, screenSize.height)
|
||||
return {
|
||||
width: maxDimension * window.devicePixelRatio,
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
|
||||
let mainWindow = null
|
||||
ipcMain.on('create-frameless-window', (event, {url}) => {
|
||||
const win = new BrowserWindow({ frame: false })
|
||||
win.loadURL(url)
|
||||
})
|
||||
|
||||
function createWindow () {
|
||||
const windowOptions = {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 600,
|
||||
height: 400,
|
||||
title: 'Create a frameless window',
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
}
|
||||
|
||||
mainWindow = new BrowserWindow(windowOptions)
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
})
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const newWindowBtn = document.getElementById('frameless-window')
|
||||
|
||||
newWindowBtn.addEventListener('click', (event) => {
|
||||
let win = new BrowserWindow({ frame: false })
|
||||
|
||||
win.on('close', () => { win = null })
|
||||
|
||||
win.loadURL('data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>')
|
||||
win.show()
|
||||
newWindowBtn.addEventListener('click', () => {
|
||||
const url = 'data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>'
|
||||
ipcRenderer.send('create-frameless-window', { url })
|
||||
})
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
ipcMain.on('create-frameless-window', (event, {url}) => {
|
||||
const win = new BrowserWindow({ frame: false })
|
||||
win.loadURL(url)
|
||||
})
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
@@ -17,17 +18,6 @@ function createWindow () {
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const framelessWindowBtn = document.getElementById('frameless-window')
|
||||
const newWindowBtn = document.getElementById('frameless-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
framelessWindowBtn.addEventListener('click', (event) => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
let win = new BrowserWindow({ frame: false })
|
||||
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
newWindowBtn.addEventListener('click', () => {
|
||||
const url = 'data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>'
|
||||
ipcRenderer.send('create-frameless-window', { url })
|
||||
})
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
ipcMain.on('create-demo-window', (event) => {
|
||||
const win = new BrowserWindow({ width: 400, height: 275 })
|
||||
|
||||
function updateReply() {
|
||||
event.sender.send('bounds-changed', {
|
||||
size: win.getSize(),
|
||||
position: win.getPosition()
|
||||
})
|
||||
}
|
||||
|
||||
win.on('resize', updateReply)
|
||||
win.on('move', updateReply)
|
||||
win.loadURL('https://electronjs.org')
|
||||
})
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
@@ -17,17 +28,6 @@ function createWindow () {
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
const { shell, ipcRenderer } = require('electron')
|
||||
|
||||
const manageWindowBtn = document.getElementById('manage-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let win
|
||||
ipcRenderer.on('bounds-changed', (event, bounds) => {
|
||||
const manageWindowReply = document.getElementById('manage-window-reply')
|
||||
const message = `Size: ${bounds.size} Position: ${bounds.position}`
|
||||
manageWindowReply.textContent = message
|
||||
})
|
||||
|
||||
manageWindowBtn.addEventListener('click', (event) => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
win = new BrowserWindow({ width: 400, height: 275 })
|
||||
|
||||
win.on('resize', updateReply)
|
||||
win.on('move', updateReply)
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
|
||||
function updateReply () {
|
||||
const manageWindowReply = document.getElementById('manage-window-reply')
|
||||
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
|
||||
manageWindowReply.innerText = message
|
||||
}
|
||||
ipcRenderer.send('create-demo-window')
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h2>Create a new window</h2>
|
||||
<h3>Supports: Win, macOS, Linux <span>|</span> Process: Main</h3>
|
||||
<button id="new-window">View Demo</button>
|
||||
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app. This main process module can be used from the renderer process with the <code>remote</code> module, as is shown in this demo.</p>
|
||||
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app.</p>
|
||||
<p>There are a lot of options when creating a new window. A few are in this demo, but visit the <a id="browser-window-link" href="">documentation<span>(opens in new window)</span></a>
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
ipcMain.on('new-window', (event, { url, width, height }) => {
|
||||
const win = new BrowserWindow({ width, height })
|
||||
win.loadURL(url)
|
||||
})
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
@@ -17,17 +18,6 @@ function createWindow () {
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const { shell } = require('electron').remote
|
||||
const { shell, ipcRenderer } = require('electron')
|
||||
|
||||
const newWindowBtn = document.getElementById('new-window')
|
||||
const link = document.getElementById('browser-window-link')
|
||||
|
||||
newWindowBtn.addEventListener('click', (event) => {
|
||||
|
||||
let win = new BrowserWindow({ width: 400, height: 320 })
|
||||
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL('https://electronjs.org')
|
||||
win.show()
|
||||
const url = 'https://electronjs.org'
|
||||
ipcRenderer.send('new-window', { url, width: 400, height: 320 });
|
||||
})
|
||||
|
||||
link.addEventListener('click', (e) => {
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
@@ -18,15 +14,27 @@ function createWindow () {
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
let demoWindow
|
||||
ipcMain.on('show-demo-window', () => {
|
||||
if (demoWindow) {
|
||||
demoWindow.focus()
|
||||
return
|
||||
}
|
||||
demoWindow = new BrowserWindow({ width: 600, height: 400 })
|
||||
demoWindow.loadURL('https://electronjs.org')
|
||||
demoWindow.on('close', () => {
|
||||
mainWindow.webContents.send('window-close')
|
||||
})
|
||||
demoWindow.on('focus', () => {
|
||||
mainWindow.webContents.send('window-focus')
|
||||
})
|
||||
demoWindow.on('blur', () => {
|
||||
mainWindow.webContents.send('window-blur')
|
||||
})
|
||||
})
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
ipcMain.on('focus-demo-window', () => {
|
||||
if (demoWindow) demoWindow.focus()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +1,33 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
const { shell, ipcRenderer } = require('electron')
|
||||
|
||||
const listenToWindowBtn = document.getElementById('listen-to-window')
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
const hideFocusBtn = () => {
|
||||
focusModalBtn.classList.add('disappear')
|
||||
focusModalBtn.classList.remove('smooth-appear')
|
||||
focusModalBtn.removeEventListener('click', focusWindow)
|
||||
}
|
||||
|
||||
let win
|
||||
const showFocusBtn = (btn) => {
|
||||
focusModalBtn.classList.add('smooth-appear')
|
||||
focusModalBtn.classList.remove('disappear')
|
||||
focusModalBtn.addEventListener('click', focusWindow)
|
||||
}
|
||||
const focusWindow = () => {
|
||||
ipcRenderer.send('focus-demo-window')
|
||||
}
|
||||
|
||||
ipcRenderer.on('window-focus', hideFocusBtn)
|
||||
ipcRenderer.on('window-close', hideFocusBtn)
|
||||
ipcRenderer.on('window-blur', showFocusBtn)
|
||||
|
||||
listenToWindowBtn.addEventListener('click', () => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
win = new BrowserWindow({ width: 600, height: 400 })
|
||||
|
||||
const hideFocusBtn = () => {
|
||||
focusModalBtn.classList.add('disappear')
|
||||
focusModalBtn.classList.remove('smooth-appear')
|
||||
focusModalBtn.removeEventListener('click', clickHandler)
|
||||
}
|
||||
|
||||
const showFocusBtn = (btn) => {
|
||||
if (!win) return
|
||||
focusModalBtn.classList.add('smooth-appear')
|
||||
focusModalBtn.classList.remove('disappear')
|
||||
focusModalBtn.addEventListener('click', clickHandler)
|
||||
}
|
||||
|
||||
win.on('focus', hideFocusBtn)
|
||||
win.on('blur', showFocusBtn)
|
||||
win.on('close', () => {
|
||||
hideFocusBtn()
|
||||
win = null
|
||||
})
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
|
||||
const clickHandler = () => { win.focus() }
|
||||
ipcRenderer.send('show-demo-window')
|
||||
})
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
|
||||
@@ -26,7 +26,8 @@ To test In-App Purchase in development with Electron you'll have to change the `
|
||||
Here is an example that shows how to use In-App Purchases in Electron. You'll have to replace the product ids by the identifiers of the products created with iTunes Connect (the identifier of `com.example.app.product1` is `product1`). Note that you have to listen to the `transactions-updated` event as soon as possible in your app.
|
||||
|
||||
```javascript
|
||||
const { inAppPurchase } = require('electron').remote
|
||||
// Main process
|
||||
const { inAppPurchase } = require('electron')
|
||||
const PRODUCT_IDS = ['id1', 'id2']
|
||||
|
||||
// Listen for transactions as soon as possible.
|
||||
|
||||
@@ -34,7 +34,6 @@ auto_filenames = {
|
||||
"docs/api/menu.md",
|
||||
"docs/api/message-channel-main.md",
|
||||
"docs/api/message-port-main.md",
|
||||
"docs/api/modernization",
|
||||
"docs/api/native-image.md",
|
||||
"docs/api/native-theme.md",
|
||||
"docs/api/net-log.md",
|
||||
|
||||
@@ -43,7 +43,7 @@ Object.defineProperty(BaseWindow.prototype, 'kiosk', {
|
||||
});
|
||||
|
||||
Object.defineProperty(BaseWindow.prototype, 'documentEdited', {
|
||||
get: function () { return this.isFullscreen(); },
|
||||
get: function () { return this.isDocumentEdited(); },
|
||||
set: function (edited) { this.setDocumentEdited(edited); }
|
||||
});
|
||||
|
||||
|
||||
@@ -92,11 +92,7 @@ BrowserWindow.getFocusedWindow = () => {
|
||||
};
|
||||
|
||||
BrowserWindow.fromWebContents = (webContents: WebContents) => {
|
||||
for (const window of BrowserWindow.getAllWindows()) {
|
||||
if (window.webContents && window.webContents.equal(webContents)) return window;
|
||||
}
|
||||
|
||||
return null;
|
||||
return webContents.getOwnerBrowserWindow();
|
||||
};
|
||||
|
||||
BrowserWindow.fromBrowserView = (browserView: BrowserView) => {
|
||||
|
||||
@@ -18,7 +18,7 @@ class CrashReporter {
|
||||
|
||||
if (submitURL == null) throw new Error('submitURL is a required option to crashReporter.start');
|
||||
|
||||
if (!compress) {
|
||||
if (!compress && uploadToServer) {
|
||||
deprecate.log('Sending uncompressed crash reports is deprecated and will be removed in a future version of Electron. Set { compress: true } to opt-in to the new behavior. Crash reports will be uploaded gzipped, which most crash reporting servers support.');
|
||||
}
|
||||
|
||||
|
||||
@@ -605,7 +605,6 @@ WebContents.prototype._init = function () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webContents,
|
||||
title: frameName,
|
||||
webPreferences,
|
||||
...options
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ const getPreloadScript = async function (preloadPath: string) {
|
||||
let preloadSrc = null;
|
||||
let preloadError = null;
|
||||
try {
|
||||
preloadSrc = (await fs.promises.readFile(preloadPath)).toString();
|
||||
preloadSrc = await fs.promises.readFile(preloadPath, 'utf8');
|
||||
} catch (error) {
|
||||
preloadError = error;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class WebFrame extends EventEmitter {
|
||||
}
|
||||
|
||||
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
|
||||
const worldSafeJS = hasSwitch('world-safe-execute-javascript') && hasSwitch('context-isolation');
|
||||
const worldSafeJS = hasSwitch('world-safe-execute-javascript') || !hasSwitch('context-isolation');
|
||||
|
||||
// Populate the methods.
|
||||
for (const name in binding) {
|
||||
|
||||
@@ -224,7 +224,7 @@ const warnAboutExperimentalFeatures = function (webPreferences?: Electron.WebPre
|
||||
const warnAboutEnableBlinkFeatures = function (webPreferences?: Electron.WebPreferences) {
|
||||
if (!webPreferences ||
|
||||
!Object.prototype.hasOwnProperty.call(webPreferences, 'enableBlinkFeatures') ||
|
||||
(webPreferences.enableBlinkFeatures && webPreferences.enableBlinkFeatures.length === 0)) {
|
||||
(webPreferences.enableBlinkFeatures != null && webPreferences.enableBlinkFeatures.length === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "11.2.2",
|
||||
"version": "11.4.0",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
expose_ripemd160.patch
|
||||
expose_aes-cfb.patch
|
||||
expose_des-ede3.patch
|
||||
|
||||
40
patches/boringssl/expose_des-ede3.patch
Normal file
40
patches/boringssl/expose_des-ede3.patch
Normal file
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Rose <nornagon@nornagon.net>
|
||||
Date: Wed, 24 Feb 2021 11:08:34 -0800
|
||||
Subject: expose des-ede3
|
||||
|
||||
This should be upstreamed.
|
||||
|
||||
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
|
||||
index 588a4773437c311877f275bf3679f9688cda3c46..e771ed6589b4579cc35300d5b2a1b68d92e444f5 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -93,6 +93,8 @@ const EVP_CIPHER *EVP_get_cipherbyname(const char *name) {
|
||||
return EVP_rc4();
|
||||
} else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) {
|
||||
return EVP_des_cbc();
|
||||
+ } else if (OPENSSL_strcasecmp(name, "des-ede3") == 0) {
|
||||
+ return EVP_des_ede3();
|
||||
} else if (OPENSSL_strcasecmp(name, "des-ede3-cbc") == 0 ||
|
||||
// This is not a name used by OpenSSL, but tcpdump registers it
|
||||
// with |EVP_add_cipher_alias|. Our |EVP_add_cipher_alias| is a
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index 84af06fc56e4aa72d4d48801d7c037add0221747..fe412e350f43ad20758025da6b9754952d164938 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -39,6 +39,7 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
callback(EVP_des_cbc(), "DES-CBC", NULL, arg);
|
||||
callback(EVP_des_ecb(), "DES-ECB", NULL, arg);
|
||||
callback(EVP_des_ede(), "DES-EDE", NULL, arg);
|
||||
+ callback(EVP_des_ede3(), "DES-EDE3", NULL, arg);
|
||||
callback(EVP_des_ede_cbc(), "DES-EDE-CBC", NULL, arg);
|
||||
callback(EVP_des_ede3_cbc(), "DES-EDE3-CBC", NULL, arg);
|
||||
callback(EVP_rc2_cbc(), "RC2-CBC", NULL, arg);
|
||||
@@ -65,6 +66,7 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
callback(EVP_des_cbc(), "des-cbc", NULL, arg);
|
||||
callback(EVP_des_ecb(), "des-ecb", NULL, arg);
|
||||
callback(EVP_des_ede(), "des-ede", NULL, arg);
|
||||
+ callback(EVP_des_ede3(), "des-ede3", NULL, arg);
|
||||
callback(EVP_des_ede_cbc(), "des-ede-cbc", NULL, arg);
|
||||
callback(EVP_des_ede3_cbc(), "des-ede3-cbc", NULL, arg);
|
||||
callback(EVP_rc2_cbc(), "rc2-cbc", NULL, arg);
|
||||
@@ -116,3 +116,21 @@ cherry-pick-06fe641d21bd.patch
|
||||
cherry-pick-3f7b67374a11.patch
|
||||
ots_backport_maxp_sanitization.patch
|
||||
ots_backport_of_glyf_guard_access_to_maxp_version_1_field.patch
|
||||
cherry-pick-df438f22f7d2.patch
|
||||
cherry-pick-5c7ad5393f74.patch
|
||||
replace_clearfilterdata_with_invalidatefilterdata.patch
|
||||
cherry-pick-5902d1aa722a.patch
|
||||
cherry-pick-76cb1cc32baa.patch
|
||||
disable_gpu_acceleration_on_all_mesa_software_rasterizers.patch
|
||||
stop_using_raw_webcontents_ptr_in_dragdownloadfile.patch
|
||||
fix_heap_overflow_in_videoframeyuvconverter.patch
|
||||
merge_to_m88_avoid_spinning_a_nested_message_loop_for_x11_clipboard.patch
|
||||
merge_to_m88_xproto_switch_event_queue_from_a_std_list_to_a.patch
|
||||
websocket_don_t_clear_event_queue_on_destruction.patch
|
||||
cherry-pick-7e0e52df283c.patch
|
||||
cherry-pick-6ed1c0c425e0.patch
|
||||
cherry-pick-aeb6bc551b60.patch
|
||||
cherry-pick-eb0c0353bf24.patch
|
||||
mediarecorder_tolerate_non-gmb_nv12_frames_for_h264.patch
|
||||
cherry-pick-18d3f86206e8.patch
|
||||
cherry-pick-6e8856624cbb.patch
|
||||
|
||||
156
patches/chromium/cherry-pick-18d3f86206e8.patch
Normal file
156
patches/chromium/cherry-pick-18d3f86206e8.patch
Normal file
@@ -0,0 +1,156 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christoph Schwering <schwering@google.com>
|
||||
Date: Tue, 24 Nov 2020 23:39:39 +0000
|
||||
Subject: Limit preview and filling only for non-state fields.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The number of times a value is filled into different fields is limited.
|
||||
The exception are state fields because websites sometimes have one
|
||||
state select box for each country and display the relevant select
|
||||
box once the respective country has been selected.
|
||||
|
||||
This CL simplifies this mechanism and makes it more explicit by
|
||||
encoding the type-dependent limits in TypeValueFormFillingLimit().
|
||||
As a side effect, the limits apply not just to filled fields but also
|
||||
unfilled fields of the same type.
|
||||
|
||||
Bug: 1075734, 1084903
|
||||
Change-Id: Icc5e8e082850ed44d9c7fbbc911d03a95033d81f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2557977
|
||||
Commit-Queue: Matthias Körber <koerber@google.com>
|
||||
Reviewed-by: Matthias Körber <koerber@google.com>
|
||||
Auto-Submit: Christoph Schwering <schwering@google.com>
|
||||
Cr-Commit-Position: refs/heads/master@{#830778}
|
||||
|
||||
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
|
||||
index a9dd2e727ddb68331e684716055af42166d69986..0b72ac3b8a0d3bb3294be995d2b9a4bc52b81a8f 100644
|
||||
--- a/components/autofill/core/browser/autofill_manager.cc
|
||||
+++ b/components/autofill/core/browser/autofill_manager.cc
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "base/check_op.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/adapters.h"
|
||||
+#include "base/containers/flat_map.h"
|
||||
#include "base/feature_list.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/guid.h"
|
||||
@@ -432,9 +433,15 @@ const char* SubmissionSourceToString(SubmissionSource source) {
|
||||
|
||||
// Returns how many fields with type |field_type| may be filled in a form at
|
||||
// maximum.
|
||||
-int TypeValueFormFillingLimit(ServerFieldType field_type) {
|
||||
- return field_type == CREDIT_CARD_NUMBER ? kCreditCardTypeValueFormFillingLimit
|
||||
- : kTypeValueFormFillingLimit;
|
||||
+size_t TypeValueFormFillingLimit(ServerFieldType field_type) {
|
||||
+ switch (field_type) {
|
||||
+ case CREDIT_CARD_NUMBER:
|
||||
+ return kCreditCardTypeValueFormFillingLimit;
|
||||
+ case ADDRESS_HOME_STATE:
|
||||
+ return kStateTypeValueFormFillingLimit;
|
||||
+ default:
|
||||
+ return kTypeValueFormFillingLimit;
|
||||
+ }
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -1760,7 +1767,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
|
||||
|
||||
// Count the number of times the value of a specific type was filled into the
|
||||
// form.
|
||||
- std::map<ServerFieldType, int> type_filling_count;
|
||||
+ base::flat_map<ServerFieldType, size_t> type_filling_count;
|
||||
+ type_filling_count.reserve(form_structure->field_count());
|
||||
|
||||
for (size_t i = 0; i < form_structure->field_count(); ++i) {
|
||||
std::string field_number = base::StringPrintf("Field %zu", i);
|
||||
@@ -1852,7 +1860,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
|
||||
|
||||
// A field with a specific type is only allowed to be filled a limited
|
||||
// number of times given by |TypeValueFormFillingLimit(field_type)|.
|
||||
- if (type_filling_count[field_type] >=
|
||||
+ if (++type_filling_count[field_type] >
|
||||
TypeValueFormFillingLimit(field_type)) {
|
||||
buffer << Tr{} << field_number
|
||||
<< "Skipped: field-type filling-limit reached";
|
||||
@@ -1887,10 +1895,6 @@ void AutofillManager::FillOrPreviewDataModelForm(
|
||||
bool has_value_after = !result.fields[i].value.empty();
|
||||
bool is_autofilled_after = result.fields[i].is_autofilled;
|
||||
|
||||
- // If the field was actually filled, increment the filling counter.
|
||||
- if (is_autofilled_after)
|
||||
- type_filling_count[field_type]++;
|
||||
-
|
||||
buffer << Tr{} << field_number
|
||||
<< base::StringPrintf(
|
||||
"Fillable - has value: %d->%d; autofilled: %d->%d. %s",
|
||||
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
|
||||
index 7d296d95b25f126cb9176af3292687965987c123..26573cfa9f71e45a8087a4a0e76f3ddfa3f4f81c 100644
|
||||
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
|
||||
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
|
||||
@@ -2947,6 +2947,14 @@ TEST_P(AutofillManagerStructuredProfileTest,
|
||||
form.fields.push_back(field);
|
||||
}
|
||||
|
||||
+ // Create a selection box for the state that hat the correct entry to be
|
||||
+ // filled with user data. Note, TN is the official abbreviation for Tennessee.
|
||||
+ for (int i = 0; i < 20; ++i) {
|
||||
+ test::CreateTestSelectField("Country", "country", "", {"DE", "FR", "US"},
|
||||
+ {"DE", "FR", "US"}, 3, &field);
|
||||
+ form.fields.push_back(field);
|
||||
+ }
|
||||
+
|
||||
std::vector<FormData> forms(1, form);
|
||||
FormsSeen(forms);
|
||||
|
||||
@@ -2983,17 +2991,18 @@ TEST_P(AutofillManagerStructuredProfileTest,
|
||||
response_data.fields[4 + i]);
|
||||
}
|
||||
|
||||
- // Verify that the next 8 selection boxes are correctly filled again.
|
||||
- for (int i = 0; i < 8; i++) {
|
||||
+ // Verify that the remaining selection boxes are correctly filled again
|
||||
+ // because there's no limit on filling ADDRESS_HOME_STATE fields.
|
||||
+ for (int i = 0; i < 20; i++) {
|
||||
ExpectFilledField("State", "state", "TN", "select-one",
|
||||
response_data.fields[24 + i]);
|
||||
}
|
||||
|
||||
- // Verify that the last 12 boxes are not filled because the filling limit for
|
||||
- // the state type is already reached.
|
||||
- for (int i = 0; i < 12; i++) {
|
||||
- ExpectFilledField("State", "state", "", "select-one",
|
||||
- response_data.fields[32 + i]);
|
||||
+ // Verify that only the first 9 of the remaining selection boxes are
|
||||
+ // correctly filled due to the limit on filling ADDRESS_HOME_COUNTRY fields.
|
||||
+ for (int i = 0; i < 20; i++) {
|
||||
+ ExpectFilledField("Country", "country", i < 9 ? "US" : "", "select-one",
|
||||
+ response_data.fields[44 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/components/autofill/core/common/autofill_constants.h b/components/autofill/core/common/autofill_constants.h
|
||||
index 84c5b916b0330ab8305db7b1831b42fa42843708..2d6ade5e6bea81ec4383d0345863514e1b551ea8 100644
|
||||
--- a/components/autofill/core/common/autofill_constants.h
|
||||
+++ b/components/autofill/core/common/autofill_constants.h
|
||||
@@ -68,12 +68,14 @@ const int64_t kAutocompleteRetentionPolicyPeriodInDays = 14 * 31;
|
||||
|
||||
// Limits the number of times the value of a specific type can be filled into a
|
||||
// form.
|
||||
-constexpr int kTypeValueFormFillingLimit = 9;
|
||||
-
|
||||
// Credit card numbers are sometimes distributed between up to 19 individual
|
||||
-// fields. Therefore, credit cards need a higher limit compared to
|
||||
-// |kTypeValueFormFillingLimit|.
|
||||
-constexpr int kCreditCardTypeValueFormFillingLimit = 19;
|
||||
+// fields. Therefore, credit cards need a higher limit.
|
||||
+// State fields are effecectively unlimited because there are sometimes hidden
|
||||
+// fields select boxes, each with a list of states for one specific countries,
|
||||
+// which are displayed only upon country selection.
|
||||
+constexpr size_t kTypeValueFormFillingLimit = 9;
|
||||
+constexpr size_t kCreditCardTypeValueFormFillingLimit = 19;
|
||||
+constexpr size_t kStateTypeValueFormFillingLimit = 1000;
|
||||
|
||||
} // namespace autofill
|
||||
|
||||
154
patches/chromium/cherry-pick-5902d1aa722a.patch
Normal file
154
patches/chromium/cherry-pick-5902d1aa722a.patch
Normal file
@@ -0,0 +1,154 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Robinson <mrobinson@igalia.com>
|
||||
Date: Fri, 15 Jan 2021 10:52:00 +0000
|
||||
Subject: Use the native combobox a11y role more often on MacOS
|
||||
|
||||
Instead of mapping the ARIA combobox role to other roles on MacOS,
|
||||
always use it unless it is applied to a multiline edit field. This
|
||||
matches the specified behavior and other browsers.
|
||||
|
||||
These were originally mapped to other roles because of VoiceOver
|
||||
failures that have been fixed with other changes.
|
||||
|
||||
Bug: 1125165
|
||||
Change-Id: I26b8ccb006c15d6329da1c29193640f529fab781
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2611093
|
||||
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
|
||||
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
|
||||
Cr-Commit-Position: refs/heads/master@{#844021}
|
||||
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
|
||||
index 71f927cd35a27dd5f656907dc177fbfe7577d3f0..9e32394d5d3eceb41873302ac1ab3b24de7d3d0f 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
|
||||
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
|
||||
@@ -1988,7 +1988,7 @@ - (NSString*)role {
|
||||
cocoa_role = NSAccessibilityGroupRole;
|
||||
} else if ((_owner->IsPlainTextField() &&
|
||||
_owner->HasState(ax::mojom::State::kMultiline)) ||
|
||||
- _owner->IsRichTextField()) {
|
||||
+ (_owner->IsRichTextField() && !ui::IsComboBox(role))) {
|
||||
cocoa_role = NSAccessibilityTextAreaRole;
|
||||
} else if (role == ax::mojom::Role::kImage &&
|
||||
_owner->HasExplicitlyEmptyName()) {
|
||||
diff --git a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
|
||||
index f30f15e3e3cb50d7d5f31ce3c15fcd5d533e8c12..a3fe1ad8d3ea617b99fd9ffbbfc2b3ff8094b190 100644
|
||||
--- a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
|
||||
@@ -1,7 +1,8 @@
|
||||
AXWebArea AXFocused=1
|
||||
++AXGroup
|
||||
++++AXStaticText AXValue='Choose a fruit, with text content'
|
||||
-++AXPopUpButton AXLinkedUIElements=[:6] AXTitle='Choose a fruit, with text content' AXValue='Apple'
|
||||
+++AXComboBox AXLinkedUIElements=[:6] AXTitle='Choose a fruit, with text content' AXValue='Apple'
|
||||
+
|
||||
++++AXStaticText AXValue='Apple'
|
||||
++AXList
|
||||
++++AXStaticText AXValue='Apple'
|
||||
diff --git a/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt b/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
|
||||
index de0f31f2065490d6085027e2800706a3926bcf5b..00280bbe561555168bdac1e39a513ce99d0f249d 100644
|
||||
--- a/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
|
||||
@@ -1,10 +1,10 @@
|
||||
AXWebArea
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='menu'
|
||||
-++AXPopUpButton
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='menu'
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox'
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='grid'
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='dialog'
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='menu'
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox'
|
||||
-++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='menu'
|
||||
+++AXComboButton
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='menu'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='listbox'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='grid'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='dialog'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='menu'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='listbox'
|
||||
+++AXComboButton AXHasPopup=1 AXPopupValue='listbox'
|
||||
diff --git a/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt b/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
|
||||
index 4c605836da4804e91142dcaedd45dc4e0c259756..c04259a0a2148413b0482595e91c7a750df8a7bd 100644
|
||||
--- a/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
|
||||
@@ -1,7 +1,7 @@
|
||||
AXWebArea
|
||||
-++AXGroup
|
||||
-++AXGroup AXOrientation='AXHorizontalOrientation'
|
||||
-++AXGroup AXOrientation='AXVerticalOrientation'
|
||||
+++AXComboBox
|
||||
+++AXComboBox AXOrientation='AXHorizontalOrientation'
|
||||
+++AXComboBox AXOrientation='AXVerticalOrientation'
|
||||
++AXList AXOrientation='AXVerticalOrientation'
|
||||
++AXList AXOrientation='AXHorizontalOrientation'
|
||||
++AXList AXOrientation='AXVerticalOrientation'
|
||||
diff --git a/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt b/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
|
||||
index b942711938c6c839317e6b96fd9e4a6aa98ee451..96f8201c834b12be7b490f23c1e2d65ab2149c96 100644
|
||||
--- a/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
|
||||
@@ -1,12 +1,12 @@
|
||||
AXWebArea
|
||||
++AXGroup
|
||||
++++AXStaticText AXValue='State'
|
||||
-++AXGroup AXTitle='State'
|
||||
+++AXComboBox AXTitle='State'
|
||||
++++AXTextField AXLinkedUIElements=[:6]
|
||||
++AXList
|
||||
++++AXStaticText AXValue='Alabama'
|
||||
++++AXStaticText AXFocused=1 AXValue='Alaska'
|
||||
-++AXGroup AXTitle='State'
|
||||
+++AXComboBox AXTitle='State'
|
||||
++++AXTextField AXLinkedUIElements=[:11]
|
||||
++AXList
|
||||
++++AXStaticText AXValue='Alabama'
|
||||
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc
|
||||
index f776bb6a7c0f1cb15a61468afe3a6264bad82830..f511d3436e3e448b00d042f35fc0077c85681523 100644
|
||||
--- a/ui/accessibility/ax_role_properties.cc
|
||||
+++ b/ui/accessibility/ax_role_properties.cc
|
||||
@@ -767,6 +767,17 @@ bool SupportsToggle(const ax::mojom::Role role) {
|
||||
}
|
||||
}
|
||||
|
||||
+bool IsComboBox(const ax::mojom::Role role) {
|
||||
+ switch (role) {
|
||||
+ case ax::mojom::Role::kComboBoxMenuButton:
|
||||
+ case ax::mojom::Role::kComboBoxGrouping:
|
||||
+ case ax::mojom::Role::kTextFieldWithComboBox:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
bool ShouldHaveReadonlyStateByDefault(const ax::mojom::Role role) {
|
||||
switch (role) {
|
||||
case ax::mojom::Role::kArticle:
|
||||
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h
|
||||
index 724de523b7dc2c009ed9b1aa84cf9071ce230bad..a8233bb36f0a532e7ce51abee9cc4823b0cb3fcf 100644
|
||||
--- a/ui/accessibility/ax_role_properties.h
|
||||
+++ b/ui/accessibility/ax_role_properties.h
|
||||
@@ -168,6 +168,8 @@ AX_BASE_EXPORT bool IsTableRow(ax::mojom::Role role);
|
||||
// break, or inline text box.
|
||||
AX_BASE_EXPORT bool IsText(ax::mojom::Role role);
|
||||
|
||||
+// Returns true if the provided role is any of the combobox-related roles.
|
||||
+AX_BASE_EXPORT bool IsComboBox(ax::mojom::Role role);
|
||||
// Returns true if the role supports expand/collapse.
|
||||
AX_BASE_EXPORT bool SupportsExpandCollapse(const ax::mojom::Role role);
|
||||
|
||||
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
|
||||
index 96d46d452188519fc3f90e9e107fa134e097a1f4..06d766c9c7a8bade5192815d1e65e31948832d4e 100644
|
||||
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
|
||||
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
|
||||
@@ -55,8 +55,8 @@ RoleMap BuildRoleMap() {
|
||||
{ax::mojom::Role::kColorWell, NSAccessibilityColorWellRole},
|
||||
{ax::mojom::Role::kColumn, NSAccessibilityColumnRole},
|
||||
{ax::mojom::Role::kColumnHeader, @"AXCell"},
|
||||
- {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityGroupRole},
|
||||
- {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityPopUpButtonRole},
|
||||
+ {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityComboBoxRole},
|
||||
+ {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityComboBoxRole},
|
||||
{ax::mojom::Role::kComment, NSAccessibilityGroupRole},
|
||||
{ax::mojom::Role::kComplementary, NSAccessibilityGroupRole},
|
||||
{ax::mojom::Role::kContentDeletion, NSAccessibilityGroupRole},
|
||||
297
patches/chromium/cherry-pick-5c7ad5393f74.patch
Normal file
297
patches/chromium/cherry-pick-5c7ad5393f74.patch
Normal file
@@ -0,0 +1,297 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Robinson <mrobinson@igalia.com>
|
||||
Date: Mon, 25 Jan 2021 14:27:23 +0000
|
||||
Subject: Mac a11y: Use the keyboard focusable element for
|
||||
NSAccessibilityTextChangeElement
|
||||
|
||||
When setting the NSAccessibilityTextChangeElement property for
|
||||
NSAccessibilitySelectedTextChangedNotifications, use the keyboard
|
||||
focusable element instead of the element that has the focus side of the
|
||||
text selection. Using the latter, when the element is an empty group,
|
||||
VoiceOver will focus the containing Web View (when using the VO
|
||||
cursor follows keyboard focus setting). This makes it impossible to use
|
||||
the down keyboard key to move past these empty nodes.
|
||||
|
||||
VoiceOver cursor" setting in contenteditable nodes.
|
||||
|
||||
AX-Relnotes: Fix a bug with the "Synchronize keyboard focus and
|
||||
Bug: 952922
|
||||
Change-Id: I3627936726f89b01132c32bd5d83758fc7c3dac4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2642686
|
||||
Auto-Submit: Martin Robinson <mrobinson@igalia.com>
|
||||
Commit-Queue: Nektarios Paisios <nektar@chromium.org>
|
||||
Reviewed-by: Nektarios Paisios <nektar@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#846707}
|
||||
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
|
||||
index 6eb2c484ddc479d9cfa566df0b103782264d3af8..07db6eed6d06340627a3c023d02274642642e87d 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
|
||||
+++ b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
|
||||
@@ -20,12 +20,11 @@
|
||||
#include "net/base/data_url.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "testing/gtest_mac.h"
|
||||
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
-namespace {
|
||||
-
|
||||
class BrowserAccessibilityCocoaBrowserTest : public ContentBrowserTest {
|
||||
public:
|
||||
BrowserAccessibilityCocoaBrowserTest() {}
|
||||
@@ -73,6 +72,11 @@ void FocusAccessibilityElementAndWaitForFocusChange(
|
||||
WaitForAccessibilityFocusChange();
|
||||
}
|
||||
|
||||
+ NSDictionary* GetUserInfoForSelectedTextChangedNotification() {
|
||||
+ auto* manager = static_cast<BrowserAccessibilityManagerMac*>(GetManager());
|
||||
+ return manager->GetUserInfoForSelectedTextChangedNotification();
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
BrowserAccessibility* FindNodeInSubtree(BrowserAccessibility& node,
|
||||
ax::mojom::Role role) {
|
||||
@@ -89,8 +93,6 @@ void FocusAccessibilityElementAndWaitForFocusChange(
|
||||
}
|
||||
};
|
||||
|
||||
-} // namespace
|
||||
-
|
||||
IN_PROC_BROWSER_TEST_F(BrowserAccessibilityCocoaBrowserTest,
|
||||
AXTextMarkerForTextEdit) {
|
||||
EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
|
||||
@@ -106,12 +108,11 @@ GURL url(R"HTML(data:text/html,
|
||||
|
||||
BrowserAccessibility* text_field = FindNode(ax::mojom::Role::kTextField);
|
||||
ASSERT_NE(nullptr, text_field);
|
||||
- EXPECT_TRUE(content::ExecuteScript(
|
||||
- shell()->web_contents(), "document.querySelector('input').focus()"));
|
||||
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
|
||||
+ "document.querySelector('input').focus()"));
|
||||
|
||||
- content::SimulateKeyPress(shell()->web_contents(),
|
||||
- ui::DomKey::FromCharacter('B'), ui::DomCode::US_B,
|
||||
- ui::VKEY_B, false, false, false, false);
|
||||
+ SimulateKeyPress(shell()->web_contents(), ui::DomKey::FromCharacter('B'),
|
||||
+ ui::DomCode::US_B, ui::VKEY_B, false, false, false, false);
|
||||
|
||||
base::scoped_nsobject<BrowserAccessibilityCocoa> cocoa_text_field(
|
||||
[ToBrowserAccessibilityCocoa(text_field) retain]);
|
||||
@@ -122,10 +123,9 @@ AccessibilityNotificationWaiter value_waiter(shell()->web_contents(),
|
||||
AXTextEdit text_edit = [cocoa_text_field computeTextEdit];
|
||||
EXPECT_NE(text_edit.edit_text_marker, nil);
|
||||
|
||||
- EXPECT_EQ(
|
||||
- content::AXTextMarkerToPosition(text_edit.edit_text_marker)->ToString(),
|
||||
- "TextPosition anchor_id=4 text_offset=1 affinity=downstream "
|
||||
- "annotated_text=B<>");
|
||||
+ EXPECT_EQ(AXTextMarkerToPosition(text_edit.edit_text_marker)->ToString(),
|
||||
+ "TextPosition anchor_id=4 text_offset=1 affinity=downstream "
|
||||
+ "annotated_text=B<>");
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(BrowserAccessibilityCocoaBrowserTest,
|
||||
@@ -519,7 +519,7 @@ GURL url(R"HTML(data:text/html,
|
||||
EXPECT_NSEQ(@"AXRow", [tree_children[0] role]);
|
||||
EXPECT_NSEQ(@"AXRow", [tree_children[1] role]);
|
||||
|
||||
- content::RenderProcessHost* render_process_host =
|
||||
+ RenderProcessHost* render_process_host =
|
||||
shell()->web_contents()->GetMainFrame()->GetProcess();
|
||||
auto menu_filter = base::MakeRefCounted<ContextMenuFilter>(
|
||||
ContextMenuFilter::ShowBehavior::kPreventShow);
|
||||
@@ -534,9 +534,8 @@ GURL url(R"HTML(data:text/html,
|
||||
ASSERT_NE(tree_point, item_1_point);
|
||||
|
||||
// Now focus the second child and trigger a context menu on the tree.
|
||||
- EXPECT_TRUE(
|
||||
- content::ExecuteScript(shell()->web_contents(),
|
||||
- "document.body.children[0].children[1].focus();"));
|
||||
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
|
||||
+ "document.body.children[0].children[1].focus();"));
|
||||
WaitForAccessibilityFocusChange();
|
||||
|
||||
// Triggering a context menu on the tree should now trigger the menu
|
||||
@@ -656,4 +655,63 @@ GURL url(R"HTML(data:text/html,
|
||||
}
|
||||
}
|
||||
|
||||
+IN_PROC_BROWSER_TEST_F(BrowserAccessibilityCocoaBrowserTest,
|
||||
+ TestNSAccessibilityTextChangeElement) {
|
||||
+ AccessibilityNotificationWaiter waiter(shell()->web_contents(),
|
||||
+ ui::kAXModeComplete,
|
||||
+ ax::mojom::Event::kLoadComplete);
|
||||
+
|
||||
+ GURL url(R"HTML(data:text/html,
|
||||
+ <div id="editable" contenteditable="true" dir="auto">
|
||||
+ <p>One</p>
|
||||
+ <p>Two</p>
|
||||
+ <p><br></p>
|
||||
+ <p>Three</p>
|
||||
+ <p>Four</p>
|
||||
+ </div>)HTML");
|
||||
+
|
||||
+ ASSERT_TRUE(NavigateToURL(shell(), url));
|
||||
+ waiter.WaitForNotification();
|
||||
+
|
||||
+ base::scoped_nsobject<BrowserAccessibilityCocoa> content_editable(
|
||||
+ [ToBrowserAccessibilityCocoa(GetManager()->GetRoot()->PlatformGetChild(0))
|
||||
+ retain]);
|
||||
+ EXPECT_EQ([[content_editable children] count], 5ul);
|
||||
+
|
||||
+ WebContents* web_contents = shell()->web_contents();
|
||||
+ auto run_script_and_wait_for_selection_change =
|
||||
+ [web_contents](const char* script) {
|
||||
+ AccessibilityNotificationWaiter waiter(
|
||||
+ web_contents, ui::kAXModeComplete,
|
||||
+ ax::mojom::Event::kTextSelectionChanged);
|
||||
+ ASSERT_TRUE(ExecuteScript(web_contents, script));
|
||||
+ waiter.WaitForNotification();
|
||||
+ };
|
||||
+
|
||||
+ FocusAccessibilityElementAndWaitForFocusChange(content_editable);
|
||||
+
|
||||
+ run_script_and_wait_for_selection_change(R"script(
|
||||
+ let editable = document.getElementById('editable');
|
||||
+ const selection = window.getSelection();
|
||||
+ selection.collapse(editable.children[0].childNodes[0], 1);)script");
|
||||
+
|
||||
+ // The focused node in the user info should be the keyboard focusable
|
||||
+ // ancestor.
|
||||
+ NSDictionary* info = GetUserInfoForSelectedTextChangedNotification();
|
||||
+ EXPECT_EQ(id{content_editable},
|
||||
+ [info objectForKey:ui::NSAccessibilityTextChangeElement]);
|
||||
+
|
||||
+ AccessibilityNotificationWaiter waiter2(
|
||||
+ web_contents, ui::kAXModeComplete,
|
||||
+ ax::mojom::Event::kTextSelectionChanged);
|
||||
+ run_script_and_wait_for_selection_change(
|
||||
+ "selection.collapse(editable.children[2].childNodes[0], 0);");
|
||||
+
|
||||
+ // Even when the cursor is in the empty paragraph text node, the focused
|
||||
+ // object should be the keyboard focusable ancestor.
|
||||
+ info = GetUserInfoForSelectedTextChangedNotification();
|
||||
+ EXPECT_EQ(id{content_editable},
|
||||
+ [info objectForKey:ui::NSAccessibilityTextChangeElement]);
|
||||
+}
|
||||
+
|
||||
} // namespace content
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||
index 925bfe1ea191ab846805fdbff1b0314e779b1c9e..5488245e22b883105dbe1e225156ab18e1a64534 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace content {
|
||||
|
||||
+class BrowserAccessibilityCocoaBrowserTest;
|
||||
+
|
||||
class CONTENT_EXPORT BrowserAccessibilityManagerMac
|
||||
: public BrowserAccessibilityManager {
|
||||
public:
|
||||
@@ -54,8 +56,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
|
||||
const std::vector<Change>& changes) override;
|
||||
|
||||
// Returns an autoreleased object.
|
||||
- NSDictionary* GetUserInfoForSelectedTextChangedNotification(
|
||||
- bool focus_changed);
|
||||
+ NSDictionary* GetUserInfoForSelectedTextChangedNotification();
|
||||
|
||||
// Returns an autoreleased object.
|
||||
NSDictionary* GetUserInfoForValueChangedNotification(
|
||||
@@ -80,6 +81,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
|
||||
// constructor.
|
||||
friend class BrowserAccessibilityManager;
|
||||
|
||||
+ friend class BrowserAccessibilityCocoaBrowserTest;
|
||||
+
|
||||
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerMac);
|
||||
};
|
||||
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
index 4232959e30ab758bff58aa8e4457b6cdd3c7745b..d172d9625c3d762a861873b2e938a931c49b9501 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
@@ -125,8 +125,6 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
auto native_node = ToBrowserAccessibilityCocoa(node);
|
||||
DCHECK(native_node);
|
||||
|
||||
- bool focus_changed = GetFocus() != GetLastFocusedNode();
|
||||
-
|
||||
// Refer to |AXObjectCache::postPlatformNotification| in WebKit source code.
|
||||
NSString* mac_notification = nullptr;
|
||||
switch (event_type) {
|
||||
@@ -212,8 +210,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
// 10.11 or later to notify Voiceover about text selection changes. This
|
||||
// API has been present on versions of OS X since 10.7 but doesn't
|
||||
// appear to be needed by Voiceover before version 10.11.
|
||||
- NSDictionary* user_info =
|
||||
- GetUserInfoForSelectedTextChangedNotification(focus_changed);
|
||||
+ NSDictionary* user_info = GetUserInfoForSelectedTextChangedNotification();
|
||||
|
||||
BrowserAccessibilityManager* root_manager = GetRootManager();
|
||||
if (!root_manager)
|
||||
@@ -439,8 +436,8 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
}
|
||||
|
||||
NSDictionary*
|
||||
-BrowserAccessibilityManagerMac::GetUserInfoForSelectedTextChangedNotification(
|
||||
- bool focus_changed) {
|
||||
+BrowserAccessibilityManagerMac::
|
||||
+ GetUserInfoForSelectedTextChangedNotification() {
|
||||
NSMutableDictionary* user_info =
|
||||
[[[NSMutableDictionary alloc] init] autorelease];
|
||||
[user_info setObject:@YES forKey:ui::NSAccessibilityTextStateSyncKey];
|
||||
@@ -457,7 +454,10 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
// TODO(mrobinson): Determine definitively what the type of this text
|
||||
// selection change is. This requires passing this information here from
|
||||
// blink.
|
||||
- if (focus_changed) {
|
||||
+ BrowserAccessibility* focused_accessibility = GetFocus();
|
||||
+ DCHECK(focused_accessibility);
|
||||
+
|
||||
+ if (focused_accessibility != GetLastFocusedNode()) {
|
||||
[user_info setObject:@(ui::AXTextStateChangeTypeSelectionMove)
|
||||
forKey:ui::NSAccessibilityTextStateChangeTypeKey];
|
||||
} else {
|
||||
@@ -465,25 +465,22 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
forKey:ui::NSAccessibilityTextStateChangeTypeKey];
|
||||
}
|
||||
|
||||
- int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
|
||||
- BrowserAccessibility* focus_object = GetFromID(focus_id);
|
||||
- if (focus_object) {
|
||||
- focus_object = focus_object->PlatformGetClosestPlatformObject();
|
||||
- auto native_focus_object = ToBrowserAccessibilityCocoa(focus_object);
|
||||
- if (native_focus_object && [native_focus_object instanceActive]) {
|
||||
- [user_info setObject:native_focus_object
|
||||
- forKey:ui::NSAccessibilityTextChangeElement];
|
||||
+ focused_accessibility =
|
||||
+ focused_accessibility->PlatformGetClosestPlatformObject();
|
||||
+ auto native_focus_object = ToBrowserAccessibilityCocoa(focused_accessibility);
|
||||
+ if (native_focus_object && [native_focus_object instanceActive]) {
|
||||
+ [user_info setObject:native_focus_object
|
||||
+ forKey:ui::NSAccessibilityTextChangeElement];
|
||||
|
||||
#ifndef MAS_BUILD
|
||||
- id selected_text = [native_focus_object selectedTextMarkerRange];
|
||||
- if (selected_text) {
|
||||
- NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
|
||||
- @"AXSelectedTextMarkerRange";
|
||||
- [user_info setObject:selected_text
|
||||
- forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
|
||||
- }
|
||||
-#endif
|
||||
+ id selected_text = [native_focus_object selectedTextMarkerRange];
|
||||
+ if (selected_text) {
|
||||
+ NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
|
||||
+ @"AXSelectedTextMarkerRange";
|
||||
+ [user_info setObject:selected_text
|
||||
+ forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
return user_info;
|
||||
71
patches/chromium/cherry-pick-6e8856624cbb.patch
Normal file
71
patches/chromium/cherry-pick-6e8856624cbb.patch
Normal file
@@ -0,0 +1,71 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Koji Ishii <kojii@chromium.org>
|
||||
Date: Thu, 11 Mar 2021 17:45:46 +0000
|
||||
Subject: Mark additional RootInlineBox dirty when culled inline box is removed
|
||||
|
||||
When a |LayoutInline| is removed, |LineBoxList::
|
||||
DirtyLinesFromChangedChild| tries to mark affected
|
||||
|RootInlineBox| dirty.
|
||||
|
||||
When the |LayoutInline| to be removed is culled, it tries to
|
||||
find the |RootInlineBox| from its previous siblings, then look
|
||||
for its previous and next |RootInlineBox|es.
|
||||
|
||||
Occasionally, the next next line of the previous sibling is
|
||||
wrapped at the |LayoutInline|, and that its |LineBreakObj()|
|
||||
holds the reference to the |LayoutInline|. This patch marks
|
||||
such |RootInlineBox| dirty.
|
||||
|
||||
(cherry picked from commit 2dbdabb28d647c8ee20cbe36e3c957e74aff663b)
|
||||
|
||||
Bug: 1186287
|
||||
Change-Id: I8ca73ebb4f5e4f13e997662fffd803d6a74ef49a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2748756
|
||||
Auto-Submit: Koji Ishii <kojii@chromium.org>
|
||||
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
|
||||
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#861724}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2749769
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4389@{#1518}
|
||||
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/layout/line/line_box_list.cc b/third_party/blink/renderer/core/layout/line/line_box_list.cc
|
||||
index 9d9d861f00cb9784041796acb91604d64dab1cb7..ed929849f721fbae25fd8c1106c95e563aca289b 100644
|
||||
--- a/third_party/blink/renderer/core/layout/line/line_box_list.cc
|
||||
+++ b/third_party/blink/renderer/core/layout/line/line_box_list.cc
|
||||
@@ -359,14 +359,32 @@ void LineBoxList::DirtyLinesFromChangedChild(LineLayoutItem container,
|
||||
// findNextLineBreak. findNextLineBreak, despite the name, actually returns
|
||||
// the first LayoutObject after the BR. <rdar://problem/3849947> "Typing
|
||||
// after pasting line does not appear until after window resize."
|
||||
- if (RootInlineBox* prev_root_box = box->PrevRootBox())
|
||||
+ if (RootInlineBox* prev_root_box = box->PrevRootBox()) {
|
||||
prev_root_box->MarkDirty();
|
||||
+#if DCHECK_IS_ON()
|
||||
+ for (; prev_root_box; prev_root_box = prev_root_box->PrevRootBox()) {
|
||||
+ DCHECK(prev_root_box->IsDirty() ||
|
||||
+ prev_root_box->LineBreakObj() != child);
|
||||
+ }
|
||||
+#endif
|
||||
+ }
|
||||
// If |child| or any of its immediately previous siblings with culled
|
||||
// lineboxes is the object after a line-break in |box| or the linebox after
|
||||
// it then that means |child| actually sits on the linebox after |box| (or
|
||||
// is its line-break object) and so we need to dirty it as well.
|
||||
- if (RootInlineBox* next_root_box = box->NextRootBox())
|
||||
+ if (RootInlineBox* next_root_box = box->NextRootBox()) {
|
||||
next_root_box->MarkDirty();
|
||||
+
|
||||
+ next_root_box = next_root_box->NextRootBox();
|
||||
+ if (next_root_box && next_root_box->LineBreakObj() == child)
|
||||
+ next_root_box->MarkDirty();
|
||||
+#if DCHECK_IS_ON()
|
||||
+ for (; next_root_box; next_root_box = next_root_box->NextRootBox()) {
|
||||
+ DCHECK(next_root_box->IsDirty() ||
|
||||
+ next_root_box->LineBreakObj() != child);
|
||||
+ }
|
||||
+#endif
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
66
patches/chromium/cherry-pick-6ed1c0c425e0.patch
Normal file
66
patches/chromium/cherry-pick-6ed1c0c425e0.patch
Normal file
@@ -0,0 +1,66 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Harald Alvestrand <hta@chromium.org>
|
||||
Date: Mon, 22 Feb 2021 13:13:58 +0000
|
||||
Subject: Fix GetP2PSocketManager ownership
|
||||
|
||||
Let it return a mojo::SharedRemote<> instead of a raw pointer - this is
|
||||
a decoration around a shared_refptr.
|
||||
|
||||
(cherry picked from commit 82cdc0781ceb4c22ef5903cf3115bea518a5523b)
|
||||
|
||||
Bug: chromium:1172054
|
||||
Change-Id: I49bd22a0dc949bf869744d2ad25c1afcaea7fdbc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2692532
|
||||
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
|
||||
Commit-Queue: Harald Alvestrand <hta@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#854050}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2709590
|
||||
Reviewed-by: Harald Alvestrand <hta@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4389@{#1280}
|
||||
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc b/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
|
||||
index 29884a255f24556f4dc8b41b22304938a4f0d775..72ec477f57871b460adf83ea9e1a4bd217d5eebe 100644
|
||||
--- a/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
|
||||
+++ b/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
|
||||
@@ -36,7 +36,7 @@ void P2PSocketDispatcher::RemoveNetworkListObserver(
|
||||
network_list_observers_->RemoveObserver(network_list_observer);
|
||||
}
|
||||
|
||||
-network::mojom::blink::P2PSocketManager*
|
||||
+mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
|
||||
P2PSocketDispatcher::GetP2PSocketManager() {
|
||||
base::AutoLock lock(p2p_socket_manager_lock_);
|
||||
if (!p2p_socket_manager_) {
|
||||
@@ -56,7 +56,7 @@ P2PSocketDispatcher::GetP2PSocketManager() {
|
||||
*main_task_runner_.get(), FROM_HERE,
|
||||
CrossThreadBindOnce(&P2PSocketDispatcher::RequestInterfaceIfNecessary,
|
||||
scoped_refptr<P2PSocketDispatcher>(this)));
|
||||
- return p2p_socket_manager_.get();
|
||||
+ return p2p_socket_manager_;
|
||||
}
|
||||
|
||||
void P2PSocketDispatcher::NetworkListChanged(
|
||||
diff --git a/third_party/blink/renderer/platform/p2p/socket_dispatcher.h b/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
|
||||
index b6268562b1b120429a0c9a17bbca5f279bdc5b75..7d75ef814e127a8743a86dfb8d362459fbe32f99 100644
|
||||
--- a/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
|
||||
+++ b/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
|
||||
@@ -65,7 +65,8 @@ class PLATFORM_EXPORT P2PSocketDispatcher
|
||||
void RemoveNetworkListObserver(
|
||||
blink::NetworkListObserver* network_list_observer) override;
|
||||
|
||||
- network::mojom::blink::P2PSocketManager* GetP2PSocketManager();
|
||||
+ mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
|
||||
+ GetP2PSocketManager();
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<P2PSocketDispatcher>;
|
||||
@@ -94,7 +95,7 @@ class PLATFORM_EXPORT P2PSocketDispatcher
|
||||
mojo::PendingReceiver<network::mojom::blink::P2PSocketManager>
|
||||
p2p_socket_manager_receiver_;
|
||||
mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
|
||||
- p2p_socket_manager_;
|
||||
+ p2p_socket_manager_ GUARDED_BY(p2p_socket_manager_lock_);
|
||||
base::Lock p2p_socket_manager_lock_;
|
||||
|
||||
// Cached from last |NetworkListChanged| call.
|
||||
67
patches/chromium/cherry-pick-76cb1cc32baa.patch
Normal file
67
patches/chromium/cherry-pick-76cb1cc32baa.patch
Normal file
@@ -0,0 +1,67 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sergei Glazunov <glazunov@google.com>
|
||||
Date: Fri, 12 Feb 2021 16:37:12 +0000
|
||||
Subject: Use a copy for transferring non detachable buffers
|
||||
|
||||
Currently, |DOMArrayBuffer::Transfer()| makes a copy, but still uses
|
||||
the original buffer for transferring, thus making it possible to share a
|
||||
regular ArrayBuffer (not SAB) with multiple threads.
|
||||
|
||||
(cherry picked from commit 0d289da12075592372940a366ad565b9a13d57ce)
|
||||
|
||||
Bug: 1177341
|
||||
Change-Id: Idb48deb1698fe555f32531bc04b55dd3e1fb0a06
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2690630
|
||||
Reviewed-by: Bill Budge <bbudge@chromium.org>
|
||||
Reviewed-by: Andreas Haas <ahaas@chromium.org>
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Commit-Queue: Sergei Glazunov <glazunov@google.com>
|
||||
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#853272}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2691251
|
||||
Reviewed-by: Krishna Govind <govind@chromium.org>
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4389@{#980}
|
||||
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
|
||||
index 17fcf0f9034d09a53376ebb380c98589d52de8f4..c456d15f2f5084d7592326e151c1a478bc2ac1fc 100644
|
||||
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
|
||||
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
|
||||
@@ -47,6 +47,13 @@ bool DOMArrayBuffer::Transfer(v8::Isolate* isolate,
|
||||
DOMArrayBuffer::Create(Content()->Data(), ByteLengthAsSizeT());
|
||||
}
|
||||
|
||||
+ return to_transfer->TransferDetachable(isolate, result);
|
||||
+}
|
||||
+
|
||||
+bool DOMArrayBuffer::TransferDetachable(v8::Isolate* isolate,
|
||||
+ ArrayBufferContents& result) {
|
||||
+ DCHECK(IsDetachable(isolate));
|
||||
+
|
||||
if (IsDetached()) {
|
||||
result.Detach();
|
||||
return false;
|
||||
@@ -62,7 +69,7 @@ bool DOMArrayBuffer::Transfer(v8::Isolate* isolate,
|
||||
|
||||
Vector<v8::Local<v8::ArrayBuffer>, 4> buffer_handles;
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
- AccumulateArrayBuffersForAllWorlds(isolate, to_transfer, buffer_handles);
|
||||
+ AccumulateArrayBuffersForAllWorlds(isolate, this, buffer_handles);
|
||||
|
||||
for (const auto& buffer_handle : buffer_handles)
|
||||
buffer_handle->Detach();
|
||||
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
|
||||
index 00ba385dafcfd476805e39e4c138cdac8f071ef6..e9a85d38d4d46d26a41cf4d394a92d1a7b511c02 100644
|
||||
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
|
||||
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
|
||||
@@ -78,6 +78,9 @@ class CORE_EXPORT DOMArrayBuffer final : public DOMArrayBufferBase {
|
||||
|
||||
v8::Local<v8::Value> Wrap(v8::Isolate*,
|
||||
v8::Local<v8::Object> creation_context) override;
|
||||
+
|
||||
+ private:
|
||||
+ bool TransferDetachable(v8::Isolate*, ArrayBufferContents& result);
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
54
patches/chromium/cherry-pick-7e0e52df283c.patch
Normal file
54
patches/chromium/cherry-pick-7e0e52df283c.patch
Normal file
@@ -0,0 +1,54 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Marijn Kruisselbrink <mek@chromium.org>
|
||||
Date: Tue, 23 Feb 2021 22:17:17 +0000
|
||||
Subject: Don't store BlobStorageLimits as a reference in transport strategy.
|
||||
|
||||
Rather than storing a const reference to something of unclear lifetime,
|
||||
just make a copy. We could just copy the specific limits we need, but
|
||||
there shouldn't be many TransportStrategy instances alive at the same
|
||||
time anyway, so the cost of duplicating shouldn't be too high.
|
||||
|
||||
(cherry picked from commit 9a10c68a381d78088532953aa8e0de0a5ff47316)
|
||||
|
||||
(cherry picked from commit 7b51cb5e4e2c6cf9dcf19bd9d7599735efd48110)
|
||||
|
||||
Bug: 1180871
|
||||
Change-Id: Ie1e31728b18f02c5d35df0ac0f285eb8f70cb268
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2713912
|
||||
Reviewed-by: Olivier Yiptong <oyiptong@chromium.org>
|
||||
Reviewed-by: Darwin Huang <huangdarwin@chromium.org>
|
||||
Reviewed-by: Victor Costan <pwnall@chromium.org>
|
||||
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/heads/master@{#856503}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2713891
|
||||
Reviewed-by: Krishna Govind <govind@chromium.org>
|
||||
Reviewed-by: Srinivas Sista <srinivassista@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/4425@{#2}
|
||||
Cr-Original-Branched-From: 4a7d24ec28ccb96c5a1cfd7b4b40b17070f2c396-refs/heads/master@{#856252}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2713958
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4389@{#1327}
|
||||
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
|
||||
diff --git a/storage/browser/blob/blob_transport_strategy.cc b/storage/browser/blob/blob_transport_strategy.cc
|
||||
index eb66014792246254db1c825b61bd18e3190970de..5ae41639f149f8ff3ead9633d3aa834ac05a8e5f 100644
|
||||
--- a/storage/browser/blob/blob_transport_strategy.cc
|
||||
+++ b/storage/browser/blob/blob_transport_strategy.cc
|
||||
@@ -239,7 +239,7 @@ class DataPipeTransportStrategy : public BlobTransportStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
- const BlobStorageLimits& limits_;
|
||||
+ const BlobStorageLimits limits_;
|
||||
base::circular_deque<base::OnceClosure> requests_;
|
||||
|
||||
mojo::ScopedDataPipeConsumerHandle consumer_handle_;
|
||||
@@ -336,7 +336,7 @@ class FileTransportStrategy : public BlobTransportStrategy {
|
||||
std::move(result_callback_).Run(BlobStatus::DONE);
|
||||
}
|
||||
|
||||
- const BlobStorageLimits& limits_;
|
||||
+ const BlobStorageLimits limits_;
|
||||
|
||||
// State used to assign bytes elements to individual files.
|
||||
// The index of the first file that still has available space.
|
||||
114
patches/chromium/cherry-pick-aeb6bc551b60.patch
Normal file
114
patches/chromium/cherry-pick-aeb6bc551b60.patch
Normal file
@@ -0,0 +1,114 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Hongchan Choi <hongchan@chromium.org>
|
||||
Date: Tue, 23 Feb 2021 23:27:31 +0000
|
||||
Subject: Prevent accessing shared buffers from audio rendering thread
|
||||
|
||||
The shared buffer in ScriptProcessorNode can be accessed by the
|
||||
audio rendering thread when it is held by the main thread.
|
||||
|
||||
The solution suggested here is simply to expand the scope of
|
||||
the mutex to minimize the code change. This is a deprecated
|
||||
feature in Web Audio, so making significant changes is not
|
||||
sensible. By locking the entire scope of Process() call, this
|
||||
area would be immune to the similar problems in the future.
|
||||
|
||||
(cherry picked from commit 60987aa224f369fc0ea38c56e498389440921356)
|
||||
|
||||
Bug: 1174582
|
||||
Test: The repro case doesn't crash on ASAN.
|
||||
Change-Id: I2b292f94be65e6ec26c6eb0e0ed32b3fb2d88466
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2681193
|
||||
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
|
||||
Reviewed-by: Raymond Toy <rtoy@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#852240}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2715585
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Reviewed-by: Srinivas Sista <srinivassista@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2238}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
|
||||
index b1ca691b07b53b927a92753906f7f25edebac919..6e80b23a32dd1895a0d51d08ee16c8cb2d44fc55 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
|
||||
@@ -110,6 +110,14 @@ void ScriptProcessorHandler::Initialize() {
|
||||
}
|
||||
|
||||
void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
|
||||
+ // The main thread might be accessing the shared buffers. If so, silience
|
||||
+ // the output and return.
|
||||
+ MutexTryLocker try_locker(process_event_lock_);
|
||||
+ if (!try_locker.Locked()) {
|
||||
+ Output(0).Bus()->Zero();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// Discussion about inputs and outputs:
|
||||
// As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
|
||||
// and output (see inputBus and outputBus below). Additionally, there is a
|
||||
@@ -181,47 +189,26 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
|
||||
buffer_read_write_index_ =
|
||||
(buffer_read_write_index_ + frames_to_process) % BufferSize();
|
||||
|
||||
- // m_bufferReadWriteIndex will wrap back around to 0 when the current input
|
||||
- // and output buffers are full.
|
||||
- // When this happens, fire an event and swap buffers.
|
||||
+ // Fire an event and swap buffers when |buffer_read_write_index_| wraps back
|
||||
+ // around to 0. It means the current input and output buffers are full.
|
||||
if (!buffer_read_write_index_) {
|
||||
- // Avoid building up requests on the main thread to fire process events when
|
||||
- // they're not being handled. This could be a problem if the main thread is
|
||||
- // very busy doing other things and is being held up handling previous
|
||||
- // requests. The audio thread can't block on this lock, so we call
|
||||
- // tryLock() instead.
|
||||
- MutexTryLocker try_locker(process_event_lock_);
|
||||
- if (!try_locker.Locked()) {
|
||||
- // We're late in handling the previous request. The main thread must be
|
||||
- // very busy. The best we can do is clear out the buffer ourself here.
|
||||
- shared_output_buffer->Zero();
|
||||
+ if (Context()->HasRealtimeConstraint()) {
|
||||
+ // For a realtime context, fire an event and do not wait.
|
||||
+ PostCrossThreadTask(
|
||||
+ *task_runner_, FROM_HERE,
|
||||
+ CrossThreadBindOnce(&ScriptProcessorHandler::FireProcessEvent,
|
||||
+ AsWeakPtr(), double_buffer_index_));
|
||||
} else {
|
||||
- // With the realtime context, execute the script code asynchronously
|
||||
- // and do not wait.
|
||||
- if (Context()->HasRealtimeConstraint()) {
|
||||
- // Fire the event on the main thread with the appropriate buffer
|
||||
- // index.
|
||||
- PostCrossThreadTask(
|
||||
- *task_runner_, FROM_HERE,
|
||||
- CrossThreadBindOnce(&ScriptProcessorHandler::FireProcessEvent,
|
||||
- AsWeakPtr(), double_buffer_index_));
|
||||
- } else {
|
||||
- // If this node is in the offline audio context, use the
|
||||
- // waitable event to synchronize to the offline rendering thread.
|
||||
- std::unique_ptr<base::WaitableEvent> waitable_event =
|
||||
- std::make_unique<base::WaitableEvent>();
|
||||
-
|
||||
- PostCrossThreadTask(
|
||||
- *task_runner_, FROM_HERE,
|
||||
- CrossThreadBindOnce(
|
||||
- &ScriptProcessorHandler::FireProcessEventForOfflineAudioContext,
|
||||
- AsWeakPtr(), double_buffer_index_,
|
||||
- CrossThreadUnretained(waitable_event.get())));
|
||||
-
|
||||
- // Okay to block the offline audio rendering thread since it is
|
||||
- // not the actual audio device thread.
|
||||
- waitable_event->Wait();
|
||||
- }
|
||||
+ // For an offline context, wait until the script execution is finished.
|
||||
+ std::unique_ptr<base::WaitableEvent> waitable_event =
|
||||
+ std::make_unique<base::WaitableEvent>();
|
||||
+ PostCrossThreadTask(
|
||||
+ *task_runner_, FROM_HERE,
|
||||
+ CrossThreadBindOnce(
|
||||
+ &ScriptProcessorHandler::FireProcessEventForOfflineAudioContext,
|
||||
+ AsWeakPtr(), double_buffer_index_,
|
||||
+ CrossThreadUnretained(waitable_event.get())));
|
||||
+ waitable_event->Wait();
|
||||
}
|
||||
|
||||
SwapBuffers();
|
||||
146
patches/chromium/cherry-pick-df438f22f7d2.patch
Normal file
146
patches/chromium/cherry-pick-df438f22f7d2.patch
Normal file
@@ -0,0 +1,146 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Artem Sumaneev <asumaneev@google.com>
|
||||
Date: Wed, 3 Feb 2021 15:00:25 +0000
|
||||
Subject: Fix navigation request reset logic
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Do not delete navigation request which has started upon receiving
|
||||
notification about beforeunload dialog being cancelled, as a) this
|
||||
navigation request is not waiting for beforeunload and b) it might have
|
||||
been this navigation request which canceled this beforeunload dialog.
|
||||
|
||||
M86 merge conflicts and resolution:
|
||||
* content/browser/frame_host/*
|
||||
In ToT files the affected under frame_host directory are moved to
|
||||
renderer_host dir. Applied patch to frame_host, no further conflicts.
|
||||
|
||||
R=alexmos@chromium.org
|
||||
BUG=1161705
|
||||
|
||||
(cherry picked from commit 23c110b5b81dc401ded5d4dcecfab65d5d88fdfa)
|
||||
|
||||
(cherry picked from commit 87550e04d9fed4bbedff4546f4161e3c02415d7e)
|
||||
|
||||
Change-Id: I7d385d4326fac6f67d17a003679471806b5ad3b2
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2624733
|
||||
Commit-Queue: Alexander Timin <altimin@chromium.org>
|
||||
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/heads/master@{#843343}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2652791
|
||||
Commit-Queue: Alex Moshchuk <alexmos@chromium.org>
|
||||
Auto-Submit: Alexander Timin <altimin@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/4324@{#2040}
|
||||
Cr-Original-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2666397
|
||||
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
|
||||
Commit-Queue: Artem Sumaneev <asumaneev@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1537}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc
|
||||
index 92ffd227304509a68a95ea922ffbb477685b6b1d..47ecfa82a0824009c24844e42b9b2c7e6c0206f3 100644
|
||||
--- a/content/browser/renderer_host/frame_tree_node.cc
|
||||
+++ b/content/browser/renderer_host/frame_tree_node.cc
|
||||
@@ -608,10 +608,12 @@ void FrameTreeNode::BeforeUnloadCanceled() {
|
||||
render_manager_.speculative_frame_host();
|
||||
if (speculative_frame_host)
|
||||
speculative_frame_host->ResetLoadingState();
|
||||
- // Note: there is no need to set an error code on the NavigationHandle here
|
||||
- // as it has not been created yet. It is only created when the
|
||||
- // BeforeUnloadCompleted callback is invoked.
|
||||
- if (navigation_request_)
|
||||
+ // Note: there is no need to set an error code on the NavigationHandle as
|
||||
+ // the observers have not been notified about its creation.
|
||||
+ // We also reset navigation request only when this navigation request was
|
||||
+ // responsible for this dialog, as a new navigation request might cancel
|
||||
+ // existing unrelated dialog.
|
||||
+ if (navigation_request_ && navigation_request_->IsWaitingForBeforeUnload())
|
||||
ResetNavigationRequest(false);
|
||||
}
|
||||
|
||||
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
|
||||
index 60b2b213d6429fa7cff783370cbbeff26a97a859..66a4bc9ac8198ea91b3705db01d85cfe172c8634 100644
|
||||
--- a/content/browser/renderer_host/navigation_request.cc
|
||||
+++ b/content/browser/renderer_host/navigation_request.cc
|
||||
@@ -5148,4 +5148,8 @@ bool NavigationRequest::MaybeCancelFailedNavigation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
+bool NavigationRequest::IsWaitingForBeforeUnload() {
|
||||
+ return state_ < WILL_START_NAVIGATION;
|
||||
+}
|
||||
+
|
||||
} // namespace content
|
||||
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
|
||||
index 5e0c08775d6e504327979218d46e999757ea508b..19576fe6cd0c0fc038418683bf1858ebc5399d1e 100644
|
||||
--- a/content/browser/renderer_host/navigation_request.h
|
||||
+++ b/content/browser/renderer_host/navigation_request.h
|
||||
@@ -719,6 +719,10 @@ class CONTENT_EXPORT NavigationRequest
|
||||
// properly determine SiteInstances and process allocation.
|
||||
UrlInfo GetUrlInfo();
|
||||
|
||||
+ // Whether this navigation request waits for the result of beforeunload before
|
||||
+ // proceeding.
|
||||
+ bool IsWaitingForBeforeUnload();
|
||||
+
|
||||
private:
|
||||
friend class NavigationRequestTest;
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
|
||||
index 8e4ac3adc3f6c5ac2ff30317ca0d441671e3cc55..653c9606cbe1a145f8e9fa4e1507ad892a727481 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
|
||||
@@ -1169,6 +1169,51 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBeforeUnloadBrowserTest,
|
||||
|
||||
namespace {
|
||||
|
||||
+class OnDidStartNavigation : public WebContentsObserver {
|
||||
+ public:
|
||||
+ OnDidStartNavigation(WebContents* web_contents,
|
||||
+ base::RepeatingClosure callback)
|
||||
+ : WebContentsObserver(web_contents), callback_(callback) {}
|
||||
+
|
||||
+ void DidStartNavigation(NavigationHandle* navigation) override {
|
||||
+ callback_.Run();
|
||||
+ }
|
||||
+
|
||||
+ private:
|
||||
+ base::RepeatingClosure callback_;
|
||||
+};
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+// This test closes beforeunload dialog due to a new navigation starting from
|
||||
+// within WebContentsObserver::DidStartNavigation. This test succeeds if it
|
||||
+// doesn't crash with a UAF while loading the second page.
|
||||
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBeforeUnloadBrowserTest,
|
||||
+ DidStartNavigationClosesDialog) {
|
||||
+ GURL url1 = embedded_test_server()->GetURL("a.com", "/title1.html");
|
||||
+ GURL url2 = embedded_test_server()->GetURL("b.com", "/title1.html");
|
||||
+
|
||||
+ EXPECT_TRUE(NavigateToURL(shell(), url1));
|
||||
+
|
||||
+ // This matches the behaviour of TabModalDialogManager in
|
||||
+ // components/javascript_dialogs.
|
||||
+ OnDidStartNavigation close_dialog(web_contents(),
|
||||
+ base::BindLambdaForTesting([&]() {
|
||||
+ CloseDialogAndCancel();
|
||||
+
|
||||
+ // Check that web_contents() were not
|
||||
+ // deleted.
|
||||
+ DCHECK(web_contents()->GetMainFrame());
|
||||
+ }));
|
||||
+
|
||||
+ web_contents()->GetMainFrame()->RunBeforeUnloadConfirm(true,
|
||||
+ base::DoNothing());
|
||||
+
|
||||
+ EXPECT_TRUE(NavigateToURL(shell(), url2));
|
||||
+}
|
||||
+
|
||||
+namespace {
|
||||
+
|
||||
// A helper to execute some script in a frame just before it is deleted, such
|
||||
// that no message loops are pumped and no sync IPC messages are processed
|
||||
// between script execution and the destruction of the RenderFrameHost .
|
||||
217
patches/chromium/cherry-pick-eb0c0353bf24.patch
Normal file
217
patches/chromium/cherry-pick-eb0c0353bf24.patch
Normal file
@@ -0,0 +1,217 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Raymond Toy <rtoy@chromium.org>
|
||||
Date: Wed, 10 Feb 2021 05:34:49 +0000
|
||||
Subject: Convert AudioParam NaN values to the default value
|
||||
|
||||
If any output value of an AudioParam (including the intrinsic values
|
||||
and any inputs to the AudioParam), should be NaN, replace the NaN
|
||||
value with the associated defaultValue.
|
||||
|
||||
This causes some slowdowns so SIMD/NEON code was added to mitigate the
|
||||
degradation. There is still some slowdown, but the worst case is now
|
||||
about 7% slower on x86 and 10% on arm. Generally, the slowdown is less
|
||||
than 2% and 5%, respectively. (Perversely, some results got faster,
|
||||
and the differences are statistically significant.)
|
||||
|
||||
Full details can be found at
|
||||
https://docs.google.com/spreadsheets/d/1EhbLHm-9cUoEO5aj1vYemVBLQ3Dh4dCJPPLTfZPrZt4/edit?usp=sharing
|
||||
|
||||
Manually tested the test case from the bug and the issue no longer
|
||||
occurs.
|
||||
|
||||
(cherry picked from commit ab1862017b5717271a28376659944dddc602195c)
|
||||
|
||||
Bug: 1170531
|
||||
Change-Id: I00d902b40a9ef9da990c6d68b664b1dcfc31b091
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2658724
|
||||
Commit-Queue: Raymond Toy <rtoy@chromium.org>
|
||||
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#851733}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2686369
|
||||
Reviewed-by: Raymond Toy <rtoy@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4389@{#880}
|
||||
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
|
||||
index c5d329479a412d52ee39167ff841b1cea417a217..135588f56ebceabd3e0a12f9f506955bb58b20ca 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
|
||||
|
||||
+#include "build/build_config.h"
|
||||
#include "third_party/blink/renderer/core/inspector/console_message.h"
|
||||
#include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
|
||||
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
|
||||
@@ -235,6 +236,49 @@ void AudioParamHandler::CalculateSampleAccurateValues(
|
||||
CalculateFinalValues(values, number_of_values, IsAudioRate());
|
||||
}
|
||||
|
||||
+// Replace NaN values in |values| with |default_value|.
|
||||
+static void HandleNaNValues(float* values,
|
||||
+ unsigned number_of_values,
|
||||
+ float default_value) {
|
||||
+ unsigned k = 0;
|
||||
+#if defined(ARCH_CPU_X86_FAMILY)
|
||||
+ if (number_of_values >= 4) {
|
||||
+ __m128 defaults = _mm_set1_ps(default_value);
|
||||
+ for (k = 0; k < number_of_values; k += 4) {
|
||||
+ __m128 v = _mm_loadu_ps(values + k);
|
||||
+ // cmpuord returns all 1's if v is NaN for each elmeent of v.
|
||||
+ __m128 isnan = _mm_cmpunord_ps(v, v);
|
||||
+ // Replace NaN parts with default.
|
||||
+ __m128 result = _mm_and_ps(isnan, defaults);
|
||||
+ // Merge in the parts that aren't NaN
|
||||
+ result = _mm_or_ps(_mm_andnot_ps(isnan, v), result);
|
||||
+ _mm_storeu_ps(values + k, result);
|
||||
+ }
|
||||
+ }
|
||||
+#elif defined(CPU_ARM_NEON)
|
||||
+ if (number_of_values >= 4) {
|
||||
+ uint32x4_t defaults = static_cast<uint32x4_t>(vdupq_n_f32(default_value));
|
||||
+ for (k = 0; k < number_of_values; k += 4) {
|
||||
+ float32x4_t v = vld1q_f32(values + k);
|
||||
+ // Returns true (all ones) if v is not NaN
|
||||
+ uint32x4_t is_not_nan = vceqq_f32(v, v);
|
||||
+ // Get the parts that are not NaN
|
||||
+ uint32x4_t result = vandq_u32(is_not_nan, v);
|
||||
+ // Replace the parts that are NaN with the default and merge with previous
|
||||
+ // result. (Note: vbic_u32(x, y) = x and not y)
|
||||
+ result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan));
|
||||
+ vst1q_f32(values + k, static_cast<float32x4_t>(result));
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ for (; k < number_of_values; ++k) {
|
||||
+ if (std::isnan(values[k])) {
|
||||
+ values[k] = default_value;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void AudioParamHandler::CalculateFinalValues(float* values,
|
||||
unsigned number_of_values,
|
||||
bool sample_accurate) {
|
||||
@@ -297,10 +341,21 @@ void AudioParamHandler::CalculateFinalValues(float* values,
|
||||
}
|
||||
}
|
||||
|
||||
- // Clamp the values now to the nominal range
|
||||
float min_value = MinValue();
|
||||
float max_value = MaxValue();
|
||||
|
||||
+ if (NumberOfRenderingConnections() > 0) {
|
||||
+ // AudioParams by themselves don't produce NaN because of the finite min
|
||||
+ // and max values. But an input to an AudioParam could have NaNs.
|
||||
+ //
|
||||
+ // NaN values in AudioParams must be replaced by the AudioParam's
|
||||
+ // defaultValue. Then these values must be clamped to lie in the nominal
|
||||
+ // range between the AudioParam's minValue and maxValue.
|
||||
+ //
|
||||
+ // See https://webaudio.github.io/web-audio-api/#computation-of-value.
|
||||
+ HandleNaNValues(values, number_of_values, DefaultValue());
|
||||
+ }
|
||||
+
|
||||
vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
|
||||
number_of_values);
|
||||
}
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e9b8f0accbd1b0359275615f3ef12bd7e9317c4f
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html
|
||||
@@ -0,0 +1,92 @@
|
||||
+<!doctype html>
|
||||
+<html>
|
||||
+ <head>
|
||||
+ <title>Test Flushing of NaN to Zero in AudioParams</title>
|
||||
+ <script src="/resources/testharness.js"></script>
|
||||
+ <script src="/resources/testharnessreport.js"></script>
|
||||
+ <script src="/webaudio/resources/audit-util.js"></script>
|
||||
+ <script src="/webaudio/resources/audit.js"></script>
|
||||
+ </head>
|
||||
+
|
||||
+ <body>
|
||||
+ <script>
|
||||
+ let audit = Audit.createTaskRunner();
|
||||
+
|
||||
+ // See
|
||||
+ // https://webaudio.github.io/web-audio-api/#computation-of-value.
|
||||
+ //
|
||||
+ // The computed value must replace NaN values in the output with
|
||||
+ // the default value of the param.
|
||||
+ audit.define('AudioParam NaN', async (task, should) => {
|
||||
+ // For testing, we only need a small number of frames; and
|
||||
+ // a low sample rate is perfectly fine. Use two channels.
|
||||
+ // The first channel is for the AudioParam output. The
|
||||
+ // second channel is for the AudioParam input.
|
||||
+ let context = new OfflineAudioContext(
|
||||
+ {numberOfChannels: 2, length: 256, sampleRate: 8192});
|
||||
+ let merger = new ChannelMergerNode(
|
||||
+ context, {numberOfInputs: context.destination.channelCount});
|
||||
+ merger.connect(context.destination);
|
||||
+
|
||||
+ // A constant source with a huge value.
|
||||
+ let mod = new ConstantSourceNode(context, {offset: 1e30});
|
||||
+
|
||||
+ // Gain nodes with a huge positive gain and huge negative
|
||||
+ // gain. Combined with the huge offset in |mod|, the
|
||||
+ // output of the gain nodes are +Infinity and -Infinity.
|
||||
+ let gainPos = new GainNode(context, {gain: 1e30});
|
||||
+ let gainNeg = new GainNode(context, {gain: -1e30});
|
||||
+
|
||||
+ mod.connect(gainPos);
|
||||
+ mod.connect(gainNeg);
|
||||
+
|
||||
+ // Connect these to the second merger channel. This is a
|
||||
+ // sanity check that the AudioParam input really is NaN.
|
||||
+ gainPos.connect(merger, 0, 1);
|
||||
+ gainNeg.connect(merger, 0, 1);
|
||||
+
|
||||
+ // Source whose AudioParam is connected to the graph
|
||||
+ // that produces NaN values. Use a non-default value offset
|
||||
+ // just in case something is wrong we get default for some
|
||||
+ // other reason.
|
||||
+ let src = new ConstantSourceNode(context, {offset: 100});
|
||||
+
|
||||
+ gainPos.connect(src.offset);
|
||||
+ gainNeg.connect(src.offset);
|
||||
+
|
||||
+ // AudioParam output goes to channel 1 of the destination.
|
||||
+ src.connect(merger, 0, 0);
|
||||
+
|
||||
+ // Let's go!
|
||||
+ mod.start();
|
||||
+ src.start();
|
||||
+
|
||||
+ let buffer = await context.startRendering();
|
||||
+
|
||||
+ let input = buffer.getChannelData(1);
|
||||
+ let output = buffer.getChannelData(0);
|
||||
+
|
||||
+ // Have to test manually for NaN values in the input because
|
||||
+ // NaN fails all comparisons.
|
||||
+ let isNaN = true;
|
||||
+ for (let k = 0; k < input.length; ++k) {
|
||||
+ if (!Number.isNaN(input[k])) {
|
||||
+ isNaN = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ should(isNaN, 'AudioParam input contains only NaN').beTrue();
|
||||
+
|
||||
+ // Output of the AudioParam should have all NaN values
|
||||
+ // replaced by the default.
|
||||
+ should(output, 'AudioParam output')
|
||||
+ .beConstantValueOf(src.offset.defaultValue);
|
||||
+
|
||||
+ task.done();
|
||||
+ });
|
||||
+
|
||||
+ audit.run();
|
||||
+ </script>
|
||||
+ </body>
|
||||
+</html>
|
||||
@@ -0,0 +1,73 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kai Ninomiya <kainino@chromium.org>
|
||||
Date: Thu, 11 Feb 2021 02:24:04 +0000
|
||||
Subject: Disable GPU acceleration on all Mesa software rasterizers
|
||||
|
||||
The previous entry only disabled acceleration on swrast, but softpipe
|
||||
and llvmpipe shouldn't be used for "GPU" acceleration either.
|
||||
This should apply to Linux but not ChromeOS, AFAICT.
|
||||
|
||||
This only improves an existing software rendering list entry, but here
|
||||
is the rationale: We prefer to rely on our own (domain specific, so more
|
||||
efficient) software paths, at least for everything other than WebGL. And
|
||||
for WebGL, SwiftShader avoids unknown factors like
|
||||
llvmpipe/softpipe/swrast.
|
||||
|
||||
If you are running a Mesa GL driver (not e.g. NVIDIA) then you can force
|
||||
these configurations with:
|
||||
- LIBGL_ALWAYS_SOFTWARE=1
|
||||
https://docs.mesa3d.org/envvars.html#libgl-environment-variables:~:text=LIBGL_ALWAYS_SOFTWARE
|
||||
- GALLIUM_DRIVER=llvmpipe, softpipe, or swr (though swr didn't work for me)
|
||||
https://docs.mesa3d.org/envvars.html#gallium-environment-variables:~:text=GALLIUM_DRIVER
|
||||
|
||||
The GL_RENDERER strings are:
|
||||
- swrast: "Software Rasterizer" (couldn't test this locally; found this online)
|
||||
- softpipe: "softpipe" (on one machine)
|
||||
- llvmpipe: "llvmpipe (LLVM 10.0.0, 256 bits)" (on one machine)
|
||||
|
||||
Drive-by updates the description of another item to be more accurate
|
||||
(SVGA3D is virtualized over hardware; it's not a software renderer).
|
||||
|
||||
# Unrelated CQ failures on branch
|
||||
(cherry picked from commit 7c7eccfc85e387a0dcd154a2a9c2389177982837)
|
||||
|
||||
No-Try: True
|
||||
Bug: 1155974
|
||||
Change-Id: I0571c1a1bf526260f7ea6cd53f88eec768973b13
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2645491
|
||||
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
|
||||
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
|
||||
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#846422}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2651183
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2176}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
|
||||
index 1df09bc1c4e548919fa8b52abbfef0dedf6f411a..a2ced859448bcfe54a92d3496181d96ca85ee791 100644
|
||||
--- a/gpu/config/software_rendering_list.json
|
||||
+++ b/gpu/config/software_rendering_list.json
|
||||
@@ -21,11 +21,11 @@
|
||||
{
|
||||
"id": 3,
|
||||
"description": "GL driver is software rendered. GPU acceleration is disabled",
|
||||
- "cr_bugs": [59302, 315217],
|
||||
+ "cr_bugs": [59302, 315217, 1155974],
|
||||
"os": {
|
||||
"type": "linux"
|
||||
},
|
||||
- "gl_renderer": "(?i).*software.*",
|
||||
+ "gl_renderer": "(?i).*(software|llvmpipe|softpipe).*",
|
||||
"features": [
|
||||
"all"
|
||||
]
|
||||
@@ -337,7 +337,7 @@
|
||||
},
|
||||
{
|
||||
"id": 50,
|
||||
- "description": "Disable VMware software renderer on older Mesa",
|
||||
+ "description": "Disable VMware virtualized renderer on older Mesa",
|
||||
"cr_bugs": [145531, 332596, 571899, 629434],
|
||||
"os": {
|
||||
"type": "linux"
|
||||
@@ -0,0 +1,72 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nathan Zabriskie <nazabris@microsoft.com>
|
||||
Date: Fri, 5 Feb 2021 20:44:16 +0000
|
||||
Subject: Fix heap overflow in VideoFrameYUVConverter
|
||||
|
||||
Currently with some texture sizes GLES2Util::ComputeImageDataSizesES3
|
||||
will attempt to add row padding when calculating the size of a
|
||||
VideoFrame plane. This is because it's currently assumed that each row
|
||||
aligns on a 4 byte boundary based on GL_UNPACK_ALIGNMENT but
|
||||
VideoFrames make no such guarantee as they may be densely packed.
|
||||
This CL removes the GL_UNPACK_ALIGNMENT assumption so that we only use
|
||||
the VideoFrame's stride when calculating padding.
|
||||
|
||||
(cherry picked from commit 7de5d0ecb5a4f73aeffe15d825bf694d0d8e2a08)
|
||||
|
||||
Bug: 1166504, 1161131
|
||||
Change-Id: I2484f5dfd2ad85b088fee57758776a5c9bd01d95
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2642765
|
||||
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
|
||||
Commit-Queue: Nathan Zabriskie <nazabris@microsoft.com>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#846298}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2679121
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Auto-Submit: Nathan Zabriskie <nazabris@microsoft.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2115}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
|
||||
index e1611b999bb2ac276c64d5848e7d205a70ed26be..6400b35a7e98483c7553275623220c3bef4acd9c 100644
|
||||
--- a/gpu/command_buffer/client/gles2_implementation.cc
|
||||
+++ b/gpu/command_buffer/client/gles2_implementation.cc
|
||||
@@ -880,7 +880,9 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
|
||||
case GL_GPU_DISJOINT_EXT:
|
||||
*params = static_cast<GLint>(query_tracker_->CheckAndResetDisjoint());
|
||||
return true;
|
||||
-
|
||||
+ case GL_UNPACK_ALIGNMENT:
|
||||
+ *params = unpack_alignment_;
|
||||
+ return true;
|
||||
case GL_VIEWPORT:
|
||||
if (state_.viewport_width > 0 && state_.viewport_height > 0 &&
|
||||
capabilities_.max_viewport_width > 0 &&
|
||||
@@ -962,7 +964,6 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
|
||||
case GL_STENCIL_VALUE_MASK:
|
||||
case GL_STENCIL_WRITEMASK:
|
||||
case GL_SUBPIXEL_BITS:
|
||||
- case GL_UNPACK_ALIGNMENT:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc
|
||||
index 997a142250c56ede4cc5d9ad42743748d8b1346c..7199aef0f3bc5a3ecf6241574c69f4c2ed39f3df 100644
|
||||
--- a/gpu/command_buffer/client/raster_implementation_gles.cc
|
||||
+++ b/gpu/command_buffer/client/raster_implementation_gles.cc
|
||||
@@ -178,6 +178,9 @@ void RasterImplementationGLES::WritePixels(const gpu::Mailbox& dest_mailbox,
|
||||
BeginSharedImageAccessDirectCHROMIUM(
|
||||
texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
|
||||
|
||||
+ GLint old_align = 0;
|
||||
+ gl_->GetIntegerv(GL_UNPACK_ALIGNMENT, &old_align);
|
||||
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, row_bytes / src_info.bytesPerPixel());
|
||||
gl_->BindTexture(texture_target, texture_id);
|
||||
gl_->TexSubImage2D(texture_target, 0, dst_x_offset, dst_y_offset,
|
||||
@@ -186,6 +189,7 @@ void RasterImplementationGLES::WritePixels(const gpu::Mailbox& dest_mailbox,
|
||||
SkColorTypeToGLDataType(src_info.colorType()), src_pixels);
|
||||
gl_->BindTexture(texture_target, 0);
|
||||
gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, old_align);
|
||||
|
||||
EndSharedImageAccessDirectCHROMIUM(texture_id);
|
||||
DeleteGpuRasterTexture(texture_id);
|
||||
@@ -0,0 +1,152 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Handell <handellm@google.com>
|
||||
Date: Tue, 23 Feb 2021 18:45:55 +0000
|
||||
Subject: MediaRecorder: tolerate non-GMB NV12 frames for H264.
|
||||
|
||||
The VPX video track recorders were updated to tolerate non-GMB NV12
|
||||
input in crrev/c/2425748, but the H264 encoder was left neglected,
|
||||
which hurts Mac users that have disabled hardware acceleration. This
|
||||
change adds that support to it.
|
||||
|
||||
[TBR landing because mcasas@chromium.org is OOO]
|
||||
|
||||
TBR=mcasas@chromium.org
|
||||
(cherry picked from commit de865890bf6a12c74ae9943ede6132d25c7a33dd)
|
||||
|
||||
Bug: 1177593
|
||||
Change-Id: I608c76b1de8261dcc44463fe896e3b63d5fd329e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2694407
|
||||
Reviewed-by: ccameron <ccameron@chromium.org>
|
||||
Reviewed-by: Evan Shrubsole <eshr@google.com>
|
||||
Reviewed-by: Miguel Casas <mcasas@chromium.org>
|
||||
Commit-Queue: Markus Handell <handellm@google.com>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#854709}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2715222
|
||||
Cr-Commit-Position: refs/branch-heads/4389@{#1320}
|
||||
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
|
||||
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
|
||||
index 3daa1cb27d5705d56d0075e82a9ecd0bfb86c366..d5a0f1b578e22822089d704fcd7b98cbb26bb405 100644
|
||||
--- a/media/base/video_util.cc
|
||||
+++ b/media/base/video_util.cc
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "base/numerics/safe_math.h"
|
||||
#include "media/base/video_frame.h"
|
||||
#include "third_party/libyuv/include/libyuv.h"
|
||||
+#include "ui/gfx/gpu_memory_buffer.h"
|
||||
|
||||
namespace media {
|
||||
|
||||
@@ -424,6 +425,38 @@ void CopyRGBToVideoFrame(const uint8_t* source,
|
||||
region_in_frame.width(), region_in_frame.height());
|
||||
}
|
||||
|
||||
+scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
|
||||
+ scoped_refptr<VideoFrame> video_frame) {
|
||||
+ DCHECK(video_frame);
|
||||
+ DCHECK(video_frame->HasGpuMemoryBuffer());
|
||||
+ auto* gmb = video_frame->GetGpuMemoryBuffer();
|
||||
+ if (!gmb->Map())
|
||||
+ return nullptr;
|
||||
+ const size_t num_planes = VideoFrame::NumPlanes(video_frame->format());
|
||||
+ uint8_t* plane_addrs[VideoFrame::kMaxPlanes] = {};
|
||||
+ for (size_t i = 0; i < num_planes; i++)
|
||||
+ plane_addrs[i] = static_cast<uint8_t*>(gmb->memory(i));
|
||||
+ auto mapped_frame = VideoFrame::WrapExternalYuvDataWithLayout(
|
||||
+ video_frame->layout(), video_frame->visible_rect(),
|
||||
+ video_frame->natural_size(), plane_addrs[0], plane_addrs[1],
|
||||
+ plane_addrs[2], video_frame->timestamp());
|
||||
+ if (!mapped_frame) {
|
||||
+ gmb->Unmap();
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ mapped_frame->set_color_space(video_frame->ColorSpace());
|
||||
+ mapped_frame->metadata()->MergeMetadataFrom(video_frame->metadata());
|
||||
+ // Pass |video_frame| so that it outlives |mapped_frame| and the mapped buffer
|
||||
+ // is unmapped on destruction.
|
||||
+ mapped_frame->AddDestructionObserver(base::BindOnce(
|
||||
+ [](scoped_refptr<VideoFrame> frame) {
|
||||
+ DCHECK(frame->HasGpuMemoryBuffer());
|
||||
+ frame->GetGpuMemoryBuffer()->Unmap();
|
||||
+ },
|
||||
+ std::move(video_frame)));
|
||||
+ return mapped_frame;
|
||||
+}
|
||||
+
|
||||
scoped_refptr<VideoFrame> WrapAsI420VideoFrame(
|
||||
scoped_refptr<VideoFrame> frame) {
|
||||
DCHECK_EQ(VideoFrame::STORAGE_OWNED_MEMORY, frame->storage_type());
|
||||
diff --git a/media/base/video_util.h b/media/base/video_util.h
|
||||
index 42e060a25b711fca8bba3cef8ade9bbaa2092c55..2681163c55618ae8738d91987bb46a4e8bcc541b 100644
|
||||
--- a/media/base/video_util.h
|
||||
+++ b/media/base/video_util.h
|
||||
@@ -134,6 +134,12 @@ MEDIA_EXPORT gfx::Size GetRectSizeFromOrigin(const gfx::Rect& rect);
|
||||
MEDIA_EXPORT gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
|
||||
const gfx::Size& target);
|
||||
|
||||
+// A helper function to map GpuMemoryBuffer-based VideoFrame. This function
|
||||
+// maps the given GpuMemoryBuffer of |frame| as-is without converting pixel
|
||||
+// format. The returned VideoFrame owns the |frame|.
|
||||
+MEDIA_EXPORT scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
|
||||
+ scoped_refptr<VideoFrame> frame);
|
||||
+
|
||||
// Copy an RGB bitmap into the specified |region_in_frame| of a YUV video frame.
|
||||
// Fills the regions outside |region_in_frame| with black.
|
||||
MEDIA_EXPORT void CopyRGBToVideoFrame(const uint8_t* source,
|
||||
diff --git a/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc b/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
|
||||
index 401e696e886f68fc4a9bb9ac0614959f0a8673a8..c323faab804ad421b1c8f8d7789222304c4d44e6 100644
|
||||
--- a/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
|
||||
@@ -54,9 +54,13 @@ void H264Encoder::EncodeOnEncodingTaskRunner(
|
||||
base::TimeTicks capture_timestamp) {
|
||||
TRACE_EVENT0("media", "H264Encoder::EncodeOnEncodingTaskRunner");
|
||||
DCHECK(encoding_task_runner_->BelongsToCurrentThread());
|
||||
+ DCHECK(frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_NV12 ||
|
||||
+ frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_I420 ||
|
||||
+ frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_I420A);
|
||||
|
||||
- if (frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER)
|
||||
+ if (frame->format() == media::PIXEL_FORMAT_NV12)
|
||||
frame = ConvertToI420ForSoftwareEncoder(frame);
|
||||
+ DCHECK(frame->IsMappable());
|
||||
|
||||
const gfx::Size frame_size = frame->visible_rect().size();
|
||||
if (!openh264_encoder_ || configured_size_ != frame_size) {
|
||||
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
|
||||
index 8f69cc61257cbe2c4c349912cfb4647ceaf771f7..1ace9b3f6ed14a96af7b8e8779a3929675be9a0a 100644
|
||||
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
|
||||
@@ -415,20 +415,17 @@ bool VideoTrackRecorderImpl::Encoder::CanEncodeAlphaChannel() {
|
||||
scoped_refptr<media::VideoFrame>
|
||||
VideoTrackRecorderImpl::Encoder::ConvertToI420ForSoftwareEncoder(
|
||||
scoped_refptr<media::VideoFrame> frame) {
|
||||
- DCHECK_EQ(frame->storage_type(),
|
||||
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
|
||||
- // NV12 is currently the only supported pixel format for GpuMemoryBuffer.
|
||||
DCHECK_EQ(frame->format(), media::VideoPixelFormat::PIXEL_FORMAT_NV12);
|
||||
|
||||
- auto* gmb = frame->GetGpuMemoryBuffer();
|
||||
- if (!gmb->Map())
|
||||
- return frame;
|
||||
+ if (frame->GetGpuMemoryBuffer())
|
||||
+ frame = media::ConvertToMemoryMappedFrame(frame);
|
||||
+
|
||||
scoped_refptr<media::VideoFrame> i420_frame = media::VideoFrame::CreateFrame(
|
||||
media::VideoPixelFormat::PIXEL_FORMAT_I420, frame->coded_size(),
|
||||
frame->visible_rect(), frame->natural_size(), frame->timestamp());
|
||||
auto ret = libyuv::NV12ToI420(
|
||||
- static_cast<const uint8_t*>(gmb->memory(0)), gmb->stride(0),
|
||||
- static_cast<const uint8_t*>(gmb->memory(1)), gmb->stride(1),
|
||||
+ static_cast<const uint8_t*>(frame->data(0)), frame->stride(0),
|
||||
+ static_cast<const uint8_t*>(frame->data(1)), frame->stride(1),
|
||||
i420_frame->data(media::VideoFrame::kYPlane),
|
||||
i420_frame->stride(media::VideoFrame::kYPlane),
|
||||
i420_frame->data(media::VideoFrame::kUPlane),
|
||||
@@ -436,7 +433,6 @@ VideoTrackRecorderImpl::Encoder::ConvertToI420ForSoftwareEncoder(
|
||||
i420_frame->data(media::VideoFrame::kVPlane),
|
||||
i420_frame->stride(media::VideoFrame::kVPlane),
|
||||
frame->coded_size().width(), frame->coded_size().height());
|
||||
- gmb->Unmap();
|
||||
if (ret)
|
||||
return frame;
|
||||
return i420_frame;
|
||||
@@ -0,0 +1,119 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Anderson <thomasanderson@chromium.org>
|
||||
Date: Wed, 10 Feb 2021 23:53:26 +0000
|
||||
Subject: Avoid spinning a nested message loop for X11 clipboard
|
||||
|
||||
*** NOTE: THIS IS NOT A CLEAN MERGE ***
|
||||
|
||||
> BUG=443355,1138143,1161141,1161143,1161144,1161145,1161146,1161147,1161149,1161151,1161152
|
||||
>
|
||||
> Change-Id: I5c95a9d066683d18f344d694e517274e3ef7ccb4
|
||||
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2622521
|
||||
> Reviewed-by: Scott Violet <sky@chromium.org>
|
||||
> Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
|
||||
> Cr-Commit-Position: refs/heads/master@{#844318}
|
||||
|
||||
BUG=1138143
|
||||
TBR=sky
|
||||
|
||||
Change-Id: I7269ac8af7c91988a7d5520b3faf88dac89a577e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2688137
|
||||
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2166}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc
|
||||
index 7a83c814a756eb4daea020a47035c80320a129c3..f669f075b4dee7bbbc53c28abfe2f87fa6f27ed1 100644
|
||||
--- a/ui/base/x/selection_requestor.cc
|
||||
+++ b/ui/base/x/selection_requestor.cc
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
-#include "base/run_loop.h"
|
||||
#include "ui/base/x/selection_owner.h"
|
||||
#include "ui/base/x/selection_utils.h"
|
||||
#include "ui/base/x/x11_util.h"
|
||||
@@ -28,7 +27,7 @@ const char kChromeSelection[] = "CHROME_SELECTION";
|
||||
const int KSelectionRequestorTimerPeriodMs = 100;
|
||||
|
||||
// The amount of time to wait for a request to complete before aborting it.
|
||||
-const int kRequestTimeoutMs = 10000;
|
||||
+const int kRequestTimeoutMs = 1000;
|
||||
|
||||
static_assert(KSelectionRequestorTimerPeriodMs <= kRequestTimeoutMs,
|
||||
"timer period must be <= request timeout");
|
||||
@@ -235,37 +234,30 @@ void SelectionRequestor::ConvertSelectionForCurrentRequest() {
|
||||
}
|
||||
|
||||
void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
|
||||
- if (X11EventSource::HasInstance()) {
|
||||
- if (!abort_timer_.IsRunning()) {
|
||||
- abort_timer_.Start(
|
||||
- FROM_HERE,
|
||||
- base::TimeDelta::FromMilliseconds(KSelectionRequestorTimerPeriodMs),
|
||||
- this, &SelectionRequestor::AbortStaleRequests);
|
||||
- }
|
||||
-
|
||||
- base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
|
||||
- request->quit_closure = run_loop.QuitClosure();
|
||||
- run_loop.Run();
|
||||
-
|
||||
- // We cannot put logic to process the next request here because the RunLoop
|
||||
- // might be nested. For instance, request 'B' may start a RunLoop while the
|
||||
- // RunLoop for request 'A' is running. It is not possible to end the RunLoop
|
||||
- // for request 'A' without first ending the RunLoop for request 'B'.
|
||||
- } else {
|
||||
- // This occurs if PerformBlockingConvertSelection() is called during
|
||||
- // shutdown and the X11EventSource has already been destroyed.
|
||||
- auto* conn = x11::Connection::Get();
|
||||
- auto& events = conn->events();
|
||||
- while (!request->completed && request->timeout > base::TimeTicks::Now()) {
|
||||
- conn->Flush();
|
||||
- conn->ReadResponses();
|
||||
- if (!conn->events().empty()) {
|
||||
- x11::Event event = std::move(events.front());
|
||||
- events.pop_front();
|
||||
- dispatcher_->DispatchXEvent(&event);
|
||||
+ auto* connection = x11::Connection::Get();
|
||||
+ auto& events = connection->events();
|
||||
+ size_t i = 0;
|
||||
+ while (!request->completed && request->timeout > base::TimeTicks::Now()) {
|
||||
+ connection->Flush();
|
||||
+ connection->ReadResponses();
|
||||
+ size_t events_size = events.size();
|
||||
+ for (; i < events_size; ++i) {
|
||||
+ auto& event = events[i];
|
||||
+ if (auto* notify = event.As<x11::SelectionNotifyEvent>()) {
|
||||
+ if (notify->requestor == x_window_) {
|
||||
+ OnSelectionNotify(*notify);
|
||||
+ event = x11::Event();
|
||||
+ }
|
||||
+ } else if (auto* prop = event.As<x11::PropertyNotifyEvent>()) {
|
||||
+ if (CanDispatchPropertyEvent(event)) {
|
||||
+ OnPropertyEvent(event);
|
||||
+ event = x11::Event();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
+ DCHECK_EQ(events_size, events.size());
|
||||
}
|
||||
+ AbortStaleRequests();
|
||||
}
|
||||
|
||||
SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() {
|
||||
diff --git a/ui/base/x/selection_requestor_unittest.cc b/ui/base/x/selection_requestor_unittest.cc
|
||||
index c67b8e62213456e0b3006a1eac618c733d28e1e2..efb31b6f3c07ea7debb188bdc8012849362b8dae 100644
|
||||
--- a/ui/base/x/selection_requestor_unittest.cc
|
||||
+++ b/ui/base/x/selection_requestor_unittest.cc
|
||||
@@ -102,7 +102,8 @@ void PerformBlockingConvertSelection(SelectionRequestor* requestor,
|
||||
|
||||
// Test that SelectionRequestor correctly handles receiving a request while it
|
||||
// is processing another request.
|
||||
-TEST_F(SelectionRequestorTest, NestedRequests) {
|
||||
+// TODO(https://crbug.com/443355): Reenable once clipboard interface is async.
|
||||
+TEST_F(SelectionRequestorTest, DISABLED_NestedRequests) {
|
||||
// Assume that |selection| will have no owner. If there is an owner, the owner
|
||||
// will set the property passed into the XConvertSelection() request which is
|
||||
// undesirable.
|
||||
@@ -0,0 +1,257 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Anderson <thomasanderson@chromium.org>
|
||||
Date: Wed, 10 Feb 2021 22:45:10 +0000
|
||||
Subject: Switch event queue from a std::list to a base::circular_deque
|
||||
|
||||
*** NOTE: THIS IS NOT A CLEAN MERGE ***
|
||||
|
||||
> This is needed as a prerequisite for [1]. It also improves performance
|
||||
> a bit by replacing a node-based data structure with a flat one.
|
||||
>
|
||||
> [1] https://chromium-review.googlesource.com/c/chromium/src/+/2622521
|
||||
>
|
||||
> Change-Id: Ibe2e522f6c131876ed73793305524c25b42ab910
|
||||
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2625784
|
||||
> Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
|
||||
> Reviewed-by: Scott Violet <sky@chromium.org>
|
||||
> Cr-Commit-Position: refs/heads/master@{#844303}
|
||||
|
||||
BUG=1138143
|
||||
TBR=sky
|
||||
|
||||
Change-Id: I181af2c82d5552a3614747d8b4f6740583ec4ffe
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2687828
|
||||
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2163}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
|
||||
index c604bcd0f9b567957646f2cc16931d010bc0f9c6..c210014f2b07e731fb2e7c3ccbce44dec43dda25 100644
|
||||
--- a/ui/base/x/x11_util.cc
|
||||
+++ b/ui/base/x/x11_util.cc
|
||||
@@ -348,16 +348,14 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
|
||||
|
||||
conn->ReadResponses();
|
||||
if (motion) {
|
||||
- for (auto it = conn->events().begin(); it != conn->events().end();) {
|
||||
- const auto& next_event = *it;
|
||||
+ for (auto& next_event : conn->events()) {
|
||||
// Discard all but the most recent motion event that targets the same
|
||||
// window with unchanged state.
|
||||
const auto* next_motion = next_event.As<x11::MotionNotifyEvent>();
|
||||
if (next_motion && next_motion->event == motion->event &&
|
||||
next_motion->child == motion->child &&
|
||||
next_motion->state == motion->state) {
|
||||
- *last_event = std::move(*it);
|
||||
- it = conn->events().erase(it);
|
||||
+ *last_event = std::move(next_event);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -367,8 +365,8 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
|
||||
device->opcode == x11::Input::DeviceEvent::TouchUpdate);
|
||||
|
||||
auto* ddmx11 = ui::DeviceDataManagerX11::GetInstance();
|
||||
- for (auto it = conn->events().begin(); it != conn->events().end();) {
|
||||
- auto* next_device = it->As<x11::Input::DeviceEvent>();
|
||||
+ for (auto& event : conn->events()) {
|
||||
+ auto* next_device = event.As<x11::Input::DeviceEvent>();
|
||||
|
||||
if (!next_device)
|
||||
break;
|
||||
@@ -379,13 +377,13 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
|
||||
// always be at least one pending.
|
||||
if (!ui::TouchFactory::GetInstance()->ShouldProcessDeviceEvent(
|
||||
*next_device)) {
|
||||
- it = conn->events().erase(it);
|
||||
+ event = x11::Event();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next_device->opcode == device->opcode &&
|
||||
- !ddmx11->IsCMTGestureEvent(*it) &&
|
||||
- ddmx11->GetScrollClassEventDetail(*it) == SCROLL_TYPE_NO_SCROLL) {
|
||||
+ !ddmx11->IsCMTGestureEvent(event) &&
|
||||
+ ddmx11->GetScrollClassEventDetail(event) == SCROLL_TYPE_NO_SCROLL) {
|
||||
// Confirm that the motion event is targeted at the same window
|
||||
// and that no buttons or modifiers have changed.
|
||||
if (device->event == next_device->event &&
|
||||
@@ -396,12 +394,12 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
|
||||
device->mods.latched == next_device->mods.latched &&
|
||||
device->mods.locked == next_device->mods.locked &&
|
||||
device->mods.effective == next_device->mods.effective) {
|
||||
- *last_event = std::move(*it);
|
||||
- it = conn->events().erase(it);
|
||||
+ *last_event = std::move(event);
|
||||
num_coalesced++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
+
|
||||
break;
|
||||
}
|
||||
}
|
||||
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
|
||||
index ae9b1d5174e6b39995bde80034ad426dcf4478c8..7164a2c47e2cd73092818896a1d94b705c98dbb1 100644
|
||||
--- a/ui/events/platform/x11/x11_event_source.cc
|
||||
+++ b/ui/events/platform/x11/x11_event_source.cc
|
||||
@@ -221,8 +221,9 @@ x11::Time X11EventSource::GetCurrentServerTime() {
|
||||
};
|
||||
|
||||
auto& events = connection_->events();
|
||||
- events.erase(std::remove_if(events.begin(), events.end(), pred),
|
||||
- events.end());
|
||||
+ auto it = std::find_if(events.begin(), events.end(), pred);
|
||||
+ if (it != events.end())
|
||||
+ *it = x11::Event();
|
||||
return time;
|
||||
}
|
||||
|
||||
diff --git a/ui/gfx/x/connection.cc b/ui/gfx/x/connection.cc
|
||||
index cea4895e776f6329ea65f94e3987402dadccabcb..c6a8b27f9a7f0ec4dae5187de471100c54a76b5c 100644
|
||||
--- a/ui/gfx/x/connection.cc
|
||||
+++ b/ui/gfx/x/connection.cc
|
||||
@@ -326,12 +326,21 @@ Connection::Request::Request(Request&& other)
|
||||
|
||||
Connection::Request::~Request() = default;
|
||||
|
||||
-bool Connection::HasNextResponse() const {
|
||||
+bool Connection::HasNextResponse() {
|
||||
return !requests_.empty() &&
|
||||
CompareSequenceIds(XLastKnownRequestProcessed(display_),
|
||||
requests_.front().sequence) >= 0;
|
||||
}
|
||||
|
||||
+bool Connection::HasNextEvent() {
|
||||
+ while (!events_.empty()) {
|
||||
+ if (events_.front().Initialized())
|
||||
+ return true;
|
||||
+ events_.pop_front();
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
int Connection::GetFd() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
return Ready() ? xcb_get_file_descriptor(XcbConnection()) : -1;
|
||||
@@ -389,7 +398,7 @@ void Connection::ReadResponses() {
|
||||
|
||||
Event Connection::WaitForNextEvent() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
- if (!events_.empty()) {
|
||||
+ if (HasNextEvent()) {
|
||||
Event event = std::move(events_.front());
|
||||
events_.pop_front();
|
||||
return event;
|
||||
@@ -401,9 +410,9 @@ Event Connection::WaitForNextEvent() {
|
||||
return Event();
|
||||
}
|
||||
|
||||
-bool Connection::HasPendingResponses() const {
|
||||
+bool Connection::HasPendingResponses() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
- return !events_.empty() || HasNextResponse();
|
||||
+ return HasNextEvent() || HasNextResponse();
|
||||
}
|
||||
|
||||
const Connection::VisualInfo* Connection::GetVisualInfoFromId(
|
||||
@@ -475,7 +484,7 @@ void Connection::Dispatch(Delegate* delegate) {
|
||||
};
|
||||
|
||||
auto process_next_event = [&] {
|
||||
- DCHECK(!events_.empty());
|
||||
+ DCHECK(HasNextEvent());
|
||||
|
||||
Event event = std::move(events_.front());
|
||||
events_.pop_front();
|
||||
@@ -488,7 +497,7 @@ void Connection::Dispatch(Delegate* delegate) {
|
||||
Flush();
|
||||
ReadResponses();
|
||||
|
||||
- if (HasNextResponse() && !events_.empty()) {
|
||||
+ if (HasNextResponse() && HasNextEvent()) {
|
||||
if (!events_.front().sequence_valid()) {
|
||||
process_next_event();
|
||||
continue;
|
||||
@@ -506,7 +515,7 @@ void Connection::Dispatch(Delegate* delegate) {
|
||||
process_next_event();
|
||||
} else if (HasNextResponse()) {
|
||||
process_next_response();
|
||||
- } else if (!events_.empty()) {
|
||||
+ } else if (HasNextEvent()) {
|
||||
process_next_event();
|
||||
} else {
|
||||
break;
|
||||
diff --git a/ui/gfx/x/connection.h b/ui/gfx/x/connection.h
|
||||
index 1e0fa6c230052e16fc67a4f6b154864477216445..107105d4236a6a99b544741a9e4ddf83407531de 100644
|
||||
--- a/ui/gfx/x/connection.h
|
||||
+++ b/ui/gfx/x/connection.h
|
||||
@@ -5,10 +5,10 @@
|
||||
#ifndef UI_GFX_X_CONNECTION_H_
|
||||
#define UI_GFX_X_CONNECTION_H_
|
||||
|
||||
-#include <list>
|
||||
#include <queue>
|
||||
|
||||
#include "base/component_export.h"
|
||||
+#include "base/containers/circular_deque.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "ui/events/platform/platform_event_source.h"
|
||||
#include "ui/gfx/x/event.h"
|
||||
@@ -113,7 +113,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
|
||||
Event WaitForNextEvent();
|
||||
|
||||
// Are there any events, errors, or replies already buffered?
|
||||
- bool HasPendingResponses() const;
|
||||
+ bool HasPendingResponses();
|
||||
|
||||
// Dispatch any buffered events, errors, or replies.
|
||||
void Dispatch(Delegate* delegate);
|
||||
@@ -126,8 +126,10 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
|
||||
|
||||
KeySym KeycodeToKeysym(uint32_t keycode, unsigned int modifiers);
|
||||
|
||||
- // Access the event buffer. Clients can add, delete, or modify events.
|
||||
- std::list<Event>& events() {
|
||||
+ // Access the event buffer. Clients may modify the queue, including
|
||||
+ // "deleting" events by setting events[i] = x11::Event(), which will
|
||||
+ // guarantee all calls to x11::Event::As() will return nullptr.
|
||||
+ base::circular_deque<Event>& events() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
return events_;
|
||||
}
|
||||
@@ -159,7 +161,9 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
|
||||
|
||||
void AddRequest(unsigned int sequence, FutureBase::ResponseCallback callback);
|
||||
|
||||
- bool HasNextResponse() const;
|
||||
+ bool HasNextResponse();
|
||||
+
|
||||
+ bool HasNextEvent();
|
||||
|
||||
void PreDispatchEvent(const Event& event);
|
||||
|
||||
@@ -194,7 +198,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
|
||||
uint8_t mode_switch_ = 0;
|
||||
uint8_t num_lock_ = 0;
|
||||
|
||||
- std::list<Event> events_;
|
||||
+ base::circular_deque<Event> events_;
|
||||
|
||||
std::queue<Request> requests_;
|
||||
|
||||
diff --git a/ui/gfx/x/event.h b/ui/gfx/x/event.h
|
||||
index 7e3d41dc7cefc5b01bd582b55274fd1f75c7782f..b370b0f9a95a2f1fec19d82ad17a76bb07015511 100644
|
||||
--- a/ui/gfx/x/event.h
|
||||
+++ b/ui/gfx/x/event.h
|
||||
@@ -76,6 +76,8 @@ class COMPONENT_EXPORT(X11) Event {
|
||||
*window_ = window;
|
||||
}
|
||||
|
||||
+ bool Initialized() const { return deleter_; }
|
||||
+
|
||||
private:
|
||||
friend void ReadEvent(Event* event,
|
||||
Connection* connection,
|
||||
@@ -0,0 +1,137 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Raymond Zhao <raymondzhao@microsoft.com>
|
||||
Date: Wed, 10 Feb 2021 12:03:34 -0800
|
||||
Subject: Replace ClearFilterData with InvalidateFilterData
|
||||
|
||||
This is a hand-patch of
|
||||
https://chromium-review.googlesource.com/c/chromium/src/+/2566992,
|
||||
where the InvalidateFilterData function is from
|
||||
https://chromium-review.googlesource.com/c/chromium/src/+/2454053.
|
||||
|
||||
Firstly, the InvalidateFilterData function was copied over.
|
||||
Then, the ClearFilterData function was deleted, and any calls to it
|
||||
were replaced with InvalidateFilterData. Redundant calls were removed.
|
||||
|
||||
The InvalidateFilterData function in this patch contains
|
||||
a fix for SVG content sometimes failing to appear after modification
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=1154050.
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
|
||||
index c7093ea1724dc99a26c3eef033d7ef13c2888f54..852eeb24ec617ae86e9aecd08bfe564445fbdca9 100644
|
||||
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
|
||||
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
|
||||
@@ -227,16 +227,11 @@ static inline void RemoveFromCacheAndInvalidateDependencies(
|
||||
if (resources->HasClipOrMaskOrFilter()) {
|
||||
InvalidationModeMask invalidation_mask =
|
||||
SVGResourceClient::kBoundariesInvalidation;
|
||||
- bool filter_data_invalidated = false;
|
||||
if (resources->Filter()) {
|
||||
- filter_data_invalidated = client->ClearFilterData();
|
||||
- invalidation_mask |=
|
||||
- filter_data_invalidated ? SVGResourceClient::kPaintInvalidation : 0;
|
||||
+ client->InvalidateFilterData();
|
||||
}
|
||||
LayoutSVGResourceContainer::MarkClientForInvalidation(object,
|
||||
invalidation_mask);
|
||||
- if (filter_data_invalidated)
|
||||
- client->MarkFilterDataDirty();
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
|
||||
index f37cb5c3052d72ab15e769b29f8456e7ced9b5af..41ec00a53c1bb1c587b42f74867af4adab7e8641 100644
|
||||
--- a/third_party/blink/renderer/core/layout/svg/svg_resources.cc
|
||||
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
|
||||
@@ -604,12 +604,7 @@ void SVGResources::ClearClipPathFilterMask(SVGElement& element,
|
||||
old_reference_clip->RemoveClient(*client);
|
||||
if (style->HasFilter()) {
|
||||
style->Filter().RemoveClient(*client);
|
||||
- if (client->ClearFilterData()) {
|
||||
- LayoutObject* layout_object = element.GetLayoutObject();
|
||||
- LayoutSVGResourceContainer::MarkClientForInvalidation(
|
||||
- *layout_object, SVGResourceClient::kPaintInvalidation);
|
||||
- client->MarkFilterDataDirty();
|
||||
- }
|
||||
+ client->InvalidateFilterData();
|
||||
}
|
||||
if (StyleSVGResource* masker_resource = style->SvgStyle().MaskerResource())
|
||||
masker_resource->RemoveClient(*client);
|
||||
@@ -712,14 +707,10 @@ void SVGElementResourceClient::ResourceContentChanged(
|
||||
return;
|
||||
}
|
||||
|
||||
- const bool filter_data_invalidated = ClearFilterData();
|
||||
- if (filter_data_invalidated)
|
||||
- invalidation_mask |= SVGResourceClient::kPaintInvalidation;
|
||||
+ InvalidateFilterData();
|
||||
|
||||
LayoutSVGResourceContainer::MarkClientForInvalidation(*layout_object,
|
||||
invalidation_mask);
|
||||
- if (filter_data_invalidated)
|
||||
- MarkFilterDataDirty();
|
||||
|
||||
bool needs_layout =
|
||||
invalidation_mask & SVGResourceClient::kLayoutInvalidation;
|
||||
@@ -729,12 +720,8 @@ void SVGElementResourceClient::ResourceContentChanged(
|
||||
|
||||
void SVGElementResourceClient::ResourceElementChanged() {
|
||||
if (LayoutObject* layout_object = element_->GetLayoutObject()) {
|
||||
- ClearFilterData();
|
||||
+ InvalidateFilterData();
|
||||
SVGResourcesCache::ResourceReferenceChanged(*layout_object);
|
||||
- // TODO(fs): If the resource element (for a filter) doesn't actually change
|
||||
- // we don't need to perform the associated invalidations.
|
||||
- layout_object->SetNeedsPaintPropertyUpdate();
|
||||
- MarkFilterDataDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,11 +788,16 @@ void SVGElementResourceClient::UpdateFilterData(
|
||||
filter_data_dirty_ = false;
|
||||
}
|
||||
|
||||
-bool SVGElementResourceClient::ClearFilterData() {
|
||||
- FilterData* filter_data = filter_data_.Release();
|
||||
- if (filter_data)
|
||||
+void SVGElementResourceClient::InvalidateFilterData() {
|
||||
+ // If we performed an "optimized" invalidation via FilterPrimitiveChanged(),
|
||||
+ // we could have set |filter_data_dirty_| but not cleared |filter_data_|.
|
||||
+ if (filter_data_dirty_ && !filter_data_)
|
||||
+ return;
|
||||
+ if (FilterData* filter_data = filter_data_.Release())
|
||||
filter_data->Dispose();
|
||||
- return !!filter_data;
|
||||
+ LayoutObject* layout_object = element_->GetLayoutObject();
|
||||
+ layout_object->SetNeedsPaintPropertyUpdate();
|
||||
+ MarkFilterDataDirty();
|
||||
}
|
||||
|
||||
void SVGElementResourceClient::MarkFilterDataDirty() {
|
||||
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.h b/third_party/blink/renderer/core/layout/svg/svg_resources.h
|
||||
index bfe056704b698d2189e5b759040f4f6cb3c54308..3416de3d5e062a31a0beb2df4d7398d2d435ec6a 100644
|
||||
--- a/third_party/blink/renderer/core/layout/svg/svg_resources.h
|
||||
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources.h
|
||||
@@ -228,7 +228,7 @@ class SVGElementResourceClient final
|
||||
const QualifiedName& attribute) override;
|
||||
|
||||
void UpdateFilterData(CompositorFilterOperations&);
|
||||
- bool ClearFilterData();
|
||||
+ void InvalidateFilterData();
|
||||
void MarkFilterDataDirty();
|
||||
|
||||
void Trace(Visitor*) const override;
|
||||
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
|
||||
index b9aea888de151de41591ec9fd76ef4a3c0f4b017..6fa6ee6eb18f049603c5fc177a53c772239761cc 100644
|
||||
--- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
|
||||
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
|
||||
@@ -99,9 +99,7 @@ void SVGResourcesCache::ClientLayoutChanged(LayoutObject& object) {
|
||||
invalidation_flags = SVGResourceClient::kBoundariesInvalidation;
|
||||
bool filter_data_invalidated = false;
|
||||
if (resources->Filter()) {
|
||||
- filter_data_invalidated = client->ClearFilterData();
|
||||
- invalidation_flags |=
|
||||
- filter_data_invalidated ? SVGResourceClient::kPaintInvalidation : 0;
|
||||
+ client->InvalidateFilterData();
|
||||
}
|
||||
if (LayoutSVGResourcePaintServer* fill = resources->Fill()) {
|
||||
fill->RemoveClientFromCache(*client);
|
||||
@@ -0,0 +1,140 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Min Qin <qinmin@chromium.org>
|
||||
Date: Fri, 12 Feb 2021 22:45:08 +0000
|
||||
Subject: Stop using raw WebContents ptr in DragDownloadFile
|
||||
|
||||
BUG=1172192
|
||||
|
||||
(cherry picked from commit 99dc876a13df19f3512bcfb97e794ab5d1b28905)
|
||||
|
||||
Change-Id: Ie029713553ff88c1e271db1c84396e1ddda19286
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2666189
|
||||
Reviewed-by: Xing Liu <xingliu@chromium.org>
|
||||
Commit-Queue: Min Qin <qinmin@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#849692}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2692927
|
||||
Reviewed-by: Shakti Sahu <shaktisahu@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2200}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/content/browser/download/drag_download_file.cc b/content/browser/download/drag_download_file.cc
|
||||
index 05c110adcbdebd67adc58a5e17b46dbd50ccc220..5dc8fe2214f6b5ef16445196e54ccb668c9fb5ef 100644
|
||||
--- a/content/browser/download/drag_download_file.cc
|
||||
+++ b/content/browser/download/drag_download_file.cc
|
||||
@@ -37,15 +37,17 @@ class DragDownloadFile::DragDownloadFileUI
|
||||
DragDownloadFileUI(const GURL& url,
|
||||
const Referrer& referrer,
|
||||
const std::string& referrer_encoding,
|
||||
- WebContents* web_contents,
|
||||
+ int render_process_id,
|
||||
+ int render_frame_id,
|
||||
OnCompleted on_completed)
|
||||
: on_completed_(std::move(on_completed)),
|
||||
url_(url),
|
||||
referrer_(referrer),
|
||||
referrer_encoding_(referrer_encoding),
|
||||
- web_contents_(web_contents) {
|
||||
+ render_process_id_(render_process_id),
|
||||
+ render_frame_id_(render_frame_id) {
|
||||
DCHECK(on_completed_);
|
||||
- DCHECK(web_contents_);
|
||||
+ DCHECK_GE(render_frame_id_, 0);
|
||||
// May be called on any thread.
|
||||
// Do not call weak_ptr_factory_.GetWeakPtr() outside the UI thread.
|
||||
}
|
||||
@@ -54,6 +56,10 @@ class DragDownloadFile::DragDownloadFileUI
|
||||
const base::FilePath& file_path) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
+ RenderFrameHost* host =
|
||||
+ RenderFrameHost::FromID(render_process_id_, render_frame_id_);
|
||||
+ if (!host)
|
||||
+ return;
|
||||
// TODO(https://crbug.com/614134) This should use the frame actually
|
||||
// containing the link being dragged rather than the main frame of the tab.
|
||||
net::NetworkTrafficAnnotationTag traffic_annotation =
|
||||
@@ -79,9 +85,9 @@ class DragDownloadFile::DragDownloadFileUI
|
||||
}
|
||||
}
|
||||
})");
|
||||
- std::unique_ptr<download::DownloadUrlParameters> params(
|
||||
- DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
|
||||
- web_contents_, url_, traffic_annotation));
|
||||
+ auto params = std::make_unique<download::DownloadUrlParameters>(
|
||||
+ url_, render_process_id_, host->GetRenderViewHost()->GetRoutingID(),
|
||||
+ render_frame_id_, traffic_annotation);
|
||||
params->set_referrer(referrer_.url);
|
||||
params->set_referrer_policy(
|
||||
Referrer::ReferrerPolicyForUrlRequest(referrer_.policy));
|
||||
@@ -91,7 +97,7 @@ class DragDownloadFile::DragDownloadFileUI
|
||||
params->set_file_path(file_path);
|
||||
params->set_file(std::move(file)); // Nulls file.
|
||||
params->set_download_source(download::DownloadSource::DRAG_AND_DROP);
|
||||
- BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext())
|
||||
+ BrowserContext::GetDownloadManager(host->GetBrowserContext())
|
||||
->DownloadUrl(std::move(params));
|
||||
}
|
||||
|
||||
@@ -165,7 +171,8 @@ class DragDownloadFile::DragDownloadFileUI
|
||||
GURL url_;
|
||||
Referrer referrer_;
|
||||
std::string referrer_encoding_;
|
||||
- WebContents* web_contents_;
|
||||
+ int render_process_id_;
|
||||
+ int render_frame_id_;
|
||||
download::DownloadItem* download_item_ = nullptr;
|
||||
|
||||
// Only used in the callback from DownloadManager::DownloadUrl().
|
||||
@@ -182,8 +189,10 @@ DragDownloadFile::DragDownloadFile(const base::FilePath& file_path,
|
||||
WebContents* web_contents)
|
||||
: file_path_(file_path), file_(std::move(file)) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
+ RenderFrameHost* host = web_contents->GetMainFrame();
|
||||
drag_ui_ = new DragDownloadFileUI(
|
||||
- url, referrer, referrer_encoding, web_contents,
|
||||
+ url, referrer, referrer_encoding, host->GetProcess()->GetID(),
|
||||
+ host->GetRoutingID(),
|
||||
base::BindOnce(&DragDownloadFile::DownloadCompleted,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
DCHECK(!file_path_.empty());
|
||||
diff --git a/content/browser/download/drag_download_file_browsertest.cc b/content/browser/download/drag_download_file_browsertest.cc
|
||||
index 800891a6df4f0d79f1dd0a9cf89b47b882d0f3de..88e248e49898ef55eff694d0979e01bbe69aa2f6 100644
|
||||
--- a/content/browser/download/drag_download_file_browsertest.cc
|
||||
+++ b/content/browser/download/drag_download_file_browsertest.cc
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "content/public/test/content_browser_test.h"
|
||||
#include "content/public/test/content_browser_test_utils.h"
|
||||
#include "content/public/test/download_test_observer.h"
|
||||
+#include "content/public/test/test_utils.h"
|
||||
#include "content/shell/browser/shell.h"
|
||||
#include "content/shell/browser/shell_browser_context.h"
|
||||
#include "content/shell/browser/shell_download_manager_delegate.h"
|
||||
@@ -129,6 +130,28 @@ IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_Complete) {
|
||||
RunUntilSucceed();
|
||||
}
|
||||
|
||||
+IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_ClosePage) {
|
||||
+ base::FilePath name(
|
||||
+ downloads_directory().AppendASCII("DragDownloadFileTest_Complete.txt"));
|
||||
+ GURL url = embedded_test_server()->GetURL("/download/download-test.lib");
|
||||
+ Referrer referrer;
|
||||
+ std::string referrer_encoding;
|
||||
+ auto file = std::make_unique<DragDownloadFile>(name, base::File(), url,
|
||||
+ referrer, referrer_encoding,
|
||||
+ shell()->web_contents());
|
||||
+ scoped_refptr<MockDownloadFileObserver> observer(
|
||||
+ new MockDownloadFileObserver());
|
||||
+ ON_CALL(*observer.get(), OnDownloadAborted())
|
||||
+ .WillByDefault(InvokeWithoutArgs(this, &DragDownloadFileTest::FailFast));
|
||||
+ DownloadManager* manager = BrowserContext::GetDownloadManager(
|
||||
+ shell()->web_contents()->GetBrowserContext());
|
||||
+ file->Start(observer.get());
|
||||
+ shell()->web_contents()->Close();
|
||||
+ RunAllTasksUntilIdle();
|
||||
+ std::vector<download::DownloadItem*> downloads;
|
||||
+ manager->GetAllDownloads(&downloads);
|
||||
+ ASSERT_EQ(0u, downloads.size());
|
||||
+}
|
||||
// TODO(benjhayden): Test Stop().
|
||||
|
||||
} // namespace content
|
||||
@@ -0,0 +1,92 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Adam Rice <ricea@chromium.org>
|
||||
Date: Fri, 12 Feb 2021 10:43:43 +0000
|
||||
Subject: WebSocket: Don't clear event queue on destruction
|
||||
|
||||
It's unnecessary to clear the event queue as it will be garbage
|
||||
collected anyway. Stop doing it.
|
||||
|
||||
Also add a unit test for GC with pending events. This can only happen if
|
||||
the execution context changes while the events are pending.
|
||||
|
||||
BUG=1170657
|
||||
|
||||
(cherry picked from commit 2dae20b0b3890af23852345a69158c99b47746aa)
|
||||
|
||||
(cherry picked from commit 171d6ee562c3cac850d9705e18745bb1214e5d83)
|
||||
|
||||
Change-Id: I01e5a687587f7471e88640c43f0dfe83e5c01bd1
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2655089
|
||||
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
|
||||
Commit-Queue: Adam Rice <ricea@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/heads/master@{#848065}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2660955
|
||||
Reviewed-by: Adam Rice <ricea@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/4389@{#419}
|
||||
Cr-Original-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2690730
|
||||
Auto-Submit: Adam Rice <ricea@chromium.org>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4324@{#2191}
|
||||
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
|
||||
index e4aa818faaf0f04a8f63bbcaff9f3391166e178c..06f2d0f5678f369e58370a5ad027e8d1bde26656 100644
|
||||
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.cc
|
||||
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
|
||||
@@ -78,9 +78,7 @@ namespace blink {
|
||||
DOMWebSocket::EventQueue::EventQueue(EventTarget* target)
|
||||
: state_(kActive), target_(target) {}
|
||||
|
||||
-DOMWebSocket::EventQueue::~EventQueue() {
|
||||
- ContextDestroyed();
|
||||
-}
|
||||
+DOMWebSocket::EventQueue::~EventQueue() = default;
|
||||
|
||||
void DOMWebSocket::EventQueue::Dispatch(Event* event) {
|
||||
switch (state_) {
|
||||
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
|
||||
index 1aadd61a2a3bddf1de039537b20e429e9e844a60..61c49deeee3a87552b5cdb5d99aabb65fdf943c6 100644
|
||||
--- a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
|
||||
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
|
||||
#include "third_party/blink/renderer/platform/heap/handle.h"
|
||||
#include "third_party/blink/renderer/platform/heap/heap.h"
|
||||
+#include "third_party/blink/renderer/platform/heap/impl/thread_state.h"
|
||||
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
|
||||
@@ -920,6 +921,32 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
DOMWebSocketInvalidClosingCodeTest,
|
||||
testing::Values(0, 1, 998, 999, 1001, 2999, 5000, 9999, 65535));
|
||||
|
||||
+TEST(DOMWebSocketTest, GCWhileEventsPending) {
|
||||
+ V8TestingScope scope;
|
||||
+ {
|
||||
+ DOMWebSocketTestScope websocket_scope(scope.GetExecutionContext());
|
||||
+
|
||||
+ EXPECT_CALL(websocket_scope.Channel(),
|
||||
+ Connect(KURL("ws://example.com/"), String()))
|
||||
+ .WillOnce(Return(true));
|
||||
+ EXPECT_CALL(websocket_scope.Channel(), Disconnect());
|
||||
+
|
||||
+ auto& socket = websocket_scope.Socket();
|
||||
+
|
||||
+ // Cause events to be queued rather than fired.
|
||||
+ socket.ContextLifecycleStateChanged(mojom::FrameLifecycleState::kPaused);
|
||||
+
|
||||
+ socket.Connect("ws://example.com/", Vector<String>(), ASSERT_NO_EXCEPTION);
|
||||
+ socket.DidError();
|
||||
+ socket.DidClose(DOMWebSocket::kClosingHandshakeIncomplete, 1006, "");
|
||||
+
|
||||
+ // Stop HasPendingActivity() from keeping the object alive.
|
||||
+ socket.SetExecutionContext(nullptr);
|
||||
+ }
|
||||
+
|
||||
+ ThreadState::Current()->CollectAllGarbageForTesting();
|
||||
+}
|
||||
+
|
||||
} // namespace
|
||||
|
||||
} // namespace blink
|
||||
@@ -16,6 +16,10 @@
|
||||
"src/electron/patches/sqlite": "src/third_party/sqlite/src",
|
||||
|
||||
"src/electron/patches/icu": "src/third_party/icu",
|
||||
|
||||
"src/electron/patches/skia": "src/third_party/skia",
|
||||
|
||||
"src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib"
|
||||
"src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib",
|
||||
|
||||
"src/electron/patches/pdfium": "src/third_party/pdfium"
|
||||
}
|
||||
|
||||
@@ -47,3 +47,4 @@ fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch
|
||||
chore_expose_v8_initialization_isolate_callbacks.patch
|
||||
fix_add_safeforterminationscopes_for_sigint_interruptions.patch
|
||||
allow_preventing_preparestacktracecallback.patch
|
||||
src_inline_asynccleanuphookhandle_in_headers.patch
|
||||
|
||||
@@ -9,42 +9,46 @@ with what's exposed through BoringSSL. I plan to upstream parts of this or
|
||||
otherwise introduce shims to reduce friction.
|
||||
|
||||
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
|
||||
index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d87773dcd6 100644
|
||||
index c373533ce85241f86d64eab8a49af79f935acdeb..19932c2a0abf454ddb1848b0b2cd19e3e9b2cfe9 100644
|
||||
--- a/src/node_crypto.cc
|
||||
+++ b/src/node_crypto.cc
|
||||
@@ -5145,6 +5145,7 @@ bool DiffieHellman::Init(int primeLength, int g) {
|
||||
|
||||
@@ -5146,11 +5146,11 @@ bool DiffieHellman::Init(int primeLength, int g) {
|
||||
bool DiffieHellman::Init(const char* p, int p_len, int g) {
|
||||
dh_.reset(DH_new());
|
||||
+#if 0
|
||||
if (p_len <= 0) {
|
||||
BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
|
||||
return false;
|
||||
@@ -5153,6 +5154,7 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
|
||||
DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
|
||||
- BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
|
||||
+ OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
|
||||
return false;
|
||||
}
|
||||
if (g <= 1) {
|
||||
- DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
|
||||
+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
|
||||
return false;
|
||||
}
|
||||
+#endif
|
||||
BIGNUM* bn_p =
|
||||
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
|
||||
BIGNUM* bn_g = BN_new();
|
||||
@@ -5168,6 +5170,7 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
|
||||
|
||||
@@ -5169,18 +5169,18 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
|
||||
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
|
||||
dh_.reset(DH_new());
|
||||
+#if 0
|
||||
if (p_len <= 0) {
|
||||
BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
|
||||
return false;
|
||||
@@ -5190,6 +5193,7 @@ bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
|
||||
BN_free(bn_g);
|
||||
- BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
|
||||
+ OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
|
||||
return false;
|
||||
}
|
||||
+#endif
|
||||
return VerifyContext();
|
||||
}
|
||||
|
||||
@@ -6157,6 +6161,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
if (g_len <= 0) {
|
||||
- DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
|
||||
+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
|
||||
return false;
|
||||
}
|
||||
BIGNUM* bn_g =
|
||||
BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, nullptr);
|
||||
if (BN_is_zero(bn_g) || BN_is_one(bn_g)) {
|
||||
BN_free(bn_g);
|
||||
- DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
|
||||
+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
|
||||
return false;
|
||||
}
|
||||
BIGNUM* bn_p =
|
||||
@@ -6157,6 +6157,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
EVPKeyCtxPointer Setup() override {
|
||||
EVPKeyPointer params;
|
||||
if (prime_info_.fixed_value_) {
|
||||
@@ -52,7 +56,7 @@ index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d8
|
||||
DHPointer dh(DH_new());
|
||||
if (!dh)
|
||||
return nullptr;
|
||||
@@ -6173,6 +6178,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
@@ -6173,6 +6174,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
params = EVPKeyPointer(EVP_PKEY_new());
|
||||
CHECK(params);
|
||||
EVP_PKEY_assign_DH(params.get(), dh.release());
|
||||
@@ -60,7 +64,7 @@ index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d8
|
||||
} else {
|
||||
EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
|
||||
if (!param_ctx)
|
||||
@@ -6180,7 +6186,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
@@ -6180,7 +6182,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
|
||||
if (EVP_PKEY_paramgen_init(param_ctx.get()) <= 0)
|
||||
return nullptr;
|
||||
@@ -69,7 +73,7 @@ index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d8
|
||||
if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(param_ctx.get(),
|
||||
prime_info_.prime_size_) <= 0)
|
||||
return nullptr;
|
||||
@@ -6188,7 +6194,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
@@ -6188,7 +6190,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
|
||||
if (EVP_PKEY_CTX_set_dh_paramgen_generator(param_ctx.get(),
|
||||
generator_) <= 0)
|
||||
return nullptr;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Ang-Wanek <tylerw@axosoft.com>
|
||||
Date: Tue, 19 Jan 2021 07:39:14 -0700
|
||||
Subject: src: inline AsyncCleanupHookHandle in headers
|
||||
|
||||
Fixes: https://github.com/nodejs/node/issues/36349
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/37000
|
||||
Reviewed-By: Anna Henningsen <anna@addaleax.net>
|
||||
Reviewed-By: Rich Trott <rtrott@gmail.com>
|
||||
Reviewed-By: James M Snell <jasnell@gmail.com>
|
||||
|
||||
diff --git a/src/api/hooks.cc b/src/api/hooks.cc
|
||||
index 3b16c0350d8a8494202144407664af41d338fe04..8b6f209cc8f167173a957049dec96dbec7ccc8d1 100644
|
||||
--- a/src/api/hooks.cc
|
||||
+++ b/src/api/hooks.cc
|
||||
@@ -131,7 +131,7 @@ static void RunAsyncCleanupHook(void* arg) {
|
||||
info->fun(info->arg, FinishAsyncCleanupHook, info);
|
||||
}
|
||||
|
||||
-AsyncCleanupHookHandle AddEnvironmentCleanupHook(
|
||||
+ACHHandle* AddEnvironmentCleanupHookInternal(
|
||||
Isolate* isolate,
|
||||
AsyncCleanupHook fun,
|
||||
void* arg) {
|
||||
@@ -143,11 +143,11 @@ AsyncCleanupHookHandle AddEnvironmentCleanupHook(
|
||||
info->arg = arg;
|
||||
info->self = info;
|
||||
env->AddCleanupHook(RunAsyncCleanupHook, info.get());
|
||||
- return AsyncCleanupHookHandle(new ACHHandle { info });
|
||||
+ return new ACHHandle { info };
|
||||
}
|
||||
|
||||
-void RemoveEnvironmentCleanupHook(
|
||||
- AsyncCleanupHookHandle handle) {
|
||||
+void RemoveEnvironmentCleanupHookInternal(
|
||||
+ ACHHandle* handle) {
|
||||
if (handle->info->started) return;
|
||||
handle->info->self.reset();
|
||||
handle->info->env->RemoveCleanupHook(RunAsyncCleanupHook, handle->info.get());
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index 0917daec298229a942c1790becfbefd19d01fb8d..8e52f9e8065750b48ddb36f447e4af54f993acfa 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -747,12 +747,26 @@ struct ACHHandle;
|
||||
struct NODE_EXTERN DeleteACHHandle { void operator()(ACHHandle*) const; };
|
||||
typedef std::unique_ptr<ACHHandle, DeleteACHHandle> AsyncCleanupHookHandle;
|
||||
|
||||
-NODE_EXTERN AsyncCleanupHookHandle AddEnvironmentCleanupHook(
|
||||
+/* This function is not intended to be used externally, it exists to aid in
|
||||
+ * keeping ABI compatibility between Node and Electron. */
|
||||
+NODE_EXTERN ACHHandle* AddEnvironmentCleanupHookInternal(
|
||||
v8::Isolate* isolate,
|
||||
void (*fun)(void* arg, void (*cb)(void*), void* cbarg),
|
||||
void* arg);
|
||||
+inline AsyncCleanupHookHandle AddEnvironmentCleanupHook(
|
||||
+ v8::Isolate* isolate,
|
||||
+ void (*fun)(void* arg, void (*cb)(void*), void* cbarg),
|
||||
+ void* arg) {
|
||||
+ return AsyncCleanupHookHandle(AddEnvironmentCleanupHookInternal(isolate, fun,
|
||||
+ arg));
|
||||
+}
|
||||
|
||||
-NODE_EXTERN void RemoveEnvironmentCleanupHook(AsyncCleanupHookHandle holder);
|
||||
+/* This function is not intended to be used externally, it exists to aid in
|
||||
+ * keeping ABI compatibility between Node and Electron. */
|
||||
+NODE_EXTERN void RemoveEnvironmentCleanupHookInternal(ACHHandle* holder);
|
||||
+inline void RemoveEnvironmentCleanupHook(AsyncCleanupHookHandle holder) {
|
||||
+ RemoveEnvironmentCleanupHookInternal(holder.get());
|
||||
+}
|
||||
|
||||
/* Returns the id of the current execution context. If the return value is
|
||||
* zero then no execution has been set. This will happen if the user handles
|
||||
1
patches/pdfium/.patches
Normal file
1
patches/pdfium/.patches
Normal file
@@ -0,0 +1 @@
|
||||
m89_upgrade_openjpeg_to_2_4_0.patch
|
||||
8883
patches/pdfium/m89_upgrade_openjpeg_to_2_4_0.patch
Normal file
8883
patches/pdfium/m89_upgrade_openjpeg_to_2_4_0.patch
Normal file
File diff suppressed because it is too large
Load Diff
1
patches/skia/.patches
Normal file
1
patches/skia/.patches
Normal file
@@ -0,0 +1 @@
|
||||
cherry-pick-b0d3d3e85fa6.patch
|
||||
158
patches/skia/cherry-pick-b0d3d3e85fa6.patch
Normal file
158
patches/skia/cherry-pick-b0d3d3e85fa6.patch
Normal file
@@ -0,0 +1,158 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brian Salomon <bsalomon@google.com>
|
||||
Date: Tue, 19 Jan 2021 10:28:15 -0500
|
||||
Subject: Fix DrawEdgeAAQuad degenerate issue where 3D points don't correctly
|
||||
project to 2D points.
|
||||
|
||||
Bug: chromium:1162942
|
||||
|
||||
Change-Id: Idc1dcb725ff9eae651b84de2fe792b188dcd1c1b
|
||||
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/354671
|
||||
Commit-Queue: Brian Salomon <bsalomon@google.com>
|
||||
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
|
||||
(cherry picked from commit 7656c4b7e89b4ff00480a6d7a8a19e3fd0e5c86e)
|
||||
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/360376
|
||||
Reviewed-by: Brian Salomon <bsalomon@google.com>
|
||||
|
||||
diff --git a/gm/crbug_1162942.cpp b/gm/crbug_1162942.cpp
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e5d1f6360f3d68e1d3e353752e2e676928c93aef
|
||||
--- /dev/null
|
||||
+++ b/gm/crbug_1162942.cpp
|
||||
@@ -0,0 +1,60 @@
|
||||
+/*
|
||||
+ * Copyright 2020 Google LLC
|
||||
+ *
|
||||
+ * Use of this source code is governed by a BSD-style license that can be
|
||||
+ * found in the LICENSE file.
|
||||
+ */
|
||||
+
|
||||
+#include "gm/gm.h"
|
||||
+#include "include/core/SkCanvas.h"
|
||||
+#include "include/core/SkMatrix.h"
|
||||
+#include "include/core/SkRect.h"
|
||||
+
|
||||
+// This tests a scenario where when the 2D projection of a perspective quad is inset we degenerate
|
||||
+// the inset 2d geometry to a triangle because an inset vertex crosses the opposite edge. When we
|
||||
+// project back to 3D and try to move the original verts along the original edges so that they
|
||||
+// project to the 2D points. Whether an edge can be moved along depends on whether the adjacent edge
|
||||
+// at the vertex is AA. However, in the degenerate triangle case the 2D point may not fall along
|
||||
+// either of the edges. Thus, if we're constrained to moving along one edge and solve for X or Y the
|
||||
+// other value may go wildly away from projecting to the 2D value. The current approach is to force
|
||||
+// AA on at both edges that meet at a vertex whose inset point has been replaced by an off-edge
|
||||
+// point if either is AA originally. This gives us an additional vector to move along so that we can
|
||||
+// find a 3D point that projects to the 2D point in both X and Y.
|
||||
+DEF_SIMPLE_GM(crbug_1162942, canvas, 620, 200) {
|
||||
+ // Matrix and quad values taken from Chrome repro scenario.
|
||||
+ SkMatrix ctm = SkMatrix::MakeAll(
|
||||
+ SkBits2Float(0x3FCC7F75), SkBits2Float(0x3D5784FC), SkBits2Float(0x44C48C99),
|
||||
+ SkBits2Float(0x3F699F7F), SkBits2Float(0x3E0A0D37), SkBits2Float(0x43908518),
|
||||
+ SkBits2Float(0x3AA17423), SkBits2Float(0x3A6CCDC3), SkBits2Float(0x3F2EFEEC));
|
||||
+ ctm.postTranslate(-1500.f, -325.f);
|
||||
+
|
||||
+ SkPoint pts[4] = {{SkBits2Float(0x3F39778B), SkBits2Float(0x43FF7FFC)},
|
||||
+ {SkBits2Float(0x0), SkBits2Float(0x43FF7FFA)},
|
||||
+ {SkBits2Float(0xB83B055E), SkBits2Float(0x42500003)},
|
||||
+ {SkBits2Float(0x3F39776F), SkBits2Float(0x4250000D)}};
|
||||
+ SkRect bounds;
|
||||
+ bounds.setBounds(pts, 4);
|
||||
+
|
||||
+ canvas->clear(SK_ColorWHITE);
|
||||
+
|
||||
+ SkCanvas::QuadAAFlags flags[] = {
|
||||
+ (SkCanvas::QuadAAFlags) (SkCanvas::kTop_QuadAAFlag | SkCanvas::kLeft_QuadAAFlag ),
|
||||
+ (SkCanvas::QuadAAFlags) (SkCanvas::kBottom_QuadAAFlag | SkCanvas::kRight_QuadAAFlag),
|
||||
+ (SkCanvas::QuadAAFlags) (SkCanvas::kBottom_QuadAAFlag),
|
||||
+ (SkCanvas::QuadAAFlags) (SkCanvas::kRight_QuadAAFlag),
|
||||
+ (SkCanvas::QuadAAFlags) (SkCanvas::kRight_QuadAAFlag | SkCanvas::kLeft_QuadAAFlag),
|
||||
+ (SkCanvas::QuadAAFlags) (SkCanvas::kTop_QuadAAFlag | SkCanvas::kBottom_QuadAAFlag),
|
||||
+ };
|
||||
+
|
||||
+ SkColor color = SK_ColorGREEN;
|
||||
+ for (auto aaFlags : flags) {
|
||||
+ canvas->save();
|
||||
+ canvas->concat(ctm);
|
||||
+ canvas->experimental_DrawEdgeAAQuad(bounds, pts, aaFlags, color, SkBlendMode::kSrcOver);
|
||||
+ SkColor rgb = color & 0x00FFFFFF;
|
||||
+ color = 0xFF000000 | (rgb << 4) | (rgb >> 20);
|
||||
+ canvas->restore();
|
||||
+ canvas->translate(0, 25);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
diff --git a/gn/gm.gni b/gn/gm.gni
|
||||
index 731222e3a443ff20591fc15457aed7dc6d766451..8b0f2d414d245e3a573d86b75f264026ed21458b 100644
|
||||
--- a/gn/gm.gni
|
||||
+++ b/gn/gm.gni
|
||||
@@ -109,6 +109,7 @@ gm_sources = [
|
||||
"$_gm/crbug_1073670.cpp",
|
||||
"$_gm/crbug_1086705.cpp",
|
||||
"$_gm/crbug_1113794.cpp",
|
||||
+ "$_gm/crbug_1162942.cpp",
|
||||
"$_gm/crbug_224618.cpp",
|
||||
"$_gm/crbug_691386.cpp",
|
||||
"$_gm/crbug_788500.cpp",
|
||||
diff --git a/src/gpu/geometry/GrQuadUtils.cpp b/src/gpu/geometry/GrQuadUtils.cpp
|
||||
index 26b1415807a5218518e8eedabe1d1e0250a0f7f1..8bf8d19b84cb2ac27bebf4719d4d17d1abfc64ce 100644
|
||||
--- a/src/gpu/geometry/GrQuadUtils.cpp
|
||||
+++ b/src/gpu/geometry/GrQuadUtils.cpp
|
||||
@@ -717,7 +717,10 @@ V4f TessellationHelper::EdgeEquations::estimateCoverage(const V4f& x2d, const V4
|
||||
}
|
||||
|
||||
int TessellationHelper::EdgeEquations::computeDegenerateQuad(const V4f& signedEdgeDistances,
|
||||
- V4f* x2d, V4f* y2d) const {
|
||||
+ V4f* x2d, V4f* y2d,
|
||||
+ M4f* aaMask) const {
|
||||
+ *aaMask = signedEdgeDistances != 0.f;
|
||||
+
|
||||
// Move the edge by the signed edge adjustment.
|
||||
V4f oc = fC + signedEdgeDistances;
|
||||
|
||||
@@ -792,10 +795,19 @@ int TessellationHelper::EdgeEquations::computeDegenerateQuad(const V4f& signedEd
|
||||
if (SkScalarAbs(eDenom[0]) > kTolerance) {
|
||||
px = if_then_else(d1v0, V4f(ex[0]), px);
|
||||
py = if_then_else(d1v0, V4f(ey[0]), py);
|
||||
+ // If we replace a vertex with an intersection then it will not fall along the
|
||||
+ // edges that intersect at the original vertex. When we apply AA later to the
|
||||
+ // original points we move along the original 3d edges to move towards the 2d
|
||||
+ // points we're computing here. If we have an AA edge and a non-AA edge we
|
||||
+ // can only move along 1 edge, but now the point we're moving toward isn't
|
||||
+ // on that edge. Thus, we provide an additional degree of freedom by turning
|
||||
+ // AA on for both edges if either edge is AA.
|
||||
+ *aaMask = *aaMask | (d1v0 & skvx::shuffle<2, 0, 3, 1>(*aaMask));
|
||||
}
|
||||
if (SkScalarAbs(eDenom[1]) > kTolerance) {
|
||||
px = if_then_else(d2v0, V4f(ex[1]), px);
|
||||
py = if_then_else(d2v0, V4f(ey[1]), py);
|
||||
+ *aaMask = *aaMask | (d2v0 & skvx::shuffle<2, 0, 3, 1>(*aaMask));
|
||||
}
|
||||
|
||||
*x2d = px;
|
||||
@@ -1156,9 +1168,11 @@ int TessellationHelper::adjustDegenerateVertices(const skvx::Vec<4, float>& sign
|
||||
// handles perspective).
|
||||
V4f x2d = fEdgeVectors.fX2D;
|
||||
V4f y2d = fEdgeVectors.fY2D;
|
||||
+
|
||||
+ M4f aaMask;
|
||||
int vertexCount = this->getEdgeEquations().computeDegenerateQuad(signedEdgeDistances,
|
||||
- &x2d, &y2d);
|
||||
- vertices->moveTo(x2d, y2d, signedEdgeDistances != 0.f);
|
||||
+ &x2d, &y2d, &aaMask);
|
||||
+ vertices->moveTo(x2d, y2d, aaMask);
|
||||
return vertexCount;
|
||||
}
|
||||
}
|
||||
diff --git a/src/gpu/geometry/GrQuadUtils.h b/src/gpu/geometry/GrQuadUtils.h
|
||||
index 1288ba538d5a3fa646b1ae872254ddd51863ad17..f3e16df853cedc18707be8a96276f8e009df9e7c 100644
|
||||
--- a/src/gpu/geometry/GrQuadUtils.h
|
||||
+++ b/src/gpu/geometry/GrQuadUtils.h
|
||||
@@ -113,7 +113,8 @@ namespace GrQuadUtils {
|
||||
// small, edges are near parallel, or edges are very short/zero-length. Returns number
|
||||
// of effective vertices in the degenerate quad.
|
||||
int computeDegenerateQuad(const skvx::Vec<4, float>& signedEdgeDistances,
|
||||
- skvx::Vec<4, float>* x2d, skvx::Vec<4, float>* y2d) const;
|
||||
+ skvx::Vec<4, float>* x2d, skvx::Vec<4, float>* y2d,
|
||||
+ skvx::Vec<4, int32_t>* aaMask) const;
|
||||
};
|
||||
|
||||
struct OutsetRequest {
|
||||
@@ -12,3 +12,6 @@ perf_make_getpositioninfoslow_faster.patch
|
||||
cherry-pick-ffd6ff5a61b9.patch
|
||||
merged_deoptimizer_stricter_checks_during_deoptimization.patch
|
||||
merged_compiler_mark_jsstoreinarrayliteral_as_needing_a_frame.patch
|
||||
cherry-pick-36abafa0a316.patch
|
||||
mac_wasm_work_around_macos_11_2_code_page_decommit_failures.patch
|
||||
merged_interpreter_store_accumulator_to_callee_after_optional.patch
|
||||
|
||||
71
patches/v8/cherry-pick-36abafa0a316.patch
Normal file
71
patches/v8/cherry-pick-36abafa0a316.patch
Normal file
@@ -0,0 +1,71 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Deepti Gandluri <gdeepti@chromium.org>
|
||||
Date: Wed, 27 Jan 2021 22:19:44 -0800
|
||||
Subject: PostMessage of Memory.buffer should throw
|
||||
|
||||
PostMessage of an ArrayBuffer that is not detachable should result
|
||||
in a DataCloneError.
|
||||
|
||||
TBR=gdeepti@chromium.org
|
||||
|
||||
(cherry picked from commit dfcf1e86fac0a7b067caf8fdfc13eaf3e3f445e4)
|
||||
|
||||
Bug: chromium:1170176, chromium:961059
|
||||
No-Try: true
|
||||
No-Presubmit: true
|
||||
No-Tree-Checks: true
|
||||
Change-Id: Ife852df032841b7001375acd5e101d614c4b0771
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2674169
|
||||
Reviewed-by: Zhi An Ng <zhin@chromium.org>
|
||||
Commit-Queue: Zhi An Ng <zhin@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/8.8@{#30}
|
||||
Cr-Branched-From: 2dbcdc105b963ee2501c82139eef7e0603977ff0-refs/heads/8.8.278@{#1}
|
||||
Cr-Branched-From: 366d30c99049b3f1c673f8a93deb9f879d0fa9f0-refs/heads/master@{#71094}
|
||||
|
||||
diff --git a/src/common/message-template.h b/src/common/message-template.h
|
||||
index b7bbc6da84ca03f6e0e1d969e731b04a688c5246..dc4d7581f165915833cefc1ec5d65f1f408e3ac9 100644
|
||||
--- a/src/common/message-template.h
|
||||
+++ b/src/common/message-template.h
|
||||
@@ -575,6 +575,8 @@ namespace internal {
|
||||
T(DataCloneErrorOutOfMemory, "Data cannot be cloned, out of memory.") \
|
||||
T(DataCloneErrorDetachedArrayBuffer, \
|
||||
"An ArrayBuffer is detached and could not be cloned.") \
|
||||
+ T(DataCloneErrorNonDetachableArrayBuffer, \
|
||||
+ "ArrayBuffer is not detachable and could not be cloned.") \
|
||||
T(DataCloneErrorSharedArrayBufferTransferred, \
|
||||
"A SharedArrayBuffer could not be cloned. SharedArrayBuffer must not be " \
|
||||
"transferred.") \
|
||||
diff --git a/src/objects/value-serializer.cc b/src/objects/value-serializer.cc
|
||||
index b34076025f07ff5b4fadb8800c44acefa5480d19..d9abe45124f176d9ea7ab931a8247fbbd279c70a 100644
|
||||
--- a/src/objects/value-serializer.cc
|
||||
+++ b/src/objects/value-serializer.cc
|
||||
@@ -860,6 +860,11 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
|
||||
WriteVarint(index.FromJust());
|
||||
return ThrowIfOutOfMemory();
|
||||
}
|
||||
+ if (!array_buffer->is_detachable()) {
|
||||
+ ThrowDataCloneError(
|
||||
+ MessageTemplate::kDataCloneErrorNonDetachableArrayBuffer);
|
||||
+ return Nothing<bool>();
|
||||
+ }
|
||||
|
||||
uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer);
|
||||
if (transfer_entry) {
|
||||
diff --git a/test/mjsunit/wasm/worker-memory.js b/test/mjsunit/wasm/worker-memory.js
|
||||
index c5b99ede7e28364bbbe31165dfd8b8449a718137..bf5430f7139815c229e641eb6d40725b066035c5 100644
|
||||
--- a/test/mjsunit/wasm/worker-memory.js
|
||||
+++ b/test/mjsunit/wasm/worker-memory.js
|
||||
@@ -11,6 +11,13 @@
|
||||
assertThrows(() => worker.postMessage(memory), Error);
|
||||
})();
|
||||
|
||||
+(function TestPostMessageUnsharedMemoryBuffer() {
|
||||
+ let worker = new Worker('', {type: 'string'});
|
||||
+ let memory = new WebAssembly.Memory({initial: 1, maximum: 2});
|
||||
+
|
||||
+ assertThrows(() => worker.postMessage(memory.buffer), Error);
|
||||
+})();
|
||||
+
|
||||
// Can't use assert in a worker.
|
||||
let workerHelpers =
|
||||
`function assertTrue(value, msg) {
|
||||
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Mon, 8 Feb 2021 13:20:09 -0800
|
||||
Subject: Work around MacOS 11.2 code page decommit failures
|
||||
|
||||
MacOS 11.2 refuses to set "no access" permissions on memory that
|
||||
we previously used for JIT-compiled code. It is still unclear
|
||||
whether this is WAI on the part of the kernel. In the meantime,
|
||||
as a workaround, we use madvise(..., MADV_FREE_REUSABLE) instead
|
||||
of mprotect(..., NONE) when discarding code pages. This is inspired
|
||||
by what Chromium's gin platform does.
|
||||
|
||||
Fixed: v8:11389
|
||||
Change-Id: I866586932573b4253002436ae5eee4e0411c45fc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2679688
|
||||
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
|
||||
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#72559}
|
||||
|
||||
diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc
|
||||
index 89173b593a6ce887c0f3cea082f2d31e17f8f5db..0afaa5269bd4b61cb62532a8ffc6debcfc508dfb 100644
|
||||
--- a/src/base/platform/platform-posix.cc
|
||||
+++ b/src/base/platform/platform-posix.cc
|
||||
@@ -417,6 +417,16 @@ bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
|
||||
|
||||
int prot = GetProtectionFromMemoryPermission(access);
|
||||
int ret = mprotect(address, size, prot);
|
||||
+
|
||||
+ // MacOS 11.2 on Apple Silicon refuses to switch permissions from
|
||||
+ // rwx to none. Just use madvise instead.
|
||||
+#if defined(V8_OS_MACOSX)
|
||||
+ if (ret != 0 && access == OS::MemoryPermission::kNoAccess) {
|
||||
+ ret = madvise(address, size, MADV_FREE_REUSABLE);
|
||||
+ return ret == 0;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
|
||||
// This is advisory; ignore errors and continue execution.
|
||||
USE(DiscardSystemPages(address, size));
|
||||
@@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mythri A <mythria@chromium.org>
|
||||
Date: Thu, 11 Feb 2021 10:09:03 +0000
|
||||
Subject: Merged: [interpreter] Store accumulator to callee after optional
|
||||
chain checks
|
||||
|
||||
Revision: df98901c19ce17ca995ee6750379b0f004210d68
|
||||
|
||||
BUG=chromium:1171954
|
||||
NOTRY=true
|
||||
NOPRESUBMIT=true
|
||||
NOTREECHECKS=true
|
||||
R=rmcilroy@chromium.org
|
||||
|
||||
Change-Id: Ib62b5cecb1f0c5a31856a26d97464e1ca941bc39
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2689191
|
||||
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/8.8@{#34}
|
||||
Cr-Branched-From: 2dbcdc105b963ee2501c82139eef7e0603977ff0-refs/heads/8.8.278@{#1}
|
||||
Cr-Branched-From: 366d30c99049b3f1c673f8a93deb9f879d0fa9f0-refs/heads/master@{#71094}
|
||||
|
||||
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
|
||||
index 6b29add333e31e51eb8c63e41baf9f88300b9548..406a3966fe776731c6499ab55ee5883de77a6f8c 100644
|
||||
--- a/src/interpreter/bytecode-generator.cc
|
||||
+++ b/src/interpreter/bytecode-generator.cc
|
||||
@@ -4921,8 +4921,9 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
||||
Property* property = chain->expression()->AsProperty();
|
||||
BuildOptionalChain([&]() {
|
||||
VisitAndPushIntoRegisterList(property->obj(), &args);
|
||||
- VisitPropertyLoadForRegister(args.last_register(), property, callee);
|
||||
+ VisitPropertyLoad(args.last_register(), property);
|
||||
});
|
||||
+ builder()->StoreAccumulatorInRegister(callee);
|
||||
break;
|
||||
}
|
||||
case Call::SUPER_CALL:
|
||||
diff --git a/test/mjsunit/regress/regress-crbug-1038178.js b/test/mjsunit/regress/regress-crbug-1038178.js
|
||||
index 0362f69bcda3ad1807d70de04b31deb8eea13af6..3a84066b837d514bffa5e96c6aca060f85232e02 100644
|
||||
--- a/test/mjsunit/regress/regress-crbug-1038178.js
|
||||
+++ b/test/mjsunit/regress/regress-crbug-1038178.js
|
||||
@@ -15,7 +15,7 @@ function opt(){
|
||||
(((function(){})())?.v)()
|
||||
}
|
||||
%PrepareFunctionForOptimization(opt)
|
||||
-assertThrows(opt());
|
||||
-assertThrows(opt());
|
||||
+assertThrows(() => opt());
|
||||
+assertThrows(() => opt());
|
||||
%OptimizeFunctionOnNextCall(opt)
|
||||
-assertThrows(opt());
|
||||
+assertThrows(() => opt());
|
||||
diff --git a/test/mjsunit/regress/regress-crbug-1171954.js b/test/mjsunit/regress/regress-crbug-1171954.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..94fbb329bc47b4885d87d3e570a05e02909321c7
|
||||
--- /dev/null
|
||||
+++ b/test/mjsunit/regress/regress-crbug-1171954.js
|
||||
@@ -0,0 +1,19 @@
|
||||
+// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+// Flags: --always-opt
|
||||
+
|
||||
+// This causes the register used by the call in the later try-catch block to be
|
||||
+// used by the ToName conversion for null which causes a DCHECK fail when
|
||||
+// compiling. If register allocation changes, this test may no longer reproduce
|
||||
+// the crash but it is not easy write a proper test because it is linked to
|
||||
+// register allocation. This test should always work, so shouldn't cause any
|
||||
+// flakes.
|
||||
+try {
|
||||
+ var { [null]: __v_12, } = {};
|
||||
+} catch (e) {}
|
||||
+
|
||||
+try {
|
||||
+ assertEquals((__v_40?.o?.m)().p);
|
||||
+} catch (e) {}
|
||||
@@ -783,6 +783,25 @@ void BaseWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
|
||||
}
|
||||
}
|
||||
|
||||
void BaseWindow::SetTopBrowserView(v8::Local<v8::Value> value,
|
||||
gin_helper::Arguments* args) {
|
||||
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 get_that_view = browser_views_.find(browser_view->ID());
|
||||
if (get_that_view == browser_views_.end() ||
|
||||
(owner_window && owner_window != window_.get())) {
|
||||
args->ThrowError("Given BrowserView is not attached to the window");
|
||||
return;
|
||||
}
|
||||
|
||||
window_->SetTopBrowserView(browser_view->view());
|
||||
}
|
||||
}
|
||||
|
||||
std::string BaseWindow::GetMediaSourceId() const {
|
||||
return window_->GetDesktopMediaID().ToString();
|
||||
}
|
||||
@@ -1086,7 +1105,7 @@ void BaseWindow::ResetBrowserViews() {
|
||||
// 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 == window_.get()) {
|
||||
if (owner_window && owner_window == window_.get()) {
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
}
|
||||
@@ -1210,6 +1229,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setBrowserView", &BaseWindow::SetBrowserView)
|
||||
.SetMethod("addBrowserView", &BaseWindow::AddBrowserView)
|
||||
.SetMethod("removeBrowserView", &BaseWindow::RemoveBrowserView)
|
||||
.SetMethod("setTopBrowserView", &BaseWindow::SetTopBrowserView)
|
||||
.SetMethod("getMediaSourceId", &BaseWindow::GetMediaSourceId)
|
||||
.SetMethod("getNativeWindowHandle", &BaseWindow::GetNativeWindowHandle)
|
||||
.SetMethod("setProgressBar", &BaseWindow::SetProgressBar)
|
||||
|
||||
@@ -175,6 +175,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
||||
virtual void SetBrowserView(v8::Local<v8::Value> value);
|
||||
virtual void AddBrowserView(v8::Local<v8::Value> value);
|
||||
virtual void RemoveBrowserView(v8::Local<v8::Value> value);
|
||||
virtual void SetTopBrowserView(v8::Local<v8::Value> value,
|
||||
gin_helper::Arguments* args);
|
||||
virtual std::vector<v8::Local<v8::Value>> GetBrowserViews() const;
|
||||
virtual void ResetBrowserViews();
|
||||
std::string GetMediaSourceId() const;
|
||||
|
||||
@@ -377,6 +377,14 @@ void BrowserWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWindow::SetTopBrowserView(v8::Local<v8::Value> value,
|
||||
gin_helper::Arguments* args) {
|
||||
BaseWindow::SetTopBrowserView(value, args);
|
||||
#if defined(OS_MAC)
|
||||
UpdateDraggableRegions(draggable_regions_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWindow::ResetBrowserViews() {
|
||||
BaseWindow::ResetBrowserViews();
|
||||
#if defined(OS_MAC)
|
||||
|
||||
@@ -84,6 +84,8 @@ class BrowserWindow : public BaseWindow,
|
||||
void SetBrowserView(v8::Local<v8::Value> value) override;
|
||||
void AddBrowserView(v8::Local<v8::Value> value) override;
|
||||
void RemoveBrowserView(v8::Local<v8::Value> value) override;
|
||||
void SetTopBrowserView(v8::Local<v8::Value> value,
|
||||
gin_helper::Arguments* args) override;
|
||||
void ResetBrowserViews() override;
|
||||
void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) override;
|
||||
void OnWindowShow() override;
|
||||
|
||||
@@ -680,7 +680,8 @@ std::vector<base::FilePath::StringType> Session::GetPreloads() const {
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
v8::Local<v8::Promise> Session::LoadExtension(
|
||||
const base::FilePath& extension_path) {
|
||||
const base::FilePath& extension_path,
|
||||
gin::Arguments* args) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
gin_helper::Promise<const extensions::Extension*> promise(isolate);
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
@@ -697,10 +698,19 @@ v8::Local<v8::Promise> Session::LoadExtension(
|
||||
return handle;
|
||||
}
|
||||
|
||||
int load_flags = extensions::Extension::FOLLOW_SYMLINKS_ANYWHERE;
|
||||
gin_helper::Dictionary options;
|
||||
if (args->GetNext(&options)) {
|
||||
bool allowFileAccess = false;
|
||||
options.Get("allowFileAccess", &allowFileAccess);
|
||||
if (allowFileAccess)
|
||||
load_flags |= extensions::Extension::ALLOW_FILE_ACCESS;
|
||||
}
|
||||
|
||||
auto* extension_system = static_cast<extensions::ElectronExtensionSystem*>(
|
||||
extensions::ExtensionSystem::Get(browser_context()));
|
||||
extension_system->LoadExtension(
|
||||
extension_path,
|
||||
extension_path, load_flags,
|
||||
base::BindOnce(
|
||||
[](gin_helper::Promise<const extensions::Extension*> promise,
|
||||
const extensions::Extension* extension,
|
||||
|
||||
@@ -122,7 +122,8 @@ class Session : public gin::Wrappable<Session>,
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
v8::Local<v8::Promise> LoadExtension(const base::FilePath& extension_path);
|
||||
v8::Local<v8::Promise> LoadExtension(const base::FilePath& extension_path,
|
||||
gin::Arguments* args);
|
||||
void RemoveExtension(const std::string& extension_id);
|
||||
v8::Local<v8::Value> GetExtension(const std::string& extension_id);
|
||||
v8::Local<v8::Value> GetAllExtensions();
|
||||
|
||||
@@ -26,9 +26,11 @@
|
||||
#include "shell/browser/mac/dict_util.h"
|
||||
#include "shell/browser/mac/electron_application.h"
|
||||
#include "shell/browser/ui/cocoa/NSColor+Hex.h"
|
||||
#include "shell/common/color_util.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/process_util.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "ui/native_theme/native_theme.h"
|
||||
|
||||
namespace gin {
|
||||
@@ -384,7 +386,8 @@ std::string SystemPreferences::GetAccentColor() {
|
||||
if (@available(macOS 10.14, *))
|
||||
sysColor = [NSColor controlAccentColor];
|
||||
|
||||
return base::SysNSStringToUTF8([sysColor RGBAValue]);
|
||||
return ToRGBAHex(skia::NSSystemColorToSkColor(sysColor),
|
||||
false /* include_hash */);
|
||||
}
|
||||
|
||||
std::string SystemPreferences::GetSystemColor(gin_helper::ErrorThrower thrower,
|
||||
@@ -413,7 +416,7 @@ std::string SystemPreferences::GetSystemColor(gin_helper::ErrorThrower thrower,
|
||||
return "";
|
||||
}
|
||||
|
||||
return base::SysNSStringToUTF8([sysColor hexadecimalValue]);
|
||||
return ToRGBHex(skia::NSSystemColorToSkColor(sysColor));
|
||||
}
|
||||
|
||||
bool SystemPreferences::CanPromptTouchID() {
|
||||
@@ -571,7 +574,7 @@ std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
|
||||
}
|
||||
|
||||
if (sysColor)
|
||||
return base::SysNSStringToUTF8([sysColor hexadecimalValue]);
|
||||
return ToRGBHex(skia::NSSystemColorToSkColor(sysColor));
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -877,7 +877,7 @@ content::WebContents* WebContents::OpenURLFromTab(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!weak_this)
|
||||
if (!weak_this || !web_contents())
|
||||
return nullptr;
|
||||
|
||||
return CommonWebContentsDelegate::OpenURLFromTab(source, params);
|
||||
@@ -1091,6 +1091,19 @@ void WebContents::BeforeUnloadFired(bool proceed,
|
||||
void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
|
||||
if (!background_throttling_)
|
||||
render_view_host->SetSchedulerThrottling(false);
|
||||
|
||||
// Set the background color of RenderWidgetHostView.
|
||||
auto* const view = web_contents()->GetRenderWidgetHostView();
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
||||
if (view && web_preferences) {
|
||||
std::string color_name;
|
||||
if (web_preferences->GetPreference(options::kBackgroundColor,
|
||||
&color_name)) {
|
||||
view->SetBackgroundColor(ParseHexColor(color_name));
|
||||
} else {
|
||||
view->SetBackgroundColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::RenderFrameCreated(
|
||||
@@ -1122,7 +1135,13 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
|
||||
}
|
||||
|
||||
void WebContents::RenderProcessGone(base::TerminationStatus status) {
|
||||
auto weak_this = GetWeakPtr();
|
||||
Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
|
||||
|
||||
// User might destroy WebContents in the crashed event.
|
||||
if (!weak_this || !web_contents())
|
||||
return;
|
||||
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
gin_helper::Dictionary details = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
@@ -1190,7 +1209,7 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
|
||||
// ⚠️WARNING!⚠️
|
||||
// Emit() triggers JS which can call destroy() on |this|. It's not safe to
|
||||
// assume that |this| points to valid memory at this point.
|
||||
if (is_main_frame && weak_this)
|
||||
if (is_main_frame && weak_this && web_contents())
|
||||
Emit("did-finish-load");
|
||||
}
|
||||
|
||||
@@ -1561,6 +1580,7 @@ void WebContents::WebContentsDestroyed() {
|
||||
// also do not want any method to be used, so just mark as destroyed here.
|
||||
MarkDestroyed();
|
||||
|
||||
Observe(nullptr); // this->web_contents() will return nullptr
|
||||
Emit("destroyed");
|
||||
|
||||
// For guest view based on OOPIF, the WebContents is released by the embedder
|
||||
@@ -1707,23 +1727,8 @@ void WebContents::LoadURL(const GURL& url,
|
||||
// ⚠️WARNING!⚠️
|
||||
// LoadURLWithParams() triggers JS events which can call destroy() on |this|.
|
||||
// It's not safe to assume that |this| points to valid memory at this point.
|
||||
if (!weak_this)
|
||||
if (!weak_this || !web_contents())
|
||||
return;
|
||||
|
||||
// Set the background color of RenderWidgetHostView.
|
||||
// We have to call it right after LoadURL because the RenderViewHost is only
|
||||
// created after loading a page.
|
||||
auto* const view = weak_this->web_contents()->GetRenderWidgetHostView();
|
||||
if (view) {
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
||||
std::string color_name;
|
||||
if (web_preferences->GetPreference(options::kBackgroundColor,
|
||||
&color_name)) {
|
||||
view->SetBackgroundColor(ParseHexColor(color_name));
|
||||
} else {
|
||||
view->SetBackgroundColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::DownloadURL(const GURL& url) {
|
||||
@@ -2629,6 +2634,18 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
#if !defined(OS_MAC)
|
||||
// If the view's renderer is suspended this may fail on Windows/Linux -
|
||||
// bail if so. See CopyFromSurface in
|
||||
// content/public/browser/render_widget_host_view.h.
|
||||
auto* rfh = web_contents()->GetMainFrame();
|
||||
if (rfh &&
|
||||
rfh->GetVisibilityState() == blink::mojom::PageVisibilityState::kHidden) {
|
||||
promise.Resolve(gfx::Image());
|
||||
return handle;
|
||||
}
|
||||
#endif // defined(OS_MAC)
|
||||
|
||||
// Capture full page if user doesn't specify a |rect|.
|
||||
const gfx::Size view_size =
|
||||
rect.IsEmpty() ? view->GetViewBounds().size() : rect.size();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "shell/browser/ui/cocoa/event_dispatching_window.h"
|
||||
#include "shell/browser/web_contents_preferences.h"
|
||||
#include "ui/base/cocoa/command_dispatcher.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
|
||||
@interface NSWindow (EventDispatchingWindow)
|
||||
@@ -48,6 +49,16 @@ bool CommonWebContentsDelegate::HandleKeyboardEvent(
|
||||
// devtools windows as Widgets in order to take advantage of the
|
||||
// pre-existing redispatch code in bridged_native_widget.
|
||||
return false;
|
||||
} else if (event.os_event.window &&
|
||||
[event.os_event.window
|
||||
conformsToProtocol:@protocol(CommandDispatchingWindow)]) {
|
||||
NSObject<CommandDispatchingWindow>* window =
|
||||
static_cast<NSObject<CommandDispatchingWindow>*>(event.os_event.window);
|
||||
[[window commandDispatcher] redispatchKeyEvent:event.os_event];
|
||||
// FIXME(clavin): Not exactly sure what to return here, likely the same
|
||||
// situation as the branch above. If a future refactor removes
|
||||
// |EventDispatchingWindow| then only this branch will need to remain.
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -277,14 +277,6 @@ int ElectronBrowserMainParts::GetExitCode() {
|
||||
return exit_code_ != nullptr ? *exit_code_ : 0;
|
||||
}
|
||||
|
||||
void ElectronBrowserMainParts::RegisterDestructionCallback(
|
||||
base::OnceClosure callback) {
|
||||
// The destructors should be called in reversed order, so dependencies between
|
||||
// JavaScript objects can be correctly resolved.
|
||||
// For example WebContentsView => WebContents => Session.
|
||||
destructors_.insert(destructors_.begin(), std::move(callback));
|
||||
}
|
||||
|
||||
int ElectronBrowserMainParts::PreEarlyInitialization() {
|
||||
field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr);
|
||||
#if defined(USE_X11)
|
||||
@@ -577,18 +569,6 @@ void ElectronBrowserMainParts::PostMainMessageLoopRun() {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure destruction callbacks are called before message loop is
|
||||
// destroyed, otherwise some objects that need to be deleted on IO thread
|
||||
// won't be freed.
|
||||
// We don't use ranged for loop because iterators are getting invalided when
|
||||
// the callback runs.
|
||||
for (auto iter = destructors_.begin(); iter != destructors_.end();) {
|
||||
base::OnceClosure callback = std::move(*iter);
|
||||
if (!callback.is_null())
|
||||
std::move(callback).Run();
|
||||
++iter;
|
||||
}
|
||||
|
||||
// Destroy node platform after all destructors_ are executed, as they may
|
||||
// invoke Node/V8 APIs inside them.
|
||||
node_debugger_->Stop();
|
||||
|
||||
@@ -76,11 +76,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
|
||||
// Gets the exit code
|
||||
int GetExitCode();
|
||||
|
||||
// Register a callback that should be destroyed before JavaScript environment
|
||||
// gets destroyed.
|
||||
// Returns a closure that can be used to remove |callback| from the list.
|
||||
void RegisterDestructionCallback(base::OnceClosure callback);
|
||||
|
||||
// Returns the connection to GeolocationControl which can be
|
||||
// used to enable the location services once per client.
|
||||
device::mojom::GeolocationControl* GetGeolocationControl();
|
||||
@@ -159,9 +154,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
|
||||
std::unique_ptr<ElectronExtensionsBrowserClient> extensions_browser_client_;
|
||||
#endif
|
||||
|
||||
// List of callbacks should be executed before destroying JS env.
|
||||
std::list<base::OnceClosure> destructors_;
|
||||
|
||||
mojo::Remote<device::mojom::GeolocationControl> geolocation_control_;
|
||||
|
||||
static ElectronBrowserMainParts* self_;
|
||||
|
||||
@@ -37,15 +37,27 @@ base::FilePath CreateDownloadPath(const GURL& url,
|
||||
const std::string& content_disposition,
|
||||
const std::string& suggested_filename,
|
||||
const std::string& mime_type,
|
||||
const base::FilePath& last_saved_directory,
|
||||
const base::FilePath& default_download_path) {
|
||||
auto generated_name =
|
||||
net::GenerateFileName(url, content_disposition, std::string(),
|
||||
suggested_filename, mime_type, "download");
|
||||
|
||||
if (!base::PathExists(default_download_path))
|
||||
base::CreateDirectory(default_download_path);
|
||||
base::FilePath download_path;
|
||||
|
||||
return default_download_path.Append(generated_name);
|
||||
// If the last saved directory is a non-empty existent path, use it as the
|
||||
// default.
|
||||
if (last_saved_directory.empty() || !base::PathExists(last_saved_directory)) {
|
||||
download_path = default_download_path;
|
||||
|
||||
if (!base::PathExists(download_path))
|
||||
base::CreateDirectory(download_path);
|
||||
} else {
|
||||
// Otherwise use the global default.
|
||||
download_path = last_saved_directory;
|
||||
}
|
||||
|
||||
return download_path.Append(generated_name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -153,10 +165,7 @@ void ElectronDownloadManagerDelegate::OnDownloadSaveDialogDone(
|
||||
if (!canceled) {
|
||||
if (result.Get("filePath", &path)) {
|
||||
// Remember the last selected download directory.
|
||||
auto* browser_context = static_cast<ElectronBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
|
||||
path.DirName());
|
||||
last_saved_directory_ = path.DirName();
|
||||
|
||||
api::DownloadItem* download = api::DownloadItem::FromDownloadItem(item);
|
||||
if (download)
|
||||
@@ -222,7 +231,7 @@ bool ElectronDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
base::BindOnce(&CreateDownloadPath, download->GetURL(),
|
||||
download->GetContentDisposition(),
|
||||
download->GetSuggestedFilename(), download->GetMimeType(),
|
||||
default_download_path),
|
||||
last_saved_directory_, default_download_path),
|
||||
base::BindOnce(&ElectronDownloadManagerDelegate::OnDownloadPathGenerated,
|
||||
weak_ptr_factory_.GetWeakPtr(), download->GetId(),
|
||||
std::move(*callback)));
|
||||
|
||||
@@ -52,6 +52,8 @@ class ElectronDownloadManagerDelegate
|
||||
content::DownloadTargetCallback download_callback,
|
||||
gin_helper::Dictionary result);
|
||||
|
||||
base::FilePath last_saved_directory_;
|
||||
|
||||
content::DownloadManager* download_manager_;
|
||||
base::WeakPtrFactory<ElectronDownloadManagerDelegate> weak_ptr_factory_;
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
|
||||
namespace {
|
||||
|
||||
std::pair<scoped_refptr<const Extension>, std::string> LoadUnpacked(
|
||||
const base::FilePath& extension_dir) {
|
||||
const base::FilePath& extension_dir,
|
||||
int load_flags) {
|
||||
// app_shell only supports unpacked extensions.
|
||||
// NOTE: If you add packed extension support consider removing the flag
|
||||
// FOLLOW_SYMLINKS_ANYWHERE below. Packed extensions should not have symlinks.
|
||||
@@ -40,7 +41,6 @@ std::pair<scoped_refptr<const Extension>, std::string> LoadUnpacked(
|
||||
return std::make_pair(nullptr, err);
|
||||
}
|
||||
|
||||
int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
|
||||
std::string load_error;
|
||||
scoped_refptr<Extension> extension = file_util::LoadExtension(
|
||||
extension_dir, Manifest::COMMAND_LINE, load_flags, &load_error);
|
||||
@@ -76,10 +76,11 @@ ElectronExtensionLoader::~ElectronExtensionLoader() = default;
|
||||
|
||||
void ElectronExtensionLoader::LoadExtension(
|
||||
const base::FilePath& extension_dir,
|
||||
int load_flags,
|
||||
base::OnceCallback<void(const Extension*, const std::string&)> cb) {
|
||||
base::PostTaskAndReplyWithResult(
|
||||
GetExtensionFileTaskRunner().get(), FROM_HERE,
|
||||
base::BindOnce(&LoadUnpacked, extension_dir),
|
||||
base::BindOnce(&LoadUnpacked, extension_dir, load_flags),
|
||||
base::BindOnce(&ElectronExtensionLoader::FinishExtensionLoad,
|
||||
weak_factory_.GetWeakPtr(), std::move(cb)));
|
||||
}
|
||||
@@ -112,22 +113,22 @@ void ElectronExtensionLoader::FinishExtensionLoad(
|
||||
scoped_refptr<const Extension> extension = result.first;
|
||||
if (extension) {
|
||||
extension_registrar_.AddExtension(extension);
|
||||
}
|
||||
|
||||
// Write extension install time to ExtensionPrefs. This is required by
|
||||
// WebRequestAPI which calls extensions::ExtensionPrefs::GetInstallTime.
|
||||
//
|
||||
// Implementation for writing the pref was based on
|
||||
// PreferenceAPIBase::SetExtensionControlledPref.
|
||||
{
|
||||
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
|
||||
ExtensionPrefs::ScopedDictionaryUpdate update(
|
||||
extension_prefs, extension.get()->id(),
|
||||
extensions::pref_names::kPrefPreferences);
|
||||
auto preference = update.Create();
|
||||
const base::Time install_time = base::Time().Now();
|
||||
preference->SetString("install_time",
|
||||
base::NumberToString(install_time.ToInternalValue()));
|
||||
// Write extension install time to ExtensionPrefs. This is required by
|
||||
// WebRequestAPI which calls extensions::ExtensionPrefs::GetInstallTime.
|
||||
//
|
||||
// Implementation for writing the pref was based on
|
||||
// PreferenceAPIBase::SetExtensionControlledPref.
|
||||
{
|
||||
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
|
||||
ExtensionPrefs::ScopedDictionaryUpdate update(
|
||||
extension_prefs, extension.get()->id(),
|
||||
extensions::pref_names::kPrefPreferences);
|
||||
auto preference = update.Create();
|
||||
const base::Time install_time = base::Time().Now();
|
||||
preference->SetString(
|
||||
"install_time", base::NumberToString(install_time.ToInternalValue()));
|
||||
}
|
||||
}
|
||||
|
||||
std::move(cb).Run(extension.get(), result.second);
|
||||
@@ -175,9 +176,13 @@ void ElectronExtensionLoader::LoadExtensionForReload(
|
||||
LoadErrorBehavior load_error_behavior) {
|
||||
CHECK(!path.empty());
|
||||
|
||||
// TODO(nornagon): we should save whether file access was granted
|
||||
// when loading this extension and retain it here. As is, reloading an
|
||||
// extension will cause the file access permission to be dropped.
|
||||
int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
|
||||
base::PostTaskAndReplyWithResult(
|
||||
GetExtensionFileTaskRunner().get(), FROM_HERE,
|
||||
base::BindOnce(&LoadUnpacked, path),
|
||||
base::BindOnce(&LoadUnpacked, path, load_flags),
|
||||
base::BindOnce(&ElectronExtensionLoader::FinishExtensionReload,
|
||||
weak_factory_.GetWeakPtr(), extension_id));
|
||||
did_schedule_reload_ = true;
|
||||
|
||||
@@ -37,6 +37,7 @@ class ElectronExtensionLoader : public ExtensionRegistrar::Delegate {
|
||||
// Loads an unpacked extension from a directory synchronously. Returns the
|
||||
// extension on success, or nullptr otherwise.
|
||||
void LoadExtension(const base::FilePath& extension_dir,
|
||||
int load_flags,
|
||||
base::OnceCallback<void(const Extension* extension,
|
||||
const std::string&)> cb);
|
||||
|
||||
|
||||
@@ -56,8 +56,9 @@ ElectronExtensionSystem::~ElectronExtensionSystem() = default;
|
||||
|
||||
void ElectronExtensionSystem::LoadExtension(
|
||||
const base::FilePath& extension_dir,
|
||||
int load_flags,
|
||||
base::OnceCallback<void(const Extension*, const std::string&)> cb) {
|
||||
extension_loader_->LoadExtension(extension_dir, std::move(cb));
|
||||
extension_loader_->LoadExtension(extension_dir, load_flags, std::move(cb));
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::FinishInitialization() {
|
||||
|
||||
@@ -41,6 +41,7 @@ class ElectronExtensionSystem : public ExtensionSystem {
|
||||
// success, or nullptr otherwise.
|
||||
void LoadExtension(
|
||||
const base::FilePath& extension_dir,
|
||||
int load_flags,
|
||||
base::OnceCallback<void(const Extension*, const std::string&)> cb);
|
||||
|
||||
// Finish initialization for the shell extension system.
|
||||
|
||||
@@ -60,9 +60,11 @@ void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
|
||||
void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
|
||||
switch (state) {
|
||||
case DiscoveryState::FAILED_TO_START:
|
||||
refreshing_ = false;
|
||||
event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
|
||||
break;
|
||||
case DiscoveryState::IDLE:
|
||||
refreshing_ = false;
|
||||
if (device_map_.empty()) {
|
||||
auto event = ++num_retries_ > kMaxScanRetries
|
||||
? content::BluetoothChooserEvent::CANCELLED
|
||||
@@ -81,6 +83,14 @@ void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
|
||||
}
|
||||
break;
|
||||
case DiscoveryState::DISCOVERING:
|
||||
// The first time this state fires is due to a rescan triggering so set a
|
||||
// flag to ignore devices
|
||||
if (!refreshing_) {
|
||||
refreshing_ = true;
|
||||
} else {
|
||||
// The second time this state fires we are now safe to pick a device
|
||||
refreshing_ = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -91,6 +101,11 @@ void BluetoothChooser::AddOrUpdateDevice(const std::string& device_id,
|
||||
bool is_gatt_connected,
|
||||
bool is_paired,
|
||||
int signal_strength_level) {
|
||||
if (refreshing_) {
|
||||
// If the list of bluetooth devices is currently being generated don't fire
|
||||
// an event
|
||||
return;
|
||||
}
|
||||
bool changed = false;
|
||||
auto entry = device_map_.find(device_id);
|
||||
if (entry == device_map_.end()) {
|
||||
|
||||
@@ -41,6 +41,7 @@ class BluetoothChooser : public content::BluetoothChooser {
|
||||
api::WebContents* api_web_contents_;
|
||||
EventHandler event_handler_;
|
||||
int num_retries_ = 0;
|
||||
bool refreshing_ = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BluetoothChooser);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shell/browser/native_browser_view_mac.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#include <vector>
|
||||
|
||||
#include "shell/browser/ui/drag_util.h"
|
||||
@@ -30,6 +31,33 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
||||
|
||||
@synthesize initialLocation;
|
||||
|
||||
+ (void)load {
|
||||
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
SEL originalSelector = @selector(drawRect:);
|
||||
SEL swizzledSelector = @selector(drawDebugRect:);
|
||||
|
||||
Method originalMethod =
|
||||
class_getInstanceMethod([self class], originalSelector);
|
||||
Method swizzledMethod =
|
||||
class_getInstanceMethod([self class], swizzledSelector);
|
||||
BOOL didAddMethod =
|
||||
class_addMethod([self class], originalSelector,
|
||||
method_getImplementation(swizzledMethod),
|
||||
method_getTypeEncoding(swizzledMethod));
|
||||
|
||||
if (didAddMethod) {
|
||||
class_replaceMethod([self class], swizzledSelector,
|
||||
method_getImplementation(originalMethod),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow {
|
||||
return NO;
|
||||
}
|
||||
@@ -134,11 +162,9 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
||||
}
|
||||
|
||||
// For debugging purposes only.
|
||||
- (void)drawRect:(NSRect)aRect {
|
||||
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
||||
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
|
||||
NSRectFill([self bounds]);
|
||||
}
|
||||
- (void)drawDebugRect:(NSRect)aRect {
|
||||
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
|
||||
NSRectFill([self bounds]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -148,16 +174,41 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
||||
|
||||
@implementation ExcludeDragRegionView
|
||||
|
||||
+ (void)load {
|
||||
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
SEL originalSelector = @selector(drawRect:);
|
||||
SEL swizzledSelector = @selector(drawDebugRect:);
|
||||
|
||||
Method originalMethod =
|
||||
class_getInstanceMethod([self class], originalSelector);
|
||||
Method swizzledMethod =
|
||||
class_getInstanceMethod([self class], swizzledSelector);
|
||||
BOOL didAddMethod =
|
||||
class_addMethod([self class], originalSelector,
|
||||
method_getImplementation(swizzledMethod),
|
||||
method_getTypeEncoding(swizzledMethod));
|
||||
|
||||
if (didAddMethod) {
|
||||
class_replaceMethod([self class], swizzledSelector,
|
||||
method_getImplementation(originalMethod),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// For debugging purposes only.
|
||||
- (void)drawRect:(NSRect)aRect {
|
||||
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
||||
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
|
||||
NSRectFill([self bounds]);
|
||||
}
|
||||
- (void)drawDebugRect:(NSRect)aRect {
|
||||
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
|
||||
NSRectFill([self bounds]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -248,7 +299,6 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
|
||||
NSView* web_view = GetWebContents()->GetNativeView().GetNativeNSView();
|
||||
NSView* inspectable_view = iwc_view->GetNativeView().GetNativeNSView();
|
||||
NSView* window_content_view = inspectable_view.superview;
|
||||
const auto window_content_view_height = NSHeight(window_content_view.bounds);
|
||||
|
||||
// Remove all DragRegionViews that were added last time. Note that we need
|
||||
// to copy the `subviews` array to avoid mutation during iteration.
|
||||
@@ -264,14 +314,15 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
|
||||
[[DragRegionView alloc] initWithFrame:web_view.bounds]);
|
||||
[web_view addSubview:drag_region_view];
|
||||
|
||||
// Then, on top of that, add "exclusion zones"
|
||||
// Then, on top of that, add "exclusion zones".
|
||||
auto const offset = GetBounds().OffsetFromOrigin();
|
||||
const auto window_content_view_height = NSHeight(window_content_view.bounds);
|
||||
for (const auto& rect : drag_exclude_rects) {
|
||||
const auto window_content_view_exclude_rect =
|
||||
NSMakeRect(rect.x(), window_content_view_height - rect.bottom(),
|
||||
rect.width(), rect.height());
|
||||
const auto x = rect.x() + offset.x();
|
||||
const auto y = window_content_view_height - rect.bottom() + offset.y();
|
||||
const auto exclude_rect = NSMakeRect(x, y, rect.width(), rect.height());
|
||||
const auto drag_region_view_exclude_rect =
|
||||
[window_content_view convertRect:window_content_view_exclude_rect
|
||||
toView:drag_region_view];
|
||||
[window_content_view convertRect:exclude_rect toView:drag_region_view];
|
||||
|
||||
base::scoped_nsobject<NSView> exclude_drag_region_view(
|
||||
[[ExcludeDragRegionView alloc]
|
||||
|
||||
@@ -165,6 +165,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual void SetParentWindow(NativeWindow* parent);
|
||||
virtual void AddBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual void RemoveBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual void SetTopBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual content::DesktopMediaID GetDesktopMediaID() const = 0;
|
||||
virtual gfx::NativeView GetNativeView() const = 0;
|
||||
virtual gfx::NativeWindow GetNativeWindow() const = 0;
|
||||
|
||||
@@ -113,6 +113,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
|
||||
void SetFocusable(bool focusable) override;
|
||||
void AddBrowserView(NativeBrowserView* browser_view) override;
|
||||
void RemoveBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetTopBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
content::DesktopMediaID GetDesktopMediaID() const override;
|
||||
gfx::NativeView GetNativeView() const override;
|
||||
|
||||
@@ -1202,8 +1202,10 @@ void NativeWindowMac::SetBackgroundColor(SkColor color) {
|
||||
}
|
||||
|
||||
SkColor NativeWindowMac::GetBackgroundColor() {
|
||||
return skia::CGColorRefToSkColor(
|
||||
[[[window_ contentView] layer] backgroundColor]);
|
||||
CGColorRef color = [[[window_ contentView] layer] backgroundColor];
|
||||
if (!color)
|
||||
return SK_ColorTRANSPARENT;
|
||||
return skia::CGColorRefToSkColor(color);
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetHasShadow(bool has_shadow) {
|
||||
@@ -1301,6 +1303,30 @@ void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
|
||||
[CATransaction commit];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetTopBrowserView(NativeBrowserView* view) {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
|
||||
if (!view) {
|
||||
[CATransaction commit];
|
||||
return;
|
||||
}
|
||||
|
||||
remove_browser_view(view);
|
||||
add_browser_view(view);
|
||||
if (view->GetInspectableWebContentsView()) {
|
||||
auto* native_view = view->GetInspectableWebContentsView()
|
||||
->GetNativeView()
|
||||
.GetNativeNSView();
|
||||
[[window_ contentView] addSubview:native_view
|
||||
positioned:NSWindowAbove
|
||||
relativeTo:nil];
|
||||
native_view.hidden = NO;
|
||||
}
|
||||
|
||||
[CATransaction commit];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
|
||||
InternalSetParentWindow(parent, IsVisible());
|
||||
}
|
||||
|
||||
@@ -915,7 +915,10 @@ bool NativeWindowViews::IsKiosk() {
|
||||
}
|
||||
|
||||
SkColor NativeWindowViews::GetBackgroundColor() {
|
||||
return root_view_->background()->get_color();
|
||||
auto* background = root_view_->background();
|
||||
if (!background)
|
||||
return SK_ColorTRANSPARENT;
|
||||
return background->get_color();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetBackgroundColor(SkColor background_color) {
|
||||
@@ -1104,6 +1107,22 @@ void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
|
||||
remove_browser_view(view);
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetTopBrowserView(NativeBrowserView* view) {
|
||||
if (!content_view())
|
||||
return;
|
||||
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_browser_view(view);
|
||||
add_browser_view(view);
|
||||
|
||||
if (view->GetInspectableWebContentsView())
|
||||
content_view()->ReorderChildView(
|
||||
view->GetInspectableWebContentsView()->GetView(), -1);
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
|
||||
NativeWindow::SetParentWindow(parent);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user