mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa768aa749 | ||
|
|
f7e22ed743 | ||
|
|
437bf7d1fd | ||
|
|
d0b2a4e48f | ||
|
|
192295697e | ||
|
|
e47bdb67f8 | ||
|
|
25dee92c57 | ||
|
|
053031e96c | ||
|
|
1e64527ec3 | ||
|
|
1645aece38 | ||
|
|
1f66b20392 | ||
|
|
8df8cad3a0 | ||
|
|
6d111ddbe3 | ||
|
|
2c9f2e81e8 | ||
|
|
14c6c397d0 | ||
|
|
3ce4c24c4b | ||
|
|
97018c7be1 | ||
|
|
42c90f3eeb | ||
|
|
bb2f62f95f | ||
|
|
b60166eddc | ||
|
|
1b762ef8a1 | ||
|
|
3815e90434 | ||
|
|
65fba6f51b | ||
|
|
5e6d99a6af | ||
|
|
bfb3b6d9a4 | ||
|
|
45caec231c | ||
|
|
7254da337b | ||
|
|
612775dad5 | ||
|
|
66845e7aa3 | ||
|
|
31380eeb87 | ||
|
|
0f4fce9448 | ||
|
|
f933ce3755 | ||
|
|
4845dd7a71 | ||
|
|
bd0e65292f | ||
|
|
22bd19ddc1 | ||
|
|
580c04e69f | ||
|
|
99a78dc37c | ||
|
|
18b2a4e957 | ||
|
|
a21fa57cae | ||
|
|
54fe508125 | ||
|
|
a662023207 |
@@ -68,9 +68,11 @@ for:
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
Write-warning "Skipping build for doc only change"
|
||||
Exit-AppveyorBuild
|
||||
} else {
|
||||
$global:LASTEXITCODE = 0
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- ps: Write-Host "Building $env:GN_CONFIG build"
|
||||
- git config --global core.longpaths true
|
||||
@@ -222,9 +224,11 @@ for:
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
Write-warning "Skipping build for doc only change"
|
||||
Exit-AppveyorBuild
|
||||
} else {
|
||||
$global:LASTEXITCODE = 0
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- mkdir out\Default
|
||||
- cd ..
|
||||
|
||||
12
appveyor.yml
12
appveyor.yml
@@ -66,9 +66,11 @@ for:
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
Write-warning "Skipping build for doc only change"
|
||||
Exit-AppveyorBuild
|
||||
} else {
|
||||
$global:LASTEXITCODE = 0
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- ps: Write-Host "Building $env:GN_CONFIG build"
|
||||
- git config --global core.longpaths true
|
||||
@@ -218,9 +220,11 @@ for:
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
Write-warning "Skipping build for doc only change"
|
||||
Exit-AppveyorBuild
|
||||
} else {
|
||||
$global:LASTEXITCODE = 0
|
||||
}
|
||||
$global:LASTEXITCODE = 0
|
||||
- cd ..
|
||||
- mkdir out\Default
|
||||
- cd ..
|
||||
|
||||
@@ -960,7 +960,7 @@ app.setJumpList([
|
||||
title: 'Tool A',
|
||||
program: process.execPath,
|
||||
args: '--run-tool-a',
|
||||
icon: process.execPath,
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0,
|
||||
description: 'Runs Tool A'
|
||||
},
|
||||
@@ -969,7 +969,7 @@ app.setJumpList([
|
||||
title: 'Tool B',
|
||||
program: process.execPath,
|
||||
args: '--run-tool-b',
|
||||
icon: process.execPath,
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0,
|
||||
description: 'Runs Tool B'
|
||||
}
|
||||
@@ -1407,8 +1407,8 @@ const fs = require('fs')
|
||||
let filepath
|
||||
let bookmark
|
||||
|
||||
dialog.showOpenDialog(null, { securityScopedBookmarks: true }, (filepaths, bookmarks) => {
|
||||
filepath = filepaths[0]
|
||||
dialog.showOpenDialog(null, { securityScopedBookmarks: true }).then(({ filePaths, bookmarks }) => {
|
||||
filepath = filePaths[0]
|
||||
bookmark = bookmarks[0]
|
||||
fs.readFileSync(filepath)
|
||||
})
|
||||
|
||||
@@ -104,6 +104,7 @@ window, you have to set both `parent` and `modal` options:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
|
||||
const top = new BrowserWindow()
|
||||
const child = new BrowserWindow({ parent: top, modal: true, show: false })
|
||||
child.loadURL('https://github.com')
|
||||
child.once('ready-to-show', () => {
|
||||
@@ -887,7 +888,7 @@ On Linux the setter is a no-op, although the getter returns `true`.
|
||||
|
||||
A `boolean` property that determines whether the window is excluded from the application’s Windows menu. `false` by default.
|
||||
|
||||
```js
|
||||
```js @ts-expect-error=[11]
|
||||
const win = new BrowserWindow({ height: 600, width: 600 })
|
||||
|
||||
const template = [
|
||||
@@ -1490,6 +1491,9 @@ Node's [`url.format`](https://nodejs.org/api/url.html#url_url_format_urlobject)
|
||||
method:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
|
||||
const url = require('url').format({
|
||||
protocol: 'file',
|
||||
slashes: true,
|
||||
@@ -1503,6 +1507,9 @@ You can load a URL using a `POST` request with URL-encoded data by doing
|
||||
the following:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.loadURL('http://localhost:8000/post', {
|
||||
postData: [{
|
||||
type: 'rawData',
|
||||
|
||||
@@ -95,7 +95,7 @@ The `callback` function is expected to be called back with user credentials:
|
||||
* `username` string
|
||||
* `password` string
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={request:Electron.ClientRequest}
|
||||
request.on('login', (authInfo, callback) => {
|
||||
callback('username', 'password')
|
||||
})
|
||||
@@ -104,7 +104,7 @@ request.on('login', (authInfo, callback) => {
|
||||
Providing empty credentials will cancel the request and report an authentication
|
||||
error on the response object:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={request:Electron.ClientRequest}
|
||||
request.on('response', (response) => {
|
||||
console.log(`STATUS: ${response.statusCode}`)
|
||||
response.on('error', (error) => {
|
||||
|
||||
@@ -148,10 +148,7 @@ clipboard.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeBookmark({
|
||||
text: 'https://electronjs.org',
|
||||
bookmark: 'Electron Homepage'
|
||||
})
|
||||
clipboard.writeBookmark('Electron Homepage', 'https://electronjs.org')
|
||||
```
|
||||
|
||||
### `clipboard.readFindText()` _macOS_
|
||||
@@ -226,7 +223,7 @@ clipboard.writeBuffer('public/utf8-plain-text', buffer)
|
||||
|
||||
const ret = clipboard.readBuffer('public/utf8-plain-text')
|
||||
|
||||
console.log(buffer.equals(out))
|
||||
console.log(buffer.equals(ret))
|
||||
// true
|
||||
```
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ contextBridge.exposeInMainWorld(
|
||||
)
|
||||
```
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
// Renderer (Main World)
|
||||
|
||||
window.electron.doThing()
|
||||
@@ -104,7 +104,7 @@ contextBridge.exposeInIsolatedWorld(
|
||||
)
|
||||
```
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
// Renderer (In isolated world id1004)
|
||||
|
||||
window.electron.doThing()
|
||||
|
||||
@@ -10,7 +10,9 @@ title is `Electron`:
|
||||
|
||||
```javascript
|
||||
// In the main process.
|
||||
const { desktopCapturer } = require('electron')
|
||||
const { BrowserWindow, desktopCapturer } = require('electron')
|
||||
|
||||
const mainWindow = new BrowserWindow()
|
||||
|
||||
desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
|
||||
for (const source of sources) {
|
||||
@@ -22,7 +24,7 @@ desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources =
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
// In the preload script.
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ and a directory selector, so if you set `properties` to
|
||||
`['openFile', 'openDirectory']` on these platforms, a directory selector will be
|
||||
shown.
|
||||
|
||||
```js
|
||||
```js @ts-type={mainWindow:Electron.BrowserWindow}
|
||||
dialog.showOpenDialogSync(mainWindow, {
|
||||
properties: ['openFile', 'openDirectory']
|
||||
})
|
||||
@@ -139,7 +139,7 @@ and a directory selector, so if you set `properties` to
|
||||
`['openFile', 'openDirectory']` on these platforms, a directory selector will be
|
||||
shown.
|
||||
|
||||
```js
|
||||
```js @ts-type={mainWindow:Electron.BrowserWindow}
|
||||
dialog.showOpenDialog(mainWindow, {
|
||||
properties: ['openFile', 'openDirectory']
|
||||
}).then(result => {
|
||||
|
||||
@@ -89,7 +89,7 @@ tuples. So, the even-numbered offsets are key values, and the odd-numbered
|
||||
offsets are the associated values. Header names are not lowercased, and
|
||||
duplicates are not merged.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={response:Electron.IncomingMessage}
|
||||
// Prints something like:
|
||||
//
|
||||
// [ 'user-agent',
|
||||
@@ -100,5 +100,5 @@ duplicates are not merged.
|
||||
// '127.0.0.1:8000',
|
||||
// 'ACCEPT',
|
||||
// '*/*' ]
|
||||
console.log(request.rawHeaders)
|
||||
console.log(response.rawHeaders)
|
||||
```
|
||||
|
||||
@@ -83,14 +83,14 @@ If `listener` returns a Promise, the eventual result of the promise will be
|
||||
returned as a reply to the remote caller. Otherwise, the return value of the
|
||||
listener will be used as the value of the reply.
|
||||
|
||||
```js title='Main Process'
|
||||
```js title='Main Process' @ts-type={somePromise:(...args:unknown[])=>Promise<unknown>}
|
||||
ipcMain.handle('my-invokable-ipc', async (event, ...args) => {
|
||||
const result = await somePromise(...args)
|
||||
return result
|
||||
})
|
||||
```
|
||||
|
||||
```js title='Renderer Process'
|
||||
```js title='Renderer Process' @ts-type={arg1:unknown} @ts-type={arg2:unknown}
|
||||
async () => {
|
||||
const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2)
|
||||
// ...
|
||||
|
||||
@@ -101,7 +101,7 @@ The main process should listen for `channel` with
|
||||
|
||||
For example:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={someArgument:unknown} @ts-type={doSomeWork:(arg:unknown)=>Promise<unknown>}
|
||||
// Renderer process
|
||||
ipcRenderer.invoke('some-name', someArgument).then((result) => {
|
||||
// ...
|
||||
|
||||
@@ -147,7 +147,7 @@ can have a submenu.
|
||||
|
||||
An example of creating the application menu with the simple template API:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[107]
|
||||
const { app, Menu } = require('electron')
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
@@ -267,7 +267,7 @@ menu on behalf of the renderer.
|
||||
|
||||
Below is an example of showing a menu when the user right clicks the page:
|
||||
|
||||
```js
|
||||
```js @ts-expect-error=[21]
|
||||
// renderer
|
||||
window.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
@@ -289,7 +289,7 @@ ipcMain.on('show-context-menu', (event) => {
|
||||
{ label: 'Menu Item 2', type: 'checkbox', checked: true }
|
||||
]
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
menu.popup(BrowserWindow.fromWebContents(event.sender))
|
||||
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) })
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ Example:
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const { MessageChannelMain } = require('electron')
|
||||
const { BrowserWindow, MessageChannelMain } = require('electron')
|
||||
const w = new BrowserWindow()
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
w.webContents.postMessage('port', null, [port2])
|
||||
port1.postMessage({ some: 'message' })
|
||||
@@ -26,9 +27,9 @@ port1.postMessage({ some: 'message' })
|
||||
const { ipcRenderer } = require('electron')
|
||||
ipcRenderer.on('port', (e) => {
|
||||
// e.ports is a list of ports sent along with this message
|
||||
e.ports[0].on('message', (messageEvent) => {
|
||||
e.ports[0].onmessage = (messageEvent) => {
|
||||
console.log(messageEvent.data)
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
```javascript
|
||||
const { netLog } = require('electron')
|
||||
const { app, netLog } = require('electron')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
await netLog.startLogging('/path/to/net-log')
|
||||
|
||||
@@ -36,7 +36,7 @@ To have your custom protocol work in combination with a custom session, you need
|
||||
to register it to that session explicitly.
|
||||
|
||||
```javascript
|
||||
const { session, app, protocol } = require('electron')
|
||||
const { app, BrowserWindow, net, protocol, session } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
@@ -48,7 +48,7 @@ app.whenReady().then(() => {
|
||||
callback({ path: path.normalize(path.join(__dirname, url)) })
|
||||
})
|
||||
|
||||
mainWindow = new BrowserWindow({ webPreferences: { partition } })
|
||||
const mainWindow = new BrowserWindow({ webPreferences: { partition } })
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ Emitted when Electron is about to download `item` in `webContents`.
|
||||
Calling `event.preventDefault()` will cancel the download and `item` will not be
|
||||
available from next tick of the process.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[4]
|
||||
const { session } = require('electron')
|
||||
session.defaultSession.on('will-download', (event, item, webContents) => {
|
||||
event.preventDefault()
|
||||
@@ -198,7 +198,7 @@ cancel the request. Additionally, permissioning on `navigator.hid` can
|
||||
be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler)
|
||||
and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)}
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
@@ -237,7 +237,7 @@ app.whenReady().then(() => {
|
||||
win.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
return device.vendorId === 9025 && device.productId === 67
|
||||
})
|
||||
callback(selectedDevice?.deviceId)
|
||||
})
|
||||
@@ -304,7 +304,7 @@ cancel the request. Additionally, permissioning on `navigator.serial` can
|
||||
be managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler)
|
||||
with the `serial` permission.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)}
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
@@ -447,7 +447,7 @@ cancel the request. Additionally, permissioning on `navigator.usb` can
|
||||
be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler)
|
||||
and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} @ts-type={updateGrantedDevices:(devices:Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)=>void}
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
@@ -486,7 +486,7 @@ app.whenReady().then(() => {
|
||||
win.webContents.session.on('select-usb-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
return device.vendorId === 9025 && device.productId === 67
|
||||
})
|
||||
if (selectedDevice) {
|
||||
// Optionally, add this to the persisted devices (updateGrantedDevices needs to be implemented by developer to persist permissions)
|
||||
@@ -741,15 +741,17 @@ Sets download saving directory. By default, the download directory will be the
|
||||
Emulates network with the given configuration for the `session`.
|
||||
|
||||
```javascript
|
||||
const win = new BrowserWindow()
|
||||
|
||||
// To emulate a GPRS connection with 50kbps throughput and 500 ms latency.
|
||||
window.webContents.session.enableNetworkEmulation({
|
||||
win.webContents.session.enableNetworkEmulation({
|
||||
latency: 500,
|
||||
downloadThroughput: 6400,
|
||||
uploadThroughput: 6400
|
||||
})
|
||||
|
||||
// To emulate a network outage.
|
||||
window.webContents.session.enableNetworkEmulation({ offline: true })
|
||||
win.webContents.session.enableNetworkEmulation({ offline: true })
|
||||
```
|
||||
|
||||
#### `ses.preconnect(options)`
|
||||
@@ -967,7 +969,7 @@ Additionally, the default behavior of Electron is to store granted device permis
|
||||
If longer term storage is needed, a developer can store granted device
|
||||
permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)}
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
@@ -1015,9 +1017,58 @@ app.whenReady().then(() => {
|
||||
win.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
return device.vendorId === 9025 && device.productId === 67
|
||||
})
|
||||
callback(selectedDevice?.deviceId)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### `ses.setUSBProtectedClassesHandler(handler)`
|
||||
|
||||
* `handler` Function\<string[]> | null
|
||||
* `details` Object
|
||||
* `protectedClasses` string[] - The current list of protected USB classes. Possible class values are:
|
||||
* `audio`
|
||||
* `audio-video`
|
||||
* `hid`
|
||||
* `mass-storage`
|
||||
* `smart-card`
|
||||
* `video`
|
||||
* `wireless`
|
||||
|
||||
Sets the handler which can be used to override which [USB classes are protected](https://wicg.github.io/webusb/#usbinterface-interface).
|
||||
The return value for the handler is a string array of USB classes which should be considered protected (eg not available in the renderer). Valid values for the array are:
|
||||
|
||||
* `audio`
|
||||
* `audio-video`
|
||||
* `hid`
|
||||
* `mass-storage`
|
||||
* `smart-card`
|
||||
* `video`
|
||||
* `wireless`
|
||||
|
||||
Returning an empty string array from the handler will allow all USB classes; returning the passed in array will maintain the default list of protected USB classes (this is also the default behavior if a handler is not defined).
|
||||
To clear the handler, call `setUSBProtectedClassesHandler(null)`.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow()
|
||||
|
||||
win.webContents.session.setUSBProtectedClassesHandler((details) => {
|
||||
// Allow all classes:
|
||||
// return []
|
||||
// Keep the current set of protected classes:
|
||||
// return details.protectedClasses
|
||||
// Selectively remove classes:
|
||||
return details.protectedClasses.filter((usbClass) => {
|
||||
// Exclude classes except for audio classes
|
||||
return usbClass.indexOf('audio') === -1
|
||||
})
|
||||
callback(selectedPort?.deviceId)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -1056,32 +1107,32 @@ macOS does not require a handler because macOS handles the pairing
|
||||
automatically. To clear the handler, call `setBluetoothPairingHandler(null)`.
|
||||
|
||||
```javascript
|
||||
|
||||
const { app, BrowserWindow, ipcMain, session } = require('electron')
|
||||
|
||||
let bluetoothPinCallback = null
|
||||
const { app, BrowserWindow, session } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
let bluetoothPinCallback = null
|
||||
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => {
|
||||
bluetoothPinCallback = callback
|
||||
// Send a IPC message to the renderer to prompt the user to confirm the pairing.
|
||||
// Note that this will require logic in the renderer to handle this message and
|
||||
// display a prompt to the user.
|
||||
mainWindow.webContents.send('bluetooth-pairing-request', details)
|
||||
})
|
||||
|
||||
// Listen for an IPC message from the renderer to get the response for the Bluetooth pairing.
|
||||
mainWindow.webContents.ipc.on('bluetooth-pairing-response', (event, response) => {
|
||||
bluetoothPinCallback(response)
|
||||
})
|
||||
}
|
||||
|
||||
// Listen for an IPC message from the renderer to get the response for the Bluetooth pairing.
|
||||
ipcMain.on('bluetooth-pairing-response', (event, response) => {
|
||||
bluetoothPinCallback(response)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => {
|
||||
bluetoothPinCallback = callback
|
||||
// Send a IPC message to the renderer to prompt the user to confirm the pairing.
|
||||
// Note that this will require logic in the renderer to handle this message and
|
||||
// display a prompt to the user.
|
||||
mainWindow.webContents.send('bluetooth-pairing-request', details)
|
||||
})
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
* `portId` string - Unique identifier for the port.
|
||||
* `portName` string - Name of the port.
|
||||
* `displayName` string - A string suitable for display to the user for describing this device.
|
||||
* `vendorId` string - Optional USB vendor ID.
|
||||
* `productId` string - Optional USB product ID.
|
||||
* `serialNumber` string - The USB device serial number.
|
||||
* `usbDriverName` string (optional) - Represents a single serial port on macOS can be enumerated by multiple drivers.
|
||||
* `deviceInstanceId` string (optional) - A stable identifier on Windows that can be used for device permissions.
|
||||
* `displayName` string (optional) - A string suitable for display to the user for describing this device.
|
||||
* `vendorId` string (optional) - The USB vendor ID.
|
||||
* `productId` string (optional) - The USB product ID.
|
||||
* `serialNumber` string (optional) - The USB device serial number.
|
||||
* `usbDriverName` string (optional) _macOS_ - Represents a single serial port on macOS can be enumerated by multiple drivers.
|
||||
* `deviceInstanceId` string (optional) _Windows_ - A stable identifier on Windows that can be used for device permissions.
|
||||
|
||||
@@ -87,12 +87,12 @@ const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar
|
||||
let spinning = false
|
||||
|
||||
// Reel labels
|
||||
const reel1 = new TouchBarLabel()
|
||||
const reel2 = new TouchBarLabel()
|
||||
const reel3 = new TouchBarLabel()
|
||||
const reel1 = new TouchBarLabel({ label: '' })
|
||||
const reel2 = new TouchBarLabel({ label: '' })
|
||||
const reel3 = new TouchBarLabel({ label: '' })
|
||||
|
||||
// Spin result label
|
||||
const result = new TouchBarLabel()
|
||||
const result = new TouchBarLabel({ label: '' })
|
||||
|
||||
// Spin button
|
||||
const spin = new TouchBarButton({
|
||||
|
||||
@@ -68,7 +68,7 @@ async function lookupTargetId (browserWindow) {
|
||||
await wc.debugger.attach('1.3')
|
||||
const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo')
|
||||
const { targetId } = targetInfo
|
||||
const targetWebContents = await webContents.fromDevToolsTargetId(targetId)
|
||||
const targetWebContents = await wc.fromDevToolsTargetId(targetId)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -906,9 +906,9 @@ e.g. the `http://` or `file://`. If the load should bypass http cache then
|
||||
use the `pragma` header to achieve it.
|
||||
|
||||
```javascript
|
||||
const { webContents } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
const options = { extraHeaders: 'pragma: no-cache\n' }
|
||||
webContents.loadURL('https://github.com', options)
|
||||
win.webContents.loadURL('https://github.com', options)
|
||||
```
|
||||
|
||||
#### `contents.loadFile(filePath[, options])`
|
||||
@@ -938,6 +938,7 @@ an app structure like this:
|
||||
Would require code like this
|
||||
|
||||
```js
|
||||
const win = new BrowserWindow()
|
||||
win.loadFile('src/index.html')
|
||||
```
|
||||
|
||||
@@ -1074,7 +1075,9 @@ when this process is unstable or unusable, for instance in order to recover
|
||||
from the `unresponsive` event.
|
||||
|
||||
```js
|
||||
contents.on('unresponsive', async () => {
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.webContents.on('unresponsive', async () => {
|
||||
const { response } = await dialog.showMessageBox({
|
||||
message: 'App X has become unresponsive',
|
||||
title: 'Do you want to try forcefully reloading the app?',
|
||||
@@ -1082,8 +1085,8 @@ contents.on('unresponsive', async () => {
|
||||
cancelId: 1
|
||||
})
|
||||
if (response === 0) {
|
||||
contents.forcefullyCrashRenderer()
|
||||
contents.reload()
|
||||
win.webContents.forcefullyCrashRenderer()
|
||||
win.webContents.reload()
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1110,8 +1113,9 @@ Injects CSS into the current web page and returns a unique key for the inserted
|
||||
stylesheet.
|
||||
|
||||
```js
|
||||
contents.on('did-finish-load', () => {
|
||||
contents.insertCSS('html, body { background-color: #f00; }')
|
||||
const win = new BrowserWindow()
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
win.webContents.insertCSS('html, body { background-color: #f00; }')
|
||||
})
|
||||
```
|
||||
|
||||
@@ -1125,9 +1129,11 @@ Removes the inserted CSS from the current web page. The stylesheet is identified
|
||||
by its key, which is returned from `contents.insertCSS(css)`.
|
||||
|
||||
```js
|
||||
contents.on('did-finish-load', async () => {
|
||||
const key = await contents.insertCSS('html, body { background-color: #f00; }')
|
||||
contents.removeInsertedCSS(key)
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.webContents.on('did-finish-load', async () => {
|
||||
const key = await win.webContents.insertCSS('html, body { background-color: #f00; }')
|
||||
win.webContents.removeInsertedCSS(key)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -1148,7 +1154,9 @@ this limitation.
|
||||
Code execution will be suspended until web page stop loading.
|
||||
|
||||
```js
|
||||
contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true)
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.webContents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true)
|
||||
.then((result) => {
|
||||
console.log(result) // Will be the JSON object from the fetch call
|
||||
})
|
||||
@@ -1259,7 +1267,8 @@ Sets the maximum and minimum pinch-to-zoom level.
|
||||
> **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, call:
|
||||
>
|
||||
> ```js
|
||||
> contents.setVisualZoomLevelLimits(1, 3)
|
||||
> const win = new BrowserWindow()
|
||||
> win.webContents.setVisualZoomLevelLimits(1, 3)
|
||||
> ```
|
||||
|
||||
#### `contents.undo()`
|
||||
@@ -1350,12 +1359,12 @@ can be obtained by subscribing to [`found-in-page`](web-contents.md#event-found-
|
||||
Stops any `findInPage` request for the `webContents` with the provided `action`.
|
||||
|
||||
```javascript
|
||||
const { webContents } = require('electron')
|
||||
webContents.on('found-in-page', (event, result) => {
|
||||
if (result.finalUpdate) webContents.stopFindInPage('clearSelection')
|
||||
const win = new BrowserWindow()
|
||||
win.webContents.on('found-in-page', (event, result) => {
|
||||
if (result.finalUpdate) win.webContents.stopFindInPage('clearSelection')
|
||||
})
|
||||
|
||||
const requestId = webContents.findInPage('api')
|
||||
const requestId = win.webContents.findInPage('api')
|
||||
console.log(requestId)
|
||||
```
|
||||
|
||||
@@ -1435,6 +1444,7 @@ Use `page-break-before: always;` CSS style to force to print to a new page.
|
||||
Example usage:
|
||||
|
||||
```js
|
||||
const win = new BrowserWindow()
|
||||
const options = {
|
||||
silent: true,
|
||||
deviceName: 'My-Printer',
|
||||
@@ -1731,8 +1741,9 @@ For example:
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const win = new BrowserWindow()
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
webContents.postMessage('port', { message: 'hello' }, [port1])
|
||||
win.webContents.postMessage('port', { message: 'hello' }, [port1])
|
||||
|
||||
// Renderer process
|
||||
ipcRenderer.on('port', (e, msg) => {
|
||||
|
||||
@@ -128,8 +128,9 @@ For example:
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const win = new BrowserWindow()
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
webContents.mainFrame.postMessage('port', { message: 'hello' }, [port1])
|
||||
win.webContents.mainFrame.postMessage('port', { message: 'hello' }, [port1])
|
||||
|
||||
// Renderer process
|
||||
ipcRenderer.on('port', (e, msg) => {
|
||||
|
||||
@@ -96,13 +96,12 @@ with an array of misspelt words when complete.
|
||||
|
||||
An example of using [node-spellchecker][spellchecker] as provider:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[2,6]
|
||||
const { webFrame } = require('electron')
|
||||
const spellChecker = require('spellchecker')
|
||||
webFrame.setSpellCheckProvider('en-US', {
|
||||
spellCheck (words, callback) {
|
||||
setTimeout(() => {
|
||||
const spellchecker = require('spellchecker')
|
||||
const misspelled = words.filter(x => spellchecker.isMisspelled(x))
|
||||
callback(misspelled)
|
||||
}, 0)
|
||||
|
||||
@@ -255,7 +255,7 @@ The `webview` tag has the following methods:
|
||||
|
||||
**Example**
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[3]
|
||||
const webview = document.querySelector('webview')
|
||||
webview.addEventListener('dom-ready', () => {
|
||||
webview.openDevTools()
|
||||
@@ -776,7 +776,7 @@ Fired when the guest window logs a console message.
|
||||
The following example code forwards all log messages to the embedder's console
|
||||
without regard for log level or other properties.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[3]
|
||||
const webview = document.querySelector('webview')
|
||||
webview.addEventListener('console-message', (e) => {
|
||||
console.log('Guest page logged a message:', e.message)
|
||||
@@ -797,7 +797,7 @@ Returns:
|
||||
Fired when a result is available for
|
||||
[`webview.findInPage`](#webviewfindinpagetext-options) request.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[3,6]
|
||||
const webview = document.querySelector('webview')
|
||||
webview.addEventListener('found-in-page', (e) => {
|
||||
webview.stopFindInPage('keepSelection')
|
||||
@@ -900,7 +900,7 @@ Fired when the guest page attempts to close itself.
|
||||
The following example code navigates the `webview` to `about:blank` when the
|
||||
guest attempts to close itself.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[3]
|
||||
const webview = document.querySelector('webview')
|
||||
webview.addEventListener('close', () => {
|
||||
webview.src = 'about:blank'
|
||||
@@ -920,7 +920,7 @@ Fired when the guest page has sent an asynchronous message to embedder page.
|
||||
With `sendToHost` method and `ipc-message` event you can communicate
|
||||
between guest page and embedder page:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[4,7]
|
||||
// In embedder page.
|
||||
const webview = document.querySelector('webview')
|
||||
webview.addEventListener('ipc-message', (event) => {
|
||||
|
||||
@@ -191,6 +191,39 @@ webContents.setWindowOpenHandler((details) => {
|
||||
})
|
||||
```
|
||||
|
||||
### Removed: `<webview>` `new-window` event
|
||||
|
||||
The `new-window` event of `<webview>` has been removed. There is no direct replacement.
|
||||
|
||||
```js
|
||||
// Removed in Electron 22
|
||||
webview.addEventListener('new-window', (event) => {})
|
||||
```
|
||||
|
||||
```javascript fiddle='docs/fiddles/ipc/webview-new-window'
|
||||
// Replace with
|
||||
|
||||
// main.js
|
||||
mainWindow.webContents.on('did-attach-webview', (event, wc) => {
|
||||
wc.setWindowOpenHandler((details) => {
|
||||
mainWindow.webContents.send('webview-new-window', wc.id, details)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
})
|
||||
|
||||
// preload.js
|
||||
const { ipcRenderer } = require('electron')
|
||||
ipcRenderer.on('webview-new-window', (e, webContentsId, details) => {
|
||||
console.log('webview-new-window', webContentsId, details)
|
||||
document.getElementById('webview').dispatchEvent(new Event('new-window'))
|
||||
})
|
||||
|
||||
// renderer.js
|
||||
document.getElementById('webview').addEventListener('new-window', () => {
|
||||
console.log('got new-window event')
|
||||
})
|
||||
```
|
||||
|
||||
### Deprecated: BrowserWindow `scroll-touch-*` events
|
||||
|
||||
The `scroll-touch-begin`, `scroll-touch-end` and `scroll-touch-edge` events on
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# Updating an Appveyor Azure Image
|
||||
|
||||
Electron CI on Windows uses AppVeyor, which in turn uses Azure VM images to run. Occasionally, these VM images need to be updated due to changes in Chromium requirements. In order to update you will need [PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.3&viewFallbackFrom=powershell-6) and the [Azure PowerShell module](https://learn.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-9.5.0&viewFallbackFrom=azps-1.8.0).
|
||||
|
||||
Occasionally we need to update these images owing to changes in Chromium or other miscellaneous build requirement changes.
|
||||
|
||||
Example Use Case:
|
||||
* We need `VS15.9` and we have `VS15.7` installed; this would require us to update an Azure image.
|
||||
|
||||
1. Identify the image you wish to modify.
|
||||
* In [appveyor.yml](https://github.com/electron/electron/blob/main/appveyor.yml), the image is identified by the property _image_.
|
||||
* The names used correspond to the _"images"_ defined for a build cloud, eg the [libcc-20 cloud](https://windows-ci.electronjs.org/build-clouds/8).
|
||||
* Find the image you wish to modify in the build cloud and make note of the **VHD Blob Path** for that image, which is the value for that corresponding key.
|
||||
* You will need this URI path to copy into a new image.
|
||||
* You will also need the storage account name which is labeled in AppVeyor as the **Disk Storage Account Name**
|
||||
|
||||
2. Get the Azure storage account key
|
||||
* Log into Azure using credentials stored in LastPass (under Azure Enterprise) and then find the storage account corresponding to the name found in AppVeyor.
|
||||
* Example, for `appveyorlibccbuilds` **Disk Storage Account Name** you'd look for `appveyorlibccbuilds` in the list of storage accounts @ Home < Storage Accounts
|
||||
* Click into it and look for `Access Keys`, and then you can use any of the keys present in the list.
|
||||
|
||||
3. Get the full virtual machine image URI from Azure
|
||||
* Navigate to Home < Storage Accounts < `$ACCT_NAME` < Blobs < Images
|
||||
* In the following list, look for the VHD path name you got from Appveyor and then click on it.
|
||||
* Copy the whole URL from the top of the subsequent window.
|
||||
|
||||
4. Copy the image using the [Copy Master Image PowerShell script](https://github.com/appveyor/ci/blob/master/scripts/enterprise/copy-master-image-azure.ps1).
|
||||
* It is essential to copy the VM because if you spin up a VM against an image that image cannot at the same time be used by AppVeyor.
|
||||
* Use the storage account name, key, and URI obtained from Azure to run this script.
|
||||
* See Step 3 for URI & when prompted, press enter to use same storage account as destination.
|
||||
* Use default destination container name `(images)`
|
||||
* Also, when naming the copy, use a name that indicates what the new image will contain (if that has changed) and date stamp.
|
||||
* Ex. `libcc-20core-vs2017-15.9-2019-04-15.vhd`
|
||||
* Go into Azure and get the URI for the newly created image as described in a previous step
|
||||
|
||||
5. Spin up a new VM using the [Create Master VM from VHD PowerShell](https://github.com/appveyor/ci/blob/master/scripts/enterprise/create_master_vm_from_vhd.ps1).
|
||||
* From PowerShell, execute `ps1` file with `./create_master_vm_from_vhd.ps1`
|
||||
* You will need the credential information available in the AppVeyor build cloud definition.
|
||||
* This includes:
|
||||
* Client ID
|
||||
* Client Secret
|
||||
* Tenant ID
|
||||
* Subscription ID
|
||||
* Resource Group
|
||||
* Virtual Network
|
||||
* You will also need to specify
|
||||
* Master VM name - just a unique name to identify the temporary VM
|
||||
* Master VM size - use `Standard_F32s_v2`
|
||||
* Master VHD URI - use URI obtained @ end of previous step
|
||||
* Location use `East US`
|
||||
|
||||
6. Log back into Azure and find the VM you just created in Home < Virtual Machines < `$YOUR_NEW_VM`
|
||||
* You can download a RDP (Remote Desktop) file to access the VM.
|
||||
|
||||
7. Using Microsoft Remote Desktop, click `Connect` to connect to the VM.
|
||||
* Credentials for logging into the VM are found in LastPass under the `AppVeyor Enterprise master VM` credentials.
|
||||
|
||||
8. Modify the VM as required.
|
||||
|
||||
9. Shut down the VM and then delete it in Azure.
|
||||
|
||||
10. Add the new image to the Appveyor Cloud settings or modify an existing image to point to the new VHD.
|
||||
@@ -51,6 +51,13 @@ function createWindow () {
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setUSBProtectedClassesHandler((details) => {
|
||||
return details.protectedClasses.filter((usbClass) => {
|
||||
// Exclude classes except for audio classes
|
||||
return usbClass.indexOf('audio') === -1
|
||||
})
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
|
||||
3
docs/fiddles/ipc/webview-new-window/child.html
Normal file
3
docs/fiddles/ipc/webview-new-window/child.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
<a href="child.html" target="_blank">new window</a>
|
||||
</body>
|
||||
4
docs/fiddles/ipc/webview-new-window/index.html
Normal file
4
docs/fiddles/ipc/webview-new-window/index.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<body>
|
||||
<webview id=webview src="child.html" allowpopups></webview>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
51
docs/fiddles/ipc/webview-new-window/main.js
Normal file
51
docs/fiddles/ipc/webview-new-window/main.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
webviewTag: true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('did-attach-webview', (event, wc) => {
|
||||
wc.setWindowOpenHandler((details) => {
|
||||
mainWindow.webContents.send('webview-new-window', wc.id, details)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
6
docs/fiddles/ipc/webview-new-window/preload.js
Normal file
6
docs/fiddles/ipc/webview-new-window/preload.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
const webview = document.getElementById('webview')
|
||||
ipcRenderer.on('webview-new-window', (e, webContentsId, details) => {
|
||||
console.log('webview-new-window', webContentsId, details)
|
||||
webview.dispatchEvent(new Event('new-window'))
|
||||
})
|
||||
4
docs/fiddles/ipc/webview-new-window/renderer.js
Normal file
4
docs/fiddles/ipc/webview-new-window/renderer.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const webview = document.getElementById('webview')
|
||||
webview.addEventListener('new-window', () => {
|
||||
console.log('got new-window event')
|
||||
})
|
||||
@@ -55,7 +55,7 @@ fs.readdirSync('/path/to/example.asar')
|
||||
|
||||
Use a module from the archive:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
require('./path/to/example.asar/dir/module.js')
|
||||
```
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of t
|
||||
|
||||
ASAR integrity checking is currently disabled by default and can be enabled by toggling a fuse. See [Electron Fuses](fuses.md) for more information on what Electron Fuses are and how they work. When enabling this fuse you typically also want to enable the `onlyLoadAppFromAsar` fuse otherwise the validity checking can be bypassed via the Electron app code search path.
|
||||
|
||||
```js
|
||||
```js @ts-nocheck
|
||||
require('@electron/fuses').flipFuses(
|
||||
// E.g. /a/b/Foo.app
|
||||
pathToPackagedApp,
|
||||
|
||||
@@ -90,7 +90,7 @@ Usage of `selenium-webdriver` with Electron is the same as with
|
||||
normal websites, except that you have to manually specify how to connect
|
||||
ChromeDriver and where to find the binary of your Electron app:
|
||||
|
||||
```js title='test.js'
|
||||
```js title='test.js' @ts-expect-error=[1]
|
||||
const webdriver = require('selenium-webdriver')
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by ChromeDriver.
|
||||
@@ -155,7 +155,7 @@ Playwright launches your app in development mode through the `_electron.launch`
|
||||
To point this API to your Electron app, you can pass the path to your main process
|
||||
entry point (here, it is `main.js`).
|
||||
|
||||
```js {5}
|
||||
```js {5} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
|
||||
@@ -169,7 +169,7 @@ test('launch app', async () => {
|
||||
After that, you will access to an instance of Playwright's `ElectronApp` class. This
|
||||
is a powerful class that has access to main process modules for example:
|
||||
|
||||
```js {6-11}
|
||||
```js {6-11} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
|
||||
@@ -189,7 +189,7 @@ test('get isPackaged', async () => {
|
||||
It can also create individual [Page][playwright-page] objects from Electron BrowserWindow instances.
|
||||
For example, to grab the first BrowserWindow and save a screenshot:
|
||||
|
||||
```js {6-7}
|
||||
```js {6-7} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
|
||||
@@ -205,7 +205,7 @@ test('save screenshot', async () => {
|
||||
Putting all this together using the PlayWright Test runner, let's create a `example.spec.js`
|
||||
test file with a single test and assertion:
|
||||
|
||||
```js title='example.spec.js'
|
||||
```js title='example.spec.js' @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test, expect } = require('@playwright/test')
|
||||
|
||||
@@ -259,7 +259,7 @@ expose custom methods to your test suite.
|
||||
To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API.
|
||||
The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js title='testDriver.js'
|
||||
```js title='testDriver.js' @ts-nocheck
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
@@ -296,7 +296,7 @@ For convenience, you may want to wrap `appProcess` in a driver object that provi
|
||||
high-level functions. Here is an example of how you can do this. Let's start by creating
|
||||
a `TestDriver` class:
|
||||
|
||||
```js title='testDriver.js'
|
||||
```js title='testDriver.js' @ts-nocheck
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
@@ -378,7 +378,7 @@ framework of your choosing. The following example uses
|
||||
[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest
|
||||
or Mocha would work as well:
|
||||
|
||||
```js title='test.js'
|
||||
```js title='test.js' @ts-nocheck
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
const { TestDriver } = require('./testDriver')
|
||||
|
||||
@@ -67,7 +67,7 @@ are likely using [`electron-packager`][], which includes [`@electron/osx-sign`][
|
||||
If you're using Packager's API, you can pass [in configuration that both signs
|
||||
and notarizes your application](https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html).
|
||||
|
||||
```js
|
||||
```js @ts-nocheck
|
||||
const packager = require('electron-packager')
|
||||
|
||||
packager({
|
||||
@@ -116,7 +116,7 @@ Electron app. This is the tool used under the hood by Electron Forge's
|
||||
`electron-winstaller` directly, use the `certificateFile` and `certificatePassword` configuration
|
||||
options when creating your installer.
|
||||
|
||||
```js {10-11}
|
||||
```js {10-11} @ts-nocheck
|
||||
const electronInstaller = require('electron-winstaller')
|
||||
// NB: Use this syntax within an async function, Node does not have support for
|
||||
// top-level await as of Node 12.
|
||||
@@ -146,7 +146,7 @@ If you're not using Electron Forge and want to use `electron-wix-msi` directly,
|
||||
`certificateFile` and `certificatePassword` configuration options
|
||||
or pass in parameters directly to [SignTool.exe][] with the `signWithParams` option.
|
||||
|
||||
```js {12-13}
|
||||
```js {12-13} @ts-nocheck
|
||||
import { MSICreator } from 'electron-wix-msi'
|
||||
|
||||
// Step 1: Instantiate the MSICreator
|
||||
|
||||
@@ -16,7 +16,7 @@ Context isolation has been enabled by default since Electron 12, and it is a rec
|
||||
|
||||
Exposing APIs from your preload script to a loaded website in the renderer process is a common use-case. With context isolation disabled, your preload script would share a common global `window` object with the renderer. You could then attach arbitrary properties to a preload script:
|
||||
|
||||
```javascript title='preload.js'
|
||||
```javascript title='preload.js' @ts-nocheck
|
||||
// preload with contextIsolation disabled
|
||||
window.myAPI = {
|
||||
doAThing: () => {}
|
||||
@@ -25,7 +25,7 @@ window.myAPI = {
|
||||
|
||||
The `doAThing()` function could then be used directly in the renderer process:
|
||||
|
||||
```javascript title='renderer.js'
|
||||
```javascript title='renderer.js' @ts-nocheck
|
||||
// use the exposed API in the renderer
|
||||
window.myAPI.doAThing()
|
||||
```
|
||||
@@ -43,7 +43,7 @@ contextBridge.exposeInMainWorld('myAPI', {
|
||||
})
|
||||
```
|
||||
|
||||
```javascript title='renderer.js'
|
||||
```javascript title='renderer.js' @ts-nocheck
|
||||
// use the exposed API in the renderer
|
||||
window.myAPI.doAThing()
|
||||
```
|
||||
@@ -98,7 +98,7 @@ declare global {
|
||||
|
||||
Doing so will ensure that the TypeScript compiler will know about the `electronAPI` property on your global `window` object when writing scripts in your renderer process:
|
||||
|
||||
```typescript title='renderer.ts'
|
||||
```typescript title='renderer.ts' @ts-nocheck
|
||||
window.electronAPI.loadPreferences()
|
||||
```
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ Now the renderer process can communicate with the main process securely and perf
|
||||
|
||||
The `renderer.js` file is responsible for controlling the `<button>` functionality.
|
||||
|
||||
```js title='renderer.js'
|
||||
```js title='renderer.js' @ts-expect-error=[2,7]
|
||||
document.getElementById('toggle-dark-mode').addEventListener('click', async () => {
|
||||
const isDarkMode = await window.darkMode.toggle()
|
||||
document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light'
|
||||
|
||||
@@ -142,6 +142,8 @@ Electron provides several APIs for working with the WebUSB API:
|
||||
`setDevicePermissionHandler`.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable USB access for specific origins.
|
||||
* [`ses.setUSBProtectedClassesHandler](../api/session.md#sessetusbprotectedclasseshandlerhandler)
|
||||
can be used to allow usage of [protected USB classes](https://wicg.github.io/webusb/#usbinterface-interface) that are not available by default.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is
|
||||
|
||||
We've made a handy module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases.
|
||||
|
||||
```js
|
||||
```js @ts-nocheck
|
||||
require('@electron/fuses').flipFuses(
|
||||
// Path to electron
|
||||
require('electron'),
|
||||
|
||||
@@ -66,7 +66,7 @@ You can use environment variables to override the base URL, the path at which to
|
||||
look for Electron binaries, and the binary filename. The URL used by `@electron/get`
|
||||
is composed as follows:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
url = ELECTRON_MIRROR + ELECTRON_CUSTOM_DIR + '/' + ELECTRON_CUSTOM_FILENAME
|
||||
```
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ To make these elements interactive, we'll be adding a few lines of code in the i
|
||||
`renderer.js` file that leverages the `window.electronAPI` functionality exposed from the preload
|
||||
script:
|
||||
|
||||
```javascript title='renderer.js (Renderer Process)'
|
||||
```javascript title='renderer.js (Renderer Process)' @ts-expect-error=[4,5]
|
||||
const setButton = document.getElementById('btn')
|
||||
const titleInput = document.getElementById('title')
|
||||
setButton.addEventListener('click', () => {
|
||||
@@ -182,13 +182,13 @@ provided to the renderer process. Please refer to
|
||||
:::
|
||||
|
||||
```javascript {6-13,25} title='main.js (Main Process)'
|
||||
const { BrowserWindow, dialog, ipcMain } = require('electron')
|
||||
const { app, BrowserWindow, dialog, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// ...
|
||||
|
||||
async function handleFileOpen () {
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog()
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog({})
|
||||
if (!canceled) {
|
||||
return filePaths[0]
|
||||
}
|
||||
@@ -203,7 +203,7 @@ function createWindow () {
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady(() => {
|
||||
app.whenReady().then(() => {
|
||||
ipcMain.handle('dialog:openFile', handleFileOpen)
|
||||
createWindow()
|
||||
})
|
||||
@@ -263,7 +263,7 @@ The UI consists of a single `#btn` button element that will be used to trigger o
|
||||
a `#filePath` element that will be used to display the path of the selected file. Making these
|
||||
pieces work will take a few lines of code in the renderer process script:
|
||||
|
||||
```javascript title='renderer.js (Renderer Process)'
|
||||
```javascript title='renderer.js (Renderer Process)' @ts-expect-error=[5]
|
||||
const btn = document.getElementById('btn')
|
||||
const filePathElement = document.getElementById('filePath')
|
||||
|
||||
@@ -412,7 +412,7 @@ function createWindow () {
|
||||
For the purposes of the tutorial, it's important to note that the `click` handler
|
||||
sends a message (either `1` or `-1`) to the renderer process through the `update-counter` channel.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
click: () => mainWindow.webContents.send('update-counter', -1)
|
||||
```
|
||||
|
||||
@@ -486,7 +486,7 @@ To tie it all together, we'll create an interface in the loaded HTML file that c
|
||||
Finally, to make the values update in the HTML document, we'll add a few lines of DOM manipulation
|
||||
so that the value of the `#counter` element is updated whenever we fire an `update-counter` event.
|
||||
|
||||
```javascript title='renderer.js (Renderer Process)'
|
||||
```javascript title='renderer.js (Renderer Process)' @ts-nocheck
|
||||
const counter = document.getElementById('counter')
|
||||
|
||||
window.electronAPI.onUpdateCounter((_event, value) => {
|
||||
@@ -509,7 +509,7 @@ We can demonstrate this with slight modifications to the code from the previous
|
||||
renderer process, use the `event` parameter to send a reply back to the main process through the
|
||||
`counter-value` channel.
|
||||
|
||||
```javascript title='renderer.js (Renderer Process)'
|
||||
```javascript title='renderer.js (Renderer Process)' @ts-nocheck
|
||||
const counter = document.getElementById('counter')
|
||||
|
||||
window.electronAPI.onUpdateCounter((event, value) => {
|
||||
|
||||
@@ -56,7 +56,7 @@ Starting with a working application from the
|
||||
[Quick Start Guide](quick-start.md), update the `main.js` file with the
|
||||
following lines:
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/keyboard-shortcuts/global'
|
||||
```javascript fiddle='docs/fiddles/features/keyboard-shortcuts/global' @ts-type={createWindow:()=>void}
|
||||
const { app, globalShortcut } = require('electron')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
@@ -131,7 +131,7 @@ If you don't want to do manual shortcut parsing, there are libraries that do
|
||||
advanced key detection, such as [mousetrap][]. Below are examples of usage of the
|
||||
`mousetrap` running in the Renderer process:
|
||||
|
||||
```js
|
||||
```js @ts-nocheck
|
||||
Mousetrap.bind('4', () => { console.log('4') })
|
||||
Mousetrap.bind('?', () => { console.log('show shortcuts!') })
|
||||
Mousetrap.bind('esc', () => { console.log('escape') }, 'keyup')
|
||||
|
||||
@@ -45,6 +45,8 @@ if (process.defaultApp) {
|
||||
We will now define the function in charge of creating our browser window and load our application's `index.html` file.
|
||||
|
||||
```javascript
|
||||
let mainWindow
|
||||
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
@@ -65,7 +67,7 @@ This code will be different in Windows compared to MacOS and Linux. This is due
|
||||
|
||||
#### Windows code:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={mainWindow:Electron.BrowserWindow} @ts-type={createWindow:()=>void}
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
@@ -91,7 +93,7 @@ if (!gotTheLock) {
|
||||
|
||||
#### MacOS and Linux code:
|
||||
|
||||
```javascript
|
||||
```javascript @ts-type={createWindow:()=>void}
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
@@ -166,7 +168,7 @@ If you're using Electron Packager's API, adding support for protocol handlers is
|
||||
Electron Forge is handled, except
|
||||
`protocols` is part of the Packager options passed to the `packager` function.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-nocheck
|
||||
const packager = require('electron-packager')
|
||||
|
||||
packager({
|
||||
|
||||
@@ -126,7 +126,7 @@ app.whenReady().then(async () => {
|
||||
Then, in your preload scripts you receive the port through IPC and set up the
|
||||
listeners.
|
||||
|
||||
```js title='preloadMain.js and preloadSecondary.js (Preload scripts)'
|
||||
```js title='preloadMain.js and preloadSecondary.js (Preload scripts)' @ts-nocheck
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
ipcRenderer.on('port', e => {
|
||||
@@ -148,7 +148,7 @@ That means window.electronMessagePort is globally available and you can call
|
||||
`postMessage` on it from anywhere in your app to send a message to the other
|
||||
renderer.
|
||||
|
||||
```js title='renderer.js (Renderer Process)'
|
||||
```js title='renderer.js (Renderer Process)' @ts-nocheck
|
||||
// elsewhere in your code to send a message to the other renderers message handler
|
||||
window.electronMessagePort.postmessage('ping')
|
||||
```
|
||||
@@ -181,7 +181,7 @@ app.whenReady().then(async () => {
|
||||
// We can't use ipcMain.handle() here, because the reply needs to transfer a
|
||||
// MessagePort.
|
||||
// Listen for message sent from the top-level frame
|
||||
mainWindow.webContents.mainFrame.on('request-worker-channel', (event) => {
|
||||
mainWindow.webContents.mainFrame.ipc.on('request-worker-channel', (event) => {
|
||||
// Create a new channel ...
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
// ... send one end to the worker ...
|
||||
@@ -245,7 +245,7 @@ Electron's built-in IPC methods only support two modes: fire-and-forget
|
||||
can implement a "response stream", where a single request responds with a
|
||||
stream of data.
|
||||
|
||||
```js title='renderer.js (Renderer Process)'
|
||||
```js title='renderer.js (Renderer Process)' @ts-expect-error=[18]
|
||||
const makeStreamingRequest = (element, callback) => {
|
||||
// MessageChannels are lightweight--it's cheap to create a new one for each
|
||||
// request.
|
||||
|
||||
@@ -42,7 +42,7 @@ safe.
|
||||
The only way to load a native module safely for now, is to make sure the app
|
||||
loads no native modules after the Web Workers get started.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[1]
|
||||
process.dlopen = () => {
|
||||
throw new Error('Load native module is not safe')
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ In `preload.js` use the [`contextBridge`][] to inject a method `window.electron.
|
||||
|
||||
```js
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
startDrag: (fileName) => {
|
||||
@@ -43,7 +44,7 @@ Add a draggable element to `index.html`, and reference your renderer script:
|
||||
|
||||
In `renderer.js` set up the renderer process to handle drag events by calling the method you added via the [`contextBridge`][] above.
|
||||
|
||||
```javascript
|
||||
```javascript @ts-expect-error=[3]
|
||||
document.getElementById('drag').ondragstart = (event) => {
|
||||
event.preventDefault()
|
||||
window.electron.startDrag('drag-and-drop.md')
|
||||
|
||||
@@ -172,7 +172,7 @@ in the fictitious `.foo` format. In order to do that, it relies on the
|
||||
equally fictitious `foo-parser` module. In traditional Node.js development,
|
||||
you might write code that eagerly loads dependencies:
|
||||
|
||||
```js title='parser.js'
|
||||
```js title='parser.js' @ts-expect-error=[2]
|
||||
const fs = require('fs')
|
||||
const fooParser = require('foo-parser')
|
||||
|
||||
@@ -195,7 +195,7 @@ In the above example, we're doing a lot of work that's being executed as soon
|
||||
as the file is loaded. Do we need to get parsed files right away? Could we
|
||||
do this work a little later, when `getParsedFiles()` is actually called?
|
||||
|
||||
```js title='parser.js'
|
||||
```js title='parser.js' @ts-expect-error=[20]
|
||||
// "fs" is likely already being loaded, so the `require()` call is cheap
|
||||
const fs = require('fs')
|
||||
|
||||
@@ -204,7 +204,7 @@ class Parser {
|
||||
// Touch the disk as soon as `getFiles` is called, not sooner.
|
||||
// Also, ensure that we're not blocking other operations by using
|
||||
// the asynchronous version.
|
||||
this.files = this.files || await fs.readdir('.')
|
||||
this.files = this.files || await fs.promises.readdir('.')
|
||||
|
||||
return this.files
|
||||
}
|
||||
|
||||
@@ -175,13 +175,13 @@ Although preload scripts share a `window` global with the renderer they're attac
|
||||
you cannot directly attach any variables from the preload script to `window` because of
|
||||
the [`contextIsolation`][context-isolation] default.
|
||||
|
||||
```js title='preload.js'
|
||||
```js title='preload.js' @ts-nocheck
|
||||
window.myAPI = {
|
||||
desktop: true
|
||||
}
|
||||
```
|
||||
|
||||
```js title='renderer.js'
|
||||
```js title='renderer.js' @ts-nocheck
|
||||
console.log(window.myAPI)
|
||||
// => undefined
|
||||
```
|
||||
@@ -200,7 +200,7 @@ contextBridge.exposeInMainWorld('myAPI', {
|
||||
})
|
||||
```
|
||||
|
||||
```js title='renderer.js'
|
||||
```js title='renderer.js' @ts-nocheck
|
||||
console.log(window.myAPI)
|
||||
// => { desktop: true }
|
||||
```
|
||||
|
||||
@@ -182,7 +182,7 @@ In Electron, browser windows can only be created after the `app` module's
|
||||
[`app.whenReady()`][app-when-ready] API. Call `createWindow()` after `whenReady()`
|
||||
resolves its Promise.
|
||||
|
||||
```js
|
||||
```js @ts-type={createWindow:()=>void}
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
@@ -239,7 +239,7 @@ from within your existing `whenReady()` callback.
|
||||
|
||||
[activate]: ../api/app.md#event-activate-macos
|
||||
|
||||
```js
|
||||
```js @ts-type={createWindow:()=>void}
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
@@ -290,6 +290,7 @@ To attach this script to your renderer process, pass in the path to your preload
|
||||
to the `webPreferences.preload` option in your existing `BrowserWindow` constructor.
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
// include the Node.js 'path' module at the top of your file
|
||||
const path = require('path')
|
||||
|
||||
|
||||
@@ -46,11 +46,17 @@ scripts attached to sandboxed renderers will still have a polyfilled subset of N
|
||||
APIs available. A `require` function similar to Node's `require` module is exposed,
|
||||
but can only import a subset of Electron and Node's built-in modules:
|
||||
|
||||
* `electron` (only renderer process modules)
|
||||
* `electron` (following renderer process modules: `contextBridge`, `crashReporter`, `ipcRenderer`, `nativeImage`, `webFrame`)
|
||||
* [`events`](https://nodejs.org/api/events.html)
|
||||
* [`timers`](https://nodejs.org/api/timers.html)
|
||||
* [`url`](https://nodejs.org/api/url.html)
|
||||
|
||||
[node: imports](https://nodejs.org/api/esm.html#node-imports) are supported as well:
|
||||
|
||||
* [`node:events`](https://nodejs.org/api/events.html)
|
||||
* [`node:timers`](https://nodejs.org/api/timers.html)
|
||||
* [`node:url`](https://nodejs.org/api/url.html)
|
||||
|
||||
In addition, the preload script also polyfills certain Node.js primitives as globals:
|
||||
|
||||
* [`Buffer`](https://nodejs.org/api/buffer.html)
|
||||
|
||||
@@ -141,7 +141,7 @@ like `HTTP`. Similarly, we recommend the use of `WSS` over `WS`, `FTPS` over
|
||||
|
||||
#### How?
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
```js title='main.js (Main Process)' @ts-type={browserWindow:Electron.BrowserWindow}
|
||||
// Bad
|
||||
browserWindow.loadURL('http://example.com')
|
||||
|
||||
@@ -278,7 +278,7 @@ security-conscious developers might want to assume the very opposite.
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
const { session } = require('electron')
|
||||
const URL = require('url').URL
|
||||
const { URL } = require('url')
|
||||
|
||||
session
|
||||
.fromPartition('some-partition')
|
||||
@@ -608,7 +608,8 @@ sometimes be fooled - a `startsWith('https://example.com')` test would let
|
||||
`https://example.com.attacker.com` through.
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
const URL = require('url').URL
|
||||
const { URL } = require('url')
|
||||
const { app } = require('electron')
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
contents.on('will-navigate', (event, navigationUrl) => {
|
||||
@@ -647,8 +648,8 @@ receive, amongst other parameters, the `url` the window was requested to open
|
||||
and the options used to create it. We recommend that you register a handler to
|
||||
monitor the creation of windows, and deny any unexpected window creation.
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
const { shell } = require('electron')
|
||||
```js title='main.js (Main Process)' @ts-type={isSafeForExternalOpen:(url:string)=>boolean}
|
||||
const { app, shell } = require('electron')
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
contents.setWindowOpenHandler(({ url }) => {
|
||||
@@ -683,7 +684,7 @@ leveraged to execute arbitrary commands.
|
||||
|
||||
#### How?
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
```js title='main.js (Main Process)' @ts-type={USER_CONTROLLED_DATA_HERE:string}
|
||||
// Bad
|
||||
const { shell } = require('electron')
|
||||
shell.openExternal(USER_CONTROLLED_DATA_HERE)
|
||||
@@ -739,7 +740,7 @@ You should be validating the `sender` of **all** IPC messages by default.
|
||||
|
||||
#### How?
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
```js title='main.js (Main Process)' @ts-type={getSecrets:()=>unknown}
|
||||
// Bad
|
||||
ipcMain.handle('get-secrets', () => {
|
||||
return getSecrets()
|
||||
|
||||
@@ -72,7 +72,7 @@ npx electron-installer-snap --src=out/myappname-linux-x64
|
||||
If you have an existing build pipeline, you can use `electron-installer-snap`
|
||||
programmatically. For more information, see the [Snapcraft API docs][snapcraft-syntax].
|
||||
|
||||
```js
|
||||
```js @ts-nocheck
|
||||
const snap = require('electron-installer-snap')
|
||||
|
||||
snap(options)
|
||||
|
||||
@@ -20,12 +20,12 @@ On macOS as we use the native APIs there is no way to set the language that the
|
||||
|
||||
For Windows and Linux there are a few Electron APIs you should use to set the languages for the spellchecker.
|
||||
|
||||
```js
|
||||
```js @ts-type={myWindow:Electron.BrowserWindow}
|
||||
// Sets the spellchecker to check English US and French
|
||||
myWindow.session.setSpellCheckerLanguages(['en-US', 'fr'])
|
||||
myWindow.webContents.session.setSpellCheckerLanguages(['en-US', 'fr'])
|
||||
|
||||
// An array of all available language codes
|
||||
const possibleLanguages = myWindow.session.availableSpellCheckerLanguages
|
||||
const possibleLanguages = myWindow.webContents.session.availableSpellCheckerLanguages
|
||||
```
|
||||
|
||||
By default the spellchecker will enable the language matching the current OS locale.
|
||||
@@ -35,7 +35,7 @@ By default the spellchecker will enable the language matching the current OS loc
|
||||
All the required information to generate a context menu is provided in the [`context-menu`](../api/web-contents.md#event-context-menu) event on each `webContents` instance. A small example
|
||||
of how to make a context menu with this information is provided below.
|
||||
|
||||
```js
|
||||
```js @ts-type={myWindow:Electron.BrowserWindow}
|
||||
const { Menu, MenuItem } = require('electron')
|
||||
|
||||
myWindow.webContents.on('context-menu', (event, params) => {
|
||||
@@ -45,7 +45,7 @@ myWindow.webContents.on('context-menu', (event, params) => {
|
||||
for (const suggestion of params.dictionarySuggestions) {
|
||||
menu.append(new MenuItem({
|
||||
label: suggestion,
|
||||
click: () => mainWindow.webContents.replaceMisspelling(suggestion)
|
||||
click: () => myWindow.webContents.replaceMisspelling(suggestion)
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ myWindow.webContents.on('context-menu', (event, params) => {
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
label: 'Add to dictionary',
|
||||
click: () => mainWindow.webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord)
|
||||
click: () => myWindow.webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord)
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -67,8 +67,8 @@ myWindow.webContents.on('context-menu', (event, params) => {
|
||||
|
||||
Although the spellchecker itself does not send any typings, words or user input to Google services the hunspell dictionary files are downloaded from a Google CDN by default. If you want to avoid this you can provide an alternative URL to download the dictionaries from.
|
||||
|
||||
```js
|
||||
myWindow.session.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')
|
||||
```js @ts-type={myWindow:Electron.BrowserWindow}
|
||||
myWindow.webContents.session.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')
|
||||
```
|
||||
|
||||
Check out the docs for [`session.setSpellCheckerDictionaryDownloadURL`](../api/session.md#sessetspellcheckerdictionarydownloadurlurl) for more information on where to get the dictionary files from and how you need to host them.
|
||||
|
||||
@@ -51,7 +51,7 @@ app.whenReady().then(() => {
|
||||
|
||||
Great! Now we can start attaching a context menu to our Tray, like so:
|
||||
|
||||
```js
|
||||
```js @ts-expect-error=[8]
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Item1', type: 'radio' },
|
||||
{ label: 'Item2', type: 'radio' },
|
||||
@@ -68,7 +68,7 @@ To read more about constructing native menus, click
|
||||
|
||||
Finally, let's give our tray a tooltip and a title.
|
||||
|
||||
```js
|
||||
```js @ts-type={tray:Electron.Tray}
|
||||
tray.setToolTip('This is my application')
|
||||
tray.setTitle('This is my title')
|
||||
```
|
||||
|
||||
@@ -256,7 +256,7 @@ const createWindow = () => {
|
||||
|
||||
### Calling your function when the app is ready
|
||||
|
||||
```js title='main.js (Lines 12-14)'
|
||||
```js title='main.js (Lines 12-14)' @ts-type={createWindow:()=>void}
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
@@ -336,7 +336,7 @@ Because windows cannot be created before the `ready` event, you should only list
|
||||
`activate` events after your app is initialized. Do this by only listening for activate
|
||||
events inside your existing `whenReady()` callback.
|
||||
|
||||
```js
|
||||
```js @ts-type={createWindow:()=>void}
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ information in the window. This variable can be accessed via `window.versions` o
|
||||
`versions`. Create a `renderer.js` script that uses the [`document.getElementById`][]
|
||||
DOM API to replace the displayed text for the HTML element with `info` as its `id` property.
|
||||
|
||||
```js title="renderer.js"
|
||||
```js title="renderer.js" @ts-nocheck
|
||||
const information = document.getElementById('info')
|
||||
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`
|
||||
```
|
||||
@@ -223,7 +223,7 @@ app.whenReady().then(createWindow)
|
||||
Once you have the sender and receiver set up, you can now send messages from the renderer
|
||||
to the main process through the `'ping'` channel you just defined.
|
||||
|
||||
```js title='renderer.js'
|
||||
```js title='renderer.js' @ts-expect-error=[2]
|
||||
const func = async () => {
|
||||
const response = await window.versions.ping()
|
||||
console.log(response) // prints out 'pong'
|
||||
|
||||
@@ -188,7 +188,7 @@ npm install update-electron-app
|
||||
|
||||
Then, import the module and call it immediately in the main process.
|
||||
|
||||
```js title='main.js'
|
||||
```js title='main.js' @ts-nocheck
|
||||
require('update-electron-app')()
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ npm install update-electron-app
|
||||
|
||||
Then, invoke the updater from your app's main process file:
|
||||
|
||||
```js title="main.js"
|
||||
```js title="main.js" @ts-nocheck
|
||||
require('update-electron-app')()
|
||||
```
|
||||
|
||||
@@ -113,7 +113,7 @@ Now that you've configured the basic update mechanism for your application, you
|
||||
need to ensure that the user will get notified when there's an update. This
|
||||
can be achieved using the [autoUpdater API events](../api/auto-updater.md#events):
|
||||
|
||||
```javascript title="main.js"
|
||||
```javascript title="main.js" @ts-expect-error=[11]
|
||||
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
|
||||
const dialogOpts = {
|
||||
type: 'info',
|
||||
|
||||
@@ -196,9 +196,9 @@ const win = new BrowserWindow({
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
|
||||
ipcMain.on('set-ignore-mouse-events', (event, ignore, options) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
win.setIgnoreMouseEvents(...args)
|
||||
win.setIgnoreMouseEvents(ignore, options)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ Starting with a working application from the
|
||||
following lines:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const { BrowserWindow, nativeImage } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
@@ -133,11 +133,11 @@ const win = new BrowserWindow()
|
||||
win.setThumbarButtons([
|
||||
{
|
||||
tooltip: 'button1',
|
||||
icon: path.join(__dirname, 'button1.png'),
|
||||
icon: nativeImage.createFromPath(path.join(__dirname, 'button1.png')),
|
||||
click () { console.log('button1 clicked') }
|
||||
}, {
|
||||
tooltip: 'button2',
|
||||
icon: path.join(__dirname, 'button2.png'),
|
||||
icon: nativeImage.createFromPath(path.join(__dirname, 'button2.png')),
|
||||
flags: ['enabled', 'dismissonclick'],
|
||||
click () { console.log('button2 clicked.') }
|
||||
}
|
||||
@@ -189,11 +189,11 @@ Starting with a working application from the
|
||||
following lines:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const { BrowserWindow, nativeImage } = require('electron')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.setOverlayIcon('path/to/overlay.png', 'Description for overlay')
|
||||
win.setOverlayIcon(nativeImage.createFromPath('path/to/overlay.png'), 'Description for overlay')
|
||||
```
|
||||
|
||||
[msdn-icon-overlay]: https://learn.microsoft.com/en-us/windows/win32/shell/taskbar-extensions#icon-overlays
|
||||
|
||||
@@ -317,7 +317,7 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
|
||||
if (options.preferCSSPageSize !== undefined) {
|
||||
if (typeof options.preferCSSPageSize !== 'boolean') {
|
||||
return Promise.reject(new Error('footerTemplate must be a String'));
|
||||
return Promise.reject(new Error('preferCSSPageSize must be a Boolean'));
|
||||
}
|
||||
printSettings.preferCSSPageSize = options.preferCSSPageSize;
|
||||
}
|
||||
@@ -335,36 +335,34 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
}
|
||||
};
|
||||
|
||||
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions = {}, callback) {
|
||||
// TODO(codebytere): deduplicate argument sanitization by moving rest of
|
||||
// print param logic into new file shared between printToPDF and print
|
||||
if (typeof options === 'object') {
|
||||
// Optionally set size for PDF.
|
||||
if (options.pageSize !== undefined) {
|
||||
const pageSize = options.pageSize;
|
||||
if (typeof pageSize === 'object') {
|
||||
if (!pageSize.height || !pageSize.width) {
|
||||
throw new Error('height and width properties are required for pageSize');
|
||||
}
|
||||
|
||||
// Dimensions in Microns - 1 meter = 10^6 microns
|
||||
const height = Math.ceil(pageSize.height);
|
||||
const width = Math.ceil(pageSize.width);
|
||||
if (!isValidCustomPageSize(width, height)) {
|
||||
throw new Error('height and width properties must be minimum 352 microns.');
|
||||
}
|
||||
|
||||
options.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
width_microns: width
|
||||
};
|
||||
} else if (PDFPageSizes[pageSize]) {
|
||||
options.mediaSize = PDFPageSizes[pageSize];
|
||||
} else {
|
||||
throw new Error(`Unsupported pageSize: ${pageSize}`);
|
||||
// TODO(codebytere): deduplicate argument sanitization by moving rest of
|
||||
// print param logic into new file shared between printToPDF and print
|
||||
WebContents.prototype.print = function (printOptions: ElectronInternal.WebContentsPrintOptions, callback) {
|
||||
const options = printOptions ?? {};
|
||||
if (options.pageSize) {
|
||||
const pageSize = options.pageSize;
|
||||
if (typeof pageSize === 'object') {
|
||||
if (!pageSize.height || !pageSize.width) {
|
||||
throw new Error('height and width properties are required for pageSize');
|
||||
}
|
||||
|
||||
// Dimensions in Microns - 1 meter = 10^6 microns
|
||||
const height = Math.ceil(pageSize.height);
|
||||
const width = Math.ceil(pageSize.width);
|
||||
if (!isValidCustomPageSize(width, height)) {
|
||||
throw new Error('height and width properties must be minimum 352 microns.');
|
||||
}
|
||||
|
||||
options.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
width_microns: width
|
||||
};
|
||||
} else if (PDFPageSizes[pageSize]) {
|
||||
options.mediaSize = PDFPageSizes[pageSize];
|
||||
} else {
|
||||
throw new Error(`Unsupported pageSize: ${pageSize}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,15 @@ const loadedModules = new Map<string, any>([
|
||||
['electron', electron],
|
||||
['electron/common', electron],
|
||||
['electron/renderer', electron],
|
||||
['events', events]
|
||||
['events', events],
|
||||
['node:events', events]
|
||||
]);
|
||||
|
||||
const loadableModules = new Map<string, Function>([
|
||||
['timers', () => require('timers')],
|
||||
['url', () => require('url')]
|
||||
['node:timers', () => require('timers')],
|
||||
['url', () => require('url')],
|
||||
['node:url', () => require('url')]
|
||||
]);
|
||||
|
||||
// Pass different process object to the preload script.
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"@electron/asar": "^3.2.1",
|
||||
"@electron/docs-parser": "^1.0.0",
|
||||
"@electron/fiddle-core": "^1.0.4",
|
||||
"@electron/github-app-auth": "^1.5.0",
|
||||
"@electron/lint-roller": "^1.2.1",
|
||||
"@electron/github-app-auth": "^2.0.0",
|
||||
"@electron/lint-roller": "^1.5.0",
|
||||
"@electron/typescript-definitions": "^8.10.0",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@primer/octicons": "^10.0.0",
|
||||
@@ -30,6 +30,7 @@
|
||||
"@types/stream-json": "^1.5.1",
|
||||
"@types/temp": "^0.8.34",
|
||||
"@types/uuid": "^3.4.6",
|
||||
"@types/w3c-web-serial": "^1.0.3",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-env": "^1.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.4.1",
|
||||
@@ -88,10 +89,11 @@
|
||||
"lint:objc": "node ./script/lint.js --objc",
|
||||
"lint:py": "node ./script/lint.js --py",
|
||||
"lint:gn": "node ./script/lint.js --gn",
|
||||
"lint:docs": "remark docs -qf && npm run lint:js-in-markdown && npm run create-typescript-definitions && npm run lint:docs-fiddles && npm run lint:docs-relative-links && npm run lint:markdownlint",
|
||||
"lint:docs": "remark docs -qf && npm run lint:js-in-markdown && npm run create-typescript-definitions && npm run lint:ts-check-js-in-markdown && npm run lint:docs-fiddles && npm run lint:docs-relative-links && npm run lint:markdownlint",
|
||||
"lint:docs-fiddles": "standard \"docs/fiddles/**/*.js\"",
|
||||
"lint:docs-relative-links": "electron-lint-markdown-links --root docs \"**/*.md\"",
|
||||
"lint:markdownlint": "electron-markdownlint \"*.md\" \"docs/**/*.md\"",
|
||||
"lint:ts-check-js-in-markdown": "electron-lint-markdown-ts-check --root docs \"**/*.md\" --ignore \"breaking-changes.md\"",
|
||||
"lint:js-in-markdown": "electron-lint-markdown-standard --root docs \"**/*.md\"",
|
||||
"create-api-json": "node script/create-api-json.js",
|
||||
"create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --api=electron-api.json && node spec/ts-smoke/runner.js",
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
expose_ripemd160.patch
|
||||
expose_aes-cfb.patch
|
||||
expose_des-ede3.patch
|
||||
fix_sync_evp_get_cipherbynid_and_evp_get_cipherbyname.patch
|
||||
expose_blowfish_ciphers.patch
|
||||
revert_track_ssl_error_zero_return_explicitly.patch
|
||||
feat_expose_several_extra_cipher_functions.patch
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||
Date: Fri, 18 Jan 2019 14:23:28 -0800
|
||||
Subject: expose aes-{128,256}-cfb
|
||||
|
||||
This exposes AES-CFB ciphers through the EVP APIs. BoringSSL has
|
||||
implementations for these ciphers, but Node doesn't realise that because
|
||||
without this patch, they're not listed in the APIs that Node uses.
|
||||
|
||||
This should be upstreamed. See e.g.
|
||||
https://boringssl-review.googlesource.com/c/boringssl/+/33984 for a
|
||||
similar patch that was merged upstream.
|
||||
|
||||
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
|
||||
index 62850ab6a216d401d023f81007fb59a33b4585f3..0c30b0329d32b94b22f342f95035e927797d0aaf 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -73,6 +73,7 @@ static const struct {
|
||||
const EVP_CIPHER *(*func)(void);
|
||||
} kCiphers[] = {
|
||||
{NID_aes_128_cbc, "aes-128-cbc", EVP_aes_128_cbc},
|
||||
+ {NID_aes_128_cfb128, "aes-128-cfb", EVP_aes_128_cfb128},
|
||||
{NID_aes_128_ctr, "aes-128-ctr", EVP_aes_128_ctr},
|
||||
{NID_aes_128_ecb, "aes-128-ecb", EVP_aes_128_ecb},
|
||||
{NID_aes_128_gcm, "aes-128-gcm", EVP_aes_128_gcm},
|
||||
@@ -83,6 +84,7 @@ static const struct {
|
||||
{NID_aes_192_gcm, "aes-192-gcm", EVP_aes_192_gcm},
|
||||
{NID_aes_192_ofb128, "aes-192-ofb", EVP_aes_192_ofb},
|
||||
{NID_aes_256_cbc, "aes-256-cbc", EVP_aes_256_cbc},
|
||||
+ {NID_aes_256_cfb128, "aes-256-cfb", EVP_aes_256_cfb128},
|
||||
{NID_aes_256_ctr, "aes-256-ctr", EVP_aes_256_ctr},
|
||||
{NID_aes_256_ecb, "aes-256-ecb", EVP_aes_256_ecb},
|
||||
{NID_aes_256_gcm, "aes-256-gcm", EVP_aes_256_gcm},
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index 852b76bea69988e0b3ac76a17b603128f239dde0..d443f4dc2daea0b7aa86ae75d31d995fae667ba9 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -20,8 +20,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
const char *unused, void *arg),
|
||||
void *arg) {
|
||||
callback(EVP_aes_128_cbc(), "AES-128-CBC", NULL, arg);
|
||||
+ callback(EVP_aes_128_cfb128(), "AES-128-CFB", NULL, arg);
|
||||
callback(EVP_aes_192_cbc(), "AES-192-CBC", NULL, arg);
|
||||
callback(EVP_aes_256_cbc(), "AES-256-CBC", NULL, arg);
|
||||
+ callback(EVP_aes_256_cfb128(), "AES-256-CFB", NULL, arg);
|
||||
callback(EVP_aes_128_ctr(), "AES-128-CTR", NULL, arg);
|
||||
callback(EVP_aes_192_ctr(), "AES-192-CTR", NULL, arg);
|
||||
callback(EVP_aes_256_ctr(), "AES-256-CTR", NULL, arg);
|
||||
@@ -44,8 +46,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
|
||||
// OpenSSL returns everything twice, the second time in lower case.
|
||||
callback(EVP_aes_128_cbc(), "aes-128-cbc", NULL, arg);
|
||||
+ callback(EVP_aes_128_cfb128(), "aes-128-cfb", NULL, arg);
|
||||
callback(EVP_aes_192_cbc(), "aes-192-cbc", NULL, arg);
|
||||
callback(EVP_aes_256_cbc(), "aes-256-cbc", NULL, arg);
|
||||
+ callback(EVP_aes_256_cfb128(), "aes-256-cfb", NULL, arg);
|
||||
callback(EVP_aes_128_ctr(), "aes-128-ctr", NULL, arg);
|
||||
callback(EVP_aes_192_ctr(), "aes-192-ctr", NULL, arg);
|
||||
callback(EVP_aes_256_ctr(), "aes-256-ctr", NULL, arg);
|
||||
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
|
||||
index 310d7c237fd884ba715e3fa97ccf1393b6d04fbb..66e69d487fbb767438b7d0dfdf3770f54e3cf7b2 100644
|
||||
--- a/include/openssl/cipher.h
|
||||
+++ b/include/openssl/cipher.h
|
||||
@@ -476,6 +476,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void);
|
||||
|
||||
// EVP_aes_128_cfb128 is only available in decrepit.
|
||||
OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cfb128(void);
|
||||
+OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_cfb128(void);
|
||||
|
||||
// EVP_aes_128_cfb is an alias for |EVP_aes_128_cfb128| and is only available in
|
||||
// decrepit.
|
||||
@@ -1,47 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Rose <nornagon@nornagon.net>
|
||||
Date: Wed, 5 Jan 2022 13:08:10 -0800
|
||||
Subject: expose blowfish ciphers
|
||||
|
||||
This exposes the (decrepit) blowfish cipher family, bf-cbc, bf-cfb and
|
||||
bf-ecb through the EVP interface. This adds references to decrepit code
|
||||
from non-decrepit code, so upstream is unlikely to take the patch.
|
||||
|
||||
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
|
||||
index cfdb69e3c556fea11aa7c2d28d4b7da524df15c3..95bd172c99874610ec9157c52df4fe0232e78c7f 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -89,6 +89,9 @@ static const struct {
|
||||
{NID_aes_256_ecb, "aes-256-ecb", EVP_aes_256_ecb},
|
||||
{NID_aes_256_gcm, "aes-256-gcm", EVP_aes_256_gcm},
|
||||
{NID_aes_256_ofb128, "aes-256-ofb", EVP_aes_256_ofb},
|
||||
+ {NID_bf_cbc, "bf-cbc", EVP_bf_cbc},
|
||||
+ {NID_bf_cfb64, "bf-cfb", EVP_bf_cfb},
|
||||
+ {NID_bf_ecb, "bf-ecb", EVP_bf_ecb},
|
||||
{NID_des_cbc, "des-cbc", EVP_des_cbc},
|
||||
{NID_des_ecb, "des-ecb", EVP_des_ecb},
|
||||
{NID_des_ede_cbc, "des-ede-cbc", EVP_des_ede_cbc},
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index 5e71420b765019edea82a33884ace539cd91bda5..43fc792697519325725e9ce87801c5dc176c70a1 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -36,6 +36,9 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
callback(EVP_aes_128_gcm(), "AES-128-GCM", NULL, arg);
|
||||
callback(EVP_aes_192_gcm(), "AES-192-GCM", NULL, arg);
|
||||
callback(EVP_aes_256_gcm(), "AES-256-GCM", NULL, arg);
|
||||
+ callback(EVP_bf_cbc(), "BF-CBC", NULL, arg);
|
||||
+ callback(EVP_bf_cfb(), "BF-CFB", NULL, arg);
|
||||
+ callback(EVP_bf_ecb(), "BF-ECB", NULL, arg);
|
||||
callback(EVP_des_cbc(), "DES-CBC", NULL, arg);
|
||||
callback(EVP_des_ecb(), "DES-ECB", NULL, arg);
|
||||
callback(EVP_des_ede(), "DES-EDE", NULL, arg);
|
||||
@@ -63,6 +66,9 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
callback(EVP_aes_128_gcm(), "aes-128-gcm", NULL, arg);
|
||||
callback(EVP_aes_192_gcm(), "aes-192-gcm", NULL, arg);
|
||||
callback(EVP_aes_256_gcm(), "aes-256-gcm", NULL, arg);
|
||||
+ callback(EVP_bf_cbc(), "bf-cbc", NULL, arg);
|
||||
+ callback(EVP_bf_cfb(), "bf-cfb", NULL, arg);
|
||||
+ callback(EVP_bf_ecb(), "bf-ecb", NULL, arg);
|
||||
callback(EVP_des_cbc(), "des-cbc", NULL, arg);
|
||||
callback(EVP_des_ecb(), "des-ecb", NULL, arg);
|
||||
callback(EVP_des_ede(), "des-ede", NULL, arg);
|
||||
@@ -1,39 +0,0 @@
|
||||
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 0c30b0329d32b94b22f342f95035e927797d0aaf..d97f67fb03756169446edf6b41d3a33fe3ae8205 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -93,6 +93,7 @@ static const struct {
|
||||
{NID_des_ecb, "des-ecb", EVP_des_ecb},
|
||||
{NID_des_ede_cbc, "des-ede-cbc", EVP_des_ede_cbc},
|
||||
{NID_des_ede_ecb, "des-ede", EVP_des_ede},
|
||||
+ {NID_des_ede3_ecb, "des-ede3", EVP_des_ede3},
|
||||
{NID_des_ede3_cbc, "des-ede3-cbc", EVP_des_ede3_cbc},
|
||||
{NID_rc2_cbc, "rc2-cbc", EVP_rc2_cbc},
|
||||
{NID_rc4, "rc4", EVP_rc4},
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index d443f4dc2daea0b7aa86ae75d31d995fae667ba9..5e71420b765019edea82a33884ace539cd91bda5 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);
|
||||
@@ -0,0 +1,131 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Wed, 31 May 2023 11:36:48 +0200
|
||||
Subject: feat: expose several extra cipher functions
|
||||
|
||||
This patch exposes the following ciphers:
|
||||
|
||||
AES_CFB Ciphers: aes-128-cfb, aes-256-cfb
|
||||
|
||||
Implementations for these ciphers exist but aren't exposed, so they're
|
||||
unusable without this patch. We should upstream this as similar
|
||||
patches for implemented cipher functions have been accepted.
|
||||
|
||||
Blowfish Ciphers: bf-cbc, bf-cfb, bf-ecb
|
||||
|
||||
The addition of Blowfish ciphers adds references decrepit code
|
||||
from non-decrepit code, so upstream is unlikely to take the patch.
|
||||
|
||||
DES Ciphers: des-ede3
|
||||
|
||||
An implementation for this cipher exists but isn't exposed, so it's
|
||||
unusable without this patch. Akin to the AES_CFB exposures, we should
|
||||
upstream this as similar patches for implemented cipher functions have
|
||||
been accepted.
|
||||
|
||||
RC2 Ciphers: rc2-40-cbc
|
||||
|
||||
It's unclear whether this would be accepted upstream. We should try regardless.
|
||||
|
||||
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
|
||||
index 62850ab6a216d401d023f81007fb59a33b4585f3..95bd172c99874610ec9157c52df4fe0232e78c7f 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -73,6 +73,7 @@ static const struct {
|
||||
const EVP_CIPHER *(*func)(void);
|
||||
} kCiphers[] = {
|
||||
{NID_aes_128_cbc, "aes-128-cbc", EVP_aes_128_cbc},
|
||||
+ {NID_aes_128_cfb128, "aes-128-cfb", EVP_aes_128_cfb128},
|
||||
{NID_aes_128_ctr, "aes-128-ctr", EVP_aes_128_ctr},
|
||||
{NID_aes_128_ecb, "aes-128-ecb", EVP_aes_128_ecb},
|
||||
{NID_aes_128_gcm, "aes-128-gcm", EVP_aes_128_gcm},
|
||||
@@ -83,17 +84,23 @@ static const struct {
|
||||
{NID_aes_192_gcm, "aes-192-gcm", EVP_aes_192_gcm},
|
||||
{NID_aes_192_ofb128, "aes-192-ofb", EVP_aes_192_ofb},
|
||||
{NID_aes_256_cbc, "aes-256-cbc", EVP_aes_256_cbc},
|
||||
+ {NID_aes_256_cfb128, "aes-256-cfb", EVP_aes_256_cfb128},
|
||||
{NID_aes_256_ctr, "aes-256-ctr", EVP_aes_256_ctr},
|
||||
{NID_aes_256_ecb, "aes-256-ecb", EVP_aes_256_ecb},
|
||||
{NID_aes_256_gcm, "aes-256-gcm", EVP_aes_256_gcm},
|
||||
{NID_aes_256_ofb128, "aes-256-ofb", EVP_aes_256_ofb},
|
||||
+ {NID_bf_cbc, "bf-cbc", EVP_bf_cbc},
|
||||
+ {NID_bf_cfb64, "bf-cfb", EVP_bf_cfb},
|
||||
+ {NID_bf_ecb, "bf-ecb", EVP_bf_ecb},
|
||||
{NID_des_cbc, "des-cbc", EVP_des_cbc},
|
||||
{NID_des_ecb, "des-ecb", EVP_des_ecb},
|
||||
{NID_des_ede_cbc, "des-ede-cbc", EVP_des_ede_cbc},
|
||||
{NID_des_ede_ecb, "des-ede", EVP_des_ede},
|
||||
+ {NID_des_ede3_ecb, "des-ede3", EVP_des_ede3},
|
||||
{NID_des_ede3_cbc, "des-ede3-cbc", EVP_des_ede3_cbc},
|
||||
{NID_rc2_cbc, "rc2-cbc", EVP_rc2_cbc},
|
||||
{NID_rc4, "rc4", EVP_rc4},
|
||||
+ {NID_rc2_40_cbc, "rc2-40-cbc", EVP_rc2_40_cbc}
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index 852b76bea69988e0b3ac76a17b603128f239dde0..43fc792697519325725e9ce87801c5dc176c70a1 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -20,8 +20,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
const char *unused, void *arg),
|
||||
void *arg) {
|
||||
callback(EVP_aes_128_cbc(), "AES-128-CBC", NULL, arg);
|
||||
+ callback(EVP_aes_128_cfb128(), "AES-128-CFB", NULL, arg);
|
||||
callback(EVP_aes_192_cbc(), "AES-192-CBC", NULL, arg);
|
||||
callback(EVP_aes_256_cbc(), "AES-256-CBC", NULL, arg);
|
||||
+ callback(EVP_aes_256_cfb128(), "AES-256-CFB", NULL, arg);
|
||||
callback(EVP_aes_128_ctr(), "AES-128-CTR", NULL, arg);
|
||||
callback(EVP_aes_192_ctr(), "AES-192-CTR", NULL, arg);
|
||||
callback(EVP_aes_256_ctr(), "AES-256-CTR", NULL, arg);
|
||||
@@ -34,9 +36,13 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
callback(EVP_aes_128_gcm(), "AES-128-GCM", NULL, arg);
|
||||
callback(EVP_aes_192_gcm(), "AES-192-GCM", NULL, arg);
|
||||
callback(EVP_aes_256_gcm(), "AES-256-GCM", NULL, arg);
|
||||
+ callback(EVP_bf_cbc(), "BF-CBC", NULL, arg);
|
||||
+ callback(EVP_bf_cfb(), "BF-CFB", NULL, arg);
|
||||
+ callback(EVP_bf_ecb(), "BF-ECB", NULL, arg);
|
||||
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);
|
||||
@@ -44,8 +50,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
|
||||
// OpenSSL returns everything twice, the second time in lower case.
|
||||
callback(EVP_aes_128_cbc(), "aes-128-cbc", NULL, arg);
|
||||
+ callback(EVP_aes_128_cfb128(), "aes-128-cfb", NULL, arg);
|
||||
callback(EVP_aes_192_cbc(), "aes-192-cbc", NULL, arg);
|
||||
callback(EVP_aes_256_cbc(), "aes-256-cbc", NULL, arg);
|
||||
+ callback(EVP_aes_256_cfb128(), "aes-256-cfb", NULL, arg);
|
||||
callback(EVP_aes_128_ctr(), "aes-128-ctr", NULL, arg);
|
||||
callback(EVP_aes_192_ctr(), "aes-192-ctr", NULL, arg);
|
||||
callback(EVP_aes_256_ctr(), "aes-256-ctr", NULL, arg);
|
||||
@@ -58,9 +66,13 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
callback(EVP_aes_128_gcm(), "aes-128-gcm", NULL, arg);
|
||||
callback(EVP_aes_192_gcm(), "aes-192-gcm", NULL, arg);
|
||||
callback(EVP_aes_256_gcm(), "aes-256-gcm", NULL, arg);
|
||||
+ callback(EVP_bf_cbc(), "bf-cbc", NULL, arg);
|
||||
+ callback(EVP_bf_cfb(), "bf-cfb", NULL, arg);
|
||||
+ callback(EVP_bf_ecb(), "bf-ecb", NULL, arg);
|
||||
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);
|
||||
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
|
||||
index 310d7c237fd884ba715e3fa97ccf1393b6d04fbb..66e69d487fbb767438b7d0dfdf3770f54e3cf7b2 100644
|
||||
--- a/include/openssl/cipher.h
|
||||
+++ b/include/openssl/cipher.h
|
||||
@@ -476,6 +476,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void);
|
||||
|
||||
// EVP_aes_128_cfb128 is only available in decrepit.
|
||||
OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cfb128(void);
|
||||
+OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_cfb128(void);
|
||||
|
||||
// EVP_aes_128_cfb is an alias for |EVP_aes_128_cfb128| and is only available in
|
||||
// decrepit.
|
||||
@@ -1,25 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 28 Jun 2021 10:41:09 +0200
|
||||
Subject: fix: sync EVP_get_cipherbynid and EVP_get_cipherbyname
|
||||
|
||||
This commit syncs the results of EVP_get_cipherbynid and
|
||||
EVP_get_cipherbyname. Node.js logic assumes that calling EVP_get_cipherbynid
|
||||
on a NID returned from a call to `getCipherInfo` with the cipher name
|
||||
will return the same cipher information - this assumption holds in OpenSSL
|
||||
and should also hold in BoringSSL.
|
||||
|
||||
This will be upstreamed.
|
||||
|
||||
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
|
||||
index d97f67fb03756169446edf6b41d3a33fe3ae8205..cfdb69e3c556fea11aa7c2d28d4b7da524df15c3 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -97,6 +97,7 @@ static const struct {
|
||||
{NID_des_ede3_cbc, "des-ede3-cbc", EVP_des_ede3_cbc},
|
||||
{NID_rc2_cbc, "rc2-cbc", EVP_rc2_cbc},
|
||||
{NID_rc4, "rc4", EVP_rc4},
|
||||
+ {NID_rc2_40_cbc, "rc2-40-cbc", EVP_rc2_40_cbc}
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
|
||||
@@ -128,3 +128,10 @@ fix_x11_window_restore_minimized_maximized_window.patch
|
||||
chore_defer_usb_service_getdevices_request_until_usb_service_is.patch
|
||||
revert_x11_keep_windowcache_alive_for_a_time_interval.patch
|
||||
cherry-pick-ec53103cc72d.patch
|
||||
cherry-pick-94af9d13a14b.patch
|
||||
cherry-pick-ea1cd76358e0.patch
|
||||
m114_merge_fix_a_crash_caused_by_calling_trace_event.patch
|
||||
mojoipcz_copy_incoming_messages_early.patch
|
||||
base_do_not_use_va_args_twice_in_asprintf.patch
|
||||
cherry-pick-85beff6fd302.patch
|
||||
cherry-pick-60b93798c991.patch
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benoit Lize <lizeb@chromium.org>
|
||||
Date: Fri, 9 Jun 2023 17:59:08 +0000
|
||||
Subject: Do not use va_args twice in asprintf()
|
||||
|
||||
(cherry picked from commit 3cff0cb19a6d01cbdd9932f43dabaaeda9c0330a)
|
||||
|
||||
Bug: 1450536
|
||||
Change-Id: Ib34d96935278869a63897f9a1c66afc98865d90f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4579347
|
||||
Reviewed-by: Egor Pasko <pasko@chromium.org>
|
||||
Commit-Queue: Benoit Lize <lizeb@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1151796}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4604070
|
||||
Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1224}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
index 621873126602463a09efca1bf1548ed10910d323..de2af6d7d54e254b9e7b8264b53d30a338fb13e8 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
@@ -123,13 +123,21 @@ SHIM_ALWAYS_EXPORT char* __wrap_getcwd(char* buffer, size_t size) {
|
||||
SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
const char* fmt,
|
||||
va_list va_args) {
|
||||
+ // There are cases where we need to use the list of arguments twice, namely
|
||||
+ // when the original buffer is too small. It is not allowed to walk the list
|
||||
+ // twice, so make a copy for the second invocation of vsnprintf().
|
||||
+ va_list va_args_copy;
|
||||
+ va_copy(va_args_copy, va_args);
|
||||
+
|
||||
constexpr int kInitialSize = 128;
|
||||
*strp = static_cast<char*>(
|
||||
malloc(kInitialSize)); // Our malloc() doesn't return nullptr.
|
||||
|
||||
int actual_size = vsnprintf(*strp, kInitialSize, fmt, va_args);
|
||||
- if (actual_size < 0)
|
||||
+ if (actual_size < 0) {
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
+ }
|
||||
*strp =
|
||||
static_cast<char*>(realloc(*strp, static_cast<size_t>(actual_size + 1)));
|
||||
|
||||
@@ -139,9 +147,14 @@ SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
//
|
||||
// This is very lightly used in Chromium in practice, see crbug.com/116558 for
|
||||
// details.
|
||||
- if (actual_size >= kInitialSize)
|
||||
- return vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt, va_args);
|
||||
-
|
||||
+ if (actual_size >= kInitialSize) {
|
||||
+ int ret = vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt,
|
||||
+ va_args_copy);
|
||||
+ va_end(va_args_copy);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
index dcf26fa5fc6d51de6276aa6fdcc4691f781c4bfd..fd46a15799864acaf58ef57315606bf515b48b15 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
@@ -734,6 +734,28 @@ TEST_F(AllocatorShimTest, InterceptVasprintf) {
|
||||
// Should not crash.
|
||||
}
|
||||
|
||||
+TEST_F(AllocatorShimTest, InterceptLongVasprintf) {
|
||||
+ char* str = nullptr;
|
||||
+ const char* lorem_ipsum =
|
||||
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. "
|
||||
+ "Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, "
|
||||
+ "ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula "
|
||||
+ "massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci "
|
||||
+ "nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit "
|
||||
+ "amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat "
|
||||
+ "in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero "
|
||||
+ "pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo "
|
||||
+ "in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue "
|
||||
+ "blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus "
|
||||
+ "et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed "
|
||||
+ "pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales "
|
||||
+ "hendrerit.";
|
||||
+ int err = asprintf(&str, "%s", lorem_ipsum);
|
||||
+ EXPECT_EQ(err, static_cast<int>(strlen(lorem_ipsum)));
|
||||
+ EXPECT_TRUE(str);
|
||||
+ free(str);
|
||||
+}
|
||||
+
|
||||
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
|
||||
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
99
patches/chromium/cherry-pick-60b93798c991.patch
Normal file
99
patches/chromium/cherry-pick-60b93798c991.patch
Normal file
@@ -0,0 +1,99 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eugene Zemtsov <eugene@chromium.org>
|
||||
Date: Wed, 21 Jun 2023 17:57:52 +0000
|
||||
Subject: webcodecs: Fix crash when changing temporal layer count in AV1
|
||||
encoder
|
||||
|
||||
(cherry picked from commit f312efac1b90117729e8961b58c643fc0eae1fbd)
|
||||
|
||||
Bug: 1447568
|
||||
Change-Id: I4ecb02ed956707571573a65ade17fdffe676b502
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4554300
|
||||
Auto-Submit: Eugene Zemtsov <eugene@chromium.org>
|
||||
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
|
||||
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1148041}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4610718
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1360}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/media/video/av1_video_encoder.cc b/media/video/av1_video_encoder.cc
|
||||
index 19796f667564412391abdb9d28f900f0364e37e3..72e4184861b6eb837a5d4830140d720b28c90f0f 100644
|
||||
--- a/media/video/av1_video_encoder.cc
|
||||
+++ b/media/video/av1_video_encoder.cc
|
||||
@@ -119,6 +119,7 @@ EncoderStatus SetUpAomConfig(const VideoEncoder::Options& opts,
|
||||
svc_params = {};
|
||||
svc_params.framerate_factor[0] = 1;
|
||||
svc_params.number_spatial_layers = 1;
|
||||
+ svc_params.number_temporal_layers = 1;
|
||||
if (opts.scalability_mode.has_value()) {
|
||||
switch (opts.scalability_mode.value()) {
|
||||
case SVCScalabilityMode::kL1T1:
|
||||
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc
|
||||
index c05337f87ff4b8e3a8baf4a417a7dcfc3a2074cc..7954254f7ebf21d7375fb7661cbeb3276a5a4e7f 100644
|
||||
--- a/media/video/software_video_encoder_test.cc
|
||||
+++ b/media/video/software_video_encoder_test.cc
|
||||
@@ -612,6 +612,63 @@ TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) {
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_P(SVCVideoEncoderTest, ChangeLayers) {
|
||||
+ VideoEncoder::Options options;
|
||||
+ options.frame_size = gfx::Size(640, 480);
|
||||
+ options.bitrate = Bitrate::ConstantBitrate(1000000u); // 1Mbps
|
||||
+ options.framerate = 25;
|
||||
+ options.scalability_mode = GetParam().scalability_mode;
|
||||
+ std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
|
||||
+
|
||||
+ std::vector<VideoEncoderOutput> chunks;
|
||||
+ size_t total_frames_count = 80;
|
||||
+
|
||||
+ // Encoder all frames with 3 temporal layers and put all outputs in |chunks|
|
||||
+ auto frame_duration = base::Seconds(1.0 / options.framerate.value());
|
||||
+
|
||||
+ VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
|
||||
+ [&](VideoEncoderOutput output,
|
||||
+ absl::optional<VideoEncoder::CodecDescription> desc) {
|
||||
+ chunks.push_back(std::move(output));
|
||||
+ });
|
||||
+
|
||||
+ encoder_->Initialize(profile_, options, /*info_cb=*/base::DoNothing(),
|
||||
+ std::move(encoder_output_cb),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+
|
||||
+ uint32_t color = 0x964050;
|
||||
+ for (auto frame_index = 0u; frame_index < total_frames_count; frame_index++) {
|
||||
+ auto timestamp = frame_index * frame_duration;
|
||||
+
|
||||
+ const bool reconfigure = (frame_index == total_frames_count / 2);
|
||||
+ if (reconfigure) {
|
||||
+ encoder_->Flush(ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+
|
||||
+ // Ask encoder to change SVC mode, empty output callback
|
||||
+ // means the encoder should keep the old one.
|
||||
+ options.scalability_mode = SVCScalabilityMode::kL1T1;
|
||||
+ encoder_->ChangeOptions(
|
||||
+ options, VideoEncoder::OutputCB(),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ }
|
||||
+
|
||||
+ auto frame =
|
||||
+ CreateFrame(options.frame_size, pixel_format_, timestamp, color);
|
||||
+ color = (color << 1) + frame_index;
|
||||
+ frames_to_encode.push_back(frame);
|
||||
+ encoder_->Encode(frame, VideoEncoder::EncodeOptions(false),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ }
|
||||
+
|
||||
+ encoder_->Flush(ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ EXPECT_EQ(chunks.size(), total_frames_count);
|
||||
+}
|
||||
+
|
||||
TEST_P(H264VideoEncoderTest, ReconfigureWithResize) {
|
||||
VideoEncoder::Options options;
|
||||
gfx::Size size1(320, 200), size2(400, 240);
|
||||
215
patches/chromium/cherry-pick-85beff6fd302.patch
Normal file
215
patches/chromium/cherry-pick-85beff6fd302.patch
Normal file
@@ -0,0 +1,215 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin McNee <mcnee@chromium.org>
|
||||
Date: Wed, 14 Jun 2023 01:10:19 +0000
|
||||
Subject: M114: Don't recursively destroy guests when clearing unattached
|
||||
guests
|
||||
|
||||
Don't recursively destroy guests when clearing unattached guests
|
||||
|
||||
When an embedder process is destroyed, we also destroy any unattached
|
||||
guests associated with that process. This is currently done with a
|
||||
single call to `owned_guests_.erase`. However, it's possible that two
|
||||
unattached guests could have an opener relationship, which causes the
|
||||
destruction of the opener guest to also destroy the other guest, during
|
||||
the call to `erase`, which is unsafe.
|
||||
|
||||
We now separate the steps of erasing `owned_guests_` and destroying the
|
||||
guests, to avoid this recursive guest destruction.
|
||||
|
||||
This also fixes the WaitForNumGuestsCreated test method to not
|
||||
return prematurely.
|
||||
|
||||
(cherry picked from commit 6345e7871e8197af92f9c6158b06c6e197f87945)
|
||||
|
||||
Bug: 1450397
|
||||
Change-Id: Ifef5ec9ff3a1e6952ff56ec279e29e8522625ac0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4589949
|
||||
Commit-Queue: Kevin McNee <mcnee@chromium.org>
|
||||
Auto-Submit: Kevin McNee <mcnee@chromium.org>
|
||||
Reviewed-by: James Maclean <wjmaclean@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1153396}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4611152
|
||||
Commit-Queue: James Maclean <wjmaclean@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1292}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
index c5167c135a7e41705ac018d3aec568c65fdcb0dc..bdfbf5c75a4275d4a395ff182cbfeda3cb2cc699 100644
|
||||
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
@@ -2884,6 +2884,22 @@ IN_PROC_BROWSER_TEST_P(WebViewNewWindowTest,
|
||||
EXPECT_TRUE(content::NavigateToURLFromRenderer(guest2, coop_url));
|
||||
}
|
||||
|
||||
+// This test creates a situation where we have two unattached webviews which
|
||||
+// have an opener relationship, and ensures that we can shutdown safely. See
|
||||
+// https://crbug.com/1450397.
|
||||
+IN_PROC_BROWSER_TEST_P(WebViewNewWindowTest, DestroyOpenerBeforeAttachment) {
|
||||
+ TestHelper("testDestroyOpenerBeforeAttachment", "web_view/newwindow",
|
||||
+ NEEDS_TEST_SERVER);
|
||||
+ GetGuestViewManager()->WaitForNumGuestsCreated(2);
|
||||
+
|
||||
+ content::RenderProcessHost* embedder_rph =
|
||||
+ GetEmbedderWebContents()->GetPrimaryMainFrame()->GetProcess();
|
||||
+ content::RenderProcessHostWatcher kill_observer(
|
||||
+ embedder_rph, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
|
||||
+ EXPECT_TRUE(embedder_rph->Shutdown(content::RESULT_CODE_KILLED));
|
||||
+ kill_observer.Wait();
|
||||
+}
|
||||
+
|
||||
IN_PROC_BROWSER_TEST_P(WebViewTest, ContextMenuInspectElement) {
|
||||
LoadAppWithGuest("web_view/context_menus/basic");
|
||||
content::RenderFrameHost* guest_rfh = GetGuestRenderFrameHost();
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
index 900911f4963d23d74225868dce01326ba533f63a..4dd25d8849b0b13957ab7fa2912c0a158d3cd244 100644
|
||||
--- a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
@@ -34,6 +34,9 @@ embedder.setUp_ = function(config) {
|
||||
embedder.guestWithLinkURL = embedder.baseGuestURL +
|
||||
'/extensions/platform_apps/web_view/newwindow' +
|
||||
'/guest_with_link.html';
|
||||
+ embedder.guestOpenOnLoadURL = embedder.baseGuestURL +
|
||||
+ '/extensions/platform_apps/web_view/newwindow' +
|
||||
+ '/guest_opener_open_on_load.html';
|
||||
};
|
||||
|
||||
/** @private */
|
||||
@@ -652,6 +655,24 @@ function testNewWindowDeferredAttachmentIndefinitely() {
|
||||
embedder.setUpNewWindowRequest_(webview, 'guest.html', '', testName);
|
||||
}
|
||||
|
||||
+// This is not a test in and of itself, but a means of creating a webview that
|
||||
+// is left in an unattached state while its opener webview is also in an
|
||||
+// unattached state, so that the C++ side can test it in that state.
|
||||
+function testDestroyOpenerBeforeAttachment() {
|
||||
+ embedder.test.succeed();
|
||||
+
|
||||
+ let webview = new WebView();
|
||||
+ webview.src = embedder.guestOpenOnLoadURL;
|
||||
+ document.body.appendChild(webview);
|
||||
+
|
||||
+ // By spinning forever here, we prevent `webview` from completing the
|
||||
+ // attachment process. But since the guest is still created and it calls
|
||||
+ // window.open, we have a situation where two unattached webviews have an
|
||||
+ // opener relationship. The C++ side will test that we can shutdown safely in
|
||||
+ // this case.
|
||||
+ while (true) {}
|
||||
+}
|
||||
+
|
||||
embedder.test.testList = {
|
||||
'testNewWindowAttachAfterOpenerDestroyed':
|
||||
testNewWindowAttachAfterOpenerDestroyed,
|
||||
@@ -675,7 +696,9 @@ embedder.test.testList = {
|
||||
testNewWindowWebViewNameTakesPrecedence,
|
||||
'testNewWindowAndUpdateOpener': testNewWindowAndUpdateOpener,
|
||||
'testNewWindowDeferredAttachmentIndefinitely':
|
||||
- testNewWindowDeferredAttachmentIndefinitely
|
||||
+ testNewWindowDeferredAttachmentIndefinitely,
|
||||
+ 'testDestroyOpenerBeforeAttachment':
|
||||
+ testDestroyOpenerBeforeAttachment
|
||||
};
|
||||
|
||||
onload = function() {
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html b/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e961feb3c6487066801adf414bf4a2746c50a3f6
|
||||
--- /dev/null
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html
|
||||
@@ -0,0 +1,13 @@
|
||||
+<!--
|
||||
+Copyright 2023 The Chromium Authors
|
||||
+Use of this source code is governed by a BSD-style license that can be
|
||||
+found in the LICENSE file.
|
||||
+-->
|
||||
+<html>
|
||||
+<body>
|
||||
+<script>
|
||||
+ // A guest that opens a new window on load.
|
||||
+ window.open('guest.html');
|
||||
+</script>
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/components/guest_view/browser/guest_view_manager.cc b/components/guest_view/browser/guest_view_manager.cc
|
||||
index 6b18dc43962386c11c9b656a0f74ae6867b50cd4..eecc03787430cfdbbf1804ebb5245fd6abf731db 100644
|
||||
--- a/components/guest_view/browser/guest_view_manager.cc
|
||||
+++ b/components/guest_view/browser/guest_view_manager.cc
|
||||
@@ -332,7 +332,20 @@ void GuestViewManager::RemoveGuest(int guest_instance_id, bool invalidate_id) {
|
||||
|
||||
void GuestViewManager::EmbedderProcessDestroyed(int embedder_process_id) {
|
||||
embedders_observed_.erase(embedder_process_id);
|
||||
+
|
||||
+ // We can't just call std::multimap::erase here because destroying a guest
|
||||
+ // could trigger the destruction of another guest which is also owned by
|
||||
+ // `owned_guests_`. Recursively calling std::multimap::erase is unsafe (see
|
||||
+ // https://crbug.com/1450397). So we take ownership of all of the guests that
|
||||
+ // will be destroyed before erasing the entries from the map.
|
||||
+ std::vector<std::unique_ptr<GuestViewBase>> guests_to_destroy;
|
||||
+ const auto destroy_range = owned_guests_.equal_range(embedder_process_id);
|
||||
+ for (auto it = destroy_range.first; it != destroy_range.second; ++it) {
|
||||
+ guests_to_destroy.push_back(std::move(it->second));
|
||||
+ }
|
||||
owned_guests_.erase(embedder_process_id);
|
||||
+ guests_to_destroy.clear();
|
||||
+
|
||||
CallViewDestructionCallbacks(embedder_process_id);
|
||||
}
|
||||
|
||||
diff --git a/components/guest_view/browser/test_guest_view_manager.cc b/components/guest_view/browser/test_guest_view_manager.cc
|
||||
index a0fb5885084cb04688770323c940825ca8e0b6d5..44e264730e2a21d613f4515e8552ad81703f062b 100644
|
||||
--- a/components/guest_view/browser/test_guest_view_manager.cc
|
||||
+++ b/components/guest_view/browser/test_guest_view_manager.cc
|
||||
@@ -37,7 +37,6 @@ TestGuestViewManager::TestGuestViewManager(
|
||||
num_guests_created_(0),
|
||||
expected_num_guests_created_(0),
|
||||
num_views_garbage_collected_(0),
|
||||
- waiting_for_guests_created_(false),
|
||||
waiting_for_attach_(nullptr) {}
|
||||
|
||||
TestGuestViewManager::~TestGuestViewManager() = default;
|
||||
@@ -128,14 +127,15 @@ GuestViewBase* TestGuestViewManager::WaitForNextGuestViewCreated() {
|
||||
}
|
||||
|
||||
void TestGuestViewManager::WaitForNumGuestsCreated(size_t count) {
|
||||
- if (count == num_guests_created_)
|
||||
+ if (count == num_guests_created_) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
- waiting_for_guests_created_ = true;
|
||||
expected_num_guests_created_ = count;
|
||||
|
||||
num_created_run_loop_ = std::make_unique<base::RunLoop>();
|
||||
num_created_run_loop_->Run();
|
||||
+ num_created_run_loop_ = nullptr;
|
||||
}
|
||||
|
||||
void TestGuestViewManager::WaitUntilAttached(GuestViewBase* guest_view) {
|
||||
@@ -180,13 +180,11 @@ void TestGuestViewManager::AddGuest(int guest_instance_id,
|
||||
created_run_loop_->Quit();
|
||||
|
||||
++num_guests_created_;
|
||||
- if (!waiting_for_guests_created_ &&
|
||||
- num_guests_created_ != expected_num_guests_created_) {
|
||||
- return;
|
||||
- }
|
||||
|
||||
- if (num_created_run_loop_)
|
||||
+ if (num_created_run_loop_ &&
|
||||
+ num_guests_created_ == expected_num_guests_created_) {
|
||||
num_created_run_loop_->Quit();
|
||||
+ }
|
||||
}
|
||||
|
||||
void TestGuestViewManager::AttachGuest(int embedder_process_id,
|
||||
diff --git a/components/guest_view/browser/test_guest_view_manager.h b/components/guest_view/browser/test_guest_view_manager.h
|
||||
index 094524fad8b5d46cc938e8ac8559bac019b25c09..0c0b718be474335bf95767308f400e40379775d1 100644
|
||||
--- a/components/guest_view/browser/test_guest_view_manager.h
|
||||
+++ b/components/guest_view/browser/test_guest_view_manager.h
|
||||
@@ -120,7 +120,6 @@ class TestGuestViewManager : public GuestViewManager {
|
||||
size_t num_guests_created_;
|
||||
size_t expected_num_guests_created_;
|
||||
int num_views_garbage_collected_;
|
||||
- bool waiting_for_guests_created_;
|
||||
|
||||
// Tracks the life time of the GuestView's main FrameTreeNode. The main FTN
|
||||
// has the same lifesspan as the GuestView.
|
||||
35
patches/chromium/cherry-pick-94af9d13a14b.patch
Normal file
35
patches/chromium/cherry-pick-94af9d13a14b.patch
Normal file
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ivan Pavlotsky <ivan.pavlotsky@lge.com>
|
||||
Date: Mon, 1 May 2023 07:48:23 +0000
|
||||
Subject: Check nullptr in ZWPTextInputWrapperV1::Activate()
|
||||
|
||||
After the CL https://crrev.com/c/4160118 a crash occurres on the
|
||||
wl::get_version_of_object() call in ZWPTextInputWrapperV1::Activate()
|
||||
when |ZWPTextInputWrapperV1::extended_obj_| is not set.
|
||||
|
||||
Added nullptr check to fix it.
|
||||
|
||||
Bug: b:251677220, 1431532
|
||||
Change-Id: Ia5606f1c0d08f552f1091b2a9350655f4bdac939
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4423030
|
||||
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
|
||||
Reviewed-by: Maksim Sisov <msisov@igalia.com>
|
||||
Commit-Queue: Maksim Sisov <msisov@igalia.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#1137771}
|
||||
|
||||
diff --git a/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
|
||||
index d577ac4f822901340281c48bc754425484f28f48..b9e508824c7cb17c0673007532f88242a99fa5df 100644
|
||||
--- a/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
|
||||
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
|
||||
@@ -156,8 +156,9 @@ void ZWPTextInputWrapperV1::Reset() {
|
||||
void ZWPTextInputWrapperV1::Activate(WaylandWindow* window,
|
||||
TextInputClient::FocusReason reason) {
|
||||
DCHECK(connection_->seat());
|
||||
- if (wl::get_version_of_object(extended_obj_.get()) >=
|
||||
- ZCR_EXTENDED_TEXT_INPUT_V1_SET_FOCUS_REASON_SINCE_VERSION) {
|
||||
+ if (extended_obj_.get() &&
|
||||
+ wl::get_version_of_object(extended_obj_.get()) >=
|
||||
+ ZCR_EXTENDED_TEXT_INPUT_V1_SET_FOCUS_REASON_SINCE_VERSION) {
|
||||
absl::optional<uint32_t> wayland_focus_reason;
|
||||
switch (reason) {
|
||||
case ui::TextInputClient::FocusReason::FOCUS_REASON_NONE:
|
||||
200
patches/chromium/cherry-pick-ea1cd76358e0.patch
Normal file
200
patches/chromium/cherry-pick-ea1cd76358e0.patch
Normal file
@@ -0,0 +1,200 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin McNee <mcnee@chromium.org>
|
||||
Date: Tue, 23 May 2023 15:46:16 +0000
|
||||
Subject: M114: Compute all webview find options before cloning them
|
||||
|
||||
Compute all webview find options before cloning them
|
||||
|
||||
In WebViewFindHelper::Find, we're cloning the find options before we've
|
||||
set the value for `new_session`. For requests that are part of the same
|
||||
session, in WebViewFindHelper::FindReply, we're using the incorrect
|
||||
value for `new_session` and we're destroying the FindInfo for what we
|
||||
think is a previous session but is actually for the request we're
|
||||
currently processing.
|
||||
|
||||
We now fully compute the options before cloning them.
|
||||
|
||||
(cherry picked from commit bb8e17b942b8b1de0a58b2dce34197e00a3b6525)
|
||||
|
||||
Bug: 1443401
|
||||
Change-Id: Ife6747aedabaf74f9a4855a173349ffe612b6f95
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4533923
|
||||
Reviewed-by: James Maclean <wjmaclean@chromium.org>
|
||||
Commit-Queue: James Maclean <wjmaclean@chromium.org>
|
||||
Auto-Submit: Kevin McNee <mcnee@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1145265}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4556646
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#941}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
index 7762464ba5eb84702021f8328e455e0d05e87b46..c5167c135a7e41705ac018d3aec568c65fdcb0dc 100644
|
||||
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
@@ -3983,6 +3983,11 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_testFindInMultipleWebViews) {
|
||||
TestHelper("testFindInMultipleWebViews", "web_view/shim", NO_TEST_SERVER);
|
||||
}
|
||||
|
||||
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestFindAfterTerminate) {
|
||||
+ content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
|
||||
+ TestHelper("testFindAfterTerminate", "web_view/shim", NO_TEST_SERVER);
|
||||
+}
|
||||
+
|
||||
IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_TestLoadDataAPI) {
|
||||
TestHelper("testLoadDataAPI", "web_view/shim", NEEDS_TEST_SERVER);
|
||||
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
|
||||
index 12c29cc718765d0f04b81430011569786587f677..c252e13563dff2660af1187ce3a16d5997f0679d 100644
|
||||
--- a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
|
||||
@@ -2868,6 +2868,20 @@ function testFindInMultipleWebViews() {
|
||||
});
|
||||
}
|
||||
|
||||
+function testFindAfterTerminate() {
|
||||
+ let webview = new WebView();
|
||||
+ webview.src = 'data:text/html,<body><iframe></iframe></body>';
|
||||
+ webview.addEventListener('loadstop', () => {
|
||||
+ webview.find('A');
|
||||
+ webview.terminate();
|
||||
+ webview.find('B', {'backward': true});
|
||||
+ webview.find('B', {'backward': true}, (results) => {
|
||||
+ embedder.test.succeed();
|
||||
+ });
|
||||
+ });
|
||||
+ document.body.appendChild(webview);
|
||||
+}
|
||||
+
|
||||
function testLoadDataAPI() {
|
||||
var webview = new WebView();
|
||||
webview.src = 'about:blank';
|
||||
@@ -3644,6 +3658,7 @@ embedder.test.testList = {
|
||||
'testFindAPI': testFindAPI,
|
||||
'testFindAPI_findupdate': testFindAPI_findupdate,
|
||||
'testFindInMultipleWebViews': testFindInMultipleWebViews,
|
||||
+ 'testFindAfterTerminate': testFindAfterTerminate,
|
||||
'testLoadDataAPI': testLoadDataAPI,
|
||||
'testLoadDataAPIAccessibleResources': testLoadDataAPIAccessibleResources,
|
||||
'testResizeEvents': testResizeEvents,
|
||||
diff --git a/extensions/browser/guest_view/web_view/web_view_find_helper.cc b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
|
||||
index 0913a8f3da48420c6b0fd328d37268ca5b0e6e63..3e70549084be8537198996c07d2f61c6308ad893 100644
|
||||
--- a/extensions/browser/guest_view/web_view/web_view_find_helper.cc
|
||||
+++ b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
|
||||
@@ -36,12 +36,12 @@ void WebViewFindHelper::CancelAllFindSessions() {
|
||||
|
||||
void WebViewFindHelper::DispatchFindUpdateEvent(bool canceled,
|
||||
bool final_update) {
|
||||
- DCHECK(find_update_event_.get());
|
||||
+ CHECK(find_update_event_);
|
||||
base::Value::Dict args;
|
||||
find_update_event_->PrepareResults(args);
|
||||
args.Set(webview::kFindCanceled, canceled);
|
||||
args.Set(webview::kFindFinalUpdate, final_update);
|
||||
- DCHECK(webview_guest_);
|
||||
+ CHECK(webview_guest_);
|
||||
webview_guest_->DispatchEventToView(std::make_unique<GuestViewEvent>(
|
||||
webview::kEventFindReply, std::move(args)));
|
||||
}
|
||||
@@ -94,6 +94,17 @@ void WebViewFindHelper::Find(
|
||||
// Need a new request_id for each new find request.
|
||||
++current_find_request_id_;
|
||||
|
||||
+ if (current_find_session_) {
|
||||
+ const std::u16string& current_search_text =
|
||||
+ current_find_session_->search_text();
|
||||
+ bool current_match_case = current_find_session_->options()->match_case;
|
||||
+ options->new_session = current_search_text.empty() ||
|
||||
+ current_search_text != search_text ||
|
||||
+ current_match_case != options->match_case;
|
||||
+ } else {
|
||||
+ options->new_session = true;
|
||||
+ }
|
||||
+
|
||||
// Stores the find request information by request_id so that its callback
|
||||
// function can be called when the find results are available.
|
||||
std::pair<FindInfoMap::iterator, bool> insert_result =
|
||||
@@ -102,32 +113,19 @@ void WebViewFindHelper::Find(
|
||||
base::MakeRefCounted<FindInfo>(current_find_request_id_, search_text,
|
||||
options.Clone(), find_function)));
|
||||
// No duplicate insertions.
|
||||
- DCHECK(insert_result.second);
|
||||
-
|
||||
- blink::mojom::FindOptionsPtr full_options =
|
||||
- insert_result.first->second->options().Clone();
|
||||
-
|
||||
- if (current_find_session_) {
|
||||
- const std::u16string& current_search_text =
|
||||
- current_find_session_->search_text();
|
||||
- bool current_match_case = current_find_session_->options()->match_case;
|
||||
- full_options->new_session = current_search_text.empty() ||
|
||||
- current_search_text != search_text ||
|
||||
- current_match_case != options->match_case;
|
||||
- } else {
|
||||
- full_options->new_session = true;
|
||||
- }
|
||||
+ CHECK(insert_result.second);
|
||||
|
||||
// Link find requests that are a part of the same find session.
|
||||
- if (!full_options->new_session && current_find_session_) {
|
||||
- DCHECK(current_find_request_id_ != current_find_session_->request_id());
|
||||
+ if (!options->new_session && current_find_session_) {
|
||||
+ CHECK(current_find_request_id_ != current_find_session_->request_id());
|
||||
current_find_session_->AddFindNextRequest(
|
||||
insert_result.first->second->AsWeakPtr());
|
||||
}
|
||||
|
||||
// Update the current find session, if necessary.
|
||||
- if (full_options->new_session)
|
||||
+ if (options->new_session) {
|
||||
current_find_session_ = insert_result.first->second;
|
||||
+ }
|
||||
|
||||
// Handle the empty |search_text| case internally.
|
||||
if (search_text.empty()) {
|
||||
@@ -137,7 +135,7 @@ void WebViewFindHelper::Find(
|
||||
}
|
||||
|
||||
guest_web_contents->Find(current_find_request_id_, search_text,
|
||||
- std::move(full_options), /*skip_delay=*/true);
|
||||
+ std::move(options), /*skip_delay=*/true);
|
||||
}
|
||||
|
||||
void WebViewFindHelper::FindReply(int request_id,
|
||||
@@ -152,14 +150,14 @@ void WebViewFindHelper::FindReply(int request_id,
|
||||
return;
|
||||
|
||||
// This find request must be a part of an existing find session.
|
||||
- DCHECK(current_find_session_);
|
||||
+ CHECK(current_find_session_);
|
||||
|
||||
WebViewFindHelper::FindInfo* find_info = find_iterator->second.get();
|
||||
// Handle canceled find requests.
|
||||
if (find_info->options()->new_session &&
|
||||
find_info_map_.begin()->first < request_id) {
|
||||
- DCHECK_NE(current_find_session_->request_id(),
|
||||
- find_info_map_.begin()->first);
|
||||
+ CHECK_NE(current_find_session_->request_id(),
|
||||
+ find_info_map_.begin()->first);
|
||||
if (find_update_event_)
|
||||
DispatchFindUpdateEvent(true /* canceled */, true /* final_update */);
|
||||
EndFindSession(find_info_map_.begin()->first, true /* canceled */);
|
||||
@@ -174,11 +172,12 @@ void WebViewFindHelper::FindReply(int request_id,
|
||||
// Aggregate the find results.
|
||||
find_info->AggregateResults(number_of_matches, selection_rect,
|
||||
active_match_ordinal, final_update);
|
||||
- find_update_event_->AggregateResults(number_of_matches, selection_rect,
|
||||
- active_match_ordinal, final_update);
|
||||
-
|
||||
- // Propagate incremental results to the |findupdate| event.
|
||||
- DispatchFindUpdateEvent(false /* canceled */, final_update);
|
||||
+ if (find_update_event_) {
|
||||
+ find_update_event_->AggregateResults(number_of_matches, selection_rect,
|
||||
+ active_match_ordinal, final_update);
|
||||
+ // Propagate incremental results to the |findupdate| event.
|
||||
+ DispatchFindUpdateEvent(false /* canceled */, final_update);
|
||||
+ }
|
||||
|
||||
// Call the callback functions of completed find requests.
|
||||
if (final_update)
|
||||
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Maggie Chen <magchen@chromium.org>
|
||||
Date: Thu, 18 May 2023 00:20:34 +0000
|
||||
Subject: Fix a crash caused by calling TRACE_EVENT
|
||||
|
||||
Now use literal constant for TRACE_EVENT. Passing a pointer instead of
|
||||
string content to TRACE_EVENT causes a crash in ScopedTracer.
|
||||
|
||||
(cherry picked from commit 6f2e587807aff2306309025db1c15fc59290eb6f)
|
||||
|
||||
Bug: 1444195
|
||||
Change-Id: I02aa1148d61e7596e9293ffc866135e99991e42e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4522164
|
||||
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
|
||||
Commit-Queue: Maggie Chen <magchen@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1144352}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4544885
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#749}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
|
||||
index a3263dd2fa9163ed98121ce62c216c176235f0ea..2665d9d3575e1c82698061d068858e77ee0afbbd 100644
|
||||
--- a/ui/gl/swap_chain_presenter.cc
|
||||
+++ b/ui/gl/swap_chain_presenter.cc
|
||||
@@ -1701,10 +1701,8 @@ bool SwapChainPresenter::ReallocateSwapChain(
|
||||
}
|
||||
}
|
||||
if (!use_yuv_swap_chain) {
|
||||
- std::ostringstream trace_event_stream;
|
||||
- trace_event_stream << "SwapChainPresenter::ReallocateSwapChain::"
|
||||
- << DxgiFormatToString(swap_chain_format);
|
||||
- TRACE_EVENT0("gpu", trace_event_stream.str().c_str());
|
||||
+ TRACE_EVENT1("gpu", "SwapChainPresenter::ReallocateSwapChain::BGRA",
|
||||
+ "format", DxgiFormatToString(swap_chain_format));
|
||||
|
||||
desc.Format = swap_chain_format;
|
||||
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO;
|
||||
51
patches/chromium/mojoipcz_copy_incoming_messages_early.patch
Normal file
51
patches/chromium/mojoipcz_copy_incoming_messages_early.patch
Normal file
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Rockot <rockot@google.com>
|
||||
Date: Mon, 3 Apr 2023 19:43:13 +0000
|
||||
Subject: MojoIpcz: Copy incoming messages early
|
||||
|
||||
Fixed: 1429720
|
||||
Change-Id: Id6cb7269d3a3e9118cc6ff1579b56e18bf911c07
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4390758
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1125510}
|
||||
|
||||
diff --git a/mojo/core/ipcz_driver/mojo_message.cc b/mojo/core/ipcz_driver/mojo_message.cc
|
||||
index da073af255795b37418b5030bf2f1cc2c0c0c7d1..e362f3db6003c9f75701b657fe32b7e65cd82661 100644
|
||||
--- a/mojo/core/ipcz_driver/mojo_message.cc
|
||||
+++ b/mojo/core/ipcz_driver/mojo_message.cc
|
||||
@@ -109,23 +109,20 @@ void MojoMessage::SetParcel(ScopedIpczHandle parcel) {
|
||||
|
||||
// We always pass a parcel object in, so Begin/EndGet() must always succeed.
|
||||
DCHECK_EQ(result, IPCZ_RESULT_OK);
|
||||
+ if (num_bytes > 0) {
|
||||
+ data_storage_.reset(
|
||||
+ static_cast<uint8_t*>(base::AllocNonScannable(num_bytes)));
|
||||
+ memcpy(data_storage_.get(), data, num_bytes);
|
||||
+ } else {
|
||||
+ data_storage_.reset();
|
||||
+ }
|
||||
+ data_ = {data_storage_.get(), num_bytes};
|
||||
+ data_storage_size_ = num_bytes;
|
||||
|
||||
- // Grab only the handles.
|
||||
handles_.resize(num_handles);
|
||||
- result = GetIpczAPI().EndGet(parcel_.get(), 0, num_handles, IPCZ_NO_FLAGS,
|
||||
- nullptr, handles_.data());
|
||||
- DCHECK_EQ(result, IPCZ_RESULT_OK);
|
||||
-
|
||||
- // Now start a new two-phase get, which we'll leave active indefinitely for
|
||||
- // `data_` to reference.
|
||||
- result = GetIpczAPI().BeginGet(parcel_.get(), IPCZ_NO_FLAGS, nullptr, &data,
|
||||
- &num_bytes, &num_handles);
|
||||
+ result = GetIpczAPI().EndGet(parcel_.get(), num_bytes, num_handles,
|
||||
+ IPCZ_NO_FLAGS, nullptr, handles_.data());
|
||||
DCHECK_EQ(result, IPCZ_RESULT_OK);
|
||||
-
|
||||
- DCHECK_EQ(0u, num_handles);
|
||||
- data_ = base::make_span(static_cast<uint8_t*>(const_cast<void*>(data)),
|
||||
- num_bytes);
|
||||
-
|
||||
if (!FixUpDataPipeHandles(handles_)) {
|
||||
// The handle list was malformed. Although this is a validation error, it
|
||||
// is not safe to trigger MojoNotifyBadMessage from within MojoReadMessage,
|
||||
@@ -23,5 +23,7 @@
|
||||
|
||||
"src/electron/patches/ReactiveObjC": "src/third_party/squirrel.mac/vendor/ReactiveObjC",
|
||||
|
||||
"src/electron/patches/webrtc": "src/third_party/webrtc"
|
||||
"src/electron/patches/webrtc": "src/third_party/webrtc",
|
||||
|
||||
"src/electron/patches/pdfium": "src/third_party/pdfium"
|
||||
}
|
||||
|
||||
3
patches/pdfium/.patches
Normal file
3
patches/pdfium/.patches
Normal file
@@ -0,0 +1,3 @@
|
||||
m114_observe_cpwl_combobox_across_all_on_methods.patch
|
||||
m114_observe_widget_across_setoptionselection_calls.patch
|
||||
m114_always_check_return_code_from_cpwl_combobox_setpopup.patch
|
||||
@@ -0,0 +1,236 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Sepez <tsepez@chromium.org>
|
||||
Date: Fri, 19 May 2023 18:41:31 +0000
|
||||
Subject: Always check return code from CPWL_ComboBox::SetPopup().
|
||||
|
||||
Operation must not continue when false is returned.
|
||||
|
||||
Bug: chromium:1444238
|
||||
Change-Id: Ic8c29653ac185ac80b6248203649ce05d0e10f06
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107390
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
(cherry picked from commit 3eb3c4d77d4f9372f77aa4895b85a1d4e4755c89)
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107812
|
||||
|
||||
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
index 5631822e0a342a6cba0f26fc45919168a74ec102..c84b7c071466e741cc4e6d113c1dc292ea685828 100644
|
||||
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
@@ -405,7 +405,9 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
// options.
|
||||
switch (nChar) {
|
||||
case pdfium::ascii::kReturn:
|
||||
- SetPopup(!IsPopup());
|
||||
+ if (!SetPopup(!IsPopup())) {
|
||||
+ return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
return true;
|
||||
case pdfium::ascii::kSpace:
|
||||
@@ -413,7 +415,9 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
// editable
|
||||
if (!HasFlag(PCBS_ALLOWCUSTOMTEXT)) {
|
||||
if (!IsPopup()) {
|
||||
- SetPopup(/*bPopUp=*/true);
|
||||
+ if (!SetPopup(/*bPopUp=*/true)) {
|
||||
+ return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
}
|
||||
return true;
|
||||
@@ -443,7 +447,7 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
|
||||
void CPWL_ComboBox::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {
|
||||
if (child == m_pButton) {
|
||||
- SetPopup(!m_bPopup);
|
||||
+ (void)SetPopup(!m_bPopup);
|
||||
// Note, |this| may no longer be viable at this point. If more work needs to
|
||||
// be done, check the return value of SetPopup().
|
||||
}
|
||||
@@ -456,7 +460,7 @@ void CPWL_ComboBox::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {
|
||||
SetSelectText();
|
||||
SelectAllText();
|
||||
m_pEdit->SetFocus();
|
||||
- SetPopup(false);
|
||||
+ (void)SetPopup(false);
|
||||
// Note, |this| may no longer be viable at this point. If more work needs to
|
||||
// be done, check the return value of SetPopup().
|
||||
}
|
||||
diff --git a/fpdfsdk/pwl/cpwl_combo_box.h b/fpdfsdk/pwl/cpwl_combo_box.h
|
||||
index bb8fa0ceca354b27b7699127ed10030ee9817fc5..87749fa7820bdd0cc7f098695071336fe55ef9c7 100644
|
||||
--- a/fpdfsdk/pwl/cpwl_combo_box.h
|
||||
+++ b/fpdfsdk/pwl/cpwl_combo_box.h
|
||||
@@ -65,7 +65,7 @@ class CPWL_ComboBox final : public CPWL_Wnd {
|
||||
void CreateListBox(const CreateParams& cp);
|
||||
|
||||
// Returns |true| iff this instance is still allocated.
|
||||
- bool SetPopup(bool bPopup);
|
||||
+ [[nodiscard]] bool SetPopup(bool bPopup);
|
||||
|
||||
UnownedPtr<CPWL_Edit> m_pEdit;
|
||||
UnownedPtr<CPWL_CBButton> m_pButton;
|
||||
diff --git a/testing/resources/javascript/xfa_specific/bug_1444238.evt b/testing/resources/javascript/xfa_specific/bug_1444238.evt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..adca35aa0d756e76eb395c5d60ba41b86c3d0090
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/xfa_specific/bug_1444238.evt
|
||||
@@ -0,0 +1,3 @@
|
||||
+mousedown,left,91,539
|
||||
+mouseup,left,91,539
|
||||
+charcode,32
|
||||
diff --git a/testing/resources/javascript/xfa_specific/bug_1444238.in b/testing/resources/javascript/xfa_specific/bug_1444238.in
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..675178c9446b0181c3633a4b5c9bc664bb4c127d
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/xfa_specific/bug_1444238.in
|
||||
@@ -0,0 +1,149 @@
|
||||
+{{header}}
|
||||
+{{object 1 0}} <<
|
||||
+ /Type /Catalog
|
||||
+ /Pages 2 0 R
|
||||
+ /AcroForm 4 0 R
|
||||
+ /OpenAction 40 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 2 0}} <<
|
||||
+ /Type /Pages
|
||||
+ /Count 2
|
||||
+ /Kids [
|
||||
+ 32 0 R
|
||||
+ 34 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Forms
|
||||
+{{object 4 0}} <<
|
||||
+ /XFA 43 0 R
|
||||
+ /Fields [
|
||||
+ 10 0 R
|
||||
+ 11 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 10 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Tx
|
||||
+ /T (MyField5)
|
||||
+ /V (myfield_5)
|
||||
+ /Rect [0 500 600 600]
|
||||
+>>
|
||||
+% Fields
|
||||
+{{object 11 0}} <<
|
||||
+ /T (MyField3)
|
||||
+ /Parent 4 0 R
|
||||
+ /Kids [12 0 R]
|
||||
+ /Opt [(a) (b) (c) (d)]
|
||||
+ /V [(a) (b) (c)]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 12 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Ch
|
||||
+ /Ff 131072
|
||||
+ /Parent 11 0 R
|
||||
+ /Kids [13 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 13 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /Parent 12 0 R
|
||||
+ /Rect [0 400 600 600]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 14 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /Parent 12 0 R
|
||||
+ /Rect [100 400 500 500]
|
||||
+>>
|
||||
+endobj
|
||||
+% Page number 2.
|
||||
+{{object 32 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [13 0 R]
|
||||
+
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 34 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [10 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+% Document JS Action
|
||||
+{{object 40 0}} <<
|
||||
+ /Type /Action
|
||||
+ /S /JavaScript
|
||||
+ /JS 41 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+% JS program to exexute
|
||||
+{{object 41 0}} <<
|
||||
+>>
|
||||
+stream
|
||||
+var f5 = this.getField("MyField5");
|
||||
+var f3 = this.getField("MyField3");
|
||||
+f3.setFocus();
|
||||
+this.__defineGetter__("pageNum",function o(){f5.setFocus(); f3.borderStyle="dashed"; f3.setFocus();});
|
||||
+endstream
|
||||
+endobj
|
||||
+{{object 43 0}} <<
|
||||
+ {{streamlen}}
|
||||
+>>
|
||||
+stream
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
|
||||
+<config></config>
|
||||
+<template xmlns="http://www.xfa.org/schema/xfa-template/2.8/">
|
||||
+ <subform layout="tb" locale="en_US">
|
||||
+ <pageSet>
|
||||
+ <pageArea id="Page1" name="Page1">
|
||||
+ <contentArea h="268.939mm" w="203.2mm" x="6.35mm" y="6.35mm"/>
|
||||
+ <medium long="792pt" short="612pt" stock="default"/>
|
||||
+ </pageArea>
|
||||
+ </pageSet>
|
||||
+ <field h="9.0001mm" name="MyField3" w="47.625mm" x="120mm" y="120mm">
|
||||
+ <ui>
|
||||
+ <choiceList open="onEntry">
|
||||
+ <border>
|
||||
+ <edge/>
|
||||
+ </border>
|
||||
+ </choiceList>
|
||||
+ </ui>
|
||||
+ <items save="1">
|
||||
+ <text>apples</text>
|
||||
+ <text>bananas</text>
|
||||
+ <text>pears</text>
|
||||
+ </items>
|
||||
+ <value>
|
||||
+ <text>apples</text>
|
||||
+ </value>
|
||||
+ <event activity="preOpen">
|
||||
+ <script contentType="application/x-javascript">
|
||||
+ var aa = this.pageNum;
|
||||
+ </script>
|
||||
+ </event>
|
||||
+ </field>
|
||||
+ </subform>
|
||||
+</template>
|
||||
+</xdp:xdp>
|
||||
+endstream
|
||||
+endobj
|
||||
+{{xref}}
|
||||
+{{trailer}}
|
||||
+{{startxref}}
|
||||
+%%EOF
|
||||
@@ -0,0 +1,213 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Sepez <tsepez@chromium.org>
|
||||
Date: Fri, 19 May 2023 20:05:10 +0000
|
||||
Subject: Observe CPWL_ComboBox across all On* methods
|
||||
|
||||
Bug: chromium:1445426
|
||||
Change-Id: I1d7ebf66fe170ca016c27a0df3ac4574e75c763c
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107650
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
(cherry picked from commit 29c665ea4c61b089746c3f502c30fcb5f4b11486)
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107811
|
||||
|
||||
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
index 29d1cea2bce2d91e975dc3a7ce4923d487f7de2a..5631822e0a342a6cba0f26fc45919168a74ec102 100644
|
||||
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
@@ -344,31 +344,42 @@ bool CPWL_ComboBox::OnKeyDown(FWL_VKEYCODE nKeyCode,
|
||||
if (!m_pEdit)
|
||||
return false;
|
||||
|
||||
+ ObservedPtr<CPWL_Wnd> thisObserved(this);
|
||||
m_nSelectItem = -1;
|
||||
|
||||
switch (nKeyCode) {
|
||||
case FWL_VKEY_Up:
|
||||
if (m_pList->GetCurSel() > 0) {
|
||||
- if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag))
|
||||
+ if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
- if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag))
|
||||
+ }
|
||||
+ if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
if (m_pList->IsMovementKey(nKeyCode)) {
|
||||
- if (m_pList->OnMovementKeyDown(nKeyCode, nFlag))
|
||||
+ if (m_pList->OnMovementKeyDown(nKeyCode, nFlag) || !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case FWL_VKEY_Down:
|
||||
if (m_pList->GetCurSel() < m_pList->GetCount() - 1) {
|
||||
- if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag))
|
||||
+ if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
- if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag))
|
||||
+ }
|
||||
+ if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
if (m_pList->IsMovementKey(nKeyCode)) {
|
||||
- if (m_pList->OnMovementKeyDown(nKeyCode, nFlag))
|
||||
+ if (m_pList->OnMovementKeyDown(nKeyCode, nFlag) || !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
}
|
||||
}
|
||||
@@ -416,10 +427,15 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
|
||||
return m_pEdit->OnChar(nChar, nFlag);
|
||||
|
||||
- if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag))
|
||||
+ ObservedPtr<CPWL_Wnd> thisObserved(this);
|
||||
+ if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
- if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag))
|
||||
+ }
|
||||
+ if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
if (!m_pList->IsChar(nChar, nFlag))
|
||||
return false;
|
||||
return m_pList->OnCharNotify(nChar, nFlag);
|
||||
diff --git a/testing/resources/javascript/bug_1445426.evt b/testing/resources/javascript/bug_1445426.evt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..265e85b0471b33509568238ccae30d2395b4b4ab
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/bug_1445426.evt
|
||||
@@ -0,0 +1,3 @@
|
||||
+mousedown,left,202,697
|
||||
+mouseup,left,202,697
|
||||
+keycode,40
|
||||
diff --git a/testing/resources/javascript/bug_1445426.in b/testing/resources/javascript/bug_1445426.in
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..1483da72f5759e9f2c8fdb538d5c6fa0cd1611c5
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/bug_1445426.in
|
||||
@@ -0,0 +1,114 @@
|
||||
+{{header}}
|
||||
+{{object 1 0}} <<
|
||||
+ /Type /Catalog
|
||||
+ /Pages 2 0 R
|
||||
+ /AcroForm 4 0 R
|
||||
+ /OpenAction 40 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 2 0}} <<
|
||||
+ /Type /Pages
|
||||
+ /Count 2
|
||||
+ /Kids [
|
||||
+ 32 0 R
|
||||
+ 34 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Forms
|
||||
+{{object 4 0}} <<
|
||||
+ /Fields [
|
||||
+ 10 0 R
|
||||
+ 11 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 10 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Tx
|
||||
+ /T (Field_TextEdit)
|
||||
+ /Rect [0 0 612 792]
|
||||
+>>
|
||||
+{{object 11 0}} <<
|
||||
+ /T (Field_ComboBox)
|
||||
+ /Parent 4 0 R
|
||||
+ /Kids [12 0 R]
|
||||
+ /Opt [(a) (b) (c) (d)]
|
||||
+ /V [(a)]
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 12 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Ch
|
||||
+ /Ff 131072
|
||||
+ /Parent 11 0 R
|
||||
+ /Kids [13 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 13 0}} <<
|
||||
+ /Parent 12 0 R
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /Rect [0 0 612 792]
|
||||
+ /AA << /K 20 0 R >>
|
||||
+>>
|
||||
+endobj
|
||||
+% Pages
|
||||
+{{object 32 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [13 0 R]
|
||||
+
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 34 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [10 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+% Document JS Action
|
||||
+{{object 40 0}} <<
|
||||
+ /Type /Action
|
||||
+ /S /JavaScript
|
||||
+ /JS 41 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+% JS program to exexute
|
||||
+{{object 41 0}} <<
|
||||
+ {{streamlen}}
|
||||
+>>
|
||||
+stream
|
||||
+var field_text = this.getField("Field_TextEdit");
|
||||
+var field_combobox = this.getField("Field_ComboBox");
|
||||
+field_combobox.setFocus();
|
||||
+this.__defineGetter__("filesize", function new_getter(){
|
||||
+ field_text.setFocus();
|
||||
+ field_combobox.borderStyle="dashed";
|
||||
+ field_combobox.setFocus();
|
||||
+ });
|
||||
+endstream
|
||||
+endobj
|
||||
+% OpenAction action
|
||||
+{{object 20 0}} <<
|
||||
+ /S /JavaScript
|
||||
+ /JS 21 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+% JS program to exexute
|
||||
+{{object 21 0}} <<
|
||||
+ {{streamlen}}
|
||||
+>>
|
||||
+stream
|
||||
+var t = this.filesize;
|
||||
+endstream
|
||||
+endobj
|
||||
+{{xref}}
|
||||
+{{trailer}}
|
||||
+{{startxref}}
|
||||
+%%EOF
|
||||
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Sepez <tsepez@chromium.org>
|
||||
Date: Thu, 18 May 2023 18:37:17 +0000
|
||||
Subject: Observe widget across SetOptionSelection() calls.
|
||||
|
||||
Call may re-enter JavaScript.
|
||||
|
||||
Bug: chromium:1444581
|
||||
Change-Id: Id7a2f17b3b81f822ca8f4496ac08c19b7794c48a
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107394
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
(cherry picked from commit a9ff918a86d700c3bdf9b5820faed35490c0cd25)
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107735
|
||||
Auto-Submit: Tom Sepez <tsepez@chromium.org>
|
||||
|
||||
diff --git a/fpdfsdk/formfiller/cffl_listbox.cpp b/fpdfsdk/formfiller/cffl_listbox.cpp
|
||||
index ea119ec093c748c6c8bfb7b3c31b4ae97f959908..31134bb1e576003cc377eb90a61898f8097f080c 100644
|
||||
--- a/fpdfsdk/formfiller/cffl_listbox.cpp
|
||||
+++ b/fpdfsdk/formfiller/cffl_listbox.cpp
|
||||
@@ -116,11 +116,18 @@ void CFFL_ListBox::SaveData(const CPDFSDK_PageView* pPageView) {
|
||||
}
|
||||
if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
|
||||
for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
|
||||
- if (pListBox->IsItemSelected(i))
|
||||
+ if (pListBox->IsItemSelected(i)) {
|
||||
m_pWidget->SetOptionSelection(i);
|
||||
+ if (!observed_box) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
m_pWidget->SetOptionSelection(pListBox->GetCurSel());
|
||||
+ if (!observed_box) {
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget);
|
||||
ObservedPtr<CFFL_ListBox> observed_this(this);
|
||||
@@ -9,3 +9,10 @@ fix_disable_implies_dcheck_for_node_stream_array_buffers.patch
|
||||
force_cppheapcreateparams_to_be_noncopyable.patch
|
||||
chore_allow_customizing_microtask_policy_per_context.patch
|
||||
store_the_thread_stack_start_in_tls.patch
|
||||
cherry-pick-3b0607d14060.patch
|
||||
cherry-pick-9c6dfc733fce.patch
|
||||
cherry-pick-73af1a19a901.patch
|
||||
cherry-pick-0035a4a8dac2.patch
|
||||
cherry-pick-2e76270cf65e.patch
|
||||
merged_runtime_set_instance_prototypes_directly_on_maps.patch
|
||||
merged_compiler_stackcheck_can_have_side_effects.patch
|
||||
|
||||
125
patches/v8/cherry-pick-0035a4a8dac2.patch
Normal file
125
patches/v8/cherry-pick-0035a4a8dac2.patch
Normal file
@@ -0,0 +1,125 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Fri, 2 Jun 2023 14:49:41 +0200
|
||||
Subject: Merged: [ic] Fix store handler selection for arguments objects
|
||||
|
||||
Drive-by: fix printing of handlers in --trace-feedback-updates mode.
|
||||
|
||||
Bug: chromium:1450481
|
||||
(cherry picked from commit e144f3b71e64e01d6ffd247eb15ca1ff56f6287b)
|
||||
|
||||
Change-Id: I0d2c90d92aa006ab37a653822f3a514343a5bac4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4583221
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#37}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc
|
||||
index 213f6f8ea0af4157c66c9e2ac66ab4c8687dfd8d..9405e0dbfb107448e122b46e70e0eaf340102190 100644
|
||||
--- a/src/diagnostics/objects-printer.cc
|
||||
+++ b/src/diagnostics/objects-printer.cc
|
||||
@@ -1338,12 +1338,18 @@ void FeedbackNexus::Print(std::ostream& os) {
|
||||
case FeedbackSlotKind::kSetKeyedStrict: {
|
||||
os << InlineCacheState2String(ic_state());
|
||||
if (ic_state() == InlineCacheState::MONOMORPHIC) {
|
||||
- os << "\n " << Brief(GetFeedback()) << ": ";
|
||||
- Object handler = GetFeedbackExtra().GetHeapObjectOrSmi();
|
||||
- if (handler.IsWeakFixedArray()) {
|
||||
- handler = WeakFixedArray::cast(handler).Get(0).GetHeapObjectOrSmi();
|
||||
+ HeapObject feedback = GetFeedback().GetHeapObject();
|
||||
+ HeapObject feedback_extra = GetFeedbackExtra().GetHeapObject();
|
||||
+ if (feedback.IsName()) {
|
||||
+ os << " with name " << Brief(feedback);
|
||||
+ WeakFixedArray array = WeakFixedArray::cast(feedback_extra);
|
||||
+ os << "\n " << Brief(array.Get(0)) << ": ";
|
||||
+ Object handler = array.Get(1).GetHeapObjectOrSmi();
|
||||
+ StoreHandler::PrintHandler(handler, os);
|
||||
+ } else {
|
||||
+ os << "\n " << Brief(feedback) << ": ";
|
||||
+ StoreHandler::PrintHandler(feedback_extra, os);
|
||||
}
|
||||
- StoreHandler::PrintHandler(handler, os);
|
||||
} else if (ic_state() == InlineCacheState::POLYMORPHIC) {
|
||||
HeapObject feedback = GetFeedback().GetHeapObject();
|
||||
WeakFixedArray array;
|
||||
diff --git a/src/ic/handler-configuration.cc b/src/ic/handler-configuration.cc
|
||||
index 51c25e40dc0162d9b6bced1db712e42dae02d466..0eed4713837d7e683df8c021de10d0d0f341f1a8 100644
|
||||
--- a/src/ic/handler-configuration.cc
|
||||
+++ b/src/ic/handler-configuration.cc
|
||||
@@ -593,8 +593,11 @@ void StoreHandler::PrintHandler(Object handler, std::ostream& os) {
|
||||
os << ", validity cell = ";
|
||||
store_handler.validity_cell().ShortPrint(os);
|
||||
os << ")" << std::endl;
|
||||
+ } else if (handler.IsMap()) {
|
||||
+ os << "StoreHandler(field transition to " << Brief(handler) << ")"
|
||||
+ << std::endl;
|
||||
} else {
|
||||
- os << "StoreHandler(<unexpected>)(" << Brief(handler) << ")";
|
||||
+ os << "StoreHandler(<unexpected>)(" << Brief(handler) << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
||||
index 8754a849636826a0eef18381773b7a2a8a0a4edc..51371baa30b6465e46a51f540ffaba98251ebf67 100644
|
||||
--- a/src/ic/ic.cc
|
||||
+++ b/src/ic/ic.cc
|
||||
@@ -2308,10 +2308,18 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
receiver_map->has_sealed_elements() ||
|
||||
receiver_map->has_nonextensible_elements() ||
|
||||
receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
|
||||
+ // TODO(jgruber): Update counter name.
|
||||
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
|
||||
- code = StoreHandler::StoreFastElementBuiltin(isolate(), store_mode);
|
||||
- if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
|
||||
- return code;
|
||||
+ if (receiver_map->IsJSArgumentsObjectMap() &&
|
||||
+ receiver_map->has_fast_packed_elements()) {
|
||||
+ // Allow fast behaviour for in-bounds stores while making it miss and
|
||||
+ // properly handle the out of bounds store case.
|
||||
+ code = StoreHandler::StoreFastElementBuiltin(isolate(), STANDARD_STORE);
|
||||
+ } else {
|
||||
+ code = StoreHandler::StoreFastElementBuiltin(isolate(), store_mode);
|
||||
+ if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
|
||||
+ return code;
|
||||
+ }
|
||||
}
|
||||
} else if (IsStoreInArrayLiteralIC()) {
|
||||
// TODO(jgruber): Update counter name.
|
||||
@@ -2322,7 +2330,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
|
||||
DCHECK(DICTIONARY_ELEMENTS == receiver_map->elements_kind() ||
|
||||
receiver_map->has_frozen_elements());
|
||||
- code = StoreHandler::StoreSlow(isolate(), store_mode);
|
||||
+ return StoreHandler::StoreSlow(isolate(), store_mode);
|
||||
}
|
||||
|
||||
if (IsAnyDefineOwn() || IsStoreInArrayLiteralIC()) return code;
|
||||
diff --git a/src/objects/map-inl.h b/src/objects/map-inl.h
|
||||
index 2c42cf2ee635896b1f5c631be5fbfa5dc167f763..077d7fb0562d731a1918d671a544fd0040759bf1 100644
|
||||
--- a/src/objects/map-inl.h
|
||||
+++ b/src/objects/map-inl.h
|
||||
@@ -613,6 +613,10 @@ bool Map::has_fast_elements() const {
|
||||
return IsFastElementsKind(elements_kind());
|
||||
}
|
||||
|
||||
+bool Map::has_fast_packed_elements() const {
|
||||
+ return IsFastPackedElementsKind(elements_kind());
|
||||
+}
|
||||
+
|
||||
bool Map::has_sloppy_arguments_elements() const {
|
||||
return IsSloppyArgumentsElementsKind(elements_kind());
|
||||
}
|
||||
diff --git a/src/objects/map.h b/src/objects/map.h
|
||||
index bdc10ee2baa7b2ba3ffa8e1292eace4376f84a88..2e61b1eb97c701a5646bbadb6bbbe7f0c06e0351 100644
|
||||
--- a/src/objects/map.h
|
||||
+++ b/src/objects/map.h
|
||||
@@ -426,6 +426,7 @@ class Map : public TorqueGeneratedMap<Map, HeapObject> {
|
||||
inline bool has_fast_smi_or_object_elements() const;
|
||||
inline bool has_fast_double_elements() const;
|
||||
inline bool has_fast_elements() const;
|
||||
+ inline bool has_fast_packed_elements() const;
|
||||
inline bool has_sloppy_arguments_elements() const;
|
||||
inline bool has_fast_sloppy_arguments_elements() const;
|
||||
inline bool has_fast_string_wrapper_elements() const;
|
||||
45
patches/v8/cherry-pick-2e76270cf65e.patch
Normal file
45
patches/v8/cherry-pick-2e76270cf65e.patch
Normal file
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Mon, 5 Jun 2023 16:05:52 -0700
|
||||
Subject: Merged: Check for encoding when appending in string builder
|
||||
|
||||
Fixed: chromium:1450114
|
||||
(cherry picked from commit a7e2bef27b72f187a7dcdf95714df686f56d9e0b)
|
||||
|
||||
Change-Id: I5838383b6b12d137e84c8a36863ef88000e85c76
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4604652
|
||||
Reviewed-by: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#41}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/strings/string-builder.cc b/src/strings/string-builder.cc
|
||||
index f6871d9e6aa33942ec595e3076f689c2008989d7..30540b6a32a006fa4417d612a1243f18f59d3c2e 100644
|
||||
--- a/src/strings/string-builder.cc
|
||||
+++ b/src/strings/string-builder.cc
|
||||
@@ -317,12 +317,21 @@ bool IncrementalStringBuilder::CanAppendByCopy(Handle<String> string) {
|
||||
void IncrementalStringBuilder::AppendStringByCopy(Handle<String> string) {
|
||||
DCHECK(CanAppendByCopy(string));
|
||||
|
||||
- Handle<SeqOneByteString> part =
|
||||
- Handle<SeqOneByteString>::cast(current_part());
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
- String::WriteToFlat(*string, part->GetChars(no_gc) + current_index_, 0,
|
||||
- string->length());
|
||||
+ if (encoding_ == String::ONE_BYTE_ENCODING) {
|
||||
+ String::WriteToFlat(
|
||||
+ *string,
|
||||
+ Handle<SeqOneByteString>::cast(current_part())->GetChars(no_gc) +
|
||||
+ current_index_,
|
||||
+ 0, string->length());
|
||||
+ } else {
|
||||
+ String::WriteToFlat(
|
||||
+ *string,
|
||||
+ Handle<SeqTwoByteString>::cast(current_part())->GetChars(no_gc) +
|
||||
+ current_index_,
|
||||
+ 0, string->length());
|
||||
+ }
|
||||
}
|
||||
current_index_ += string->length();
|
||||
DCHECK(current_index_ <= part_length_);
|
||||
186
patches/v8/cherry-pick-3b0607d14060.patch
Normal file
186
patches/v8/cherry-pick-3b0607d14060.patch
Normal file
@@ -0,0 +1,186 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Wed, 17 May 2023 13:47:36 +0200
|
||||
Subject: Merged: [runtime] Remove redundant calls to GetPropertyAttributes
|
||||
|
||||
... when defining properties in favour of CheckIfCanDefine.
|
||||
|
||||
Drive-by: move JSReceiver::CheckIfCanDefine to
|
||||
JSObject::CheckIfCanDefineAsConfigurable and fix handling of
|
||||
absent properties.
|
||||
|
||||
Bug: chromium:1443452
|
||||
(cherry picked from commit e98baa3526426c0219bb0474028ca301b8bd0677)
|
||||
|
||||
Change-Id: Ia1fd617778be608accee99dcee37f7d1ce3460b8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4545762
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#22}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
||||
index 55aa9d2c989f3fc846f0523ce5bd6a1483d448fa..8754a849636826a0eef18381773b7a2a8a0a4edc 100644
|
||||
--- a/src/ic/ic.cc
|
||||
+++ b/src/ic/ic.cc
|
||||
@@ -1815,14 +1815,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
|
||||
// been thrown if the private field already exists in the object.
|
||||
if (IsAnyDefineOwn() && !name->IsPrivateName() && !object->IsJSProxy() &&
|
||||
!Handle<JSObject>::cast(object)->HasNamedInterceptor()) {
|
||||
- Maybe<bool> can_define = JSReceiver::CheckIfCanDefine(
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
isolate(), &it, value, Nothing<ShouldThrow>());
|
||||
MAYBE_RETURN_NULL(can_define);
|
||||
if (!can_define.FromJust()) {
|
||||
return isolate()->factory()->undefined_value();
|
||||
}
|
||||
- // Restart the lookup iterator updated by CheckIfCanDefine() for
|
||||
- // UpdateCaches() to handle access checks.
|
||||
+ // Restart the lookup iterator updated by CheckIfCanDefineAsConfigurable()
|
||||
+ // for UpdateCaches() to handle access checks.
|
||||
if (use_ic && object->IsAccessCheckNeeded()) {
|
||||
it.Restart();
|
||||
}
|
||||
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
||||
index 8e11fb4ac241f1995aab7b4722822a352654108e..a53d487479d2c9e1de7da2bd63769e8e429f1890 100644
|
||||
--- a/src/objects/js-objects.cc
|
||||
+++ b/src/objects/js-objects.cc
|
||||
@@ -249,27 +249,6 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it,
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
-// static
|
||||
-Maybe<bool> JSReceiver::CheckIfCanDefine(Isolate* isolate, LookupIterator* it,
|
||||
- Handle<Object> value,
|
||||
- Maybe<ShouldThrow> should_throw) {
|
||||
- if (it->IsFound()) {
|
||||
- Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
|
||||
- MAYBE_RETURN(attributes, Nothing<bool>());
|
||||
- if ((attributes.FromJust() & DONT_DELETE) != 0) {
|
||||
- RETURN_FAILURE(
|
||||
- isolate, GetShouldThrow(isolate, should_throw),
|
||||
- NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
|
||||
- }
|
||||
- } else if (!JSObject::IsExtensible(
|
||||
- isolate, Handle<JSObject>::cast(it->GetReceiver()))) {
|
||||
- RETURN_FAILURE(
|
||||
- isolate, GetShouldThrow(isolate, should_throw),
|
||||
- NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
|
||||
- }
|
||||
- return Just(true);
|
||||
-}
|
||||
-
|
||||
namespace {
|
||||
|
||||
bool HasExcludedProperty(
|
||||
@@ -3679,7 +3658,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
|
||||
if (semantics == EnforceDefineSemantics::kDefine) {
|
||||
it->Restart();
|
||||
- Maybe<bool> can_define = JSReceiver::CheckIfCanDefine(
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
it->isolate(), it, value, should_throw);
|
||||
if (can_define.IsNothing() || !can_define.FromJust()) {
|
||||
return can_define;
|
||||
@@ -4108,16 +4087,15 @@ Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
|
||||
Handle<Object> value,
|
||||
Maybe<ShouldThrow> should_throw) {
|
||||
DCHECK(it->GetReceiver()->IsJSObject());
|
||||
- MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
|
||||
Isolate* isolate = it->isolate();
|
||||
|
||||
- Maybe<bool> can_define =
|
||||
- JSReceiver::CheckIfCanDefine(isolate, it, value, should_throw);
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
+ isolate, it, value, should_throw);
|
||||
if (can_define.IsNothing() || !can_define.FromJust()) {
|
||||
return can_define;
|
||||
}
|
||||
|
||||
- RETURN_ON_EXCEPTION_VALUE(it->isolate(),
|
||||
+ RETURN_ON_EXCEPTION_VALUE(isolate,
|
||||
DefineOwnPropertyIgnoreAttributes(it, value, NONE),
|
||||
Nothing<bool>());
|
||||
|
||||
@@ -4753,19 +4731,43 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
|
||||
return it.factory()->undefined_value();
|
||||
}
|
||||
|
||||
- CHECK(GetPropertyAttributes(&it).IsJust());
|
||||
-
|
||||
- // ES5 forbids turning a property into an accessor if it's not
|
||||
- // configurable. See 8.6.1 (Table 5).
|
||||
- if (it.IsFound() && !it.IsConfigurable()) {
|
||||
- return it.factory()->undefined_value();
|
||||
- }
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
+ isolate, &it, info, Nothing<ShouldThrow>());
|
||||
+ MAYBE_RETURN_NULL(can_define);
|
||||
+ if (!can_define.FromJust()) return it.factory()->undefined_value();
|
||||
|
||||
it.TransitionToAccessorPair(info, attributes);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
+// static
|
||||
+Maybe<bool> JSObject::CheckIfCanDefineAsConfigurable(
|
||||
+ Isolate* isolate, LookupIterator* it, Handle<Object> value,
|
||||
+ Maybe<ShouldThrow> should_throw) {
|
||||
+ DCHECK(it->GetReceiver()->IsJSObject());
|
||||
+ if (it->IsFound()) {
|
||||
+ Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
|
||||
+ MAYBE_RETURN(attributes, Nothing<bool>());
|
||||
+ if (attributes.FromJust() != ABSENT) {
|
||||
+ if ((attributes.FromJust() & DONT_DELETE) != 0) {
|
||||
+ RETURN_FAILURE(
|
||||
+ isolate, GetShouldThrow(isolate, should_throw),
|
||||
+ NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
|
||||
+ }
|
||||
+ return Just(true);
|
||||
+ }
|
||||
+ // Property does not exist, check object extensibility.
|
||||
+ }
|
||||
+ if (!JSObject::IsExtensible(isolate,
|
||||
+ Handle<JSObject>::cast(it->GetReceiver()))) {
|
||||
+ RETURN_FAILURE(
|
||||
+ isolate, GetShouldThrow(isolate, should_throw),
|
||||
+ NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
|
||||
+ }
|
||||
+ return Just(true);
|
||||
+}
|
||||
+
|
||||
Object JSObject::SlowReverseLookup(Object value) {
|
||||
if (HasFastProperties()) {
|
||||
DescriptorArray descs = map().instance_descriptors();
|
||||
diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
|
||||
index db154b56e2c5bc157345afed8d1a1fad35d56eae..dc1745a753a19c37320fd3a483d17b29c311793c 100644
|
||||
--- a/src/objects/js-objects.h
|
||||
+++ b/src/objects/js-objects.h
|
||||
@@ -167,12 +167,6 @@ class JSReceiver : public TorqueGeneratedJSReceiver<JSReceiver, HeapObject> {
|
||||
V8_WARN_UNUSED_RESULT static Maybe<bool> CheckPrivateNameStore(
|
||||
LookupIterator* it, bool is_define);
|
||||
|
||||
- // Check if a data property can be created on the object. It will fail with
|
||||
- // an error when it cannot.
|
||||
- V8_WARN_UNUSED_RESULT static Maybe<bool> CheckIfCanDefine(
|
||||
- Isolate* isolate, LookupIterator* it, Handle<Object> value,
|
||||
- Maybe<ShouldThrow> should_throw);
|
||||
-
|
||||
// ES6 7.3.4 (when passed kDontThrow)
|
||||
V8_WARN_UNUSED_RESULT static Maybe<bool> CreateDataProperty(
|
||||
Isolate* isolate, Handle<JSReceiver> object, Handle<Name> key,
|
||||
@@ -550,6 +544,12 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> info,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
+ // Check if a data property can be created on the object. It will fail with
|
||||
+ // an error when it cannot.
|
||||
+ V8_WARN_UNUSED_RESULT static Maybe<bool> CheckIfCanDefineAsConfigurable(
|
||||
+ Isolate* isolate, LookupIterator* it, Handle<Object> value,
|
||||
+ Maybe<ShouldThrow> should_throw);
|
||||
+
|
||||
// The result must be checked first for exceptions. If there's no exception,
|
||||
// the output parameter |done| indicates whether the interceptor has a result
|
||||
// or not.
|
||||
257
patches/v8/cherry-pick-73af1a19a901.patch
Normal file
257
patches/v8/cherry-pick-73af1a19a901.patch
Normal file
@@ -0,0 +1,257 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Thu, 1 Jun 2023 10:59:39 +0200
|
||||
Subject: Merged: [lookup] Robustify LookupIterator against own lookups
|
||||
|
||||
... on non-JSReceiver objects.
|
||||
|
||||
Bug: chromium:1447430
|
||||
(cherry picked from commit 515f187ba067ee4a99fdf5198cca2c97abd342fd)
|
||||
|
||||
Change-Id: Ib9382d90ce19d6b55ee0b236dd299ded03ade04d
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4575069
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#35}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/lookup-inl.h b/src/objects/lookup-inl.h
|
||||
index 00c95e013c17ae77a630431c74f9b44cdf49f884..8b5717021beb806d2572e43b20f2b06c4d3f035e 100644
|
||||
--- a/src/objects/lookup-inl.h
|
||||
+++ b/src/objects/lookup-inl.h
|
||||
@@ -190,7 +190,7 @@ Handle<Name> PropertyKey::GetName(Isolate* isolate) {
|
||||
}
|
||||
|
||||
Handle<Name> LookupIterator::name() const {
|
||||
- DCHECK(!IsElement(*holder_));
|
||||
+ DCHECK_IMPLIES(!holder_.is_null(), !IsElement(*holder_));
|
||||
return name_;
|
||||
}
|
||||
|
||||
@@ -285,6 +285,7 @@ void LookupIterator::UpdateProtector() {
|
||||
}
|
||||
|
||||
InternalIndex LookupIterator::descriptor_number() const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(has_property_);
|
||||
DCHECK(holder_->HasFastProperties(isolate_));
|
||||
@@ -292,6 +293,7 @@ InternalIndex LookupIterator::descriptor_number() const {
|
||||
}
|
||||
|
||||
InternalIndex LookupIterator::dictionary_entry() const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(has_property_);
|
||||
DCHECK(!holder_->HasFastProperties(isolate_));
|
||||
@@ -306,13 +308,14 @@ LookupIterator::Configuration LookupIterator::ComputeConfiguration(
|
||||
}
|
||||
|
||||
// static
|
||||
-Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
|
||||
- Handle<Object> lookup_start_object,
|
||||
- size_t index) {
|
||||
+MaybeHandle<JSReceiver> LookupIterator::GetRoot(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration) {
|
||||
if (lookup_start_object->IsJSReceiver(isolate)) {
|
||||
return Handle<JSReceiver>::cast(lookup_start_object);
|
||||
}
|
||||
- return GetRootForNonJSReceiver(isolate, lookup_start_object, index);
|
||||
+ return GetRootForNonJSReceiver(isolate, lookup_start_object, index,
|
||||
+ configuration);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
diff --git a/src/objects/lookup.cc b/src/objects/lookup.cc
|
||||
index e3bf4794e88e7c3ae5d4028b16eeadf282d9c410..149149beba8d6e62dd5d821f7017b18e08445bd8 100644
|
||||
--- a/src/objects/lookup.cc
|
||||
+++ b/src/objects/lookup.cc
|
||||
@@ -42,27 +42,20 @@ PropertyKey::PropertyKey(Isolate* isolate, Handle<Object> key, bool* success) {
|
||||
}
|
||||
}
|
||||
|
||||
-LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
|
||||
- Handle<Name> name, Handle<Map> transition_map,
|
||||
- PropertyDetails details, bool has_property)
|
||||
- : configuration_(DEFAULT),
|
||||
- state_(TRANSITION),
|
||||
- has_property_(has_property),
|
||||
- interceptor_state_(InterceptorState::kUninitialized),
|
||||
- property_details_(details),
|
||||
- isolate_(isolate),
|
||||
- name_(name),
|
||||
- transition_(transition_map),
|
||||
- receiver_(receiver),
|
||||
- lookup_start_object_(receiver),
|
||||
- index_(kInvalidIndex) {
|
||||
- holder_ = GetRoot(isolate, lookup_start_object_);
|
||||
-}
|
||||
-
|
||||
template <bool is_element>
|
||||
void LookupIterator::Start() {
|
||||
// GetRoot might allocate if lookup_start_object_ is a string.
|
||||
- holder_ = GetRoot(isolate_, lookup_start_object_, index_);
|
||||
+ MaybeHandle<JSReceiver> maybe_holder =
|
||||
+ GetRoot(isolate_, lookup_start_object_, index_, configuration_);
|
||||
+ if (!maybe_holder.ToHandle(&holder_)) {
|
||||
+ // This is an attempt to perform an own property lookup on a non-JSReceiver
|
||||
+ // that doesn't have any properties.
|
||||
+ DCHECK(!lookup_start_object_->IsJSReceiver());
|
||||
+ DCHECK(!check_prototype_chain());
|
||||
+ has_property_ = false;
|
||||
+ state_ = NOT_FOUND;
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
@@ -135,19 +128,27 @@ template void LookupIterator::RestartInternal<true>(InterceptorState);
|
||||
template void LookupIterator::RestartInternal<false>(InterceptorState);
|
||||
|
||||
// static
|
||||
-Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
|
||||
- Isolate* isolate, Handle<Object> lookup_start_object, size_t index) {
|
||||
- // Strings are the only objects with properties (only elements) directly on
|
||||
- // the wrapper. Hence we can skip generating the wrapper for all other cases.
|
||||
- if (lookup_start_object->IsString(isolate) &&
|
||||
- index <
|
||||
- static_cast<size_t>(String::cast(*lookup_start_object).length())) {
|
||||
- // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
|
||||
- // context, ensuring that we don't leak it into JS?
|
||||
- Handle<JSFunction> constructor = isolate->string_function();
|
||||
- Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
|
||||
- Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
|
||||
- return result;
|
||||
+MaybeHandle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration) {
|
||||
+ // Strings are the only non-JSReceiver objects with properties (only elements
|
||||
+ // and 'length') directly on the wrapper. Hence we can skip generating
|
||||
+ // the wrapper for all other cases.
|
||||
+ bool own_property_lookup = (configuration & kPrototypeChain) == 0;
|
||||
+ if (lookup_start_object->IsString(isolate)) {
|
||||
+ if (own_property_lookup ||
|
||||
+ index <
|
||||
+ static_cast<size_t>(String::cast(*lookup_start_object).length())) {
|
||||
+ // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the
|
||||
+ // native context, ensuring that we don't leak it into JS?
|
||||
+ Handle<JSFunction> constructor = isolate->string_function();
|
||||
+ Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
|
||||
+ Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
|
||||
+ return result;
|
||||
+ }
|
||||
+ } else if (own_property_lookup) {
|
||||
+ // Signal that the lookup will not find anything.
|
||||
+ return {};
|
||||
}
|
||||
Handle<HeapObject> root(
|
||||
lookup_start_object->GetPrototypeChainRootMap(isolate).prototype(isolate),
|
||||
@@ -918,6 +919,7 @@ Handle<Object> LookupIterator::FetchValue(
|
||||
}
|
||||
|
||||
bool LookupIterator::CanStayConst(Object value) const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(holder_->HasFastProperties(isolate_));
|
||||
DCHECK_EQ(PropertyLocation::kField, property_details_.location());
|
||||
@@ -951,6 +953,7 @@ bool LookupIterator::CanStayConst(Object value) const {
|
||||
}
|
||||
|
||||
bool LookupIterator::DictCanStayConst(Object value) const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(!holder_->HasFastProperties(isolate_));
|
||||
DCHECK(!holder_->IsJSGlobalObject());
|
||||
@@ -997,6 +1000,7 @@ int LookupIterator::GetAccessorIndex() const {
|
||||
|
||||
FieldIndex LookupIterator::GetFieldIndex() const {
|
||||
DCHECK(has_property_);
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(holder_->HasFastProperties(isolate_));
|
||||
DCHECK_EQ(PropertyLocation::kField, property_details_.location());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
@@ -1004,6 +1008,7 @@ FieldIndex LookupIterator::GetFieldIndex() const {
|
||||
}
|
||||
|
||||
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
|
||||
return handle(holder->global_dictionary(isolate_, kAcquireLoad)
|
||||
diff --git a/src/objects/lookup.h b/src/objects/lookup.h
|
||||
index 06ed50e97b14e29c7328d2612151b1788c85c84f..5d2d926b7e3dcecf8529f7d1c1e919033d9faa7f 100644
|
||||
--- a/src/objects/lookup.h
|
||||
+++ b/src/objects/lookup.h
|
||||
@@ -222,11 +222,6 @@ class V8_EXPORT_PRIVATE LookupIterator final {
|
||||
Handle<Object> lookup_start_object,
|
||||
Configuration configuration);
|
||||
|
||||
- // For |ForTransitionHandler|.
|
||||
- LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
|
||||
- Handle<Map> transition_map, PropertyDetails details,
|
||||
- bool has_property);
|
||||
-
|
||||
static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver,
|
||||
Handle<Name> name);
|
||||
|
||||
@@ -286,12 +281,12 @@ class V8_EXPORT_PRIVATE LookupIterator final {
|
||||
Configuration configuration,
|
||||
Handle<Name> name);
|
||||
|
||||
- static Handle<JSReceiver> GetRootForNonJSReceiver(
|
||||
- Isolate* isolate, Handle<Object> lookup_start_object,
|
||||
- size_t index = kInvalidIndex);
|
||||
- static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
|
||||
- Handle<Object> lookup_start_object,
|
||||
- size_t index = kInvalidIndex);
|
||||
+ static MaybeHandle<JSReceiver> GetRootForNonJSReceiver(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration);
|
||||
+ static inline MaybeHandle<JSReceiver> GetRoot(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration);
|
||||
|
||||
State NotFound(JSReceiver const holder) const;
|
||||
|
||||
diff --git a/test/mjsunit/regress/regress-crbug-1447430.js b/test/mjsunit/regress/regress-crbug-1447430.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c7bb3e72e3af1b9f8c2fa82faeeb2d813fe6ab3c
|
||||
--- /dev/null
|
||||
+++ b/test/mjsunit/regress/regress-crbug-1447430.js
|
||||
@@ -0,0 +1,34 @@
|
||||
+// Copyright 2023 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: --allow-natives-syntax
|
||||
+
|
||||
+var s = %CreatePrivateSymbol('x');
|
||||
+
|
||||
+(function TestSmi() {
|
||||
+ function f(o, p) {
|
||||
+ o[p] = 153;
|
||||
+ }
|
||||
+ (1).__proto__[s] = 42;
|
||||
+ %PrepareFunctionForOptimization(f);
|
||||
+ assertEquals(f(42, s), undefined);
|
||||
+}());
|
||||
+
|
||||
+(function TestString() {
|
||||
+ function f(o, p) {
|
||||
+ o[p] = 153;
|
||||
+ }
|
||||
+ ('xyz').__proto__[s] = 42;
|
||||
+ %PrepareFunctionForOptimization(f);
|
||||
+ assertEquals(f('abc', s), undefined);
|
||||
+}());
|
||||
+
|
||||
+(function TestSymbol() {
|
||||
+ function f(o, p) {
|
||||
+ o[p] = 153;
|
||||
+ }
|
||||
+ Symbol('xyz').__proto__[s] = 42;
|
||||
+ %PrepareFunctionForOptimization(f);
|
||||
+ assertEquals(f(Symbol('abc'), s), undefined);
|
||||
+}());
|
||||
150
patches/v8/cherry-pick-9c6dfc733fce.patch
Normal file
150
patches/v8/cherry-pick-9c6dfc733fce.patch
Normal file
@@ -0,0 +1,150 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Tue, 16 May 2023 16:01:49 +0200
|
||||
Subject: Merged: [runtime] Fix handling of interceptors
|
||||
|
||||
Drive-by: simplify creation of LookupIterator copies.
|
||||
|
||||
Bug: chromium:1440695
|
||||
(cherry picked from commit d125c7329f6e22af4523de3c55de3a22f168acc9)
|
||||
|
||||
Change-Id: I58416531b9af3456f53264566ec1eb7457328f94
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4545763
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#23}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
||||
index a53d487479d2c9e1de7da2bd63769e8e429f1890..9bc37cc246fc89d2856b6c8a7800cad930e28dc7 100644
|
||||
--- a/src/objects/js-objects.cc
|
||||
+++ b/src/objects/js-objects.cc
|
||||
@@ -3669,10 +3669,8 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
// own property without the interceptor.
|
||||
Isolate* isolate = it->isolate();
|
||||
Handle<Object> receiver = it->GetReceiver();
|
||||
- LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR;
|
||||
- LookupIterator own_lookup =
|
||||
- it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
|
||||
- : LookupIterator(isolate, receiver, it->name(), c);
|
||||
+ LookupIterator own_lookup(isolate, receiver, it->GetKey(),
|
||||
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
return JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
&own_lookup, value, attributes, should_throw, handling, semantics,
|
||||
store_origin);
|
||||
diff --git a/src/objects/lookup-inl.h b/src/objects/lookup-inl.h
|
||||
index d34f710147ea799bcc8a89b4b58e176918071bf6..00c95e013c17ae77a630431c74f9b44cdf49f884 100644
|
||||
--- a/src/objects/lookup-inl.h
|
||||
+++ b/src/objects/lookup-inl.h
|
||||
@@ -130,6 +130,29 @@ PropertyKey::PropertyKey(Isolate* isolate, double index) {
|
||||
#endif
|
||||
}
|
||||
|
||||
+PropertyKey::PropertyKey(Isolate* isolate, Handle<Name> name, size_t index)
|
||||
+ : name_(name), index_(index) {
|
||||
+ DCHECK_IMPLIES(index_ == LookupIterator::kInvalidIndex, !name_.is_null());
|
||||
+#if V8_TARGET_ARCH_32_BIT
|
||||
+ DCHECK_IMPLIES(index_ != LookupIterator::kInvalidIndex,
|
||||
+ index_ <= JSObject::kMaxElementIndex);
|
||||
+#endif
|
||||
+#if DEBUG
|
||||
+ if (index_ != LookupIterator::kInvalidIndex && !name_.is_null()) {
|
||||
+ // If both valid index and name are given then the name is a string
|
||||
+ // representation of the same index.
|
||||
+ size_t integer_index;
|
||||
+ CHECK(name_->AsIntegerIndex(&integer_index));
|
||||
+ CHECK_EQ(index_, integer_index);
|
||||
+ } else if (index_ == LookupIterator::kInvalidIndex) {
|
||||
+ // If only name is given it must not be a string representing an integer
|
||||
+ // index.
|
||||
+ size_t integer_index;
|
||||
+ CHECK(!name_->AsIntegerIndex(&integer_index));
|
||||
+ }
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
PropertyKey::PropertyKey(Isolate* isolate, Handle<Name> name) {
|
||||
if (name->AsIntegerIndex(&index_)) {
|
||||
name_ = name;
|
||||
@@ -179,6 +202,10 @@ Handle<Name> LookupIterator::GetName() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
+PropertyKey LookupIterator::GetKey() const {
|
||||
+ return PropertyKey(isolate_, name_, index_);
|
||||
+}
|
||||
+
|
||||
bool LookupIterator::IsElement(JSReceiver object) const {
|
||||
return index_ <= JSObject::kMaxElementIndex ||
|
||||
(index_ != kInvalidIndex &&
|
||||
diff --git a/src/objects/lookup.h b/src/objects/lookup.h
|
||||
index 9adee79b3028c53e6481a07316d74aed616f01bd..06ed50e97b14e29c7328d2612151b1788c85c84f 100644
|
||||
--- a/src/objects/lookup.h
|
||||
+++ b/src/objects/lookup.h
|
||||
@@ -36,6 +36,11 @@ class PropertyKey {
|
||||
inline Handle<Name> GetName(Isolate* isolate);
|
||||
|
||||
private:
|
||||
+ friend LookupIterator;
|
||||
+
|
||||
+ // Shortcut for constructing PropertyKey from an active LookupIterator.
|
||||
+ inline PropertyKey(Isolate* isolate, Handle<Name> name, size_t index);
|
||||
+
|
||||
Handle<Name> name_;
|
||||
size_t index_;
|
||||
};
|
||||
@@ -108,6 +113,9 @@ class V8_EXPORT_PRIVATE LookupIterator final {
|
||||
return static_cast<uint32_t>(index_);
|
||||
}
|
||||
|
||||
+ // Helper method for creating a copy of of the iterator.
|
||||
+ inline PropertyKey GetKey() const;
|
||||
+
|
||||
// Returns true if this LookupIterator has an index in the range
|
||||
// [0, size_t::max).
|
||||
bool IsElement() const { return index_ != kInvalidIndex; }
|
||||
diff --git a/src/objects/objects.cc b/src/objects/objects.cc
|
||||
index 26a8d59b34e99ca110479b3f3211e298d1ecbcc4..0907a4b3444d10ce22c16de1a5ecbdb5f4b982af 100644
|
||||
--- a/src/objects/objects.cc
|
||||
+++ b/src/objects/objects.cc
|
||||
@@ -2662,11 +2662,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
|
||||
// Note, the callers rely on the fact that this code is redoing the full own
|
||||
// lookup from scratch.
|
||||
- LookupIterator::Configuration c = LookupIterator::OWN;
|
||||
- LookupIterator own_lookup =
|
||||
- it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
|
||||
- : LookupIterator(isolate, receiver, it->name(), c);
|
||||
-
|
||||
+ LookupIterator own_lookup(isolate, receiver, it->GetKey(),
|
||||
+ LookupIterator::OWN);
|
||||
for (; own_lookup.IsFound(); own_lookup.Next()) {
|
||||
switch (own_lookup.state()) {
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
@@ -2703,6 +2700,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
|
||||
MAYBE_RETURN(owned, Nothing<bool>());
|
||||
if (!owned.FromJust()) {
|
||||
+ // |own_lookup| might become outdated at this point anyway.
|
||||
+ own_lookup.Restart();
|
||||
if (!CheckContextualStoreToJSGlobalObject(&own_lookup,
|
||||
should_throw)) {
|
||||
return Nothing<bool>();
|
||||
diff --git a/test/unittests/api/interceptor-unittest.cc b/test/unittests/api/interceptor-unittest.cc
|
||||
index 635bf6a0b72f8d49591be333b1314846c9c47269..416f9bd1eb4c59160eb03031e6011ae02dcf021e 100644
|
||||
--- a/test/unittests/api/interceptor-unittest.cc
|
||||
+++ b/test/unittests/api/interceptor-unittest.cc
|
||||
@@ -174,8 +174,10 @@ TEST_F(InterceptorLoggingTest, DispatchTest) {
|
||||
EXPECT_EQ(Run("obj.foo"), "named getter");
|
||||
EXPECT_EQ(Run("obj[42]"), "indexed getter");
|
||||
|
||||
- EXPECT_EQ(Run("obj.foo = null"), "named setter, named descriptor");
|
||||
- EXPECT_EQ(Run("obj[42] = null"), "indexed setter, indexed descriptor");
|
||||
+ EXPECT_EQ(Run("obj.foo = null"),
|
||||
+ "named setter, named descriptor, named query");
|
||||
+ EXPECT_EQ(Run("obj[42] = null"),
|
||||
+ "indexed setter, indexed descriptor, indexed query");
|
||||
|
||||
EXPECT_EQ(Run("Object.getOwnPropertyDescriptor(obj, 'foo')"),
|
||||
"named descriptor");
|
||||
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Tebbi <tebbi@chromium.org>
|
||||
Date: Tue, 13 Jun 2023 17:08:59 +0200
|
||||
Subject: Merged: [compiler] StackCheck can have side effects
|
||||
|
||||
Bug: chromium:1452137
|
||||
(cherry picked from commit e548943e473b020fdc1de6e5543ca31b24d8b7f9)
|
||||
|
||||
Change-Id: Ibd7c9b02efd12341b452e4c34a635a58a817649f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4637129
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
|
||||
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
|
||||
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#49}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc
|
||||
index 1728f91280bf9e6a3cf173fe399a8b68bd64cad3..abdd45a16e9f207c8d9012cfb434e816218bbf7c 100644
|
||||
--- a/src/compiler/js-operator.cc
|
||||
+++ b/src/compiler/js-operator.cc
|
||||
@@ -1400,7 +1400,7 @@ const Operator* JSOperatorBuilder::CloneObject(FeedbackSource const& feedback,
|
||||
const Operator* JSOperatorBuilder::StackCheck(StackCheckKind kind) {
|
||||
return zone()->New<Operator1<StackCheckKind>>( // --
|
||||
IrOpcode::kJSStackCheck, // opcode
|
||||
- Operator::kNoWrite, // properties
|
||||
+ Operator::kNoProperties, // properties
|
||||
"JSStackCheck", // name
|
||||
0, 1, 1, 0, 1, 2, // counts
|
||||
kind); // parameter
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Toon Verwaest <verwaest@chromium.org>
|
||||
Date: Fri, 16 Jun 2023 17:13:52 +0200
|
||||
Subject: Merged: [runtime] Set instance prototypes directly on maps
|
||||
|
||||
Bug: chromium:1452137
|
||||
(cherry picked from commit c7c447735f762f6d6d0878e229371797845ef4ab)
|
||||
|
||||
Change-Id: I611c41f942e2e51f3c4b4f1d119c18410617188e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4637888
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Auto-Submit: Igor Sheludko <ishell@chromium.org>
|
||||
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#47}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/js-function.cc b/src/objects/js-function.cc
|
||||
index 6f9b2f676ac5d3f91589a78344b27765dc8bef06..d50743b1c73ad3304c5c5c22a4e0589cca302502 100644
|
||||
--- a/src/objects/js-function.cc
|
||||
+++ b/src/objects/js-function.cc
|
||||
@@ -676,6 +676,10 @@ void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
|
||||
// At that point, a new initial map is created and the prototype is put
|
||||
// into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value, kReleaseStore);
|
||||
+ if (value->IsJSObjectThatCanBeTrackedAsPrototype()) {
|
||||
+ // Optimize as prototype to detach it from its transition tree.
|
||||
+ JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
|
||||
+ }
|
||||
} else {
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, initial_map, "SetInstancePrototype");
|
||||
@@ -801,8 +805,10 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
||||
Handle<HeapObject> prototype;
|
||||
if (function->has_instance_prototype()) {
|
||||
prototype = handle(function->instance_prototype(), isolate);
|
||||
+ map->set_prototype(*prototype);
|
||||
} else {
|
||||
prototype = isolate->factory()->NewFunctionPrototype(function);
|
||||
+ Map::SetPrototype(isolate, map, prototype);
|
||||
}
|
||||
DCHECK(map->has_fast_object_elements());
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
fix_fallback_to_x11_capturer_on_wayland.patch
|
||||
m114_move_transceiver_iteration_loop_over_to_the_signaling_thread.patch
|
||||
m114_sdp_reject_duplicate_ssrcs_in_ssrc-groups.patch
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tommi <tommi@webrtc.org>
|
||||
Date: Thu, 1 Jun 2023 16:08:52 +0200
|
||||
Subject: Move transceiver iteration loop over to the signaling thread.
|
||||
|
||||
This is required for ReportTransportStats since iterating over the
|
||||
transceiver list from the network thread is not safe.
|
||||
|
||||
(cherry picked from commit dba22d31909298161318e00d43a80cdb0abc940f)
|
||||
|
||||
No-Try: true
|
||||
Bug: chromium:1446274, webrtc:12692
|
||||
Change-Id: I7c514df9f029112c4b1da85826af91217850fb26
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/307340
|
||||
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
|
||||
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#40197}
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/308001
|
||||
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#3}
|
||||
Cr-Branched-From: df7df199abd619e75b9f1d9a7e12fc3f3f748775-refs/heads/main@{#39949}
|
||||
|
||||
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
|
||||
index 88b99bb515325b9c616b7d06495c7a9c924133b2..5701504e7a6ebd96bd5cafdbe37de4a510f6a436 100644
|
||||
--- a/pc/peer_connection.cc
|
||||
+++ b/pc/peer_connection.cc
|
||||
@@ -728,9 +728,6 @@ JsepTransportController* PeerConnection::InitializeTransportController_n(
|
||||
transport_controller_->SubscribeIceConnectionState(
|
||||
[this](cricket::IceConnectionState s) {
|
||||
RTC_DCHECK_RUN_ON(network_thread());
|
||||
- if (s == cricket::kIceConnectionConnected) {
|
||||
- ReportTransportStats();
|
||||
- }
|
||||
signaling_thread()->PostTask(
|
||||
SafeTask(signaling_thread_safety_.flag(), [this, s]() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
@@ -2415,6 +2412,20 @@ void PeerConnection::OnTransportControllerConnectionState(
|
||||
case cricket::kIceConnectionConnected:
|
||||
RTC_LOG(LS_INFO) << "Changing to ICE connected state because "
|
||||
"all transports are writable.";
|
||||
+ {
|
||||
+ std::vector<RtpTransceiverProxyRefPtr> transceivers;
|
||||
+ if (ConfiguredForMedia()) {
|
||||
+ transceivers = rtp_manager()->transceivers()->List();
|
||||
+ }
|
||||
+
|
||||
+ network_thread()->PostTask(
|
||||
+ SafeTask(network_thread_safety_,
|
||||
+ [this, transceivers = std::move(transceivers)] {
|
||||
+ RTC_DCHECK_RUN_ON(network_thread());
|
||||
+ ReportTransportStats(std::move(transceivers));
|
||||
+ }));
|
||||
+ }
|
||||
+
|
||||
SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
|
||||
NoteUsageEvent(UsageEvent::ICE_STATE_CONNECTED);
|
||||
break;
|
||||
@@ -2762,20 +2773,18 @@ void PeerConnection::OnTransportControllerGatheringState(
|
||||
}
|
||||
|
||||
// Runs on network_thread().
|
||||
-void PeerConnection::ReportTransportStats() {
|
||||
+void PeerConnection::ReportTransportStats(
|
||||
+ std::vector<RtpTransceiverProxyRefPtr> transceivers) {
|
||||
TRACE_EVENT0("webrtc", "PeerConnection::ReportTransportStats");
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
std::map<std::string, std::set<cricket::MediaType>>
|
||||
media_types_by_transport_name;
|
||||
- if (ConfiguredForMedia()) {
|
||||
- for (const auto& transceiver :
|
||||
- rtp_manager()->transceivers()->UnsafeList()) {
|
||||
- if (transceiver->internal()->channel()) {
|
||||
- std::string transport_name(
|
||||
- transceiver->internal()->channel()->transport_name());
|
||||
- media_types_by_transport_name[transport_name].insert(
|
||||
- transceiver->media_type());
|
||||
- }
|
||||
+ for (const auto& transceiver : transceivers) {
|
||||
+ if (transceiver->internal()->channel()) {
|
||||
+ std::string transport_name(
|
||||
+ transceiver->internal()->channel()->transport_name());
|
||||
+ media_types_by_transport_name[transport_name].insert(
|
||||
+ transceiver->media_type());
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
|
||||
index 850142b9584a9f2e5b29b337b2bcd433d4b0224d..69b2ca7925eceb636aa4d22b9397cb25a7637051 100644
|
||||
--- a/pc/peer_connection.h
|
||||
+++ b/pc/peer_connection.h
|
||||
@@ -569,7 +569,8 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
|
||||
// Invoked when TransportController connection completion is signaled.
|
||||
// Reports stats for all transports in use.
|
||||
- void ReportTransportStats() RTC_RUN_ON(network_thread());
|
||||
+ void ReportTransportStats(std::vector<RtpTransceiverProxyRefPtr> transceivers)
|
||||
+ RTC_RUN_ON(network_thread());
|
||||
|
||||
// Gather the usage of IPv4/IPv6 as best connection.
|
||||
static void ReportBestConnectionState(const cricket::TransportStats& stats);
|
||||
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
|
||||
index 1d1bec3e93e0e87bb0b1da13c13ed11712ad0480..c373e2f643b33dea4e619e38dfc8d1007f2cedad 100644
|
||||
--- a/pc/peer_connection_integrationtest.cc
|
||||
+++ b/pc/peer_connection_integrationtest.cc
|
||||
@@ -1831,6 +1831,10 @@ TEST_P(PeerConnectionIntegrationTest,
|
||||
EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected,
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
|
||||
+ // Part of reporting the stats will occur on the network thread, so flush it
|
||||
+ // before checking NumEvents.
|
||||
+ SendTask(network_thread(), [] {});
|
||||
+
|
||||
EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(
|
||||
"WebRTC.PeerConnection.CandidatePairType_UDP",
|
||||
webrtc::kIceCandidatePairHostNameHostName));
|
||||
@@ -1959,6 +1963,10 @@ TEST_P(PeerConnectionIntegrationIceStatesTest, MAYBE_VerifyBestConnection) {
|
||||
EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected,
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
|
||||
+ // Part of reporting the stats will occur on the network thread, so flush it
|
||||
+ // before checking NumEvents.
|
||||
+ SendTask(network_thread(), [] {});
|
||||
+
|
||||
// TODO(bugs.webrtc.org/9456): Fix it.
|
||||
const int num_best_ipv4 = webrtc::metrics::NumEvents(
|
||||
"WebRTC.PeerConnection.IPMetrics", webrtc::kBestConnections_IPv4);
|
||||
@@ -0,0 +1,79 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Philipp Hancke <phancke@microsoft.com>
|
||||
Date: Thu, 15 Jun 2023 07:21:56 +0200
|
||||
Subject: sdp: reject duplicate ssrcs in ssrc-groups
|
||||
|
||||
while not really covered by
|
||||
https://www.rfc-editor.org/rfc/rfc5576.html#section-4.2
|
||||
and using the same SSRC for RTX and primary payload may work
|
||||
since payload type demuxing *could* be used is not a good idea.
|
||||
This also applies to flexfec's FEC-FR.
|
||||
|
||||
For the nonstandard SIM ssrc-group duplicates make no sense.
|
||||
This rejects duplicates for unknown ssrc-groups as well.
|
||||
|
||||
BUG=chromium:1454860
|
||||
|
||||
(cherry picked from commit 6a38a3eb38f732b89ca0d8e36c43a434670c4ef5)
|
||||
|
||||
No-Try: true
|
||||
Change-Id: I3e86101dbd5d6c4099f2fdb7b4a52d5cd0809c5f
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/308820
|
||||
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
|
||||
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
|
||||
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#40292}
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/309601
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#4}
|
||||
Cr-Branched-From: df7df199abd619e75b9f1d9a7e12fc3f3f748775-refs/heads/main@{#39949}
|
||||
|
||||
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
|
||||
index 6d041ff0a1c8ce731a0e4fc20731129663924374..4beb6b0faa0eb78a794cd91507fb476821e94b7c 100644
|
||||
--- a/pc/webrtc_sdp.cc
|
||||
+++ b/pc/webrtc_sdp.cc
|
||||
@@ -3542,6 +3542,11 @@ bool ParseSsrcGroupAttribute(absl::string_view line,
|
||||
if (!GetValueFromString(line, fields[i], &ssrc, error)) {
|
||||
return false;
|
||||
}
|
||||
+ // Reject duplicates. While not forbidden by RFC 5576,
|
||||
+ // they don't make sense.
|
||||
+ if (absl::c_linear_search(ssrcs, ssrc)) {
|
||||
+ return ParseFailed(line, "Duplicate SSRC in ssrc-group", error);
|
||||
+ }
|
||||
ssrcs.push_back(ssrc);
|
||||
}
|
||||
ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
|
||||
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
|
||||
index 37464425c6d88a097140d04fa0a44af5410a64b5..d6a851a2974c348200bf8347aaa16b585f4b9fab 100644
|
||||
--- a/pc/webrtc_sdp_unittest.cc
|
||||
+++ b/pc/webrtc_sdp_unittest.cc
|
||||
@@ -5058,3 +5058,29 @@ TEST_F(WebRtcSdpTest, RejectSessionLevelMediaLevelExtmapMixedUsage) {
|
||||
JsepSessionDescription jdesc(kDummyType);
|
||||
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
|
||||
}
|
||||
+
|
||||
+TEST_F(WebRtcSdpTest, RejectDuplicateSsrcInSsrcGroup) {
|
||||
+ std::string sdp =
|
||||
+ "v=0\r\n"
|
||||
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
|
||||
+ "s=-\r\n"
|
||||
+ "t=0 0\r\n"
|
||||
+ "a=group:BUNDLE 0\r\n"
|
||||
+ "a=fingerprint:sha-1 "
|
||||
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
|
||||
+ "a=setup:actpass\r\n"
|
||||
+ "a=ice-ufrag:ETEn\r\n"
|
||||
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
|
||||
+ "m=video 9 UDP/TLS/RTP/SAVPF 96 97\r\n"
|
||||
+ "c=IN IP4 0.0.0.0\r\n"
|
||||
+ "a=rtcp-mux\r\n"
|
||||
+ "a=sendonly\r\n"
|
||||
+ "a=mid:0\r\n"
|
||||
+ "a=rtpmap:96 VP8/90000\r\n"
|
||||
+ "a=rtpmap:97 rtx/90000\r\n"
|
||||
+ "a=fmtp:97 apt=96\r\n"
|
||||
+ "a=ssrc-group:FID 1234 1234\r\n"
|
||||
+ "a=ssrc:1234 cname:test\r\n";
|
||||
+ JsepSessionDescription jdesc(kDummyType);
|
||||
+ EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
|
||||
+}
|
||||
@@ -30,6 +30,32 @@ const IGNORELIST = new Set([
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
|
||||
const CPPLINT_FILTERS = [
|
||||
// from presubmit_canned_checks.py OFF_BY_DEFAULT_LINT_FILTERS
|
||||
'-build/include',
|
||||
'-build/include_order',
|
||||
'-build/namespaces',
|
||||
'-readability/casting',
|
||||
'-runtime/int',
|
||||
'-whitespace/braces',
|
||||
// from presubmit_canned_checks.py OFF_UNLESS_MANUALLY_ENABLED_LINT_FILTERS
|
||||
'-build/c++11',
|
||||
'-build/header_guard',
|
||||
'-readability/todo',
|
||||
'-runtime/references',
|
||||
'-whitespace/braces',
|
||||
'-whitespace/comma',
|
||||
'-whitespace/end_of_line',
|
||||
'-whitespace/forcolon',
|
||||
'-whitespace/indent',
|
||||
'-whitespace/line_length',
|
||||
'-whitespace/newline',
|
||||
'-whitespace/operators',
|
||||
'-whitespace/parens',
|
||||
'-whitespace/semicolon',
|
||||
'-whitespace/tab'
|
||||
];
|
||||
|
||||
function spawnAndCheckExitCode (cmd, args, opts) {
|
||||
opts = { stdio: 'inherit', ...opts };
|
||||
const { error, status, signal } = childProcess.spawnSync(cmd, args, opts);
|
||||
@@ -78,7 +104,7 @@ const LINTERS = [{
|
||||
const clangFormatFlags = opts.fix ? ['--fix'] : [];
|
||||
for (const chunk of chunkFilenames(filenames)) {
|
||||
spawnAndCheckExitCode('python3', ['script/run-clang-format.py', ...clangFormatFlags, ...chunk]);
|
||||
cpplint(chunk);
|
||||
cpplint([`--filter=${CPPLINT_FILTERS.join(',')}`, ...chunk]);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
@@ -88,13 +114,7 @@ const LINTERS = [{
|
||||
run: (opts, filenames) => {
|
||||
const clangFormatFlags = opts.fix ? ['--fix'] : [];
|
||||
spawnAndCheckExitCode('python3', ['script/run-clang-format.py', '-r', ...clangFormatFlags, ...filenames]);
|
||||
const filter = [
|
||||
'-readability/braces',
|
||||
'-readability/casting',
|
||||
'-whitespace/braces',
|
||||
'-whitespace/indent',
|
||||
'-whitespace/parens'
|
||||
];
|
||||
const filter = [...CPPLINT_FILTERS, '-readability/braces'];
|
||||
cpplint(['--extensions=mm,h', `--filter=${filter.join(',')}`, ...filenames]);
|
||||
}
|
||||
}, {
|
||||
|
||||
@@ -77,7 +77,7 @@ async function validateReleaseAssets (release, validatingRelease) {
|
||||
} else {
|
||||
await verifyShasumsForRemoteFiles(downloadUrls)
|
||||
.catch(err => {
|
||||
console.log(`${fail} error verifyingShasums`, err);
|
||||
console.error(`${fail} error verifyingShasums`, err);
|
||||
});
|
||||
}
|
||||
const azRemoteFiles = azRemoteFilesForVersion(release.tag_name);
|
||||
@@ -90,7 +90,7 @@ function check (condition, statement, exitIfFail = false) {
|
||||
console.log(`${pass} ${statement}`);
|
||||
} else {
|
||||
failureCount++;
|
||||
console.log(`${fail} ${statement}`);
|
||||
console.error(`${fail} ${statement}`);
|
||||
if (exitIfFail) process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ function runScript (scriptName, scriptArgs, cwd) {
|
||||
try {
|
||||
return execSync(scriptCommand, scriptOptions);
|
||||
} catch (err) {
|
||||
console.log(`${fail} Error running ${scriptName}`, err);
|
||||
console.error(`${fail} Error running ${scriptName}`, err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,8 @@ async function createReleaseShasums (release) {
|
||||
repo: targetRepo,
|
||||
asset_id: existingAssets[0].id
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error deleting ${fileName} on GitHub:`, err);
|
||||
console.error(`${fail} Error deleting ${fileName} on GitHub:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
console.log(`Creating and uploading the release ${fileName}.`);
|
||||
@@ -292,7 +293,7 @@ async function uploadShasumFile (filePath, fileName, releaseId) {
|
||||
data: fs.createReadStream(filePath),
|
||||
name: fileName
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error uploading ${filePath} to GitHub:`, err);
|
||||
console.error(`${fail} Error uploading ${filePath} to GitHub:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -301,13 +302,13 @@ function saveShaSumFile (checksums, fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
temp.open(fileName, (err, info) => {
|
||||
if (err) {
|
||||
console.log(`${fail} Could not create ${fileName} file`);
|
||||
console.error(`${fail} Could not create ${fileName} file`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
fs.writeFileSync(info.fd, checksums);
|
||||
fs.close(info.fd, (err) => {
|
||||
if (err) {
|
||||
console.log(`${fail} Could close ${fileName} file`);
|
||||
console.error(`${fail} Could close ${fileName} file`);
|
||||
process.exit(1);
|
||||
}
|
||||
resolve(info.path);
|
||||
@@ -333,7 +334,7 @@ async function publishRelease (release) {
|
||||
draft: false,
|
||||
make_latest: makeLatest ? 'true' : 'false'
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error publishing release:`, err);
|
||||
console.error(`${fail} Error publishing release:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -351,13 +352,17 @@ async function makeRelease (releaseToValidate) {
|
||||
} else {
|
||||
let draftRelease = await getDraftRelease();
|
||||
uploadNodeShasums();
|
||||
uploadIndexJson();
|
||||
|
||||
await createReleaseShasums(draftRelease);
|
||||
|
||||
// Fetch latest version of release before verifying
|
||||
draftRelease = await getDraftRelease(pkgVersion, true);
|
||||
await validateReleaseAssets(draftRelease);
|
||||
// index.json goes live once uploaded so do these uploads as
|
||||
// late as possible to reduce the chances it contains a release
|
||||
// which fails to publish. It has to be done before the final
|
||||
// publish to ensure there aren't published releases not contained
|
||||
// in index.json, which causes other problems in downstream projects
|
||||
uploadIndexJson();
|
||||
await publishRelease(draftRelease);
|
||||
console.log(`${pass} SUCCESS!!! Release has been published. Please run ` +
|
||||
'"npm run publish-to-npm" to publish release to npm.');
|
||||
@@ -403,7 +408,7 @@ async function verifyDraftGitHubReleaseAssets (release) {
|
||||
|
||||
return { url: response.headers.location, file: asset.name };
|
||||
})).catch(err => {
|
||||
console.log(`${fail} Error downloading files from GitHub`, err);
|
||||
console.error(`${fail} Error downloading files from GitHub`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ppapi/buildflags/buildflags.h"
|
||||
#include "shell/common/electron_paths.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/process_util.h"
|
||||
#include "third_party/widevine/cdm/buildflags.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
@@ -148,16 +149,13 @@ base::RefCountedMemory* ElectronContentClient::GetDataResourceBytes(
|
||||
}
|
||||
|
||||
void ElectronContentClient::AddAdditionalSchemes(Schemes* schemes) {
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
std::string process_type =
|
||||
command_line->GetSwitchValueASCII(::switches::kProcessType);
|
||||
// Browser Process registration happens in
|
||||
// `api::Protocol::RegisterSchemesAsPrivileged`
|
||||
//
|
||||
// Renderer Process registration happens in `RendererClientBase`
|
||||
//
|
||||
// We use this for registration to network utility process
|
||||
if (process_type == ::switches::kUtilityProcess) {
|
||||
if (IsUtilityProcess()) {
|
||||
AppendDelimitedSwitchToVector(switches::kServiceWorkerSchemes,
|
||||
&schemes->service_worker_schemes);
|
||||
AppendDelimitedSwitchToVector(switches::kStandardSchemes,
|
||||
|
||||
@@ -316,9 +316,7 @@ absl::optional<int> ElectronMainDelegate::BasicStartupComplete() {
|
||||
|
||||
void ElectronMainDelegate::PreSandboxStartup() {
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
std::string process_type =
|
||||
command_line->GetSwitchValueASCII(::switches::kProcessType);
|
||||
std::string process_type = GetProcessType();
|
||||
|
||||
base::FilePath user_data_dir =
|
||||
command_line->GetSwitchValuePath(::switches::kUserDataDir);
|
||||
@@ -335,9 +333,9 @@ void ElectronMainDelegate::PreSandboxStartup() {
|
||||
// know the correct user-data directory. (And, further, accessing the
|
||||
// application name on Linux can cause glib calls that end up spawning
|
||||
// threads, which if done before the zygote is booted, causes a CHECK().)
|
||||
logging::InitElectronLogging(*command_line,
|
||||
/* is_preinit = */ process_type.empty() ||
|
||||
process_type == ::switches::kZygoteProcess);
|
||||
logging::InitElectronLogging(
|
||||
*command_line,
|
||||
/* is_preinit = */ IsBrowserProcess() || IsZygoteProcess());
|
||||
#endif
|
||||
|
||||
#if !IS_MAS_BUILD()
|
||||
@@ -356,7 +354,7 @@ void ElectronMainDelegate::PreSandboxStartup() {
|
||||
// In the main process, we wait for JS to call crashReporter.start() before
|
||||
// initializing crashpad. If we're in the renderer, we want to initialize it
|
||||
// immediately at boot.
|
||||
if (!process_type.empty()) {
|
||||
if (!IsBrowserProcess()) {
|
||||
ElectronCrashReporterClient::Create();
|
||||
crash_reporter::InitializeCrashpad(false, process_type);
|
||||
}
|
||||
@@ -364,7 +362,7 @@ void ElectronMainDelegate::PreSandboxStartup() {
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
// Zygote needs to call InitCrashReporter() in RunZygote().
|
||||
if (process_type != ::switches::kZygoteProcess && !process_type.empty()) {
|
||||
if (!IsZygoteProcess() && !IsBrowserProcess()) {
|
||||
ElectronCrashReporterClient::Create();
|
||||
if (command_line->HasSwitch(
|
||||
crash_reporter::switches::kCrashpadHandlerPid)) {
|
||||
@@ -414,12 +412,8 @@ absl::optional<int> ElectronMainDelegate::PreBrowserMain() {
|
||||
}
|
||||
|
||||
base::StringPiece ElectronMainDelegate::GetBrowserV8SnapshotFilename() {
|
||||
const base::CommandLine* command_line =
|
||||
base::CommandLine::ForCurrentProcess();
|
||||
std::string process_type =
|
||||
command_line->GetSwitchValueASCII(::switches::kProcessType);
|
||||
bool load_browser_process_specific_v8_snapshot =
|
||||
process_type.empty() &&
|
||||
IsBrowserProcess() &&
|
||||
electron::fuses::IsLoadBrowserProcessSpecificV8SnapshotEnabled();
|
||||
if (load_browser_process_specific_v8_snapshot) {
|
||||
return "browser_v8_context_snapshot.bin";
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/fixed_flat_set.h"
|
||||
#include "base/feature_list.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@@ -54,9 +54,13 @@ namespace {
|
||||
// See https://nodejs.org/api/cli.html#cli_options
|
||||
int SetNodeCliFlags() {
|
||||
// Options that are unilaterally disallowed
|
||||
const std::unordered_set<base::StringPiece, base::StringPieceHash>
|
||||
disallowed = {"--openssl-config", "--use-bundled-ca", "--use-openssl-ca",
|
||||
"--force-fips", "--enable-fips"};
|
||||
static constexpr auto disallowed = base::MakeFixedFlatSet<base::StringPiece>({
|
||||
"--enable-fips",
|
||||
"--force-fips",
|
||||
"--openssl-config",
|
||||
"--use-bundled-ca",
|
||||
"--use-openssl-ca",
|
||||
});
|
||||
|
||||
const auto argv = base::CommandLine::ForCurrentProcess()->argv();
|
||||
std::vector<std::string> args;
|
||||
@@ -74,7 +78,7 @@ int SetNodeCliFlags() {
|
||||
const auto& option = arg;
|
||||
#endif
|
||||
const auto stripped = base::StringPiece(option).substr(0, option.find('='));
|
||||
if (disallowed.count(stripped) != 0) {
|
||||
if (disallowed.contains(stripped)) {
|
||||
LOG(ERROR) << "The Node.js cli flag " << stripped
|
||||
<< " is not supported in Electron";
|
||||
// Node.js returns 9 from ProcessGlobalArgs for any errors encountered
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -473,51 +474,38 @@ IconLoader::IconSize GetIconSizeByString(const std::string& size) {
|
||||
}
|
||||
|
||||
// Return the path constant from string.
|
||||
int GetPathConstant(const std::string& name) {
|
||||
if (name == "appData")
|
||||
return DIR_APP_DATA;
|
||||
else if (name == "sessionData")
|
||||
return DIR_SESSION_DATA;
|
||||
else if (name == "userData")
|
||||
return chrome::DIR_USER_DATA;
|
||||
else if (name == "cache")
|
||||
constexpr int GetPathConstant(base::StringPiece name) {
|
||||
// clang-format off
|
||||
constexpr auto Lookup = base::MakeFixedFlatMap<base::StringPiece, int>({
|
||||
{"appData", DIR_APP_DATA},
|
||||
#if BUILDFLAG(IS_POSIX)
|
||||
return base::DIR_CACHE;
|
||||
{"cache", base::DIR_CACHE},
|
||||
#else
|
||||
return base::DIR_ROAMING_APP_DATA;
|
||||
{"cache", base::DIR_ROAMING_APP_DATA},
|
||||
#endif
|
||||
else if (name == "userCache")
|
||||
return DIR_USER_CACHE;
|
||||
else if (name == "logs")
|
||||
return DIR_APP_LOGS;
|
||||
else if (name == "crashDumps")
|
||||
return DIR_CRASH_DUMPS;
|
||||
else if (name == "home")
|
||||
return base::DIR_HOME;
|
||||
else if (name == "temp")
|
||||
return base::DIR_TEMP;
|
||||
else if (name == "userDesktop" || name == "desktop")
|
||||
return base::DIR_USER_DESKTOP;
|
||||
else if (name == "exe")
|
||||
return base::FILE_EXE;
|
||||
else if (name == "module")
|
||||
return base::FILE_MODULE;
|
||||
else if (name == "documents")
|
||||
return chrome::DIR_USER_DOCUMENTS;
|
||||
else if (name == "downloads")
|
||||
return chrome::DIR_DEFAULT_DOWNLOADS;
|
||||
else if (name == "music")
|
||||
return chrome::DIR_USER_MUSIC;
|
||||
else if (name == "pictures")
|
||||
return chrome::DIR_USER_PICTURES;
|
||||
else if (name == "videos")
|
||||
return chrome::DIR_USER_VIDEOS;
|
||||
{"crashDumps", DIR_CRASH_DUMPS},
|
||||
{"desktop", base::DIR_USER_DESKTOP},
|
||||
{"documents", chrome::DIR_USER_DOCUMENTS},
|
||||
{"downloads", chrome::DIR_DEFAULT_DOWNLOADS},
|
||||
{"exe", base::FILE_EXE},
|
||||
{"home", base::DIR_HOME},
|
||||
{"logs", DIR_APP_LOGS},
|
||||
{"module", base::FILE_MODULE},
|
||||
{"music", chrome::DIR_USER_MUSIC},
|
||||
{"pictures", chrome::DIR_USER_PICTURES},
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
else if (name == "recent")
|
||||
return electron::DIR_RECENT;
|
||||
{"recent", electron::DIR_RECENT},
|
||||
#endif
|
||||
else
|
||||
return -1;
|
||||
{"sessionData", DIR_SESSION_DATA},
|
||||
{"temp", base::DIR_TEMP},
|
||||
{"userCache", DIR_USER_CACHE},
|
||||
{"userData", chrome::DIR_USER_DATA},
|
||||
{"userDesktop", base::DIR_USER_DESKTOP},
|
||||
{"videos", chrome::DIR_USER_VIDEOS},
|
||||
});
|
||||
// clang-format on
|
||||
const auto* iter = Lookup.find(name);
|
||||
return iter != Lookup.end() ? iter->second : -1;
|
||||
}
|
||||
|
||||
bool NotificationCallbackWrapper(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "gin/dictionary.h"
|
||||
@@ -708,8 +709,6 @@ void BaseWindow::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
|
||||
v8::Local<v8::Object> object;
|
||||
if (value->IsObject() && value->ToObject(context).ToLocal(&object) &&
|
||||
gin::ConvertFromV8(isolate, value, &menu) && !menu.IsEmpty()) {
|
||||
menu_.Reset(isolate, menu.ToV8());
|
||||
|
||||
// We only want to update the menu if the menu has a non-zero item count,
|
||||
// or we risk crashes.
|
||||
if (menu->model()->GetItemCount() == 0) {
|
||||
@@ -717,6 +716,8 @@ void BaseWindow::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
|
||||
} else {
|
||||
window_->SetMenu(menu->model());
|
||||
}
|
||||
|
||||
menu_.Reset(isolate, menu.ToV8());
|
||||
} else if (value->IsNull()) {
|
||||
RemoveMenu();
|
||||
} else {
|
||||
@@ -760,8 +761,7 @@ void BaseWindow::SetBrowserView(
|
||||
}
|
||||
|
||||
void BaseWindow::AddBrowserView(gin::Handle<BrowserView> browser_view) {
|
||||
auto iter = browser_views_.find(browser_view->ID());
|
||||
if (iter == browser_views_.end()) {
|
||||
if (!base::Contains(browser_views_, browser_view->ID())) {
|
||||
// If we're reparenting a BrowserView, ensure that it's detached from
|
||||
// its previous owner window.
|
||||
BaseWindow* owner_window = browser_view->owner_window();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user