Compare commits

...

68 Commits

Author SHA1 Message Date
Electron Bot
f1f0ed1ecd Bump v11.4.0 2021-03-15 10:25:31 -07:00
Pedro Pontes
570db18ef2 chore: cherry-pick 6e8856624cbb from chromium (#28165)
* chore: cherry-pick 6e8856624cbb from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
2021-03-15 11:52:18 -04:00
trop[bot]
43b9988c57 chore: cherry-pick 1fe571a from node (#28108)
* chore: cherry-pick 1fe571a from node

Backports https://github.com/nodejs/node/pull/37000

* Fix merge error

* update patches

Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-03-15 04:39:08 -07:00
trop[bot]
b740cd2202 fix: handle a nil backgroundColor in win.getBackgroundColor() (#28186)
* fix: handle a nil backgroundColor in win.getBackgroundColor()

* spec: add crash case

* fix: update to fix native_views transparent color

* chore: fix lint

Co-authored-by: Samuel Attard <sattard@slack-corp.com>
Co-authored-by: Samuel Attard <sam@electronjs.org>
2021-03-15 11:08:12 +09:00
trop[bot]
592430f918 fix: convert system colors to device color space in systemPreferences (#28171)
Co-authored-by: Samuel Attard <sattard@slack-corp.com>
2021-03-13 05:01:23 -08:00
Pedro Pontes
3445fbf7dc chore: cherry-pick 18d3f86206e8 from chromium (#28097)
* chore: cherry-pick 18d3f86206e8 from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
2021-03-13 10:44:25 +09:00
Pedro Pontes
df5ff97144 cherry-pick 157601b9b9 from pdfium (#28101) 2021-03-12 09:24:23 -08:00
Pedro Pontes
3bb800ce04 chore: cherry-pick eb0c0353bf24 from chromium (#28093)
* chore: cherry-pick eb0c0353bf24 from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-03-12 19:44:21 +09:00
trop[bot]
413fbcfa18 fix: change #if defined(OS_MACOSX) to #if defined(OS_MAC) (#28151)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-03-12 16:43:24 +09:00
Pedro Pontes
8877087e51 chore: cherry-pick 38781b86f0 from chromium (#28050) 2021-03-12 16:37:40 +09:00
trop[bot]
275eecdfcb docs: fix cookies event documentation for type generation (#28138)
Co-authored-by: Samuel Attard <sattard@slack-corp.com>
2021-03-11 16:22:53 -08:00
Pedro Pontes
6ecf43c8c4 chore: cherry-pick aeb6bc551b60 from chromium (#28089)
* chore: cherry-pick aeb6bc551b60 from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-03-10 13:43:25 -05:00
Pedro Pontes
aec62a9874 chore: cherry-pick 6ed1c0c425e0 from chromium (#28091)
* chore: cherry-pick 6ed1c0c425e0 from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
2021-03-10 11:26:03 -05:00
trop[bot]
291b4f9980 fix: capturePage not resolving with hidden windows (#28074)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-03-09 13:42:49 -08:00
trop[bot]
a841bd195c build: call goma_ctl.py ensure_start directly (#28058)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-03-09 16:05:36 +09:00
Pedro Pontes
4a5a18f003 chore: cherry-pick 7e0e52df283c from chromium (#28046)
* chore: cherry-pick 7e0e52df283c from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
2021-03-08 16:58:37 -05:00
trop[bot]
5c29d3b533 chore: Add a condition to crashReporter deprecate log (#28012)
* Add a condition to crashReporter deprecate log

When developer set  submitURL to '' crash reports will be saved  at `...\AppData\Roaming\...\Crashpad\reports`, will not be uploaded to the server.
So  at this time `deprecate.log('Sending uncompressed crash reports....')`  is  unnecessary.

* Update lib/browser/api/crash-reporter.ts

change to check uploadToServer

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

Co-authored-by: liulun <xland@live.cn>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-03-07 16:31:27 +09:00
trop[bot]
e0172c45f0 fix: warning when worldSafeExecuteJavaScript is disabled (#27968)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-03-05 10:14:47 +09:00
trop[bot]
3fa9826b8b feat: expose des-ede3 cipher (#27993)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-03-04 15:38:42 -05:00
trop[bot]
e262b5040a fix: ensure owner window valid (#27948)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-03-04 16:39:08 +09:00
trop[bot]
e5eafc8ee9 fix: check web_contents() for destroyed WebContents (#27965)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-03-04 16:33:37 +09:00
trop[bot]
2bcf583bcf fix: offset browserview drag regions on macOS (#27987)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-03-04 16:32:45 +09:00
Shelley Vohr
c50d0e49c1 fix: set WebContents background color ubiquitously (#27944)
Move it from LoadURL to RenderViewCreated which is present
in all window creation cases and is called early enough to be
relevant from user prespective and after RenderWidgetHostView
is already present.

Co-authored-by: marekharanczyk <48673767+marekharanczyk@users.noreply.github.com>
2021-03-01 13:21:16 -08:00
John Kleinschmidt
26c5cc2801 fix: navigator.bluetooth.requestDevice crash (#27941)
* fix: navigator.bluetooth.requestDevice crash

* update bluetooth test to handle bluetooth permission denied

(cherry picked from commit 1c7ca277cc)
2021-03-01 12:39:54 -08:00
trop[bot]
fb5822af43 docs: fix header level of some events in app.md (#27886)
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2021-02-24 20:36:19 +09:00
trop[bot]
97626aeac8 fix: isFullScreen typo (#27863)
* fix isFullScreen typo

* Update lib/browser/api/base-window.ts

Co-authored-by: John Kleinschmidt <jkleinsc@github.com>

Co-authored-by: Tony Wu <tonywoo@fb.com>
Co-authored-by: Tony <TonyWuu@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@github.com>
2021-02-24 18:05:16 +09:00
Shelley Vohr
b8d136aeea fix: libuv hang when nodeIntegrationInSubframes enabled (#27880) 2021-02-24 17:58:56 +09:00
Erick Zhao
eed55d5923 docs: remove v5 and v6 modernization docs (#27857) 2021-02-22 12:21:16 -08:00
trop[bot]
ef4d98ac7f fix: cap sendInputEvent text length at n-1 (#27853)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-02-22 11:54:10 -08:00
Michaela Laurencin
8ae9c5c7cf fix: replace default frameName title with null check (#27813)
* fix: replace default frameName title with null check (#27521)

* refactor: replace default frameName title with null check

* add isNativeWindowOpen check in makeBrowserWindowOptions

* modify snapshot test files

* replace title with frame-name again for proxy - not native open

* modify proxy snapshot title key-value to come after height key-value

* add nativewindowopen check to null title

* fix lint and json formatting

* reformat test cases for this branch

the merged changes included some rearrangements to the json items that
do not apply to this branch, so the items were reordered according to
this branch's previous files.

* remove default frameName title for native open call and modify test txts
2021-02-22 11:07:18 -05:00
Electron Bot
1631fc9b0c Bump v11.3.0 2021-02-19 11:40:19 -08:00
trop[bot]
cc0848a86e revert: patch libuv to use posix_spawn on macOS (#27026) (#27809)
* Revert "perf: patch libuv to use posix_spawn on macOS (#27026)"

This reverts commit f69c11105f.

* Update .patches

Co-authored-by: VerteDinde <khammond@slack-corp.com>
Co-authored-by: Robo <hop2deep@gmail.com>
2021-02-19 09:50:35 -08:00
trop[bot]
c7a2b32c5a docs: update menu item '&' escaping (#27817)
Co-authored-by: mlaurencin <mlaurencin@electronjs.org>
2021-02-19 09:44:41 -08:00
trop[bot]
18cfdb1c82 fix: enableBlinkFeatures warning in webviews (#27789)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-02-19 15:46:47 +09:00
trop[bot]
1105931d0a fix: don't create last saved path if none exists (#27808)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-02-19 15:44:44 +09:00
Robo
234309497e chore: cherry-pick b712f9fd66 from chromium (#27781)
Backports https://chromium-review.googlesource.com/c/chromium/src/+/2690730
2021-02-18 17:23:41 -08:00
Calvin
6fa2ab2edd fix: restore window event redispatching on mac (#27787) 2021-02-18 16:19:13 -08:00
Robo
527c767107 chore: cherry-pick 202b40b9ae, 135a6e537f from chromium (#27780)
* chore: cherry-pick 202b40b9ae, 135a6e537f from chromium

Backports:
https://chromium-review.googlesource.com/c/chromium/src/+/2687828
https://chromium-review.googlesource.com/c/chromium/src/+/2688137

* update patches

* fix: compilation errors

Co-authored-by: Electron Bot <electron@github.com>
2021-02-18 15:34:00 -08:00
Robo
15468432c8 chore: cherry-pick 59f3ca2780 from chromium (#27778)
Backports https://chromium-review.googlesource.com/c/chromium/src/+/2679121
2021-02-18 14:11:11 -08:00
Robo
af34655cb7 chore: cherry-pick 3a6f6fbfd8 from chromium (#27776)
* chore: cherry-pick 3a6f6fbfd8 from chromium

Backports https://chromium-review.googlesource.com/c/chromium/src/+/2692927

* fix: compilation errors
2021-02-18 13:41:13 -08:00
Robo
111b737ae4 chore: cherry-pick 84853ff62a from v8 (#27777)
Backports https://chromium-review.googlesource.com/c/v8/v8/+/2689191
2021-02-18 13:21:49 -08:00
Robo
e33df2c7b6 chore: cherry-pick 62bda83979 from chromium (#27779)
Backports https://chromium-review.googlesource.com/c/chromium/src/+/2651183
2021-02-18 11:11:08 -08:00
Robo
f30018b4b0 fix: crash in crypto.createDiffieHellman (#27766) 2021-02-18 10:34:56 +09:00
Eryk Rakowski
795200a838 feat: add win.setTopBrowserView() so that BrowserViews can be raised (#27007) (#27712)
* feat: Raise a browser view via `BrowserWindow.setTopBrowserView()`.

This is similar to removing and re-adding a browser view, but avoids a visible flicker as the browser view is not removed from the window when using `setTopBrowserView`. Note: if the given browser view is not attached to the window, it will be added.

This commit contains the macOS implementation.

* feat: setTopBrowserView support for Windows and Linux

* docs: add info about setTopBrowserView

* docs: Clarify behavior when browserView is not yet attached.

* fix: throw en error when browserView is not attached to the window

* fix: build error

* fix: test

* fix: add test case

* fix: tests

* fix: reparenting

* fix: close second window in tests

Co-authored-by: sentialx <sentialx@gmail.com>

Co-authored-by: Stewart Lord <stew@offbynone.com>
2021-02-18 10:20:55 +09:00
trop[bot]
64d4e5969f fix: check WebContents before emitting render-process-gone event (#27757)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-02-18 10:17:03 +09:00
trop[bot]
be670059a6 test: fix flaky did-change-theme-color test (#27767)
* test: move did-change-theme-color test to main

* test: enable did-change-theme-color test for WOA

Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-02-18 10:15:15 +09:00
Jeremy Rose
5d64c42801 chore: cherry-pick 76cb1cc32baa from chromium (#27750)
* chore: cherry-pick 76cb1cc32baa from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
2021-02-17 10:22:14 -08:00
Jeremy Rose
5b81463423 feat: implement allowFileAccess loadExtension option (#27703)
Co-authored-by: Сковорода Никита Андреевич <chalkerx@gmail.com>
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
2021-02-16 15:32:37 -08:00
Erick Zhao
92df786066 PATCH (#27558) 2021-02-15 11:59:18 +09:00
trop[bot]
59aaa65381 ci: ignore errors deleting user app directories on WOA testing (#27728)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-02-15 11:49:23 +09:00
Raymond Zhao
715ffe4e51 fix: Replace ClearFilterData with InvalidateFilterData (#27699) 2021-02-15 09:54:48 +09:00
trop[bot]
51bb0ad36d docs: remove references to remote from docs (#27715)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-02-12 11:41:22 -06:00
Jeremy Rose
4636dfe68e chore: cherry-pick df438f22f7d2 from chromium (#27609) 2021-02-11 16:37:05 -08:00
Jeremy Rose
e3f6b2b082 chore: cherry-pick b0d3d3e85fa6 from skia (#27614)
* chore: cherry-pick b0d3d3e85fa6 from skia

* Update config.json

* resolve conflict
2021-02-11 15:58:51 -08:00
trop[bot]
968db9285f docs: update menu example to avoid remote (#27714)
* docs: update menu example to avoid remote

* Update menu.md

* lint

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2021-02-11 13:48:56 -08:00
trop[bot]
19f8ea37a5 perf: patch libuv to use posix_spawn on macOS (#27654)
* perf: patch libuv to use posix_spawn on macOS

patch libuv to fix a performance regression in macOS >= 11

Spawning child processes in an Electron application with a hardened
runtime has become slow in macOS Big Sur. This patch is a squashed
version of https://github.com/libuv/libuv/pull/3064

This patch should be removed when libuv PR 3064 is merged.

Fixes: https://github.com/libuv/libuv/issues/3050
Fixes: https://github.com/electron/electron/issues/26143
PR-URL: https://github.com/libuv/libuv/pull/3064

Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com>
Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>

* Remove trailing whitespaces from patch file

* update patches

* Update patch description

* Update .patches

Co-authored-by: Pat DeSantis <pdesantis3@gmail.com>
Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: Robo <hop2deep@gmail.com>
2021-02-10 16:53:51 -08:00
trop[bot]
99eb8ac059 chore: cherry-pick 0c8b6e41 from v8 (#27684)
* chore: cherry-pick 0c8b6e41 from v8

Backports https://chromium-review.googlesource.com/c/v8/v8/+/2679688

* update patches

* Update .patches

* update patches

Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-02-10 16:53:22 -08:00
Shelley Vohr
3bcdc276e1 fix: BrowserView rendering flicker (#27659) 2021-02-10 08:02:24 -08:00
trop[bot]
85dad8fb18 refactor: load preload script directly as a string (#27662)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-02-09 14:14:38 -08:00
trop[bot]
5f60640ddc perf: optimize data structures in context_bridge::ObjectCache (#27664)
* Use std::forward_list instead of base::LinkedList for better perf,
more consistent memory management.  Better than std::list because we
don't need the double-linked-list behavior of std::list
* Use std::unordered_map instead of std::map for the v8 hash table

Co-authored-by: Samuel Attard <sattard@slack-corp.com>
2021-02-09 08:31:59 -08:00
trop[bot]
f9e6e6eff9 fix: do not run display check on "closed" windows in tray (#27669)
* fix: only run display check on restored wndow if minimized

* fix: don't run display check on hidden, non-minimized windows

Co-authored-by: VerteDinde <keeleymhammond@gmail.com>
2021-02-09 08:31:10 -08:00
Raymond Zhao
7695f3f1ee fix: Backport SVG filter invalidation fix from Chromium (#27635) 2021-02-08 10:15:12 -05:00
trop[bot]
3492077f33 fix: memory leak in BrowserWindow (#27640)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-02-08 17:36:00 +09:00
trop[bot]
0933c6796c fix: clean up base::LinkedList in context_bridge::ObjectCache (#27638)
base::LinkedList does not delete its members on destruction. We need to
manually ensure the linkedlist is empty when the ObjectCache is
destroyed.

Fixes #27039

Notes: Fixed memory leak when sending non-primitives over the context
bridge

Co-authored-by: Samuel Attard <sattard@slack-corp.com>
2021-02-05 14:25:13 -08:00
Electron Bot
137f45750f Bump v11.2.3 2021-02-05 10:09:13 -08:00
Jeremy Rose
a0175137fb chore: cherry-pick 36abafa0a316 from v8 (#27624) 2021-02-05 09:43:20 -08:00
Erick Zhao
90eee5f909 fix: cherry-pick 5c7ad5393f74 from chromium (#27584)
* patch

* patch more

* patch more more
2021-02-03 20:47:35 -08:00
trop[bot]
a09dada8e4 fix: crash when loadExtension fails (#27588)
Co-authored-by: samuelmaddock <samuel.maddock@gmail.com>
2021-02-03 16:28:28 +09:00
127 changed files with 12590 additions and 570 deletions

View File

@@ -324,7 +324,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
npm install
mkdir third_party
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
node -e "require('./src/utils/goma.js').ensure()"
third_party/goma/goma_ctl.py ensure_start
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
cd ..

View File

@@ -1 +1 @@
11.2.2
11.4.0

View File

@@ -93,6 +93,6 @@ steps:
condition: always()
- powershell: |
Remove-Item -path $env:APPDATA/Electron* -Recurse
Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore
displayName: 'Delete user app data directories'
condition: always()

View File

@@ -390,7 +390,7 @@ which contains more information about why the render process disappeared. It
isn't always because it crashed. The `killed` boolean can be replaced by
checking `reason === 'killed'` when you switch to that event.
#### Event: 'render-process-gone'
### Event: 'render-process-gone'
Returns:
@@ -409,7 +409,7 @@ Returns:
Emitted when the renderer process unexpectedly disappears. This is normally
because it was crashed or killed.
#### Event: 'child-process-gone'
### Event: 'child-process-gone'
Returns:
@@ -502,7 +502,7 @@ Returns:
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will make it return empty sources.
### Event: 'remote-require'
### Event: 'remote-require' _Deprecated_
Returns:
@@ -514,7 +514,7 @@ Emitted when `remote.require()` is called in the renderer process of `webContent
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-global'
### Event: 'remote-get-global' _Deprecated_
Returns:
@@ -526,7 +526,7 @@ Emitted when `remote.getGlobal()` is called in the renderer process of `webConte
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-builtin'
### Event: 'remote-get-builtin' _Deprecated_
Returns:
@@ -538,7 +538,7 @@ Emitted when `remote.getBuiltin()` is called in the renderer process of `webCont
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-current-window'
### Event: 'remote-get-current-window' _Deprecated_
Returns:
@@ -549,7 +549,7 @@ Emitted when `remote.getCurrentWindow()` is called in the renderer process of `w
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-current-web-contents'
### Event: 'remote-get-current-web-contents' _Deprecated_
Returns:

View File

@@ -8,9 +8,6 @@ Process: [Main](../glossary.md#main-process)
// In the main process.
const { BrowserWindow } = require('electron')
// Or use `remote` from the renderer process.
// const { BrowserWindow } = require('electron').remote
const win = new BrowserWindow({ width: 800, height: 600 })
// Load a remote URL
@@ -733,7 +730,7 @@ The method will also not return if the extension's manifest is missing or incomp
is emitted.
**Note:** This method is deprecated. Instead, use
[`ses.loadExtension(path)`](session.md#sesloadextensionpath).
[`ses.loadExtension(path)`](session.md#sesloadextensionpath-options).
#### `BrowserWindow.removeExtension(name)` _Deprecated_
@@ -775,7 +772,7 @@ The method will also not return if the extension's manifest is missing or incomp
is emitted.
**Note:** This method is deprecated. Instead, use
[`ses.loadExtension(path)`](session.md#sesloadextensionpath).
[`ses.loadExtension(path)`](session.md#sesloadextensionpath-options).
#### `BrowserWindow.removeDevToolsExtension(name)` _Deprecated_
@@ -1444,7 +1441,7 @@ Returns `Boolean` - Whether the window's document has been edited.
Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty.
#### `win.loadURL(url[, options])`
@@ -1852,6 +1849,13 @@ Replacement API for setBrowserView supporting work with multi browser views.
* `browserView` [BrowserView](browser-view.md)
#### `win.setTopBrowserView(browserView)` _Experimental_
* `browserView` [BrowserView](browser-view.md)
Raises `browserView` above other `BrowserView`s attached to `win`.
Throws an error if `browserView` is not attached to `win`.
#### `win.getBrowserViews()` _Experimental_
Returns `BrowserView[]` - an array of all BrowserViews that have been attached

View File

@@ -45,6 +45,8 @@ The following events are available on instances of `Cookies`:
#### Event: 'changed'
Returns:
* `event` Event
* `cookie` [Cookie](structures/cookie.md) - The cookie that was changed.
* `cause` String - The cause of the change with one of the following values:

View File

@@ -11,14 +11,6 @@ const { dialog } = require('electron')
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
```
The Dialog is opened from Electron's main thread. If you want to use the dialog
object from a renderer process, remember to access it using the remote:
```javascript
const { dialog } = require('electron').remote
console.log(dialog)
```
## Methods
The `dialog` module has the following methods:

View File

@@ -15,7 +15,7 @@ extension capabilities.
Electron only supports loading unpacked extensions (i.e., `.crx` files do not
work). Extensions are installed per-`session`. To load an extension, call
[`ses.loadExtension`](session.md#sesloadextensionpath):
[`ses.loadExtension`](session.md#sesloadextensionpath-options):
```js
const { session } = require('electron')

View File

@@ -112,13 +112,19 @@ optional parameter can be used to forward mouse move messages to the web page,
allowing events such as `mouseleave` to be emitted:
```javascript
const win = require('electron').remote.getCurrentWindow()
const { ipcRenderer } = require('electron')
const el = document.getElementById('clickThroughElement')
el.addEventListener('mouseenter', () => {
win.setIgnoreMouseEvents(true, { forward: true })
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
})
el.addEventListener('mouseleave', () => {
win.setIgnoreMouseEvents(false)
ipcRenderer.send('set-ignore-mouse-events', false)
})
// Main process
const { ipcMain } = require('electron')
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args)
})
```

View File

@@ -22,8 +22,10 @@ Sets `menu` as the application menu on macOS. On Windows and Linux, the
Also on Windows and Linux, you can use a `&` in the top-level item name to
indicate which letter should get a generated accelerator. For example, using
`&File` for the file menu would result in a generated `Alt-F` accelerator that
opens the associated menu. The indicated character in the button label gets an
underline. The `&` character is not displayed on the button label.
opens the associated menu. The indicated character in the button label then gets an
underline, and the `&` character is not displayed on the button label.
In order to escape the `&` character in an item name, add a proceeding `&`. For example, `&&File` would result in `&File` displayed on the button label.
Passing `null` will suppress the default menu. On Windows and Linux,
this has the additional effect of removing the menu bar from the window.
@@ -141,13 +143,7 @@ can have a submenu.
## Examples
The `Menu` class is only available in the main process, but you can also use it
in the render process via the [`remote`](remote.md) module.
### Main process
An example of creating the application menu in the main process with the
simple template API:
An example of creating the application menu with the simple template API:
```javascript
const { app, Menu } = require('electron')
@@ -257,26 +253,36 @@ Menu.setApplicationMenu(menu)
### Render process
Below is an example of creating a menu dynamically in a web page
(render process) by using the [`remote`](remote.md) module, and showing it when
the user right clicks the page:
To create menus initiated by the renderer process, send the required
information to the main process using IPC and have the main process display the
menu on behalf of the renderer.
```html
<!-- index.html -->
<script>
const { remote } = require('electron')
const { Menu, MenuItem } = remote
const menu = new Menu()
menu.append(new MenuItem({ label: 'MenuItem1', click() { console.log('item 1 clicked') } }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }))
Below is an example of showing a menu when the user right clicks the page:
```js
// renderer
window.addEventListener('contextmenu', (e) => {
e.preventDefault()
menu.popup({ window: remote.getCurrentWindow() })
}, false)
</script>
ipcRenderer.send('show-context-menu')
})
ipcRenderer.on('context-menu-command', (e, command) => {
// ...
})
// main
ipcMain.on('show-context-menu', (event) => {
const template = [
{
label: 'Menu Item 1',
click: () => { event.sender.send('context-menu-command', 'menu-item-1') }
},
{ type: 'separator' },
{ label: 'Menu Item 2', type: 'checkbox', checked: true }
]
const menu = Menu.buildFromTemplate(template)
menu.popup(BrowserWindow.fromWebContents(event.sender))
})
```
## Notes on macOS Application Menu

View File

@@ -1,10 +0,0 @@
## Modernization
The Electron team is currently undergoing an initiative to modernize our API in a few concrete ways. These include: updating our modules to use idiomatic JS properties instead of separate `getPropertyX` and `setpropertyX`, converting callbacks to promises, and removing some other anti-patterns present in our APIs. The current status of the Promise initiative can be tracked in the [promisification](promisification.md) tracking file.
As we work to perform these updates, we seek to create the least disruptive amount of change at any given time, so as many changes as possible will be introduced in a backward compatible manner and deprecated after enough time has passed to give users a chance to upgrade their API calls.
This document and its child documents will be updated to reflect the latest status of our API changes.
* [Promisification](promisification.md)
* [Property Updates](property-updates.md)

View File

@@ -1,42 +0,0 @@
## Promisification
The Electron team recently underwent an initiative to convert callback-based APIs to Promise-based ones. See converted functions below:
- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
- [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript)
- [contents.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#printToPDF)
- [contents.savePage(fullPath, saveType, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#savePage)
- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
- [contentTracing.startRecording(options, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#startRecording)
- [contentTracing.stopRecording(resultFilePath, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#stopRecording)
- [contentTracing.getTraceBufferUsage(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getTraceBufferUsage)
- [cookies.flushStore(callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#flushStore)
- [cookies.get(filter, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#get)
- [cookies.remove(url, name, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#remove)
- [cookies.set(details, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#set)
- [debugger.sendCommand(method[, commandParams, callback])](https://github.com/electron/electron/blob/master/docs/api/debugger.md#sendCommand)
- [desktopCapturer.getSources(options, callback)](https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md#getSources)
- [dialog.showOpenDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showOpenDialog)
- [dialog.showSaveDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showSaveDialog)
- [inAppPurchase.purchaseProduct(productID, quantity, callback)](https://github.com/electron/electron/blob/master/docs/api/in-app-purchase.md#purchaseProduct)
- [inAppPurchase.getProducts(productIDs, callback)](https://github.com/electron/electron/blob/master/docs/api/in-app-purchase.md#getProducts)
- [dialog.showMessageBox([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showMessageBox)
- [dialog.showCertificateTrustDialog([browserWindow, ]options, callback)](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showCertificateTrustDialog)
- [netLog.stopLogging([callback])](https://github.com/electron/electron/blob/master/docs/api/net-log.md#stopLogging)
- [protocol.isProtocolHandled(scheme, callback)](https://github.com/electron/electron/blob/master/docs/api/protocol.md#isProtocolHandled)
- [ses.clearHostResolverCache([callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearHostResolverCache)
- [ses.clearStorageData([options, callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearStorageData)
- [ses.setProxy(config, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#setProxy)
- [ses.resolveProxy(url, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#resolveProxy)
- [ses.getCacheSize(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getCacheSize)
- [ses.clearAuthCache(options[, callback])](https://github.com/electron/electron/blob/master/docs/api/session.md#clearAuthCache)
- [ses.clearCache(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#clearCache)
- [ses.getBlobData(identifier, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getBlobData)
- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal)
- [webFrame.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScript)
- [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld)
- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
- [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript)
- [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF)
- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)

View File

@@ -1,41 +0,0 @@
## Property Updates
The Electron team is currently undergoing an initiative to convert separate getter and setter functions in Electron to bespoke properties with `get` and `set` functionality. During this transition period, both the new properties and old getters and setters of these functions will work correctly and be documented.
## Candidates
* `BrowserWindow`
* `menubarVisible`
* `crashReporter` module
* `uploadToServer`
* `webFrame` modules
* `zoomFactor`
* `zoomLevel`
* `audioMuted`
* `<webview>`
* `zoomFactor`
* `zoomLevel`
* `audioMuted`
## Converted Properties
* `app` module
* `accessibilitySupport`
* `applicationMenu`
* `badgeCount`
* `name`
* `DownloadItem` class
* `savePath`
* `BrowserWindow` module
* `autohideMenuBar`
* `resizable`
* `maximizable`
* `minimizable`
* `fullscreenable`
* `movable`
* `closable`
* `backgroundThrottling`
* `NativeImage`
* `isMacTemplateImage`
* `SystemPreferences` module
* `appLevelAppearance`

View File

@@ -88,26 +88,17 @@ and preload.js:
```js
// This file is loaded whenever a javascript context is created. It runs in a
// private scope that can access a subset of Electron renderer APIs. We must be
// careful to not leak any objects into the global scope!
const { ipcRenderer, remote } = require('electron')
const fs = remote.require('fs')
// read a configuration file using the `fs` module
const buf = fs.readFileSync('allowed-popup-urls.json')
const allowedUrls = JSON.parse(buf.toString('utf8'))
// private scope that can access a subset of Electron renderer APIs. Without
// contextIsolation enabled, it's possible to accidentally leak privileged
// globals like ipcRenderer to web content.
const { ipcRenderer } = require('electron')
const defaultWindowOpen = window.open
function customWindowOpen (url, ...args) {
if (allowedUrls.indexOf(url) === -1) {
ipcRenderer.sendSync('blocked-popup-notification', location.origin, url)
return null
}
return defaultWindowOpen(url, ...args)
window.open = function customWindowOpen (url, ...args) {
ipcRenderer.send('report-window-open', location.origin, url, args)
return defaultWindowOpen(url + '?from_electron=1', ...args)
}
window.open = customWindowOpen
```
Important things to notice in the preload script:
@@ -115,8 +106,6 @@ Important things to notice in the preload script:
- Even though the sandboxed renderer doesn't have Node.js running, it still has
access to a limited node-like environment: `Buffer`, `process`, `setImmediate`,
`clearImmediate` and `require` are available.
- The preload script can indirectly access all APIs from the main process through the
`remote` and `ipcRenderer` modules.
- The preload script must be contained in a single script, but it is possible to have
complex preload code composed with multiple modules by using a tool like
webpack or browserify. An example of using browserify is below.
@@ -144,15 +133,12 @@ following modules:
- `desktopCapturer`
- `ipcRenderer`
- `nativeImage`
- `remote`
- `webFrame`
- `events`
- `timers`
- `url`
More may be added as needed to expose more Electron APIs in the sandbox, but any
module in the main process can already be used through
`electron.remote.require`.
More may be added as needed to expose more Electron APIs in the sandbox.
## Rendering untrusted content

View File

@@ -568,9 +568,13 @@ will not work on non-persistent (in-memory) sessions.
**Note:** On macOS and Windows 10 this word will be removed from the OS custom dictionary as well
#### `ses.loadExtension(path)`
#### `ses.loadExtension(path[, options])`
* `path` String - Path to a directory containing an unpacked Chrome extension
* `options` Object (optional)
* `allowFileAccess` Boolean - Whether to allow the extension to read local files over `file://`
protocol and inject content scripts into `file://` pages. This is required e.g. for loading
devtools extensions on `file://` URLs. Defaults to false.
Returns `Promise<Extension>` - resolves when the extension is loaded.
@@ -593,7 +597,11 @@ const { app, session } = require('electron')
const path = require('path')
app.on('ready', async () => {
await session.defaultSession.loadExtension(path.join(__dirname, 'react-devtools'))
await session.defaultSession.loadExtension(
path.join(__dirname, 'react-devtools'),
// allowFileAccess is required to load the devtools extension on file:// URLs.
{ allowFileAccess: true }
)
// Note that in order to use the React DevTools extension, you'll need to
// download and unzip a copy of the extension.
})

View File

@@ -9,7 +9,7 @@ the [native modules](../tutorial/using-native-node-modules.md)).
Electron also provides some extra built-in modules for developing native
desktop applications. Some modules are only available in the main process, some
are only available in the renderer process (web page), and some can be used in
both processes.
either process type.
The basic rule is: if a module is [GUI][gui] or low-level system related, then
it should be only available in the main process. You need to be familiar with
@@ -29,15 +29,15 @@ app.whenReady().then(() => {
```
The renderer process is no different than a normal web page, except for the
extra ability to use node modules:
extra ability to use node modules if `nodeIntegration` is enabled:
```html
<!DOCTYPE html>
<html>
<body>
<script>
const { app } = require('electron').remote
console.log(app.getVersion())
const fs = require('fs')
console.log(fs.readFileSync(__filename, 'utf8'))
</script>
</body>
</html>

View File

@@ -785,7 +785,7 @@ Returns:
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
Calling `event.preventDefault()` will make it return empty sources.
#### Event: 'remote-require'
#### Event: 'remote-require' _Deprecated_
Returns:
@@ -796,7 +796,7 @@ Emitted when `remote.require()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-global'
#### Event: 'remote-get-global' _Deprecated_
Returns:
@@ -807,7 +807,7 @@ Emitted when `remote.getGlobal()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-builtin'
#### Event: 'remote-get-builtin' _Deprecated_
Returns:
@@ -818,7 +818,7 @@ Emitted when `remote.getBuiltin()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-current-window'
#### Event: 'remote-get-current-window' _Deprecated_
Returns:
@@ -828,7 +828,7 @@ Emitted when `remote.getCurrentWindow()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-current-web-contents'
#### Event: 'remote-get-current-web-contents' _Deprecated_
Returns:
@@ -1482,7 +1482,7 @@ An example of showing devtools in a `<webview>` tag:
<webview id="browser" src="https://github.com"></webview>
<webview id="devtools" src="about:blank"></webview>
<script>
const { webContents } = require('electron').remote
const { ipcRenderer } = require('electron')
const emittedOnce = (element, eventName) => new Promise(resolve => {
element.addEventListener(eventName, event => resolve(event), { once: true })
})
@@ -1491,16 +1491,26 @@ An example of showing devtools in a `<webview>` tag:
const browserReady = emittedOnce(browserView, 'dom-ready')
const devtoolsReady = emittedOnce(devtoolsView, 'dom-ready')
Promise.all([browserReady, devtoolsReady]).then(() => {
const browser = webContents.fromId(browserView.getWebContentsId())
const devtools = webContents.fromId(devtoolsView.getWebContentsId())
browser.setDevToolsWebContents(devtools)
browser.openDevTools()
const targetId = browserView.getWebContentsId()
const devtoolsId = devtoolsView.getWebContentsId()
ipcRenderer.send('open-devtools', targetId, devtoolsId)
})
</script>
</body>
</html>
```
```js
// Main process
const { ipcMain, webContents } = require('electron')
ipcMain.on('open-devtools', (event, targetContentsId, devtoolsContentsId) => {
const target = webContents.fromId(targetContentsId)
const devtools = webContents.fromId(devtoolsContentsId)
target.setDevToolsWebContents(devtools)
target.openDevTools()
})
```
An example of showing devtools in a `BrowserWindow`:
```js

View File

@@ -137,7 +137,7 @@ This option is disabled by default in the guest page.
```
A `Boolean`. When this attribute is `false` the guest page in `webview` will not have access
to the [`remote`](remote.md) module. The remote module is available by default.
to the [`remote`](remote.md) module. The remote module is unavailable by default.
### `plugins`

View File

@@ -519,6 +519,55 @@ Note that `webkitdirectory` no longer exposes the path to the selected folder.
If you require the path to the selected folder rather than the folder contents,
see the `dialog.showOpenDialog` API ([link](https://github.com/electron/electron/blob/master/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options)).
### API Changed: Callback-based versions of promisified APIs
Electron 5 and Electron 6 introduced Promise-based versions of existing
asynchronous APIs and deprecated their older, callback-based counterparts.
In Electron 7, all deprecated callback-based APIs are now removed.
These functions now only return Promises:
* `app.getFileIcon()` [#15742](https://github.com/electron/electron/pull/15742)
* `app.dock.show()` [#16904](https://github.com/electron/electron/pull/16904)
* `contentTracing.getCategories()` [#16583](https://github.com/electron/electron/pull/16583)
* `contentTracing.getTraceBufferUsage()` [#16600](https://github.com/electron/electron/pull/16600)
* `contentTracing.startRecording()` [#16584](https://github.com/electron/electron/pull/16584)
* `contentTracing.stopRecording()` [#16584](https://github.com/electron/electron/pull/16584)
* `contents.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312)
* `cookies.flushStore()` [#16464](https://github.com/electron/electron/pull/16464)
* `cookies.get()` [#16464](https://github.com/electron/electron/pull/16464)
* `cookies.remove()` [#16464](https://github.com/electron/electron/pull/16464)
* `cookies.set()` [#16464](https://github.com/electron/electron/pull/16464)
* `debugger.sendCommand()` [#16861](https://github.com/electron/electron/pull/16861)
* `dialog.showCertificateTrustDialog()` [#17181](https://github.com/electron/electron/pull/17181)
* `inAppPurchase.getProducts()` [#17355](https://github.com/electron/electron/pull/17355)
* `inAppPurchase.purchaseProduct()`[#17355](https://github.com/electron/electron/pull/17355)
* `netLog.stopLogging()` [#16862](https://github.com/electron/electron/pull/16862)
* `session.clearAuthCache()` [#17259](https://github.com/electron/electron/pull/17259)
* `session.clearCache()` [#17185](https://github.com/electron/electron/pull/17185)
* `session.clearHostResolverCache()` [#17229](https://github.com/electron/electron/pull/17229)
* `session.clearStorageData()` [#17249](https://github.com/electron/electron/pull/17249)
* `session.getBlobData()` [#17303](https://github.com/electron/electron/pull/17303)
* `session.getCacheSize()` [#17185](https://github.com/electron/electron/pull/17185)
* `session.resolveProxy()` [#17222](https://github.com/electron/electron/pull/17222)
* `session.setProxy()` [#17222](https://github.com/electron/electron/pull/17222)
* `shell.openExternal()` [#16176](https://github.com/electron/electron/pull/16176)
* `webContents.loadFile()` [#15855](https://github.com/electron/electron/pull/15855)
* `webContents.loadURL()` [#15855](https://github.com/electron/electron/pull/15855)
* `webContents.hasServiceWorker()` [#16535](https://github.com/electron/electron/pull/16535)
* `webContents.printToPDF()` [#16795](https://github.com/electron/electron/pull/16795)
* `webContents.savePage()` [#16742](https://github.com/electron/electron/pull/16742)
* `webFrame.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312)
* `webFrame.executeJavaScriptInIsolatedWorld()` [#17312](https://github.com/electron/electron/pull/17312)
* `webviewTag.executeJavaScript()` [#17312](https://github.com/electron/electron/pull/17312)
* `win.capturePage()` [#15743](https://github.com/electron/electron/pull/15743)
These functions now have two forms, synchronous and Promise-based asynchronous:
* `dialog.showMessageBox()`/`dialog.showMessageBoxSync()` [#17298](https://github.com/electron/electron/pull/17298)
* `dialog.showOpenDialog()`/`dialog.showOpenDialogSync()` [#16973](https://github.com/electron/electron/pull/16973)
* `dialog.showSaveDialog()`/`dialog.showSaveDialogSync()` [#17054](https://github.com/electron/electron/pull/17054)
## Planned Breaking API Changes (6.0)
### API Changed: `win.setMenu(null)` is now `win.removeMenu()`
@@ -530,19 +579,6 @@ win.setMenu(null)
win.removeMenu()
```
### API Changed: `contentTracing.getTraceBufferUsage()` is now a promise
```js
// Deprecated
contentTracing.getTraceBufferUsage((percentage, value) => {
// do something
})
// Replace with
contentTracing.getTraceBufferUsage().then(infoObject => {
// infoObject has percentage and value fields
})
```
### API Changed: `electron.screen` in the renderer process should be accessed via `remote`
```js
@@ -679,6 +715,31 @@ webFrame.setSpellCheckProvider('en-US', {
})
```
### API Changed: `webContents.getZoomLevel` and `webContents.getZoomFactor` are now synchronous
`webContents.getZoomLevel` and `webContents.getZoomFactor` no longer take callback parameters,
instead directly returning their number values.
```js
// Deprecated
webContents.getZoomLevel((level) => {
console.log(level)
})
// Replace with
const level = webContents.getZoomLevel()
console.log(level)
```
```js
// Deprecated
webContents.getZoomFactor((factor) => {
console.log(factor)
})
// Replace with
const factor = webContents.getZoomFactor()
console.log(factor)
```
## Planned Breaking API Changes (4.0)
The following list includes the breaking API changes made in Electron 4.0.

View File

@@ -69,8 +69,7 @@ way of figuring out which is which.
### Which Process Should I Attach to?
Code executed within the main process (that is, code found in or eventually run
by your main JavaScript file) as well as code called using the remote
(`require('electron').remote`) will run inside the main process, while other
by your main JavaScript file) will run inside the main process, while other
code will execute inside its respective renderer process.
You can be attached to multiple programs when you are debugging, but only one

View File

@@ -1,7 +1,11 @@
const { BrowserWindow, app } = require('electron')
const { BrowserWindow, app, screen, ipcMain } = require('electron')
let mainWindow = null
ipcMain.handle('get-screen-size', () => {
return screen.getPrimaryDisplay().workAreaSize
})
function createWindow () {
const windowOptions = {
width: 600,

View File

@@ -1,5 +1,4 @@
const { desktopCapturer } = require('electron')
const { screen, shell } = require('electron').remote
const { desktopCapturer, shell, ipcRenderer } = require('electron')
const fs = require('fs')
const os = require('os')
@@ -8,9 +7,9 @@ const path = require('path')
const screenshot = document.getElementById('screen-shot')
const screenshotMsg = document.getElementById('screenshot-path')
screenshot.addEventListener('click', (event) => {
screenshot.addEventListener('click', async (event) => {
screenshotMsg.textContent = 'Gathering screens...'
const thumbSize = determineScreenShotSize()
const thumbSize = await determineScreenShotSize()
const options = { types: ['screen'], thumbnailSize: thumbSize }
desktopCapturer.getSources(options, (error, sources) => {
@@ -33,8 +32,8 @@ screenshot.addEventListener('click', (event) => {
})
})
function determineScreenShotSize () {
const screenSize = screen.getPrimaryDisplay().workAreaSize
async function determineScreenShotSize () {
const screenSize = await ipcRenderer.invoke('get-screen-size')
const maxDimension = Math.max(screenSize.width, screenSize.height)
return {
width: maxDimension * window.devicePixelRatio,

View File

@@ -1,23 +1,20 @@
const { app, BrowserWindow } = require('electron')
const { app, BrowserWindow, ipcMain } = require('electron')
let mainWindow = null
ipcMain.on('create-frameless-window', (event, {url}) => {
const win = new BrowserWindow({ frame: false })
win.loadURL(url)
})
function createWindow () {
const windowOptions = {
const mainWindow = new BrowserWindow({
width: 600,
height: 400,
title: 'Create a frameless window',
webPreferences: {
nodeIntegration: true
}
}
mainWindow = new BrowserWindow(windowOptions)
mainWindow.loadFile('index.html')
mainWindow.on('closed', () => {
mainWindow = null
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {

View File

@@ -1,12 +1,8 @@
const { BrowserWindow } = require('electron').remote
const { ipcRenderer } = require('electron')
const newWindowBtn = document.getElementById('frameless-window')
newWindowBtn.addEventListener('click', (event) => {
let win = new BrowserWindow({ frame: false })
win.on('close', () => { win = null })
win.loadURL('data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>')
win.show()
newWindowBtn.addEventListener('click', () => {
const url = 'data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>'
ipcRenderer.send('create-frameless-window', { url })
})

View File

@@ -1,13 +1,14 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
ipcMain.on('create-frameless-window', (event, {url}) => {
const win = new BrowserWindow({ frame: false })
win.loadURL(url)
})
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
@@ -17,17 +18,6 @@ function createWindow () {
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished

View File

@@ -1,25 +1,8 @@
const { BrowserWindow } = require('electron').remote
const shell = require('electron').shell
const { ipcRenderer } = require('electron')
const framelessWindowBtn = document.getElementById('frameless-window')
const newWindowBtn = document.getElementById('frameless-window')
const links = document.querySelectorAll('a[href]')
framelessWindowBtn.addEventListener('click', (event) => {
const modalPath = 'https://electronjs.org'
let win = new BrowserWindow({ frame: false })
win.on('close', () => { win = null })
win.loadURL(modalPath)
win.show()
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
newWindowBtn.addEventListener('click', () => {
const url = 'data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>'
ipcRenderer.send('create-frameless-window', { url })
})

View File

@@ -1,9 +1,20 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const { app, BrowserWindow, ipcMain } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
ipcMain.on('create-demo-window', (event) => {
const win = new BrowserWindow({ width: 400, height: 275 })
function updateReply() {
event.sender.send('bounds-changed', {
size: win.getSize(),
position: win.getPosition()
})
}
win.on('resize', updateReply)
win.on('move', updateReply)
win.loadURL('https://electronjs.org')
})
function createWindow () {
// Create the browser window.
@@ -17,17 +28,6 @@ function createWindow () {
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished

View File

@@ -1,27 +1,17 @@
const { BrowserWindow } = require('electron').remote
const shell = require('electron').shell
const { shell, ipcRenderer } = require('electron')
const manageWindowBtn = document.getElementById('manage-window')
const links = document.querySelectorAll('a[href]')
let win
ipcRenderer.on('bounds-changed', (event, bounds) => {
const manageWindowReply = document.getElementById('manage-window-reply')
const message = `Size: ${bounds.size} Position: ${bounds.position}`
manageWindowReply.textContent = message
})
manageWindowBtn.addEventListener('click', (event) => {
const modalPath = 'https://electronjs.org'
win = new BrowserWindow({ width: 400, height: 275 })
win.on('resize', updateReply)
win.on('move', updateReply)
win.on('close', () => { win = null })
win.loadURL(modalPath)
win.show()
function updateReply () {
const manageWindowReply = document.getElementById('manage-window-reply')
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
manageWindowReply.innerText = message
}
ipcRenderer.send('create-demo-window')
})
Array.prototype.forEach.call(links, (link) => {

View File

@@ -7,7 +7,7 @@
<h2>Create a new window</h2>
<h3>Supports: Win, macOS, Linux <span>|</span> Process: Main</h3>
<button id="new-window">View Demo</button>
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app. This main process module can be used from the renderer process with the <code>remote</code> module, as is shown in this demo.</p>
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app.</p>
<p>There are a lot of options when creating a new window. A few are in this demo, but visit the <a id="browser-window-link" href="">documentation<span>(opens in new window)</span></a>
<div>
<h2>ProTip</h2>

View File

@@ -1,13 +1,14 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const { app, BrowserWindow, ipcMain } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
ipcMain.on('new-window', (event, { url, width, height }) => {
const win = new BrowserWindow({ width, height })
win.loadURL(url)
})
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
@@ -17,17 +18,6 @@ function createWindow () {
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished

View File

@@ -1,16 +1,11 @@
const { BrowserWindow } = require('electron').remote
const { shell } = require('electron').remote
const { shell, ipcRenderer } = require('electron')
const newWindowBtn = document.getElementById('new-window')
const link = document.getElementById('browser-window-link')
newWindowBtn.addEventListener('click', (event) => {
let win = new BrowserWindow({ width: 400, height: 320 })
win.on('close', () => { win = null })
win.loadURL('https://electronjs.org')
win.show()
const url = 'https://electronjs.org'
ipcRenderer.send('new-window', { url, width: 400, height: 320 });
})
link.addEventListener('click', (e) => {

View File

@@ -1,13 +1,9 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
const { app, BrowserWindow, ipcMain } = require('electron')
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
@@ -18,15 +14,27 @@ function createWindow () {
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
let demoWindow
ipcMain.on('show-demo-window', () => {
if (demoWindow) {
demoWindow.focus()
return
}
demoWindow = new BrowserWindow({ width: 600, height: 400 })
demoWindow.loadURL('https://electronjs.org')
demoWindow.on('close', () => {
mainWindow.webContents.send('window-close')
})
demoWindow.on('focus', () => {
mainWindow.webContents.send('window-focus')
})
demoWindow.on('blur', () => {
mainWindow.webContents.send('window-blur')
})
})
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
ipcMain.on('focus-demo-window', () => {
if (demoWindow) demoWindow.focus()
})
}

View File

@@ -1,42 +1,33 @@
const { BrowserWindow } = require('electron').remote
const shell = require('electron').shell
const { shell, ipcRenderer } = require('electron')
const listenToWindowBtn = document.getElementById('listen-to-window')
const focusModalBtn = document.getElementById('focus-on-modal-window')
const links = document.querySelectorAll('a[href]')
const hideFocusBtn = () => {
focusModalBtn.classList.add('disappear')
focusModalBtn.classList.remove('smooth-appear')
focusModalBtn.removeEventListener('click', focusWindow)
}
let win
const showFocusBtn = (btn) => {
focusModalBtn.classList.add('smooth-appear')
focusModalBtn.classList.remove('disappear')
focusModalBtn.addEventListener('click', focusWindow)
}
const focusWindow = () => {
ipcRenderer.send('focus-demo-window')
}
ipcRenderer.on('window-focus', hideFocusBtn)
ipcRenderer.on('window-close', hideFocusBtn)
ipcRenderer.on('window-blur', showFocusBtn)
listenToWindowBtn.addEventListener('click', () => {
const modalPath = 'https://electronjs.org'
win = new BrowserWindow({ width: 600, height: 400 })
const hideFocusBtn = () => {
focusModalBtn.classList.add('disappear')
focusModalBtn.classList.remove('smooth-appear')
focusModalBtn.removeEventListener('click', clickHandler)
}
const showFocusBtn = (btn) => {
if (!win) return
focusModalBtn.classList.add('smooth-appear')
focusModalBtn.classList.remove('disappear')
focusModalBtn.addEventListener('click', clickHandler)
}
win.on('focus', hideFocusBtn)
win.on('blur', showFocusBtn)
win.on('close', () => {
hideFocusBtn()
win = null
})
win.loadURL(modalPath)
win.show()
const clickHandler = () => { win.focus() }
ipcRenderer.send('show-demo-window')
})
const links = document.querySelectorAll('a[href]')
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {

View File

@@ -26,7 +26,8 @@ To test In-App Purchase in development with Electron you'll have to change the `
Here is an example that shows how to use In-App Purchases in Electron. You'll have to replace the product ids by the identifiers of the products created with iTunes Connect (the identifier of `com.example.app.product1` is `product1`). Note that you have to listen to the `transactions-updated` event as soon as possible in your app.
```javascript
const { inAppPurchase } = require('electron').remote
// Main process
const { inAppPurchase } = require('electron')
const PRODUCT_IDS = ['id1', 'id2']
// Listen for transactions as soon as possible.

View File

@@ -34,7 +34,6 @@ auto_filenames = {
"docs/api/menu.md",
"docs/api/message-channel-main.md",
"docs/api/message-port-main.md",
"docs/api/modernization",
"docs/api/native-image.md",
"docs/api/native-theme.md",
"docs/api/net-log.md",

View File

@@ -43,7 +43,7 @@ Object.defineProperty(BaseWindow.prototype, 'kiosk', {
});
Object.defineProperty(BaseWindow.prototype, 'documentEdited', {
get: function () { return this.isFullscreen(); },
get: function () { return this.isDocumentEdited(); },
set: function (edited) { this.setDocumentEdited(edited); }
});

View File

@@ -92,11 +92,7 @@ BrowserWindow.getFocusedWindow = () => {
};
BrowserWindow.fromWebContents = (webContents: WebContents) => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.webContents && window.webContents.equal(webContents)) return window;
}
return null;
return webContents.getOwnerBrowserWindow();
};
BrowserWindow.fromBrowserView = (browserView: BrowserView) => {

View File

@@ -18,7 +18,7 @@ class CrashReporter {
if (submitURL == null) throw new Error('submitURL is a required option to crashReporter.start');
if (!compress) {
if (!compress && uploadToServer) {
deprecate.log('Sending uncompressed crash reports is deprecated and will be removed in a future version of Electron. Set { compress: true } to opt-in to the new behavior. Crash reports will be uploaded gzipped, which most crash reporting servers support.');
}

View File

@@ -605,7 +605,6 @@ WebContents.prototype._init = function () {
width: 800,
height: 600,
webContents,
title: frameName,
webPreferences,
...options
};

View File

@@ -81,7 +81,7 @@ const getPreloadScript = async function (preloadPath: string) {
let preloadSrc = null;
let preloadError = null;
try {
preloadSrc = (await fs.promises.readFile(preloadPath)).toString();
preloadSrc = await fs.promises.readFile(preloadPath, 'utf8');
} catch (error) {
preloadError = error;
}

View File

@@ -49,7 +49,7 @@ class WebFrame extends EventEmitter {
}
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
const worldSafeJS = hasSwitch('world-safe-execute-javascript') && hasSwitch('context-isolation');
const worldSafeJS = hasSwitch('world-safe-execute-javascript') || !hasSwitch('context-isolation');
// Populate the methods.
for (const name in binding) {

View File

@@ -224,7 +224,7 @@ const warnAboutExperimentalFeatures = function (webPreferences?: Electron.WebPre
const warnAboutEnableBlinkFeatures = function (webPreferences?: Electron.WebPreferences) {
if (!webPreferences ||
!Object.prototype.hasOwnProperty.call(webPreferences, 'enableBlinkFeatures') ||
(webPreferences.enableBlinkFeatures && webPreferences.enableBlinkFeatures.length === 0)) {
(webPreferences.enableBlinkFeatures != null && webPreferences.enableBlinkFeatures.length === 0)) {
return;
}

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "11.2.2",
"version": "11.4.0",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {

View File

@@ -1,2 +1,3 @@
expose_ripemd160.patch
expose_aes-cfb.patch
expose_des-ede3.patch

View File

@@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jeremy Rose <nornagon@nornagon.net>
Date: Wed, 24 Feb 2021 11:08:34 -0800
Subject: expose des-ede3
This should be upstreamed.
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
index 588a4773437c311877f275bf3679f9688cda3c46..e771ed6589b4579cc35300d5b2a1b68d92e444f5 100644
--- a/crypto/cipher_extra/cipher_extra.c
+++ b/crypto/cipher_extra/cipher_extra.c
@@ -93,6 +93,8 @@ const EVP_CIPHER *EVP_get_cipherbyname(const char *name) {
return EVP_rc4();
} else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) {
return EVP_des_cbc();
+ } else if (OPENSSL_strcasecmp(name, "des-ede3") == 0) {
+ return EVP_des_ede3();
} else if (OPENSSL_strcasecmp(name, "des-ede3-cbc") == 0 ||
// This is not a name used by OpenSSL, but tcpdump registers it
// with |EVP_add_cipher_alias|. Our |EVP_add_cipher_alias| is a
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
index 84af06fc56e4aa72d4d48801d7c037add0221747..fe412e350f43ad20758025da6b9754952d164938 100644
--- a/decrepit/evp/evp_do_all.c
+++ b/decrepit/evp/evp_do_all.c
@@ -39,6 +39,7 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
callback(EVP_des_cbc(), "DES-CBC", NULL, arg);
callback(EVP_des_ecb(), "DES-ECB", NULL, arg);
callback(EVP_des_ede(), "DES-EDE", NULL, arg);
+ callback(EVP_des_ede3(), "DES-EDE3", NULL, arg);
callback(EVP_des_ede_cbc(), "DES-EDE-CBC", NULL, arg);
callback(EVP_des_ede3_cbc(), "DES-EDE3-CBC", NULL, arg);
callback(EVP_rc2_cbc(), "RC2-CBC", NULL, arg);
@@ -65,6 +66,7 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
callback(EVP_des_cbc(), "des-cbc", NULL, arg);
callback(EVP_des_ecb(), "des-ecb", NULL, arg);
callback(EVP_des_ede(), "des-ede", NULL, arg);
+ callback(EVP_des_ede3(), "des-ede3", NULL, arg);
callback(EVP_des_ede_cbc(), "des-ede-cbc", NULL, arg);
callback(EVP_des_ede3_cbc(), "des-ede3-cbc", NULL, arg);
callback(EVP_rc2_cbc(), "rc2-cbc", NULL, arg);

View File

@@ -116,3 +116,21 @@ cherry-pick-06fe641d21bd.patch
cherry-pick-3f7b67374a11.patch
ots_backport_maxp_sanitization.patch
ots_backport_of_glyf_guard_access_to_maxp_version_1_field.patch
cherry-pick-df438f22f7d2.patch
cherry-pick-5c7ad5393f74.patch
replace_clearfilterdata_with_invalidatefilterdata.patch
cherry-pick-5902d1aa722a.patch
cherry-pick-76cb1cc32baa.patch
disable_gpu_acceleration_on_all_mesa_software_rasterizers.patch
stop_using_raw_webcontents_ptr_in_dragdownloadfile.patch
fix_heap_overflow_in_videoframeyuvconverter.patch
merge_to_m88_avoid_spinning_a_nested_message_loop_for_x11_clipboard.patch
merge_to_m88_xproto_switch_event_queue_from_a_std_list_to_a.patch
websocket_don_t_clear_event_queue_on_destruction.patch
cherry-pick-7e0e52df283c.patch
cherry-pick-6ed1c0c425e0.patch
cherry-pick-aeb6bc551b60.patch
cherry-pick-eb0c0353bf24.patch
mediarecorder_tolerate_non-gmb_nv12_frames_for_h264.patch
cherry-pick-18d3f86206e8.patch
cherry-pick-6e8856624cbb.patch

View File

@@ -0,0 +1,156 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Christoph Schwering <schwering@google.com>
Date: Tue, 24 Nov 2020 23:39:39 +0000
Subject: Limit preview and filling only for non-state fields.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The number of times a value is filled into different fields is limited.
The exception are state fields because websites sometimes have one
state select box for each country and display the relevant select
box once the respective country has been selected.
This CL simplifies this mechanism and makes it more explicit by
encoding the type-dependent limits in TypeValueFormFillingLimit().
As a side effect, the limits apply not just to filled fields but also
unfilled fields of the same type.
Bug: 1075734, 1084903
Change-Id: Icc5e8e082850ed44d9c7fbbc911d03a95033d81f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2557977
Commit-Queue: Matthias Körber <koerber@google.com>
Reviewed-by: Matthias Körber <koerber@google.com>
Auto-Submit: Christoph Schwering <schwering@google.com>
Cr-Commit-Position: refs/heads/master@{#830778}
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index a9dd2e727ddb68331e684716055af42166d69986..0b72ac3b8a0d3bb3294be995d2b9a4bc52b81a8f 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -20,6 +20,7 @@
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
+#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/guid.h"
@@ -432,9 +433,15 @@ const char* SubmissionSourceToString(SubmissionSource source) {
// Returns how many fields with type |field_type| may be filled in a form at
// maximum.
-int TypeValueFormFillingLimit(ServerFieldType field_type) {
- return field_type == CREDIT_CARD_NUMBER ? kCreditCardTypeValueFormFillingLimit
- : kTypeValueFormFillingLimit;
+size_t TypeValueFormFillingLimit(ServerFieldType field_type) {
+ switch (field_type) {
+ case CREDIT_CARD_NUMBER:
+ return kCreditCardTypeValueFormFillingLimit;
+ case ADDRESS_HOME_STATE:
+ return kStateTypeValueFormFillingLimit;
+ default:
+ return kTypeValueFormFillingLimit;
+ }
}
} // namespace
@@ -1760,7 +1767,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
// Count the number of times the value of a specific type was filled into the
// form.
- std::map<ServerFieldType, int> type_filling_count;
+ base::flat_map<ServerFieldType, size_t> type_filling_count;
+ type_filling_count.reserve(form_structure->field_count());
for (size_t i = 0; i < form_structure->field_count(); ++i) {
std::string field_number = base::StringPrintf("Field %zu", i);
@@ -1852,7 +1860,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
// A field with a specific type is only allowed to be filled a limited
// number of times given by |TypeValueFormFillingLimit(field_type)|.
- if (type_filling_count[field_type] >=
+ if (++type_filling_count[field_type] >
TypeValueFormFillingLimit(field_type)) {
buffer << Tr{} << field_number
<< "Skipped: field-type filling-limit reached";
@@ -1887,10 +1895,6 @@ void AutofillManager::FillOrPreviewDataModelForm(
bool has_value_after = !result.fields[i].value.empty();
bool is_autofilled_after = result.fields[i].is_autofilled;
- // If the field was actually filled, increment the filling counter.
- if (is_autofilled_after)
- type_filling_count[field_type]++;
-
buffer << Tr{} << field_number
<< base::StringPrintf(
"Fillable - has value: %d->%d; autofilled: %d->%d. %s",
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 7d296d95b25f126cb9176af3292687965987c123..26573cfa9f71e45a8087a4a0e76f3ddfa3f4f81c 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -2947,6 +2947,14 @@ TEST_P(AutofillManagerStructuredProfileTest,
form.fields.push_back(field);
}
+ // Create a selection box for the state that hat the correct entry to be
+ // filled with user data. Note, TN is the official abbreviation for Tennessee.
+ for (int i = 0; i < 20; ++i) {
+ test::CreateTestSelectField("Country", "country", "", {"DE", "FR", "US"},
+ {"DE", "FR", "US"}, 3, &field);
+ form.fields.push_back(field);
+ }
+
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -2983,17 +2991,18 @@ TEST_P(AutofillManagerStructuredProfileTest,
response_data.fields[4 + i]);
}
- // Verify that the next 8 selection boxes are correctly filled again.
- for (int i = 0; i < 8; i++) {
+ // Verify that the remaining selection boxes are correctly filled again
+ // because there's no limit on filling ADDRESS_HOME_STATE fields.
+ for (int i = 0; i < 20; i++) {
ExpectFilledField("State", "state", "TN", "select-one",
response_data.fields[24 + i]);
}
- // Verify that the last 12 boxes are not filled because the filling limit for
- // the state type is already reached.
- for (int i = 0; i < 12; i++) {
- ExpectFilledField("State", "state", "", "select-one",
- response_data.fields[32 + i]);
+ // Verify that only the first 9 of the remaining selection boxes are
+ // correctly filled due to the limit on filling ADDRESS_HOME_COUNTRY fields.
+ for (int i = 0; i < 20; i++) {
+ ExpectFilledField("Country", "country", i < 9 ? "US" : "", "select-one",
+ response_data.fields[44 + i]);
}
}
diff --git a/components/autofill/core/common/autofill_constants.h b/components/autofill/core/common/autofill_constants.h
index 84c5b916b0330ab8305db7b1831b42fa42843708..2d6ade5e6bea81ec4383d0345863514e1b551ea8 100644
--- a/components/autofill/core/common/autofill_constants.h
+++ b/components/autofill/core/common/autofill_constants.h
@@ -68,12 +68,14 @@ const int64_t kAutocompleteRetentionPolicyPeriodInDays = 14 * 31;
// Limits the number of times the value of a specific type can be filled into a
// form.
-constexpr int kTypeValueFormFillingLimit = 9;
-
// Credit card numbers are sometimes distributed between up to 19 individual
-// fields. Therefore, credit cards need a higher limit compared to
-// |kTypeValueFormFillingLimit|.
-constexpr int kCreditCardTypeValueFormFillingLimit = 19;
+// fields. Therefore, credit cards need a higher limit.
+// State fields are effecectively unlimited because there are sometimes hidden
+// fields select boxes, each with a list of states for one specific countries,
+// which are displayed only upon country selection.
+constexpr size_t kTypeValueFormFillingLimit = 9;
+constexpr size_t kCreditCardTypeValueFormFillingLimit = 19;
+constexpr size_t kStateTypeValueFormFillingLimit = 1000;
} // namespace autofill

View File

@@ -0,0 +1,154 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Robinson <mrobinson@igalia.com>
Date: Fri, 15 Jan 2021 10:52:00 +0000
Subject: Use the native combobox a11y role more often on MacOS
Instead of mapping the ARIA combobox role to other roles on MacOS,
always use it unless it is applied to a multiline edit field. This
matches the specified behavior and other browsers.
These were originally mapped to other roles because of VoiceOver
failures that have been fixed with other changes.
Bug: 1125165
Change-Id: I26b8ccb006c15d6329da1c29193640f529fab781
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2611093
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
Cr-Commit-Position: refs/heads/master@{#844021}
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 71f927cd35a27dd5f656907dc177fbfe7577d3f0..9e32394d5d3eceb41873302ac1ab3b24de7d3d0f 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1988,7 +1988,7 @@ - (NSString*)role {
cocoa_role = NSAccessibilityGroupRole;
} else if ((_owner->IsPlainTextField() &&
_owner->HasState(ax::mojom::State::kMultiline)) ||
- _owner->IsRichTextField()) {
+ (_owner->IsRichTextField() && !ui::IsComboBox(role))) {
cocoa_role = NSAccessibilityTextAreaRole;
} else if (role == ax::mojom::Role::kImage &&
_owner->HasExplicitlyEmptyName()) {
diff --git a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
index f30f15e3e3cb50d7d5f31ce3c15fcd5d533e8c12..a3fe1ad8d3ea617b99fd9ffbbfc2b3ff8094b190 100644
--- a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-mac.txt
@@ -1,7 +1,8 @@
AXWebArea AXFocused=1
++AXGroup
++++AXStaticText AXValue='Choose a fruit, with text content'
-++AXPopUpButton AXLinkedUIElements=[:6] AXTitle='Choose a fruit, with text content' AXValue='Apple'
+++AXComboBox AXLinkedUIElements=[:6] AXTitle='Choose a fruit, with text content' AXValue='Apple'
+
++++AXStaticText AXValue='Apple'
++AXList
++++AXStaticText AXValue='Apple'
diff --git a/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt b/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
index de0f31f2065490d6085027e2800706a3926bcf5b..00280bbe561555168bdac1e39a513ce99d0f249d 100644
--- a/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-haspopup-expected-mac.txt
@@ -1,10 +1,10 @@
AXWebArea
-++AXPopUpButton AXHasPopup=1 AXPopupValue='menu'
-++AXPopUpButton
-++AXPopUpButton AXHasPopup=1 AXPopupValue='menu'
-++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox'
-++AXPopUpButton AXHasPopup=1 AXPopupValue='grid'
-++AXPopUpButton AXHasPopup=1 AXPopupValue='dialog'
-++AXPopUpButton AXHasPopup=1 AXPopupValue='menu'
-++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox'
-++AXPopUpButton AXHasPopup=1 AXPopupValue='listbox'
+++AXComboButton AXHasPopup=1 AXPopupValue='menu'
+++AXComboButton
+++AXComboButton AXHasPopup=1 AXPopupValue='menu'
+++AXComboButton AXHasPopup=1 AXPopupValue='listbox'
+++AXComboButton AXHasPopup=1 AXPopupValue='grid'
+++AXComboButton AXHasPopup=1 AXPopupValue='dialog'
+++AXComboButton AXHasPopup=1 AXPopupValue='menu'
+++AXComboButton AXHasPopup=1 AXPopupValue='listbox'
+++AXComboButton AXHasPopup=1 AXPopupValue='listbox'
diff --git a/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt b/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
index 4c605836da4804e91142dcaedd45dc4e0c259756..c04259a0a2148413b0482595e91c7a750df8a7bd 100644
--- a/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-orientation-expected-mac.txt
@@ -1,7 +1,7 @@
AXWebArea
-++AXGroup
-++AXGroup AXOrientation='AXHorizontalOrientation'
-++AXGroup AXOrientation='AXVerticalOrientation'
+++AXComboBox
+++AXComboBox AXOrientation='AXHorizontalOrientation'
+++AXComboBox AXOrientation='AXVerticalOrientation'
++AXList AXOrientation='AXVerticalOrientation'
++AXList AXOrientation='AXHorizontalOrientation'
++AXList AXOrientation='AXVerticalOrientation'
diff --git a/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt b/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
index b942711938c6c839317e6b96fd9e4a6aa98ee451..96f8201c834b12be7b490f23c1e2d65ab2149c96 100644
--- a/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria1.1-combobox-expected-mac.txt
@@ -1,12 +1,12 @@
AXWebArea
++AXGroup
++++AXStaticText AXValue='State'
-++AXGroup AXTitle='State'
+++AXComboBox AXTitle='State'
++++AXTextField AXLinkedUIElements=[:6]
++AXList
++++AXStaticText AXValue='Alabama'
++++AXStaticText AXFocused=1 AXValue='Alaska'
-++AXGroup AXTitle='State'
+++AXComboBox AXTitle='State'
++++AXTextField AXLinkedUIElements=[:11]
++AXList
++++AXStaticText AXValue='Alabama'
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc
index f776bb6a7c0f1cb15a61468afe3a6264bad82830..f511d3436e3e448b00d042f35fc0077c85681523 100644
--- a/ui/accessibility/ax_role_properties.cc
+++ b/ui/accessibility/ax_role_properties.cc
@@ -767,6 +767,17 @@ bool SupportsToggle(const ax::mojom::Role role) {
}
}
+bool IsComboBox(const ax::mojom::Role role) {
+ switch (role) {
+ case ax::mojom::Role::kComboBoxMenuButton:
+ case ax::mojom::Role::kComboBoxGrouping:
+ case ax::mojom::Role::kTextFieldWithComboBox:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool ShouldHaveReadonlyStateByDefault(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kArticle:
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h
index 724de523b7dc2c009ed9b1aa84cf9071ce230bad..a8233bb36f0a532e7ce51abee9cc4823b0cb3fcf 100644
--- a/ui/accessibility/ax_role_properties.h
+++ b/ui/accessibility/ax_role_properties.h
@@ -168,6 +168,8 @@ AX_BASE_EXPORT bool IsTableRow(ax::mojom::Role role);
// break, or inline text box.
AX_BASE_EXPORT bool IsText(ax::mojom::Role role);
+// Returns true if the provided role is any of the combobox-related roles.
+AX_BASE_EXPORT bool IsComboBox(ax::mojom::Role role);
// Returns true if the role supports expand/collapse.
AX_BASE_EXPORT bool SupportsExpandCollapse(const ax::mojom::Role role);
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
index 96d46d452188519fc3f90e9e107fa134e097a1f4..06d766c9c7a8bade5192815d1e65e31948832d4e 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -55,8 +55,8 @@ RoleMap BuildRoleMap() {
{ax::mojom::Role::kColorWell, NSAccessibilityColorWellRole},
{ax::mojom::Role::kColumn, NSAccessibilityColumnRole},
{ax::mojom::Role::kColumnHeader, @"AXCell"},
- {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityGroupRole},
- {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityPopUpButtonRole},
+ {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityComboBoxRole},
+ {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityComboBoxRole},
{ax::mojom::Role::kComment, NSAccessibilityGroupRole},
{ax::mojom::Role::kComplementary, NSAccessibilityGroupRole},
{ax::mojom::Role::kContentDeletion, NSAccessibilityGroupRole},

View File

@@ -0,0 +1,297 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Robinson <mrobinson@igalia.com>
Date: Mon, 25 Jan 2021 14:27:23 +0000
Subject: Mac a11y: Use the keyboard focusable element for
NSAccessibilityTextChangeElement
When setting the NSAccessibilityTextChangeElement property for
NSAccessibilitySelectedTextChangedNotifications, use the keyboard
focusable element instead of the element that has the focus side of the
text selection. Using the latter, when the element is an empty group,
VoiceOver will focus the containing Web View (when using the VO
cursor follows keyboard focus setting). This makes it impossible to use
the down keyboard key to move past these empty nodes.
VoiceOver cursor" setting in contenteditable nodes.
AX-Relnotes: Fix a bug with the "Synchronize keyboard focus and
Bug: 952922
Change-Id: I3627936726f89b01132c32bd5d83758fc7c3dac4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2642686
Auto-Submit: Martin Robinson <mrobinson@igalia.com>
Commit-Queue: Nektarios Paisios <nektar@chromium.org>
Reviewed-by: Nektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846707}
diff --git a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
index 6eb2c484ddc479d9cfa566df0b103782264d3af8..07db6eed6d06340627a3c023d02274642642e87d 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
@@ -20,12 +20,11 @@
#include "net/base/data_url.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
#include "url/gurl.h"
namespace content {
-namespace {
-
class BrowserAccessibilityCocoaBrowserTest : public ContentBrowserTest {
public:
BrowserAccessibilityCocoaBrowserTest() {}
@@ -73,6 +72,11 @@ void FocusAccessibilityElementAndWaitForFocusChange(
WaitForAccessibilityFocusChange();
}
+ NSDictionary* GetUserInfoForSelectedTextChangedNotification() {
+ auto* manager = static_cast<BrowserAccessibilityManagerMac*>(GetManager());
+ return manager->GetUserInfoForSelectedTextChangedNotification();
+ }
+
private:
BrowserAccessibility* FindNodeInSubtree(BrowserAccessibility& node,
ax::mojom::Role role) {
@@ -89,8 +93,6 @@ void FocusAccessibilityElementAndWaitForFocusChange(
}
};
-} // namespace
-
IN_PROC_BROWSER_TEST_F(BrowserAccessibilityCocoaBrowserTest,
AXTextMarkerForTextEdit) {
EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
@@ -106,12 +108,11 @@ GURL url(R"HTML(data:text/html,
BrowserAccessibility* text_field = FindNode(ax::mojom::Role::kTextField);
ASSERT_NE(nullptr, text_field);
- EXPECT_TRUE(content::ExecuteScript(
- shell()->web_contents(), "document.querySelector('input').focus()"));
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.querySelector('input').focus()"));
- content::SimulateKeyPress(shell()->web_contents(),
- ui::DomKey::FromCharacter('B'), ui::DomCode::US_B,
- ui::VKEY_B, false, false, false, false);
+ SimulateKeyPress(shell()->web_contents(), ui::DomKey::FromCharacter('B'),
+ ui::DomCode::US_B, ui::VKEY_B, false, false, false, false);
base::scoped_nsobject<BrowserAccessibilityCocoa> cocoa_text_field(
[ToBrowserAccessibilityCocoa(text_field) retain]);
@@ -122,10 +123,9 @@ AccessibilityNotificationWaiter value_waiter(shell()->web_contents(),
AXTextEdit text_edit = [cocoa_text_field computeTextEdit];
EXPECT_NE(text_edit.edit_text_marker, nil);
- EXPECT_EQ(
- content::AXTextMarkerToPosition(text_edit.edit_text_marker)->ToString(),
- "TextPosition anchor_id=4 text_offset=1 affinity=downstream "
- "annotated_text=B<>");
+ EXPECT_EQ(AXTextMarkerToPosition(text_edit.edit_text_marker)->ToString(),
+ "TextPosition anchor_id=4 text_offset=1 affinity=downstream "
+ "annotated_text=B<>");
}
IN_PROC_BROWSER_TEST_F(BrowserAccessibilityCocoaBrowserTest,
@@ -519,7 +519,7 @@ GURL url(R"HTML(data:text/html,
EXPECT_NSEQ(@"AXRow", [tree_children[0] role]);
EXPECT_NSEQ(@"AXRow", [tree_children[1] role]);
- content::RenderProcessHost* render_process_host =
+ RenderProcessHost* render_process_host =
shell()->web_contents()->GetMainFrame()->GetProcess();
auto menu_filter = base::MakeRefCounted<ContextMenuFilter>(
ContextMenuFilter::ShowBehavior::kPreventShow);
@@ -534,9 +534,8 @@ GURL url(R"HTML(data:text/html,
ASSERT_NE(tree_point, item_1_point);
// Now focus the second child and trigger a context menu on the tree.
- EXPECT_TRUE(
- content::ExecuteScript(shell()->web_contents(),
- "document.body.children[0].children[1].focus();"));
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.body.children[0].children[1].focus();"));
WaitForAccessibilityFocusChange();
// Triggering a context menu on the tree should now trigger the menu
@@ -656,4 +655,63 @@ GURL url(R"HTML(data:text/html,
}
}
+IN_PROC_BROWSER_TEST_F(BrowserAccessibilityCocoaBrowserTest,
+ TestNSAccessibilityTextChangeElement) {
+ AccessibilityNotificationWaiter waiter(shell()->web_contents(),
+ ui::kAXModeComplete,
+ ax::mojom::Event::kLoadComplete);
+
+ GURL url(R"HTML(data:text/html,
+ <div id="editable" contenteditable="true" dir="auto">
+ <p>One</p>
+ <p>Two</p>
+ <p><br></p>
+ <p>Three</p>
+ <p>Four</p>
+ </div>)HTML");
+
+ ASSERT_TRUE(NavigateToURL(shell(), url));
+ waiter.WaitForNotification();
+
+ base::scoped_nsobject<BrowserAccessibilityCocoa> content_editable(
+ [ToBrowserAccessibilityCocoa(GetManager()->GetRoot()->PlatformGetChild(0))
+ retain]);
+ EXPECT_EQ([[content_editable children] count], 5ul);
+
+ WebContents* web_contents = shell()->web_contents();
+ auto run_script_and_wait_for_selection_change =
+ [web_contents](const char* script) {
+ AccessibilityNotificationWaiter waiter(
+ web_contents, ui::kAXModeComplete,
+ ax::mojom::Event::kTextSelectionChanged);
+ ASSERT_TRUE(ExecuteScript(web_contents, script));
+ waiter.WaitForNotification();
+ };
+
+ FocusAccessibilityElementAndWaitForFocusChange(content_editable);
+
+ run_script_and_wait_for_selection_change(R"script(
+ let editable = document.getElementById('editable');
+ const selection = window.getSelection();
+ selection.collapse(editable.children[0].childNodes[0], 1);)script");
+
+ // The focused node in the user info should be the keyboard focusable
+ // ancestor.
+ NSDictionary* info = GetUserInfoForSelectedTextChangedNotification();
+ EXPECT_EQ(id{content_editable},
+ [info objectForKey:ui::NSAccessibilityTextChangeElement]);
+
+ AccessibilityNotificationWaiter waiter2(
+ web_contents, ui::kAXModeComplete,
+ ax::mojom::Event::kTextSelectionChanged);
+ run_script_and_wait_for_selection_change(
+ "selection.collapse(editable.children[2].childNodes[0], 0);");
+
+ // Even when the cursor is in the empty paragraph text node, the focused
+ // object should be the keyboard focusable ancestor.
+ info = GetUserInfoForSelectedTextChangedNotification();
+ EXPECT_EQ(id{content_editable},
+ [info objectForKey:ui::NSAccessibilityTextChangeElement]);
+}
+
} // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
index 925bfe1ea191ab846805fdbff1b0314e779b1c9e..5488245e22b883105dbe1e225156ab18e1a64534 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -19,6 +19,8 @@
namespace content {
+class BrowserAccessibilityCocoaBrowserTest;
+
class CONTENT_EXPORT BrowserAccessibilityManagerMac
: public BrowserAccessibilityManager {
public:
@@ -54,8 +56,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
const std::vector<Change>& changes) override;
// Returns an autoreleased object.
- NSDictionary* GetUserInfoForSelectedTextChangedNotification(
- bool focus_changed);
+ NSDictionary* GetUserInfoForSelectedTextChangedNotification();
// Returns an autoreleased object.
NSDictionary* GetUserInfoForValueChangedNotification(
@@ -80,6 +81,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
// constructor.
friend class BrowserAccessibilityManager;
+ friend class BrowserAccessibilityCocoaBrowserTest;
+
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerMac);
};
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 4232959e30ab758bff58aa8e4457b6cdd3c7745b..d172d9625c3d762a861873b2e938a931c49b9501 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -125,8 +125,6 @@ void PostAnnouncementNotification(NSString* announcement) {
auto native_node = ToBrowserAccessibilityCocoa(node);
DCHECK(native_node);
- bool focus_changed = GetFocus() != GetLastFocusedNode();
-
// Refer to |AXObjectCache::postPlatformNotification| in WebKit source code.
NSString* mac_notification = nullptr;
switch (event_type) {
@@ -212,8 +210,7 @@ void PostAnnouncementNotification(NSString* announcement) {
// 10.11 or later to notify Voiceover about text selection changes. This
// API has been present on versions of OS X since 10.7 but doesn't
// appear to be needed by Voiceover before version 10.11.
- NSDictionary* user_info =
- GetUserInfoForSelectedTextChangedNotification(focus_changed);
+ NSDictionary* user_info = GetUserInfoForSelectedTextChangedNotification();
BrowserAccessibilityManager* root_manager = GetRootManager();
if (!root_manager)
@@ -439,8 +436,8 @@ void PostAnnouncementNotification(NSString* announcement) {
}
NSDictionary*
-BrowserAccessibilityManagerMac::GetUserInfoForSelectedTextChangedNotification(
- bool focus_changed) {
+BrowserAccessibilityManagerMac::
+ GetUserInfoForSelectedTextChangedNotification() {
NSMutableDictionary* user_info =
[[[NSMutableDictionary alloc] init] autorelease];
[user_info setObject:@YES forKey:ui::NSAccessibilityTextStateSyncKey];
@@ -457,7 +454,10 @@ void PostAnnouncementNotification(NSString* announcement) {
// TODO(mrobinson): Determine definitively what the type of this text
// selection change is. This requires passing this information here from
// blink.
- if (focus_changed) {
+ BrowserAccessibility* focused_accessibility = GetFocus();
+ DCHECK(focused_accessibility);
+
+ if (focused_accessibility != GetLastFocusedNode()) {
[user_info setObject:@(ui::AXTextStateChangeTypeSelectionMove)
forKey:ui::NSAccessibilityTextStateChangeTypeKey];
} else {
@@ -465,25 +465,22 @@ void PostAnnouncementNotification(NSString* announcement) {
forKey:ui::NSAccessibilityTextStateChangeTypeKey];
}
- int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
- BrowserAccessibility* focus_object = GetFromID(focus_id);
- if (focus_object) {
- focus_object = focus_object->PlatformGetClosestPlatformObject();
- auto native_focus_object = ToBrowserAccessibilityCocoa(focus_object);
- if (native_focus_object && [native_focus_object instanceActive]) {
- [user_info setObject:native_focus_object
- forKey:ui::NSAccessibilityTextChangeElement];
+ focused_accessibility =
+ focused_accessibility->PlatformGetClosestPlatformObject();
+ auto native_focus_object = ToBrowserAccessibilityCocoa(focused_accessibility);
+ if (native_focus_object && [native_focus_object instanceActive]) {
+ [user_info setObject:native_focus_object
+ forKey:ui::NSAccessibilityTextChangeElement];
#ifndef MAS_BUILD
- id selected_text = [native_focus_object selectedTextMarkerRange];
- if (selected_text) {
- NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
- @"AXSelectedTextMarkerRange";
- [user_info setObject:selected_text
- forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
- }
-#endif
+ id selected_text = [native_focus_object selectedTextMarkerRange];
+ if (selected_text) {
+ NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
+ @"AXSelectedTextMarkerRange";
+ [user_info setObject:selected_text
+ forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
}
+#endif
}
return user_info;

View File

@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Koji Ishii <kojii@chromium.org>
Date: Thu, 11 Mar 2021 17:45:46 +0000
Subject: Mark additional RootInlineBox dirty when culled inline box is removed
When a |LayoutInline| is removed, |LineBoxList::
DirtyLinesFromChangedChild| tries to mark affected
|RootInlineBox| dirty.
When the |LayoutInline| to be removed is culled, it tries to
find the |RootInlineBox| from its previous siblings, then look
for its previous and next |RootInlineBox|es.
Occasionally, the next next line of the previous sibling is
wrapped at the |LayoutInline|, and that its |LineBreakObj()|
holds the reference to the |LayoutInline|. This patch marks
such |RootInlineBox| dirty.
(cherry picked from commit 2dbdabb28d647c8ee20cbe36e3c957e74aff663b)
Bug: 1186287
Change-Id: I8ca73ebb4f5e4f13e997662fffd803d6a74ef49a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2748756
Auto-Submit: Koji Ishii <kojii@chromium.org>
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#861724}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2749769
Commit-Queue: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/4389@{#1518}
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
diff --git a/third_party/blink/renderer/core/layout/line/line_box_list.cc b/third_party/blink/renderer/core/layout/line/line_box_list.cc
index 9d9d861f00cb9784041796acb91604d64dab1cb7..ed929849f721fbae25fd8c1106c95e563aca289b 100644
--- a/third_party/blink/renderer/core/layout/line/line_box_list.cc
+++ b/third_party/blink/renderer/core/layout/line/line_box_list.cc
@@ -359,14 +359,32 @@ void LineBoxList::DirtyLinesFromChangedChild(LineLayoutItem container,
// findNextLineBreak. findNextLineBreak, despite the name, actually returns
// the first LayoutObject after the BR. <rdar://problem/3849947> "Typing
// after pasting line does not appear until after window resize."
- if (RootInlineBox* prev_root_box = box->PrevRootBox())
+ if (RootInlineBox* prev_root_box = box->PrevRootBox()) {
prev_root_box->MarkDirty();
+#if DCHECK_IS_ON()
+ for (; prev_root_box; prev_root_box = prev_root_box->PrevRootBox()) {
+ DCHECK(prev_root_box->IsDirty() ||
+ prev_root_box->LineBreakObj() != child);
+ }
+#endif
+ }
// If |child| or any of its immediately previous siblings with culled
// lineboxes is the object after a line-break in |box| or the linebox after
// it then that means |child| actually sits on the linebox after |box| (or
// is its line-break object) and so we need to dirty it as well.
- if (RootInlineBox* next_root_box = box->NextRootBox())
+ if (RootInlineBox* next_root_box = box->NextRootBox()) {
next_root_box->MarkDirty();
+
+ next_root_box = next_root_box->NextRootBox();
+ if (next_root_box && next_root_box->LineBreakObj() == child)
+ next_root_box->MarkDirty();
+#if DCHECK_IS_ON()
+ for (; next_root_box; next_root_box = next_root_box->NextRootBox()) {
+ DCHECK(next_root_box->IsDirty() ||
+ next_root_box->LineBreakObj() != child);
+ }
+#endif
+ }
}
}

View File

@@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Harald Alvestrand <hta@chromium.org>
Date: Mon, 22 Feb 2021 13:13:58 +0000
Subject: Fix GetP2PSocketManager ownership
Let it return a mojo::SharedRemote<> instead of a raw pointer - this is
a decoration around a shared_refptr.
(cherry picked from commit 82cdc0781ceb4c22ef5903cf3115bea518a5523b)
Bug: chromium:1172054
Change-Id: I49bd22a0dc949bf869744d2ad25c1afcaea7fdbc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2692532
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Commit-Queue: Harald Alvestrand <hta@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#854050}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2709590
Reviewed-by: Harald Alvestrand <hta@chromium.org>
Cr-Commit-Position: refs/branch-heads/4389@{#1280}
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
diff --git a/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc b/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
index 29884a255f24556f4dc8b41b22304938a4f0d775..72ec477f57871b460adf83ea9e1a4bd217d5eebe 100644
--- a/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
+++ b/third_party/blink/renderer/platform/p2p/socket_dispatcher.cc
@@ -36,7 +36,7 @@ void P2PSocketDispatcher::RemoveNetworkListObserver(
network_list_observers_->RemoveObserver(network_list_observer);
}
-network::mojom::blink::P2PSocketManager*
+mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
P2PSocketDispatcher::GetP2PSocketManager() {
base::AutoLock lock(p2p_socket_manager_lock_);
if (!p2p_socket_manager_) {
@@ -56,7 +56,7 @@ P2PSocketDispatcher::GetP2PSocketManager() {
*main_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&P2PSocketDispatcher::RequestInterfaceIfNecessary,
scoped_refptr<P2PSocketDispatcher>(this)));
- return p2p_socket_manager_.get();
+ return p2p_socket_manager_;
}
void P2PSocketDispatcher::NetworkListChanged(
diff --git a/third_party/blink/renderer/platform/p2p/socket_dispatcher.h b/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
index b6268562b1b120429a0c9a17bbca5f279bdc5b75..7d75ef814e127a8743a86dfb8d362459fbe32f99 100644
--- a/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
+++ b/third_party/blink/renderer/platform/p2p/socket_dispatcher.h
@@ -65,7 +65,8 @@ class PLATFORM_EXPORT P2PSocketDispatcher
void RemoveNetworkListObserver(
blink::NetworkListObserver* network_list_observer) override;
- network::mojom::blink::P2PSocketManager* GetP2PSocketManager();
+ mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
+ GetP2PSocketManager();
private:
friend class base::RefCountedThreadSafe<P2PSocketDispatcher>;
@@ -94,7 +95,7 @@ class PLATFORM_EXPORT P2PSocketDispatcher
mojo::PendingReceiver<network::mojom::blink::P2PSocketManager>
p2p_socket_manager_receiver_;
mojo::SharedRemote<network::mojom::blink::P2PSocketManager>
- p2p_socket_manager_;
+ p2p_socket_manager_ GUARDED_BY(p2p_socket_manager_lock_);
base::Lock p2p_socket_manager_lock_;
// Cached from last |NetworkListChanged| call.

View File

@@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sergei Glazunov <glazunov@google.com>
Date: Fri, 12 Feb 2021 16:37:12 +0000
Subject: Use a copy for transferring non detachable buffers
Currently, |DOMArrayBuffer::Transfer()| makes a copy, but still uses
the original buffer for transferring, thus making it possible to share a
regular ArrayBuffer (not SAB) with multiple threads.
(cherry picked from commit 0d289da12075592372940a366ad565b9a13d57ce)
Bug: 1177341
Change-Id: Idb48deb1698fe555f32531bc04b55dd3e1fb0a06
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2690630
Reviewed-by: Bill Budge <bbudge@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Sergei Glazunov <glazunov@google.com>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#853272}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2691251
Reviewed-by: Krishna Govind <govind@chromium.org>
Commit-Queue: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/4389@{#980}
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
index 17fcf0f9034d09a53376ebb380c98589d52de8f4..c456d15f2f5084d7592326e151c1a478bc2ac1fc 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
@@ -47,6 +47,13 @@ bool DOMArrayBuffer::Transfer(v8::Isolate* isolate,
DOMArrayBuffer::Create(Content()->Data(), ByteLengthAsSizeT());
}
+ return to_transfer->TransferDetachable(isolate, result);
+}
+
+bool DOMArrayBuffer::TransferDetachable(v8::Isolate* isolate,
+ ArrayBufferContents& result) {
+ DCHECK(IsDetachable(isolate));
+
if (IsDetached()) {
result.Detach();
return false;
@@ -62,7 +69,7 @@ bool DOMArrayBuffer::Transfer(v8::Isolate* isolate,
Vector<v8::Local<v8::ArrayBuffer>, 4> buffer_handles;
v8::HandleScope handle_scope(isolate);
- AccumulateArrayBuffersForAllWorlds(isolate, to_transfer, buffer_handles);
+ AccumulateArrayBuffersForAllWorlds(isolate, this, buffer_handles);
for (const auto& buffer_handle : buffer_handles)
buffer_handle->Detach();
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
index 00ba385dafcfd476805e39e4c138cdac8f071ef6..e9a85d38d4d46d26a41cf4d394a92d1a7b511c02 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
@@ -78,6 +78,9 @@ class CORE_EXPORT DOMArrayBuffer final : public DOMArrayBufferBase {
v8::Local<v8::Value> Wrap(v8::Isolate*,
v8::Local<v8::Object> creation_context) override;
+
+ private:
+ bool TransferDetachable(v8::Isolate*, ArrayBufferContents& result);
};
} // namespace blink

View File

@@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marijn Kruisselbrink <mek@chromium.org>
Date: Tue, 23 Feb 2021 22:17:17 +0000
Subject: Don't store BlobStorageLimits as a reference in transport strategy.
Rather than storing a const reference to something of unclear lifetime,
just make a copy. We could just copy the specific limits we need, but
there shouldn't be many TransportStrategy instances alive at the same
time anyway, so the cost of duplicating shouldn't be too high.
(cherry picked from commit 9a10c68a381d78088532953aa8e0de0a5ff47316)
(cherry picked from commit 7b51cb5e4e2c6cf9dcf19bd9d7599735efd48110)
Bug: 1180871
Change-Id: Ie1e31728b18f02c5d35df0ac0f285eb8f70cb268
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2713912
Reviewed-by: Olivier Yiptong <oyiptong@chromium.org>
Reviewed-by: Darwin Huang <huangdarwin@chromium.org>
Reviewed-by: Victor Costan <pwnall@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Cr-Original-Original-Commit-Position: refs/heads/master@{#856503}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2713891
Reviewed-by: Krishna Govind <govind@chromium.org>
Reviewed-by: Srinivas Sista <srinivassista@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/4425@{#2}
Cr-Original-Branched-From: 4a7d24ec28ccb96c5a1cfd7b4b40b17070f2c396-refs/heads/master@{#856252}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2713958
Commit-Queue: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/4389@{#1327}
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
diff --git a/storage/browser/blob/blob_transport_strategy.cc b/storage/browser/blob/blob_transport_strategy.cc
index eb66014792246254db1c825b61bd18e3190970de..5ae41639f149f8ff3ead9633d3aa834ac05a8e5f 100644
--- a/storage/browser/blob/blob_transport_strategy.cc
+++ b/storage/browser/blob/blob_transport_strategy.cc
@@ -239,7 +239,7 @@ class DataPipeTransportStrategy : public BlobTransportStrategy {
}
}
- const BlobStorageLimits& limits_;
+ const BlobStorageLimits limits_;
base::circular_deque<base::OnceClosure> requests_;
mojo::ScopedDataPipeConsumerHandle consumer_handle_;
@@ -336,7 +336,7 @@ class FileTransportStrategy : public BlobTransportStrategy {
std::move(result_callback_).Run(BlobStatus::DONE);
}
- const BlobStorageLimits& limits_;
+ const BlobStorageLimits limits_;
// State used to assign bytes elements to individual files.
// The index of the first file that still has available space.

View File

@@ -0,0 +1,114 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hongchan Choi <hongchan@chromium.org>
Date: Tue, 23 Feb 2021 23:27:31 +0000
Subject: Prevent accessing shared buffers from audio rendering thread
The shared buffer in ScriptProcessorNode can be accessed by the
audio rendering thread when it is held by the main thread.
The solution suggested here is simply to expand the scope of
the mutex to minimize the code change. This is a deprecated
feature in Web Audio, so making significant changes is not
sensible. By locking the entire scope of Process() call, this
area would be immune to the similar problems in the future.
(cherry picked from commit 60987aa224f369fc0ea38c56e498389440921356)
Bug: 1174582
Test: The repro case doesn't crash on ASAN.
Change-Id: I2b292f94be65e6ec26c6eb0e0ed32b3fb2d88466
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2681193
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
Reviewed-by: Raymond Toy <rtoy@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#852240}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2715585
Commit-Queue: Krishna Govind <govind@chromium.org>
Reviewed-by: Srinivas Sista <srinivassista@chromium.org>
Cr-Commit-Position: refs/branch-heads/4324@{#2238}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
index b1ca691b07b53b927a92753906f7f25edebac919..6e80b23a32dd1895a0d51d08ee16c8cb2d44fc55 100644
--- a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
@@ -110,6 +110,14 @@ void ScriptProcessorHandler::Initialize() {
}
void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
+ // The main thread might be accessing the shared buffers. If so, silience
+ // the output and return.
+ MutexTryLocker try_locker(process_event_lock_);
+ if (!try_locker.Locked()) {
+ Output(0).Bus()->Zero();
+ return;
+ }
+
// Discussion about inputs and outputs:
// As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
// and output (see inputBus and outputBus below). Additionally, there is a
@@ -181,47 +189,26 @@ void ScriptProcessorHandler::Process(uint32_t frames_to_process) {
buffer_read_write_index_ =
(buffer_read_write_index_ + frames_to_process) % BufferSize();
- // m_bufferReadWriteIndex will wrap back around to 0 when the current input
- // and output buffers are full.
- // When this happens, fire an event and swap buffers.
+ // Fire an event and swap buffers when |buffer_read_write_index_| wraps back
+ // around to 0. It means the current input and output buffers are full.
if (!buffer_read_write_index_) {
- // Avoid building up requests on the main thread to fire process events when
- // they're not being handled. This could be a problem if the main thread is
- // very busy doing other things and is being held up handling previous
- // requests. The audio thread can't block on this lock, so we call
- // tryLock() instead.
- MutexTryLocker try_locker(process_event_lock_);
- if (!try_locker.Locked()) {
- // We're late in handling the previous request. The main thread must be
- // very busy. The best we can do is clear out the buffer ourself here.
- shared_output_buffer->Zero();
+ if (Context()->HasRealtimeConstraint()) {
+ // For a realtime context, fire an event and do not wait.
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(&ScriptProcessorHandler::FireProcessEvent,
+ AsWeakPtr(), double_buffer_index_));
} else {
- // With the realtime context, execute the script code asynchronously
- // and do not wait.
- if (Context()->HasRealtimeConstraint()) {
- // Fire the event on the main thread with the appropriate buffer
- // index.
- PostCrossThreadTask(
- *task_runner_, FROM_HERE,
- CrossThreadBindOnce(&ScriptProcessorHandler::FireProcessEvent,
- AsWeakPtr(), double_buffer_index_));
- } else {
- // If this node is in the offline audio context, use the
- // waitable event to synchronize to the offline rendering thread.
- std::unique_ptr<base::WaitableEvent> waitable_event =
- std::make_unique<base::WaitableEvent>();
-
- PostCrossThreadTask(
- *task_runner_, FROM_HERE,
- CrossThreadBindOnce(
- &ScriptProcessorHandler::FireProcessEventForOfflineAudioContext,
- AsWeakPtr(), double_buffer_index_,
- CrossThreadUnretained(waitable_event.get())));
-
- // Okay to block the offline audio rendering thread since it is
- // not the actual audio device thread.
- waitable_event->Wait();
- }
+ // For an offline context, wait until the script execution is finished.
+ std::unique_ptr<base::WaitableEvent> waitable_event =
+ std::make_unique<base::WaitableEvent>();
+ PostCrossThreadTask(
+ *task_runner_, FROM_HERE,
+ CrossThreadBindOnce(
+ &ScriptProcessorHandler::FireProcessEventForOfflineAudioContext,
+ AsWeakPtr(), double_buffer_index_,
+ CrossThreadUnretained(waitable_event.get())));
+ waitable_event->Wait();
}
SwapBuffers();

View File

@@ -0,0 +1,146 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Artem Sumaneev <asumaneev@google.com>
Date: Wed, 3 Feb 2021 15:00:25 +0000
Subject: Fix navigation request reset logic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Do not delete navigation request which has started upon receiving
notification about beforeunload dialog being cancelled, as a) this
navigation request is not waiting for beforeunload and b) it might have
been this navigation request which canceled this beforeunload dialog.
M86 merge conflicts and resolution:
* content/browser/frame_host/*
In ToT files the affected under frame_host directory are moved to
renderer_host dir. Applied patch to frame_host, no further conflicts.
R=alexmos@chromium.org
BUG=1161705
(cherry picked from commit 23c110b5b81dc401ded5d4dcecfab65d5d88fdfa)
(cherry picked from commit 87550e04d9fed4bbedff4546f4161e3c02415d7e)
Change-Id: I7d385d4326fac6f67d17a003679471806b5ad3b2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2624733
Commit-Queue: Alexander Timin <altimin@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Cr-Original-Original-Commit-Position: refs/heads/master@{#843343}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2652791
Commit-Queue: Alex Moshchuk <alexmos@chromium.org>
Auto-Submit: Alexander Timin <altimin@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/4324@{#2040}
Cr-Original-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2666397
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
Commit-Queue: Artem Sumaneev <asumaneev@google.com>
Cr-Commit-Position: refs/branch-heads/4240@{#1537}
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc
index 92ffd227304509a68a95ea922ffbb477685b6b1d..47ecfa82a0824009c24844e42b9b2c7e6c0206f3 100644
--- a/content/browser/renderer_host/frame_tree_node.cc
+++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -608,10 +608,12 @@ void FrameTreeNode::BeforeUnloadCanceled() {
render_manager_.speculative_frame_host();
if (speculative_frame_host)
speculative_frame_host->ResetLoadingState();
- // Note: there is no need to set an error code on the NavigationHandle here
- // as it has not been created yet. It is only created when the
- // BeforeUnloadCompleted callback is invoked.
- if (navigation_request_)
+ // Note: there is no need to set an error code on the NavigationHandle as
+ // the observers have not been notified about its creation.
+ // We also reset navigation request only when this navigation request was
+ // responsible for this dialog, as a new navigation request might cancel
+ // existing unrelated dialog.
+ if (navigation_request_ && navigation_request_->IsWaitingForBeforeUnload())
ResetNavigationRequest(false);
}
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 60b2b213d6429fa7cff783370cbbeff26a97a859..66a4bc9ac8198ea91b3705db01d85cfe172c8634 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -5148,4 +5148,8 @@ bool NavigationRequest::MaybeCancelFailedNavigation() {
return false;
}
+bool NavigationRequest::IsWaitingForBeforeUnload() {
+ return state_ < WILL_START_NAVIGATION;
+}
+
} // namespace content
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 5e0c08775d6e504327979218d46e999757ea508b..19576fe6cd0c0fc038418683bf1858ebc5399d1e 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -719,6 +719,10 @@ class CONTENT_EXPORT NavigationRequest
// properly determine SiteInstances and process allocation.
UrlInfo GetUrlInfo();
+ // Whether this navigation request waits for the result of beforeunload before
+ // proceeding.
+ bool IsWaitingForBeforeUnload();
+
private:
friend class NavigationRequestTest;
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index 8e4ac3adc3f6c5ac2ff30317ca0d441671e3cc55..653c9606cbe1a145f8e9fa4e1507ad892a727481 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -1169,6 +1169,51 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBeforeUnloadBrowserTest,
namespace {
+class OnDidStartNavigation : public WebContentsObserver {
+ public:
+ OnDidStartNavigation(WebContents* web_contents,
+ base::RepeatingClosure callback)
+ : WebContentsObserver(web_contents), callback_(callback) {}
+
+ void DidStartNavigation(NavigationHandle* navigation) override {
+ callback_.Run();
+ }
+
+ private:
+ base::RepeatingClosure callback_;
+};
+
+} // namespace
+
+// This test closes beforeunload dialog due to a new navigation starting from
+// within WebContentsObserver::DidStartNavigation. This test succeeds if it
+// doesn't crash with a UAF while loading the second page.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBeforeUnloadBrowserTest,
+ DidStartNavigationClosesDialog) {
+ GURL url1 = embedded_test_server()->GetURL("a.com", "/title1.html");
+ GURL url2 = embedded_test_server()->GetURL("b.com", "/title1.html");
+
+ EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+ // This matches the behaviour of TabModalDialogManager in
+ // components/javascript_dialogs.
+ OnDidStartNavigation close_dialog(web_contents(),
+ base::BindLambdaForTesting([&]() {
+ CloseDialogAndCancel();
+
+ // Check that web_contents() were not
+ // deleted.
+ DCHECK(web_contents()->GetMainFrame());
+ }));
+
+ web_contents()->GetMainFrame()->RunBeforeUnloadConfirm(true,
+ base::DoNothing());
+
+ EXPECT_TRUE(NavigateToURL(shell(), url2));
+}
+
+namespace {
+
// A helper to execute some script in a frame just before it is deleted, such
// that no message loops are pumped and no sync IPC messages are processed
// between script execution and the destruction of the RenderFrameHost .

View File

@@ -0,0 +1,217 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Raymond Toy <rtoy@chromium.org>
Date: Wed, 10 Feb 2021 05:34:49 +0000
Subject: Convert AudioParam NaN values to the default value
If any output value of an AudioParam (including the intrinsic values
and any inputs to the AudioParam), should be NaN, replace the NaN
value with the associated defaultValue.
This causes some slowdowns so SIMD/NEON code was added to mitigate the
degradation. There is still some slowdown, but the worst case is now
about 7% slower on x86 and 10% on arm. Generally, the slowdown is less
than 2% and 5%, respectively. (Perversely, some results got faster,
and the differences are statistically significant.)
Full details can be found at
https://docs.google.com/spreadsheets/d/1EhbLHm-9cUoEO5aj1vYemVBLQ3Dh4dCJPPLTfZPrZt4/edit?usp=sharing
Manually tested the test case from the bug and the issue no longer
occurs.
(cherry picked from commit ab1862017b5717271a28376659944dddc602195c)
Bug: 1170531
Change-Id: I00d902b40a9ef9da990c6d68b664b1dcfc31b091
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2658724
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#851733}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2686369
Reviewed-by: Raymond Toy <rtoy@chromium.org>
Cr-Commit-Position: refs/branch-heads/4389@{#880}
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
index c5d329479a412d52ee39167ff841b1cea417a217..135588f56ebceabd3e0a12f9f506955bb58b20ca 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
+#include "build/build_config.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
@@ -235,6 +236,49 @@ void AudioParamHandler::CalculateSampleAccurateValues(
CalculateFinalValues(values, number_of_values, IsAudioRate());
}
+// Replace NaN values in |values| with |default_value|.
+static void HandleNaNValues(float* values,
+ unsigned number_of_values,
+ float default_value) {
+ unsigned k = 0;
+#if defined(ARCH_CPU_X86_FAMILY)
+ if (number_of_values >= 4) {
+ __m128 defaults = _mm_set1_ps(default_value);
+ for (k = 0; k < number_of_values; k += 4) {
+ __m128 v = _mm_loadu_ps(values + k);
+ // cmpuord returns all 1's if v is NaN for each elmeent of v.
+ __m128 isnan = _mm_cmpunord_ps(v, v);
+ // Replace NaN parts with default.
+ __m128 result = _mm_and_ps(isnan, defaults);
+ // Merge in the parts that aren't NaN
+ result = _mm_or_ps(_mm_andnot_ps(isnan, v), result);
+ _mm_storeu_ps(values + k, result);
+ }
+ }
+#elif defined(CPU_ARM_NEON)
+ if (number_of_values >= 4) {
+ uint32x4_t defaults = static_cast<uint32x4_t>(vdupq_n_f32(default_value));
+ for (k = 0; k < number_of_values; k += 4) {
+ float32x4_t v = vld1q_f32(values + k);
+ // Returns true (all ones) if v is not NaN
+ uint32x4_t is_not_nan = vceqq_f32(v, v);
+ // Get the parts that are not NaN
+ uint32x4_t result = vandq_u32(is_not_nan, v);
+ // Replace the parts that are NaN with the default and merge with previous
+ // result. (Note: vbic_u32(x, y) = x and not y)
+ result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan));
+ vst1q_f32(values + k, static_cast<float32x4_t>(result));
+ }
+ }
+#endif
+
+ for (; k < number_of_values; ++k) {
+ if (std::isnan(values[k])) {
+ values[k] = default_value;
+ }
+ }
+}
+
void AudioParamHandler::CalculateFinalValues(float* values,
unsigned number_of_values,
bool sample_accurate) {
@@ -297,10 +341,21 @@ void AudioParamHandler::CalculateFinalValues(float* values,
}
}
- // Clamp the values now to the nominal range
float min_value = MinValue();
float max_value = MaxValue();
+ if (NumberOfRenderingConnections() > 0) {
+ // AudioParams by themselves don't produce NaN because of the finite min
+ // and max values. But an input to an AudioParam could have NaNs.
+ //
+ // NaN values in AudioParams must be replaced by the AudioParam's
+ // defaultValue. Then these values must be clamped to lie in the nominal
+ // range between the AudioParam's minValue and maxValue.
+ //
+ // See https://webaudio.github.io/web-audio-api/#computation-of-value.
+ HandleNaNValues(values, number_of_values, DefaultValue());
+ }
+
vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
number_of_values);
}
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html
new file mode 100644
index 0000000000000000000000000000000000000000..e9b8f0accbd1b0359275615f3ef12bd7e9317c4f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html
@@ -0,0 +1,92 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Test Flushing of NaN to Zero in AudioParams</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/webaudio/resources/audit-util.js"></script>
+ <script src="/webaudio/resources/audit.js"></script>
+ </head>
+
+ <body>
+ <script>
+ let audit = Audit.createTaskRunner();
+
+ // See
+ // https://webaudio.github.io/web-audio-api/#computation-of-value.
+ //
+ // The computed value must replace NaN values in the output with
+ // the default value of the param.
+ audit.define('AudioParam NaN', async (task, should) => {
+ // For testing, we only need a small number of frames; and
+ // a low sample rate is perfectly fine. Use two channels.
+ // The first channel is for the AudioParam output. The
+ // second channel is for the AudioParam input.
+ let context = new OfflineAudioContext(
+ {numberOfChannels: 2, length: 256, sampleRate: 8192});
+ let merger = new ChannelMergerNode(
+ context, {numberOfInputs: context.destination.channelCount});
+ merger.connect(context.destination);
+
+ // A constant source with a huge value.
+ let mod = new ConstantSourceNode(context, {offset: 1e30});
+
+ // Gain nodes with a huge positive gain and huge negative
+ // gain. Combined with the huge offset in |mod|, the
+ // output of the gain nodes are +Infinity and -Infinity.
+ let gainPos = new GainNode(context, {gain: 1e30});
+ let gainNeg = new GainNode(context, {gain: -1e30});
+
+ mod.connect(gainPos);
+ mod.connect(gainNeg);
+
+ // Connect these to the second merger channel. This is a
+ // sanity check that the AudioParam input really is NaN.
+ gainPos.connect(merger, 0, 1);
+ gainNeg.connect(merger, 0, 1);
+
+ // Source whose AudioParam is connected to the graph
+ // that produces NaN values. Use a non-default value offset
+ // just in case something is wrong we get default for some
+ // other reason.
+ let src = new ConstantSourceNode(context, {offset: 100});
+
+ gainPos.connect(src.offset);
+ gainNeg.connect(src.offset);
+
+ // AudioParam output goes to channel 1 of the destination.
+ src.connect(merger, 0, 0);
+
+ // Let's go!
+ mod.start();
+ src.start();
+
+ let buffer = await context.startRendering();
+
+ let input = buffer.getChannelData(1);
+ let output = buffer.getChannelData(0);
+
+ // Have to test manually for NaN values in the input because
+ // NaN fails all comparisons.
+ let isNaN = true;
+ for (let k = 0; k < input.length; ++k) {
+ if (!Number.isNaN(input[k])) {
+ isNaN = false;
+ break;
+ }
+ }
+
+ should(isNaN, 'AudioParam input contains only NaN').beTrue();
+
+ // Output of the AudioParam should have all NaN values
+ // replaced by the default.
+ should(output, 'AudioParam output')
+ .beConstantValueOf(src.offset.defaultValue);
+
+ task.done();
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>

View File

@@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kai Ninomiya <kainino@chromium.org>
Date: Thu, 11 Feb 2021 02:24:04 +0000
Subject: Disable GPU acceleration on all Mesa software rasterizers
The previous entry only disabled acceleration on swrast, but softpipe
and llvmpipe shouldn't be used for "GPU" acceleration either.
This should apply to Linux but not ChromeOS, AFAICT.
This only improves an existing software rendering list entry, but here
is the rationale: We prefer to rely on our own (domain specific, so more
efficient) software paths, at least for everything other than WebGL. And
for WebGL, SwiftShader avoids unknown factors like
llvmpipe/softpipe/swrast.
If you are running a Mesa GL driver (not e.g. NVIDIA) then you can force
these configurations with:
- LIBGL_ALWAYS_SOFTWARE=1
https://docs.mesa3d.org/envvars.html#libgl-environment-variables:~:text=LIBGL_ALWAYS_SOFTWARE
- GALLIUM_DRIVER=llvmpipe, softpipe, or swr (though swr didn't work for me)
https://docs.mesa3d.org/envvars.html#gallium-environment-variables:~:text=GALLIUM_DRIVER
The GL_RENDERER strings are:
- swrast: "Software Rasterizer" (couldn't test this locally; found this online)
- softpipe: "softpipe" (on one machine)
- llvmpipe: "llvmpipe (LLVM 10.0.0, 256 bits)" (on one machine)
Drive-by updates the description of another item to be more accurate
(SVGA3D is virtualized over hardware; it's not a software renderer).
# Unrelated CQ failures on branch
(cherry picked from commit 7c7eccfc85e387a0dcd154a2a9c2389177982837)
No-Try: True
Bug: 1155974
Change-Id: I0571c1a1bf526260f7ea6cd53f88eec768973b13
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2645491
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#846422}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2651183
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/branch-heads/4324@{#2176}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
index 1df09bc1c4e548919fa8b52abbfef0dedf6f411a..a2ced859448bcfe54a92d3496181d96ca85ee791 100644
--- a/gpu/config/software_rendering_list.json
+++ b/gpu/config/software_rendering_list.json
@@ -21,11 +21,11 @@
{
"id": 3,
"description": "GL driver is software rendered. GPU acceleration is disabled",
- "cr_bugs": [59302, 315217],
+ "cr_bugs": [59302, 315217, 1155974],
"os": {
"type": "linux"
},
- "gl_renderer": "(?i).*software.*",
+ "gl_renderer": "(?i).*(software|llvmpipe|softpipe).*",
"features": [
"all"
]
@@ -337,7 +337,7 @@
},
{
"id": 50,
- "description": "Disable VMware software renderer on older Mesa",
+ "description": "Disable VMware virtualized renderer on older Mesa",
"cr_bugs": [145531, 332596, 571899, 629434],
"os": {
"type": "linux"

View File

@@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nathan Zabriskie <nazabris@microsoft.com>
Date: Fri, 5 Feb 2021 20:44:16 +0000
Subject: Fix heap overflow in VideoFrameYUVConverter
Currently with some texture sizes GLES2Util::ComputeImageDataSizesES3
will attempt to add row padding when calculating the size of a
VideoFrame plane. This is because it's currently assumed that each row
aligns on a 4 byte boundary based on GL_UNPACK_ALIGNMENT but
VideoFrames make no such guarantee as they may be densely packed.
This CL removes the GL_UNPACK_ALIGNMENT assumption so that we only use
the VideoFrame's stride when calculating padding.
(cherry picked from commit 7de5d0ecb5a4f73aeffe15d825bf694d0d8e2a08)
Bug: 1166504, 1161131
Change-Id: I2484f5dfd2ad85b088fee57758776a5c9bd01d95
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2642765
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Commit-Queue: Nathan Zabriskie <nazabris@microsoft.com>
Cr-Original-Commit-Position: refs/heads/master@{#846298}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2679121
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Nathan Zabriskie <nazabris@microsoft.com>
Cr-Commit-Position: refs/branch-heads/4324@{#2115}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index e1611b999bb2ac276c64d5848e7d205a70ed26be..6400b35a7e98483c7553275623220c3bef4acd9c 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -880,7 +880,9 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
case GL_GPU_DISJOINT_EXT:
*params = static_cast<GLint>(query_tracker_->CheckAndResetDisjoint());
return true;
-
+ case GL_UNPACK_ALIGNMENT:
+ *params = unpack_alignment_;
+ return true;
case GL_VIEWPORT:
if (state_.viewport_width > 0 && state_.viewport_height > 0 &&
capabilities_.max_viewport_width > 0 &&
@@ -962,7 +964,6 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
case GL_STENCIL_VALUE_MASK:
case GL_STENCIL_WRITEMASK:
case GL_SUBPIXEL_BITS:
- case GL_UNPACK_ALIGNMENT:
return false;
default:
break;
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc
index 997a142250c56ede4cc5d9ad42743748d8b1346c..7199aef0f3bc5a3ecf6241574c69f4c2ed39f3df 100644
--- a/gpu/command_buffer/client/raster_implementation_gles.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -178,6 +178,9 @@ void RasterImplementationGLES::WritePixels(const gpu::Mailbox& dest_mailbox,
BeginSharedImageAccessDirectCHROMIUM(
texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
+ GLint old_align = 0;
+ gl_->GetIntegerv(GL_UNPACK_ALIGNMENT, &old_align);
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, row_bytes / src_info.bytesPerPixel());
gl_->BindTexture(texture_target, texture_id);
gl_->TexSubImage2D(texture_target, 0, dst_x_offset, dst_y_offset,
@@ -186,6 +189,7 @@ void RasterImplementationGLES::WritePixels(const gpu::Mailbox& dest_mailbox,
SkColorTypeToGLDataType(src_info.colorType()), src_pixels);
gl_->BindTexture(texture_target, 0);
gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, old_align);
EndSharedImageAccessDirectCHROMIUM(texture_id);
DeleteGpuRasterTexture(texture_id);

View File

@@ -0,0 +1,152 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Markus Handell <handellm@google.com>
Date: Tue, 23 Feb 2021 18:45:55 +0000
Subject: MediaRecorder: tolerate non-GMB NV12 frames for H264.
The VPX video track recorders were updated to tolerate non-GMB NV12
input in crrev/c/2425748, but the H264 encoder was left neglected,
which hurts Mac users that have disabled hardware acceleration. This
change adds that support to it.
[TBR landing because mcasas@chromium.org is OOO]
TBR=mcasas@chromium.org
(cherry picked from commit de865890bf6a12c74ae9943ede6132d25c7a33dd)
Bug: 1177593
Change-Id: I608c76b1de8261dcc44463fe896e3b63d5fd329e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2694407
Reviewed-by: ccameron <ccameron@chromium.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Reviewed-by: Miguel Casas <mcasas@chromium.org>
Commit-Queue: Markus Handell <handellm@google.com>
Cr-Original-Commit-Position: refs/heads/master@{#854709}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2715222
Cr-Commit-Position: refs/branch-heads/4389@{#1320}
Cr-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index 3daa1cb27d5705d56d0075e82a9ecd0bfb86c366..d5a0f1b578e22822089d704fcd7b98cbb26bb405 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -13,6 +13,7 @@
#include "base/numerics/safe_math.h"
#include "media/base/video_frame.h"
#include "third_party/libyuv/include/libyuv.h"
+#include "ui/gfx/gpu_memory_buffer.h"
namespace media {
@@ -424,6 +425,38 @@ void CopyRGBToVideoFrame(const uint8_t* source,
region_in_frame.width(), region_in_frame.height());
}
+scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
+ scoped_refptr<VideoFrame> video_frame) {
+ DCHECK(video_frame);
+ DCHECK(video_frame->HasGpuMemoryBuffer());
+ auto* gmb = video_frame->GetGpuMemoryBuffer();
+ if (!gmb->Map())
+ return nullptr;
+ const size_t num_planes = VideoFrame::NumPlanes(video_frame->format());
+ uint8_t* plane_addrs[VideoFrame::kMaxPlanes] = {};
+ for (size_t i = 0; i < num_planes; i++)
+ plane_addrs[i] = static_cast<uint8_t*>(gmb->memory(i));
+ auto mapped_frame = VideoFrame::WrapExternalYuvDataWithLayout(
+ video_frame->layout(), video_frame->visible_rect(),
+ video_frame->natural_size(), plane_addrs[0], plane_addrs[1],
+ plane_addrs[2], video_frame->timestamp());
+ if (!mapped_frame) {
+ gmb->Unmap();
+ return nullptr;
+ }
+ mapped_frame->set_color_space(video_frame->ColorSpace());
+ mapped_frame->metadata()->MergeMetadataFrom(video_frame->metadata());
+ // Pass |video_frame| so that it outlives |mapped_frame| and the mapped buffer
+ // is unmapped on destruction.
+ mapped_frame->AddDestructionObserver(base::BindOnce(
+ [](scoped_refptr<VideoFrame> frame) {
+ DCHECK(frame->HasGpuMemoryBuffer());
+ frame->GetGpuMemoryBuffer()->Unmap();
+ },
+ std::move(video_frame)));
+ return mapped_frame;
+}
+
scoped_refptr<VideoFrame> WrapAsI420VideoFrame(
scoped_refptr<VideoFrame> frame) {
DCHECK_EQ(VideoFrame::STORAGE_OWNED_MEMORY, frame->storage_type());
diff --git a/media/base/video_util.h b/media/base/video_util.h
index 42e060a25b711fca8bba3cef8ade9bbaa2092c55..2681163c55618ae8738d91987bb46a4e8bcc541b 100644
--- a/media/base/video_util.h
+++ b/media/base/video_util.h
@@ -134,6 +134,12 @@ MEDIA_EXPORT gfx::Size GetRectSizeFromOrigin(const gfx::Rect& rect);
MEDIA_EXPORT gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
const gfx::Size& target);
+// A helper function to map GpuMemoryBuffer-based VideoFrame. This function
+// maps the given GpuMemoryBuffer of |frame| as-is without converting pixel
+// format. The returned VideoFrame owns the |frame|.
+MEDIA_EXPORT scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
+ scoped_refptr<VideoFrame> frame);
+
// Copy an RGB bitmap into the specified |region_in_frame| of a YUV video frame.
// Fills the regions outside |region_in_frame| with black.
MEDIA_EXPORT void CopyRGBToVideoFrame(const uint8_t* source,
diff --git a/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc b/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
index 401e696e886f68fc4a9bb9ac0614959f0a8673a8..c323faab804ad421b1c8f8d7789222304c4d44e6 100644
--- a/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/h264_encoder.cc
@@ -54,9 +54,13 @@ void H264Encoder::EncodeOnEncodingTaskRunner(
base::TimeTicks capture_timestamp) {
TRACE_EVENT0("media", "H264Encoder::EncodeOnEncodingTaskRunner");
DCHECK(encoding_task_runner_->BelongsToCurrentThread());
+ DCHECK(frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_NV12 ||
+ frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_I420 ||
+ frame->format() == media::VideoPixelFormat::PIXEL_FORMAT_I420A);
- if (frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER)
+ if (frame->format() == media::PIXEL_FORMAT_NV12)
frame = ConvertToI420ForSoftwareEncoder(frame);
+ DCHECK(frame->IsMappable());
const gfx::Size frame_size = frame->visible_rect().size();
if (!openh264_encoder_ || configured_size_ != frame_size) {
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index 8f69cc61257cbe2c4c349912cfb4647ceaf771f7..1ace9b3f6ed14a96af7b8e8779a3929675be9a0a 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -415,20 +415,17 @@ bool VideoTrackRecorderImpl::Encoder::CanEncodeAlphaChannel() {
scoped_refptr<media::VideoFrame>
VideoTrackRecorderImpl::Encoder::ConvertToI420ForSoftwareEncoder(
scoped_refptr<media::VideoFrame> frame) {
- DCHECK_EQ(frame->storage_type(),
- media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
- // NV12 is currently the only supported pixel format for GpuMemoryBuffer.
DCHECK_EQ(frame->format(), media::VideoPixelFormat::PIXEL_FORMAT_NV12);
- auto* gmb = frame->GetGpuMemoryBuffer();
- if (!gmb->Map())
- return frame;
+ if (frame->GetGpuMemoryBuffer())
+ frame = media::ConvertToMemoryMappedFrame(frame);
+
scoped_refptr<media::VideoFrame> i420_frame = media::VideoFrame::CreateFrame(
media::VideoPixelFormat::PIXEL_FORMAT_I420, frame->coded_size(),
frame->visible_rect(), frame->natural_size(), frame->timestamp());
auto ret = libyuv::NV12ToI420(
- static_cast<const uint8_t*>(gmb->memory(0)), gmb->stride(0),
- static_cast<const uint8_t*>(gmb->memory(1)), gmb->stride(1),
+ static_cast<const uint8_t*>(frame->data(0)), frame->stride(0),
+ static_cast<const uint8_t*>(frame->data(1)), frame->stride(1),
i420_frame->data(media::VideoFrame::kYPlane),
i420_frame->stride(media::VideoFrame::kYPlane),
i420_frame->data(media::VideoFrame::kUPlane),
@@ -436,7 +433,6 @@ VideoTrackRecorderImpl::Encoder::ConvertToI420ForSoftwareEncoder(
i420_frame->data(media::VideoFrame::kVPlane),
i420_frame->stride(media::VideoFrame::kVPlane),
frame->coded_size().width(), frame->coded_size().height());
- gmb->Unmap();
if (ret)
return frame;
return i420_frame;

View File

@@ -0,0 +1,119 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tom Anderson <thomasanderson@chromium.org>
Date: Wed, 10 Feb 2021 23:53:26 +0000
Subject: Avoid spinning a nested message loop for X11 clipboard
*** NOTE: THIS IS NOT A CLEAN MERGE ***
> BUG=443355,1138143,1161141,1161143,1161144,1161145,1161146,1161147,1161149,1161151,1161152
>
> Change-Id: I5c95a9d066683d18f344d694e517274e3ef7ccb4
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2622521
> Reviewed-by: Scott Violet <sky@chromium.org>
> Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#844318}
BUG=1138143
TBR=sky
Change-Id: I7269ac8af7c91988a7d5520b3faf88dac89a577e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2688137
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/branch-heads/4324@{#2166}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc
index 7a83c814a756eb4daea020a47035c80320a129c3..f669f075b4dee7bbbc53c28abfe2f87fa6f27ed1 100644
--- a/ui/base/x/selection_requestor.cc
+++ b/ui/base/x/selection_requestor.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "base/memory/ref_counted_memory.h"
-#include "base/run_loop.h"
#include "ui/base/x/selection_owner.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_util.h"
@@ -28,7 +27,7 @@ const char kChromeSelection[] = "CHROME_SELECTION";
const int KSelectionRequestorTimerPeriodMs = 100;
// The amount of time to wait for a request to complete before aborting it.
-const int kRequestTimeoutMs = 10000;
+const int kRequestTimeoutMs = 1000;
static_assert(KSelectionRequestorTimerPeriodMs <= kRequestTimeoutMs,
"timer period must be <= request timeout");
@@ -235,37 +234,30 @@ void SelectionRequestor::ConvertSelectionForCurrentRequest() {
}
void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) {
- if (X11EventSource::HasInstance()) {
- if (!abort_timer_.IsRunning()) {
- abort_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(KSelectionRequestorTimerPeriodMs),
- this, &SelectionRequestor::AbortStaleRequests);
- }
-
- base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- request->quit_closure = run_loop.QuitClosure();
- run_loop.Run();
-
- // We cannot put logic to process the next request here because the RunLoop
- // might be nested. For instance, request 'B' may start a RunLoop while the
- // RunLoop for request 'A' is running. It is not possible to end the RunLoop
- // for request 'A' without first ending the RunLoop for request 'B'.
- } else {
- // This occurs if PerformBlockingConvertSelection() is called during
- // shutdown and the X11EventSource has already been destroyed.
- auto* conn = x11::Connection::Get();
- auto& events = conn->events();
- while (!request->completed && request->timeout > base::TimeTicks::Now()) {
- conn->Flush();
- conn->ReadResponses();
- if (!conn->events().empty()) {
- x11::Event event = std::move(events.front());
- events.pop_front();
- dispatcher_->DispatchXEvent(&event);
+ auto* connection = x11::Connection::Get();
+ auto& events = connection->events();
+ size_t i = 0;
+ while (!request->completed && request->timeout > base::TimeTicks::Now()) {
+ connection->Flush();
+ connection->ReadResponses();
+ size_t events_size = events.size();
+ for (; i < events_size; ++i) {
+ auto& event = events[i];
+ if (auto* notify = event.As<x11::SelectionNotifyEvent>()) {
+ if (notify->requestor == x_window_) {
+ OnSelectionNotify(*notify);
+ event = x11::Event();
+ }
+ } else if (auto* prop = event.As<x11::PropertyNotifyEvent>()) {
+ if (CanDispatchPropertyEvent(event)) {
+ OnPropertyEvent(event);
+ event = x11::Event();
+ }
}
}
+ DCHECK_EQ(events_size, events.size());
}
+ AbortStaleRequests();
}
SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() {
diff --git a/ui/base/x/selection_requestor_unittest.cc b/ui/base/x/selection_requestor_unittest.cc
index c67b8e62213456e0b3006a1eac618c733d28e1e2..efb31b6f3c07ea7debb188bdc8012849362b8dae 100644
--- a/ui/base/x/selection_requestor_unittest.cc
+++ b/ui/base/x/selection_requestor_unittest.cc
@@ -102,7 +102,8 @@ void PerformBlockingConvertSelection(SelectionRequestor* requestor,
// Test that SelectionRequestor correctly handles receiving a request while it
// is processing another request.
-TEST_F(SelectionRequestorTest, NestedRequests) {
+// TODO(https://crbug.com/443355): Reenable once clipboard interface is async.
+TEST_F(SelectionRequestorTest, DISABLED_NestedRequests) {
// Assume that |selection| will have no owner. If there is an owner, the owner
// will set the property passed into the XConvertSelection() request which is
// undesirable.

View File

@@ -0,0 +1,257 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tom Anderson <thomasanderson@chromium.org>
Date: Wed, 10 Feb 2021 22:45:10 +0000
Subject: Switch event queue from a std::list to a base::circular_deque
*** NOTE: THIS IS NOT A CLEAN MERGE ***
> This is needed as a prerequisite for [1]. It also improves performance
> a bit by replacing a node-based data structure with a flat one.
>
> [1] https://chromium-review.googlesource.com/c/chromium/src/+/2622521
>
> Change-Id: Ibe2e522f6c131876ed73793305524c25b42ab910
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2625784
> Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
> Reviewed-by: Scott Violet <sky@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#844303}
BUG=1138143
TBR=sky
Change-Id: I181af2c82d5552a3614747d8b4f6740583ec4ffe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2687828
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/branch-heads/4324@{#2163}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index c604bcd0f9b567957646f2cc16931d010bc0f9c6..c210014f2b07e731fb2e7c3ccbce44dec43dda25 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -348,16 +348,14 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
conn->ReadResponses();
if (motion) {
- for (auto it = conn->events().begin(); it != conn->events().end();) {
- const auto& next_event = *it;
+ for (auto& next_event : conn->events()) {
// Discard all but the most recent motion event that targets the same
// window with unchanged state.
const auto* next_motion = next_event.As<x11::MotionNotifyEvent>();
if (next_motion && next_motion->event == motion->event &&
next_motion->child == motion->child &&
next_motion->state == motion->state) {
- *last_event = std::move(*it);
- it = conn->events().erase(it);
+ *last_event = std::move(next_event);
} else {
break;
}
@@ -367,8 +365,8 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
device->opcode == x11::Input::DeviceEvent::TouchUpdate);
auto* ddmx11 = ui::DeviceDataManagerX11::GetInstance();
- for (auto it = conn->events().begin(); it != conn->events().end();) {
- auto* next_device = it->As<x11::Input::DeviceEvent>();
+ for (auto& event : conn->events()) {
+ auto* next_device = event.As<x11::Input::DeviceEvent>();
if (!next_device)
break;
@@ -379,13 +377,13 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
// always be at least one pending.
if (!ui::TouchFactory::GetInstance()->ShouldProcessDeviceEvent(
*next_device)) {
- it = conn->events().erase(it);
+ event = x11::Event();
continue;
}
if (next_device->opcode == device->opcode &&
- !ddmx11->IsCMTGestureEvent(*it) &&
- ddmx11->GetScrollClassEventDetail(*it) == SCROLL_TYPE_NO_SCROLL) {
+ !ddmx11->IsCMTGestureEvent(event) &&
+ ddmx11->GetScrollClassEventDetail(event) == SCROLL_TYPE_NO_SCROLL) {
// Confirm that the motion event is targeted at the same window
// and that no buttons or modifiers have changed.
if (device->event == next_device->event &&
@@ -396,12 +394,12 @@ int CoalescePendingMotionEvents(const x11::Event* x11_event,
device->mods.latched == next_device->mods.latched &&
device->mods.locked == next_device->mods.locked &&
device->mods.effective == next_device->mods.effective) {
- *last_event = std::move(*it);
- it = conn->events().erase(it);
+ *last_event = std::move(event);
num_coalesced++;
continue;
}
}
+
break;
}
}
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
index ae9b1d5174e6b39995bde80034ad426dcf4478c8..7164a2c47e2cd73092818896a1d94b705c98dbb1 100644
--- a/ui/events/platform/x11/x11_event_source.cc
+++ b/ui/events/platform/x11/x11_event_source.cc
@@ -221,8 +221,9 @@ x11::Time X11EventSource::GetCurrentServerTime() {
};
auto& events = connection_->events();
- events.erase(std::remove_if(events.begin(), events.end(), pred),
- events.end());
+ auto it = std::find_if(events.begin(), events.end(), pred);
+ if (it != events.end())
+ *it = x11::Event();
return time;
}
diff --git a/ui/gfx/x/connection.cc b/ui/gfx/x/connection.cc
index cea4895e776f6329ea65f94e3987402dadccabcb..c6a8b27f9a7f0ec4dae5187de471100c54a76b5c 100644
--- a/ui/gfx/x/connection.cc
+++ b/ui/gfx/x/connection.cc
@@ -326,12 +326,21 @@ Connection::Request::Request(Request&& other)
Connection::Request::~Request() = default;
-bool Connection::HasNextResponse() const {
+bool Connection::HasNextResponse() {
return !requests_.empty() &&
CompareSequenceIds(XLastKnownRequestProcessed(display_),
requests_.front().sequence) >= 0;
}
+bool Connection::HasNextEvent() {
+ while (!events_.empty()) {
+ if (events_.front().Initialized())
+ return true;
+ events_.pop_front();
+ }
+ return false;
+}
+
int Connection::GetFd() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return Ready() ? xcb_get_file_descriptor(XcbConnection()) : -1;
@@ -389,7 +398,7 @@ void Connection::ReadResponses() {
Event Connection::WaitForNextEvent() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!events_.empty()) {
+ if (HasNextEvent()) {
Event event = std::move(events_.front());
events_.pop_front();
return event;
@@ -401,9 +410,9 @@ Event Connection::WaitForNextEvent() {
return Event();
}
-bool Connection::HasPendingResponses() const {
+bool Connection::HasPendingResponses() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return !events_.empty() || HasNextResponse();
+ return HasNextEvent() || HasNextResponse();
}
const Connection::VisualInfo* Connection::GetVisualInfoFromId(
@@ -475,7 +484,7 @@ void Connection::Dispatch(Delegate* delegate) {
};
auto process_next_event = [&] {
- DCHECK(!events_.empty());
+ DCHECK(HasNextEvent());
Event event = std::move(events_.front());
events_.pop_front();
@@ -488,7 +497,7 @@ void Connection::Dispatch(Delegate* delegate) {
Flush();
ReadResponses();
- if (HasNextResponse() && !events_.empty()) {
+ if (HasNextResponse() && HasNextEvent()) {
if (!events_.front().sequence_valid()) {
process_next_event();
continue;
@@ -506,7 +515,7 @@ void Connection::Dispatch(Delegate* delegate) {
process_next_event();
} else if (HasNextResponse()) {
process_next_response();
- } else if (!events_.empty()) {
+ } else if (HasNextEvent()) {
process_next_event();
} else {
break;
diff --git a/ui/gfx/x/connection.h b/ui/gfx/x/connection.h
index 1e0fa6c230052e16fc67a4f6b154864477216445..107105d4236a6a99b544741a9e4ddf83407531de 100644
--- a/ui/gfx/x/connection.h
+++ b/ui/gfx/x/connection.h
@@ -5,10 +5,10 @@
#ifndef UI_GFX_X_CONNECTION_H_
#define UI_GFX_X_CONNECTION_H_
-#include <list>
#include <queue>
#include "base/component_export.h"
+#include "base/containers/circular_deque.h"
#include "base/sequence_checker.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/x/event.h"
@@ -113,7 +113,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
Event WaitForNextEvent();
// Are there any events, errors, or replies already buffered?
- bool HasPendingResponses() const;
+ bool HasPendingResponses();
// Dispatch any buffered events, errors, or replies.
void Dispatch(Delegate* delegate);
@@ -126,8 +126,10 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
KeySym KeycodeToKeysym(uint32_t keycode, unsigned int modifiers);
- // Access the event buffer. Clients can add, delete, or modify events.
- std::list<Event>& events() {
+ // Access the event buffer. Clients may modify the queue, including
+ // "deleting" events by setting events[i] = x11::Event(), which will
+ // guarantee all calls to x11::Event::As() will return nullptr.
+ base::circular_deque<Event>& events() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return events_;
}
@@ -159,7 +161,9 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
void AddRequest(unsigned int sequence, FutureBase::ResponseCallback callback);
- bool HasNextResponse() const;
+ bool HasNextResponse();
+
+ bool HasNextEvent();
void PreDispatchEvent(const Event& event);
@@ -194,7 +198,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
uint8_t mode_switch_ = 0;
uint8_t num_lock_ = 0;
- std::list<Event> events_;
+ base::circular_deque<Event> events_;
std::queue<Request> requests_;
diff --git a/ui/gfx/x/event.h b/ui/gfx/x/event.h
index 7e3d41dc7cefc5b01bd582b55274fd1f75c7782f..b370b0f9a95a2f1fec19d82ad17a76bb07015511 100644
--- a/ui/gfx/x/event.h
+++ b/ui/gfx/x/event.h
@@ -76,6 +76,8 @@ class COMPONENT_EXPORT(X11) Event {
*window_ = window;
}
+ bool Initialized() const { return deleter_; }
+
private:
friend void ReadEvent(Event* event,
Connection* connection,

View File

@@ -0,0 +1,137 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Raymond Zhao <raymondzhao@microsoft.com>
Date: Wed, 10 Feb 2021 12:03:34 -0800
Subject: Replace ClearFilterData with InvalidateFilterData
This is a hand-patch of
https://chromium-review.googlesource.com/c/chromium/src/+/2566992,
where the InvalidateFilterData function is from
https://chromium-review.googlesource.com/c/chromium/src/+/2454053.
Firstly, the InvalidateFilterData function was copied over.
Then, the ClearFilterData function was deleted, and any calls to it
were replaced with InvalidateFilterData. Redundant calls were removed.
The InvalidateFilterData function in this patch contains
a fix for SVG content sometimes failing to appear after modification
https://bugs.chromium.org/p/chromium/issues/detail?id=1154050.
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
index c7093ea1724dc99a26c3eef033d7ef13c2888f54..852eeb24ec617ae86e9aecd08bfe564445fbdca9 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
@@ -227,16 +227,11 @@ static inline void RemoveFromCacheAndInvalidateDependencies(
if (resources->HasClipOrMaskOrFilter()) {
InvalidationModeMask invalidation_mask =
SVGResourceClient::kBoundariesInvalidation;
- bool filter_data_invalidated = false;
if (resources->Filter()) {
- filter_data_invalidated = client->ClearFilterData();
- invalidation_mask |=
- filter_data_invalidated ? SVGResourceClient::kPaintInvalidation : 0;
+ client->InvalidateFilterData();
}
LayoutSVGResourceContainer::MarkClientForInvalidation(object,
invalidation_mask);
- if (filter_data_invalidated)
- client->MarkFilterDataDirty();
}
}
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
index f37cb5c3052d72ab15e769b29f8456e7ced9b5af..41ec00a53c1bb1c587b42f74867af4adab7e8641 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -604,12 +604,7 @@ void SVGResources::ClearClipPathFilterMask(SVGElement& element,
old_reference_clip->RemoveClient(*client);
if (style->HasFilter()) {
style->Filter().RemoveClient(*client);
- if (client->ClearFilterData()) {
- LayoutObject* layout_object = element.GetLayoutObject();
- LayoutSVGResourceContainer::MarkClientForInvalidation(
- *layout_object, SVGResourceClient::kPaintInvalidation);
- client->MarkFilterDataDirty();
- }
+ client->InvalidateFilterData();
}
if (StyleSVGResource* masker_resource = style->SvgStyle().MaskerResource())
masker_resource->RemoveClient(*client);
@@ -712,14 +707,10 @@ void SVGElementResourceClient::ResourceContentChanged(
return;
}
- const bool filter_data_invalidated = ClearFilterData();
- if (filter_data_invalidated)
- invalidation_mask |= SVGResourceClient::kPaintInvalidation;
+ InvalidateFilterData();
LayoutSVGResourceContainer::MarkClientForInvalidation(*layout_object,
invalidation_mask);
- if (filter_data_invalidated)
- MarkFilterDataDirty();
bool needs_layout =
invalidation_mask & SVGResourceClient::kLayoutInvalidation;
@@ -729,12 +720,8 @@ void SVGElementResourceClient::ResourceContentChanged(
void SVGElementResourceClient::ResourceElementChanged() {
if (LayoutObject* layout_object = element_->GetLayoutObject()) {
- ClearFilterData();
+ InvalidateFilterData();
SVGResourcesCache::ResourceReferenceChanged(*layout_object);
- // TODO(fs): If the resource element (for a filter) doesn't actually change
- // we don't need to perform the associated invalidations.
- layout_object->SetNeedsPaintPropertyUpdate();
- MarkFilterDataDirty();
}
}
@@ -801,11 +788,16 @@ void SVGElementResourceClient::UpdateFilterData(
filter_data_dirty_ = false;
}
-bool SVGElementResourceClient::ClearFilterData() {
- FilterData* filter_data = filter_data_.Release();
- if (filter_data)
+void SVGElementResourceClient::InvalidateFilterData() {
+ // If we performed an "optimized" invalidation via FilterPrimitiveChanged(),
+ // we could have set |filter_data_dirty_| but not cleared |filter_data_|.
+ if (filter_data_dirty_ && !filter_data_)
+ return;
+ if (FilterData* filter_data = filter_data_.Release())
filter_data->Dispose();
- return !!filter_data;
+ LayoutObject* layout_object = element_->GetLayoutObject();
+ layout_object->SetNeedsPaintPropertyUpdate();
+ MarkFilterDataDirty();
}
void SVGElementResourceClient::MarkFilterDataDirty() {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.h b/third_party/blink/renderer/core/layout/svg/svg_resources.h
index bfe056704b698d2189e5b759040f4f6cb3c54308..3416de3d5e062a31a0beb2df4d7398d2d435ec6a 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources.h
@@ -228,7 +228,7 @@ class SVGElementResourceClient final
const QualifiedName& attribute) override;
void UpdateFilterData(CompositorFilterOperations&);
- bool ClearFilterData();
+ void InvalidateFilterData();
void MarkFilterDataDirty();
void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
index b9aea888de151de41591ec9fd76ef4a3c0f4b017..6fa6ee6eb18f049603c5fc177a53c772239761cc 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
@@ -99,9 +99,7 @@ void SVGResourcesCache::ClientLayoutChanged(LayoutObject& object) {
invalidation_flags = SVGResourceClient::kBoundariesInvalidation;
bool filter_data_invalidated = false;
if (resources->Filter()) {
- filter_data_invalidated = client->ClearFilterData();
- invalidation_flags |=
- filter_data_invalidated ? SVGResourceClient::kPaintInvalidation : 0;
+ client->InvalidateFilterData();
}
if (LayoutSVGResourcePaintServer* fill = resources->Fill()) {
fill->RemoveClientFromCache(*client);

View File

@@ -0,0 +1,140 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Min Qin <qinmin@chromium.org>
Date: Fri, 12 Feb 2021 22:45:08 +0000
Subject: Stop using raw WebContents ptr in DragDownloadFile
BUG=1172192
(cherry picked from commit 99dc876a13df19f3512bcfb97e794ab5d1b28905)
Change-Id: Ie029713553ff88c1e271db1c84396e1ddda19286
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2666189
Reviewed-by: Xing Liu <xingliu@chromium.org>
Commit-Queue: Min Qin <qinmin@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#849692}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2692927
Reviewed-by: Shakti Sahu <shaktisahu@chromium.org>
Cr-Commit-Position: refs/branch-heads/4324@{#2200}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/content/browser/download/drag_download_file.cc b/content/browser/download/drag_download_file.cc
index 05c110adcbdebd67adc58a5e17b46dbd50ccc220..5dc8fe2214f6b5ef16445196e54ccb668c9fb5ef 100644
--- a/content/browser/download/drag_download_file.cc
+++ b/content/browser/download/drag_download_file.cc
@@ -37,15 +37,17 @@ class DragDownloadFile::DragDownloadFileUI
DragDownloadFileUI(const GURL& url,
const Referrer& referrer,
const std::string& referrer_encoding,
- WebContents* web_contents,
+ int render_process_id,
+ int render_frame_id,
OnCompleted on_completed)
: on_completed_(std::move(on_completed)),
url_(url),
referrer_(referrer),
referrer_encoding_(referrer_encoding),
- web_contents_(web_contents) {
+ render_process_id_(render_process_id),
+ render_frame_id_(render_frame_id) {
DCHECK(on_completed_);
- DCHECK(web_contents_);
+ DCHECK_GE(render_frame_id_, 0);
// May be called on any thread.
// Do not call weak_ptr_factory_.GetWeakPtr() outside the UI thread.
}
@@ -54,6 +56,10 @@ class DragDownloadFile::DragDownloadFileUI
const base::FilePath& file_path) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHost* host =
+ RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+ if (!host)
+ return;
// TODO(https://crbug.com/614134) This should use the frame actually
// containing the link being dragged rather than the main frame of the tab.
net::NetworkTrafficAnnotationTag traffic_annotation =
@@ -79,9 +85,9 @@ class DragDownloadFile::DragDownloadFileUI
}
}
})");
- std::unique_ptr<download::DownloadUrlParameters> params(
- DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
- web_contents_, url_, traffic_annotation));
+ auto params = std::make_unique<download::DownloadUrlParameters>(
+ url_, render_process_id_, host->GetRenderViewHost()->GetRoutingID(),
+ render_frame_id_, traffic_annotation);
params->set_referrer(referrer_.url);
params->set_referrer_policy(
Referrer::ReferrerPolicyForUrlRequest(referrer_.policy));
@@ -91,7 +97,7 @@ class DragDownloadFile::DragDownloadFileUI
params->set_file_path(file_path);
params->set_file(std::move(file)); // Nulls file.
params->set_download_source(download::DownloadSource::DRAG_AND_DROP);
- BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext())
+ BrowserContext::GetDownloadManager(host->GetBrowserContext())
->DownloadUrl(std::move(params));
}
@@ -165,7 +171,8 @@ class DragDownloadFile::DragDownloadFileUI
GURL url_;
Referrer referrer_;
std::string referrer_encoding_;
- WebContents* web_contents_;
+ int render_process_id_;
+ int render_frame_id_;
download::DownloadItem* download_item_ = nullptr;
// Only used in the callback from DownloadManager::DownloadUrl().
@@ -182,8 +189,10 @@ DragDownloadFile::DragDownloadFile(const base::FilePath& file_path,
WebContents* web_contents)
: file_path_(file_path), file_(std::move(file)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHost* host = web_contents->GetMainFrame();
drag_ui_ = new DragDownloadFileUI(
- url, referrer, referrer_encoding, web_contents,
+ url, referrer, referrer_encoding, host->GetProcess()->GetID(),
+ host->GetRoutingID(),
base::BindOnce(&DragDownloadFile::DownloadCompleted,
weak_ptr_factory_.GetWeakPtr()));
DCHECK(!file_path_.empty());
diff --git a/content/browser/download/drag_download_file_browsertest.cc b/content/browser/download/drag_download_file_browsertest.cc
index 800891a6df4f0d79f1dd0a9cf89b47b882d0f3de..88e248e49898ef55eff694d0979e01bbe69aa2f6 100644
--- a/content/browser/download/drag_download_file_browsertest.cc
+++ b/content/browser/download/drag_download_file_browsertest.cc
@@ -21,6 +21,7 @@
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/download_test_observer.h"
+#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
@@ -129,6 +130,28 @@ IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_Complete) {
RunUntilSucceed();
}
+IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_ClosePage) {
+ base::FilePath name(
+ downloads_directory().AppendASCII("DragDownloadFileTest_Complete.txt"));
+ GURL url = embedded_test_server()->GetURL("/download/download-test.lib");
+ Referrer referrer;
+ std::string referrer_encoding;
+ auto file = std::make_unique<DragDownloadFile>(name, base::File(), url,
+ referrer, referrer_encoding,
+ shell()->web_contents());
+ scoped_refptr<MockDownloadFileObserver> observer(
+ new MockDownloadFileObserver());
+ ON_CALL(*observer.get(), OnDownloadAborted())
+ .WillByDefault(InvokeWithoutArgs(this, &DragDownloadFileTest::FailFast));
+ DownloadManager* manager = BrowserContext::GetDownloadManager(
+ shell()->web_contents()->GetBrowserContext());
+ file->Start(observer.get());
+ shell()->web_contents()->Close();
+ RunAllTasksUntilIdle();
+ std::vector<download::DownloadItem*> downloads;
+ manager->GetAllDownloads(&downloads);
+ ASSERT_EQ(0u, downloads.size());
+}
// TODO(benjhayden): Test Stop().
} // namespace content

View File

@@ -0,0 +1,92 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Adam Rice <ricea@chromium.org>
Date: Fri, 12 Feb 2021 10:43:43 +0000
Subject: WebSocket: Don't clear event queue on destruction
It's unnecessary to clear the event queue as it will be garbage
collected anyway. Stop doing it.
Also add a unit test for GC with pending events. This can only happen if
the execution context changes while the events are pending.
BUG=1170657
(cherry picked from commit 2dae20b0b3890af23852345a69158c99b47746aa)
(cherry picked from commit 171d6ee562c3cac850d9705e18745bb1214e5d83)
Change-Id: I01e5a687587f7471e88640c43f0dfe83e5c01bd1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2655089
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Original-Original-Commit-Position: refs/heads/master@{#848065}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2660955
Reviewed-by: Adam Rice <ricea@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/4389@{#419}
Cr-Original-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2690730
Auto-Submit: Adam Rice <ricea@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4324@{#2191}
Cr-Branched-From: c73b5a651d37a6c4d0b8e3262cc4015a5579c6c8-refs/heads/master@{#827102}
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
index e4aa818faaf0f04a8f63bbcaff9f3391166e178c..06f2d0f5678f369e58370a5ad027e8d1bde26656 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -78,9 +78,7 @@ namespace blink {
DOMWebSocket::EventQueue::EventQueue(EventTarget* target)
: state_(kActive), target_(target) {}
-DOMWebSocket::EventQueue::~EventQueue() {
- ContextDestroyed();
-}
+DOMWebSocket::EventQueue::~EventQueue() = default;
void DOMWebSocket::EventQueue::Dispatch(Event* event) {
switch (state_) {
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index 1aadd61a2a3bddf1de039537b20e429e9e844a60..61c49deeee3a87552b5cdb5d99aabb65fdf943c6 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/heap/impl/thread_state.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -920,6 +921,32 @@ INSTANTIATE_TEST_SUITE_P(
DOMWebSocketInvalidClosingCodeTest,
testing::Values(0, 1, 998, 999, 1001, 2999, 5000, 9999, 65535));
+TEST(DOMWebSocketTest, GCWhileEventsPending) {
+ V8TestingScope scope;
+ {
+ DOMWebSocketTestScope websocket_scope(scope.GetExecutionContext());
+
+ EXPECT_CALL(websocket_scope.Channel(),
+ Connect(KURL("ws://example.com/"), String()))
+ .WillOnce(Return(true));
+ EXPECT_CALL(websocket_scope.Channel(), Disconnect());
+
+ auto& socket = websocket_scope.Socket();
+
+ // Cause events to be queued rather than fired.
+ socket.ContextLifecycleStateChanged(mojom::FrameLifecycleState::kPaused);
+
+ socket.Connect("ws://example.com/", Vector<String>(), ASSERT_NO_EXCEPTION);
+ socket.DidError();
+ socket.DidClose(DOMWebSocket::kClosingHandshakeIncomplete, 1006, "");
+
+ // Stop HasPendingActivity() from keeping the object alive.
+ socket.SetExecutionContext(nullptr);
+ }
+
+ ThreadState::Current()->CollectAllGarbageForTesting();
+}
+
} // namespace
} // namespace blink

View File

@@ -16,6 +16,10 @@
"src/electron/patches/sqlite": "src/third_party/sqlite/src",
"src/electron/patches/icu": "src/third_party/icu",
"src/electron/patches/skia": "src/third_party/skia",
"src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib"
"src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib",
"src/electron/patches/pdfium": "src/third_party/pdfium"
}

View File

@@ -47,3 +47,4 @@ fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch
chore_expose_v8_initialization_isolate_callbacks.patch
fix_add_safeforterminationscopes_for_sigint_interruptions.patch
allow_preventing_preparestacktracecallback.patch
src_inline_asynccleanuphookhandle_in_headers.patch

View File

@@ -9,42 +9,46 @@ with what's exposed through BoringSSL. I plan to upstream parts of this or
otherwise introduce shims to reduce friction.
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d87773dcd6 100644
index c373533ce85241f86d64eab8a49af79f935acdeb..19932c2a0abf454ddb1848b0b2cd19e3e9b2cfe9 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -5145,6 +5145,7 @@ bool DiffieHellman::Init(int primeLength, int g) {
@@ -5146,11 +5146,11 @@ bool DiffieHellman::Init(int primeLength, int g) {
bool DiffieHellman::Init(const char* p, int p_len, int g) {
dh_.reset(DH_new());
+#if 0
if (p_len <= 0) {
BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
return false;
@@ -5153,6 +5154,7 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
- BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
+ OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
return false;
}
if (g <= 1) {
- DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
return false;
}
+#endif
BIGNUM* bn_p =
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
BIGNUM* bn_g = BN_new();
@@ -5168,6 +5170,7 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
@@ -5169,18 +5169,18 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
dh_.reset(DH_new());
+#if 0
if (p_len <= 0) {
BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
return false;
@@ -5190,6 +5193,7 @@ bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
BN_free(bn_g);
- BNerr(BN_F_BN_GENERATE_PRIME_EX, BN_R_BITS_TOO_SMALL);
+ OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
return false;
}
+#endif
return VerifyContext();
}
@@ -6157,6 +6161,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
if (g_len <= 0) {
- DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
return false;
}
BIGNUM* bn_g =
BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, nullptr);
if (BN_is_zero(bn_g) || BN_is_one(bn_g)) {
BN_free(bn_g);
- DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR);
+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
return false;
}
BIGNUM* bn_p =
@@ -6157,6 +6157,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
EVPKeyCtxPointer Setup() override {
EVPKeyPointer params;
if (prime_info_.fixed_value_) {
@@ -52,7 +56,7 @@ index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d8
DHPointer dh(DH_new());
if (!dh)
return nullptr;
@@ -6173,6 +6178,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
@@ -6173,6 +6174,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
params = EVPKeyPointer(EVP_PKEY_new());
CHECK(params);
EVP_PKEY_assign_DH(params.get(), dh.release());
@@ -60,7 +64,7 @@ index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d8
} else {
EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
if (!param_ctx)
@@ -6180,7 +6186,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
@@ -6180,7 +6182,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
if (EVP_PKEY_paramgen_init(param_ctx.get()) <= 0)
return nullptr;
@@ -69,7 +73,7 @@ index c373533ce85241f86d64eab8a49af79f935acdeb..454fff5ada0c271db7fb975f809c84d8
if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(param_ctx.get(),
prime_info_.prime_size_) <= 0)
return nullptr;
@@ -6188,7 +6194,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
@@ -6188,7 +6190,7 @@ class DHKeyPairGenerationConfig : public KeyPairGenerationConfig {
if (EVP_PKEY_CTX_set_dh_paramgen_generator(param_ctx.get(),
generator_) <= 0)
return nullptr;

View File

@@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tyler Ang-Wanek <tylerw@axosoft.com>
Date: Tue, 19 Jan 2021 07:39:14 -0700
Subject: src: inline AsyncCleanupHookHandle in headers
Fixes: https://github.com/nodejs/node/issues/36349
PR-URL: https://github.com/nodejs/node/pull/37000
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
diff --git a/src/api/hooks.cc b/src/api/hooks.cc
index 3b16c0350d8a8494202144407664af41d338fe04..8b6f209cc8f167173a957049dec96dbec7ccc8d1 100644
--- a/src/api/hooks.cc
+++ b/src/api/hooks.cc
@@ -131,7 +131,7 @@ static void RunAsyncCleanupHook(void* arg) {
info->fun(info->arg, FinishAsyncCleanupHook, info);
}
-AsyncCleanupHookHandle AddEnvironmentCleanupHook(
+ACHHandle* AddEnvironmentCleanupHookInternal(
Isolate* isolate,
AsyncCleanupHook fun,
void* arg) {
@@ -143,11 +143,11 @@ AsyncCleanupHookHandle AddEnvironmentCleanupHook(
info->arg = arg;
info->self = info;
env->AddCleanupHook(RunAsyncCleanupHook, info.get());
- return AsyncCleanupHookHandle(new ACHHandle { info });
+ return new ACHHandle { info };
}
-void RemoveEnvironmentCleanupHook(
- AsyncCleanupHookHandle handle) {
+void RemoveEnvironmentCleanupHookInternal(
+ ACHHandle* handle) {
if (handle->info->started) return;
handle->info->self.reset();
handle->info->env->RemoveCleanupHook(RunAsyncCleanupHook, handle->info.get());
diff --git a/src/node.h b/src/node.h
index 0917daec298229a942c1790becfbefd19d01fb8d..8e52f9e8065750b48ddb36f447e4af54f993acfa 100644
--- a/src/node.h
+++ b/src/node.h
@@ -747,12 +747,26 @@ struct ACHHandle;
struct NODE_EXTERN DeleteACHHandle { void operator()(ACHHandle*) const; };
typedef std::unique_ptr<ACHHandle, DeleteACHHandle> AsyncCleanupHookHandle;
-NODE_EXTERN AsyncCleanupHookHandle AddEnvironmentCleanupHook(
+/* This function is not intended to be used externally, it exists to aid in
+ * keeping ABI compatibility between Node and Electron. */
+NODE_EXTERN ACHHandle* AddEnvironmentCleanupHookInternal(
v8::Isolate* isolate,
void (*fun)(void* arg, void (*cb)(void*), void* cbarg),
void* arg);
+inline AsyncCleanupHookHandle AddEnvironmentCleanupHook(
+ v8::Isolate* isolate,
+ void (*fun)(void* arg, void (*cb)(void*), void* cbarg),
+ void* arg) {
+ return AsyncCleanupHookHandle(AddEnvironmentCleanupHookInternal(isolate, fun,
+ arg));
+}
-NODE_EXTERN void RemoveEnvironmentCleanupHook(AsyncCleanupHookHandle holder);
+/* This function is not intended to be used externally, it exists to aid in
+ * keeping ABI compatibility between Node and Electron. */
+NODE_EXTERN void RemoveEnvironmentCleanupHookInternal(ACHHandle* holder);
+inline void RemoveEnvironmentCleanupHook(AsyncCleanupHookHandle holder) {
+ RemoveEnvironmentCleanupHookInternal(holder.get());
+}
/* Returns the id of the current execution context. If the return value is
* zero then no execution has been set. This will happen if the user handles

1
patches/pdfium/.patches Normal file
View File

@@ -0,0 +1 @@
m89_upgrade_openjpeg_to_2_4_0.patch

File diff suppressed because it is too large Load Diff

1
patches/skia/.patches Normal file
View File

@@ -0,0 +1 @@
cherry-pick-b0d3d3e85fa6.patch

View File

@@ -0,0 +1,158 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brian Salomon <bsalomon@google.com>
Date: Tue, 19 Jan 2021 10:28:15 -0500
Subject: Fix DrawEdgeAAQuad degenerate issue where 3D points don't correctly
project to 2D points.
Bug: chromium:1162942
Change-Id: Idc1dcb725ff9eae651b84de2fe792b188dcd1c1b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/354671
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
(cherry picked from commit 7656c4b7e89b4ff00480a6d7a8a19e3fd0e5c86e)
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/360376
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/gm/crbug_1162942.cpp b/gm/crbug_1162942.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5d1f6360f3d68e1d3e353752e2e676928c93aef
--- /dev/null
+++ b/gm/crbug_1162942.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm/gm.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkRect.h"
+
+// This tests a scenario where when the 2D projection of a perspective quad is inset we degenerate
+// the inset 2d geometry to a triangle because an inset vertex crosses the opposite edge. When we
+// project back to 3D and try to move the original verts along the original edges so that they
+// project to the 2D points. Whether an edge can be moved along depends on whether the adjacent edge
+// at the vertex is AA. However, in the degenerate triangle case the 2D point may not fall along
+// either of the edges. Thus, if we're constrained to moving along one edge and solve for X or Y the
+// other value may go wildly away from projecting to the 2D value. The current approach is to force
+// AA on at both edges that meet at a vertex whose inset point has been replaced by an off-edge
+// point if either is AA originally. This gives us an additional vector to move along so that we can
+// find a 3D point that projects to the 2D point in both X and Y.
+DEF_SIMPLE_GM(crbug_1162942, canvas, 620, 200) {
+ // Matrix and quad values taken from Chrome repro scenario.
+ SkMatrix ctm = SkMatrix::MakeAll(
+ SkBits2Float(0x3FCC7F75), SkBits2Float(0x3D5784FC), SkBits2Float(0x44C48C99),
+ SkBits2Float(0x3F699F7F), SkBits2Float(0x3E0A0D37), SkBits2Float(0x43908518),
+ SkBits2Float(0x3AA17423), SkBits2Float(0x3A6CCDC3), SkBits2Float(0x3F2EFEEC));
+ ctm.postTranslate(-1500.f, -325.f);
+
+ SkPoint pts[4] = {{SkBits2Float(0x3F39778B), SkBits2Float(0x43FF7FFC)},
+ {SkBits2Float(0x0), SkBits2Float(0x43FF7FFA)},
+ {SkBits2Float(0xB83B055E), SkBits2Float(0x42500003)},
+ {SkBits2Float(0x3F39776F), SkBits2Float(0x4250000D)}};
+ SkRect bounds;
+ bounds.setBounds(pts, 4);
+
+ canvas->clear(SK_ColorWHITE);
+
+ SkCanvas::QuadAAFlags flags[] = {
+ (SkCanvas::QuadAAFlags) (SkCanvas::kTop_QuadAAFlag | SkCanvas::kLeft_QuadAAFlag ),
+ (SkCanvas::QuadAAFlags) (SkCanvas::kBottom_QuadAAFlag | SkCanvas::kRight_QuadAAFlag),
+ (SkCanvas::QuadAAFlags) (SkCanvas::kBottom_QuadAAFlag),
+ (SkCanvas::QuadAAFlags) (SkCanvas::kRight_QuadAAFlag),
+ (SkCanvas::QuadAAFlags) (SkCanvas::kRight_QuadAAFlag | SkCanvas::kLeft_QuadAAFlag),
+ (SkCanvas::QuadAAFlags) (SkCanvas::kTop_QuadAAFlag | SkCanvas::kBottom_QuadAAFlag),
+ };
+
+ SkColor color = SK_ColorGREEN;
+ for (auto aaFlags : flags) {
+ canvas->save();
+ canvas->concat(ctm);
+ canvas->experimental_DrawEdgeAAQuad(bounds, pts, aaFlags, color, SkBlendMode::kSrcOver);
+ SkColor rgb = color & 0x00FFFFFF;
+ color = 0xFF000000 | (rgb << 4) | (rgb >> 20);
+ canvas->restore();
+ canvas->translate(0, 25);
+ }
+}
+
diff --git a/gn/gm.gni b/gn/gm.gni
index 731222e3a443ff20591fc15457aed7dc6d766451..8b0f2d414d245e3a573d86b75f264026ed21458b 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -109,6 +109,7 @@ gm_sources = [
"$_gm/crbug_1073670.cpp",
"$_gm/crbug_1086705.cpp",
"$_gm/crbug_1113794.cpp",
+ "$_gm/crbug_1162942.cpp",
"$_gm/crbug_224618.cpp",
"$_gm/crbug_691386.cpp",
"$_gm/crbug_788500.cpp",
diff --git a/src/gpu/geometry/GrQuadUtils.cpp b/src/gpu/geometry/GrQuadUtils.cpp
index 26b1415807a5218518e8eedabe1d1e0250a0f7f1..8bf8d19b84cb2ac27bebf4719d4d17d1abfc64ce 100644
--- a/src/gpu/geometry/GrQuadUtils.cpp
+++ b/src/gpu/geometry/GrQuadUtils.cpp
@@ -717,7 +717,10 @@ V4f TessellationHelper::EdgeEquations::estimateCoverage(const V4f& x2d, const V4
}
int TessellationHelper::EdgeEquations::computeDegenerateQuad(const V4f& signedEdgeDistances,
- V4f* x2d, V4f* y2d) const {
+ V4f* x2d, V4f* y2d,
+ M4f* aaMask) const {
+ *aaMask = signedEdgeDistances != 0.f;
+
// Move the edge by the signed edge adjustment.
V4f oc = fC + signedEdgeDistances;
@@ -792,10 +795,19 @@ int TessellationHelper::EdgeEquations::computeDegenerateQuad(const V4f& signedEd
if (SkScalarAbs(eDenom[0]) > kTolerance) {
px = if_then_else(d1v0, V4f(ex[0]), px);
py = if_then_else(d1v0, V4f(ey[0]), py);
+ // If we replace a vertex with an intersection then it will not fall along the
+ // edges that intersect at the original vertex. When we apply AA later to the
+ // original points we move along the original 3d edges to move towards the 2d
+ // points we're computing here. If we have an AA edge and a non-AA edge we
+ // can only move along 1 edge, but now the point we're moving toward isn't
+ // on that edge. Thus, we provide an additional degree of freedom by turning
+ // AA on for both edges if either edge is AA.
+ *aaMask = *aaMask | (d1v0 & skvx::shuffle<2, 0, 3, 1>(*aaMask));
}
if (SkScalarAbs(eDenom[1]) > kTolerance) {
px = if_then_else(d2v0, V4f(ex[1]), px);
py = if_then_else(d2v0, V4f(ey[1]), py);
+ *aaMask = *aaMask | (d2v0 & skvx::shuffle<2, 0, 3, 1>(*aaMask));
}
*x2d = px;
@@ -1156,9 +1168,11 @@ int TessellationHelper::adjustDegenerateVertices(const skvx::Vec<4, float>& sign
// handles perspective).
V4f x2d = fEdgeVectors.fX2D;
V4f y2d = fEdgeVectors.fY2D;
+
+ M4f aaMask;
int vertexCount = this->getEdgeEquations().computeDegenerateQuad(signedEdgeDistances,
- &x2d, &y2d);
- vertices->moveTo(x2d, y2d, signedEdgeDistances != 0.f);
+ &x2d, &y2d, &aaMask);
+ vertices->moveTo(x2d, y2d, aaMask);
return vertexCount;
}
}
diff --git a/src/gpu/geometry/GrQuadUtils.h b/src/gpu/geometry/GrQuadUtils.h
index 1288ba538d5a3fa646b1ae872254ddd51863ad17..f3e16df853cedc18707be8a96276f8e009df9e7c 100644
--- a/src/gpu/geometry/GrQuadUtils.h
+++ b/src/gpu/geometry/GrQuadUtils.h
@@ -113,7 +113,8 @@ namespace GrQuadUtils {
// small, edges are near parallel, or edges are very short/zero-length. Returns number
// of effective vertices in the degenerate quad.
int computeDegenerateQuad(const skvx::Vec<4, float>& signedEdgeDistances,
- skvx::Vec<4, float>* x2d, skvx::Vec<4, float>* y2d) const;
+ skvx::Vec<4, float>* x2d, skvx::Vec<4, float>* y2d,
+ skvx::Vec<4, int32_t>* aaMask) const;
};
struct OutsetRequest {

View File

@@ -12,3 +12,6 @@ perf_make_getpositioninfoslow_faster.patch
cherry-pick-ffd6ff5a61b9.patch
merged_deoptimizer_stricter_checks_during_deoptimization.patch
merged_compiler_mark_jsstoreinarrayliteral_as_needing_a_frame.patch
cherry-pick-36abafa0a316.patch
mac_wasm_work_around_macos_11_2_code_page_decommit_failures.patch
merged_interpreter_store_accumulator_to_callee_after_optional.patch

View File

@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Deepti Gandluri <gdeepti@chromium.org>
Date: Wed, 27 Jan 2021 22:19:44 -0800
Subject: PostMessage of Memory.buffer should throw
PostMessage of an ArrayBuffer that is not detachable should result
in a DataCloneError.
TBR=gdeepti@chromium.org
(cherry picked from commit dfcf1e86fac0a7b067caf8fdfc13eaf3e3f445e4)
Bug: chromium:1170176, chromium:961059
No-Try: true
No-Presubmit: true
No-Tree-Checks: true
Change-Id: Ife852df032841b7001375acd5e101d614c4b0771
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2674169
Reviewed-by: Zhi An Ng <zhin@chromium.org>
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Cr-Commit-Position: refs/branch-heads/8.8@{#30}
Cr-Branched-From: 2dbcdc105b963ee2501c82139eef7e0603977ff0-refs/heads/8.8.278@{#1}
Cr-Branched-From: 366d30c99049b3f1c673f8a93deb9f879d0fa9f0-refs/heads/master@{#71094}
diff --git a/src/common/message-template.h b/src/common/message-template.h
index b7bbc6da84ca03f6e0e1d969e731b04a688c5246..dc4d7581f165915833cefc1ec5d65f1f408e3ac9 100644
--- a/src/common/message-template.h
+++ b/src/common/message-template.h
@@ -575,6 +575,8 @@ namespace internal {
T(DataCloneErrorOutOfMemory, "Data cannot be cloned, out of memory.") \
T(DataCloneErrorDetachedArrayBuffer, \
"An ArrayBuffer is detached and could not be cloned.") \
+ T(DataCloneErrorNonDetachableArrayBuffer, \
+ "ArrayBuffer is not detachable and could not be cloned.") \
T(DataCloneErrorSharedArrayBufferTransferred, \
"A SharedArrayBuffer could not be cloned. SharedArrayBuffer must not be " \
"transferred.") \
diff --git a/src/objects/value-serializer.cc b/src/objects/value-serializer.cc
index b34076025f07ff5b4fadb8800c44acefa5480d19..d9abe45124f176d9ea7ab931a8247fbbd279c70a 100644
--- a/src/objects/value-serializer.cc
+++ b/src/objects/value-serializer.cc
@@ -860,6 +860,11 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
WriteVarint(index.FromJust());
return ThrowIfOutOfMemory();
}
+ if (!array_buffer->is_detachable()) {
+ ThrowDataCloneError(
+ MessageTemplate::kDataCloneErrorNonDetachableArrayBuffer);
+ return Nothing<bool>();
+ }
uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer);
if (transfer_entry) {
diff --git a/test/mjsunit/wasm/worker-memory.js b/test/mjsunit/wasm/worker-memory.js
index c5b99ede7e28364bbbe31165dfd8b8449a718137..bf5430f7139815c229e641eb6d40725b066035c5 100644
--- a/test/mjsunit/wasm/worker-memory.js
+++ b/test/mjsunit/wasm/worker-memory.js
@@ -11,6 +11,13 @@
assertThrows(() => worker.postMessage(memory), Error);
})();
+(function TestPostMessageUnsharedMemoryBuffer() {
+ let worker = new Worker('', {type: 'string'});
+ let memory = new WebAssembly.Memory({initial: 1, maximum: 2});
+
+ assertThrows(() => worker.postMessage(memory.buffer), Error);
+})();
+
// Can't use assert in a worker.
let workerHelpers =
`function assertTrue(value, msg) {

View File

@@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
Date: Mon, 8 Feb 2021 13:20:09 -0800
Subject: Work around MacOS 11.2 code page decommit failures
MacOS 11.2 refuses to set "no access" permissions on memory that
we previously used for JIT-compiled code. It is still unclear
whether this is WAI on the part of the kernel. In the meantime,
as a workaround, we use madvise(..., MADV_FREE_REUSABLE) instead
of mprotect(..., NONE) when discarding code pages. This is inspired
by what Chromium's gin platform does.
Fixed: v8:11389
Change-Id: I866586932573b4253002436ae5eee4e0411c45fc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2679688
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72559}
diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc
index 89173b593a6ce887c0f3cea082f2d31e17f8f5db..0afaa5269bd4b61cb62532a8ffc6debcfc508dfb 100644
--- a/src/base/platform/platform-posix.cc
+++ b/src/base/platform/platform-posix.cc
@@ -417,6 +417,16 @@ bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
int prot = GetProtectionFromMemoryPermission(access);
int ret = mprotect(address, size, prot);
+
+ // MacOS 11.2 on Apple Silicon refuses to switch permissions from
+ // rwx to none. Just use madvise instead.
+#if defined(V8_OS_MACOSX)
+ if (ret != 0 && access == OS::MemoryPermission::kNoAccess) {
+ ret = madvise(address, size, MADV_FREE_REUSABLE);
+ return ret == 0;
+ }
+#endif
+
if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
// This is advisory; ignore errors and continue execution.
USE(DiscardSystemPages(address, size));

View File

@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mythri A <mythria@chromium.org>
Date: Thu, 11 Feb 2021 10:09:03 +0000
Subject: Merged: [interpreter] Store accumulator to callee after optional
chain checks
Revision: df98901c19ce17ca995ee6750379b0f004210d68
BUG=chromium:1171954
NOTRY=true
NOPRESUBMIT=true
NOTREECHECKS=true
R=rmcilroy@chromium.org
Change-Id: Ib62b5cecb1f0c5a31856a26d97464e1ca941bc39
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2689191
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/branch-heads/8.8@{#34}
Cr-Branched-From: 2dbcdc105b963ee2501c82139eef7e0603977ff0-refs/heads/8.8.278@{#1}
Cr-Branched-From: 366d30c99049b3f1c673f8a93deb9f879d0fa9f0-refs/heads/master@{#71094}
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index 6b29add333e31e51eb8c63e41baf9f88300b9548..406a3966fe776731c6499ab55ee5883de77a6f8c 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -4921,8 +4921,9 @@ void BytecodeGenerator::VisitCall(Call* expr) {
Property* property = chain->expression()->AsProperty();
BuildOptionalChain([&]() {
VisitAndPushIntoRegisterList(property->obj(), &args);
- VisitPropertyLoadForRegister(args.last_register(), property, callee);
+ VisitPropertyLoad(args.last_register(), property);
});
+ builder()->StoreAccumulatorInRegister(callee);
break;
}
case Call::SUPER_CALL:
diff --git a/test/mjsunit/regress/regress-crbug-1038178.js b/test/mjsunit/regress/regress-crbug-1038178.js
index 0362f69bcda3ad1807d70de04b31deb8eea13af6..3a84066b837d514bffa5e96c6aca060f85232e02 100644
--- a/test/mjsunit/regress/regress-crbug-1038178.js
+++ b/test/mjsunit/regress/regress-crbug-1038178.js
@@ -15,7 +15,7 @@ function opt(){
(((function(){})())?.v)()
}
%PrepareFunctionForOptimization(opt)
-assertThrows(opt());
-assertThrows(opt());
+assertThrows(() => opt());
+assertThrows(() => opt());
%OptimizeFunctionOnNextCall(opt)
-assertThrows(opt());
+assertThrows(() => opt());
diff --git a/test/mjsunit/regress/regress-crbug-1171954.js b/test/mjsunit/regress/regress-crbug-1171954.js
new file mode 100644
index 0000000000000000000000000000000000000000..94fbb329bc47b4885d87d3e570a05e02909321c7
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-1171954.js
@@ -0,0 +1,19 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --always-opt
+
+// This causes the register used by the call in the later try-catch block to be
+// used by the ToName conversion for null which causes a DCHECK fail when
+// compiling. If register allocation changes, this test may no longer reproduce
+// the crash but it is not easy write a proper test because it is linked to
+// register allocation. This test should always work, so shouldn't cause any
+// flakes.
+try {
+ var { [null]: __v_12, } = {};
+} catch (e) {}
+
+try {
+ assertEquals((__v_40?.o?.m)().p);
+} catch (e) {}

View File

@@ -783,6 +783,25 @@ void BaseWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
}
}
void BaseWindow::SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args) {
gin::Handle<BrowserView> browser_view;
if (value->IsObject() &&
gin::ConvertFromV8(isolate(), value, &browser_view)) {
if (!browser_view->web_contents())
return;
auto* owner_window = browser_view->web_contents()->owner_window();
auto get_that_view = browser_views_.find(browser_view->ID());
if (get_that_view == browser_views_.end() ||
(owner_window && owner_window != window_.get())) {
args->ThrowError("Given BrowserView is not attached to the window");
return;
}
window_->SetTopBrowserView(browser_view->view());
}
}
std::string BaseWindow::GetMediaSourceId() const {
return window_->GetDesktopMediaID().ToString();
}
@@ -1086,7 +1105,7 @@ void BaseWindow::ResetBrowserViews() {
// reset if the owner window is *this* window.
if (browser_view->web_contents()) {
auto* owner_window = browser_view->web_contents()->owner_window();
if (owner_window == window_.get()) {
if (owner_window && owner_window == window_.get()) {
browser_view->web_contents()->SetOwnerWindow(nullptr);
owner_window->RemoveBrowserView(browser_view->view());
}
@@ -1210,6 +1229,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setBrowserView", &BaseWindow::SetBrowserView)
.SetMethod("addBrowserView", &BaseWindow::AddBrowserView)
.SetMethod("removeBrowserView", &BaseWindow::RemoveBrowserView)
.SetMethod("setTopBrowserView", &BaseWindow::SetTopBrowserView)
.SetMethod("getMediaSourceId", &BaseWindow::GetMediaSourceId)
.SetMethod("getNativeWindowHandle", &BaseWindow::GetNativeWindowHandle)
.SetMethod("setProgressBar", &BaseWindow::SetProgressBar)

View File

@@ -175,6 +175,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
virtual void SetBrowserView(v8::Local<v8::Value> value);
virtual void AddBrowserView(v8::Local<v8::Value> value);
virtual void RemoveBrowserView(v8::Local<v8::Value> value);
virtual void SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args);
virtual std::vector<v8::Local<v8::Value>> GetBrowserViews() const;
virtual void ResetBrowserViews();
std::string GetMediaSourceId() const;

View File

@@ -377,6 +377,14 @@ void BrowserWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
#endif
}
void BrowserWindow::SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args) {
BaseWindow::SetTopBrowserView(value, args);
#if defined(OS_MAC)
UpdateDraggableRegions(draggable_regions_);
#endif
}
void BrowserWindow::ResetBrowserViews() {
BaseWindow::ResetBrowserViews();
#if defined(OS_MAC)

View File

@@ -84,6 +84,8 @@ class BrowserWindow : public BaseWindow,
void SetBrowserView(v8::Local<v8::Value> value) override;
void AddBrowserView(v8::Local<v8::Value> value) override;
void RemoveBrowserView(v8::Local<v8::Value> value) override;
void SetTopBrowserView(v8::Local<v8::Value> value,
gin_helper::Arguments* args) override;
void ResetBrowserViews() override;
void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) override;
void OnWindowShow() override;

View File

@@ -680,7 +680,8 @@ std::vector<base::FilePath::StringType> Session::GetPreloads() const {
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
v8::Local<v8::Promise> Session::LoadExtension(
const base::FilePath& extension_path) {
const base::FilePath& extension_path,
gin::Arguments* args) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
gin_helper::Promise<const extensions::Extension*> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
@@ -697,10 +698,19 @@ v8::Local<v8::Promise> Session::LoadExtension(
return handle;
}
int load_flags = extensions::Extension::FOLLOW_SYMLINKS_ANYWHERE;
gin_helper::Dictionary options;
if (args->GetNext(&options)) {
bool allowFileAccess = false;
options.Get("allowFileAccess", &allowFileAccess);
if (allowFileAccess)
load_flags |= extensions::Extension::ALLOW_FILE_ACCESS;
}
auto* extension_system = static_cast<extensions::ElectronExtensionSystem*>(
extensions::ExtensionSystem::Get(browser_context()));
extension_system->LoadExtension(
extension_path,
extension_path, load_flags,
base::BindOnce(
[](gin_helper::Promise<const extensions::Extension*> promise,
const extensions::Extension* extension,

View File

@@ -122,7 +122,8 @@ class Session : public gin::Wrappable<Session>,
#endif
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
v8::Local<v8::Promise> LoadExtension(const base::FilePath& extension_path);
v8::Local<v8::Promise> LoadExtension(const base::FilePath& extension_path,
gin::Arguments* args);
void RemoveExtension(const std::string& extension_id);
v8::Local<v8::Value> GetExtension(const std::string& extension_id);
v8::Local<v8::Value> GetAllExtensions();

View File

@@ -26,9 +26,11 @@
#include "shell/browser/mac/dict_util.h"
#include "shell/browser/mac/electron_application.h"
#include "shell/browser/ui/cocoa/NSColor+Hex.h"
#include "shell/common/color_util.h"
#include "shell/common/gin_converters/gurl_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/process_util.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/native_theme/native_theme.h"
namespace gin {
@@ -384,7 +386,8 @@ std::string SystemPreferences::GetAccentColor() {
if (@available(macOS 10.14, *))
sysColor = [NSColor controlAccentColor];
return base::SysNSStringToUTF8([sysColor RGBAValue]);
return ToRGBAHex(skia::NSSystemColorToSkColor(sysColor),
false /* include_hash */);
}
std::string SystemPreferences::GetSystemColor(gin_helper::ErrorThrower thrower,
@@ -413,7 +416,7 @@ std::string SystemPreferences::GetSystemColor(gin_helper::ErrorThrower thrower,
return "";
}
return base::SysNSStringToUTF8([sysColor hexadecimalValue]);
return ToRGBHex(skia::NSSystemColorToSkColor(sysColor));
}
bool SystemPreferences::CanPromptTouchID() {
@@ -571,7 +574,7 @@ std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
}
if (sysColor)
return base::SysNSStringToUTF8([sysColor hexadecimalValue]);
return ToRGBHex(skia::NSSystemColorToSkColor(sysColor));
return "";
}

View File

@@ -877,7 +877,7 @@ content::WebContents* WebContents::OpenURLFromTab(
return nullptr;
}
if (!weak_this)
if (!weak_this || !web_contents())
return nullptr;
return CommonWebContentsDelegate::OpenURLFromTab(source, params);
@@ -1091,6 +1091,19 @@ void WebContents::BeforeUnloadFired(bool proceed,
void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
if (!background_throttling_)
render_view_host->SetSchedulerThrottling(false);
// Set the background color of RenderWidgetHostView.
auto* const view = web_contents()->GetRenderWidgetHostView();
auto* web_preferences = WebContentsPreferences::From(web_contents());
if (view && web_preferences) {
std::string color_name;
if (web_preferences->GetPreference(options::kBackgroundColor,
&color_name)) {
view->SetBackgroundColor(ParseHexColor(color_name));
} else {
view->SetBackgroundColor(SK_ColorTRANSPARENT);
}
}
}
void WebContents::RenderFrameCreated(
@@ -1122,7 +1135,13 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
}
void WebContents::RenderProcessGone(base::TerminationStatus status) {
auto weak_this = GetWeakPtr();
Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
// User might destroy WebContents in the crashed event.
if (!weak_this || !web_contents())
return;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Dictionary details = gin_helper::Dictionary::CreateEmpty(isolate);
@@ -1190,7 +1209,7 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
// ⚠WARNING!⚠️
// Emit() triggers JS which can call destroy() on |this|. It's not safe to
// assume that |this| points to valid memory at this point.
if (is_main_frame && weak_this)
if (is_main_frame && weak_this && web_contents())
Emit("did-finish-load");
}
@@ -1561,6 +1580,7 @@ void WebContents::WebContentsDestroyed() {
// also do not want any method to be used, so just mark as destroyed here.
MarkDestroyed();
Observe(nullptr); // this->web_contents() will return nullptr
Emit("destroyed");
// For guest view based on OOPIF, the WebContents is released by the embedder
@@ -1707,23 +1727,8 @@ void WebContents::LoadURL(const GURL& url,
// ⚠WARNING!⚠️
// LoadURLWithParams() triggers JS events which can call destroy() on |this|.
// It's not safe to assume that |this| points to valid memory at this point.
if (!weak_this)
if (!weak_this || !web_contents())
return;
// Set the background color of RenderWidgetHostView.
// We have to call it right after LoadURL because the RenderViewHost is only
// created after loading a page.
auto* const view = weak_this->web_contents()->GetRenderWidgetHostView();
if (view) {
auto* web_preferences = WebContentsPreferences::From(web_contents());
std::string color_name;
if (web_preferences->GetPreference(options::kBackgroundColor,
&color_name)) {
view->SetBackgroundColor(ParseHexColor(color_name));
} else {
view->SetBackgroundColor(SK_ColorTRANSPARENT);
}
}
}
void WebContents::DownloadURL(const GURL& url) {
@@ -2629,6 +2634,18 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
return handle;
}
#if !defined(OS_MAC)
// If the view's renderer is suspended this may fail on Windows/Linux -
// bail if so. See CopyFromSurface in
// content/public/browser/render_widget_host_view.h.
auto* rfh = web_contents()->GetMainFrame();
if (rfh &&
rfh->GetVisibilityState() == blink::mojom::PageVisibilityState::kHidden) {
promise.Resolve(gfx::Image());
return handle;
}
#endif // defined(OS_MAC)
// Capture full page if user doesn't specify a |rect|.
const gfx::Size view_size =
rect.IsEmpty() ? view->GetViewBounds().size() : rect.size();

View File

@@ -9,6 +9,7 @@
#include "content/public/browser/native_web_keyboard_event.h"
#include "shell/browser/ui/cocoa/event_dispatching_window.h"
#include "shell/browser/web_contents_preferences.h"
#include "ui/base/cocoa/command_dispatcher.h"
#include "ui/events/keycodes/keyboard_codes.h"
@interface NSWindow (EventDispatchingWindow)
@@ -48,6 +49,16 @@ bool CommonWebContentsDelegate::HandleKeyboardEvent(
// devtools windows as Widgets in order to take advantage of the
// pre-existing redispatch code in bridged_native_widget.
return false;
} else if (event.os_event.window &&
[event.os_event.window
conformsToProtocol:@protocol(CommandDispatchingWindow)]) {
NSObject<CommandDispatchingWindow>* window =
static_cast<NSObject<CommandDispatchingWindow>*>(event.os_event.window);
[[window commandDispatcher] redispatchKeyEvent:event.os_event];
// FIXME(clavin): Not exactly sure what to return here, likely the same
// situation as the branch above. If a future refactor removes
// |EventDispatchingWindow| then only this branch will need to remain.
return false;
}
return false;

View File

@@ -277,14 +277,6 @@ int ElectronBrowserMainParts::GetExitCode() {
return exit_code_ != nullptr ? *exit_code_ : 0;
}
void ElectronBrowserMainParts::RegisterDestructionCallback(
base::OnceClosure callback) {
// The destructors should be called in reversed order, so dependencies between
// JavaScript objects can be correctly resolved.
// For example WebContentsView => WebContents => Session.
destructors_.insert(destructors_.begin(), std::move(callback));
}
int ElectronBrowserMainParts::PreEarlyInitialization() {
field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr);
#if defined(USE_X11)
@@ -577,18 +569,6 @@ void ElectronBrowserMainParts::PostMainMessageLoopRun() {
}
}
// Make sure destruction callbacks are called before message loop is
// destroyed, otherwise some objects that need to be deleted on IO thread
// won't be freed.
// We don't use ranged for loop because iterators are getting invalided when
// the callback runs.
for (auto iter = destructors_.begin(); iter != destructors_.end();) {
base::OnceClosure callback = std::move(*iter);
if (!callback.is_null())
std::move(callback).Run();
++iter;
}
// Destroy node platform after all destructors_ are executed, as they may
// invoke Node/V8 APIs inside them.
node_debugger_->Stop();

View File

@@ -76,11 +76,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
// Gets the exit code
int GetExitCode();
// Register a callback that should be destroyed before JavaScript environment
// gets destroyed.
// Returns a closure that can be used to remove |callback| from the list.
void RegisterDestructionCallback(base::OnceClosure callback);
// Returns the connection to GeolocationControl which can be
// used to enable the location services once per client.
device::mojom::GeolocationControl* GetGeolocationControl();
@@ -159,9 +154,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
std::unique_ptr<ElectronExtensionsBrowserClient> extensions_browser_client_;
#endif
// List of callbacks should be executed before destroying JS env.
std::list<base::OnceClosure> destructors_;
mojo::Remote<device::mojom::GeolocationControl> geolocation_control_;
static ElectronBrowserMainParts* self_;

View File

@@ -37,15 +37,27 @@ base::FilePath CreateDownloadPath(const GURL& url,
const std::string& content_disposition,
const std::string& suggested_filename,
const std::string& mime_type,
const base::FilePath& last_saved_directory,
const base::FilePath& default_download_path) {
auto generated_name =
net::GenerateFileName(url, content_disposition, std::string(),
suggested_filename, mime_type, "download");
if (!base::PathExists(default_download_path))
base::CreateDirectory(default_download_path);
base::FilePath download_path;
return default_download_path.Append(generated_name);
// If the last saved directory is a non-empty existent path, use it as the
// default.
if (last_saved_directory.empty() || !base::PathExists(last_saved_directory)) {
download_path = default_download_path;
if (!base::PathExists(download_path))
base::CreateDirectory(download_path);
} else {
// Otherwise use the global default.
download_path = last_saved_directory;
}
return download_path.Append(generated_name);
}
} // namespace
@@ -153,10 +165,7 @@ void ElectronDownloadManagerDelegate::OnDownloadSaveDialogDone(
if (!canceled) {
if (result.Get("filePath", &path)) {
// Remember the last selected download directory.
auto* browser_context = static_cast<ElectronBrowserContext*>(
download_manager_->GetBrowserContext());
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
last_saved_directory_ = path.DirName();
api::DownloadItem* download = api::DownloadItem::FromDownloadItem(item);
if (download)
@@ -222,7 +231,7 @@ bool ElectronDownloadManagerDelegate::DetermineDownloadTarget(
base::BindOnce(&CreateDownloadPath, download->GetURL(),
download->GetContentDisposition(),
download->GetSuggestedFilename(), download->GetMimeType(),
default_download_path),
last_saved_directory_, default_download_path),
base::BindOnce(&ElectronDownloadManagerDelegate::OnDownloadPathGenerated,
weak_ptr_factory_.GetWeakPtr(), download->GetId(),
std::move(*callback)));

View File

@@ -52,6 +52,8 @@ class ElectronDownloadManagerDelegate
content::DownloadTargetCallback download_callback,
gin_helper::Dictionary result);
base::FilePath last_saved_directory_;
content::DownloadManager* download_manager_;
base::WeakPtrFactory<ElectronDownloadManagerDelegate> weak_ptr_factory_;

View File

@@ -30,7 +30,8 @@ using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
namespace {
std::pair<scoped_refptr<const Extension>, std::string> LoadUnpacked(
const base::FilePath& extension_dir) {
const base::FilePath& extension_dir,
int load_flags) {
// app_shell only supports unpacked extensions.
// NOTE: If you add packed extension support consider removing the flag
// FOLLOW_SYMLINKS_ANYWHERE below. Packed extensions should not have symlinks.
@@ -40,7 +41,6 @@ std::pair<scoped_refptr<const Extension>, std::string> LoadUnpacked(
return std::make_pair(nullptr, err);
}
int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
std::string load_error;
scoped_refptr<Extension> extension = file_util::LoadExtension(
extension_dir, Manifest::COMMAND_LINE, load_flags, &load_error);
@@ -76,10 +76,11 @@ ElectronExtensionLoader::~ElectronExtensionLoader() = default;
void ElectronExtensionLoader::LoadExtension(
const base::FilePath& extension_dir,
int load_flags,
base::OnceCallback<void(const Extension*, const std::string&)> cb) {
base::PostTaskAndReplyWithResult(
GetExtensionFileTaskRunner().get(), FROM_HERE,
base::BindOnce(&LoadUnpacked, extension_dir),
base::BindOnce(&LoadUnpacked, extension_dir, load_flags),
base::BindOnce(&ElectronExtensionLoader::FinishExtensionLoad,
weak_factory_.GetWeakPtr(), std::move(cb)));
}
@@ -112,22 +113,22 @@ void ElectronExtensionLoader::FinishExtensionLoad(
scoped_refptr<const Extension> extension = result.first;
if (extension) {
extension_registrar_.AddExtension(extension);
}
// Write extension install time to ExtensionPrefs. This is required by
// WebRequestAPI which calls extensions::ExtensionPrefs::GetInstallTime.
//
// Implementation for writing the pref was based on
// PreferenceAPIBase::SetExtensionControlledPref.
{
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
ExtensionPrefs::ScopedDictionaryUpdate update(
extension_prefs, extension.get()->id(),
extensions::pref_names::kPrefPreferences);
auto preference = update.Create();
const base::Time install_time = base::Time().Now();
preference->SetString("install_time",
base::NumberToString(install_time.ToInternalValue()));
// Write extension install time to ExtensionPrefs. This is required by
// WebRequestAPI which calls extensions::ExtensionPrefs::GetInstallTime.
//
// Implementation for writing the pref was based on
// PreferenceAPIBase::SetExtensionControlledPref.
{
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
ExtensionPrefs::ScopedDictionaryUpdate update(
extension_prefs, extension.get()->id(),
extensions::pref_names::kPrefPreferences);
auto preference = update.Create();
const base::Time install_time = base::Time().Now();
preference->SetString(
"install_time", base::NumberToString(install_time.ToInternalValue()));
}
}
std::move(cb).Run(extension.get(), result.second);
@@ -175,9 +176,13 @@ void ElectronExtensionLoader::LoadExtensionForReload(
LoadErrorBehavior load_error_behavior) {
CHECK(!path.empty());
// TODO(nornagon): we should save whether file access was granted
// when loading this extension and retain it here. As is, reloading an
// extension will cause the file access permission to be dropped.
int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
base::PostTaskAndReplyWithResult(
GetExtensionFileTaskRunner().get(), FROM_HERE,
base::BindOnce(&LoadUnpacked, path),
base::BindOnce(&LoadUnpacked, path, load_flags),
base::BindOnce(&ElectronExtensionLoader::FinishExtensionReload,
weak_factory_.GetWeakPtr(), extension_id));
did_schedule_reload_ = true;

View File

@@ -37,6 +37,7 @@ class ElectronExtensionLoader : public ExtensionRegistrar::Delegate {
// Loads an unpacked extension from a directory synchronously. Returns the
// extension on success, or nullptr otherwise.
void LoadExtension(const base::FilePath& extension_dir,
int load_flags,
base::OnceCallback<void(const Extension* extension,
const std::string&)> cb);

View File

@@ -56,8 +56,9 @@ ElectronExtensionSystem::~ElectronExtensionSystem() = default;
void ElectronExtensionSystem::LoadExtension(
const base::FilePath& extension_dir,
int load_flags,
base::OnceCallback<void(const Extension*, const std::string&)> cb) {
extension_loader_->LoadExtension(extension_dir, std::move(cb));
extension_loader_->LoadExtension(extension_dir, load_flags, std::move(cb));
}
void ElectronExtensionSystem::FinishInitialization() {

View File

@@ -41,6 +41,7 @@ class ElectronExtensionSystem : public ExtensionSystem {
// success, or nullptr otherwise.
void LoadExtension(
const base::FilePath& extension_dir,
int load_flags,
base::OnceCallback<void(const Extension*, const std::string&)> cb);
// Finish initialization for the shell extension system.

View File

@@ -60,9 +60,11 @@ void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
switch (state) {
case DiscoveryState::FAILED_TO_START:
refreshing_ = false;
event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
break;
case DiscoveryState::IDLE:
refreshing_ = false;
if (device_map_.empty()) {
auto event = ++num_retries_ > kMaxScanRetries
? content::BluetoothChooserEvent::CANCELLED
@@ -81,6 +83,14 @@ void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
}
break;
case DiscoveryState::DISCOVERING:
// The first time this state fires is due to a rescan triggering so set a
// flag to ignore devices
if (!refreshing_) {
refreshing_ = true;
} else {
// The second time this state fires we are now safe to pick a device
refreshing_ = false;
}
break;
}
}
@@ -91,6 +101,11 @@ void BluetoothChooser::AddOrUpdateDevice(const std::string& device_id,
bool is_gatt_connected,
bool is_paired,
int signal_strength_level) {
if (refreshing_) {
// If the list of bluetooth devices is currently being generated don't fire
// an event
return;
}
bool changed = false;
auto entry = device_map_.find(device_id);
if (entry == device_map_.end()) {

View File

@@ -41,6 +41,7 @@ class BluetoothChooser : public content::BluetoothChooser {
api::WebContents* api_web_contents_;
EventHandler event_handler_;
int num_retries_ = 0;
bool refreshing_ = false;
DISALLOW_COPY_AND_ASSIGN(BluetoothChooser);
};

View File

@@ -4,6 +4,7 @@
#include "shell/browser/native_browser_view_mac.h"
#import <objc/runtime.h>
#include <vector>
#include "shell/browser/ui/drag_util.h"
@@ -30,6 +31,33 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
@synthesize initialLocation;
+ (void)load {
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originalSelector = @selector(drawRect:);
SEL swizzledSelector = @selector(drawDebugRect:);
Method originalMethod =
class_getInstanceMethod([self class], originalSelector);
Method swizzledMethod =
class_getInstanceMethod([self class], swizzledSelector);
BOOL didAddMethod =
class_addMethod([self class], originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod([self class], swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
}
- (BOOL)mouseDownCanMoveWindow {
return NO;
}
@@ -134,11 +162,9 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
}
// For debugging purposes only.
- (void)drawRect:(NSRect)aRect {
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
NSRectFill([self bounds]);
}
- (void)drawDebugRect:(NSRect)aRect {
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
NSRectFill([self bounds]);
}
@end
@@ -148,16 +174,41 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
@implementation ExcludeDragRegionView
+ (void)load {
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originalSelector = @selector(drawRect:);
SEL swizzledSelector = @selector(drawDebugRect:);
Method originalMethod =
class_getInstanceMethod([self class], originalSelector);
Method swizzledMethod =
class_getInstanceMethod([self class], swizzledSelector);
BOOL didAddMethod =
class_addMethod([self class], originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod([self class], swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
}
- (BOOL)mouseDownCanMoveWindow {
return NO;
}
// For debugging purposes only.
- (void)drawRect:(NSRect)aRect {
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
NSRectFill([self bounds]);
}
- (void)drawDebugRect:(NSRect)aRect {
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
NSRectFill([self bounds]);
}
@end
@@ -248,7 +299,6 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
NSView* web_view = GetWebContents()->GetNativeView().GetNativeNSView();
NSView* inspectable_view = iwc_view->GetNativeView().GetNativeNSView();
NSView* window_content_view = inspectable_view.superview;
const auto window_content_view_height = NSHeight(window_content_view.bounds);
// Remove all DragRegionViews that were added last time. Note that we need
// to copy the `subviews` array to avoid mutation during iteration.
@@ -264,14 +314,15 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
[[DragRegionView alloc] initWithFrame:web_view.bounds]);
[web_view addSubview:drag_region_view];
// Then, on top of that, add "exclusion zones"
// Then, on top of that, add "exclusion zones".
auto const offset = GetBounds().OffsetFromOrigin();
const auto window_content_view_height = NSHeight(window_content_view.bounds);
for (const auto& rect : drag_exclude_rects) {
const auto window_content_view_exclude_rect =
NSMakeRect(rect.x(), window_content_view_height - rect.bottom(),
rect.width(), rect.height());
const auto x = rect.x() + offset.x();
const auto y = window_content_view_height - rect.bottom() + offset.y();
const auto exclude_rect = NSMakeRect(x, y, rect.width(), rect.height());
const auto drag_region_view_exclude_rect =
[window_content_view convertRect:window_content_view_exclude_rect
toView:drag_region_view];
[window_content_view convertRect:exclude_rect toView:drag_region_view];
base::scoped_nsobject<NSView> exclude_drag_region_view(
[[ExcludeDragRegionView alloc]

View File

@@ -165,6 +165,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void SetParentWindow(NativeWindow* parent);
virtual void AddBrowserView(NativeBrowserView* browser_view) = 0;
virtual void RemoveBrowserView(NativeBrowserView* browser_view) = 0;
virtual void SetTopBrowserView(NativeBrowserView* browser_view) = 0;
virtual content::DesktopMediaID GetDesktopMediaID() const = 0;
virtual gfx::NativeView GetNativeView() const = 0;
virtual gfx::NativeWindow GetNativeWindow() const = 0;

View File

@@ -113,6 +113,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void SetFocusable(bool focusable) override;
void AddBrowserView(NativeBrowserView* browser_view) override;
void RemoveBrowserView(NativeBrowserView* browser_view) override;
void SetTopBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override;
content::DesktopMediaID GetDesktopMediaID() const override;
gfx::NativeView GetNativeView() const override;

View File

@@ -1202,8 +1202,10 @@ void NativeWindowMac::SetBackgroundColor(SkColor color) {
}
SkColor NativeWindowMac::GetBackgroundColor() {
return skia::CGColorRefToSkColor(
[[[window_ contentView] layer] backgroundColor]);
CGColorRef color = [[[window_ contentView] layer] backgroundColor];
if (!color)
return SK_ColorTRANSPARENT;
return skia::CGColorRefToSkColor(color);
}
void NativeWindowMac::SetHasShadow(bool has_shadow) {
@@ -1301,6 +1303,30 @@ void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
[CATransaction commit];
}
void NativeWindowMac::SetTopBrowserView(NativeBrowserView* view) {
[CATransaction begin];
[CATransaction setDisableActions:YES];
if (!view) {
[CATransaction commit];
return;
}
remove_browser_view(view);
add_browser_view(view);
if (view->GetInspectableWebContentsView()) {
auto* native_view = view->GetInspectableWebContentsView()
->GetNativeView()
.GetNativeNSView();
[[window_ contentView] addSubview:native_view
positioned:NSWindowAbove
relativeTo:nil];
native_view.hidden = NO;
}
[CATransaction commit];
}
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
InternalSetParentWindow(parent, IsVisible());
}

View File

@@ -915,7 +915,10 @@ bool NativeWindowViews::IsKiosk() {
}
SkColor NativeWindowViews::GetBackgroundColor() {
return root_view_->background()->get_color();
auto* background = root_view_->background();
if (!background)
return SK_ColorTRANSPARENT;
return background->get_color();
}
void NativeWindowViews::SetBackgroundColor(SkColor background_color) {
@@ -1104,6 +1107,22 @@ void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
remove_browser_view(view);
}
void NativeWindowViews::SetTopBrowserView(NativeBrowserView* view) {
if (!content_view())
return;
if (!view) {
return;
}
remove_browser_view(view);
add_browser_view(view);
if (view->GetInspectableWebContentsView())
content_view()->ReorderChildView(
view->GetInspectableWebContentsView()->GetView(), -1);
}
void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
NativeWindow::SetParentWindow(parent);

Some files were not shown because too many files have changed in this diff Show More