mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
274 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b804177fa | ||
|
|
77478353c6 | ||
|
|
30e8011b9f | ||
|
|
54432ab8b2 | ||
|
|
37558a6215 | ||
|
|
d5ba5c8e0a | ||
|
|
b1b83f79b7 | ||
|
|
a85b38847e | ||
|
|
ade9151181 | ||
|
|
9d2961868c | ||
|
|
cdd6fc93b2 | ||
|
|
1e21b7c910 | ||
|
|
c224431ae8 | ||
|
|
9e0fda8393 | ||
|
|
36b72ba5ee | ||
|
|
dd8c63e15a | ||
|
|
6bfa54fcf2 | ||
|
|
6d9f3a4945 | ||
|
|
a20396588a | ||
|
|
f988853128 | ||
|
|
8bc25e8a9d | ||
|
|
a8f8b507aa | ||
|
|
eb320cbbf9 | ||
|
|
37eab5c66e | ||
|
|
fc912026e2 | ||
|
|
6aa0609a97 | ||
|
|
620d615fe0 | ||
|
|
ec7baba401 | ||
|
|
f8ba4d6012 | ||
|
|
79af6f3493 | ||
|
|
6a952c4ff1 | ||
|
|
ce7c83e8d6 | ||
|
|
a686f7e102 | ||
|
|
fa07b74836 | ||
|
|
587353dbc9 | ||
|
|
21b8b3064d | ||
|
|
0f05991c3e | ||
|
|
6bdab4a353 | ||
|
|
6e5f02426a | ||
|
|
30da5dee2a | ||
|
|
bd9c7c41ba | ||
|
|
76f4ced8d4 | ||
|
|
cac38cb6ea | ||
|
|
e8f89da1c4 | ||
|
|
a0f73938cd | ||
|
|
1bf71fa81f | ||
|
|
0de8079b33 | ||
|
|
52fd3da443 | ||
|
|
742aab764e | ||
|
|
1f669c3cc5 | ||
|
|
d26d064082 | ||
|
|
a31e722d43 | ||
|
|
81b923c8f5 | ||
|
|
b745364907 | ||
|
|
91cf2e2163 | ||
|
|
53af38ad54 | ||
|
|
2fef020e06 | ||
|
|
b60dfe4117 | ||
|
|
7e123ac6e5 | ||
|
|
a29136950e | ||
|
|
458a843174 | ||
|
|
e11e12d5b3 | ||
|
|
25ed65150d | ||
|
|
8737aa046d | ||
|
|
0d94bdda50 | ||
|
|
2c3081afb8 | ||
|
|
f583acff46 | ||
|
|
271e98c059 | ||
|
|
8279c02e9a | ||
|
|
ef4cbe86af | ||
|
|
300a40f939 | ||
|
|
79b45ac5f6 | ||
|
|
e5e8dd5156 | ||
|
|
4e75499270 | ||
|
|
1bc5b6177f | ||
|
|
5647382a55 | ||
|
|
fd272d89bc | ||
|
|
d745647c54 | ||
|
|
9038bdd7bc | ||
|
|
bbc862c878 | ||
|
|
ff57df1ecb | ||
|
|
37dfd8be4a | ||
|
|
f043e665dd | ||
|
|
798f151e05 | ||
|
|
a9a3910aa0 | ||
|
|
2f28e10543 | ||
|
|
f1021b93d0 | ||
|
|
6788561bb3 | ||
|
|
35d3f35a44 | ||
|
|
f949a1aafd | ||
|
|
b8e22532b0 | ||
|
|
c2758554ed | ||
|
|
05cb4240bd | ||
|
|
c84b152164 | ||
|
|
20f8c10977 | ||
|
|
38be2dfb25 | ||
|
|
0c371e53a4 | ||
|
|
8e517202ea | ||
|
|
3410147699 | ||
|
|
ce5157236c | ||
|
|
8ec2469379 | ||
|
|
ddf348d609 | ||
|
|
f757a17821 | ||
|
|
8519ba881e | ||
|
|
bd31023314 | ||
|
|
fb0eb6c0ca | ||
|
|
390349e3db | ||
|
|
f6e6873971 | ||
|
|
ecd6918166 | ||
|
|
d54f1d58f7 | ||
|
|
5d5b2bf8e5 | ||
|
|
fa37e1533f | ||
|
|
f9cf232597 | ||
|
|
615c15c914 | ||
|
|
4550baa7a5 | ||
|
|
7469c72d80 | ||
|
|
bedb5e1055 | ||
|
|
6815c823b3 | ||
|
|
78c5a2cf4b | ||
|
|
3c3d279182 | ||
|
|
1c7a612931 | ||
|
|
4615dcbbfd | ||
|
|
3bbe839403 | ||
|
|
0f5967fce2 | ||
|
|
da171befe7 | ||
|
|
c850e2452c | ||
|
|
f3ca6ff998 | ||
|
|
58e9dedd76 | ||
|
|
51a673e7e0 | ||
|
|
fed01fb57d | ||
|
|
65c9f47e15 | ||
|
|
1b54c4bc44 | ||
|
|
f903141394 | ||
|
|
6c1f9f8270 | ||
|
|
7432ea43b7 | ||
|
|
0d1b7be451 | ||
|
|
e0a7f869de | ||
|
|
d9dd6138e2 | ||
|
|
c1651e333b | ||
|
|
c0ea40e71d | ||
|
|
501bb98a10 | ||
|
|
9fe9a0ccc1 | ||
|
|
f6d2b9dc63 | ||
|
|
b04be1dff6 | ||
|
|
656463c2f4 | ||
|
|
a0e9cc6c02 | ||
|
|
27e2c79dd0 | ||
|
|
d74441f00e | ||
|
|
97e52764a8 | ||
|
|
112392c414 | ||
|
|
42c2eecdef | ||
|
|
98603c645e | ||
|
|
11391e7351 | ||
|
|
a636ab7c61 | ||
|
|
53e39eb9c0 | ||
|
|
cccd74e6a6 | ||
|
|
1efa631b56 | ||
|
|
221d2220e1 | ||
|
|
ae3ee8ad00 | ||
|
|
b39a34650f | ||
|
|
8292b3dc0c | ||
|
|
8653dfc8b3 | ||
|
|
1ef9a756e5 | ||
|
|
fdfa5d41d4 | ||
|
|
86e10b06dd | ||
|
|
d2497a14e0 | ||
|
|
5963024ac7 | ||
|
|
26690b12f2 | ||
|
|
1a148a8232 | ||
|
|
cff70f15aa | ||
|
|
a6f094c983 | ||
|
|
04dcbe4c74 | ||
|
|
28def9ed7d | ||
|
|
2089370bbb | ||
|
|
837dc05204 | ||
|
|
9f08e46018 | ||
|
|
6a70d8a6ca | ||
|
|
aab276c532 | ||
|
|
053fea1b44 | ||
|
|
0b0e991a54 | ||
|
|
ec7408a2d4 | ||
|
|
250b7ed3db | ||
|
|
d136430b35 | ||
|
|
79abfe7ac8 | ||
|
|
a18a4609ad | ||
|
|
cdf661939d | ||
|
|
98cf0e5dff | ||
|
|
be9dccfcc6 | ||
|
|
e4bb98195f | ||
|
|
099560c59c | ||
|
|
efd276d31f | ||
|
|
e2cb43768d | ||
|
|
e654f5ecb3 | ||
|
|
f74940b536 | ||
|
|
fe8508a287 | ||
|
|
d5dd50f87e | ||
|
|
952994c591 | ||
|
|
536b5c4e3b | ||
|
|
210bae878f | ||
|
|
9b78227260 | ||
|
|
0a50571460 | ||
|
|
248a6012d5 | ||
|
|
ed52801e09 | ||
|
|
6226507536 | ||
|
|
098a118dce | ||
|
|
56e08fe5f1 | ||
|
|
8dba1cf5fa | ||
|
|
1fc7634f69 | ||
|
|
52e443ec52 | ||
|
|
16be926e0a | ||
|
|
5c2d65c749 | ||
|
|
7bf1d3c110 | ||
|
|
92969d6032 | ||
|
|
b48d0f2cbe | ||
|
|
ff8594b11b | ||
|
|
a41f04028e | ||
|
|
1f320e0688 | ||
|
|
1f23e83ef9 | ||
|
|
11ea44925b | ||
|
|
21a6c6dc76 | ||
|
|
057c24feec | ||
|
|
69014e7aad | ||
|
|
ec293f4de0 | ||
|
|
15038974ad | ||
|
|
d2287a1935 | ||
|
|
e298bf46e4 | ||
|
|
5426d2c920 | ||
|
|
3e0a2edec4 | ||
|
|
f74d89ba80 | ||
|
|
4e14dca687 | ||
|
|
1aaf1e7241 | ||
|
|
1e7c8a3c63 | ||
|
|
8496a12321 | ||
|
|
98bab0ca28 | ||
|
|
a630db8c86 | ||
|
|
7e19dbad6f | ||
|
|
2b8fc8a139 | ||
|
|
30b9d15af0 | ||
|
|
bcf04f5878 | ||
|
|
9fba8b35cb | ||
|
|
ad3563687f | ||
|
|
4e2c19944f | ||
|
|
95814288cf | ||
|
|
b711b8f98d | ||
|
|
a1744e5de0 | ||
|
|
e9446f0dc4 | ||
|
|
1cda1d0e86 | ||
|
|
c2023dd9f5 | ||
|
|
c98059abd9 | ||
|
|
df726b619d | ||
|
|
c2b1db192d | ||
|
|
235c32ee55 | ||
|
|
7e66d6a952 | ||
|
|
0db4d5add5 | ||
|
|
9380803004 | ||
|
|
2a12d5fa7f | ||
|
|
93e8de87a5 | ||
|
|
b6c9110923 | ||
|
|
5e815df20f | ||
|
|
e676b3862c | ||
|
|
cd8f678a8d | ||
|
|
79554ba989 | ||
|
|
ad67a27dcf | ||
|
|
c9476eb821 | ||
|
|
2c6321c9af | ||
|
|
715de396d4 | ||
|
|
98d6b9bf15 | ||
|
|
a05ed73f43 | ||
|
|
f7fdd34c45 | ||
|
|
55e6ce81e0 | ||
|
|
b5c81db591 | ||
|
|
cffbeeaefa | ||
|
|
c81380848f | ||
|
|
45a1d81315 |
1
.circleci/.gitignore
vendored
Normal file
1
.circleci/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
config-staging
|
||||
2603
.circleci/config.yml
2603
.circleci/config.yml
File diff suppressed because it is too large
Load Diff
2469
.circleci/config/base.yml
Normal file
2469
.circleci/config/base.yml
Normal file
File diff suppressed because it is too large
Load Diff
34
.circleci/config/build.js
Normal file
34
.circleci/config/build.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const cp = require('child_process');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const STAGING_DIR = path.resolve(__dirname, '..', 'config-staging');
|
||||
|
||||
function copyAndExpand(dir = './') {
|
||||
const absDir = path.resolve(__dirname, dir);
|
||||
const targetDir = path.resolve(STAGING_DIR, dir);
|
||||
|
||||
if (!fs.existsSync(targetDir)) {
|
||||
fs.mkdirSync(targetDir);
|
||||
}
|
||||
|
||||
for (const file of fs.readdirSync(absDir)) {
|
||||
if (!file.endsWith('.yml')) {
|
||||
if (fs.statSync(path.resolve(absDir, file)).isDirectory()) {
|
||||
copyAndExpand(path.join(dir, file));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.resolve(targetDir, file), yaml.dump(yaml.load(fs.readFileSync(path.resolve(absDir, file), 'utf8')), {
|
||||
noRefs: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.pathExists(STAGING_DIR)) fs.removeSync(STAGING_DIR);
|
||||
copyAndExpand();
|
||||
|
||||
const output = cp.spawnSync(process.env.CIRCLECI_BINARY || 'circleci', ['config', 'pack', STAGING_DIR]);
|
||||
fs.writeFileSync(path.resolve(STAGING_DIR, 'built.yml'), output.stdout.toString());
|
||||
51
.circleci/config/jobs/lint.yml
Normal file
51
.circleci/config/jobs/lint.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: medium
|
||||
steps:
|
||||
- checkout:
|
||||
path: src/electron
|
||||
- run:
|
||||
name: Setup third_party Depot Tools
|
||||
command: |
|
||||
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
|
||||
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
|
||||
echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV
|
||||
- run:
|
||||
name: Download GN Binary
|
||||
command: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
|
||||
cipd ensure -ensure-file - -root . \<<-CIPD
|
||||
\$ServiceURL https://chrome-infra-packages.appspot.com/
|
||||
@Subdir src/buildtools/linux64
|
||||
gn/gn/linux-amd64 $gn_version
|
||||
CIPD
|
||||
|
||||
echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV
|
||||
- run:
|
||||
name: Download clang-format Binary
|
||||
command: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
|
||||
sha1_path='buildtools/linux64/clang-format.sha1'
|
||||
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}"
|
||||
|
||||
download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}"
|
||||
- run:
|
||||
name: Run Lint
|
||||
command: |
|
||||
# gn.py tries to find a gclient root folder starting from the current dir.
|
||||
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
|
||||
touch .gclient
|
||||
# Another option would be to checkout "buildtools" inside the Electron checkout,
|
||||
# but then we would lint its contents (at least gn format), and it doesn't pass it.
|
||||
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
node script/yarn lint
|
||||
- run:
|
||||
name: Run Script Typechecker
|
||||
command: |
|
||||
cd src/electron
|
||||
node script/yarn tsc -p tsconfig.script.json
|
||||
10
.circleci/config/package.json
Normal file
10
.circleci/config/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@electron/circleci-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fs-extra": "^10.1.0",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
}
|
||||
43
.circleci/config/yarn.lock
Normal file
43
.circleci/config/yarn.lock
Normal file
@@ -0,0 +1,43 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
fs-extra@^10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
|
||||
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.10"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
|
||||
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
jsonfile@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
||||
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
|
||||
dependencies:
|
||||
universalify "^2.0.0"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -4,7 +4,7 @@
|
||||
# https://git-scm.com/docs/gitignore
|
||||
|
||||
# Upgrades WG
|
||||
/patches/ @electron/wg-upgrades
|
||||
/patches/ @electron/wg-upgrades @electron/wg-security
|
||||
DEPS @electron/wg-upgrades
|
||||
|
||||
# Releases WG
|
||||
|
||||
20
.github/workflows/semantic.yml
vendored
Normal file
20
.github/workflows/semantic.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: "Check Semantic Commit"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Validate PR Title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: semantic-pull-request
|
||||
uses: amannn/action-semantic-pull-request@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
validateSingleCommit: false
|
||||
17
BUILD.gn
17
BUILD.gn
@@ -187,6 +187,12 @@ action("electron_js2c") {
|
||||
rebase_path(sources, root_build_dir)
|
||||
}
|
||||
|
||||
action("generate_config_gypi") {
|
||||
outputs = [ "$root_gen_dir/config.gypi" ]
|
||||
script = "script/generate-config-gypi.py"
|
||||
args = rebase_path(outputs) + [ target_cpu ]
|
||||
}
|
||||
|
||||
target_gen_default_app_js = "$target_gen_dir/js/default_app"
|
||||
|
||||
typescript_build("default_app_js") {
|
||||
@@ -1225,6 +1231,10 @@ if (is_mac) {
|
||||
if (!is_component_build && is_component_ffmpeg) {
|
||||
configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
deps += [ "//sandbox/linux:chrome_sandbox" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1361,11 +1371,13 @@ dist_zip("electron_dist_zip") {
|
||||
if (is_linux) {
|
||||
data_deps += [ "//sandbox/linux:chrome_sandbox" ]
|
||||
}
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/dist.zip" ]
|
||||
}
|
||||
|
||||
dist_zip("electron_ffmpeg_zip") {
|
||||
data_deps = [ "//third_party/ffmpeg" ]
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/ffmpeg.zip" ]
|
||||
}
|
||||
|
||||
@@ -1383,6 +1395,7 @@ group("electron_chromedriver") {
|
||||
dist_zip("electron_chromedriver_zip") {
|
||||
testonly = true
|
||||
data_deps = electron_chromedriver_deps
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/chromedriver.zip" ]
|
||||
}
|
||||
|
||||
@@ -1401,6 +1414,7 @@ group("electron_mksnapshot") {
|
||||
|
||||
dist_zip("electron_mksnapshot_zip") {
|
||||
data_deps = mksnapshot_deps
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/mksnapshot.zip" ]
|
||||
}
|
||||
|
||||
@@ -1411,6 +1425,7 @@ copy("hunspell_dictionaries") {
|
||||
|
||||
dist_zip("hunspell_dictionaries_zip") {
|
||||
data_deps = [ ":hunspell_dictionaries" ]
|
||||
deps = data_deps
|
||||
flatten = true
|
||||
|
||||
outputs = [ "$root_build_dir/hunspell_dictionaries.zip" ]
|
||||
@@ -1424,6 +1439,7 @@ copy("libcxx_headers") {
|
||||
|
||||
dist_zip("libcxx_headers_zip") {
|
||||
data_deps = [ ":libcxx_headers" ]
|
||||
deps = data_deps
|
||||
flatten = true
|
||||
flatten_relative_to = rebase_path(
|
||||
"$target_gen_dir/electron_libcxx_include/buildtools/third_party/libc++/trunk",
|
||||
@@ -1439,6 +1455,7 @@ copy("libcxxabi_headers") {
|
||||
|
||||
dist_zip("libcxxabi_headers_zip") {
|
||||
data_deps = [ ":libcxxabi_headers" ]
|
||||
deps = data_deps
|
||||
flatten = true
|
||||
flatten_relative_to = rebase_path(
|
||||
"$target_gen_dir/electron_libcxxabi_include/buildtools/third_party/libc++abi/trunk",
|
||||
|
||||
2
DEPS
2
DEPS
@@ -15,7 +15,7 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'94.0.4606.71',
|
||||
'94.0.4606.81',
|
||||
'node_version':
|
||||
'v16.5.0',
|
||||
'nan_version':
|
||||
|
||||
@@ -1 +1 @@
|
||||
15.1.2
|
||||
15.5.7
|
||||
48
appveyor.yml
48
appveyor.yml
@@ -11,7 +11,7 @@
|
||||
# - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}.
|
||||
# Is used in some publishing scripts, but does NOT affect the Electron binary.
|
||||
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value.
|
||||
# - "UPLOAD_TO_S3" Set it to '1' upload a release to the S3 bucket.
|
||||
# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket.
|
||||
# Otherwise the release will be uploaded to the Github Releases.
|
||||
# (The value is only checked if "ELECTRON_RELEASE" is defined.)
|
||||
#
|
||||
@@ -66,6 +66,31 @@ build_script:
|
||||
- mkdir src
|
||||
- update_depot_tools.bat
|
||||
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
|
||||
- ps: >-
|
||||
if (Test-Path 'env:RAW_GOMA_AUTH') {
|
||||
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
|
||||
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
|
||||
}
|
||||
- git clone https://github.com/electron/build-tools.git
|
||||
- cd build-tools
|
||||
- npm install
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||
- cd ..
|
||||
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
|
||||
- ps: >-
|
||||
if (Test-Path 'env:RAW_GOMA_AUTH') {
|
||||
$goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info
|
||||
if ($goma_login -eq 'Login as Fermi Planck') {
|
||||
Write-warning "Goma authentication is correct";
|
||||
} else {
|
||||
Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token.";
|
||||
$host.SetShouldExit(1)
|
||||
}
|
||||
}
|
||||
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -ne 'release') {
|
||||
@@ -129,21 +154,6 @@ build_script:
|
||||
Write-warning "Failed to add third_party\angle\.git; continuing anyway"
|
||||
}
|
||||
}
|
||||
- ps: >-
|
||||
if (Test-Path 'env:RAW_GOMA_AUTH') {
|
||||
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
|
||||
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
|
||||
}
|
||||
- git clone https://github.com/electron/build-tools.git
|
||||
- cd build-tools
|
||||
- npm install
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||
- cd ..
|
||||
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
|
||||
- cd src
|
||||
- set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn
|
||||
- gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% "
|
||||
@@ -221,9 +231,9 @@ deploy_script:
|
||||
- cd electron
|
||||
- ps: >-
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
if (Test-Path Env:\UPLOAD_TO_S3) {
|
||||
Write-Output "Uploading Electron release distribution to s3"
|
||||
& python script\release\uploaders\upload.py --verbose --upload_to_s3
|
||||
if (Test-Path Env:\UPLOAD_TO_STORAGE) {
|
||||
Write-Output "Uploading Electron release distribution to azure"
|
||||
& python script\release\uploaders\upload.py --verbose --upload_to_storage
|
||||
} else {
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python script\release\uploaders\upload.py --verbose
|
||||
|
||||
@@ -16,6 +16,9 @@ proprietary_codecs = true
|
||||
ffmpeg_branding = "Chrome"
|
||||
|
||||
enable_basic_printing = true
|
||||
|
||||
# Removes DLLs from the build, which are only meant to be used for Chromium development.
|
||||
# See https://github.com/electron/electron/pull/17985
|
||||
angle_enable_vulkan_validation_layers = false
|
||||
dawn_enable_vulkan_validation_layers = false
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from __future__ import with_statement
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import contextlib
|
||||
import sys
|
||||
import os
|
||||
import optparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
@@ -33,36 +36,56 @@ def calculate_hash(root):
|
||||
return CalculateHash('.', None)
|
||||
|
||||
def windows_installed_software():
|
||||
import win32com.client
|
||||
strComputer = "."
|
||||
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||
objSWbemServices = objWMIService.ConnectServer(strComputer, "root\cimv2")
|
||||
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
|
||||
items = []
|
||||
powershell_command = [
|
||||
"Get-CimInstance",
|
||||
"-Namespace",
|
||||
"root\cimv2",
|
||||
"-Class",
|
||||
"Win32_product",
|
||||
"|",
|
||||
"Select",
|
||||
"vendor,",
|
||||
"description,",
|
||||
"@{l='install_location';e='InstallLocation'},",
|
||||
"@{l='install_date';e='InstallDate'},",
|
||||
"@{l='install_date_2';e='InstallDate2'},",
|
||||
"caption,",
|
||||
"version,",
|
||||
"name,",
|
||||
"@{l='sku_number';e='SKUNumber'}",
|
||||
"|",
|
||||
"ConvertTo-Json",
|
||||
]
|
||||
|
||||
for objItem in colItems:
|
||||
item = {}
|
||||
if objItem.Caption:
|
||||
item['caption'] = objItem.Caption
|
||||
if objItem.Caption:
|
||||
item['description'] = objItem.Description
|
||||
if objItem.InstallDate:
|
||||
item['install_date'] = objItem.InstallDate
|
||||
if objItem.InstallDate2:
|
||||
item['install_date_2'] = objItem.InstallDate2
|
||||
if objItem.InstallLocation:
|
||||
item['install_location'] = objItem.InstallLocation
|
||||
if objItem.Name:
|
||||
item['name'] = objItem.Name
|
||||
if objItem.SKUNumber:
|
||||
item['sku_number'] = objItem.SKUNumber
|
||||
if objItem.Vendor:
|
||||
item['vendor'] = objItem.Vendor
|
||||
if objItem.Version:
|
||||
item['version'] = objItem.Version
|
||||
items.append(item)
|
||||
proc = subprocess.Popen(
|
||||
["powershell.exe", "-Command", "-"],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
|
||||
return items
|
||||
stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8"))
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError("Failed to get list of installed software")
|
||||
|
||||
# On AppVeyor there's other output related to PSReadline,
|
||||
# so grab only the JSON output and ignore everything else
|
||||
json_match = re.match(
|
||||
r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL
|
||||
)
|
||||
|
||||
if not json_match:
|
||||
raise RuntimeError(
|
||||
"Couldn't find JSON output for list of installed software"
|
||||
)
|
||||
|
||||
# Filter out missing keys
|
||||
return list(
|
||||
map(
|
||||
lambda info: {k: info[k] for k in info if info[k]},
|
||||
json.loads(json_match.group(1)),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def windows_profile():
|
||||
@@ -89,7 +112,7 @@ def windows_profile():
|
||||
|
||||
def main(options):
|
||||
if sys.platform == 'win32':
|
||||
with open(options.output_json, 'wb') as f:
|
||||
with open(options.output_json, 'w') as f:
|
||||
json.dump(windows_profile(), f)
|
||||
else:
|
||||
raise OSError("Unsupported OS")
|
||||
|
||||
@@ -59,10 +59,9 @@ an issue:
|
||||
* [Testing and Debugging](tutorial/application-debugging.md)
|
||||
* [Debugging the Main Process](tutorial/debugging-main-process.md)
|
||||
* [Debugging with Visual Studio Code](tutorial/debugging-vscode.md)
|
||||
* [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
|
||||
* [DevTools Extension](tutorial/devtools-extension.md)
|
||||
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
|
||||
* [Automated Testing](tutorial/automated-testing.md)
|
||||
* [REPL](tutorial/repl.md)
|
||||
* [Distribution](tutorial/application-distribution.md)
|
||||
* [Supported Platforms](tutorial/support.md#supported-platforms)
|
||||
|
||||
@@ -36,10 +36,10 @@ Returns:
|
||||
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the `NSUserNotification` or information from
|
||||
[`UNNotificationResponse`](structures/notification-response.md) that was used to open the
|
||||
application, if it was launched from Notification Center. You can also call
|
||||
`app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
|
||||
or information from [`UNNotificationResponse`](https://developer.apple.com/documentation/usernotifications/unnotificationresponse)
|
||||
that was used to open the application, if it was launched from Notification Center.
|
||||
You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
to get a Promise that is fulfilled when Electron is initialized.
|
||||
|
||||
### Event: 'window-all-closed'
|
||||
|
||||
@@ -17,10 +17,11 @@ win.loadURL('https://github.com')
|
||||
win.loadFile('index.html')
|
||||
```
|
||||
|
||||
## Frameless window
|
||||
## Window customization
|
||||
|
||||
To create a window without chrome, or a transparent window in arbitrary shape,
|
||||
you can use the [Frameless Window](frameless-window.md) API.
|
||||
The `BrowserWindow` class exposes various ways to modify the look and behavior of
|
||||
your app's windows. For more details, see the [Window Customization](../tutorial/window-customization.md)
|
||||
tutorial.
|
||||
|
||||
## Showing the window gracefully
|
||||
|
||||
@@ -184,7 +185,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
`true`.
|
||||
* `paintWhenInitiallyHidden` Boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`.
|
||||
* `frame` Boolean (optional) - Specify `false` to create a
|
||||
[Frameless Window](frameless-window.md). Default is `true`.
|
||||
[frameless window](../tutorial/window-customization.md#create-frameless-windows). Default is `true`.
|
||||
* `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
|
||||
* `modal` Boolean (optional) - Whether this is a modal window. This only works when the
|
||||
window is a child window. Default is `false`.
|
||||
@@ -206,7 +207,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS.
|
||||
* `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on
|
||||
some GTK+3 desktop environments. Default is `false`.
|
||||
* `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md#transparent-window).
|
||||
* `transparent` Boolean (optional) - Makes the window [transparent](../tutorial/window-customization.md#create-transparent-windows).
|
||||
Default is `false`. On Windows, does not work unless the window is frameless.
|
||||
* `type` String (optional) - The type of window, default is normal window. See more about
|
||||
this below.
|
||||
@@ -393,6 +394,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`.
|
||||
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels. Default is system height.
|
||||
|
||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||
@@ -998,7 +1000,7 @@ APIs like `win.setSize`.
|
||||
is `true`). Default is `#FFF` (white).
|
||||
|
||||
Sets the background color of the window. See [Setting
|
||||
`backgroundColor`](#setting-backgroundcolor).
|
||||
`backgroundColor`](#setting-the-backgroundcolor-property).
|
||||
|
||||
#### `win.previewFile(path[, displayName])` _macOS_
|
||||
|
||||
@@ -1043,7 +1045,7 @@ Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `
|
||||
#### `win.getBackgroundColor()`
|
||||
|
||||
Returns `String` - Gets the background color of the window. See [Setting
|
||||
`backgroundColor`](#setting-backgroundcolor).
|
||||
`backgroundColor`](#setting-the-backgroundcolor-property).
|
||||
|
||||
#### `win.setContentBounds(bounds[, animate])`
|
||||
|
||||
@@ -1696,7 +1698,7 @@ current window into a top-level window.
|
||||
|
||||
#### `win.getParentWindow()`
|
||||
|
||||
Returns `BrowserWindow` - The parent window.
|
||||
Returns `BrowserWindow | null` - The parent window or `null` if there is no parent.
|
||||
|
||||
#### `win.getChildWindows()`
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ Writes `markup` to the clipboard.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeHTML('<b>Hi</b')
|
||||
clipboard.writeHTML('<b>Hi</b>')
|
||||
```
|
||||
|
||||
### `clipboard.readImage([type])`
|
||||
@@ -197,7 +197,7 @@ Returns `Boolean` - Whether the clipboard supports the specified `format`.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const hasFormat = clipboard.has('<p>selection</p>')
|
||||
const hasFormat = clipboard.has('public/utf8-plain-text')
|
||||
console.log(hasFormat)
|
||||
// 'true' or 'false'
|
||||
```
|
||||
|
||||
@@ -53,3 +53,12 @@ Returns `Boolean` - Whether the command-line switch is present.
|
||||
Returns `String` - The command-line switch value.
|
||||
|
||||
**Note:** When the switch is not present or has no value, it returns empty string.
|
||||
|
||||
#### `commandLine.removeSwitch(switch)`
|
||||
|
||||
* `switch` String - A command-line switch
|
||||
|
||||
Removes the specified switch from Chromium's command line.
|
||||
|
||||
**Note:** This will not affect `process.argv`. The intended usage of this function is to
|
||||
control Chromium's behavior.
|
||||
|
||||
@@ -102,8 +102,8 @@ has been included below for completeness:
|
||||
| `Boolean` | Simple | ✅ | ✅ | N/A |
|
||||
| `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. |
|
||||
| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type |
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context |
|
||||
| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. |
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) |
|
||||
| `Promise` | Complex | ✅ | ✅ | N/A
|
||||
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
|
||||
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
|
||||
| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. |
|
||||
|
||||
@@ -122,7 +122,7 @@ Prints Chromium's internal logging to the console.
|
||||
|
||||
Setting this variable is the same as passing `--enable-logging`
|
||||
on the command line. For more info, see `--enable-logging` in [command-line
|
||||
switches](./command-line-switches.md#enable-loggingfile).
|
||||
switches](./command-line-switches.md#--enable-loggingfile).
|
||||
|
||||
### `ELECTRON_LOG_FILE`
|
||||
|
||||
@@ -130,7 +130,7 @@ Sets the file destination for Chromium's internal logging.
|
||||
|
||||
Setting this variable is the same as passing `--log-file`
|
||||
on the command line. For more info, see `--log-file` in [command-line
|
||||
switches](./command-line-switches.md#log-filepath).
|
||||
switches](./command-line-switches.md#--log-filepath).
|
||||
|
||||
### `ELECTRON_DEBUG_DRAG_REGIONS`
|
||||
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
# Frameless Window
|
||||
|
||||
> Open a window without toolbars, borders, or other graphical "chrome".
|
||||
|
||||
A frameless window is a window that has no
|
||||
[chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of
|
||||
the window, like toolbars, that are not a part of the web page. These are
|
||||
options on the [`BrowserWindow`](browser-window.md) class.
|
||||
|
||||
## Create a frameless window
|
||||
|
||||
To create a frameless window, you need to set `frame` to `false` in
|
||||
[BrowserWindow](browser-window.md)'s `options`:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Alternatives
|
||||
|
||||
There's an alternative way to specify a chromeless window on macOS and Windows.
|
||||
Instead of setting `frame` to `false` which disables both the titlebar and window controls,
|
||||
you may want to have the title bar hidden and your content extend to the full window size,
|
||||
yet still preserve the window controls ("traffic lights" on macOS) for standard window actions.
|
||||
You can do so by specifying the `titleBarStyle` option:
|
||||
|
||||
#### `hidden`
|
||||
|
||||
Results in a hidden title bar and a full size content window. On macOS, the title bar still has the standard window controls (“traffic lights”) in the top left.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hidden' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Alternatives on macOS
|
||||
|
||||
#### `hiddenInset`
|
||||
|
||||
Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
#### `customButtonsOnHover`
|
||||
|
||||
Uses custom drawn close, and miniaturize buttons that display
|
||||
when hovering in the top left of the window. The fullscreen button
|
||||
is not available due to restrictions of frameless windows as they
|
||||
interface with Apple's macOS window masks. These custom buttons prevent
|
||||
issues with mouse events that occur with the standard window toolbar buttons.
|
||||
This option is only applicable for frameless windows.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
## Windows Control Overlay
|
||||
|
||||
When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS, using one of the `titleBarStyle`s as described above so
|
||||
that the traffic lights are visible, or using `titleBarStyle: hidden` on Windows, you can access the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and
|
||||
[CSS Environment Variables][overlay-css-env-vars] by setting the `titleBarOverlay` option to true. Specifying `true` will result in an overlay with default system colors.
|
||||
|
||||
On Windows, you can also specify the color of the overlay and its symbols by setting `titleBarOverlay` to an object with the options `color` and `symbolColor`. If an option is not specified, the color will default to its system color for the window control buttons:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: true
|
||||
})
|
||||
win.show()
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: {
|
||||
color: '#2f3241',
|
||||
symbolColor: '#74b1be'
|
||||
}
|
||||
})
|
||||
win.show()
|
||||
```
|
||||
|
||||
## Transparent window
|
||||
|
||||
By setting the `transparent` option to `true`, you can also make the frameless
|
||||
window transparent:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ transparent: true, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
* You can not click through the transparent area. We are going to introduce an
|
||||
API to set window shape to solve this, see
|
||||
[our issue](https://github.com/electron/electron/issues/1335) for details.
|
||||
* Transparent windows are not resizable. Setting `resizable` to `true` may make
|
||||
a transparent window stop working on some platforms.
|
||||
* The `blur` filter only applies to the web page, so there is no way to apply
|
||||
blur effect to the content below the window (i.e. other applications open on
|
||||
the user's system).
|
||||
* The window will not be transparent when DevTools is opened.
|
||||
* On Windows operating systems,
|
||||
* transparent windows will not work when DWM is
|
||||
disabled.
|
||||
* transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on [this pull request](https://github.com/electron/electron/pull/28207).
|
||||
* On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in
|
||||
the command line to disable GPU and allow ARGB to make transparent window,
|
||||
this is caused by an upstream bug that [alpha channel doesn't work on some
|
||||
NVidia drivers](https://bugs.chromium.org/p/chromium/issues/detail?id=369209) on
|
||||
Linux.
|
||||
* On Mac, the native window shadow will not be shown on a transparent window.
|
||||
|
||||
## Click-through window
|
||||
|
||||
To create a click-through window, i.e. making the window ignore all mouse
|
||||
events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
|
||||
API:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
win.setIgnoreMouseEvents(true)
|
||||
```
|
||||
|
||||
### Forwarding
|
||||
|
||||
Ignoring mouse messages makes the web page oblivious to mouse movement, meaning
|
||||
that mouse movement events will not be emitted. On Windows operating systems an
|
||||
optional parameter can be used to forward mouse move messages to the web page,
|
||||
allowing events such as `mouseleave` to be emitted:
|
||||
|
||||
```javascript
|
||||
const { ipcRenderer } = require('electron')
|
||||
const el = document.getElementById('clickThroughElement')
|
||||
el.addEventListener('mouseenter', () => {
|
||||
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
|
||||
})
|
||||
el.addEventListener('mouseleave', () => {
|
||||
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)
|
||||
})
|
||||
```
|
||||
|
||||
This makes the web page click-through when over `el`, and returns to normal
|
||||
outside it.
|
||||
|
||||
## Draggable region
|
||||
|
||||
By default, the frameless window is non-draggable. Apps need to specify
|
||||
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
|
||||
(like the OS's standard titlebar), and apps can also use
|
||||
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
|
||||
draggable region. Note that only rectangular shapes are currently supported.
|
||||
|
||||
Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [GitHub issue](https://github.com/electron/electron/issues/3647) for more information including a workaround.
|
||||
|
||||
To make the whole window draggable, you can add `-webkit-app-region: drag` as
|
||||
`body`'s style:
|
||||
|
||||
```html
|
||||
<body style="-webkit-app-region: drag">
|
||||
</body>
|
||||
```
|
||||
|
||||
And note that if you have made the whole window draggable, you must also mark
|
||||
buttons as non-draggable, otherwise it would be impossible for users to click on
|
||||
them:
|
||||
|
||||
```css
|
||||
button {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
```
|
||||
|
||||
If you're only setting a custom titlebar as draggable, you also need to make all
|
||||
buttons in titlebar non-draggable.
|
||||
|
||||
## Text selection
|
||||
|
||||
In a frameless window the dragging behavior may conflict with selecting text.
|
||||
For example, when you drag the titlebar you may accidentally select the text on
|
||||
the titlebar. To prevent this, you need to disable text selection within a
|
||||
draggable area like this:
|
||||
|
||||
```css
|
||||
.titlebar {
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
```
|
||||
|
||||
## Context menu
|
||||
|
||||
On some platforms, the draggable area will be treated as a non-client frame, so
|
||||
when you right click on it a system menu will pop up. To make the context menu
|
||||
behave correctly on all platforms you should never use a custom context menu on
|
||||
draggable areas.
|
||||
|
||||
[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options
|
||||
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
|
||||
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
|
||||
@@ -67,3 +67,8 @@ or is being instructed to show a high-contrast UI.
|
||||
|
||||
A `Boolean` for if the OS / Chromium currently has an inverted color scheme
|
||||
or is being instructed to use an inverted color scheme.
|
||||
|
||||
### `nativeTheme.inForcedColorsMode` _Windows_ _Readonly_
|
||||
|
||||
A `boolean` indicating whether Chromium is in forced colors mode, controlled by system accessibility settings.
|
||||
Currently, Windows high contrast is the only system setting that triggers forced colors mode.
|
||||
|
||||
@@ -178,7 +178,6 @@ Returns an object with V8 heap statistics. Note that all statistics are reported
|
||||
Returns `Object`:
|
||||
|
||||
* `allocated` Integer - Size of all allocated objects in Kilobytes.
|
||||
* `marked` Integer - Size of all marked objects in Kilobytes.
|
||||
* `total` Integer - Total allocated space in Kilobytes.
|
||||
|
||||
Returns an object with Blink memory information.
|
||||
|
||||
@@ -18,9 +18,9 @@ The `safeStorage` module has the following methods:
|
||||
|
||||
Returns `Boolean` - Whether encryption is available.
|
||||
|
||||
On Linux, returns true if the secret key is
|
||||
available. On MacOS, returns true if Keychain is available.
|
||||
On Windows, returns true with no other preconditions.
|
||||
On Linux, returns true if the app has emitted the `ready` event and the secret key is available.
|
||||
On MacOS, returns true if Keychain is available.
|
||||
On Windows, returns true once the app has emitted the `ready` event.
|
||||
|
||||
### `safeStorage.encryptString(plainText)`
|
||||
|
||||
|
||||
@@ -297,6 +297,35 @@ app.whenReady().then(() => {
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'serial') {
|
||||
// Add logic here to determine if permission should be given to allow serial selection
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'serial') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.serial.requestPort` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedPort = portList.find((device) => {
|
||||
@@ -588,6 +617,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `permissionGranted` Boolean - Allow or deny the permission.
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
* `externalURL` String (optional) - The url of the `openExternal` request.
|
||||
* `securityOrigin` String (optional) - The security origin of the `media` request.
|
||||
* `mediaTypes` String[] (optional) - The types of media access being requested, elements can be `video`
|
||||
or `audio`
|
||||
* `requestingUrl` String - The last URL the requesting frame loaded
|
||||
@@ -646,9 +676,9 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
|
||||
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `details` Object
|
||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid`.
|
||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid` or `serial`.
|
||||
* `origin` String - The origin URL of the device permission check.
|
||||
* `device` [HIDDevice](structures/hid-device.md) - the device that permission is being requested for.
|
||||
* `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for.
|
||||
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
|
||||
|
||||
Sets the handler which can be used to respond to device permission checks for the `session`.
|
||||
@@ -673,6 +703,8 @@ app.whenReady().then(() => {
|
||||
if (permission === 'hid') {
|
||||
// Add logic here to determine if permission should be given to allow HID selection
|
||||
return true
|
||||
} else if (permission === 'serial') {
|
||||
// Add logic here to determine if permission should be given to allow serial port selection
|
||||
}
|
||||
return false
|
||||
})
|
||||
@@ -693,6 +725,11 @@ app.whenReady().then(() => {
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
} else if (details.deviceType === 'serial') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -736,6 +736,8 @@ first available device will be selected. `callback` should be called with
|
||||
`deviceId` to be selected, passing empty string to `callback` will
|
||||
cancel the request.
|
||||
|
||||
If no event listener is added for this event, all bluetooth requests will be cancelled.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
@@ -1494,8 +1496,8 @@ win.loadURL('http://github.com')
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
@@ -1610,7 +1612,7 @@ app.whenReady().then(() => {
|
||||
|
||||
* `options` Object (optional)
|
||||
* `mode` String - Opens the devtools with specified dock state, can be
|
||||
`right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
|
||||
`left`, `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
|
||||
In `undocked` mode it's possible to dock back. In `detach` mode it's not.
|
||||
* `activate` Boolean (optional) - Whether to bring the opened devtools window
|
||||
to the foreground. The default is `true`.
|
||||
@@ -1838,7 +1840,7 @@ the cursor when dragging.
|
||||
|
||||
#### `contents.savePage(fullPath, saveType)`
|
||||
|
||||
* `fullPath` String - The full file path.
|
||||
* `fullPath` String - The absolute file path.
|
||||
* `saveType` String - Specify the save type.
|
||||
* `HTMLOnly` - Save only the HTML of the page.
|
||||
* `HTMLComplete` - Save complete-html page.
|
||||
|
||||
@@ -64,6 +64,9 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
|
||||
`features` will be passed to any registered `webContents`'s
|
||||
`did-create-window` event handler in the `options` argument.
|
||||
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
|
||||
* When opening `about:blank`, the child window's `WebPreferences` will be copied
|
||||
from the parent window, and there is no way to override it because Chromium
|
||||
skips browser side navigation in this case.
|
||||
|
||||
To customize or cancel the creation of the window, you can optionally set an
|
||||
override handler with `webContents.setWindowOpenHandler()` from the main
|
||||
|
||||
@@ -12,6 +12,18 @@ This document uses the following convention to categorize breaking changes:
|
||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||
|
||||
## Planned Breaking API Changes (15.0)
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
|
||||
Prior to Electron 15, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
## Planned Breaking API Changes (14.0)
|
||||
|
||||
### Removed: `remote` module
|
||||
@@ -62,16 +74,6 @@ ensure your code works with this property enabled. It has been enabled by defau
|
||||
|
||||
You will be affected by this change if you use either `webFrame.executeJavaScript` or `webFrame.executeJavaScriptInIsolatedWorld`. You will need to ensure that values returned by either of those methods are supported by the [Context Bridge API](api/context-bridge.md#parameter--error--return-type-support) as these methods use the same value passing semantics.
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
|
||||
Prior to Electron 14, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
### Removed: BrowserWindowConstructorOptions inheriting from parent windows
|
||||
|
||||
Prior to Electron 14, windows opened with `window.open` would inherit
|
||||
|
||||
@@ -43,8 +43,9 @@ SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\sym
|
||||
|
||||
## Using the symbol server in Visual Studio
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
## Troubleshooting: Symbols will not load
|
||||
|
||||
|
||||
@@ -59,8 +59,9 @@
|
||||
|
||||
<p>
|
||||
For more details, see the
|
||||
<a href="https://electronjs.org/docs/api/frameless-window/">
|
||||
Frameless Window
|
||||
<a href="https://electronjs.org/docs/tutorial/window-customization/">
|
||||
Window Customization
|
||||
|
||||
</a>
|
||||
documentation.
|
||||
</p>
|
||||
|
||||
BIN
docs/images/vs-options-debugging-symbols.png
Normal file
BIN
docs/images/vs-options-debugging-symbols.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/images/vs-tools-options.png
Normal file
BIN
docs/images/vs-tools-options.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/images/windows-progress-bar.png
Normal file
BIN
docs/images/windows-progress-bar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -1,48 +1,7 @@
|
||||
# Accessibility
|
||||
|
||||
Making accessible applications is important and we're happy to provide
|
||||
functionality to [Devtron][devtron] and [Spectron][spectron] that gives
|
||||
developers the opportunity to make their apps better for everyone.
|
||||
|
||||
---
|
||||
|
||||
Accessibility concerns in Electron applications are similar to those of
|
||||
websites because they're both ultimately HTML. With Electron apps, however,
|
||||
you can't use the online resources for accessibility audits because your app
|
||||
doesn't have a URL to point the auditor to.
|
||||
|
||||
These features bring those auditing tools to your Electron app. You can
|
||||
choose to add audits to your tests with Spectron or use them within DevTools
|
||||
with Devtron. Read on for a summary of the tools.
|
||||
|
||||
## Spectron
|
||||
|
||||
In the testing framework Spectron, you can now audit each window and `<webview>`
|
||||
tag in your application. For example:
|
||||
|
||||
```javascript
|
||||
app.client.auditAccessibility().then(function (audit) {
|
||||
if (audit.failed) {
|
||||
console.error(audit.message)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You can read more about this feature in [Spectron's documentation][spectron-a11y].
|
||||
|
||||
## Devtron
|
||||
|
||||
In Devtron, there is an accessibility tab which will allow you to audit a
|
||||
page in your app, sort and filter the results.
|
||||
|
||||
![devtron screenshot][devtron-screenshot]
|
||||
|
||||
Both of these tools are using the [Accessibility Developer Tools][a11y-devtools]
|
||||
library built by Google for Chrome. You can learn more about the accessibility
|
||||
audit rules this library uses on that [repository's wiki][a11y-devtools-wiki].
|
||||
|
||||
If you know of other great accessibility tools for Electron, add them to the
|
||||
accessibility documentation with a pull request.
|
||||
websites because they're both ultimately HTML.
|
||||
|
||||
## Manually enabling accessibility features
|
||||
|
||||
@@ -84,10 +43,6 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility");
|
||||
}
|
||||
```
|
||||
|
||||
[devtron]: https://electronjs.org/devtron
|
||||
[devtron-screenshot]: https://cloud.githubusercontent.com/assets/1305617/17156618/9f9bcd72-533f-11e6-880d-389115f40a2a.png
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
[spectron-a11y]: https://github.com/electron/spectron#accessibility-testing
|
||||
[a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology
|
||||
[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools
|
||||
[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
|
||||
|
||||
@@ -56,7 +56,7 @@ will then be your distribution to deliver to users.
|
||||
|
||||
### With an app source code archive
|
||||
|
||||
Instead of from shipping your app by copying all of its source files, you can
|
||||
Instead of shipping your app by copying all of its source files, you can
|
||||
package your app into an [asar] archive to improve the performance of reading
|
||||
files on platforms like Windows, if you are not already using a bundler such
|
||||
as Parcel or Webpack.
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
# Automated Testing with a Custom Driver
|
||||
|
||||
To write automated tests for your Electron app, you will need a way to "drive" your application. [Spectron](https://electronjs.org/spectron) is a commonly-used solution which lets you emulate user actions via [WebDriver](https://webdriver.io/). However, it's also possible to write your own custom driver using node's builtin IPC-over-STDIO. The benefit of a custom driver is that it tends to require less overhead than Spectron, and lets you expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [child_process](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js [process](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js
|
||||
// listen for IPC messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more high-level functions. Here is an example of how you can do this:
|
||||
|
||||
```js
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the app, you'd need to write a simple handler for the RPC calls:
|
||||
|
||||
```js
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
|
||||
async function onMessage ({ msgId, cmd, args }) {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your test-driver as follows:
|
||||
|
||||
```js
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
265
docs/tutorial/automated-testing.md
Normal file
265
docs/tutorial/automated-testing.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# Automated Testing
|
||||
|
||||
Test automation is an efficient way of validating that your application code works as intended.
|
||||
While Electron doesn't actively maintain its own testing solution, this guide will go over a couple
|
||||
ways you can run end-to-end automated tests on your Electron app.
|
||||
|
||||
## Using the WebDriver interface
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
There are a few ways that you can set up testing using WebDriver.
|
||||
|
||||
### With WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) (WDIO) is a test automation framework that provides a
|
||||
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
|
||||
(e.g. reporter and services) that can help you put together your test setup.
|
||||
|
||||
#### Install the testrunner
|
||||
|
||||
First you need to run the WebdriverIO starter toolkit in your project root directory:
|
||||
|
||||
```sh npm2yarn
|
||||
npx wdio . --yes
|
||||
```
|
||||
|
||||
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
|
||||
|
||||
#### Connect WDIO to your Electron app
|
||||
|
||||
Update the capabilities in your configuration file to point to your Electron app binary:
|
||||
|
||||
```javascript title='wdio.conf.js'
|
||||
export.config = {
|
||||
// ...
|
||||
capabilities: [{
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Run your tests
|
||||
|
||||
To run your tests:
|
||||
|
||||
```sh
|
||||
$ npx wdio run wdio.conf.js
|
||||
```
|
||||
|
||||
[chrome-driver]: https://sites.google.com/chromium.org/driver/
|
||||
|
||||
### With Selenium
|
||||
|
||||
[Selenium](https://www.selenium.dev/) is a web automation framework that
|
||||
exposes bindings to WebDriver APIs in many languages. Their Node.js bindings
|
||||
are available under the `selenium-webdriver` package on NPM.
|
||||
|
||||
#### Run a ChromeDriver server
|
||||
|
||||
In order to use Selenium with Electron, you need to download the `electron-chromedriver`
|
||||
binary, and run it:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron-chromedriver
|
||||
./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later.
|
||||
|
||||
#### Connect Selenium to ChromeDriver
|
||||
|
||||
Next, install Selenium into your project:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev selenium-webdriver
|
||||
```
|
||||
|
||||
Usage of `selenium-webdriver` with Electron is the same as with
|
||||
normal websites, except that you have to manually specify how to connect
|
||||
ChromeDriver and where to find the binary of your Electron app:
|
||||
|
||||
```js title='test.js'
|
||||
const webdriver = require('selenium-webdriver')
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by ChromeDriver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Using a custom test driver
|
||||
|
||||
It's also possible to write your own custom driver using Node.js' built-in IPC-over-STDIO.
|
||||
Custom test drivers require you to write additional app code, but have lower overhead and let you
|
||||
expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API.
|
||||
The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js title='testDriver.js'
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js
|
||||
[`process`](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js title='main.js'
|
||||
// listen for messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send a message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more
|
||||
high-level functions. Here is an example of how you can do this. Let's start by creating
|
||||
a `TestDriver` class:
|
||||
|
||||
```js title='testDriver.js'
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { TestDriver };
|
||||
```
|
||||
|
||||
In your app code, can then write a simple handler to receive RPC calls:
|
||||
|
||||
```js title='main.js'
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your `TestDriver` class with the test automation
|
||||
framework of your choosing. The following example uses
|
||||
[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest
|
||||
or Mocha would work as well:
|
||||
|
||||
```js title='test.js'
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
const { TestDriver } = require('./testDriver')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
@@ -84,13 +84,22 @@ There are several additional APIs for working with the Web Serial API:
|
||||
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
|
||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||
`navigator.serial.requestPort` process.
|
||||
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
can be used to provide default permissioning to devices without first calling
|
||||
for permission to devices via `navigator.serial.requestPort`. Additionally,
|
||||
the default behavior of Electron is to store granted device permision through
|
||||
the lifetime of the corresponding WebContents. If longer term storage is
|
||||
needed, a developer can store granted device permissions (eg when handling
|
||||
the `select-serial-port` event) and then read from that storage with
|
||||
`setDevicePermissionHandler`.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable serial access for specific origins.
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
the first available Arduino Uno serial device (if connected) through
|
||||
serial devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through
|
||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||
when the `Test Web Serial` button is clicked.
|
||||
|
||||
|
||||
@@ -2,43 +2,31 @@
|
||||
|
||||
> A detailed look at our versioning policy and implementation.
|
||||
|
||||
As of version 2.0.0, Electron follows [SemVer](#semver). The following command will install the most recent stable build of Electron:
|
||||
As of version 2.0.0, Electron follows the [SemVer](#semver) spec. The following command will install the most recent stable build of Electron:
|
||||
|
||||
```sh
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron
|
||||
```
|
||||
|
||||
To update an existing project to use the latest stable version:
|
||||
|
||||
```sh
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron@latest
|
||||
```
|
||||
|
||||
## Version 1.x
|
||||
|
||||
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Stride, Teams, Skype, VS Code, Atom, and Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
|
||||
|
||||
Here is an example of the 1.x strategy:
|
||||
|
||||

|
||||
|
||||
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
|
||||
|
||||
## Version 2.0 and Beyond
|
||||
## Versioning scheme
|
||||
|
||||
There are several major changes from our 1.x strategy outlined below. Each change is intended to satisfy the needs and priorities of developers/maintainers and app developers.
|
||||
|
||||
1. Strict use of SemVer
|
||||
1. Strict use of the [SemVer](#semver) spec
|
||||
2. Introduction of semver-compliant `-beta` tags
|
||||
3. Introduction of [conventional commit messages](https://conventionalcommits.org/)
|
||||
4. Well-defined stabilization branches
|
||||
5. The `master` branch is versionless; only stabilization branches contain version information
|
||||
5. The `main` branch is versionless; only stabilization branches contain version information
|
||||
|
||||
We will cover in detail how git branching works, how npm tagging works, what developers should expect to see, and how one can backport changes.
|
||||
|
||||
# SemVer
|
||||
|
||||
From 2.0 onward, Electron will follow SemVer.
|
||||
## SemVer
|
||||
|
||||
Below is a table explicitly mapping types of changes to their corresponding category of SemVer (e.g. Major, Minor, Patch).
|
||||
|
||||
@@ -48,22 +36,25 @@ Below is a table explicitly mapping types of changes to their corresponding cate
|
||||
| Node.js major version updates | Node.js minor version updates | Node.js patch version updates |
|
||||
| Chromium version updates | | fix-related chromium patches |
|
||||
|
||||
For more information, see the [Semantic Versioning 2.0.0](https://semver.org/) spec.
|
||||
|
||||
Note that most Chromium updates will be considered breaking. Fixes that can be backported will likely be cherry-picked as patches.
|
||||
|
||||
# Stabilization Branches
|
||||
## Stabilization branches
|
||||
|
||||
Stabilization branches are branches that run parallel to master, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to master.
|
||||
Stabilization branches are branches that run parallel to `main`, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to `main`.
|
||||
|
||||

|
||||
|
||||
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`
|
||||
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`.
|
||||
|
||||
We allow for multiple stabilization branches to exist simultaneously, one for each supported version. For more details on which versions are supported, see our [Electron Release Timelines](./electron-timelines.md) doc.
|
||||
|
||||
We allow for multiple stabilization branches to exist simultaneously, and intend to support at least two in parallel at all times, backporting security fixes as necessary.
|
||||

|
||||
|
||||
Older lines will not be supported by GitHub, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
|
||||
Older lines will not be supported by the Electron project, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
|
||||
|
||||
# Beta Releases and Bug Fixes
|
||||
## Beta releases and bug fixes
|
||||
|
||||
Developers want to know which releases are _safe_ to use. Even seemingly innocent features can introduce regressions in complex applications. At the same time, locking to a fixed version is dangerous because you’re ignoring security patches and bug fixes that may have come out since your version. Our goal is to allow the following standard semver ranges in `package.json` :
|
||||
|
||||
@@ -116,15 +107,7 @@ A few examples of how various SemVer ranges will pick up new releases:
|
||||
|
||||

|
||||
|
||||
# Missing Features: Alphas
|
||||
|
||||
Our strategy has a few tradeoffs, which for now we feel are appropriate. Most importantly that new features in master may take a while before reaching a stable release line. If you want to try a new feature immediately, you will have to build Electron yourself.
|
||||
|
||||
As a future consideration, we may introduce one or both of the following:
|
||||
|
||||
* alpha releases that have looser stability constraints to betas; for example it would be allowable to admit new features while a stability channel is in _alpha_
|
||||
|
||||
# Feature Flags
|
||||
## Feature flags
|
||||
|
||||
Feature flags are a common practice in Chromium, and are well-established in the web-development ecosystem. In the context of Electron, a feature flag or **soft branch** must have the following properties:
|
||||
|
||||
@@ -132,20 +115,29 @@ Feature flags are a common practice in Chromium, and are well-established in the
|
||||
* it completely segments new and old code paths; refactoring old code to support a new feature _violates_ the feature-flag contract
|
||||
* feature flags are eventually removed after the feature is released
|
||||
|
||||
# Semantic Commits
|
||||
## Semantic commits
|
||||
|
||||
We seek to increase clarity at all levels of the update and releases process. Starting with `2.0.0` we will require pull requests adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
|
||||
All pull requests must adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
|
||||
|
||||
* Commits that would result in a SemVer **major** bump must start their body with `BREAKING CHANGE:`.
|
||||
* Commits that would result in a SemVer **minor** bump must start with `feat:`.
|
||||
* Commits that would result in a SemVer **patch** bump must start with `fix:`.
|
||||
|
||||
* We allow squashing of commits, provided that the squashed message adheres to the above message format.
|
||||
* It is acceptable for some commits in a pull request to not include a semantic prefix, as long as the pull request title contains a meaningful encompassing semantic message.
|
||||
The `electron/electron` repository also enforces squash merging, so you only need to make sure that your pull request has the correct title prefix.
|
||||
|
||||
# Versioned `master`
|
||||
## Versioned `main` branch
|
||||
|
||||
* The `master` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`
|
||||
* Release branches are never merged back to master
|
||||
* Release branches _do_ contain the correct version in their `package.json`
|
||||
* As soon as a release branch is cut for a major, master must be bumped to the next major. I.e. `master` is always versioned as the next theoretical release branch
|
||||
* The `main` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`.
|
||||
* Release branches are never merged back to `main`.
|
||||
* Release branches _do_ contain the correct version in their `package.json`.
|
||||
* As soon as a release branch is cut for a major, `main` must be bumped to the next major (i.e. `main` is always versioned as the next theoretical release branch).
|
||||
|
||||
## Historical versioning (Electron 1.X)
|
||||
|
||||
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Teams, Skype, VS Code, and GitHub Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
|
||||
|
||||
Here is an example of the 1.x strategy:
|
||||
|
||||

|
||||
|
||||
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
|
||||
|
||||
@@ -91,7 +91,7 @@ The above configuration will download from URLs such as
|
||||
`https://npm.taobao.org/mirrors/electron/8.0.0/electron-v8.0.0-linux-x64.zip`.
|
||||
|
||||
If your mirror serves artifacts with different checksums to the official
|
||||
Electron release you may have to set `ELECTRON_USE_REMOTE_CHECKSUMS=1` to
|
||||
Electron release you may have to set `electron_use_remote_checksums=1` to
|
||||
force Electron to use the remote `SHASUMS256.txt` file to verify the checksum
|
||||
instead of the embedded checksums.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ the dirty area is passed to the `paint` event to be more efficient.
|
||||
losses with no benefits.
|
||||
* When nothing is happening on a webpage, no frames are generated.
|
||||
* An offscreen window is always created as a
|
||||
[Frameless Window](../api/frameless-window.md).
|
||||
[Frameless Window](../tutorial/window-customization.md)..
|
||||
|
||||
### Rendering Modes
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ without the need of switching to the window itself.
|
||||
|
||||
On Windows, you can use a taskbar button to display a progress bar.
|
||||
|
||||
![Windows Progress Bar][https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png]
|
||||

|
||||
|
||||
On macOS, the progress bar will be displayed as a part of the dock icon.
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
# Selenium and WebDriver
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
## Setting up Spectron
|
||||
|
||||
[Spectron][spectron] is the officially supported ChromeDriver testing framework
|
||||
for Electron. It is built on top of [WebdriverIO](https://webdriver.io/) and
|
||||
has helpers to access Electron APIs in your tests and bundles ChromeDriver.
|
||||
|
||||
```sh
|
||||
$ npm install --save-dev spectron
|
||||
```
|
||||
|
||||
```javascript
|
||||
// A simple test to verify a visible window is opened with a title
|
||||
const Application = require('spectron').Application
|
||||
const assert = require('assert')
|
||||
|
||||
const myApp = new Application({
|
||||
path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
|
||||
})
|
||||
|
||||
const verifyWindowIsVisibleWithTitle = async (app) => {
|
||||
await app.start()
|
||||
try {
|
||||
// Check if the window is visible
|
||||
const isVisible = await app.browserWindow.isVisible()
|
||||
// Verify the window is visible
|
||||
assert.strictEqual(isVisible, true)
|
||||
// Get the window's title
|
||||
const title = await app.client.getTitle()
|
||||
// Verify the window's title
|
||||
assert.strictEqual(title, 'My App')
|
||||
} catch (error) {
|
||||
// Log any failures
|
||||
console.error('Test failed', error.message)
|
||||
}
|
||||
// Stop the application
|
||||
await app.stop()
|
||||
}
|
||||
|
||||
verifyWindowIsVisibleWithTitle(myApp)
|
||||
```
|
||||
|
||||
## Setting up with WebDriverJs
|
||||
|
||||
[WebDriverJs](https://www.selenium.dev/selenium/docs/api/javascript/index.html) provides
|
||||
a Node package for testing with web driver, we will use it as an example.
|
||||
|
||||
### 1. Start ChromeDriver
|
||||
|
||||
First you need to download the `chromedriver` binary, and run it:
|
||||
|
||||
```sh
|
||||
$ npm install electron-chromedriver
|
||||
$ ./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later
|
||||
|
||||
### 2. Install WebDriverJS
|
||||
|
||||
```sh
|
||||
$ npm install selenium-webdriver
|
||||
```
|
||||
|
||||
### 3. Connect to ChromeDriver
|
||||
|
||||
The usage of `selenium-webdriver` with Electron is the same with
|
||||
upstream, except that you have to manually specify how to connect
|
||||
chrome driver and where to find Electron's binary:
|
||||
|
||||
```javascript
|
||||
const webdriver = require('selenium-webdriver')
|
||||
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by chrome driver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Setting up with WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) provides a Node package for testing with web
|
||||
driver.
|
||||
|
||||
### 1. Start ChromeDriver
|
||||
|
||||
First you need to download the `chromedriver` binary, and run it:
|
||||
|
||||
```sh
|
||||
$ npm install electron-chromedriver
|
||||
$ ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later
|
||||
|
||||
### 2. Install WebdriverIO
|
||||
|
||||
```sh
|
||||
$ npm install webdriverio
|
||||
```
|
||||
|
||||
### 3. Connect to chrome driver
|
||||
|
||||
```javascript
|
||||
const webdriverio = require('webdriverio')
|
||||
const options = {
|
||||
host: 'localhost', // Use localhost as chrome driver server
|
||||
port: 9515, // "9515" is the port opened by chrome driver.
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/Path-to-Your-App/electron', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const client = webdriverio.remote(options)
|
||||
|
||||
client
|
||||
.init()
|
||||
.url('http://google.com')
|
||||
.setValue('#q', 'webdriverio')
|
||||
.click('#btnG')
|
||||
.getTitle().then((title) => {
|
||||
console.log('Title was: ' + title)
|
||||
})
|
||||
.end()
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
To test your application without rebuilding Electron,
|
||||
[place](application-distribution.md)
|
||||
your app source into Electron's resource directory.
|
||||
|
||||
Alternatively, pass an argument to run with your Electron binary that points to
|
||||
your app's folder. This eliminates the need to copy-paste your app into
|
||||
Electron's resource directory.
|
||||
|
||||
[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
271
docs/tutorial/window-customization.md
Normal file
271
docs/tutorial/window-customization.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# Window Customization
|
||||
|
||||
The `BrowserWindow` module is the foundation of your Electron application, and it exposes
|
||||
many APIs that can change the look and behavior of your browser windows. In this
|
||||
tutorial, we will be going over the various use-cases for window customization on
|
||||
macOS, Windows, and Linux.
|
||||
|
||||
## Create frameless windows
|
||||
|
||||
A frameless window is a window that has no [chrome]. Not to be confused with the Google
|
||||
Chrome browser, window _chrome_ refers to the parts of the window (e.g. toolbars, controls)
|
||||
that are not a part of the web page.
|
||||
|
||||
To create a frameless window, you need to set `frame` to `false` in the `BrowserWindow`
|
||||
constructor.
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ frame: false })
|
||||
```
|
||||
|
||||
## Apply custom title bar styles _macOS_ _Windows_
|
||||
|
||||
Title bar styles allow you to hide most of a BrowserWindow's chrome while keeping the
|
||||
system's native window controls intact and can be configured with the `titleBarStyle`
|
||||
option in the `BrowserWindow` constructor.
|
||||
|
||||
Applying the `hidden` title bar style results in a hidden title bar and a full-size
|
||||
content window.
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hidden' })
|
||||
```
|
||||
|
||||
### Control the traffic lights _macOS_
|
||||
|
||||
On macOS, applying the `hidden` title bar style will still expose the standard window
|
||||
controls (“traffic lights”) in the top left.
|
||||
|
||||
#### Customize the look of your traffic lights _macOS_
|
||||
|
||||
The `customButtonsOnHover` title bar style will hide the traffic lights until you hover
|
||||
over them. This is useful if you want to create custom traffic lights in your HTML but still
|
||||
use the native UI to control the window.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover' })
|
||||
```
|
||||
|
||||
#### Customize the traffic light position _macOS_
|
||||
|
||||
To modify the position of the traffic light window controls, there are two configuration
|
||||
options available.
|
||||
|
||||
Applying `hiddenInset` title bar style will shift the vertical inset of the traffic lights
|
||||
by a fixed amount.
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
|
||||
```
|
||||
|
||||
If you need more granular control over the positioning of the traffic lights, you can pass
|
||||
a set of coordinates to the `trafficLightPosition` option in the `BrowserWindow`
|
||||
constructor.
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
trafficLightPosition: { x: 10, y: 10 }
|
||||
})
|
||||
```
|
||||
|
||||
#### Show and hide the traffic lights programmatically _macOS_
|
||||
|
||||
You can also show and hide the traffic lights programmatically from the main process.
|
||||
The `win.setWindowButtonVisibility` forces traffic lights to be show or hidden depending
|
||||
on the value of its boolean parameter.
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
// hides the traffic lights
|
||||
win.setWindowButtonVisibility(false)
|
||||
```
|
||||
|
||||
> Note: Given the number of APIs available, there are many ways of achieving this. For instance,
|
||||
> combining `frame: false` with `win.setWindowButtonVisibility(true)` will yield the same
|
||||
> layout outcome as setting `titleBarStyle: 'hidden'`.
|
||||
|
||||
## Window Controls Overlay _macOS_ _Windows_
|
||||
|
||||
The [Window Controls Overlay API] is a web standard that gives web apps the ability to
|
||||
customize their title bar region when installed on desktop. Electron exposes this API
|
||||
through the `BrowserWindow` constructor option `titleBarOverlay`.
|
||||
|
||||
This option only works whenever a custom `titlebarStyle` is applied on macOS or Windows.
|
||||
When `titleBarOverlay` is enabled, the window controls become exposed in their default
|
||||
position, and DOM elements cannot use the area underneath this region.
|
||||
|
||||
The `titleBarOverlay` option accepts two different value formats.
|
||||
|
||||
Specifying `true` on either platform will result in an overlay region with default
|
||||
system colors:
|
||||
|
||||
```javascript title='main.js'
|
||||
// on macOS or Windows
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: true
|
||||
})
|
||||
```
|
||||
|
||||
On Windows, you can also specify the color of the overlay and its symbols by setting
|
||||
`titleBarOverlay` to an object with the `color` and `symbolColor` properties. If an option
|
||||
is not specified, the color will default to its system color for the window control buttons:
|
||||
|
||||
```javascript title='main.js'
|
||||
// on Windows
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: {
|
||||
color: '#2f3241',
|
||||
symbolColor: '#74b1be'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
> Note: Once your title bar overlay is enabled from the main process, you can access the overlay's
|
||||
> color and dimension values from a renderer using a set of readonly
|
||||
> [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars].
|
||||
|
||||
## Create transparent windows
|
||||
|
||||
By setting the `transparent` option to `true`, you can make a fully transparent window.
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ transparent: true })
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
* You cannot click through the transparent area. See
|
||||
[#1335](https://github.com/electron/electron/issues/1335) for details.
|
||||
* Transparent windows are not resizable. Setting `resizable` to `true` may make
|
||||
a transparent window stop working on some platforms.
|
||||
* The CSS [`blur()`] filter only applies to the window's web contents, so there is no way to apply
|
||||
blur effect to the content below the window (i.e. other applications open on
|
||||
the user's system).
|
||||
* The window will not be transparent when DevTools is opened.
|
||||
* On _Windows_:
|
||||
* Transparent windows will not work when DWM is disabled.
|
||||
* Transparent windows can not be maximized using the Windows system menu or by double
|
||||
clicking the title bar. The reasoning behind this can be seen on
|
||||
PR [#28207](https://github.com/electron/electron/pull/28207).
|
||||
* On _macOS_:
|
||||
* The native window shadow will not be shown on a transparent window.
|
||||
|
||||
## Create click-through windows
|
||||
|
||||
To create a click-through window, i.e. making the window ignore all mouse
|
||||
events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
|
||||
API:
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
win.setIgnoreMouseEvents(true)
|
||||
```
|
||||
|
||||
### Forward mouse events _macOS_ _Windows_
|
||||
|
||||
Ignoring mouse messages makes the web contents oblivious to mouse movement,
|
||||
meaning that mouse movement events will not be emitted. On Windows and macOS, an
|
||||
optional parameter can be used to forward mouse move messages to the web page,
|
||||
allowing events such as `mouseleave` to be emitted:
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
win.setIgnoreMouseEvents(...args)
|
||||
})
|
||||
```
|
||||
|
||||
```javascript title='preload.js'
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const el = document.getElementById('clickThroughElement')
|
||||
el.addEventListener('mouseenter', () => {
|
||||
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
|
||||
})
|
||||
el.addEventListener('mouseleave', () => {
|
||||
ipcRenderer.send('set-ignore-mouse-events', false)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
This makes the web page click-through when over the `#clickThroughElement` element,
|
||||
and returns to normal outside it.
|
||||
|
||||
## Set custom draggable region
|
||||
|
||||
By default, the frameless window is non-draggable. Apps need to specify
|
||||
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
|
||||
(like the OS's standard titlebar), and apps can also use
|
||||
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
|
||||
draggable region. Note that only rectangular shapes are currently supported.
|
||||
|
||||
To make the whole window draggable, you can add `-webkit-app-region: drag` as
|
||||
`body`'s style:
|
||||
|
||||
```css title='styles.css'
|
||||
body {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
```
|
||||
|
||||
And note that if you have made the whole window draggable, you must also mark
|
||||
buttons as non-draggable, otherwise it would be impossible for users to click on
|
||||
them:
|
||||
|
||||
```css title='styles.css'
|
||||
button {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
```
|
||||
|
||||
If you're only setting a custom titlebar as draggable, you also need to make all
|
||||
buttons in titlebar non-draggable.
|
||||
|
||||
### Tip: disable text selection
|
||||
|
||||
When creating a draggable region, the dragging behavior may conflict with text selection.
|
||||
For example, when you drag the titlebar, you may accidentally select its text contents.
|
||||
To prevent this, you need to disable text selection within a draggable area like this:
|
||||
|
||||
```css
|
||||
.titlebar {
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
```
|
||||
|
||||
### Tip: disable context menus
|
||||
|
||||
On some platforms, the draggable area will be treated as a non-client frame, so
|
||||
when you right click on it, a system menu will pop up. To make the context menu
|
||||
behave correctly on all platforms, you should never use a custom context menu on
|
||||
draggable areas.
|
||||
|
||||
[`blur()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur()
|
||||
[`BrowserWindow`]: ../api/browser-window.md
|
||||
[chrome]: https://developer.mozilla.org/en-US/docs/Glossary/Chrome
|
||||
[ignore-mouse-events]: ../api/browser-window.md#winsetignoremouseeventsignore-options
|
||||
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
|
||||
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
|
||||
[Window Controls Overlay API]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md
|
||||
@@ -23,7 +23,6 @@ auto_filenames = {
|
||||
"docs/api/environment-variables.md",
|
||||
"docs/api/extensions.md",
|
||||
"docs/api/file-object.md",
|
||||
"docs/api/frameless-window.md",
|
||||
"docs/api/global-shortcut.md",
|
||||
"docs/api/in-app-purchase.md",
|
||||
"docs/api/incoming-message.md",
|
||||
|
||||
@@ -352,6 +352,8 @@ filenames = {
|
||||
"shell/browser/child_web_contents_tracker.h",
|
||||
"shell/browser/cookie_change_notifier.cc",
|
||||
"shell/browser/cookie_change_notifier.h",
|
||||
"shell/browser/electron_api_ipc_handler_impl.cc",
|
||||
"shell/browser/electron_api_ipc_handler_impl.h",
|
||||
"shell/browser/electron_autofill_driver.cc",
|
||||
"shell/browser/electron_autofill_driver.h",
|
||||
"shell/browser/electron_autofill_driver_factory.cc",
|
||||
@@ -360,8 +362,6 @@ filenames = {
|
||||
"shell/browser/electron_browser_client.h",
|
||||
"shell/browser/electron_browser_context.cc",
|
||||
"shell/browser/electron_browser_context.h",
|
||||
"shell/browser/electron_browser_handler_impl.cc",
|
||||
"shell/browser/electron_browser_handler_impl.h",
|
||||
"shell/browser/electron_browser_main_parts.cc",
|
||||
"shell/browser/electron_browser_main_parts.h",
|
||||
"shell/browser/electron_download_manager_delegate.cc",
|
||||
@@ -378,6 +378,8 @@ filenames = {
|
||||
"shell/browser/electron_quota_permission_context.h",
|
||||
"shell/browser/electron_speech_recognition_manager_delegate.cc",
|
||||
"shell/browser/electron_speech_recognition_manager_delegate.h",
|
||||
"shell/browser/electron_web_contents_utility_handler_impl.cc",
|
||||
"shell/browser/electron_web_contents_utility_handler_impl.h",
|
||||
"shell/browser/electron_web_ui_controller_factory.cc",
|
||||
"shell/browser/electron_web_ui_controller_factory.h",
|
||||
"shell/browser/event_emitter_mixin.cc",
|
||||
|
||||
@@ -39,7 +39,8 @@ Object.assign(app, {
|
||||
hasSwitch: (theSwitch: string) => commandLine.hasSwitch(String(theSwitch)),
|
||||
getSwitchValue: (theSwitch: string) => commandLine.getSwitchValue(String(theSwitch)),
|
||||
appendSwitch: (theSwitch: string, value?: string) => commandLine.appendSwitch(String(theSwitch), typeof value === 'undefined' ? value : String(value)),
|
||||
appendArgument: (arg: string) => commandLine.appendArgument(String(arg))
|
||||
appendArgument: (arg: string) => commandLine.appendArgument(String(arg)),
|
||||
removeSwitch: (theSwitch: string) => commandLine.removeSwitch(String(theSwitch))
|
||||
} as Electron.CommandLine
|
||||
});
|
||||
|
||||
|
||||
@@ -593,6 +593,9 @@ WebContents.prototype._init = function () {
|
||||
ipcMainInternal.emit(channel, event, ...args);
|
||||
} else {
|
||||
addReplyToEvent(event);
|
||||
if (this.listenerCount('ipc-message-sync') === 0 && ipcMain.listenerCount(channel) === 0) {
|
||||
console.warn(`WebContents #${this.id} called ipcRenderer.sendSync() with '${channel}' channel without listeners.`);
|
||||
}
|
||||
this.emit('ipc-message-sync', event, channel, ...args);
|
||||
ipcMain.emit(channel, event, ...args);
|
||||
}
|
||||
@@ -666,16 +669,6 @@ WebContents.prototype._init = function () {
|
||||
postBody
|
||||
};
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
|
||||
// if attempting to use this API with the deprecated new-window event,
|
||||
// windowOpenOverriddenOptions will always return null. This ensures
|
||||
// short-term backwards compatibility until new-window is removed.
|
||||
const parsedFeatures = parseFeatures(rawFeatures);
|
||||
const overriddenFeatures: BrowserWindowConstructorOptions = {
|
||||
...parsedFeatures.options,
|
||||
webPreferences: parsedFeatures.webPreferences
|
||||
};
|
||||
windowOpenOverriddenOptions = windowOpenOverriddenOptions || overriddenFeatures;
|
||||
|
||||
if (!event.defaultPrevented) {
|
||||
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
|
||||
// Allow setting of backgroundColor as a webPreference even though
|
||||
@@ -685,9 +678,19 @@ WebContents.prototype._init = function () {
|
||||
transparent: windowOpenOverriddenOptions.transparent,
|
||||
...windowOpenOverriddenOptions.webPreferences
|
||||
} : undefined;
|
||||
this._setNextChildWebPreferences(
|
||||
makeWebPreferences({ embedder: event.sender, secureOverrideWebPreferences })
|
||||
);
|
||||
// TODO(zcbenz): The features string is parsed twice: here where it is
|
||||
// passed to C++, and in |makeBrowserWindowOptions| later where it is
|
||||
// not actually used since the WebContents is created here.
|
||||
// We should be able to remove the latter once the |nativeWindowOpen|
|
||||
// option is removed.
|
||||
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
|
||||
// Parameters should keep same with |makeBrowserWindowOptions|.
|
||||
const webPreferences = makeWebPreferences({
|
||||
embedder: event.sender,
|
||||
insecureParsedWebPreferences: parsedWebPreferences,
|
||||
secureOverrideWebPreferences
|
||||
});
|
||||
this._setNextChildWebPreferences(webPreferences);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -735,6 +738,14 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
});
|
||||
|
||||
this.on('select-bluetooth-device', (event, devices, callback) => {
|
||||
if (this.listenerCount('select-bluetooth-device') === 1) {
|
||||
// Cancel it if there are no handlers
|
||||
event.preventDefault();
|
||||
callback('');
|
||||
}
|
||||
});
|
||||
|
||||
const event = process._linkedBinding('electron_browser_event').createEmpty();
|
||||
app.emit('web-contents-created', event, this);
|
||||
|
||||
|
||||
@@ -7,7 +7,11 @@ WebFrameMain.prototype.send = function (channel, ...args) {
|
||||
throw new Error('Missing required channel argument');
|
||||
}
|
||||
|
||||
return this._send(false /* internal */, channel, args);
|
||||
try {
|
||||
return this._send(false /* internal */, channel, args);
|
||||
} catch (e) {
|
||||
console.error('Error sending from webFrameMain: ', e);
|
||||
}
|
||||
};
|
||||
|
||||
WebFrameMain.prototype._sendInternal = function (channel, ...args) {
|
||||
@@ -15,7 +19,11 @@ WebFrameMain.prototype._sendInternal = function (channel, ...args) {
|
||||
throw new Error('Missing required channel argument');
|
||||
}
|
||||
|
||||
return this._send(true /* internal */, channel, args);
|
||||
try {
|
||||
return this._send(true /* internal */, channel, args);
|
||||
} catch (e) {
|
||||
console.error('Error sending from webFrameMain: ', e);
|
||||
}
|
||||
};
|
||||
|
||||
WebFrameMain.prototype.postMessage = function (...args) {
|
||||
|
||||
@@ -28,6 +28,17 @@ function sanitizeOptionsForGuest (options: Record<string, any>) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function makeLoadURLOptions (params: Record<string, any>) {
|
||||
const opts: Electron.LoadURLOptions = {};
|
||||
if (params.httpreferrer) {
|
||||
opts.httpReferrer = params.httpreferrer;
|
||||
}
|
||||
if (params.useragent) {
|
||||
opts.userAgent = params.useragent;
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
// Create a new guest instance.
|
||||
const createGuest = function (embedder: Electron.WebContents, params: Record<string, any>) {
|
||||
// eslint-disable-next-line no-undef
|
||||
@@ -51,7 +62,7 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
|
||||
|
||||
// Init guest web view after attached.
|
||||
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
|
||||
params = this.attachParams!;
|
||||
const params = this.attachParams!;
|
||||
delete this.attachParams;
|
||||
|
||||
const previouslyAttached = this.viewInstanceId != null;
|
||||
@@ -63,14 +74,7 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
|
||||
}
|
||||
|
||||
if (params.src) {
|
||||
const opts: Electron.LoadURLOptions = {};
|
||||
if (params.httpreferrer) {
|
||||
opts.httpReferrer = params.httpreferrer;
|
||||
}
|
||||
if (params.useragent) {
|
||||
opts.userAgent = params.useragent;
|
||||
}
|
||||
this.loadURL(params.src, opts);
|
||||
this.loadURL(params.src, params.opts);
|
||||
}
|
||||
embedder.emit('did-attach-webview', event, guest);
|
||||
});
|
||||
@@ -149,13 +153,15 @@ const attachGuest = function (event: Electron.IpcMainInvokeEvent,
|
||||
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`);
|
||||
}
|
||||
|
||||
const { instanceId } = params;
|
||||
|
||||
// If this guest is already attached to an element then remove it
|
||||
if (guestInstance.elementInstanceId) {
|
||||
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
|
||||
embedderElementsMap.delete(oldKey);
|
||||
|
||||
// Remove guest from embedder if moving across web views
|
||||
if (guest.viewInstanceId !== params.instanceId) {
|
||||
if (guest.viewInstanceId !== instanceId) {
|
||||
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
|
||||
guestInstance.embedder._sendInternal(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${guest.viewInstanceId}`);
|
||||
}
|
||||
@@ -206,12 +212,12 @@ const attachGuest = function (event: Electron.IpcMainInvokeEvent,
|
||||
|
||||
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||
if (event.defaultPrevented) {
|
||||
if (guest.viewInstanceId == null) guest.viewInstanceId = params.instanceId;
|
||||
if (guest.viewInstanceId == null) guest.viewInstanceId = instanceId;
|
||||
guest.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
guest.attachParams = params;
|
||||
guest.attachParams = { instanceId, src: params.src, opts: makeLoadURLOptions(params) };
|
||||
embedderElementsMap.set(key, guestInstanceId);
|
||||
|
||||
guest.setEmbedder(embedder);
|
||||
|
||||
@@ -65,8 +65,13 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#apis-for-creating-and-navigating-browsing-contexts-by-name
|
||||
const existingWindow = getGuestWindowByFrameName(frameName);
|
||||
if (existingWindow) {
|
||||
existingWindow.loadURL(url);
|
||||
return existingWindow;
|
||||
if (existingWindow.isDestroyed() || existingWindow.webContents.isDestroyed()) {
|
||||
// FIXME(t57ser): The webContents is destroyed for some reason, unregister the frame name
|
||||
unregisterFrameName(frameName);
|
||||
} else {
|
||||
existingWindow.loadURL(url);
|
||||
return existingWindow;
|
||||
}
|
||||
}
|
||||
|
||||
const window = new BrowserWindow({
|
||||
@@ -212,6 +217,10 @@ function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: {
|
||||
height: 600,
|
||||
...parsedOptions,
|
||||
...overrideOptions,
|
||||
// Note that for |nativeWindowOpen: true| the WebContents is created in
|
||||
// |api::WebContents::WebContentsCreatedWithFullParams|, with prefs
|
||||
// parsed in the |-will-add-new-contents| event.
|
||||
// The |webPreferences| here is only used by |nativeWindowOpen: false|.
|
||||
webPreferences: makeWebPreferences({
|
||||
embedder,
|
||||
insecureParsedWebPreferences: parsedWebPreferences,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
export const enum IPC_MESSAGES {
|
||||
BROWSER_REQUIRE = 'REMOTE_BROWSER_REQUIRE',
|
||||
BROWSER_GET_BUILTIN = 'REMOTE_BROWSER_GET_BUILTIN',
|
||||
BROWSER_GET_GLOBAL = 'REMOTE_BROWSER_GET_GLOBAL',
|
||||
BROWSER_GET_CURRENT_WINDOW = 'REMOTE_BROWSER_GET_CURRENT_WINDOW',
|
||||
BROWSER_GET_CURRENT_WEB_CONTENTS = 'REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS',
|
||||
BROWSER_CONSTRUCTOR = 'REMOTE_BROWSER_CONSTRUCTOR',
|
||||
BROWSER_FUNCTION_CALL = 'REMOTE_BROWSER_FUNCTION_CALL',
|
||||
BROWSER_MEMBER_CONSTRUCTOR = 'REMOTE_BROWSER_MEMBER_CONSTRUCTOR',
|
||||
BROWSER_MEMBER_CALL = 'REMOTE_BROWSER_MEMBER_CALL',
|
||||
BROWSER_MEMBER_GET = 'REMOTE_BROWSER_MEMBER_GET',
|
||||
BROWSER_MEMBER_SET = 'REMOTE_BROWSER_MEMBER_SET',
|
||||
BROWSER_DEREFERENCE = 'REMOTE_BROWSER_DEREFERENCE',
|
||||
BROWSER_CONTEXT_RELEASE = 'REMOTE_BROWSER_CONTEXT_RELEASE',
|
||||
BROWSER_WRONG_CONTEXT_ERROR = 'REMOTE_BROWSER_WRONG_CONTEXT_ERROR',
|
||||
|
||||
RENDERER_CALLBACK = 'REMOTE_RENDERER_CALLBACK',
|
||||
RENDERER_RELEASE_CALLBACK = 'REMOTE_RENDERER_RELEASE_CALLBACK',
|
||||
}
|
||||
@@ -27,7 +27,6 @@ export class WebViewImpl {
|
||||
public hasFocus = false
|
||||
public internalInstanceId?: number;
|
||||
public resizeObserver?: ResizeObserver;
|
||||
public userAgentOverride?: string;
|
||||
public viewInstanceId: number
|
||||
|
||||
// on* Event handlers.
|
||||
@@ -180,8 +179,7 @@ export class WebViewImpl {
|
||||
|
||||
buildParams () {
|
||||
const params: Record<string, any> = {
|
||||
instanceId: this.viewInstanceId,
|
||||
userAgentOverride: this.userAgentOverride
|
||||
instanceId: this.viewInstanceId
|
||||
};
|
||||
|
||||
for (const [attributeName, attribute] of this.attributes) {
|
||||
|
||||
@@ -22,7 +22,8 @@ if (isInstalled()) {
|
||||
const platform = process.env.npm_config_platform || process.platform;
|
||||
let arch = process.env.npm_config_arch || process.arch;
|
||||
|
||||
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64') {
|
||||
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64' &&
|
||||
process.env.npm_config_arch === undefined) {
|
||||
// When downloading for macOS ON macOS and we think we need x64 we should
|
||||
// check if we're running under rosetta and download the arm64 version if appropriate
|
||||
try {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "15.1.2",
|
||||
"version": "15.5.7",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
"@azure/storage-blob": "^12.9.0",
|
||||
"@electron/docs-parser": "^0.12.2",
|
||||
"@electron/typescript-definitions": "^8.9.5",
|
||||
"@octokit/auth-app": "^2.10.0",
|
||||
@@ -33,7 +34,7 @@
|
||||
"asar": "^3.1.0",
|
||||
"aws-sdk": "^2.727.1",
|
||||
"check-for-leaks": "^1.2.1",
|
||||
"colors": "^1.4.0",
|
||||
"colors": "1.4.0",
|
||||
"dotenv-safe": "^4.0.4",
|
||||
"dugite": "^1.103.0",
|
||||
"eslint": "^7.4.0",
|
||||
|
||||
19
patches/angle/.patches
Normal file
19
patches/angle/.patches
Normal file
@@ -0,0 +1,19 @@
|
||||
cherry-pick-bdffa0ea5148.patch
|
||||
cherry-pick-05e69c75905f.patch
|
||||
cherry-pick-891020ed64d4.patch
|
||||
cherry-pick-2b98abd8cb6c.patch
|
||||
cherry-pick-cc44ae61f37b.patch
|
||||
vangle_change_the_default_vulkan_device_choose_logic.patch
|
||||
m96_validate_samplerformat.patch
|
||||
m98_vulkan_fix_vkcmdresolveimage_extents.patch
|
||||
m98_vulkan_fix_vkcmdresolveimage_offsets.patch
|
||||
cherry-pick-49e8ff16f1fe.patch
|
||||
m99_vulkan_prevent_out_of_bounds_read_in_divisor_emulation_path.patch
|
||||
m99_vulkan_streamvertexdatawithdivisor_write_beyond_buffer_boundary.patch
|
||||
m98_protect_against_deleting_a_current_xfb_buffer.patch
|
||||
m96-lts_vulkan_fix_issue_with_redefining_a_layered_attachment.patch
|
||||
cherry-pick-d27d9d059b51.patch
|
||||
m100_fix_crash_when_pausing_xfb_then_deleting_a_buffer.patch
|
||||
cherry-pick-d49484c21e3c.patch
|
||||
cherry-pick-a602a068e022.patch
|
||||
fix_checkednumeric_using_the_wrong_type.patch
|
||||
118
patches/angle/cherry-pick-05e69c75905f.patch
Normal file
118
patches/angle/cherry-pick-05e69c75905f.patch
Normal file
@@ -0,0 +1,118 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lingfeng Yang <lfy@google.com>
|
||||
Date: Wed, 1 Dec 2021 18:16:14 -0800
|
||||
Subject: M96: Vulkan: remove staged updates on storage set
|
||||
|
||||
Previously we would allow staged updates to bigger versions of a texture
|
||||
to go through even if the texture was redefined via glTexStorage*.
|
||||
|
||||
Bug: chromium:1262080
|
||||
Change-Id: I9d861fed68d4a1fdcd0777b97caf729cc74c595e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3312718
|
||||
Reviewed-by: Charlie Lao <cclao@google.com>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Commit-Queue: Lingfeng Yang <lfy@google.com>
|
||||
(cherry picked from commit 929c8ed4e8c3912cf027d843e7a2af47b21e5612)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3328001
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
index e0be9676912e49d70473ffdcd4d7b1549210be25..b43f41dbae29356f1ffe4f961ed83e0f0e9cdcd2 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
@@ -1236,6 +1236,10 @@ angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
|
||||
{
|
||||
releaseAndDeleteImageAndViews(contextVk);
|
||||
}
|
||||
+ else if (mImage)
|
||||
+ {
|
||||
+ mImage->releaseStagingBuffer(contextVk->getRenderer());
|
||||
+ }
|
||||
|
||||
const vk::Format &format = renderer->getFormat(internalformat);
|
||||
ANGLE_TRY(ensureImageAllocated(contextVk, format));
|
||||
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
|
||||
index e79bc700d4991752289ff3d7c76f2ccbb3ba932a..a3dec629c9ea96b276ff8bf344d4a4628ff20b3b 100644
|
||||
--- a/src/tests/gl_tests/TextureTest.cpp
|
||||
+++ b/src/tests/gl_tests/TextureTest.cpp
|
||||
@@ -9703,6 +9703,73 @@ void main()
|
||||
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
+class TextureChangeStorageUploadTest : public ANGLETest
|
||||
+{
|
||||
+ protected:
|
||||
+ TextureChangeStorageUploadTest()
|
||||
+ {
|
||||
+ setWindowWidth(256);
|
||||
+ setWindowHeight(256);
|
||||
+ setConfigRedBits(8);
|
||||
+ setConfigGreenBits(8);
|
||||
+ setConfigBlueBits(8);
|
||||
+ setConfigAlphaBits(8);
|
||||
+ }
|
||||
+
|
||||
+ void testSetUp() override
|
||||
+ {
|
||||
+ mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
|
||||
+ if (mProgram == 0)
|
||||
+ {
|
||||
+ FAIL() << "shader compilation failed.";
|
||||
+ }
|
||||
+
|
||||
+ mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
|
||||
+
|
||||
+ glUseProgram(mProgram);
|
||||
+
|
||||
+ glClearColor(0, 0, 0, 0);
|
||||
+ glClearDepthf(0.0);
|
||||
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
+
|
||||
+ glEnable(GL_BLEND);
|
||||
+ glDisable(GL_DEPTH_TEST);
|
||||
+
|
||||
+ glGenTextures(1, &mTexture);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ }
|
||||
+
|
||||
+ void testTearDown() override
|
||||
+ {
|
||||
+ glDeleteTextures(1, &mTexture);
|
||||
+ glDeleteProgram(mProgram);
|
||||
+ }
|
||||
+
|
||||
+ GLuint mProgram;
|
||||
+ GLint mColorLocation;
|
||||
+ GLuint mTexture;
|
||||
+};
|
||||
+
|
||||
+// Verify that respecifying storage and re-uploading doesn't crash.
|
||||
+TEST_P(TextureChangeStorageUploadTest, Basic)
|
||||
+{
|
||||
+ constexpr int kImageSize = 8; // 4 doesn't trip ASAN
|
||||
+ constexpr int kSmallerImageSize = kImageSize / 2;
|
||||
+ EXPECT_GT(kImageSize, kSmallerImageSize);
|
||||
+ EXPECT_GT(kSmallerImageSize / 2, 0);
|
||||
+
|
||||
+ std::array<GLColor, kImageSize * kImageSize> kColor;
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D, mTexture);
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kImageSize, kImageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ kColor.data());
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSmallerImageSize, kSmallerImageSize);
|
||||
+ // need partial update to sidestep optimizations that remove the full upload
|
||||
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSmallerImageSize / 2, kSmallerImageSize / 2, GL_RGBA,
|
||||
+ GL_UNSIGNED_BYTE, kColor.data());
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
|
||||
// tests should be run against.
|
||||
#define ES2_EMULATE_COPY_TEX_IMAGE() \
|
||||
@@ -9816,4 +9883,6 @@ ANGLE_INSTANTIATE_TEST_ES31_AND(TextureBufferTestES31, WithDirectSPIRVGeneration
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CopyImageTestES31);
|
||||
ANGLE_INSTANTIATE_TEST_ES31_AND(CopyImageTestES31, WithDirectSPIRVGeneration(ES31_VULKAN()));
|
||||
|
||||
+ANGLE_INSTANTIATE_TEST_ES3(TextureChangeStorageUploadTest);
|
||||
+
|
||||
} // anonymous namespace
|
||||
96
patches/angle/cherry-pick-2b98abd8cb6c.patch
Normal file
96
patches/angle/cherry-pick-2b98abd8cb6c.patch
Normal file
@@ -0,0 +1,96 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Tue, 30 Nov 2021 23:48:30 -0500
|
||||
Subject: M96: Vulkan: Fix image respecify's usage tracking
|
||||
|
||||
When respecifying an image due to mip level count changes, the previous
|
||||
image is staged as an update to the new image. The resource usage info
|
||||
was not being transferred to the image being staged as an update,
|
||||
causing it to be prematurely deleted.
|
||||
|
||||
Test based on one authored by sugoi@google.com.
|
||||
|
||||
Bug: chromium:1270658
|
||||
Bug: angleproject:4835
|
||||
Change-Id: I9810f8940e0107bc8a04fa3fb9c26a045c0d689c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3318257
|
||||
Reviewed-by: Lingfeng Yang <lfy@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/ResourceVk.cpp b/src/libANGLE/renderer/vulkan/ResourceVk.cpp
|
||||
index efb04acf0fe5dc7c2d860ac8cc33dbe30691c4a3..e2cd1e3a96b1fa4e034efe6ed78ea1a787af6af6 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/ResourceVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/ResourceVk.cpp
|
||||
@@ -26,6 +26,12 @@ Resource::Resource(Resource &&other) : Resource()
|
||||
mUse = std::move(other.mUse);
|
||||
}
|
||||
|
||||
+Resource &Resource::operator=(Resource &&rhs)
|
||||
+{
|
||||
+ std::swap(mUse, rhs.mUse);
|
||||
+ return *this;
|
||||
+}
|
||||
+
|
||||
Resource::~Resource()
|
||||
{
|
||||
mUse.release();
|
||||
diff --git a/src/libANGLE/renderer/vulkan/ResourceVk.h b/src/libANGLE/renderer/vulkan/ResourceVk.h
|
||||
index 67440122bf7fa0f72b5412816853b2eddd770fd4..abab9900b7361c8564cb1ad30e0841eaf873ee2e 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/ResourceVk.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/ResourceVk.h
|
||||
@@ -192,6 +192,7 @@ class Resource : angle::NonCopyable
|
||||
protected:
|
||||
Resource();
|
||||
Resource(Resource &&other);
|
||||
+ Resource &operator=(Resource &&rhs);
|
||||
|
||||
// Current resource lifetime.
|
||||
SharedResourceUse mUse;
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
index a06b60d9c2c91280b925b12825e104bdbb757c05..893144ff07760dc1608a4b2d3af565e23ef27ba4 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
@@ -6140,6 +6140,9 @@ void ImageHelper::stageSelfAsSubresourceUpdates(ContextVk *contextVk,
|
||||
// Move the necessary information for staged update to work, and keep the rest as part of this
|
||||
// object.
|
||||
|
||||
+ // Usage info
|
||||
+ prevImage->get().Resource::operator=(std::move(*this));
|
||||
+
|
||||
// Vulkan objects
|
||||
prevImage->get().mImage = std::move(mImage);
|
||||
prevImage->get().mDeviceMemory = std::move(mDeviceMemory);
|
||||
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
|
||||
index 4db00e78a7d2f7375fdcb9228fbdc83395973125..8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a 100644
|
||||
--- a/src/tests/gl_tests/MipmapTest.cpp
|
||||
+++ b/src/tests/gl_tests/MipmapTest.cpp
|
||||
@@ -2106,6 +2106,30 @@ TEST_P(MipmapTestES3, GenerateMipmapZeroSize)
|
||||
glGenerateMipmap(GL_TEXTURE_3D);
|
||||
}
|
||||
|
||||
+// Test that reducing the size of the mipchain by resizing the base image then deleting it doesn't
|
||||
+// cause a crash. Issue found by fuzzer.
|
||||
+TEST_P(MipmapTestES3, ResizeBaseMipTo1x1ThenDelete)
|
||||
+{
|
||||
+ GLTexture tex;
|
||||
+ glBindTexture(GL_TEXTURE_2D, tex);
|
||||
+
|
||||
+ std::vector<GLColor> data(2, GLColor::blue);
|
||||
+
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
|
||||
+
|
||||
+ clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
|
||||
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
|
||||
+
|
||||
+ data[0] = GLColor::green;
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
|
||||
+
|
||||
+ clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
|
||||
+
|
||||
+ tex.reset();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
|
||||
+}
|
||||
+
|
||||
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
|
||||
// tests should be run against.
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MipmapTest);
|
||||
381
patches/angle/cherry-pick-49e8ff16f1fe.patch
Normal file
381
patches/angle/cherry-pick-49e8ff16f1fe.patch
Normal file
@@ -0,0 +1,381 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Tue, 25 Jan 2022 12:15:16 -0500
|
||||
Subject: M99: Vulkan: Fix texture array level redefinition
|
||||
|
||||
When a level of a texture is redefined, all staged updates to that level
|
||||
should be removed, not the ones specific to the new layers. The bug
|
||||
fixed was that if the texture was redefined to have its number of layers
|
||||
changed, the staged higher-layer-count update to the image was not
|
||||
removed.
|
||||
|
||||
Bug: chromium:1289383
|
||||
Change-Id: Iab79c38d846d1abbdd92e11b1b60a3adf0fbde4c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3441309
|
||||
Reviewed-by: Lingfeng Yang <lfy@google.com>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
index b43f41dbae29356f1ffe4f961ed83e0f0e9cdcd2..610f720b68d37aaddf142b0dca538749386cef7e 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
@@ -1553,12 +1553,25 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
|
||||
|
||||
if (mImage != nullptr)
|
||||
{
|
||||
- // If there is any staged changes for this index, we can remove them since we're going to
|
||||
+ // If there are any staged changes for this index, we can remove them since we're going to
|
||||
// override them with this call.
|
||||
gl::LevelIndex levelIndexGL(index.getLevelIndex());
|
||||
uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
|
||||
- mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
|
||||
- index.getLayerCount());
|
||||
+ if (gl::IsArrayTextureType(index.getType()))
|
||||
+ {
|
||||
+ // A multi-layer texture is being redefined, remove all updates to this level; the
|
||||
+ // number of layers may have changed.
|
||||
+ mImage->removeStagedUpdates(contextVk, levelIndexGL, levelIndexGL);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ // Otherwise remove only updates to this layer. For example, cube map updates can be
|
||||
+ // done through glTexImage2D, one per cube face (i.e. layer) and so should not remove
|
||||
+ // updates to the other layers.
|
||||
+ ASSERT(index.getLayerCount() == 1);
|
||||
+ mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
|
||||
+ index.getLayerCount());
|
||||
+ }
|
||||
|
||||
if (mImage->valid())
|
||||
{
|
||||
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
|
||||
index 8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a..957a52304edc9aa245f9f21e5557cc105cbad789 100644
|
||||
--- a/src/tests/gl_tests/MipmapTest.cpp
|
||||
+++ b/src/tests/gl_tests/MipmapTest.cpp
|
||||
@@ -1686,6 +1686,106 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D)
|
||||
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
||||
}
|
||||
|
||||
+// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
|
||||
+// in the Vulkan backend where the old higher-layer-count data upload was not removed.
|
||||
+TEST_P(MipmapTestES3, TextureArrayRedefineThenGenerateMipmap)
|
||||
+{
|
||||
+ int px = getWindowWidth() / 2;
|
||||
+ int py = getWindowHeight() / 2;
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
|
||||
+
|
||||
+ // Fill the whole texture with red, then redefine it and fill with green
|
||||
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
||||
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsRed.data());
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsGreen.data());
|
||||
+
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Generate mipmaps
|
||||
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ glUseProgram(mArrayProgram);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Draw the first slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
||||
+ drawQuad(mArrayProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+
|
||||
+ // Draw the second slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
||||
+ drawQuad(mArrayProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+}
|
||||
+
|
||||
+// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
|
||||
+// the Vulkan backend where the old higher-layer-count data upload was not removed.
|
||||
+TEST_P(MipmapTestES3, TextureArrayUseThenRedefineThenGenerateMipmap)
|
||||
+{
|
||||
+ int px = getWindowWidth() / 2;
|
||||
+ int py = getWindowHeight() / 2;
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
|
||||
+
|
||||
+ // Fill the whole texture with red.
|
||||
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsRed.data());
|
||||
+
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Generate mipmap
|
||||
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ glUseProgram(mArrayProgram);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Draw the first slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
||||
+ drawQuad(mArrayProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
||||
+
|
||||
+ // Draw the fourth slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 3);
|
||||
+ drawQuad(mArrayProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
||||
+
|
||||
+ // Redefine the image and fill with green
|
||||
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsGreen.data());
|
||||
+
|
||||
+ // Generate mipmap
|
||||
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Draw the first slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
||||
+ drawQuad(mArrayProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+
|
||||
+ // Draw the second slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
||||
+ drawQuad(mArrayProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+}
|
||||
+
|
||||
// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
|
||||
// the same, and then sample levels 0 and 2.
|
||||
// GLES 3.0.4 section 3.8.10:
|
||||
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
|
||||
index 56bef0186234f59d370669c21f588ea9c5c356fc..772fe27daac3ac0b5f54b8319cef6aa9c980208a 100644
|
||||
--- a/src/tests/gl_tests/TextureTest.cpp
|
||||
+++ b/src/tests/gl_tests/TextureTest.cpp
|
||||
@@ -1028,31 +1028,37 @@ class SamplerArrayAsFunctionParameterTest : public SamplerArrayTest
|
||||
class Texture2DArrayTestES3 : public TexCoordDrawTest
|
||||
{
|
||||
protected:
|
||||
- Texture2DArrayTestES3() : TexCoordDrawTest(), m2DArrayTexture(0), mTextureArrayLocation(-1) {}
|
||||
+ Texture2DArrayTestES3()
|
||||
+ : TexCoordDrawTest(),
|
||||
+ m2DArrayTexture(0),
|
||||
+ mTextureArrayLocation(-1),
|
||||
+ mTextureArraySliceUniformLocation(-1)
|
||||
+ {}
|
||||
|
||||
const char *getVertexShaderSource() override
|
||||
{
|
||||
- return "#version 300 es\n"
|
||||
- "out vec2 texcoord;\n"
|
||||
- "in vec4 position;\n"
|
||||
- "void main()\n"
|
||||
- "{\n"
|
||||
- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
|
||||
- " texcoord = (position.xy * 0.5) + 0.5;\n"
|
||||
- "}\n";
|
||||
+ return R"(#version 300 es
|
||||
+out vec2 texcoord;
|
||||
+in vec4 position;
|
||||
+void main()
|
||||
+{
|
||||
+ gl_Position = vec4(position.xy, 0.0, 1.0);
|
||||
+ texcoord = (position.xy * 0.5) + 0.5;
|
||||
+})";
|
||||
}
|
||||
|
||||
const char *getFragmentShaderSource() override
|
||||
{
|
||||
- return "#version 300 es\n"
|
||||
- "precision highp float;\n"
|
||||
- "uniform highp sampler2DArray tex2DArray;\n"
|
||||
- "in vec2 texcoord;\n"
|
||||
- "out vec4 fragColor;\n"
|
||||
- "void main()\n"
|
||||
- "{\n"
|
||||
- " fragColor = texture(tex2DArray, vec3(texcoord.x, texcoord.y, 0.0));\n"
|
||||
- "}\n";
|
||||
+ return R"(#version 300 es
|
||||
+precision highp float;
|
||||
+uniform highp sampler2DArray tex2DArray;
|
||||
+uniform int slice;
|
||||
+in vec2 texcoord;
|
||||
+out vec4 fragColor;
|
||||
+void main()
|
||||
+{
|
||||
+ fragColor = texture(tex2DArray, vec3(texcoord, float(slice)));
|
||||
+})";
|
||||
}
|
||||
|
||||
void testSetUp() override
|
||||
@@ -1064,6 +1070,9 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
|
||||
mTextureArrayLocation = glGetUniformLocation(mProgram, "tex2DArray");
|
||||
ASSERT_NE(-1, mTextureArrayLocation);
|
||||
|
||||
+ mTextureArraySliceUniformLocation = glGetUniformLocation(mProgram, "slice");
|
||||
+ ASSERT_NE(-1, mTextureArraySliceUniformLocation);
|
||||
+
|
||||
glGenTextures(1, &m2DArrayTexture);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
@@ -1076,6 +1085,7 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
|
||||
|
||||
GLuint m2DArrayTexture;
|
||||
GLint mTextureArrayLocation;
|
||||
+ GLint mTextureArraySliceUniformLocation;
|
||||
};
|
||||
|
||||
class TextureSizeTextureArrayTest : public TexCoordDrawTest
|
||||
@@ -1718,28 +1728,28 @@ class Texture2DArrayIntegerTestES3 : public Texture2DArrayTestES3
|
||||
|
||||
const char *getVertexShaderSource() override
|
||||
{
|
||||
- return "#version 300 es\n"
|
||||
- "out vec2 texcoord;\n"
|
||||
- "in vec4 position;\n"
|
||||
- "void main()\n"
|
||||
- "{\n"
|
||||
- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
|
||||
- " texcoord = (position.xy * 0.5) + 0.5;\n"
|
||||
- "}\n";
|
||||
+ return R"(#version 300 es
|
||||
+out vec2 texcoord;
|
||||
+in vec4 position;
|
||||
+void main()
|
||||
+{
|
||||
+ gl_Position = vec4(position.xy, 0.0, 1.0);
|
||||
+ texcoord = (position.xy * 0.5) + 0.5;
|
||||
+})";
|
||||
}
|
||||
|
||||
const char *getFragmentShaderSource() override
|
||||
{
|
||||
- return "#version 300 es\n"
|
||||
- "precision highp float;\n"
|
||||
- "uniform highp usampler2DArray tex2DArray;\n"
|
||||
- "in vec2 texcoord;\n"
|
||||
- "out vec4 fragColor;\n"
|
||||
- "void main()\n"
|
||||
- "{\n"
|
||||
- " fragColor = vec4(texture(tex2DArray, vec3(texcoord.x, texcoord.y, "
|
||||
- "0.0)))/255.0;\n"
|
||||
- "}\n";
|
||||
+ return R"(#version 300 es
|
||||
+precision highp float;
|
||||
+uniform highp usampler2DArray tex2DArray;
|
||||
+uniform int slice;
|
||||
+in vec2 texcoord;
|
||||
+out vec4 fragColor;
|
||||
+void main()
|
||||
+{
|
||||
+ fragColor = vec4(texture(tex2DArray, vec3(texcoord, slice)))/255.0;
|
||||
+})";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5112,6 +5122,94 @@ TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensio
|
||||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
|
||||
}
|
||||
|
||||
+// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
|
||||
+// in the Vulkan backend where the old higher-layer-count data upload was not removed.
|
||||
+TEST_P(Texture2DArrayTestES3, TextureArrayRedefineThenUse)
|
||||
+{
|
||||
+ int px = getWindowWidth() / 2;
|
||||
+ int py = getWindowHeight() / 2;
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
|
||||
+
|
||||
+ // Fill the whole texture with red, then redefine it and fill with green
|
||||
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
||||
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsRed.data());
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsGreen.data());
|
||||
+
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ glUseProgram(mProgram);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Draw the first slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
||||
+ drawQuad(mProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+
|
||||
+ // Draw the second slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
||||
+ drawQuad(mProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+}
|
||||
+
|
||||
+// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
|
||||
+// the Vulkan backend where the old higher-layer-count data upload was not removed.
|
||||
+TEST_P(Texture2DArrayTestES3, TextureArrayUseThenRedefineThenUse)
|
||||
+{
|
||||
+ int px = getWindowWidth() / 2;
|
||||
+ int py = getWindowHeight() / 2;
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
|
||||
+
|
||||
+ // Fill the whole texture with red.
|
||||
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsRed.data());
|
||||
+
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ glUseProgram(mProgram);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ // Draw the first slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
||||
+ drawQuad(mProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
||||
+
|
||||
+ // Draw the fourth slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 3);
|
||||
+ drawQuad(mProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
||||
+
|
||||
+ // Redefine the image and fill with green
|
||||
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
||||
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ pixelsGreen.data());
|
||||
+
|
||||
+ // Draw the first slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
||||
+ drawQuad(mProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+
|
||||
+ // Draw the second slice
|
||||
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
||||
+ drawQuad(mProgram, "position", 0.5f);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
||||
+}
|
||||
+
|
||||
// Test that texture completeness is updated if texture max level changes.
|
||||
// GLES 3.0.4 section 3.8.13 Texture completeness
|
||||
TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
|
||||
163
patches/angle/cherry-pick-891020ed64d4.patch
Normal file
163
patches/angle/cherry-pick-891020ed64d4.patch
Normal file
@@ -0,0 +1,163 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jonah Ryan-Davis <jonahr@google.com>
|
||||
Date: Mon, 22 Nov 2021 14:30:52 -0500
|
||||
Subject: Ignore the pixel unpack state for compressed textures.
|
||||
|
||||
From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding
|
||||
a compressed texture image
|
||||
This was causing a bad access when calling compressedTexImage3D
|
||||
with GL_UNPACK_IMAGE_HEIGHT greater than the image height.
|
||||
|
||||
Bug: chromium:1267496
|
||||
Change-Id: I9b1f4c645548af64f2695fd23262225a1ad07cd7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3296622
|
||||
Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
(cherry picked from commit 870f458f507ff7ba0f67b28a30a27955ce79dd3e)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3309097
|
||||
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
|
||||
index c4ce77d612d88a898f8a8164466d25b210e2144b..eb60719ac38543b608c122daebd71b1084ac35f2 100644
|
||||
--- a/src/libANGLE/Context.cpp
|
||||
+++ b/src/libANGLE/Context.cpp
|
||||
@@ -4961,7 +4961,9 @@ void Context::compressedTexImage2D(TextureTarget target,
|
||||
|
||||
Extents size(width, height, 1);
|
||||
Texture *texture = getTextureByTarget(target);
|
||||
- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
|
||||
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
|
||||
+ // image. So we use an empty PixelUnpackState.
|
||||
+ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
|
||||
internalformat, size, imageSize,
|
||||
static_cast<const uint8_t *>(data)));
|
||||
}
|
||||
@@ -4993,7 +4995,9 @@ void Context::compressedTexImage3D(TextureTarget target,
|
||||
|
||||
Extents size(width, height, depth);
|
||||
Texture *texture = getTextureByTarget(target);
|
||||
- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
|
||||
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
|
||||
+ // image. So we use an empty PixelUnpackState.
|
||||
+ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
|
||||
internalformat, size, imageSize,
|
||||
static_cast<const uint8_t *>(data)));
|
||||
}
|
||||
@@ -5027,8 +5031,10 @@ void Context::compressedTexSubImage2D(TextureTarget target,
|
||||
|
||||
Box area(xoffset, yoffset, 0, width, height, 1);
|
||||
Texture *texture = getTextureByTarget(target);
|
||||
- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
|
||||
- area, format, imageSize,
|
||||
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
|
||||
+ // image. So we use an empty PixelUnpackState.
|
||||
+ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
|
||||
+ format, imageSize,
|
||||
static_cast<const uint8_t *>(data)));
|
||||
}
|
||||
|
||||
@@ -5069,8 +5075,10 @@ void Context::compressedTexSubImage3D(TextureTarget target,
|
||||
|
||||
Box area(xoffset, yoffset, zoffset, width, height, depth);
|
||||
Texture *texture = getTextureByTarget(target);
|
||||
- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
|
||||
- area, format, imageSize,
|
||||
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
|
||||
+ // image. So we use an empty PixelUnpackState.
|
||||
+ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
|
||||
+ format, imageSize,
|
||||
static_cast<const uint8_t *>(data)));
|
||||
}
|
||||
|
||||
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
|
||||
index a3dec629c9ea96b276ff8bf344d4a4628ff20b3b..ba512a11cb023d9caae666ab2634d1e66057d12c 100644
|
||||
--- a/src/tests/gl_tests/TextureTest.cpp
|
||||
+++ b/src/tests/gl_tests/TextureTest.cpp
|
||||
@@ -5151,6 +5151,43 @@ TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
|
||||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
|
||||
}
|
||||
|
||||
+// Test that compressed textures ignore the pixel unpack state.
|
||||
+// (https://crbug.org/1267496)
|
||||
+TEST_P(Texture3DTestES3, PixelUnpackStateTexImage)
|
||||
+{
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
|
||||
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
|
||||
+
|
||||
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5);
|
||||
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D);
|
||||
+
|
||||
+ uint8_t data[64] = {0};
|
||||
+ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64,
|
||||
+ data);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
+// Test that compressed textures ignore the pixel unpack state.
|
||||
+// (https://crbug.org/1267496)
|
||||
+TEST_P(Texture3DTestES3, PixelUnpackStateTexSubImage)
|
||||
+{
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
|
||||
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D);
|
||||
+
|
||||
+ uint8_t data[64] = {0};
|
||||
+ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64,
|
||||
+ data);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5);
|
||||
+
|
||||
+ glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 4,
|
||||
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 64, data);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
// Test that 3D texture completeness is updated if texture max level changes.
|
||||
// GLES 3.0.4 section 3.8.13 Texture completeness
|
||||
TEST_P(Texture3DTestES3, Texture3DCompletenessChangesWithMaxLevel)
|
||||
@@ -5830,6 +5867,41 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1)
|
||||
EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
|
||||
}
|
||||
|
||||
+// Test that compressed textures ignore the pixel unpack state.
|
||||
+// (https://crbug.org/1267496)
|
||||
+TEST_P(Texture2DTestES3, PixelUnpackStateTexImage)
|
||||
+{
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
|
||||
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
|
||||
+
|
||||
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5);
|
||||
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
|
||||
+
|
||||
+ uint8_t data[16] = {0};
|
||||
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
+// Test that compressed textures ignore the pixel unpack state.
|
||||
+// (https://crbug.org/1267496)
|
||||
+TEST_P(Texture2DTestES3, PixelUnpackStateTexSubImage)
|
||||
+{
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
|
||||
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
|
||||
+
|
||||
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
|
||||
+
|
||||
+ uint8_t data[16] = {0};
|
||||
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5);
|
||||
+
|
||||
+ glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16,
|
||||
+ data);
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
// Copied from Texture2DTest::TexStorage
|
||||
// Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a
|
||||
// default color.
|
||||
31
patches/angle/cherry-pick-a602a068e022.patch
Normal file
31
patches/angle/cherry-pick-a602a068e022.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Tue, 19 Apr 2022 17:01:20 -0400
|
||||
Subject: Fix validate state cache after XFB buffer deleted.
|
||||
|
||||
Bug: chromium:1317650
|
||||
Change-Id: Iec9f1167c3b2957091dd0f4ef3efcfcd7c4bf3c0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3594250
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Auto-Submit: Jamie Madill <jmadill@chromium.org>
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
(cherry picked from commit 4efc4ee6830a8a53a0daf9daa3c7aa835db4220f)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3621779
|
||||
Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
|
||||
index 182709c348f7490e1ee990a05570c13d7e9d0dd7..dc2b1728e3a7ab494e616940565f08692a9ff028 100644
|
||||
--- a/src/libANGLE/State.cpp
|
||||
+++ b/src/libANGLE/State.cpp
|
||||
@@ -2115,10 +2115,7 @@ angle::Result State::detachBuffer(Context *context, const Buffer *buffer)
|
||||
if (curTransformFeedback)
|
||||
{
|
||||
ANGLE_TRY(curTransformFeedback->detachBuffer(context, bufferID));
|
||||
- if (isTransformFeedbackActiveUnpaused())
|
||||
- {
|
||||
- context->getStateCache().onActiveTransformFeedbackChange(context);
|
||||
- }
|
||||
+ context->getStateCache().onActiveTransformFeedbackChange(context);
|
||||
}
|
||||
|
||||
if (getVertexArray()->detachBuffer(context, bufferID))
|
||||
169
patches/angle/cherry-pick-bdffa0ea5148.patch
Normal file
169
patches/angle/cherry-pick-bdffa0ea5148.patch
Normal file
@@ -0,0 +1,169 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 2 Dec 2021 14:30:42 -0500
|
||||
Subject: M96: Fix changing attached renderbuffer from MSRTT to non-MSRTT
|
||||
|
||||
FramebufferAttachment::mRenderToTextureSamples was never updated if the
|
||||
renderbuffer storage was changed after attaching to framebuffer.
|
||||
|
||||
Bug: chromium:1272068
|
||||
Change-Id: Icddbb5650354ea16d06c49532d6a8d0ae962ab5f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3320923
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/FramebufferAttachment.cpp b/src/libANGLE/FramebufferAttachment.cpp
|
||||
index 00714d0a0303050893abcd9564e760b22d9b2de5..720d3000d42e6c8c23214e66eee4aa6982216a60 100644
|
||||
--- a/src/libANGLE/FramebufferAttachment.cpp
|
||||
+++ b/src/libANGLE/FramebufferAttachment.cpp
|
||||
@@ -129,7 +129,7 @@ void FramebufferAttachment::attach(const Context *context,
|
||||
mNumViews = numViews;
|
||||
mBaseViewIndex = baseViewIndex;
|
||||
mIsMultiview = isMultiview;
|
||||
- mRenderToTextureSamples = samples;
|
||||
+ mRenderToTextureSamples = type == GL_RENDERBUFFER ? kDefaultRenderToTextureSamples : samples;
|
||||
resource->onAttach(context, framebufferSerial);
|
||||
|
||||
if (mResource != nullptr)
|
||||
@@ -222,6 +222,29 @@ GLint FramebufferAttachment::getBaseViewIndex() const
|
||||
return mBaseViewIndex;
|
||||
}
|
||||
|
||||
+bool FramebufferAttachment::isRenderToTexture() const
|
||||
+{
|
||||
+ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE);
|
||||
+
|
||||
+ if (mType == GL_RENDERBUFFER)
|
||||
+ {
|
||||
+ return getRenderbuffer()->getMultisamplingMode() ==
|
||||
+ MultisamplingMode::MultisampledRenderToTexture;
|
||||
+ }
|
||||
+ return mRenderToTextureSamples != kDefaultRenderToTextureSamples;
|
||||
+}
|
||||
+
|
||||
+GLsizei FramebufferAttachment::getRenderToTextureSamples() const
|
||||
+{
|
||||
+ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE);
|
||||
+
|
||||
+ if (mType == GL_RENDERBUFFER)
|
||||
+ {
|
||||
+ return getRenderbuffer()->getState().getSamples();
|
||||
+ }
|
||||
+ return mRenderToTextureSamples;
|
||||
+}
|
||||
+
|
||||
Texture *FramebufferAttachment::getTexture() const
|
||||
{
|
||||
return rx::GetAs<Texture>(mResource);
|
||||
diff --git a/src/libANGLE/FramebufferAttachment.h b/src/libANGLE/FramebufferAttachment.h
|
||||
index 7ebf5f5e620cfac47be176fa0bc668353e923104..a5d5bf0eb0c50e37656b241d105be3f35a657585 100644
|
||||
--- a/src/libANGLE/FramebufferAttachment.h
|
||||
+++ b/src/libANGLE/FramebufferAttachment.h
|
||||
@@ -117,11 +117,8 @@ class FramebufferAttachment final
|
||||
bool isMultiview() const;
|
||||
GLint getBaseViewIndex() const;
|
||||
|
||||
- bool isRenderToTexture() const
|
||||
- {
|
||||
- return mRenderToTextureSamples != kDefaultRenderToTextureSamples;
|
||||
- }
|
||||
- GLsizei getRenderToTextureSamples() const { return mRenderToTextureSamples; }
|
||||
+ bool isRenderToTexture() const;
|
||||
+ GLsizei getRenderToTextureSamples() const;
|
||||
|
||||
// The size of the underlying resource the attachment points to. The 'depth' value will
|
||||
// correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
|
||||
@@ -195,6 +192,14 @@ class FramebufferAttachment final
|
||||
GLsizei mNumViews;
|
||||
bool mIsMultiview;
|
||||
GLint mBaseViewIndex;
|
||||
+ // A single-sampled texture can be attached to a framebuffer either as single-sampled or as
|
||||
+ // multisampled-render-to-texture. In the latter case, |mRenderToTextureSamples| will contain
|
||||
+ // the number of samples. For renderbuffers, the number of samples is inherited from the
|
||||
+ // renderbuffer itself.
|
||||
+ //
|
||||
+ // Note that textures cannot change storage between single and multisample once attached to a
|
||||
+ // framebuffer. Renderbuffers instead can, and caching the number of renderbuffer samples here
|
||||
+ // can lead to stale data.
|
||||
GLsizei mRenderToTextureSamples;
|
||||
};
|
||||
|
||||
@@ -254,8 +259,7 @@ inline Format FramebufferAttachment::getFormat() const
|
||||
|
||||
inline GLsizei FramebufferAttachment::getSamples() const
|
||||
{
|
||||
- return (mRenderToTextureSamples != kDefaultRenderToTextureSamples) ? getRenderToTextureSamples()
|
||||
- : getResourceSamples();
|
||||
+ return isRenderToTexture() ? getRenderToTextureSamples() : getResourceSamples();
|
||||
}
|
||||
|
||||
inline GLsizei FramebufferAttachment::getResourceSamples() const
|
||||
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
|
||||
index ff01848daff091d92e4fdce08bc6842a3bdd3ee9..cd733be3ae5c179860d882e305ec84d093a283ed 100644
|
||||
--- a/src/tests/gl_tests/FramebufferTest.cpp
|
||||
+++ b/src/tests/gl_tests/FramebufferTest.cpp
|
||||
@@ -3366,6 +3366,65 @@ void main() {
|
||||
|
||||
// This shouldn't crash.
|
||||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
+// Modify renderbuffer attachment samples after bind
|
||||
+TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySamples)
|
||||
+{
|
||||
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
|
||||
+ glUseProgram(program);
|
||||
+ GLint colorUniformLocation =
|
||||
+ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
|
||||
+ ASSERT_NE(colorUniformLocation, -1);
|
||||
+
|
||||
+ GLFramebuffer fbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
+
|
||||
+ GLsizei size = 16;
|
||||
+ glViewport(0, 0, size, size);
|
||||
+
|
||||
+ GLRenderbuffer color;
|
||||
+ glBindRenderbuffer(GL_RENDERBUFFER, color);
|
||||
+
|
||||
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, size, size);
|
||||
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
|
||||
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
|
||||
+
|
||||
+ glUniform4f(colorUniformLocation, 1, 0, 0, 1);
|
||||
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
|
||||
+
|
||||
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
+// Modify renderbuffer attachment size after bind
|
||||
+TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySize)
|
||||
+{
|
||||
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
|
||||
+ glUseProgram(program);
|
||||
+ GLint colorUniformLocation =
|
||||
+ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
|
||||
+ ASSERT_NE(colorUniformLocation, -1);
|
||||
+
|
||||
+ GLFramebuffer fbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
+
|
||||
+ GLsizei size = 16;
|
||||
+ glViewport(0, 0, size, size);
|
||||
+
|
||||
+ GLRenderbuffer color;
|
||||
+ glBindRenderbuffer(GL_RENDERBUFFER, color);
|
||||
+
|
||||
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
|
||||
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
|
||||
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size / 2, size * 2);
|
||||
+
|
||||
+ glUniform4f(colorUniformLocation, 1, 0, 0, 1);
|
||||
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
|
||||
+
|
||||
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2(AddMockTextureNoRenderTargetTest);
|
||||
43
patches/angle/cherry-pick-cc44ae61f37b.patch
Normal file
43
patches/angle/cherry-pick-cc44ae61f37b.patch
Normal file
@@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Tue, 4 Jan 2022 12:28:55 -0500
|
||||
Subject: M96: D3D11: Fix OOB access in vertex conversion code.
|
||||
|
||||
This could happen when using certain combinations of stride and
|
||||
offset. Fix the issue by using checked math.
|
||||
|
||||
Bug: chromium:1274499
|
||||
Change-Id: I3e286a30fe128ab4684ee5e172dc9e3345e3b2f4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3365657
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
|
||||
index 43fcdc8de5a0d15aacf4b06e0e32df008d78f886..031a12e2b8b0e0dee91087c02cbd2f8b17435a2b 100644
|
||||
--- a/src/libANGLE/renderer/d3d/VertexDataManager.cpp
|
||||
+++ b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
|
||||
@@ -58,17 +58,15 @@ int ElementsInBuffer(const gl::VertexAttribute &attrib,
|
||||
const gl::VertexBinding &binding,
|
||||
unsigned int size)
|
||||
{
|
||||
- // Size cannot be larger than a GLsizei
|
||||
- if (size > static_cast<unsigned int>(std::numeric_limits<int>::max()))
|
||||
- {
|
||||
- size = static_cast<unsigned int>(std::numeric_limits<int>::max());
|
||||
- }
|
||||
+ angle::CheckedNumeric<size_t> bufferSize(size);
|
||||
+ angle::CheckedNumeric<size_t> stride = ComputeVertexAttributeStride(attrib, binding);
|
||||
+ angle::CheckedNumeric<size_t> offset = ComputeVertexAttributeOffset(attrib, binding);
|
||||
+ angle::CheckedNumeric<size_t> elementSize = ComputeVertexAttributeTypeSize(attrib);
|
||||
+
|
||||
+ auto elementsInBuffer = (bufferSize - (offset % stride) + (stride - elementSize)) / stride;
|
||||
+ auto elementsInBufferInt = angle::CheckedNumeric<int>::cast(elementsInBuffer);
|
||||
|
||||
- GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib, binding));
|
||||
- GLsizei offset = static_cast<GLsizei>(ComputeVertexAttributeOffset(attrib, binding));
|
||||
- return (size - offset % stride +
|
||||
- (stride - static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)))) /
|
||||
- stride;
|
||||
+ return elementsInBufferInt.ValueOrDefault(0);
|
||||
}
|
||||
|
||||
// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
|
||||
100
patches/angle/cherry-pick-d27d9d059b51.patch
Normal file
100
patches/angle/cherry-pick-d27d9d059b51.patch
Normal file
@@ -0,0 +1,100 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Charlie Lao <cclao@google.com>
|
||||
Date: Tue, 15 Mar 2022 09:39:36 -0700
|
||||
Subject: Vulkan: Update mCurrentElementArrayBuffersync based on dirty bit
|
||||
|
||||
M96 merge issues:
|
||||
ContextVk.cpp:
|
||||
ContextVk::setupIndexedDraw: vertexArrayVk/getVertexArray() isn't present in M96
|
||||
ContextVk::syncState: M96 uses mVertexArray instead of vertexArrayVk
|
||||
VertexArrayVk.cpp:
|
||||
VertexArrayVk::updateCurrentElementArrayBuffer doesn't exist in M9
|
||||
Created it and kept M96 logic for retrieving buffer/offset
|
||||
|
||||
The previous fix crrev.com/c/3513553 has run into corner case that
|
||||
requires more follow up change crrev.com/c/3522565. But with that, there
|
||||
is report that now we are hitting assertion in
|
||||
handleDirtyGraphicsIndexBuffer(). This becomes a bit fragile This new
|
||||
fix relies on the DIRTY_BIT_INDEX_BUFFER dirty bit and should be more
|
||||
reliable as long as the dirty bit is set properly (if not, then we have
|
||||
other bug that it won't even send down vulkan command to bind the
|
||||
correct element buffer). We could further optimize the code path and
|
||||
create a fast path for most common usages in the future.
|
||||
|
||||
Bug: chromium:1299261
|
||||
Change-Id: Ifa8f86d431798c9ca4c128ed71a3e9e0a3537ccb
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3526021
|
||||
Commit-Queue: Charlie Lao <cclao@google.com>
|
||||
(cherry picked from commit 349636a05a3577a127adb6c79a1e947890bbe462)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3605834
|
||||
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
|
||||
Reviewed-by: Charlie Lao <cclao@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
|
||||
index 15243f0c5a42949c2ce94dbd415089b77a7e39bc..2ff2fd75a73b50e3bce5d72e64d5d3064f30bd66 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
|
||||
@@ -954,6 +954,17 @@ angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
|
||||
mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
|
||||
mLastIndexBufferOffset = indices;
|
||||
}
|
||||
+
|
||||
+ // When you draw with LineLoop mode or GL_UNSIGNED_BYTE type, we may allocate its own
|
||||
+ // element buffer and modify mCurrentElementArrayBuffer. When we switch out of that draw
|
||||
+ // mode, we must reset mCurrentElementArrayBuffer back to the vertexArray's element buffer.
|
||||
+ // Since in either case we set DIRTY_BIT_INDEX_BUFFER dirty bit, we use this bit to re-sync
|
||||
+ // mCurrentElementArrayBuffer.
|
||||
+ if (mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
|
||||
+ {
|
||||
+ mVertexArray->updateCurrentElementArrayBuffer();
|
||||
+ }
|
||||
+
|
||||
if (shouldConvertUint8VkIndexType(indexType) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
|
||||
{
|
||||
ANGLE_PERF_WARNING(getDebug(), GL_DEBUG_SEVERITY_LOW,
|
||||
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
index 93378c4b24495872405fc06ea01e15254229ab63..035c80a5ba95492247bd87e4189de602ffb47da1 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
@@ -492,6 +492,17 @@ angle::Result VertexArrayVk::convertVertexBufferCPU(ContextVk *contextVk,
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
+void VertexArrayVk::updateCurrentElementArrayBuffer()
|
||||
+{
|
||||
+ ASSERT(mState.getElementArrayBuffer() != nullptr);
|
||||
+ ASSERT(mState.getElementArrayBuffer()->getSize() > 0);
|
||||
+ gl::Buffer *bufferGL = mState.getElementArrayBuffer();
|
||||
+ BufferVk *bufferVk = vk::GetImpl(bufferGL);
|
||||
+ mCurrentElementArrayBuffer =
|
||||
+ &bufferVk->getBufferAndOffset(&mCurrentElementArrayBufferOffset);
|
||||
+
|
||||
+}
|
||||
+
|
||||
angle::Result VertexArrayVk::syncState(const gl::Context *context,
|
||||
const gl::VertexArray::DirtyBits &dirtyBits,
|
||||
gl::VertexArray::DirtyAttribBitsArray *attribBits,
|
||||
@@ -516,9 +527,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
|
||||
{
|
||||
// Note that just updating buffer data may still result in a new
|
||||
// vk::BufferHelper allocation.
|
||||
- BufferVk *bufferVk = vk::GetImpl(bufferGL);
|
||||
- mCurrentElementArrayBuffer =
|
||||
- &bufferVk->getBufferAndOffset(&mCurrentElementArrayBufferOffset);
|
||||
+ updateCurrentElementArrayBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.h b/src/libANGLE/renderer/vulkan/VertexArrayVk.h
|
||||
index c198265bf8ba2017a13fce558826862f450218b5..0b98a9ed46b7cd4b9588973c74b0bbaf9172ab6c 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.h
|
||||
@@ -34,6 +34,8 @@ class VertexArrayVk : public VertexArrayImpl
|
||||
|
||||
angle::Result updateActiveAttribInfo(ContextVk *contextVk);
|
||||
|
||||
+ void updateCurrentElementArrayBuffer();
|
||||
+
|
||||
angle::Result updateDefaultAttrib(ContextVk *contextVk,
|
||||
size_t attribIndex,
|
||||
VkBuffer bufferHandle,
|
||||
33
patches/angle/cherry-pick-d49484c21e3c.patch
Normal file
33
patches/angle/cherry-pick-d49484c21e3c.patch
Normal file
@@ -0,0 +1,33 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Mon, 11 Apr 2022 12:29:00 -0400
|
||||
Subject: Add error check on resuming XFB with deleted buffer.
|
||||
|
||||
Bug: chromium:1313905
|
||||
Change-Id: I22c6f6400b05ca32c922fba9a3b9d4b5841ca8b8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3578378
|
||||
Auto-Submit: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
(cherry picked from commit 5c85fd4e11a3835a0719223a7cedb978d309da21)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3594103
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
|
||||
index 1523cd5f0093b7b4b03bf0cd5432ee0a15f17dab..5f42d4b418fe6ae2f8c7473ef7a8954ef128ff99 100644
|
||||
--- a/src/libANGLE/validationES3.cpp
|
||||
+++ b/src/libANGLE/validationES3.cpp
|
||||
@@ -4286,6 +4286,13 @@ bool ValidateUniformBlockBinding(const Context *context,
|
||||
return false;
|
||||
}
|
||||
|
||||
+ if (!ValidateProgramExecutableXFBBuffersPresent(context,
|
||||
+ context->getState().getProgramExecutable()))
|
||||
+ {
|
||||
+ context->validationError(GL_INVALID_OPERATION, kTransformFeedbackBufferMissing);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
58
patches/angle/fix_checkednumeric_using_the_wrong_type.patch
Normal file
58
patches/angle/fix_checkednumeric_using_the_wrong_type.patch
Normal file
@@ -0,0 +1,58 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Geoff Lang <geofflang@google.com>
|
||||
Date: Fri, 1 Apr 2022 11:38:17 -0400
|
||||
Subject: Fix CheckedNumeric using the wrong type.
|
||||
|
||||
Validation for glBufferSubData checks that the buffer is large enough
|
||||
for size+offset but verifies they fit in a size_t which is a different
|
||||
type than the deduced type for size+offset on 32-bit systems.
|
||||
|
||||
Use decltype to ensure that we always verify there is no overflow on the
|
||||
correct type.
|
||||
|
||||
Bug: chromium:1298867
|
||||
Change-Id: I82f534b2d227d3273a763e626ebeae068dc918dc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3563515
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
|
||||
Commit-Queue: Geoff Lang <geofflang@chromium.org>
|
||||
(cherry picked from commit c458b5add432c3da98ef370680518d0af7e4d4e3)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3630020
|
||||
|
||||
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
|
||||
index 9802a3385d5f042df8b643b9b452de29b41ba868..e0add8edaac527fac374afefbebce216d21182e9 100644
|
||||
--- a/src/libANGLE/validationES2.cpp
|
||||
+++ b/src/libANGLE/validationES2.cpp
|
||||
@@ -3779,7 +3779,7 @@ bool ValidateBufferSubData(const Context *context,
|
||||
}
|
||||
|
||||
// Check for possible overflow of size + offset
|
||||
- angle::CheckedNumeric<size_t> checkedSize(size);
|
||||
+ angle::CheckedNumeric<decltype(size + offset)> checkedSize(size);
|
||||
checkedSize += offset;
|
||||
if (!checkedSize.IsValid())
|
||||
{
|
||||
diff --git a/src/tests/gl_tests/BufferDataTest.cpp b/src/tests/gl_tests/BufferDataTest.cpp
|
||||
index b3e70c797ace1fbcaf0002fe7d63e4b4ac418e97..bad538962d262f81b3e6e78c820a28e114ea75fa 100644
|
||||
--- a/src/tests/gl_tests/BufferDataTest.cpp
|
||||
+++ b/src/tests/gl_tests/BufferDataTest.cpp
|
||||
@@ -746,6 +746,19 @@ void main()
|
||||
EXPECT_PIXEL_COLOR_EQ(3, 3, GLColor::green);
|
||||
}
|
||||
|
||||
+// Verify that buffer sub data uploads are properly validated within the buffer size range on 32-bit
|
||||
+// systems.
|
||||
+TEST_P(BufferDataTest, BufferSizeValidation32Bit)
|
||||
+{
|
||||
+ GLBuffer buffer;
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
+ glBufferData(GL_ARRAY_BUFFER, 100, nullptr, GL_STATIC_DRAW);
|
||||
+
|
||||
+ GLubyte data = 0;
|
||||
+ glBufferSubData(GL_ARRAY_BUFFER, std::numeric_limits<uint32_t>::max(), 1, &data);
|
||||
+ EXPECT_GL_ERROR(GL_INVALID_VALUE);
|
||||
+}
|
||||
+
|
||||
// Tests a null crash bug caused by copying from null back-end buffer pointer
|
||||
// when calling bufferData again after drawing without calling bufferData in D3D11.
|
||||
TEST_P(BufferDataTestES3, DrawWithNotCallingBufferData)
|
||||
@@ -0,0 +1,60 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Mon, 14 Mar 2022 10:37:31 -0400
|
||||
Subject: Fix crash when pausing XFB then deleting a buffer.
|
||||
|
||||
Fix is to validate XFB buffer bindings even if we're paused.
|
||||
This is undefined behaviour so we can use any non-crashing solution.
|
||||
|
||||
Bug: chromium:1305190
|
||||
Change-Id: Ib95404cdb13adbde7f34d6cc77473a8b3cbf1de7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3522283
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
(cherry picked from commit 708ce9cfd63bc8eab7c48987612a2dedce78c69a)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3594105
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
|
||||
index d5732741dff989b8b8f6f669511bf7bc001c4eaa..eb571bb2de3c4568810026e0364bf069bd8ca681 100644
|
||||
--- a/src/libANGLE/validationES.cpp
|
||||
+++ b/src/libANGLE/validationES.cpp
|
||||
@@ -3949,7 +3949,7 @@ const char *ValidateDrawStates(const Context *context)
|
||||
}
|
||||
}
|
||||
|
||||
- if (state.isTransformFeedbackActiveUnpaused())
|
||||
+ if (state.isTransformFeedbackActive())
|
||||
{
|
||||
if (!ValidateProgramExecutableXFBBuffersPresent(context, executable))
|
||||
{
|
||||
diff --git a/src/tests/gl_tests/TransformFeedbackTest.cpp b/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
index 63dd230829716b7a95b7917b47fb1fc278c1098a..e6ed494e89c0a0c48af4789be91d240df769281f 100644
|
||||
--- a/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
+++ b/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
@@ -3660,6 +3660,25 @@ void main() {
|
||||
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
+// Same as the above, with a paused transform feedback.
|
||||
+TEST_P(TransformFeedbackTest, DeletePausedTransformFeedbackBuffer)
|
||||
+{
|
||||
+ ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(testProgram, essl1_shaders::vs::Simple(),
|
||||
+ essl1_shaders::fs::Green(), {"gl_Position"},
|
||||
+ GL_INTERLEAVED_ATTRIBS);
|
||||
+ glUseProgram(testProgram);
|
||||
+
|
||||
+ GLBuffer buffer;
|
||||
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
|
||||
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, 3, nullptr, GL_STATIC_DRAW);
|
||||
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer);
|
||||
+
|
||||
+ glBeginTransformFeedback(GL_POINTS);
|
||||
+ glPauseTransformFeedback();
|
||||
+ buffer.reset();
|
||||
+ glDrawArrays(GL_POINTS, 0, 1);
|
||||
+}
|
||||
+
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTest);
|
||||
ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest);
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Tue, 1 Mar 2022 15:40:38 -0500
|
||||
Subject: Vulkan: Fix issue with redefining a layered attachment.
|
||||
|
||||
The fix ensures we complete level redefinition before we get the
|
||||
layer render target in TextureVk::getAttachmentRenderTarget.
|
||||
|
||||
Bug: chromium:1296866
|
||||
Change-Id: Id7fa8e9fed5e766c30580b09336713c675c4e4f0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3498283
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
(cherry picked from commit 348ece42552a99cff88f79c80652b9dd3155ab22)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3513754
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
index 610f720b68d37aaddf142b0dca538749386cef7e..569118e7137e8ea6dc02cc6247980c2198bf92db 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
@@ -2174,6 +2174,15 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
|
||||
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
|
||||
+ if (mRedefinedLevels.any())
|
||||
+ {
|
||||
+ // If we have redefined levels, we must flush those out to fix the render targets.
|
||||
+ ANGLE_TRY(respecifyImageStorage(contextVk));
|
||||
+ }
|
||||
+
|
||||
+ // Otherwise, don't flush staged updates here. We'll handle that in FramebufferVk so we can
|
||||
+ // defer clears.
|
||||
+
|
||||
if (!mImage->valid())
|
||||
{
|
||||
// Immutable texture must already have a valid image
|
||||
@@ -2217,8 +2226,6 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
|
||||
mState.getType(), samples, *mImage, useRobustInit));
|
||||
}
|
||||
|
||||
- // Don't flush staged updates here. We'll handle that in FramebufferVk so it can defer clears.
|
||||
-
|
||||
GLuint layerIndex = 0, layerCount = 0, imageLayerCount = 0;
|
||||
GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerIndex, &layerCount,
|
||||
&imageLayerCount);
|
||||
@@ -2229,10 +2236,14 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
|
||||
gl::LevelIndex(imageIndex.getLevelIndex()),
|
||||
renderToTextureIndex);
|
||||
|
||||
- ASSERT(imageIndex.getLevelIndex() <
|
||||
- static_cast<int32_t>(mSingleLayerRenderTargets[renderToTextureIndex].size()));
|
||||
- *rtOut = &mSingleLayerRenderTargets[renderToTextureIndex][imageIndex.getLevelIndex()]
|
||||
- [layerIndex];
|
||||
+ std::vector<RenderTargetVector> &levelRenderTargets =
|
||||
+ mSingleLayerRenderTargets[renderToTextureIndex];
|
||||
+ ASSERT(imageIndex.getLevelIndex() < static_cast<int32_t>(levelRenderTargets.size()));
|
||||
+
|
||||
+ RenderTargetVector &layerRenderTargets = levelRenderTargets[imageIndex.getLevelIndex()];
|
||||
+ ASSERT(imageIndex.getLayerIndex() < static_cast<int32_t>(layerRenderTargets.size()));
|
||||
+
|
||||
+ *rtOut = &layerRenderTargets[layerIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
|
||||
index cd733be3ae5c179860d882e305ec84d093a283ed..c0b745978ae5d28d97bb833f7fe6278872d8d620 100644
|
||||
--- a/src/tests/gl_tests/FramebufferTest.cpp
|
||||
+++ b/src/tests/gl_tests/FramebufferTest.cpp
|
||||
@@ -3427,6 +3427,25 @@ TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySize)
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
+// Tests redefining a layered framebuffer attachment.
|
||||
+TEST_P(FramebufferTest_ES3, RedefineLayerAttachment)
|
||||
+{
|
||||
+ GLTexture texture;
|
||||
+ glBindTexture(GL_TEXTURE_3D, texture);
|
||||
+ std::vector<uint8_t> imgData(20480, 0);
|
||||
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, 8, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, imgData.data());
|
||||
+
|
||||
+ GLFramebuffer fbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 8);
|
||||
+ glGenerateMipmap(GL_TEXTURE_3D);
|
||||
+
|
||||
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, 16, 16, 16, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE,
|
||||
+ imgData.data());
|
||||
+ glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 2, 2, 15, 16, 16);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
ANGLE_INSTANTIATE_TEST_ES2(AddMockTextureNoRenderTargetTest);
|
||||
ANGLE_INSTANTIATE_TEST_ES2(FramebufferTest);
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(FramebufferFormatsTest);
|
||||
115
patches/angle/m96_validate_samplerformat.patch
Normal file
115
patches/angle/m96_validate_samplerformat.patch
Normal file
@@ -0,0 +1,115 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lingfeng Yang <lfy@google.com>
|
||||
Date: Wed, 1 Dec 2021 17:08:01 -0800
|
||||
Subject: M96: Validate SamplerFormat
|
||||
|
||||
We weren't validating sampler formats in ProgramExecutable validation.
|
||||
|
||||
Bug: chromium:1273661
|
||||
Change-Id: Ida0c67c0c7169ea3f47ceb2d433bee17012a7e5e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3312717
|
||||
Reviewed-by: Charlie Lao <cclao@google.com>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Commit-Queue: Lingfeng Yang <lfy@google.com>
|
||||
(cherry picked from commit 6d3435fddd7abd67699c3f020d6b4fa21445d9b3)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3335173
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/ProgramExecutable.cpp b/src/libANGLE/ProgramExecutable.cpp
|
||||
index baf63ecec6f82fda9dd79a1c398b8e95ec70e321..14e5abdfab36a95f39839fc171e6e0bc3a5dc6e9 100644
|
||||
--- a/src/libANGLE/ProgramExecutable.cpp
|
||||
+++ b/src/libANGLE/ProgramExecutable.cpp
|
||||
@@ -1132,6 +1132,19 @@ bool ProgramExecutable::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
|
||||
mCachedValidateSamplersResult = false;
|
||||
return false;
|
||||
}
|
||||
+
|
||||
+ if (mActiveSamplerFormats[textureUnit] == SamplerFormat::InvalidEnum)
|
||||
+ {
|
||||
+ if (infoLog)
|
||||
+ {
|
||||
+ (*infoLog) << "Samplers of conflicting formats refer to the same texture "
|
||||
+ "image unit ("
|
||||
+ << textureUnit << ").";
|
||||
+ }
|
||||
+
|
||||
+ mCachedValidateSamplersResult = false;
|
||||
+ return false;
|
||||
+ }
|
||||
}
|
||||
|
||||
mCachedValidateSamplersResult = true;
|
||||
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
|
||||
index ba512a11cb023d9caae666ab2634d1e66057d12c..56bef0186234f59d370669c21f588ea9c5c356fc 100644
|
||||
--- a/src/tests/gl_tests/TextureTest.cpp
|
||||
+++ b/src/tests/gl_tests/TextureTest.cpp
|
||||
@@ -9796,8 +9796,6 @@ class TextureChangeStorageUploadTest : public ANGLETest
|
||||
FAIL() << "shader compilation failed.";
|
||||
}
|
||||
|
||||
- mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
|
||||
-
|
||||
glUseProgram(mProgram);
|
||||
|
||||
glClearColor(0, 0, 0, 0);
|
||||
@@ -9842,6 +9840,53 @@ TEST_P(TextureChangeStorageUploadTest, Basic)
|
||||
EXPECT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
+class ExtraSamplerCubeShadowUseTest : public ANGLETest
|
||||
+{
|
||||
+ protected:
|
||||
+ ExtraSamplerCubeShadowUseTest() : ANGLETest() {}
|
||||
+
|
||||
+ const char *getVertexShaderSource() { return "#version 300 es\nvoid main() {}"; }
|
||||
+
|
||||
+ const char *getFragmentShaderSource()
|
||||
+ {
|
||||
+ return R"(#version 300 es
|
||||
+precision mediump float;
|
||||
+
|
||||
+uniform mediump samplerCube var_0002; // this has to be there
|
||||
+uniform highp samplerCubeShadow var_0004; // this has to be a cube shadow sampler
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+
|
||||
+ vec4 var_0031 = texture(var_0002, vec3(1,1,1));
|
||||
+ ivec2 size = textureSize(var_0004, 0) ;
|
||||
+ var_0031.x += float(size.y);
|
||||
+
|
||||
+ color = var_0031;
|
||||
+})";
|
||||
+ }
|
||||
+
|
||||
+ void testSetUp() override
|
||||
+ {
|
||||
+ mProgram = CompileProgram(getVertexShaderSource(), getFragmentShaderSource());
|
||||
+ if (mProgram == 0)
|
||||
+ {
|
||||
+ FAIL() << "shader compilation failed.";
|
||||
+ }
|
||||
+ glUseProgram(mProgram);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ }
|
||||
+
|
||||
+ void testTearDown() override { glDeleteProgram(mProgram); }
|
||||
+
|
||||
+ GLuint mProgram;
|
||||
+};
|
||||
+
|
||||
+TEST_P(ExtraSamplerCubeShadowUseTest, Basic)
|
||||
+{
|
||||
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
|
||||
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
|
||||
+}
|
||||
+
|
||||
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
|
||||
// tests should be run against.
|
||||
#define ES2_EMULATE_COPY_TEX_IMAGE() \
|
||||
@@ -9957,4 +10002,6 @@ ANGLE_INSTANTIATE_TEST_ES31_AND(CopyImageTestES31, WithDirectSPIRVGeneration(ES3
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES3(TextureChangeStorageUploadTest);
|
||||
|
||||
+ANGLE_INSTANTIATE_TEST_ES3(ExtraSamplerCubeShadowUseTest);
|
||||
+
|
||||
} // anonymous namespace
|
||||
@@ -0,0 +1,109 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Tue, 1 Mar 2022 16:14:47 -0500
|
||||
Subject: Protect against deleting a current XFB buffer.
|
||||
|
||||
Bug: chromium:1295411
|
||||
Change-Id: I097f272c38e444e0af71aa55c0dc508a07aa0bd3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3498262
|
||||
Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
(cherry picked from commit d9002eef2a5f27fc5d6b65d01d02afcfb9a35db1)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3514175
|
||||
Reviewed-by: Ian Elliott <ianelliott@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
|
||||
index 8ec1eca3f4bc70da39c838a0f81664043276bc80..182709c348f7490e1ee990a05570c13d7e9d0dd7 100644
|
||||
--- a/src/libANGLE/State.cpp
|
||||
+++ b/src/libANGLE/State.cpp
|
||||
@@ -2115,6 +2115,10 @@ angle::Result State::detachBuffer(Context *context, const Buffer *buffer)
|
||||
if (curTransformFeedback)
|
||||
{
|
||||
ANGLE_TRY(curTransformFeedback->detachBuffer(context, bufferID));
|
||||
+ if (isTransformFeedbackActiveUnpaused())
|
||||
+ {
|
||||
+ context->getStateCache().onActiveTransformFeedbackChange(context);
|
||||
+ }
|
||||
}
|
||||
|
||||
if (getVertexArray()->detachBuffer(context, bufferID))
|
||||
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
|
||||
index 4c1ec1fc73746e2aba97ea83da5e8bcbd0b41ba5..d5732741dff989b8b8f6f669511bf7bc001c4eaa 100644
|
||||
--- a/src/libANGLE/validationES.cpp
|
||||
+++ b/src/libANGLE/validationES.cpp
|
||||
@@ -3948,6 +3948,14 @@ const char *ValidateDrawStates(const Context *context)
|
||||
return kTessellationShaderRequiresBothControlAndEvaluation;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if (state.isTransformFeedbackActiveUnpaused())
|
||||
+ {
|
||||
+ if (!ValidateProgramExecutableXFBBuffersPresent(context, executable))
|
||||
+ {
|
||||
+ return kTransformFeedbackBufferMissing;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
if (programIsYUVOutput != framebufferIsYUV)
|
||||
@@ -8055,4 +8063,21 @@ bool ValidateInvalidateTextureANGLE(const Context *context, TextureType target)
|
||||
return true;
|
||||
}
|
||||
|
||||
+bool ValidateProgramExecutableXFBBuffersPresent(const Context *context,
|
||||
+ const ProgramExecutable *programExecutable)
|
||||
+{
|
||||
+ size_t programXfbCount = programExecutable->getTransformFeedbackBufferCount();
|
||||
+ const TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
|
||||
+ for (size_t programXfbIndex = 0; programXfbIndex < programXfbCount; ++programXfbIndex)
|
||||
+ {
|
||||
+ const OffsetBindingPointer<Buffer> &buffer =
|
||||
+ transformFeedback->getIndexedBuffer(programXfbIndex);
|
||||
+ if (!buffer.get())
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
} // namespace gl
|
||||
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
|
||||
index f7daadb3de4d0a28f1896bad54bdc59f31a45cd3..934a35f6557462fd8da52fd7de7aba0ee5186dff 100644
|
||||
--- a/src/libANGLE/validationES.h
|
||||
+++ b/src/libANGLE/validationES.h
|
||||
@@ -755,6 +755,9 @@ bool ValidateGetMultisamplefvBase(const Context *context,
|
||||
const GLfloat *val);
|
||||
bool ValidateSampleMaskiBase(const Context *context, GLuint maskNumber, GLbitfield mask);
|
||||
|
||||
+bool ValidateProgramExecutableXFBBuffersPresent(const Context *context,
|
||||
+ const ProgramExecutable *programExecutable);
|
||||
+
|
||||
// We should check with Khronos if returning INVALID_FRAMEBUFFER_OPERATION is OK when querying
|
||||
// implementation format info for incomplete framebuffers. It seems like these queries are
|
||||
// incongruent with the other errors.
|
||||
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
|
||||
index f385ef623cc56658dc5f840ddd3f3c3bf9bf3e05..1523cd5f0093b7b4b03bf0cd5432ee0a15f17dab 100644
|
||||
--- a/src/libANGLE/validationES3.cpp
|
||||
+++ b/src/libANGLE/validationES3.cpp
|
||||
@@ -2786,16 +2786,10 @@ bool ValidateBeginTransformFeedback(const Context *context, PrimitiveMode primit
|
||||
return false;
|
||||
}
|
||||
|
||||
- size_t programXfbCount = programExecutable->getTransformFeedbackBufferCount();
|
||||
- for (size_t programXfbIndex = 0; programXfbIndex < programXfbCount; ++programXfbIndex)
|
||||
+ if (!ValidateProgramExecutableXFBBuffersPresent(context, programExecutable))
|
||||
{
|
||||
- const OffsetBindingPointer<Buffer> &buffer =
|
||||
- transformFeedback->getIndexedBuffer(programXfbIndex);
|
||||
- if (!buffer.get())
|
||||
- {
|
||||
- context->validationError(GL_INVALID_OPERATION, kTransformFeedbackBufferMissing);
|
||||
- return false;
|
||||
- }
|
||||
+ context->validationError(GL_INVALID_OPERATION, kTransformFeedbackBufferMissing);
|
||||
+ return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
112
patches/angle/m98_vulkan_fix_vkcmdresolveimage_extents.patch
Normal file
112
patches/angle/m98_vulkan_fix_vkcmdresolveimage_extents.patch
Normal file
@@ -0,0 +1,112 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Mon, 31 Jan 2022 12:07:43 -0500
|
||||
Subject: M98: Vulkan: Fix vkCmdResolveImage extents
|
||||
|
||||
The source framebuffer's extents were accidentally used instead of the
|
||||
blit area extents.
|
||||
|
||||
Bug: chromium:1288020
|
||||
Change-Id: I5c6128a191deeea2f972dc7f010be9d40c674ce6
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3457022
|
||||
Reviewed-by: Tim Van Patten <timvp@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
|
||||
index 4f7428217a130482dbbee760d32f183cee2255f6..ac4c4086c28be29a65386ef06cc103d14dfb0d48 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
|
||||
@@ -1459,8 +1459,8 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
|
||||
resolveRegion.dstOffset.x = params.destOffset[0];
|
||||
resolveRegion.dstOffset.y = params.destOffset[1];
|
||||
resolveRegion.dstOffset.z = 0;
|
||||
- resolveRegion.extent.width = params.srcExtents[0];
|
||||
- resolveRegion.extent.height = params.srcExtents[1];
|
||||
+ resolveRegion.extent.width = params.blitArea.width;
|
||||
+ resolveRegion.extent.height = params.blitArea.height;
|
||||
resolveRegion.extent.depth = 1;
|
||||
|
||||
vk::PerfCounters &perfCounters = contextVk->getPerfCounters();
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index 5712456966c3a77ba73295c083888ad0ab821a78..b9a0423345ba3a19e425a0b7ba7985ca191fdae7 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -70,6 +70,7 @@
|
||||
// the test says. The test also fails on Intel/Vulkan/Windows.
|
||||
6068 INTEL VULKAN : MultiviewRenderPrimitiveTest.LineLoop/* = SKIP
|
||||
6068 INTEL VULKAN : MultiviewRenderPrimitiveTest.LineStrip/* = SKIP
|
||||
+6962 WIN INTEL VULKAN : BlitFramebufferTestES31.PartialResolve/* = SKIP
|
||||
|
||||
// Mac
|
||||
6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8Index/* = SKIP
|
||||
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
|
||||
index affed96be99a8e0b819919ce971968168c546ca1..22356a7c65339fe8b1e601f54a3491ea77237432 100644
|
||||
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
|
||||
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
|
||||
@@ -2637,6 +2637,67 @@ TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
|
||||
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
|
||||
}
|
||||
|
||||
+// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents
|
||||
+// as the resolve area instead of the area passed to glBlitFramebuffer.
|
||||
+TEST_P(BlitFramebufferTestES31, PartialResolve)
|
||||
+{
|
||||
+ constexpr GLint kWidth = 16;
|
||||
+ constexpr GLint kHeight = 32;
|
||||
+
|
||||
+ // Read framebuffer is multisampled.
|
||||
+ GLTexture readTexture;
|
||||
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture);
|
||||
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE);
|
||||
+
|
||||
+ GLFramebuffer readFbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
|
||||
+ readTexture, 0);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ glClearColor(1, 0, 0, 1);
|
||||
+ glClear(GL_COLOR_BUFFER_BIT);
|
||||
+
|
||||
+ // Draw framebuffer is single sampled. It's bound to a texture with base level the same size as
|
||||
+ // the read framebuffer, but it's bound to mip 1.
|
||||
+ GLTexture drawTexture;
|
||||
+ glBindTexture(GL_TEXTURE_2D, drawTexture);
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ nullptr);
|
||||
+ glGenerateMipmap(GL_TEXTURE_2D);
|
||||
+
|
||||
+ GLFramebuffer drawFbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, drawFbo);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 1);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ glClearColor(0, 1, 0, 1);
|
||||
+ glClear(GL_COLOR_BUFFER_BIT);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, GLColor::green);
|
||||
+
|
||||
+ constexpr GLint kResolveX0 = 1;
|
||||
+ constexpr GLint kResolveY0 = 2;
|
||||
+ constexpr GLint kResolveX1 = 4;
|
||||
+ constexpr GLint kResolveY1 = 6;
|
||||
+
|
||||
+ // Resolve only a portion of the read framebuffer.
|
||||
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
|
||||
+ glBlitFramebuffer(kResolveX0, kResolveY0, kResolveX1, kResolveY1, kResolveX0, kResolveY0,
|
||||
+ kResolveX1, kResolveY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+
|
||||
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kResolveY0, GLColor::green);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, 0, kResolveX0, kHeight / 2, GLColor::green);
|
||||
+ EXPECT_PIXEL_RECT_EQ(kResolveX1, 0, kWidth / 2 - kResolveX1, kHeight / 2, GLColor::green);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, kResolveY1, kWidth / 2, kHeight / 2 - kResolveY1, GLColor::green);
|
||||
+
|
||||
+ EXPECT_PIXEL_RECT_EQ(kResolveX0, kResolveY0, kResolveX1 - kResolveX0, kResolveY1 - kResolveY0,
|
||||
+ GLColor::red);
|
||||
+}
|
||||
+
|
||||
// Test that a draw call to a small FBO followed by a resolve of a large FBO works.
|
||||
TEST_P(BlitFramebufferTestES31, DrawToSmallFBOThenResolveLargeFBO)
|
||||
{
|
||||
109
patches/angle/m98_vulkan_fix_vkcmdresolveimage_offsets.patch
Normal file
109
patches/angle/m98_vulkan_fix_vkcmdresolveimage_offsets.patch
Normal file
@@ -0,0 +1,109 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Mon, 7 Feb 2022 13:46:46 -0500
|
||||
Subject: M98: Vulkan: Fix vkCmdResolveImage offsets
|
||||
|
||||
glBlitFramebuffer takes identical regions for src and dst when
|
||||
resolving. vkCmdResolveImage should use the clipped area instead of
|
||||
using the actual offsets passed to this function.
|
||||
|
||||
Bug: chromium:1292537
|
||||
Change-Id: If283a8acbca3249b771facbc30bd9f8080a03656
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3457023
|
||||
Reviewed-by: Tim Van Patten <timvp@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
|
||||
index ac4c4086c28be29a65386ef06cc103d14dfb0d48..45308e0261b48eed17d144169b698165b04422f9 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
|
||||
@@ -1451,13 +1451,13 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
|
||||
resolveRegion.srcSubresource.mipLevel = 0;
|
||||
resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer;
|
||||
resolveRegion.srcSubresource.layerCount = 1;
|
||||
- resolveRegion.srcOffset.x = params.srcOffset[0];
|
||||
- resolveRegion.srcOffset.y = params.srcOffset[1];
|
||||
+ resolveRegion.srcOffset.x = params.blitArea.x;
|
||||
+ resolveRegion.srcOffset.y = params.blitArea.y;
|
||||
resolveRegion.srcOffset.z = 0;
|
||||
resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
resolveRegion.dstSubresource.layerCount = 1;
|
||||
- resolveRegion.dstOffset.x = params.destOffset[0];
|
||||
- resolveRegion.dstOffset.y = params.destOffset[1];
|
||||
+ resolveRegion.dstOffset.x = params.blitArea.x;
|
||||
+ resolveRegion.dstOffset.y = params.blitArea.y;
|
||||
resolveRegion.dstOffset.z = 0;
|
||||
resolveRegion.extent.width = params.blitArea.width;
|
||||
resolveRegion.extent.height = params.blitArea.height;
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index b9a0423345ba3a19e425a0b7ba7985ca191fdae7..0646a12afacc16fd7df938e615976a28b6da6ab0 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -15,6 +15,8 @@
|
||||
6142 VULKAN : BlitFramebufferTest.BlitDepthStencilPixelByPixel/* = SKIP
|
||||
6153 VULKAN WIN INTEL : GLSLTest_ES31.StructAndArrayEqualOperator/ES3_1_Vulkan_DirectSPIRVGen = SKIP
|
||||
6153 VULKAN PIXEL4ORXL : GLSLTest_ES31.StructAndArrayEqualOperator/ES3_1_Vulkan_DirectSPIRVGen = SKIP
|
||||
+6989 OPENGL : BlitFramebufferTestES31.OOBResolve/* = SKIP
|
||||
+6989 GLES : BlitFramebufferTestES31.OOBResolve/* = SKIP
|
||||
|
||||
// Direct SPIR-V generation. The following tests pass on some platforms but not others. Need to investigate.
|
||||
4889 VULKAN : GeometryShaderTest.LayeredFramebufferPreRenderClear2DArrayColor/ES3_1_Vulkan_DirectSPIRVGen = SKIP
|
||||
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
|
||||
index 22356a7c65339fe8b1e601f54a3491ea77237432..697cfcc8e10db571a407c0e44da36583614f2cb8 100644
|
||||
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
|
||||
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
|
||||
@@ -2637,6 +2637,55 @@ TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
|
||||
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
|
||||
}
|
||||
|
||||
+// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was used with
|
||||
+// out-of-bounds regions.
|
||||
+TEST_P(BlitFramebufferTestES31, OOBResolve)
|
||||
+{
|
||||
+ constexpr GLint kWidth = 16;
|
||||
+ constexpr GLint kHeight = 32;
|
||||
+
|
||||
+ // Read framebuffer is multisampled.
|
||||
+ GLTexture readTexture;
|
||||
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture);
|
||||
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE);
|
||||
+
|
||||
+ GLFramebuffer readFbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
|
||||
+ readTexture, 0);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ glClearColor(1, 0, 0, 1);
|
||||
+ glClear(GL_COLOR_BUFFER_BIT);
|
||||
+
|
||||
+ // Draw framebuffer is single sampled.
|
||||
+ GLTexture drawTexture;
|
||||
+ glBindTexture(GL_TEXTURE_2D, drawTexture);
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ nullptr);
|
||||
+ glGenerateMipmap(GL_TEXTURE_2D);
|
||||
+
|
||||
+ GLFramebuffer drawFbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, drawFbo);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 0);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ glClearColor(0, 1, 0, 1);
|
||||
+ glClear(GL_COLOR_BUFFER_BIT);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
|
||||
+
|
||||
+ // Resolve the read framebuffer, using bounds that are outside the size of the image.
|
||||
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
|
||||
+ glBlitFramebuffer(-kWidth * 2, -kHeight * 3, kWidth * 11, kHeight * 8, -kWidth * 2,
|
||||
+ -kHeight * 3, kWidth * 11, kHeight * 8, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+
|
||||
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
|
||||
+}
|
||||
+
|
||||
// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents
|
||||
// as the resolve area instead of the area passed to glBlitFramebuffer.
|
||||
TEST_P(BlitFramebufferTestES31, PartialResolve)
|
||||
@@ -0,0 +1,303 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Roman Lavrov <romanl@google.com>
|
||||
Date: Tue, 18 Jan 2022 20:05:55 +0000
|
||||
Subject: M99: Vulkan: Prevent out of bounds read in divisor emulation path.
|
||||
|
||||
Split the replicated part of StreamVertexData out to
|
||||
StreamVertexDataWithDivisor, there is only a partial argument
|
||||
overlap between the two.
|
||||
|
||||
Bug: chromium:1285885
|
||||
Change-Id: Ibf6ab3efc6b12b430b1d391c6ae61bd9668b4407
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3398816
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Commit-Queue: Roman Lavrov <romanl@google.com>
|
||||
(cherry picked from commit 5f0badf4541ba52659c937cfe9190d3735a76c10)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3461414
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
index ed416508cab06797a8c4d52e7ab982d538f57e3c..1ca486af3ff004e11aea82c391b4c504b569096c 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
@@ -81,34 +81,62 @@ angle::Result StreamVertexData(ContextVk *contextVk,
|
||||
size_t destOffset,
|
||||
size_t vertexCount,
|
||||
size_t sourceStride,
|
||||
- size_t destStride,
|
||||
VertexCopyFunction vertexLoadFunction,
|
||||
vk::BufferHelper **bufferOut,
|
||||
- VkDeviceSize *bufferOffsetOut,
|
||||
- uint32_t replicateCount)
|
||||
+ VkDeviceSize *bufferOffsetOut)
|
||||
{
|
||||
uint8_t *dst = nullptr;
|
||||
ANGLE_TRY(dynamicBuffer->allocate(contextVk, bytesToAllocate, &dst, nullptr, bufferOffsetOut,
|
||||
nullptr));
|
||||
*bufferOut = dynamicBuffer->getCurrentBuffer();
|
||||
dst += destOffset;
|
||||
- if (replicateCount == 1)
|
||||
+ vertexLoadFunction(sourceData, sourceStride, vertexCount, dst);
|
||||
+
|
||||
+ ANGLE_TRY(dynamicBuffer->flush(contextVk));
|
||||
+ return angle::Result::Continue;
|
||||
+}
|
||||
+
|
||||
+angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
|
||||
+ vk::DynamicBuffer *dynamicBuffer,
|
||||
+ const uint8_t *sourceData,
|
||||
+ size_t bytesToAllocate,
|
||||
+ size_t sourceStride,
|
||||
+ size_t destStride,
|
||||
+ VertexCopyFunction vertexLoadFunction,
|
||||
+ vk::BufferHelper **bufferOut,
|
||||
+ VkDeviceSize *bufferOffsetOut,
|
||||
+ uint32_t divisor,
|
||||
+ size_t numSrcVertices)
|
||||
+{
|
||||
+ uint8_t *dst = nullptr;
|
||||
+ ANGLE_TRY(dynamicBuffer->allocate(contextVk, bytesToAllocate, &dst, nullptr, bufferOffsetOut,
|
||||
+ nullptr));
|
||||
+ *bufferOut = dynamicBuffer->getCurrentBuffer();
|
||||
+
|
||||
+ // Each source vertex is used `divisor` times before advancing. Clamp to avoid OOB reads.
|
||||
+ size_t clampedSize = std::min(numSrcVertices * destStride * divisor, bytesToAllocate);
|
||||
+
|
||||
+ ASSERT(clampedSize % destStride == 0);
|
||||
+ ASSERT(divisor > 0);
|
||||
+
|
||||
+ uint32_t sourceVertexUseCount = 0;
|
||||
+ for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += destStride, dst += destStride)
|
||||
{
|
||||
- vertexLoadFunction(sourceData, sourceStride, vertexCount, dst);
|
||||
+ vertexLoadFunction(sourceData, sourceStride, 1, dst);
|
||||
+ sourceVertexUseCount++;
|
||||
+ if (sourceVertexUseCount == divisor)
|
||||
+ {
|
||||
+ sourceData += sourceStride;
|
||||
+ sourceVertexUseCount = 0;
|
||||
+ }
|
||||
}
|
||||
- else
|
||||
+
|
||||
+ // Satisfy robustness constraints (only if extension enabled)
|
||||
+ if (contextVk->getExtensions().robustness)
|
||||
{
|
||||
- ASSERT(replicateCount > 1);
|
||||
- uint32_t sourceRemainingCount = replicateCount - 1;
|
||||
- for (size_t dataCopied = 0; dataCopied < bytesToAllocate;
|
||||
- dataCopied += destStride, dst += destStride, sourceRemainingCount--)
|
||||
+ if (clampedSize < bytesToAllocate)
|
||||
{
|
||||
- vertexLoadFunction(sourceData, sourceStride, 1, dst);
|
||||
- if (sourceRemainingCount == 0)
|
||||
- {
|
||||
- sourceData += sourceStride;
|
||||
- sourceRemainingCount = replicateCount;
|
||||
- }
|
||||
+ memset(dst + clampedSize, 0, bytesToAllocate - clampedSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +152,7 @@ size_t GetVertexCount(BufferVk *srcBuffer, const gl::VertexBinding &binding, uin
|
||||
return 0;
|
||||
|
||||
// Count the last vertex. It may occupy less than a full stride.
|
||||
+ // This is also correct if stride happens to be less than srcFormatSize.
|
||||
size_t numVertices = 1;
|
||||
bytes -= srcFormatSize;
|
||||
|
||||
@@ -452,8 +481,8 @@ angle::Result VertexArrayVk::convertVertexBufferCPU(ContextVk *contextVk,
|
||||
ASSERT(GetVertexInputAlignment(vertexFormat, compressed) <= vk::kVertexBufferAlignment);
|
||||
ANGLE_TRY(StreamVertexData(
|
||||
contextVk, &conversion->data, srcBytes, numVertices * dstFormatSize, 0, numVertices,
|
||||
- binding.getStride(), srcFormatSize, vertexFormat.getVertexLoadFunction(compressed),
|
||||
- &mCurrentArrayBuffers[attribIndex], &conversion->lastAllocationOffset, 1));
|
||||
+ binding.getStride(), vertexFormat.getVertexLoadFunction(compressed),
|
||||
+ &mCurrentArrayBuffers[attribIndex], &conversion->lastAllocationOffset));
|
||||
ANGLE_TRY(srcBuffer->unmapImpl(contextVk));
|
||||
|
||||
ASSERT(conversion->dirty);
|
||||
@@ -808,28 +837,41 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
|
||||
// Instanced attrib
|
||||
if (divisor > renderer->getMaxVertexAttribDivisor())
|
||||
{
|
||||
- // Emulated attrib
|
||||
- BufferVk *bufferVk = nullptr;
|
||||
+ // Divisor will be set to 1 & so update buffer to have 1 attrib per instance
|
||||
+ size_t bytesToAllocate = instanceCount * stride;
|
||||
+
|
||||
if (binding.getBuffer().get() != nullptr)
|
||||
{
|
||||
// Map buffer to expand attribs for divisor emulation
|
||||
- bufferVk = vk::GetImpl(binding.getBuffer().get());
|
||||
- void *buffSrc = nullptr;
|
||||
+ BufferVk *bufferVk = vk::GetImpl(binding.getBuffer().get());
|
||||
+ void *buffSrc = nullptr;
|
||||
ANGLE_TRY(bufferVk->mapImpl(contextVk, &buffSrc));
|
||||
src = reinterpret_cast<const uint8_t *>(buffSrc) + binding.getOffset();
|
||||
- }
|
||||
- // Divisor will be set to 1 & so update buffer to have 1 attrib per instance
|
||||
- size_t bytesToAllocate = instanceCount * stride;
|
||||
|
||||
- ANGLE_TRY(StreamVertexData(contextVk, &mDynamicVertexData, src, bytesToAllocate, 0,
|
||||
- instanceCount, binding.getStride(), stride,
|
||||
- vertexFormat.vertexLoadFunction,
|
||||
- &mCurrentArrayBuffers[attribIndex],
|
||||
- &mCurrentArrayBufferOffsets[attribIndex], divisor));
|
||||
- if (bufferVk)
|
||||
- {
|
||||
+ uint32_t srcAttributeSize =
|
||||
+ static_cast<uint32_t>(ComputeVertexAttributeTypeSize(attrib));
|
||||
+
|
||||
+ size_t numVertices = GetVertexCount(bufferVk, binding, srcAttributeSize);
|
||||
+
|
||||
+ ANGLE_TRY(StreamVertexDataWithDivisor(
|
||||
+ contextVk, &mDynamicVertexData, src, bytesToAllocate, binding.getStride(),
|
||||
+ stride, vertexFormat.vertexLoadFunction,
|
||||
+ &mCurrentArrayBuffers[attribIndex],
|
||||
+ &mCurrentArrayBufferOffsets[attribIndex], divisor,
|
||||
+ numVertices));
|
||||
+
|
||||
ANGLE_TRY(bufferVk->unmapImpl(contextVk));
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ size_t numVertices = instanceCount;
|
||||
+ ANGLE_TRY(StreamVertexDataWithDivisor(
|
||||
+ contextVk, &mDynamicVertexData, src, bytesToAllocate, binding.getStride(),
|
||||
+ stride, vertexFormat.vertexLoadFunction,
|
||||
+ &mCurrentArrayBuffers[attribIndex],
|
||||
+ &mCurrentArrayBufferOffsets[attribIndex], divisor,
|
||||
+ numVertices));
|
||||
+ }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -838,10 +880,10 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
|
||||
size_t bytesToAllocate = count * stride;
|
||||
|
||||
ANGLE_TRY(StreamVertexData(contextVk, &mDynamicVertexData, src, bytesToAllocate, 0,
|
||||
- count, binding.getStride(), stride,
|
||||
+ count, binding.getStride(),
|
||||
vertexFormat.vertexLoadFunction,
|
||||
&mCurrentArrayBuffers[attribIndex],
|
||||
- &mCurrentArrayBufferOffsets[attribIndex], 1));
|
||||
+ &mCurrentArrayBufferOffsets[attribIndex]));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -856,8 +898,8 @@ angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
|
||||
|
||||
ANGLE_TRY(StreamVertexData(
|
||||
contextVk, &mDynamicVertexData, src, bytesToAllocate, destOffset, vertexCount,
|
||||
- binding.getStride(), stride, vertexFormat.vertexLoadFunction,
|
||||
- &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex], 1));
|
||||
+ binding.getStride(), vertexFormat.vertexLoadFunction,
|
||||
+ &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex]));
|
||||
}
|
||||
|
||||
mCurrentArrayBufferHandles[attribIndex] =
|
||||
diff --git a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
|
||||
index 08917a2de3385eb853bced1dd576aff46f34f709..db708b0a2a3ce90a370b43786af6884b2f992bef 100644
|
||||
--- a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
|
||||
+++ b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
|
||||
@@ -564,6 +564,98 @@ TEST_P(RobustBufferAccessBehaviorTest, DynamicBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
+// Tests out of bounds read by divisor emulation due to a user-provided offset.
|
||||
+// Adapted from https://crbug.com/1285885.
|
||||
+TEST_P(RobustBufferAccessBehaviorTest, IndexOutOfBounds)
|
||||
+{
|
||||
+ ANGLE_SKIP_TEST_IF(!initExtension());
|
||||
+
|
||||
+ constexpr char kVS[] = R"(precision highp float;
|
||||
+attribute vec4 a_position;
|
||||
+void main(void) {
|
||||
+ gl_Position = a_position;
|
||||
+})";
|
||||
+
|
||||
+ constexpr char kFS[] = R"(precision highp float;
|
||||
+uniform sampler2D oTexture;
|
||||
+uniform float oColor[3];
|
||||
+void main(void) {
|
||||
+ gl_FragData[0] = texture2DProj(oTexture, vec3(0.1,0.1,0.1));
|
||||
+})";
|
||||
+
|
||||
+ GLfloat singleFloat = 1.0f;
|
||||
+
|
||||
+ GLBuffer buf;
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, buf);
|
||||
+ glBufferData(GL_ARRAY_BUFFER, 4, &singleFloat, GL_STATIC_DRAW);
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
|
||||
+ glBindAttribLocation(program, 0, "a_position");
|
||||
+ glLinkProgram(program);
|
||||
+ ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
|
||||
+
|
||||
+ glEnableVertexAttribArray(0);
|
||||
+
|
||||
+ // Trying to exceed renderer->getMaxVertexAttribDivisor()
|
||||
+ GLuint constexpr kDivisor = 4096;
|
||||
+ glVertexAttribDivisor(0, kDivisor);
|
||||
+
|
||||
+ size_t outOfBoundsOffset = 0x50000000;
|
||||
+ glVertexAttribPointer(0, 1, GL_FLOAT, false, 8, reinterpret_cast<void *>(outOfBoundsOffset));
|
||||
+
|
||||
+ glUseProgram(program);
|
||||
+
|
||||
+ glDrawArrays(GL_TRIANGLES, 0, 32);
|
||||
+
|
||||
+ // No assertions, just checking for crashes.
|
||||
+}
|
||||
+
|
||||
+// Similar to the test above but index is first within bounds then goes out of bounds.
|
||||
+TEST_P(RobustBufferAccessBehaviorTest, IndexGoingOutOfBounds)
|
||||
+{
|
||||
+ ANGLE_SKIP_TEST_IF(!initExtension());
|
||||
+
|
||||
+ constexpr char kVS[] = R"(precision highp float;
|
||||
+attribute vec4 a_position;
|
||||
+void main(void) {
|
||||
+ gl_Position = a_position;
|
||||
+})";
|
||||
+
|
||||
+ constexpr char kFS[] = R"(precision highp float;
|
||||
+uniform sampler2D oTexture;
|
||||
+uniform float oColor[3];
|
||||
+void main(void) {
|
||||
+ gl_FragData[0] = texture2DProj(oTexture, vec3(0.1,0.1,0.1));
|
||||
+})";
|
||||
+
|
||||
+ GLBuffer buf;
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, buf);
|
||||
+ std::array<GLfloat, 2> buffer = {{0.2f, 0.2f}};
|
||||
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * buffer.size(), buffer.data(), GL_STATIC_DRAW);
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
|
||||
+ glBindAttribLocation(program, 0, "a_position");
|
||||
+ glLinkProgram(program);
|
||||
+ ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
|
||||
+
|
||||
+ glEnableVertexAttribArray(0);
|
||||
+
|
||||
+ // Trying to exceed renderer->getMaxVertexAttribDivisor()
|
||||
+ GLuint constexpr kDivisor = 4096;
|
||||
+ glVertexAttribDivisor(0, kDivisor);
|
||||
+
|
||||
+ // 6 bytes remaining in the buffer from offset so only a single vertex can be read
|
||||
+ glVertexAttribPointer(0, 1, GL_FLOAT, false, 8, reinterpret_cast<void *>(2));
|
||||
+
|
||||
+ glUseProgram(program);
|
||||
+
|
||||
+ // Each vertex is read `kDivisor` times so the last read goes out of bounds
|
||||
+ GLsizei instanceCount = kDivisor + 1;
|
||||
+ glDrawArraysInstanced(GL_TRIANGLES, 0, 32, instanceCount);
|
||||
+
|
||||
+ // No assertions, just checking for crashes.
|
||||
+}
|
||||
+
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(RobustBufferAccessBehaviorTest);
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Charlie Lao <cclao@google.com>
|
||||
Date: Mon, 7 Feb 2022 15:08:15 -0800
|
||||
Subject: M99: Vulkan: StreamVertexDataWithDivisor write beyond buffer boundary
|
||||
|
||||
StreamVertexDataWithDivisor() function is advancing dst with dstStride,
|
||||
but then later on it is treating dst as if it never advanced, thus
|
||||
result in write out of buffer boundary. This was hidden by VMA's memory
|
||||
suballocation, which means it may result in some rendering artifacts.
|
||||
|
||||
Bug: angleproject:6990
|
||||
Change-Id: Ic91e917cedd247dfe85b12a69ae26b21b7a4e67a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3445528
|
||||
Reviewed-by: Roman Lavrov <romanl@google.com>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Commit-Queue: Charlie Lao <cclao@google.com>
|
||||
(cherry picked from commit 5204587698099207ce8ae70779ef44ffae877996)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3461417
|
||||
Reviewed-by: Charlie Lao <cclao@google.com>
|
||||
Commit-Queue: Roman Lavrov <romanl@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
index 1ca486af3ff004e11aea82c391b4c504b569096c..93378c4b24495872405fc06ea01e15254229ab63 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
|
||||
@@ -120,7 +120,7 @@ angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
|
||||
ASSERT(divisor > 0);
|
||||
|
||||
uint32_t sourceVertexUseCount = 0;
|
||||
- for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += destStride, dst += destStride)
|
||||
+ for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += destStride)
|
||||
{
|
||||
vertexLoadFunction(sourceData, sourceStride, 1, dst);
|
||||
sourceVertexUseCount++;
|
||||
@@ -129,6 +129,7 @@ angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
|
||||
sourceData += sourceStride;
|
||||
sourceVertexUseCount = 0;
|
||||
}
|
||||
+ dst += destStride;
|
||||
}
|
||||
|
||||
// Satisfy robustness constraints (only if extension enabled)
|
||||
@@ -136,7 +137,7 @@ angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
|
||||
{
|
||||
if (clampedSize < bytesToAllocate)
|
||||
{
|
||||
- memset(dst + clampedSize, 0, bytesToAllocate - clampedSize);
|
||||
+ memset(dst, 0, bytesToAllocate - clampedSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Peng Huang <penghuang@chromium.org>
|
||||
Date: Mon, 25 Oct 2021 15:45:36 -0400
|
||||
Subject: VANGLE: change the default vulkan device choose logic
|
||||
|
||||
To match the vulkan device choose logic in chrome, ANGLE will choose
|
||||
the default device based on the order of (discret GPU > integrated GPU
|
||||
> other GPU)
|
||||
|
||||
TODO: for long term, ANGLE should provide a way to let chrome specify
|
||||
the physical device.
|
||||
|
||||
Bug: chromium:1260869
|
||||
Change-Id: Id023138485eb65fcc1d2758103d59a4e6cb2a51d
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3242963
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Commit-Queue: Peng Huang <penghuang@chromium.org>
|
||||
|
||||
diff --git a/src/common/vulkan/vulkan_icd.cpp b/src/common/vulkan/vulkan_icd.cpp
|
||||
index 0ed7ae2aa058792b700503dfdb6fd91b05bf68fb..df14f5f674b37c49332e43ccba8f1782cb13f495 100644
|
||||
--- a/src/common/vulkan/vulkan_icd.cpp
|
||||
+++ b/src/common/vulkan/vulkan_icd.cpp
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
+#include "common/Optional.h"
|
||||
#include "common/bitset_utils.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/system_utils.h"
|
||||
@@ -94,8 +95,7 @@ ICDFilterFunc GetFilterForICD(vk::ICD preferredICD)
|
||||
const std::string anglePreferredDevice =
|
||||
angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
|
||||
return [anglePreferredDevice](const VkPhysicalDeviceProperties &deviceProperties) {
|
||||
- return (anglePreferredDevice.empty() ||
|
||||
- anglePreferredDevice == deviceProperties.deviceName);
|
||||
+ return (anglePreferredDevice == deviceProperties.deviceName);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -262,9 +262,37 @@ void ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> &physicalDevices,
|
||||
return;
|
||||
}
|
||||
}
|
||||
- WARN() << "Preferred device ICD not found. Using default physicalDevice instead.";
|
||||
|
||||
- // Fall back to first device.
|
||||
+ Optional<VkPhysicalDevice> integratedDevice;
|
||||
+ VkPhysicalDeviceProperties integratedDeviceProperties;
|
||||
+ for (const VkPhysicalDevice &physicalDevice : physicalDevices)
|
||||
+ {
|
||||
+ vkGetPhysicalDeviceProperties(physicalDevice, physicalDevicePropertiesOut);
|
||||
+ // If discrete GPU exists, uses it by default.
|
||||
+ if (physicalDevicePropertiesOut->deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
+ {
|
||||
+ *physicalDeviceOut = physicalDevice;
|
||||
+ return;
|
||||
+ }
|
||||
+ if (physicalDevicePropertiesOut->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU &&
|
||||
+ !integratedDevice.valid())
|
||||
+ {
|
||||
+ integratedDevice = physicalDevice;
|
||||
+ integratedDeviceProperties = *physicalDevicePropertiesOut;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // If only integrated GPU exists, use it by default.
|
||||
+ if (integratedDevice.valid())
|
||||
+ {
|
||||
+ *physicalDeviceOut = integratedDevice.value();
|
||||
+ *physicalDevicePropertiesOut = integratedDeviceProperties;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ WARN() << "Preferred device ICD not found. Using default physicalDevice instead.";
|
||||
+ // Fallback to the first device.
|
||||
*physicalDeviceOut = physicalDevices[0];
|
||||
vkGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut);
|
||||
}
|
||||
@@ -106,3 +106,79 @@ feat_expose_raw_response_headers_from_urlloader.patch
|
||||
fix_media_key_usage_with_globalshortcuts.patch
|
||||
cherry-pick-ec42dfd3545f.patch
|
||||
cherry-pick-39090918efac.patch
|
||||
add_ui_scopedcliboardwriter_writeunsaferawdata.patch
|
||||
mas_gate_private_enterprise_APIs.patch
|
||||
cherry-pick-8af66de55aad.patch
|
||||
cherry-pick-c69dddfe1cde.patch
|
||||
cherry-pick-2e7c9b33453b.patch
|
||||
move_networkstateobserver_from_document_to_window.patch
|
||||
cherry-pick-0894af410c4e.patch
|
||||
cherry-pick-91dd4f79ab5b.patch
|
||||
introduce_crossthreadcopier_skbitmap.patch
|
||||
allow_null_skbitmap_to_be_transferred_across_threads.patch
|
||||
use_weakptrs_for_the_threadediconloader_s_background_tasks.patch
|
||||
cherry-pick-1a8af2da50e4.patch
|
||||
cherry-pick-a5f54612590d.patch
|
||||
cachestorage_store_partial_opaque_responses.patch
|
||||
fix_aspect_ratio_with_max_size.patch
|
||||
cherry-pick-f0a63e1f361f.patch
|
||||
cherry-pick-27eb11a28555.patch
|
||||
sandbox_fix_sandbox_inheritance_m96_merge.patch
|
||||
cherry-pick-da11d71a0227.patch
|
||||
cherry-pick-dbde8795233a.patch
|
||||
cherry-pick-6bb320d134b1.patch
|
||||
cherry-pick-109fde1088be.patch
|
||||
m96_fileapi_move_origin_checks_in_bloburlstore_sooner.patch
|
||||
cherry-pick-f781748dcb3c.patch
|
||||
cherry-pick-c5571653d932.patch
|
||||
fix_crash_when_saving_edited_pdf_files.patch
|
||||
use_axnodeid_rather_than_axnode_in_axeventgenerator_tree_events.patch
|
||||
mojo_reject_addbrokerclient_on_non-broker_nodes.patch
|
||||
cherry-pick-1277917.patch
|
||||
cherry-pick-1281979.patch
|
||||
cherry-pick-1282354.patch
|
||||
cherry-pick-1283198.patch
|
||||
cherry-pick-1283375.patch
|
||||
cherry-pick-1283371.patch
|
||||
cherry-pick-9db9911e1242.patch
|
||||
cherry-pick-1284367.patch
|
||||
m97_webcodecs_various_decodertemplate_shutdown_cleanups.patch
|
||||
96_take_local_copy_of_ump_local_sources_to_iterate.patch
|
||||
pin_scrolltop_to_0_during_autofill_preview.patch
|
||||
fix_preview_state_detection.patch
|
||||
do_not_select_vulkan_device_based_on_the_passed_in_gpu_info_on_linux.patch
|
||||
handle_potentiallydanglingmarkup_for_cssimagevalue.patch
|
||||
fire_iframe_onload_for_cross-origin-initiated_same-document.patch
|
||||
merge_m-97_serial_check_for_detached_buffers_when_writing.patch
|
||||
cleanup_pausablecriptexecutor_usage.patch
|
||||
m98_fs_fix_fileutil_lifetime_issue.patch
|
||||
cherry-pick-be50c60b4225.patch
|
||||
cherry-pick-ebc188ad769e.patch
|
||||
cherry-pick-e3805f29fed7.patch
|
||||
cherry-pick-0081bb347e67.patch
|
||||
cherry-pick-62142d222a80.patch
|
||||
cherry-pick-1887414c016d.patch
|
||||
cherry-pick-6b2643846ae3.patch
|
||||
cherry-pick-905302eb3a2b.patch
|
||||
cherry-pick-246c10dede97.patch
|
||||
fix_imagebitmaprenderingcontext_interaction_with_software_compositor.patch
|
||||
remove_incorrect_width_height_adjustments.patch
|
||||
fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch
|
||||
fixed_terminate_caused_by_binding_to_wrong_version.patch
|
||||
follow_wayland_specification_regarding_xkb_keymap.patch
|
||||
cherry-pick-1665a1d16d46.patch
|
||||
cherry-pick-4d26949260aa.patch
|
||||
use-after-free_of_id_and_idref_attributes.patch
|
||||
fix_--without-valid_build.patch
|
||||
usb_fix_oob_access_with_non-sequential_interfaces.patch
|
||||
skia_renderer_-_don_t_explicitly_clip_scissor_for_large_transforms.patch
|
||||
skia_renderer_use_rectf_intersect_in_applyscissor.patch
|
||||
cherry-pick-1a31e2110440.patch
|
||||
m100_change_ownership_of_blobbytesprovider.patch
|
||||
cherry-pick-5be8e065f43e.patch
|
||||
m96-lts_add_bounds_check_to_webgpudecoderimpl_dorequestdevice.patch
|
||||
cherry-pick-5ff02e4d7368.patch
|
||||
cherry-pick-12ba78f3fa7a.patch
|
||||
reland_fix_noopener_case_for_user_activation_consumption.patch
|
||||
cherry-pick-99c3f3bfd507.patch
|
||||
cherry-pick-ec0cce63f47d.patch
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Herre <toprice@chromium.org>
|
||||
Date: Tue, 14 Dec 2021 16:35:05 +0000
|
||||
Subject: Take local copy of UMP::local_sources to iterate
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Take a local copy of UserMediaProcessor::local_sources_ when iterating
|
||||
over it in UserMediaProcessor::DetermineExistingAudioSessionId, as the
|
||||
list can be effectively concurrently modified during destruction of
|
||||
MediaStreamTracks triggered by GC during this loop. Without the copy
|
||||
this leads to a container overflow.
|
||||
|
||||
(cherry picked from commit fb6232ffb1fec14d64ec8815f7dfc2cea0887588)
|
||||
|
||||
Bug: 1238209
|
||||
Change-Id: I048387a51a58eacff87d220e6b67d2d09f610c1d
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3320283
|
||||
Reviewed-by: Henrik Boström <hbos@chromium.org>
|
||||
Commit-Queue: Tony Herre <toprice@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#950499}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3337896
|
||||
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4664@{#1303}
|
||||
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
|
||||
index d42b3d7309ce40e74ebf386f4d38eb8cce008ec0..b0b8b15657210174b000a02f711a76fa16e5948d 100644
|
||||
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
|
||||
@@ -725,6 +725,7 @@ void UserMediaProcessor::SelectAudioSettings(
|
||||
|
||||
absl::optional<base::UnguessableToken>
|
||||
UserMediaProcessor::DetermineExistingAudioSessionId() {
|
||||
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
DCHECK(current_request_info_->request()->Audio());
|
||||
|
||||
auto settings = current_request_info_->audio_capture_settings();
|
||||
@@ -733,7 +734,12 @@ UserMediaProcessor::DetermineExistingAudioSessionId() {
|
||||
// Create a copy of the MediaStreamSource objects that are
|
||||
// associated to the same audio device capture based on its device ID.
|
||||
HeapVector<Member<MediaStreamSource>> matching_sources;
|
||||
- for (const auto& source : local_sources_) {
|
||||
+
|
||||
+ // Take a defensive copy, as local_sources_ can be modified during
|
||||
+ // destructions in GC runs triggered by the push_back allocation in this loop.
|
||||
+ // crbug.com/1238209
|
||||
+ HeapVector<Member<MediaStreamSource>> local_sources_copy = local_sources_;
|
||||
+ for (const auto& source : local_sources_copy) {
|
||||
MediaStreamSource* source_copy = source;
|
||||
if (source_copy->GetType() == MediaStreamSource::kTypeAudio &&
|
||||
source_copy->Id().Utf8() == device_id) {
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Henri Torgemane <henrit@gmail.com>
|
||||
Date: Thu, 23 Sep 2021 21:30:33 -0500
|
||||
Subject: add ui::ScopedCliboardWriter::WriteUnsafeRawData
|
||||
|
||||
This restores some ability to write to the clipboard using raw formats, which
|
||||
was removed as part of the Raw Clipboard API scrubbing.
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=1217643
|
||||
|
||||
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
index 153f169d2cdef6f8a726c188283a5bc1b7395fa3..3a5d9ab8dafacafb1025e1cb8c157e8a82078424 100644
|
||||
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
@@ -212,6 +212,16 @@ void ScopedClipboardWriter::WriteData(const std::u16string& format,
|
||||
}
|
||||
}
|
||||
|
||||
+void ScopedClipboardWriter::WriteUnsafeRawData(const std::u16string& format,
|
||||
+ mojo_base::BigBuffer data) {
|
||||
+ static constexpr int kMaxRegisteredFormats = 100;
|
||||
+ if (counter_ >= kMaxRegisteredFormats)
|
||||
+ return;
|
||||
+ counter_++;
|
||||
+ platform_representations_.push_back(
|
||||
+ {base::UTF16ToUTF8(format), std::move(data)});
|
||||
+}
|
||||
+
|
||||
void ScopedClipboardWriter::Reset() {
|
||||
objects_.clear();
|
||||
platform_representations_.clear();
|
||||
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
index 879acd4f6f0101a6da3af58d78eeda877ea41a4a..4d4149b6aa34c7073804994cb1c03368830c736d 100644
|
||||
--- a/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
@@ -80,6 +80,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter {
|
||||
// This is only used to write custom format data.
|
||||
void WriteData(const std::u16string& format, mojo_base::BigBuffer data);
|
||||
|
||||
+ // write raw (non-pickled) data to the clipboard
|
||||
+ void WriteUnsafeRawData(const std::u16string& format,
|
||||
+ mojo_base::BigBuffer data);
|
||||
+
|
||||
void WriteImage(const SkBitmap& bitmap);
|
||||
|
||||
// Mark the data to be written as confidential.
|
||||
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yutaka Hirano <yhirano@chromium.org>
|
||||
Date: Tue, 9 Nov 2021 09:03:17 +0000
|
||||
Subject: Allow null SkBitmap to be transferred across threads
|
||||
|
||||
(cherry picked from commit dad0c0e5162bcc49b8f60354d3bca92224d8381b)
|
||||
|
||||
Bug: 1241091
|
||||
Change-Id: Ie96932c14c8884d6d3eafa76dab5043e7aa31888
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251815
|
||||
Reviewed-by: Florin Malita <fmalita@chromium.org>
|
||||
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#936861}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3268018
|
||||
Auto-Submit: Yutaka Hirano <yhirano@chromium.org>
|
||||
Reviewed-by: Kentaro Hara <haraken@chromium.org>
|
||||
Commit-Queue: Kentaro Hara <haraken@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4664@{#893}
|
||||
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
|
||||
index e4bde78252c90ecd19655e8c552a2a39299dff75..33d6a1f115c606c3f203b37642ad2875bcca1dd7 100644
|
||||
--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
|
||||
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
|
||||
@@ -212,11 +212,13 @@ struct CrossThreadCopier<SkBitmap> {
|
||||
|
||||
using Type = SkBitmap;
|
||||
static SkBitmap Copy(const SkBitmap& bitmap) {
|
||||
- CHECK(bitmap.isImmutable()) << "Only immutable bitmaps can be transferred.";
|
||||
+ CHECK(bitmap.isImmutable() || bitmap.isNull())
|
||||
+ << "Only immutable bitmaps can be transferred.";
|
||||
return bitmap;
|
||||
}
|
||||
static SkBitmap Copy(SkBitmap&& bitmap) {
|
||||
- CHECK(bitmap.isImmutable()) << "Only immutable bitmaps can be transferred.";
|
||||
+ CHECK(bitmap.isImmutable() || bitmap.isNull())
|
||||
+ << "Only immutable bitmaps can be transferred.";
|
||||
return std::move(bitmap);
|
||||
}
|
||||
};
|
||||
@@ -46,10 +46,10 @@ index 135ad9b24745f6d016806f3c95993efe65b370f3..c5e694cd56b9db940e8564c82e2773aa
|
||||
}
|
||||
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de5288ebaa 100644
|
||||
index 1004666505dc8c127bb2405571eba9ab60277e3f..700cc0d1f88d7873c1b29bc96e871983cc982403 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -5325,7 +5325,6 @@ test("unit_tests") {
|
||||
@@ -5329,7 +5329,6 @@ test("unit_tests") {
|
||||
assert(toolkit_views)
|
||||
sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
|
||||
deps += [
|
||||
@@ -57,7 +57,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
|
||||
"//chrome/browser:chrome_process_finder",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner:public",
|
||||
@@ -5338,6 +5337,12 @@ test("unit_tests") {
|
||||
@@ -5342,6 +5341,12 @@ test("unit_tests") {
|
||||
"//components/chrome_cleaner/public/proto",
|
||||
"//ui/events/devices:test_support",
|
||||
]
|
||||
@@ -70,7 +70,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
|
||||
}
|
||||
|
||||
# TODO(crbug.com/931218): Ninja cannot handle certain characters appearing
|
||||
@@ -5930,7 +5935,6 @@ test("unit_tests") {
|
||||
@@ -5934,7 +5939,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
@@ -78,7 +78,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
|
||||
"//chrome/browser:cart_db_content_proto",
|
||||
"//chrome/browser/media/router:test_support",
|
||||
"//chrome/browser/promo_browser_command:mojo_bindings",
|
||||
@@ -5966,6 +5970,9 @@ test("unit_tests") {
|
||||
@@ -5970,6 +5974,9 @@ test("unit_tests") {
|
||||
"//ui/color:test_support",
|
||||
"//ui/native_theme:test_support",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Kelly <wanderview@chromium.org>
|
||||
Date: Fri, 5 Nov 2021 19:47:08 +0000
|
||||
Subject: CacheStorage: Store partial opaque responses.
|
||||
|
||||
(cherry picked from commit 802faa035409ac7cbb58ad1a385bb8507fe99077)
|
||||
|
||||
Fixed: 1260649
|
||||
Change-Id: If83156096e6aecec55490330d03c56c0c26120bc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251749
|
||||
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
|
||||
Commit-Queue: Ben Kelly <wanderview@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#937400}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3264366
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4664@{#774}
|
||||
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
|
||||
|
||||
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
|
||||
index 08ed40551e5d66498931271845f345e45ed7272d..f26fcfc4c676d115f2128e843f27154d8a9e03b6 100644
|
||||
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
|
||||
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
|
||||
@@ -446,10 +446,10 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
|
||||
? metadata.response().request_include_credentials()
|
||||
: true;
|
||||
|
||||
- // Note that |has_range_requested| can be safely set to false since it only
|
||||
- // affects HTTP 206 (Partial) responses, which are blocked from cache storage.
|
||||
- // See https://fetch.spec.whatwg.org/#main-fetch for usage of
|
||||
- // |has_range_requested|.
|
||||
+ // While we block most partial responses from being stored, we can have
|
||||
+ // partial responses for bgfetch or opaque responses.
|
||||
+ bool has_range_requested = headers.contains(net::HttpRequestHeaders::kRange);
|
||||
+
|
||||
return blink::mojom::FetchAPIResponse::New(
|
||||
url_list, metadata.response().status_code(),
|
||||
metadata.response().status_text(),
|
||||
@@ -467,7 +467,7 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
|
||||
static_cast<net::HttpResponseInfo::ConnectionInfo>(
|
||||
metadata.response().connection_info()),
|
||||
alpn_negotiated_protocol, metadata.response().was_fetched_via_spdy(),
|
||||
- /*has_range_requested=*/false, /*auth_challenge_info=*/absl::nullopt,
|
||||
+ has_range_requested, /*auth_challenge_info=*/absl::nullopt,
|
||||
request_include_credentials);
|
||||
}
|
||||
|
||||
@@ -1888,7 +1888,13 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
|
||||
}
|
||||
|
||||
proto::CacheResponse* response_metadata = metadata.mutable_response();
|
||||
- DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT);
|
||||
+ if (owner_ != storage::mojom::CacheStorageOwner::kBackgroundFetch &&
|
||||
+ put_context->response->response_type !=
|
||||
+ network::mojom::FetchResponseType::kOpaque &&
|
||||
+ put_context->response->response_type !=
|
||||
+ network::mojom::FetchResponseType::kOpaqueRedirect) {
|
||||
+ DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT);
|
||||
+ }
|
||||
response_metadata->set_status_code(put_context->response->status_code);
|
||||
response_metadata->set_status_text(put_context->response->status_text);
|
||||
response_metadata->set_response_type(FetchResponseTypeToProtoResponseType(
|
||||
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc
|
||||
index c76c7677a17fd58be83d5e9f2bc263b710e528ae..8c267d2f54ae6e83b86d53dd473e2ed1354aa3c4 100644
|
||||
--- a/third_party/blink/renderer/modules/cache_storage/cache.cc
|
||||
+++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
|
||||
@@ -102,7 +102,7 @@ void ValidateResponseForPut(const Response* response,
|
||||
exception_state.ThrowTypeError("Vary header contains *");
|
||||
return;
|
||||
}
|
||||
- if (response->GetResponse()->InternalStatus() == 206) {
|
||||
+ if (response->GetResponse()->Status() == 206) {
|
||||
exception_state.ThrowTypeError(
|
||||
"Partial response (status code 206) is unsupported");
|
||||
return;
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js
|
||||
index b45910a3b8ba089e1724efa8b9e8a8d679c59320..f60c4b905ebcb61854b83177d59861ef92095624 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js
|
||||
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js
|
||||
@@ -144,7 +144,14 @@ cache_test(function(cache, test) {
|
||||
'Test framework error: The status code should be 0 for an ' +
|
||||
' opaque-filtered response. This is actually HTTP 206.');
|
||||
response = fetch_result.clone();
|
||||
- return promise_rejects_js(test, TypeError, cache.put(request, fetch_result));
|
||||
+ return cache.put(request, fetch_result);
|
||||
+ })
|
||||
+ .then(function() {
|
||||
+ return cache.match(test_url);
|
||||
+ })
|
||||
+ .then(function(result) {
|
||||
+ assert_not_equals(result, undefined,
|
||||
+ 'Cache.put should store an entry for the opaque response');
|
||||
});
|
||||
}, 'Cache.put with opaque-filtered HTTP 206 response');
|
||||
|
||||
26
patches/chromium/cherry-pick-0081bb347e67.patch
Normal file
26
patches/chromium/cherry-pick-0081bb347e67.patch
Normal file
@@ -0,0 +1,26 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Reynolds <mattreynolds@google.com>
|
||||
Date: Wed, 19 Jan 2022 21:03:08 +0000
|
||||
Subject: gamepad: Return an invalid handle after ReportBadMessage
|
||||
|
||||
Bug: 1285449
|
||||
Change-Id: I746c539577f7bdf69cbe4212ac380e0c92a5c771
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3373944
|
||||
Auto-Submit: Matt Reynolds <mattreynolds@chromium.org>
|
||||
Reviewed-by: Reilly Grant <reillyg@chromium.org>
|
||||
Commit-Queue: Reilly Grant <reillyg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#961125}
|
||||
|
||||
diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc
|
||||
index ce8ba1ef7551e52f8ae4d9a112a08308ab2ce51c..28082924e632a895fc5bc4725bc6de3d6ca120ac 100644
|
||||
--- a/device/gamepad/gamepad_monitor.cc
|
||||
+++ b/device/gamepad/gamepad_monitor.cc
|
||||
@@ -53,6 +53,8 @@ void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) {
|
||||
GamepadService* service = GamepadService::GetInstance();
|
||||
if (!service->ConsumerBecameActive(this)) {
|
||||
mojo::ReportBadMessage("GamepadMonitor::GamepadStartPolling failed");
|
||||
+ std::move(callback).Run(base::ReadOnlySharedMemoryRegion());
|
||||
+ return;
|
||||
}
|
||||
std::move(callback).Run(service->DuplicateSharedMemoryRegion());
|
||||
}
|
||||
385
patches/chromium/cherry-pick-0894af410c4e.patch
Normal file
385
patches/chromium/cherry-pick-0894af410c4e.patch
Normal file
@@ -0,0 +1,385 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Min Qin <qinmin@chromium.org>
|
||||
Date: Tue, 31 Aug 2021 23:03:03 +0000
|
||||
Subject: Quarantine save package items that's downloaded from network
|
||||
|
||||
Currently quarantine is not performed for save page downloads. This CL
|
||||
fixes the issue.
|
||||
|
||||
BUG=1243020, 811161
|
||||
|
||||
Change-Id: I85d03cc324b0b90a45bd8b3429e4e9eec1aaf857
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3126709
|
||||
Reviewed-by: Xing Liu <xingliu@chromium.org>
|
||||
Commit-Queue: Min Qin <qinmin@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#917013}
|
||||
|
||||
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
|
||||
index df2e3571636144acfefd1b79f157fd176db46ea0..f0a2d2bd58314420cc356400acc46ab412d49aca 100644
|
||||
--- a/chrome/browser/download/save_page_browsertest.cc
|
||||
+++ b/chrome/browser/download/save_page_browsertest.cc
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "components/prefs/pref_member.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/security_state/core/security_state.h"
|
||||
+#include "components/services/quarantine/test_support.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
#include "content/public/browser/notification_types.h"
|
||||
@@ -431,6 +432,10 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveFileURL) {
|
||||
EXPECT_TRUE(base::PathExists(full_file_name));
|
||||
EXPECT_FALSE(base::PathExists(dir));
|
||||
EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name));
|
||||
+#if defined(OS_WIN)
|
||||
+ // Local file URL will not be quarantined.
|
||||
+ EXPECT_FALSE(quarantine::IsFileQuarantined(full_file_name, GURL(), GURL()));
|
||||
+#endif
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,
|
||||
@@ -964,6 +969,25 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveUnauthorizedResource) {
|
||||
EXPECT_FALSE(base::PathExists(dir.AppendASCII("should-not-save.jpg")));
|
||||
}
|
||||
|
||||
+#if defined(OS_WIN)
|
||||
+// Save a file and confirm that the file is correctly quarantined.
|
||||
+IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveURLQuarantine) {
|
||||
+ GURL url = embedded_test_server()->GetURL("/save_page/text.txt");
|
||||
+ ui_test_utils::NavigateToURL(browser(), url);
|
||||
+
|
||||
+ base::FilePath full_file_name, dir;
|
||||
+ SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_ONLY_HTML, "test", 1, &dir,
|
||||
+ &full_file_name);
|
||||
+ ASSERT_FALSE(HasFailure());
|
||||
+
|
||||
+ base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
+ EXPECT_TRUE(base::PathExists(full_file_name));
|
||||
+ EXPECT_FALSE(base::PathExists(dir));
|
||||
+ EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name));
|
||||
+ EXPECT_TRUE(quarantine::IsFileQuarantined(full_file_name, url, GURL()));
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
// Test suite that allows testing --site-per-process against cross-site frames.
|
||||
// See http://dev.chromium.org/developers/design-documents/site-isolation.
|
||||
class SavePageSitePerProcessBrowserTest : public SavePageBrowserTest {
|
||||
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
|
||||
index b8f71b60bee4b0bb7f46d2a843bb30c5d9ca494f..e3e643028cc23c5a0cfee726fe65d53333a7122f 100644
|
||||
--- a/content/browser/download/download_manager_impl.h
|
||||
+++ b/content/browser/download/download_manager_impl.h
|
||||
@@ -170,6 +170,11 @@ class CONTENT_EXPORT DownloadManagerImpl
|
||||
int frame_tree_node_id,
|
||||
bool from_download_cross_origin_redirect);
|
||||
|
||||
+ // DownloadItemImplDelegate overrides.
|
||||
+ download::QuarantineConnectionCallback GetQuarantineConnectionCallback()
|
||||
+ override;
|
||||
+ std::string GetApplicationClientIdForFileScanning() const override;
|
||||
+
|
||||
private:
|
||||
using DownloadSet = std::set<download::DownloadItem*>;
|
||||
using DownloadGuidMap =
|
||||
@@ -237,7 +242,6 @@ class CONTENT_EXPORT DownloadManagerImpl
|
||||
bool ShouldOpenDownload(download::DownloadItemImpl* item,
|
||||
ShouldOpenDownloadCallback callback) override;
|
||||
void CheckForFileRemoval(download::DownloadItemImpl* download_item) override;
|
||||
- std::string GetApplicationClientIdForFileScanning() const override;
|
||||
void ResumeInterruptedDownload(
|
||||
std::unique_ptr<download::DownloadUrlParameters> params,
|
||||
const GURL& site_url) override;
|
||||
@@ -249,8 +253,6 @@ class CONTENT_EXPORT DownloadManagerImpl
|
||||
void ReportBytesWasted(download::DownloadItemImpl* download) override;
|
||||
void BindWakeLockProvider(
|
||||
mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver) override;
|
||||
- download::QuarantineConnectionCallback GetQuarantineConnectionCallback()
|
||||
- override;
|
||||
std::unique_ptr<download::DownloadItemRenameHandler>
|
||||
GetRenameHandlerForDownload(
|
||||
download::DownloadItemImpl* download_item) override;
|
||||
diff --git a/content/browser/download/save_file.cc b/content/browser/download/save_file.cc
|
||||
index 6e0cf6ed1df5db407e31be0e3a6db2e919d8e1bf..296c0cf79c9f5ee5e4ab9835394fb34ae7d92acc 100644
|
||||
--- a/content/browser/download/save_file.cc
|
||||
+++ b/content/browser/download/save_file.cc
|
||||
@@ -63,10 +63,15 @@ void SaveFile::Finish() {
|
||||
file_.Finish();
|
||||
}
|
||||
|
||||
-void SaveFile::AnnotateWithSourceInformation() {
|
||||
- // TODO(gbillock): If this method is called, it should set the
|
||||
- // file_.SetClientGuid() method first.
|
||||
- NOTREACHED();
|
||||
+void SaveFile::AnnotateWithSourceInformation(
|
||||
+ const std::string& client_guid,
|
||||
+ const GURL& source_url,
|
||||
+ const GURL& referrer_url,
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
|
||||
+ download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback) {
|
||||
+ file_.AnnotateWithSourceInformation(client_guid, source_url, referrer_url,
|
||||
+ std::move(remote_quarantine),
|
||||
+ std::move(on_annotation_done_callback));
|
||||
}
|
||||
|
||||
base::FilePath SaveFile::FullPath() const {
|
||||
diff --git a/content/browser/download/save_file.h b/content/browser/download/save_file.h
|
||||
index 688574b07f9374e75a25caaaa13bdb405aea7b0d..1893a0031f4c6642c6c806577da2246e55e49091 100644
|
||||
--- a/content/browser/download/save_file.h
|
||||
+++ b/content/browser/download/save_file.h
|
||||
@@ -34,7 +34,12 @@ class SaveFile {
|
||||
void Detach();
|
||||
void Cancel();
|
||||
void Finish();
|
||||
- void AnnotateWithSourceInformation();
|
||||
+ void AnnotateWithSourceInformation(
|
||||
+ const std::string& client_guid,
|
||||
+ const GURL& source_url,
|
||||
+ const GURL& referrer_url,
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
|
||||
+ download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback);
|
||||
base::FilePath FullPath() const;
|
||||
bool InProgress() const;
|
||||
int64_t BytesSoFar() const;
|
||||
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc
|
||||
index bb322825a449920001b3c09fce33d3ed7e4d82da..98ce67d548d0880ed187779a0e41e7995c83543b 100644
|
||||
--- a/content/browser/download/save_file_manager.cc
|
||||
+++ b/content/browser/download/save_file_manager.cc
|
||||
@@ -51,6 +51,7 @@ static SaveFileManager* g_save_file_manager = nullptr;
|
||||
class SaveFileManager::SimpleURLLoaderHelper
|
||||
: public network::SimpleURLLoaderStreamConsumer {
|
||||
public:
|
||||
+ using URLLoaderCompleteCallback = base::OnceCallback<void(bool success)>;
|
||||
static std::unique_ptr<SimpleURLLoaderHelper> CreateAndStartDownload(
|
||||
std::unique_ptr<network::ResourceRequest> resource_request,
|
||||
SaveItemId save_item_id,
|
||||
@@ -59,11 +60,12 @@ class SaveFileManager::SimpleURLLoaderHelper
|
||||
int render_frame_routing_id,
|
||||
const net::NetworkTrafficAnnotationTag& annotation_tag,
|
||||
network::mojom::URLLoaderFactory* url_loader_factory,
|
||||
- SaveFileManager* save_file_manager) {
|
||||
+ SaveFileManager* save_file_manager,
|
||||
+ URLLoaderCompleteCallback on_complete_cb) {
|
||||
return std::unique_ptr<SimpleURLLoaderHelper>(new SimpleURLLoaderHelper(
|
||||
std::move(resource_request), save_item_id, save_package_id,
|
||||
render_process_id, render_frame_routing_id, annotation_tag,
|
||||
- url_loader_factory, save_file_manager));
|
||||
+ url_loader_factory, save_file_manager, std::move(on_complete_cb)));
|
||||
}
|
||||
|
||||
~SimpleURLLoaderHelper() override = default;
|
||||
@@ -77,10 +79,12 @@ class SaveFileManager::SimpleURLLoaderHelper
|
||||
int render_frame_routing_id,
|
||||
const net::NetworkTrafficAnnotationTag& annotation_tag,
|
||||
network::mojom::URLLoaderFactory* url_loader_factory,
|
||||
- SaveFileManager* save_file_manager)
|
||||
+ SaveFileManager* save_file_manager,
|
||||
+ URLLoaderCompleteCallback on_complete_cb)
|
||||
: save_file_manager_(save_file_manager),
|
||||
save_item_id_(save_item_id),
|
||||
- save_package_id_(save_package_id) {
|
||||
+ save_package_id_(save_package_id),
|
||||
+ on_complete_cb_(std::move(on_complete_cb)) {
|
||||
GURL url = resource_request->url;
|
||||
url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
|
||||
annotation_tag);
|
||||
@@ -125,9 +129,7 @@ class SaveFileManager::SimpleURLLoaderHelper
|
||||
|
||||
void OnComplete(bool success) override {
|
||||
download::GetDownloadTaskRunner()->PostTask(
|
||||
- FROM_HERE,
|
||||
- base::BindOnce(&SaveFileManager::SaveFinished, save_file_manager_,
|
||||
- save_item_id_, save_package_id_, success));
|
||||
+ FROM_HERE, base::BindOnce(std::move(on_complete_cb_), success));
|
||||
}
|
||||
|
||||
void OnRetry(base::OnceClosure start_retry) override {
|
||||
@@ -139,6 +141,7 @@ class SaveFileManager::SimpleURLLoaderHelper
|
||||
SaveItemId save_item_id_;
|
||||
SavePackageId save_package_id_;
|
||||
std::unique_ptr<network::SimpleURLLoader> url_loader_;
|
||||
+ URLLoaderCompleteCallback on_complete_cb_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SimpleURLLoaderHelper);
|
||||
};
|
||||
@@ -189,17 +192,20 @@ SavePackage* SaveFileManager::LookupPackage(SaveItemId save_item_id) {
|
||||
}
|
||||
|
||||
// Call from SavePackage for starting a saving job
|
||||
-void SaveFileManager::SaveURL(SaveItemId save_item_id,
|
||||
- const GURL& url,
|
||||
- const Referrer& referrer,
|
||||
- int render_process_host_id,
|
||||
- int render_view_routing_id,
|
||||
- int render_frame_routing_id,
|
||||
- SaveFileCreateInfo::SaveFileSource save_source,
|
||||
- const base::FilePath& file_full_path,
|
||||
- BrowserContext* context,
|
||||
- StoragePartition* storage_partition,
|
||||
- SavePackage* save_package) {
|
||||
+void SaveFileManager::SaveURL(
|
||||
+ SaveItemId save_item_id,
|
||||
+ const GURL& url,
|
||||
+ const Referrer& referrer,
|
||||
+ int render_process_host_id,
|
||||
+ int render_view_routing_id,
|
||||
+ int render_frame_routing_id,
|
||||
+ SaveFileCreateInfo::SaveFileSource save_source,
|
||||
+ const base::FilePath& file_full_path,
|
||||
+ BrowserContext* context,
|
||||
+ StoragePartition* storage_partition,
|
||||
+ SavePackage* save_package,
|
||||
+ const std::string& client_guid,
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
// Insert started saving job to tracking list.
|
||||
@@ -285,11 +291,18 @@ void SaveFileManager::SaveURL(SaveItemId save_item_id,
|
||||
factory = storage_partition->GetURLLoaderFactoryForBrowserProcess().get();
|
||||
}
|
||||
|
||||
+ base::OnceCallback<void(bool /*success*/)> save_finished_cb =
|
||||
+ base::BindOnce(&SaveFileManager::OnURLLoaderComplete, this,
|
||||
+ save_item_id, save_package->id(),
|
||||
+ context->IsOffTheRecord() ? GURL() : url,
|
||||
+ context->IsOffTheRecord() ? GURL() : referrer.url,
|
||||
+ client_guid, std::move(remote_quarantine));
|
||||
+
|
||||
url_loader_helpers_[save_item_id] =
|
||||
SimpleURLLoaderHelper::CreateAndStartDownload(
|
||||
std::move(request), save_item_id, save_package->id(),
|
||||
render_process_host_id, render_frame_routing_id, traffic_annotation,
|
||||
- factory, this);
|
||||
+ factory, this, std::move(save_finished_cb));
|
||||
} else {
|
||||
// We manually start the save job.
|
||||
auto info = std::make_unique<SaveFileCreateInfo>(
|
||||
@@ -344,6 +357,36 @@ void SaveFileManager::SendCancelRequest(SaveItemId save_item_id) {
|
||||
base::BindOnce(&SaveFileManager::CancelSave, this, save_item_id));
|
||||
}
|
||||
|
||||
+void SaveFileManager::OnURLLoaderComplete(
|
||||
+ SaveItemId save_item_id,
|
||||
+ SavePackageId save_package_id,
|
||||
+ const GURL& url,
|
||||
+ const GURL& referrer_url,
|
||||
+ const std::string& client_guid,
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
|
||||
+ bool is_success) {
|
||||
+ DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
|
||||
+ SaveFile* save_file = LookupSaveFile(save_item_id);
|
||||
+ if (!is_success || !save_file) {
|
||||
+ SaveFinished(save_item_id, save_package_id, is_success);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ save_file->AnnotateWithSourceInformation(
|
||||
+ client_guid, url, referrer_url, std::move(remote_quarantine),
|
||||
+ base::BindOnce(&SaveFileManager::OnQuarantineComplete, this, save_item_id,
|
||||
+ save_package_id));
|
||||
+}
|
||||
+
|
||||
+void SaveFileManager::OnQuarantineComplete(
|
||||
+ SaveItemId save_item_id,
|
||||
+ SavePackageId save_package_id,
|
||||
+ download::DownloadInterruptReason result) {
|
||||
+ DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
|
||||
+ SaveFinished(save_item_id, save_package_id,
|
||||
+ result == download::DOWNLOAD_INTERRUPT_REASON_NONE);
|
||||
+}
|
||||
+
|
||||
// Notifications sent from the IO thread and run on the file thread:
|
||||
|
||||
// The IO thread created |info|, but the file thread (this method) uses it
|
||||
diff --git a/content/browser/download/save_file_manager.h b/content/browser/download/save_file_manager.h
|
||||
index 51eb63a9b189be388e4dff48e04644956e968345..0d4290b273ba4f150bc9a49418e54b709a601581 100644
|
||||
--- a/content/browser/download/save_file_manager.h
|
||||
+++ b/content/browser/download/save_file_manager.h
|
||||
@@ -61,6 +61,8 @@
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
+#include "components/download/public/common/download_interrupt_reasons.h"
|
||||
+#include "components/services/quarantine/quarantine.h"
|
||||
#include "content/browser/download/save_types.h"
|
||||
#include "content/common/content_export.h"
|
||||
|
||||
@@ -90,17 +92,20 @@ class CONTENT_EXPORT SaveFileManager
|
||||
|
||||
// Saves the specified URL |url|. |save_package| must not be deleted before
|
||||
// the call to RemoveSaveFile. Should be called on the UI thread,
|
||||
- void SaveURL(SaveItemId save_item_id,
|
||||
- const GURL& url,
|
||||
- const Referrer& referrer,
|
||||
- int render_process_host_id,
|
||||
- int render_view_routing_id,
|
||||
- int render_frame_routing_id,
|
||||
- SaveFileCreateInfo::SaveFileSource save_source,
|
||||
- const base::FilePath& file_full_path,
|
||||
- BrowserContext* context,
|
||||
- StoragePartition* storage_partition,
|
||||
- SavePackage* save_package);
|
||||
+ void SaveURL(
|
||||
+ SaveItemId save_item_id,
|
||||
+ const GURL& url,
|
||||
+ const Referrer& referrer,
|
||||
+ int render_process_host_id,
|
||||
+ int render_view_routing_id,
|
||||
+ int render_frame_routing_id,
|
||||
+ SaveFileCreateInfo::SaveFileSource save_source,
|
||||
+ const base::FilePath& file_full_path,
|
||||
+ BrowserContext* context,
|
||||
+ StoragePartition* storage_partition,
|
||||
+ SavePackage* save_package,
|
||||
+ const std::string& client_guid,
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine);
|
||||
|
||||
// Notifications sent from the IO thread and run on the file thread:
|
||||
void StartSave(std::unique_ptr<SaveFileCreateInfo> info);
|
||||
@@ -159,6 +164,21 @@ class CONTENT_EXPORT SaveFileManager
|
||||
// Help function for sending notification of canceling specific request.
|
||||
void SendCancelRequest(SaveItemId save_item_id);
|
||||
|
||||
+ // Called on the file thread when the URLLoader completes saving a SaveItem.
|
||||
+ void OnURLLoaderComplete(
|
||||
+ SaveItemId save_item_id,
|
||||
+ SavePackageId save_package_id,
|
||||
+ const GURL& url,
|
||||
+ const GURL& referrer_url,
|
||||
+ const std::string& client_guid,
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
|
||||
+ bool is_success);
|
||||
+
|
||||
+ // Called on the file thread when file quarantine finishes on a SaveItem.
|
||||
+ void OnQuarantineComplete(SaveItemId save_item_id,
|
||||
+ SavePackageId save_package_id,
|
||||
+ download::DownloadInterruptReason result);
|
||||
+
|
||||
// Notifications sent from the file thread and run on the UI thread.
|
||||
|
||||
// Lookup the SaveManager for this WebContents' saving browser context and
|
||||
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
|
||||
index 369aae121d5074f2bcabf337a87e929dc2a65b6f..b23a0201b033a0952607e00fe2d0d5e9b3337d51 100644
|
||||
--- a/content/browser/download/save_package.cc
|
||||
+++ b/content/browser/download/save_package.cc
|
||||
@@ -856,6 +856,12 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) {
|
||||
RenderFrameHostImpl* requester_frame =
|
||||
requester_frame_tree_node->current_frame_host();
|
||||
|
||||
+ mojo::PendingRemote<quarantine::mojom::Quarantine> quarantine;
|
||||
+ auto quarantine_callback =
|
||||
+ download_manager_->GetQuarantineConnectionCallback();
|
||||
+ if (quarantine_callback)
|
||||
+ quarantine_callback.Run(quarantine.InitWithNewPipeAndPassReceiver());
|
||||
+
|
||||
file_manager_->SaveURL(
|
||||
save_item_ptr->id(), save_item_ptr->url(), save_item_ptr->referrer(),
|
||||
requester_frame->GetProcess()->GetID(),
|
||||
@@ -867,8 +873,8 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) {
|
||||
.GetRenderViewHost()
|
||||
->GetProcess()
|
||||
->GetStoragePartition(),
|
||||
- this);
|
||||
-
|
||||
+ this, download_manager_->GetApplicationClientIdForFileScanning(),
|
||||
+ std::move(quarantine));
|
||||
} while (process_all_remaining_items && !waiting_item_queue_.empty());
|
||||
}
|
||||
|
||||
51
patches/chromium/cherry-pick-109fde1088be.patch
Normal file
51
patches/chromium/cherry-pick-109fde1088be.patch
Normal file
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Lippautz <mlippautz@chromium.org>
|
||||
Date: Tue, 2 Nov 2021 21:21:27 +0000
|
||||
Subject: MediaStreamSource: Retain observers till callbacks have been executed
|
||||
|
||||
(cherry picked from commit d1055cb23b15e42381bc815eeabb207ce18394d9)
|
||||
|
||||
Bug: chromium:1263620
|
||||
Change-Id: I0655474bd3c5f4f927db1834e95b2724a20ba4e9
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3247159
|
||||
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
|
||||
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
|
||||
Reviewed-by: Elad Alon <eladalon@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#935842}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3257492
|
||||
Auto-Submit: Elad Alon <eladalon@chromium.org>
|
||||
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4638@{#1004}
|
||||
Cr-Branched-From: 159257cab5585bc8421abf347984bb32fdfe9eb9-refs/heads/main@{#920003}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
|
||||
index b37a4b9297b87092233c600953eb01af820b6df1..15ac4cce06d419646979a52a00628b152ec516de 100644
|
||||
--- a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
|
||||
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
|
||||
#include "third_party/blink/renderer/platform/audio/audio_bus.h"
|
||||
+#include "third_party/blink/renderer/platform/heap/persistent.h"
|
||||
#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
|
||||
#include "third_party/blink/renderer/platform/mediastream/webaudio_destination_consumer.h"
|
||||
|
||||
@@ -171,11 +172,13 @@ void MediaStreamSource::SetReadyState(ReadyState ready_state) {
|
||||
ready_state_ = ready_state;
|
||||
|
||||
// Observers may dispatch events which create and add new Observers;
|
||||
- // take a snapshot so as to safely iterate.
|
||||
+ // take a snapshot so as to safely iterate. Wrap the observers in
|
||||
+ // weak persistents to allow cancelling callbacks in case they are reclaimed
|
||||
+ // until the callback is executed.
|
||||
Vector<base::OnceClosure> observer_callbacks;
|
||||
- for (auto it = observers_.begin(); it != observers_.end(); ++it) {
|
||||
- observer_callbacks.push_back(
|
||||
- base::BindOnce(&Observer::SourceChangedState, *it));
|
||||
+ for (const auto& it : observers_) {
|
||||
+ observer_callbacks.push_back(WTF::Bind(&Observer::SourceChangedState,
|
||||
+ WrapWeakPersistent(it.Get())));
|
||||
}
|
||||
for (auto& observer_callback : observer_callbacks) {
|
||||
std::move(observer_callback).Run();
|
||||
176
patches/chromium/cherry-pick-1277917.patch
Normal file
176
patches/chromium/cherry-pick-1277917.patch
Normal file
@@ -0,0 +1,176 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pelchat <spelchat@chromium.org>
|
||||
Date: Fri, 7 Jan 2022 20:00:37 +0000
|
||||
Subject: Avoid UAF on StreamingSearchPrefetchURLLoader.
|
||||
|
||||
StreamingSearchPrefetchURLLoader::OnDataAvailable used to "delete this",
|
||||
which results in deleting the DataPipeDrainer, which will then be used
|
||||
once OnDataAvailable returns. Instead, we post a task to delete the
|
||||
URL loader later on.
|
||||
|
||||
Bug: 1277917
|
||||
Change-Id: I8d78c73a01fff0315b96ccb0e7fe605884b99823
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3365387
|
||||
Reviewed-by: Max Curran <curranmax@chromium.org>
|
||||
Reviewed-by: Robert Ogden <robertogden@chromium.org>
|
||||
Commit-Queue: Simon Pelchat <spelchat@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#956628}
|
||||
|
||||
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
|
||||
index 1d3d1ea93c026d371a6ad5678e8ff37dc58f8423..e3eaad96fbada18211f295988c07d218ab67921f 100644
|
||||
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
|
||||
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h"
|
||||
|
||||
#include "chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h"
|
||||
+#include "streaming_search_prefetch_request.h"
|
||||
|
||||
StreamingSearchPrefetchRequest::StreamingSearchPrefetchRequest(
|
||||
const GURL& prefetch_url,
|
||||
@@ -19,7 +20,9 @@ void StreamingSearchPrefetchRequest::StartPrefetchRequestInternal(
|
||||
std::unique_ptr<network::ResourceRequest> resource_request,
|
||||
const net::NetworkTrafficAnnotationTag& network_traffic_annotation) {
|
||||
streaming_url_loader_ = std::make_unique<StreamingSearchPrefetchURLLoader>(
|
||||
- this, profile, std::move(resource_request), network_traffic_annotation);
|
||||
+ this, profile, std::move(resource_request), network_traffic_annotation,
|
||||
+ base::BindOnce(&StreamingSearchPrefetchRequest::StopPrefetch,
|
||||
+ weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
std::unique_ptr<SearchPrefetchURLLoader>
|
||||
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
|
||||
index ff051c61e9cbed67d5cffbcac007d6c12a26cc76..ad75d404abe9e743d079725ffd8b01d3a49ae017 100644
|
||||
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
|
||||
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
|
||||
@@ -47,6 +47,8 @@ class StreamingSearchPrefetchRequest : public BaseSearchPrefetchRequest {
|
||||
private:
|
||||
// The ongoing prefetch request. Null before and after the fetch.
|
||||
std::unique_ptr<StreamingSearchPrefetchURLLoader> streaming_url_loader_;
|
||||
+
|
||||
+ base::WeakPtrFactory<StreamingSearchPrefetchRequest> weak_factory_{this};
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_STREAMING_SEARCH_PREFETCH_REQUEST_H_
|
||||
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
|
||||
index 07f4e5cd7f0adde63861962a78cdac0de43591b0..8d9009c42cdde766e105b02827a539a4477ea58e 100644
|
||||
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
|
||||
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
|
||||
@@ -26,15 +26,18 @@
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "services/network/public/mojom/early_hints.mojom.h"
|
||||
#include "services/network/public/mojom/url_response_head.mojom.h"
|
||||
+#include "streaming_search_prefetch_url_loader.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
StreamingSearchPrefetchURLLoader::StreamingSearchPrefetchURLLoader(
|
||||
StreamingSearchPrefetchRequest* streaming_prefetch_request,
|
||||
Profile* profile,
|
||||
std::unique_ptr<network::ResourceRequest> resource_request,
|
||||
- const net::NetworkTrafficAnnotationTag& network_traffic_annotation)
|
||||
+ const net::NetworkTrafficAnnotationTag& network_traffic_annotation,
|
||||
+ base::OnceClosure stop_prefetch_closure)
|
||||
: resource_request_(std::move(resource_request)),
|
||||
- streaming_prefetch_request_(streaming_prefetch_request) {
|
||||
+ streaming_prefetch_request_(streaming_prefetch_request),
|
||||
+ stop_prefetch_closure_(std::move(stop_prefetch_closure)) {
|
||||
DCHECK(streaming_prefetch_request_);
|
||||
auto url_loader_factory = profile->GetDefaultStoragePartition()
|
||||
->GetURLLoaderFactoryForBrowserProcess();
|
||||
@@ -126,7 +129,7 @@ void StreamingSearchPrefetchURLLoader::OnReceiveRedirect(
|
||||
if (streaming_prefetch_request_) {
|
||||
streaming_prefetch_request_->ErrorEncountered();
|
||||
} else {
|
||||
- delete this;
|
||||
+ PostTaskToStopPrefetchAndDeleteSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +212,7 @@ void StreamingSearchPrefetchURLLoader::OnStartLoadingResponseBodyFromData() {
|
||||
mojo::CreateDataPipe(&options, producer_handle_, consumer_handle);
|
||||
|
||||
if (rv != MOJO_RESULT_OK) {
|
||||
- delete this;
|
||||
+ PostTaskToStopPrefetchAndDeleteSelf();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -231,7 +234,7 @@ void StreamingSearchPrefetchURLLoader::OnHandleReady(
|
||||
MojoResult result,
|
||||
const mojo::HandleSignalsState& state) {
|
||||
if (result != MOJO_RESULT_OK) {
|
||||
- delete this;
|
||||
+ PostTaskToStopPrefetchAndDeleteSelf();
|
||||
return;
|
||||
}
|
||||
PushData();
|
||||
@@ -257,7 +260,7 @@ void StreamingSearchPrefetchURLLoader::PushData() {
|
||||
}
|
||||
|
||||
if (result != MOJO_RESULT_OK) {
|
||||
- delete this;
|
||||
+ PostTaskToStopPrefetchAndDeleteSelf();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -344,16 +347,24 @@ void StreamingSearchPrefetchURLLoader::OnURLLoaderMojoDisconnect() {
|
||||
DCHECK(streaming_prefetch_request_);
|
||||
streaming_prefetch_request_->ErrorEncountered();
|
||||
} else {
|
||||
- delete this;
|
||||
+ PostTaskToStopPrefetchAndDeleteSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void StreamingSearchPrefetchURLLoader::OnURLLoaderClientMojoDisconnect() {
|
||||
DCHECK(forwarding_client_);
|
||||
DCHECK(!streaming_prefetch_request_);
|
||||
- delete this;
|
||||
+ PostTaskToStopPrefetchAndDeleteSelf();
|
||||
}
|
||||
|
||||
void StreamingSearchPrefetchURLLoader::ClearOwnerPointer() {
|
||||
streaming_prefetch_request_ = nullptr;
|
||||
}
|
||||
+
|
||||
+void StreamingSearchPrefetchURLLoader::PostTaskToStopPrefetchAndDeleteSelf() {
|
||||
+ // To avoid UAF bugs, post a separate task to delete this object.
|
||||
+ if (stop_prefetch_closure_) {
|
||||
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
+ FROM_HERE, std::move(stop_prefetch_closure_));
|
||||
+ }
|
||||
+}
|
||||
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
|
||||
index 2213fb079e3f29566d67030dd2fa399ce11024e2..ed225db0b4d2b0d24aae967f320a7010c1a45044 100644
|
||||
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
|
||||
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
|
||||
@@ -39,7 +39,8 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
|
||||
StreamingSearchPrefetchRequest* streaming_prefetch_request,
|
||||
Profile* profile,
|
||||
std::unique_ptr<network::ResourceRequest> resource_request,
|
||||
- const net::NetworkTrafficAnnotationTag& network_traffic_annotation);
|
||||
+ const net::NetworkTrafficAnnotationTag& network_traffic_annotation,
|
||||
+ base::OnceClosure stop_prefetch_closure);
|
||||
|
||||
~StreamingSearchPrefetchURLLoader() override;
|
||||
|
||||
@@ -105,6 +106,9 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
|
||||
// Clears |producer_handle_| and |handle_watcher_|.
|
||||
void Finish();
|
||||
|
||||
+ // Post a task to delete this object by running stop_prefetch_closure_.
|
||||
+ void PostTaskToStopPrefetchAndDeleteSelf();
|
||||
+
|
||||
// Sets up mojo forwarding to the navigation path. Resumes
|
||||
// |network_url_loader_| calls. Serves the start of the response to the
|
||||
// navigation path. After this method is called, |this| manages its own
|
||||
@@ -164,6 +168,9 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
|
||||
mojo::ScopedDataPipeProducerHandle producer_handle_;
|
||||
std::unique_ptr<mojo::SimpleWatcher> handle_watcher_;
|
||||
|
||||
+ // Closure to cancel this prefetch. Running this callback will destroy |this|.
|
||||
+ base::OnceClosure stop_prefetch_closure_;
|
||||
+
|
||||
base::WeakPtrFactory<StreamingSearchPrefetchURLLoader> weak_factory_{this};
|
||||
};
|
||||
|
||||
157
patches/chromium/cherry-pick-1281979.patch
Normal file
157
patches/chromium/cherry-pick-1281979.patch
Normal file
@@ -0,0 +1,157 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Etienne Bergeron <etienneb@chromium.org>
|
||||
Date: Wed, 5 Jan 2022 23:37:26 +0000
|
||||
Subject: Fix race condition while initializing GPU Watchdog
|
||||
|
||||
This CL is fixing a race condition detected by TSAN.
|
||||
see: crbug/1281979
|
||||
|
||||
The race condition is between these two functions:
|
||||
base::PowerMonitor::IsInitialized() and
|
||||
base::PowerMonitor::Initialize(...)
|
||||
|
||||
The power monitor doesn't need to be initialized to add
|
||||
observers. In fact, the power monitor initialization
|
||||
is for plugging a power monitor source. Observers can be
|
||||
safely added/removed.
|
||||
|
||||
R=fdoray@chromium.org
|
||||
|
||||
Bug: 1281979
|
||||
Change-Id: Icaecd877d4b0cf5e79d7fe6a096f9d76d932b076
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3367395
|
||||
Reviewed-by: Maggie Chen <magchen@chromium.org>
|
||||
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#955944}
|
||||
|
||||
diff --git a/gpu/ipc/service/gpu_watchdog_thread.cc b/gpu/ipc/service/gpu_watchdog_thread.cc
|
||||
index ecf8e17ce4183bfe2f22a9a6d666a60828f078a2..c518f978e602eda3cfa150bd8e9e07f7f7fc749b 100644
|
||||
--- a/gpu/ipc/service/gpu_watchdog_thread.cc
|
||||
+++ b/gpu/ipc/service/gpu_watchdog_thread.cc
|
||||
@@ -36,9 +36,6 @@
|
||||
#endif
|
||||
|
||||
namespace gpu {
|
||||
-namespace {
|
||||
-constexpr int64_t kDelayForAddPowerObserverInMs = 50;
|
||||
-}
|
||||
|
||||
base::TimeDelta GetGpuWatchdogTimeout() {
|
||||
std::string timeout_str =
|
||||
@@ -176,14 +173,11 @@ void GpuWatchdogThread::OnInitComplete() {
|
||||
base::Unretained(this)));
|
||||
Disarm();
|
||||
|
||||
- // Use a delayed task for AddPowerObserver. The PowerMonitor is initialized in
|
||||
- // ChildThreadImpl::Init right after GpuInit::InitializeAndStartSandbox which
|
||||
- // calls OnInitComplete() at the end if no errors.
|
||||
- task_runner()->PostDelayedTask(
|
||||
- FROM_HERE,
|
||||
- base::BindOnce(&GpuWatchdogThread::AddPowerObserver,
|
||||
- base::Unretained(this)),
|
||||
- base::TimeDelta::FromMilliseconds(kDelayForAddPowerObserverInMs));
|
||||
+ // The PowerMonitorObserver needs to be register on the watchdog thread so the
|
||||
+ // notifications are delivered on that thread.
|
||||
+ task_runner()->PostTask(FROM_HERE,
|
||||
+ base::BindOnce(&GpuWatchdogThread::AddPowerObserver,
|
||||
+ base::Unretained(this)));
|
||||
}
|
||||
|
||||
// Called from the gpu thread in viz::GpuServiceImpl::~GpuServiceImpl().
|
||||
@@ -296,26 +290,12 @@ void GpuWatchdogThread::OnResume() {
|
||||
void GpuWatchdogThread::AddPowerObserver() {
|
||||
DCHECK(watchdog_thread_task_runner_->BelongsToCurrentThread());
|
||||
|
||||
- // The Observer can only be added after the power monitor is initialized.
|
||||
- // When this function is called, PowerMonitor is probably ready.
|
||||
- if (base::PowerMonitor::IsInitialized()) {
|
||||
- bool is_system_suspended =
|
||||
- base::PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(
|
||||
- this);
|
||||
- if (is_system_suspended) {
|
||||
- StopWatchdogTimeoutTask(kPowerSuspendResume);
|
||||
- }
|
||||
-
|
||||
- is_power_observer_added_ = true;
|
||||
- } else {
|
||||
- // Just in case PowerMonitor is not ready.
|
||||
- // It usually takes hundreds of milliseconds to finish the whole GPU
|
||||
- // initialization. Try again in 100 ms.
|
||||
- task_runner()->PostDelayedTask(
|
||||
- FROM_HERE,
|
||||
- base::BindOnce(&GpuWatchdogThread::AddPowerObserver, weak_ptr_),
|
||||
- base::TimeDelta::FromMilliseconds(100));
|
||||
- }
|
||||
+ // Adding the Observer to the power monitor is safe even if power monitor is
|
||||
+ // not yet initialized.
|
||||
+ bool is_system_suspended =
|
||||
+ base::PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(this);
|
||||
+ if (is_system_suspended)
|
||||
+ StopWatchdogTimeoutTask(kPowerSuspendResume);
|
||||
}
|
||||
|
||||
// Running on the watchdog thread.
|
||||
@@ -638,7 +618,6 @@ void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
|
||||
base::debug::Alias(&in_power_suspension_);
|
||||
base::debug::Alias(&in_gpu_process_teardown_);
|
||||
base::debug::Alias(&is_backgrounded_);
|
||||
- base::debug::Alias(&is_power_observer_added_);
|
||||
base::debug::Alias(&last_on_watchdog_timeout_timeticks_);
|
||||
base::TimeDelta timeticks_elapses =
|
||||
function_begin_timeticks - last_on_watchdog_timeout_timeticks_;
|
||||
@@ -843,17 +822,4 @@ bool GpuWatchdogThread::IsGpuHangDetectedForTesting() {
|
||||
return test_result_timeout_and_gpu_hang_.IsSet();
|
||||
}
|
||||
|
||||
-// This should be called on the test main thread only. It will wait until the
|
||||
-// power observer is added on the watchdog thread.
|
||||
-void GpuWatchdogThread::WaitForPowerObserverAddedForTesting() {
|
||||
- DCHECK(watched_gpu_task_runner_->BelongsToCurrentThread());
|
||||
-
|
||||
- base::WaitableEvent event;
|
||||
- task_runner()->PostDelayedTask(
|
||||
- FROM_HERE,
|
||||
- base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)),
|
||||
- base::TimeDelta::FromMilliseconds(kDelayForAddPowerObserverInMs));
|
||||
- event.Wait();
|
||||
-}
|
||||
-
|
||||
} // namespace gpu
|
||||
diff --git a/gpu/ipc/service/gpu_watchdog_thread.h b/gpu/ipc/service/gpu_watchdog_thread.h
|
||||
index d0d20dfc7c9fd7e13896e212673519ec5233c562..622647a68ee2bc2e3d18e58bbcfb3c7f90b3102c 100644
|
||||
--- a/gpu/ipc/service/gpu_watchdog_thread.h
|
||||
+++ b/gpu/ipc/service/gpu_watchdog_thread.h
|
||||
@@ -121,8 +121,6 @@ class GPU_IPC_SERVICE_EXPORT GpuWatchdogThread
|
||||
// For gpu testing only. Return status for the watchdog tests
|
||||
bool IsGpuHangDetectedForTesting();
|
||||
|
||||
- void WaitForPowerObserverAddedForTesting();
|
||||
-
|
||||
// Implements base::Thread.
|
||||
void Init() override;
|
||||
void CleanUp() override;
|
||||
@@ -291,10 +289,6 @@ class GPU_IPC_SERVICE_EXPORT GpuWatchdogThread
|
||||
// The GPU watchdog is paused. The timeout task is temporarily stopped.
|
||||
bool is_paused_ = false;
|
||||
|
||||
- // Whether the watchdog thread has added the power monitor observer.
|
||||
- // Read/Write by the watchdog thread only.
|
||||
- bool is_power_observer_added_ = false;
|
||||
-
|
||||
// whether GpuWatchdogThreadEvent::kGpuWatchdogStart has been recorded.
|
||||
bool is_watchdog_start_histogram_recorded = false;
|
||||
|
||||
diff --git a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
|
||||
index ca2006a45dd87bad106b0f75bfe8475fa1090038..b44cdd7e22686ab37c57461291676f01512fd623 100644
|
||||
--- a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
|
||||
+++ b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
|
||||
@@ -81,9 +81,6 @@ void GpuWatchdogPowerTest::SetUp() {
|
||||
|
||||
// Report GPU init complete.
|
||||
watchdog_thread_->OnInitComplete();
|
||||
-
|
||||
- // Wait until the power observer is added on the watchdog thread
|
||||
- watchdog_thread_->WaitForPowerObserverAddedForTesting();
|
||||
}
|
||||
|
||||
void GpuWatchdogPowerTest::TearDown() {
|
||||
31
patches/chromium/cherry-pick-1282354.patch
Normal file
31
patches/chromium/cherry-pick-1282354.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Bookholt <bookholt@chromium.org>
|
||||
Date: Tue, 11 Jan 2022 00:33:53 +0000
|
||||
Subject: ServiceWorkerContainerHost::EnsureFileAccess: abort request
|
||||
processing if the requesting process lacks file access
|
||||
|
||||
Bug: 1282354
|
||||
Change-Id: Ia37ef5b97eedb0d2ad25ffe2869844a40e5be862
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3379268
|
||||
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
|
||||
Commit-Queue: Chris Bookholt <bookholt@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#957344}
|
||||
|
||||
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc
|
||||
index 82498632c53883b5d84fb0a2e5246c98e71ef00d..f13416b0cd611ddcf18053f7a543a9a423635227 100644
|
||||
--- a/content/browser/service_worker/service_worker_container_host.cc
|
||||
+++ b/content/browser/service_worker/service_worker_container_host.cc
|
||||
@@ -379,10 +379,12 @@ void ServiceWorkerContainerHost::EnsureFileAccess(
|
||||
ChildProcessSecurityPolicyImpl* policy =
|
||||
ChildProcessSecurityPolicyImpl::GetInstance();
|
||||
for (const auto& file : file_paths) {
|
||||
- if (!policy->CanReadFile(process_id_, file))
|
||||
+ if (!policy->CanReadFile(process_id_, file)) {
|
||||
mojo::ReportBadMessage(
|
||||
"The renderer doesn't have access to the file "
|
||||
"but it tried to grant access to the controller.");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (!policy->CanReadFile(controller_process_id, file))
|
||||
policy->GrantReadFile(controller_process_id, file);
|
||||
28
patches/chromium/cherry-pick-1283198.patch
Normal file
28
patches/chromium/cherry-pick-1283198.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hosseinian <dhoss@chromium.org>
|
||||
Date: Thu, 30 Dec 2021 05:08:29 +0000
|
||||
Subject: CHECK page on thumbnail requests
|
||||
|
||||
Elevate DCHECK to CHECK.
|
||||
|
||||
Fixed: 1283198
|
||||
Change-Id: Iacb3da961cfb44f94f7a377e225270a57809ef9c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3361538
|
||||
Auto-Submit: Daniel Hosseinian <dhoss@chromium.org>
|
||||
Reviewed-by: K. Moon <kmoon@chromium.org>
|
||||
Commit-Queue: K. Moon <kmoon@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#954552}
|
||||
|
||||
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
|
||||
index 341b183948b15f72edca6f8620c5039593d16a90..2b128d8fdde8048c1f8b92ec2e38f485feca2bf4 100644
|
||||
--- a/pdf/pdfium/pdfium_engine.cc
|
||||
+++ b/pdf/pdfium/pdfium_engine.cc
|
||||
@@ -4273,7 +4273,7 @@ void PDFiumEngine::SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot,
|
||||
void PDFiumEngine::RequestThumbnail(int page_index,
|
||||
float device_pixel_ratio,
|
||||
SendThumbnailCallback send_callback) {
|
||||
- DCHECK(PageIndexInBounds(page_index));
|
||||
+ CHECK(PageIndexInBounds(page_index));
|
||||
|
||||
// Thumbnails cannot be generated in the middle of a progressive paint of a
|
||||
// page. Generate the thumbnail immediately only if the page is not currently
|
||||
138
patches/chromium/cherry-pick-1283371.patch
Normal file
138
patches/chromium/cherry-pick-1283371.patch
Normal file
@@ -0,0 +1,138 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Clark DuVall <cduvall@chromium.org>
|
||||
Date: Thu, 6 Jan 2022 01:21:21 +0000
|
||||
Subject: Fix lifetime bug in PrefetchURLLoader
|
||||
|
||||
PrefetchURLLoader is now owned by PrefetchURLLoaderService, which is no
|
||||
longer refcounted. This makes the lifetime much easier to reason about.
|
||||
|
||||
Bug: 1283371
|
||||
Change-Id: Iaa58c1f44cc9f066459ce344012f57faca533197
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3361198
|
||||
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
|
||||
Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org>
|
||||
Commit-Queue: Clark DuVall <cduvall@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#955986}
|
||||
|
||||
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
|
||||
index 5211d5552d6b2e1c1967d7dd6c6079001fef6895..345bf021541a121ea183ba16fa7ed76373f0dfd1 100644
|
||||
--- a/content/browser/loader/prefetch_url_loader_service.cc
|
||||
+++ b/content/browser/loader/prefetch_url_loader_service.cc
|
||||
@@ -202,29 +202,25 @@ void PrefetchURLLoaderService::CreateLoaderAndStart(
|
||||
->prefetched_signed_exchange_cache;
|
||||
}
|
||||
|
||||
- // For now we make self owned receiver for the loader to the request, while we
|
||||
- // can also possibly make the new loader owned by the factory so that they can
|
||||
- // live longer than the client (i.e. run in detached mode).
|
||||
- // TODO(kinuko): Revisit this.
|
||||
- mojo::MakeSelfOwnedReceiver(
|
||||
- std::make_unique<PrefetchURLLoader>(
|
||||
- request_id, options, current_context.frame_tree_node_id,
|
||||
- resource_request,
|
||||
- resource_request.trusted_params
|
||||
- ? resource_request.trusted_params->isolation_info
|
||||
- .network_isolation_key()
|
||||
- : current_context.render_frame_host->GetNetworkIsolationKey(),
|
||||
- std::move(client), traffic_annotation,
|
||||
- std::move(network_loader_factory_to_use),
|
||||
- base::BindRepeating(
|
||||
- &PrefetchURLLoaderService::CreateURLLoaderThrottles, this,
|
||||
- resource_request, current_context.frame_tree_node_id),
|
||||
- browser_context_, signed_exchange_prefetch_metric_recorder_,
|
||||
- std::move(prefetched_signed_exchange_cache), accept_langs_,
|
||||
- base::BindOnce(
|
||||
- &PrefetchURLLoaderService::GenerateRecursivePrefetchToken, this,
|
||||
- current_context.weak_ptr_factory.GetWeakPtr())),
|
||||
- std::move(receiver));
|
||||
+ // base::Unretained is safe here since |this| owns the loader.
|
||||
+ auto loader = std::make_unique<PrefetchURLLoader>(
|
||||
+ request_id, options, current_context.frame_tree_node_id, resource_request,
|
||||
+ resource_request.trusted_params
|
||||
+ ? resource_request.trusted_params->isolation_info
|
||||
+ .network_isolation_key()
|
||||
+ : current_context.render_frame_host->GetNetworkIsolationKey(),
|
||||
+ std::move(client), traffic_annotation,
|
||||
+ std::move(network_loader_factory_to_use),
|
||||
+ base::BindRepeating(&PrefetchURLLoaderService::CreateURLLoaderThrottles,
|
||||
+ base::Unretained(this), resource_request,
|
||||
+ current_context.frame_tree_node_id),
|
||||
+ browser_context_, signed_exchange_prefetch_metric_recorder_,
|
||||
+ std::move(prefetched_signed_exchange_cache), accept_langs_,
|
||||
+ base::BindOnce(&PrefetchURLLoaderService::GenerateRecursivePrefetchToken,
|
||||
+ base::Unretained(this),
|
||||
+ current_context.weak_ptr_factory.GetWeakPtr()));
|
||||
+ auto* raw_loader = loader.get();
|
||||
+ prefetch_receivers_.Add(raw_loader, std::move(receiver), std::move(loader));
|
||||
}
|
||||
|
||||
PrefetchURLLoaderService::~PrefetchURLLoaderService() = default;
|
||||
diff --git a/content/browser/loader/prefetch_url_loader_service.h b/content/browser/loader/prefetch_url_loader_service.h
|
||||
index 210794966c8d25947f3e6b490538c1f851d80d52..c5fff844f73deaf2912716de9cf97547c498e4e5 100644
|
||||
--- a/content/browser/loader/prefetch_url_loader_service.h
|
||||
+++ b/content/browser/loader/prefetch_url_loader_service.h
|
||||
@@ -35,13 +35,11 @@ class URLLoaderFactoryGetter;
|
||||
// prefetches. The renderer uses it for prefetch requests including <link
|
||||
// rel="prefetch">.
|
||||
class CONTENT_EXPORT PrefetchURLLoaderService final
|
||||
- : public base::RefCountedThreadSafe<
|
||||
- PrefetchURLLoaderService,
|
||||
- content::BrowserThread::DeleteOnUIThread>,
|
||||
- public blink::mojom::RendererPreferenceWatcher,
|
||||
+ : public blink::mojom::RendererPreferenceWatcher,
|
||||
public network::mojom::URLLoaderFactory {
|
||||
public:
|
||||
explicit PrefetchURLLoaderService(BrowserContext* browser_context);
|
||||
+ ~PrefetchURLLoaderService() override;
|
||||
|
||||
void GetFactory(
|
||||
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
|
||||
@@ -67,12 +65,8 @@ class CONTENT_EXPORT PrefetchURLLoaderService final
|
||||
}
|
||||
|
||||
private:
|
||||
- friend class base::DeleteHelper<content::PrefetchURLLoaderService>;
|
||||
- friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
|
||||
struct BindContext;
|
||||
|
||||
- ~PrefetchURLLoaderService() override;
|
||||
-
|
||||
// network::mojom::URLLoaderFactory:
|
||||
void CreateLoaderAndStart(
|
||||
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
|
||||
@@ -114,6 +108,9 @@ class CONTENT_EXPORT PrefetchURLLoaderService final
|
||||
mojo::ReceiverSet<network::mojom::URLLoaderFactory,
|
||||
std::unique_ptr<BindContext>>
|
||||
loader_factory_receivers_;
|
||||
+ mojo::ReceiverSet<network::mojom::URLLoader,
|
||||
+ std::unique_ptr<network::mojom::URLLoader>>
|
||||
+ prefetch_receivers_;
|
||||
// Used in the IO thread.
|
||||
mojo::Receiver<blink::mojom::RendererPreferenceWatcher>
|
||||
preference_watcher_receiver_{this};
|
||||
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
|
||||
index ae284e031a6e051bda49258d54a2e62332773c70..e9af32dd2dc6ae75ded55b1ffd3fe7881408eefc 100644
|
||||
--- a/content/browser/storage_partition_impl.cc
|
||||
+++ b/content/browser/storage_partition_impl.cc
|
||||
@@ -1321,7 +1321,7 @@ void StoragePartitionImpl::Initialize(
|
||||
blob_context, filesystem_context_, fallback_blob_registry);
|
||||
|
||||
prefetch_url_loader_service_ =
|
||||
- base::MakeRefCounted<PrefetchURLLoaderService>(browser_context_);
|
||||
+ std::make_unique<PrefetchURLLoaderService>(browser_context_);
|
||||
|
||||
cookie_store_manager_ =
|
||||
std::make_unique<CookieStoreManager>(service_worker_context_);
|
||||
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
|
||||
index 6f3a482ae16e88271768a3f91c633201f435e271..02209f615202a987d83e72895b0782cac8a8fccd 100644
|
||||
--- a/content/browser/storage_partition_impl.h
|
||||
+++ b/content/browser/storage_partition_impl.h
|
||||
@@ -552,7 +552,7 @@ class CONTENT_EXPORT StoragePartitionImpl
|
||||
std::unique_ptr<BroadcastChannelProvider> broadcast_channel_provider_;
|
||||
std::unique_ptr<BluetoothAllowedDevicesMap> bluetooth_allowed_devices_map_;
|
||||
scoped_refptr<BlobRegistryWrapper> blob_registry_;
|
||||
- scoped_refptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
|
||||
+ std::unique_ptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
|
||||
std::unique_ptr<CookieStoreManager> cookie_store_manager_;
|
||||
scoped_refptr<BucketContext> bucket_context_;
|
||||
scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
|
||||
74
patches/chromium/cherry-pick-1283375.patch
Normal file
74
patches/chromium/cherry-pick-1283375.patch
Normal file
@@ -0,0 +1,74 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Alan Screen <awscreen@chromium.org>
|
||||
Date: Fri, 7 Jan 2022 09:38:01 +0000
|
||||
Subject: Ensure valid print render host before proceeding to print.
|
||||
|
||||
Bug: 1283375
|
||||
Change-Id: I5691fc2a9d09040e777aafd0061b957025643b8a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3369086
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
Commit-Queue: Alan Screen <awscreen@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#956443}
|
||||
|
||||
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
|
||||
index 4662db344afb08574b7ac7d96cb72c71edc802af..c7535ddd5b54ae33fe6f6aea09b6b313ba38b840 100644
|
||||
--- a/chrome/browser/printing/print_view_manager.cc
|
||||
+++ b/chrome/browser/printing/print_view_manager.cc
|
||||
@@ -111,6 +111,11 @@ bool PrintViewManager::PrintForSystemDialogNow(
|
||||
on_print_dialog_shown_callback_ = std::move(dialog_shown_callback);
|
||||
is_switching_to_system_dialog_ = true;
|
||||
|
||||
+ // Remember the ID for `print_preview_rfh_`, to enable checking that the
|
||||
+ // `RenderFrameHost` is still valid after a possible inner message loop runs
|
||||
+ // in `DisconnectFromCurrentPrintJob()`.
|
||||
+ content::GlobalRenderFrameHostId rfh_id = print_preview_rfh_->GetGlobalId();
|
||||
+
|
||||
auto weak_this = weak_factory_.GetWeakPtr();
|
||||
DisconnectFromCurrentPrintJob();
|
||||
if (!weak_this)
|
||||
@@ -120,6 +125,10 @@ bool PrintViewManager::PrintForSystemDialogNow(
|
||||
if (IsCrashed())
|
||||
return false;
|
||||
|
||||
+ // Don't print if `print_preview_rfh_` is no longer live.
|
||||
+ if (!content::RenderFrameHost::FromID(rfh_id))
|
||||
+ return false;
|
||||
+
|
||||
// TODO(crbug.com/809738) Register with `PrintBackendServiceManager` when
|
||||
// system print is enabled out-of-process.
|
||||
|
||||
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
|
||||
index 143ee383668965ba04da092e3445fc9f4a33a433..055d97cb63cb5a1b64ee0a113ec27b664113aba9 100644
|
||||
--- a/chrome/browser/printing/print_view_manager_base.cc
|
||||
+++ b/chrome/browser/printing/print_view_manager_base.cc
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "components/services/print_compositor/public/cpp/print_service_mojo_types.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
+#include "content/public/browser/global_routing_id.h"
|
||||
#include "content/public/browser/notification_details.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
#include "content/public/browser/notification_source.h"
|
||||
@@ -365,6 +366,11 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
|
||||
bool silent,
|
||||
base::Value settings,
|
||||
CompletionCallback callback) {
|
||||
+ // Remember the ID for `rfh`, to enable checking that the `RenderFrameHost`
|
||||
+ // is still valid after a possible inner message loop runs in
|
||||
+ // `DisconnectFromCurrentPrintJob()`.
|
||||
+ content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId();
|
||||
+
|
||||
auto weak_this = weak_ptr_factory_.GetWeakPtr();
|
||||
DisconnectFromCurrentPrintJob();
|
||||
if (!weak_this)
|
||||
@@ -374,6 +380,10 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
|
||||
if (IsCrashed())
|
||||
return false;
|
||||
|
||||
+ // Don't print if `rfh` is no longer live.
|
||||
+ if (!content::RenderFrameHost::FromID(rfh_id))
|
||||
+ return false;
|
||||
+
|
||||
// TODO(crbug.com/809738) Register with `PrintBackendServiceManager` when
|
||||
// system print is enabled out-of-process. A corresponding unregister should
|
||||
// go in `ReleasePrintJob()`.
|
||||
188
patches/chromium/cherry-pick-1284367.patch
Normal file
188
patches/chromium/cherry-pick-1284367.patch
Normal file
@@ -0,0 +1,188 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Xinghui Lu <xinghuilu@chromium.org>
|
||||
Date: Thu, 6 Jan 2022 08:36:45 +0000
|
||||
Subject: Use RFH global id to ensure the RFH is valid.
|
||||
|
||||
Observing via RenderFrameDeleted and RenderFrameHostChanged is not
|
||||
sufficient for validating the RFH is still valid, because the frames
|
||||
can belong to inner WebContents. As suggested in
|
||||
https://crrev.com/c/2449389, storing a GlobalFrameRoutingId is the
|
||||
preferred method of keeping a reference to a RFH.
|
||||
|
||||
Bug: 1284367
|
||||
Change-Id: I3afb40e394d6e2e7fd19b2704e0dd68fa23c7bb2
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3367466
|
||||
Reviewed-by: Daniel Rubery <drubery@chromium.org>
|
||||
Commit-Queue: Xinghui Lu <xinghuilu@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#956061}
|
||||
|
||||
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
|
||||
index ab395a814221a900976fb5f1cdfd79946ea1b742..4bf428b1a7fc8c331d0644c0785f4e57a31c0884 100644
|
||||
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
|
||||
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
|
||||
@@ -601,7 +601,8 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails) {
|
||||
parent_node->children.push_back(GURL(kDOMChildURL));
|
||||
params.push_back(std::move(parent_node));
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(params));
|
||||
|
||||
std::string serialized = WaitForThreatDetailsDone(
|
||||
report.get(), false /* did_proceed*/, 0 /* num_visit */);
|
||||
@@ -820,10 +821,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames) {
|
||||
|
||||
// Send both sets of nodes from different render frames.
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(),
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
std::move(outer_params_copy));
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- child_rfh, std::move(inner_params_copy));
|
||||
+ child_rfh->GetGlobalId(),
|
||||
+ std::move(inner_params_copy));
|
||||
|
||||
std::string serialized = WaitForThreatDetailsDone(
|
||||
report.get(), false /* did_proceed*/, 0 /* num_visit */);
|
||||
@@ -869,9 +871,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames) {
|
||||
|
||||
// Send both sets of nodes from different render frames.
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- child_rfh, std::move(inner_params));
|
||||
+ child_rfh->GetGlobalId(),
|
||||
+ std::move(inner_params));
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(outer_params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(outer_params));
|
||||
|
||||
std::string serialized = WaitForThreatDetailsDone(
|
||||
report.get(), false /* did_proceed*/, 0 /* num_visit */);
|
||||
@@ -995,9 +999,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM) {
|
||||
|
||||
// Send both sets of nodes from different render frames.
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(outer_params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(outer_params));
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- child_rfh, std::move(inner_params));
|
||||
+ child_rfh->GetGlobalId(),
|
||||
+ std::move(inner_params));
|
||||
std::string serialized = WaitForThreatDetailsDone(
|
||||
report.get(), false /* did_proceed*/, 0 /* num_visit */);
|
||||
ClientSafeBrowsingReportRequest actual;
|
||||
@@ -1262,10 +1268,10 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags) {
|
||||
|
||||
// Send both sets of nodes from different render frames.
|
||||
trimmed_report->OnReceivedThreatDOMDetails(
|
||||
- mojo::Remote<mojom::ThreatReporter>(), child_rfh,
|
||||
+ mojo::Remote<mojom::ThreatReporter>(), child_rfh->GetGlobalId(),
|
||||
std::move(inner_params));
|
||||
trimmed_report->OnReceivedThreatDOMDetails(
|
||||
- mojo::Remote<mojom::ThreatReporter>(), main_rfh(),
|
||||
+ mojo::Remote<mojom::ThreatReporter>(), main_rfh()->GetGlobalId(),
|
||||
std::move(outer_params));
|
||||
|
||||
std::string serialized = WaitForThreatDetailsDone(
|
||||
@@ -1338,10 +1344,10 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_EmptyReportNotSent) {
|
||||
|
||||
// Send both sets of nodes from different render frames.
|
||||
trimmed_report->OnReceivedThreatDOMDetails(
|
||||
- mojo::Remote<mojom::ThreatReporter>(), child_rfh,
|
||||
+ mojo::Remote<mojom::ThreatReporter>(), child_rfh->GetGlobalId(),
|
||||
std::move(inner_params));
|
||||
trimmed_report->OnReceivedThreatDOMDetails(
|
||||
- mojo::Remote<mojom::ThreatReporter>(), main_rfh(),
|
||||
+ mojo::Remote<mojom::ThreatReporter>(), main_rfh()->GetGlobalId(),
|
||||
std::move(outer_params));
|
||||
|
||||
std::string serialized = WaitForThreatDetailsDone(
|
||||
@@ -1598,7 +1604,8 @@ TEST_F(ThreatDetailsTest, HTTPCache) {
|
||||
// The cache collection starts after the IPC from the DOM is fired.
|
||||
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(params));
|
||||
|
||||
// Let the cache callbacks complete.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
@@ -1678,7 +1685,8 @@ TEST_F(ThreatDetailsTest, HttpsResourceSanitization) {
|
||||
// The cache collection starts after the IPC from the DOM is fired.
|
||||
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(params));
|
||||
|
||||
// Let the cache callbacks complete.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
@@ -1761,7 +1769,8 @@ TEST_F(ThreatDetailsTest, HTTPCacheNoEntries) {
|
||||
// The cache collection starts after the IPC from the DOM is fired.
|
||||
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(params));
|
||||
|
||||
// Let the cache callbacks complete.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
@@ -1820,7 +1829,8 @@ TEST_F(ThreatDetailsTest, HistoryServiceUrls) {
|
||||
// The redirects collection starts after the IPC from the DOM is fired.
|
||||
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
|
||||
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
|
||||
- main_rfh(), std::move(params));
|
||||
+ main_rfh()->GetGlobalId(),
|
||||
+ std::move(params));
|
||||
|
||||
// Let the redirects callbacks complete.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
diff --git a/components/safe_browsing/content/browser/threat_details.cc b/components/safe_browsing/content/browser/threat_details.cc
|
||||
index f3fe647b5d443c2a2f284289ae66d81782c5f6e8..361830189b0ab6324fe87719f36f2fa0bc948224 100644
|
||||
--- a/components/safe_browsing/content/browser/threat_details.cc
|
||||
+++ b/components/safe_browsing/content/browser/threat_details.cc
|
||||
@@ -664,16 +664,20 @@ void ThreatDetails::RequestThreatDOMDetails(content::RenderFrameHost* frame) {
|
||||
pending_render_frame_hosts_.push_back(frame);
|
||||
raw_threat_report->GetThreatDOMDetails(
|
||||
base::BindOnce(&ThreatDetails::OnReceivedThreatDOMDetails, GetWeakPtr(),
|
||||
- std::move(threat_reporter), frame));
|
||||
+ std::move(threat_reporter), frame->GetGlobalId()));
|
||||
}
|
||||
|
||||
// When the renderer is done, this is called.
|
||||
void ThreatDetails::OnReceivedThreatDOMDetails(
|
||||
mojo::Remote<mojom::ThreatReporter> threat_reporter,
|
||||
- content::RenderFrameHost* sender,
|
||||
+ content::GlobalRenderFrameHostId sender_id,
|
||||
std::vector<mojom::ThreatDOMDetailsNodePtr> params) {
|
||||
// If the RenderFrameHost was closed between sending the IPC and this callback
|
||||
// running, |sender| will be invalid.
|
||||
+ auto* sender = content::RenderFrameHost::FromID(sender_id);
|
||||
+ if (!sender) {
|
||||
+ return;
|
||||
+ }
|
||||
const auto sender_it = std::find(pending_render_frame_hosts_.begin(),
|
||||
pending_render_frame_hosts_.end(), sender);
|
||||
if (sender_it == pending_render_frame_hosts_.end()) {
|
||||
diff --git a/components/safe_browsing/content/browser/threat_details.h b/components/safe_browsing/content/browser/threat_details.h
|
||||
index 8cb89700141561aab49edc474799c9e7148b8ae8..61dcb8d9c772d223661236d99aebd1d3ebe01d3a 100644
|
||||
--- a/components/safe_browsing/content/browser/threat_details.h
|
||||
+++ b/components/safe_browsing/content/browser/threat_details.h
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "components/safe_browsing/core/common/proto/csd.pb.h"
|
||||
#include "components/security_interstitials/core/unsafe_resource.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
+#include "content/public/browser/global_routing_id.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
|
||||
@@ -169,7 +170,7 @@ class ThreatDetails : public content::WebContentsObserver {
|
||||
|
||||
void OnReceivedThreatDOMDetails(
|
||||
mojo::Remote<mojom::ThreatReporter> threat_reporter,
|
||||
- content::RenderFrameHost* sender,
|
||||
+ content::GlobalRenderFrameHostId sender_id,
|
||||
std::vector<mojom::ThreatDOMDetailsNodePtr> params);
|
||||
|
||||
void AddRedirectUrlList(const std::vector<GURL>& urls);
|
||||
89
patches/chromium/cherry-pick-12ba78f3fa7a.patch
Normal file
89
patches/chromium/cherry-pick-12ba78f3fa7a.patch
Normal file
@@ -0,0 +1,89 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Date: Mon, 25 Apr 2022 20:57:43 +0000
|
||||
Subject: Sanitize DragData markup before inserting it into document
|
||||
|
||||
(cherry picked from commit 5164a0fe3391283663e1196cf4576ec233985e89)
|
||||
|
||||
Fixed: 1315040
|
||||
Change-Id: I8a0ddfb983d12c185f7e943d3d5277788199b011
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3579670
|
||||
Quick-Run: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Commit-Queue: Kent Tamura <tkent@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#991324}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3589799
|
||||
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
|
||||
Owners-Override: Achuith Bhandarkar <achuith@chromium.org>
|
||||
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4664@{#1602}
|
||||
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/page/drag_data.cc b/third_party/blink/renderer/core/page/drag_data.cc
|
||||
index d5ace3a879ab5ab00557ba380d9470d9eb937286..36ad9f68d3a79fe3d7d948276a654aacf5db019b 100644
|
||||
--- a/third_party/blink/renderer/core/page/drag_data.cc
|
||||
+++ b/third_party/blink/renderer/core/page/drag_data.cc
|
||||
@@ -131,8 +131,8 @@ DocumentFragment* DragData::AsFragment(LocalFrame* frame) const {
|
||||
platform_drag_data_->HtmlAndBaseURL(html, base_url);
|
||||
DCHECK(frame->GetDocument());
|
||||
if (DocumentFragment* fragment =
|
||||
- CreateFragmentFromMarkup(*frame->GetDocument(), html, base_url,
|
||||
- kDisallowScriptingAndPluginContent))
|
||||
+ CreateSanitizedFragmentFromMarkupWithContext(
|
||||
+ *frame->GetDocument(), html, 0, html.length(), base_url))
|
||||
return fragment;
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/web_tests/editing/pasteboard/drag-and-drop-svg-use-sanitize.html b/third_party/blink/web_tests/editing/pasteboard/drag-and-drop-svg-use-sanitize.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..58551d28341d851dbd99322e2a5d3af68b3b0c72
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/editing/pasteboard/drag-and-drop-svg-use-sanitize.html
|
||||
@@ -0,0 +1,47 @@
|
||||
+<!doctype html>
|
||||
+<script src="../../resources/testharness.js"></script>
|
||||
+<script src="../../resources/testharnessreport.js"></script>
|
||||
+
|
||||
+<div id="drag-from" draggable=true>Drag from</div>
|
||||
+<div id="drag-to" contenteditable>Drag to</div>
|
||||
+
|
||||
+<script>
|
||||
+function computePoint(element) {
|
||||
+ return {
|
||||
+ x: element.offsetLeft + element.offsetWidth / 2,
|
||||
+ y: element.offsetTop + element.offsetHeight / 2
|
||||
+ };
|
||||
+}
|
||||
+
|
||||
+let dragged = false;
|
||||
+let executed = false;
|
||||
+const payload = `
|
||||
+ <svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='fake' onerror='executed=true' /></svg>#x" />
|
||||
+`;
|
||||
+
|
||||
+const dragFrom = document.getElementById('drag-from');
|
||||
+dragFrom.ondragstart = event => {
|
||||
+ dragged = true;
|
||||
+ event.dataTransfer.setData('text/html', payload);
|
||||
+}
|
||||
+
|
||||
+const dragTo = document.getElementById('drag-to');
|
||||
+
|
||||
+promise_test(async test => {
|
||||
+ assert_own_property(window, 'eventSender', 'This test requires eventSender to simulate drag and drop');
|
||||
+
|
||||
+ const fromPoint = computePoint(dragFrom);
|
||||
+ eventSender.mouseMoveTo(fromPoint.x, fromPoint.y);
|
||||
+ eventSender.mouseDown();
|
||||
+
|
||||
+ const toPoint = computePoint(dragTo);
|
||||
+ eventSender.mouseMoveTo(toPoint.x, toPoint.y);
|
||||
+ eventSender.mouseUp();
|
||||
+
|
||||
+ assert_true(dragged, 'Element should be dragged');
|
||||
+
|
||||
+ // The 'error' event is dispatched asynchronously.
|
||||
+ await new Promise(resolve => test.step_timeout(resolve, 100));
|
||||
+ assert_false(executed, 'Script should be blocked');
|
||||
+}, 'Script in SVG use href should be sanitized');
|
||||
+</script>
|
||||
118
patches/chromium/cherry-pick-1665a1d16d46.patch
Normal file
118
patches/chromium/cherry-pick-1665a1d16d46.patch
Normal file
@@ -0,0 +1,118 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "msw@chromium.org" <msw@chromium.org>
|
||||
Date: Tue, 1 Feb 2022 21:16:10 +0000
|
||||
Subject: Reland "Make web cursor size limits match on browser and renderer"
|
||||
|
||||
This reverts commit 38a8343085e53889eba48fcff78a6c2295927333.
|
||||
|
||||
Reason for revert: Fix without regressing https://crbug.com/1292426
|
||||
(Increased WebCursor limit 128->150px to support DevToolsEyeDropper)
|
||||
|
||||
Original change's description:
|
||||
> Revert "Make web cursor size limits match on browser and renderer"
|
||||
>
|
||||
> This reverts commit 868b44dd8b4a1a3b9698f561ca17f75e4ec78dd2.
|
||||
>
|
||||
> Reason for revert: https://crbug.com/1292426
|
||||
>
|
||||
> Original change's description:
|
||||
> > Make web cursor size limits match on browser and renderer
|
||||
> >
|
||||
> > Use NSCursor arrowCursor on Mac for ui::mojom::CursorType::kNull.
|
||||
> > (i.e. when WebCursor is constructed with an overly large custom cursor)
|
||||
> >
|
||||
> > Bug: 1246188
|
||||
> > Test: Automated unit tests and WPTs
|
||||
> > Change-Id: I89627fa13cba96b755b8f80adbc91cfc865b6b1b
|
||||
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3413912
|
||||
> > Reviewed-by: Henrique Ferreiro <hferreiro@igalia.com>
|
||||
> > Reviewed-by: Charlie Harrison <csharrison@chromium.org>
|
||||
> > Commit-Queue: Mike Wasserman <msw@chromium.org>
|
||||
> > Auto-Submit: Mike Wasserman <msw@chromium.org>
|
||||
> > Cr-Commit-Position: refs/heads/main@{#964378}
|
||||
>
|
||||
> Bug: 1246188
|
||||
> Change-Id: Id7b3b88e65c012993537ce96c2b5064b7b76646e
|
||||
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3428347
|
||||
> Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
> Commit-Queue: Mike Wasserman <msw@chromium.org>
|
||||
> Cr-Commit-Position: refs/heads/main@{#965475}
|
||||
|
||||
Fixed: 1246188
|
||||
Bug: 1292426
|
||||
Change-Id: I5a490603c3e21e17f3136a3d792a18429eb3f633
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3428624
|
||||
Auto-Submit: Mike Wasserman <msw@chromium.org>
|
||||
Reviewed-by: Charlie Harrison <csharrison@chromium.org>
|
||||
Commit-Queue: Mike Wasserman <msw@chromium.org>
|
||||
Reviewed-by: Henrique Ferreiro <hferreiro@igalia.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#965857}
|
||||
|
||||
diff --git a/content/common/cursors/webcursor.cc b/content/common/cursors/webcursor.cc
|
||||
index c8b6b9d3f75d0cac98cc4ab8e71b68117837c1dc..4c80616e41e6ba5b171ae09d06d7f4110589f70a 100644
|
||||
--- a/content/common/cursors/webcursor.cc
|
||||
+++ b/content/common/cursors/webcursor.cc
|
||||
@@ -22,16 +22,19 @@ WebCursor::WebCursor(const ui::Cursor& cursor) {
|
||||
WebCursor::WebCursor(const WebCursor& other) = default;
|
||||
|
||||
bool WebCursor::SetCursor(const ui::Cursor& cursor) {
|
||||
- static constexpr int kMaxSize = 1024;
|
||||
+ // This value is just large enough to accommodate:
|
||||
+ // - kMaximumCursorSize in Blink's EventHandler
|
||||
+ // - kCursorSize in Chrome's DevToolsEyeDropper
|
||||
+ static constexpr int kMaximumCursorSize = 150;
|
||||
if (cursor.image_scale_factor() < 0.01f ||
|
||||
cursor.image_scale_factor() > 100.f ||
|
||||
(cursor.type() == ui::mojom::CursorType::kCustom &&
|
||||
- (cursor.custom_bitmap().width() > kMaxSize ||
|
||||
- cursor.custom_bitmap().height() > kMaxSize ||
|
||||
+ (cursor.custom_bitmap().width() > kMaximumCursorSize ||
|
||||
+ cursor.custom_bitmap().height() > kMaximumCursorSize ||
|
||||
cursor.custom_bitmap().width() / cursor.image_scale_factor() >
|
||||
- kMaxSize ||
|
||||
+ kMaximumCursorSize ||
|
||||
cursor.custom_bitmap().height() / cursor.image_scale_factor() >
|
||||
- kMaxSize))) {
|
||||
+ kMaximumCursorSize))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/content/common/cursors/webcursor_mac.mm b/content/common/cursors/webcursor_mac.mm
|
||||
index f85c421f8581abe191738eaee133004b729a817d..fdc70bdff2ddc517f3e341dd16263ae89d8b153f 100644
|
||||
--- a/content/common/cursors/webcursor_mac.mm
|
||||
+++ b/content/common/cursors/webcursor_mac.mm
|
||||
@@ -265,6 +265,7 @@ - (CrCoreCursorType)_coreCursorType {
|
||||
case ui::mojom::CursorType::kCustom:
|
||||
return CreateCustomCursor(cursor_);
|
||||
case ui::mojom::CursorType::kNull:
|
||||
+ return [NSCursor arrowCursor];
|
||||
case ui::mojom::CursorType::kDndNone:
|
||||
case ui::mojom::CursorType::kDndMove:
|
||||
case ui::mojom::CursorType::kDndCopy:
|
||||
diff --git a/content/common/cursors/webcursor_unittest.cc b/content/common/cursors/webcursor_unittest.cc
|
||||
index 530f0e2cc0e7255fb120ebdef45c57d01c0f2b5f..b948e52da81d2d12543d76575c49bfa8a09288c4 100644
|
||||
--- a/content/common/cursors/webcursor_unittest.cc
|
||||
+++ b/content/common/cursors/webcursor_unittest.cc
|
||||
@@ -122,11 +122,11 @@ TEST(WebCursorTest, SetCursor) {
|
||||
|
||||
// SetCursor should return false when the image width is too large.
|
||||
cursor.set_image_scale_factor(1.f);
|
||||
- cursor.set_custom_bitmap(CreateTestBitmap(1025, 3));
|
||||
+ cursor.set_custom_bitmap(CreateTestBitmap(151, 3));
|
||||
EXPECT_FALSE(webcursor.SetCursor(cursor));
|
||||
|
||||
// SetCursor should return false when the image height is too large.
|
||||
- cursor.set_custom_bitmap(CreateTestBitmap(3, 1025));
|
||||
+ cursor.set_custom_bitmap(CreateTestBitmap(3, 151));
|
||||
EXPECT_FALSE(webcursor.SetCursor(cursor));
|
||||
|
||||
// SetCursor should return false when the scaled image width is too large.
|
||||
@@ -136,7 +136,7 @@ TEST(WebCursorTest, SetCursor) {
|
||||
|
||||
// SetCursor should return false when the scaled image height is too large.
|
||||
cursor.set_image_scale_factor(0.1f);
|
||||
- cursor.set_custom_bitmap(CreateTestBitmap(5, 200));
|
||||
+ cursor.set_custom_bitmap(CreateTestBitmap(5, 20));
|
||||
EXPECT_FALSE(webcursor.SetCursor(cursor));
|
||||
}
|
||||
|
||||
53
patches/chromium/cherry-pick-1887414c016d.patch
Normal file
53
patches/chromium/cherry-pick-1887414c016d.patch
Normal file
@@ -0,0 +1,53 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Muyao Xu <muyaoxu@google.com>
|
||||
Date: Thu, 17 Feb 2022 16:23:29 +0000
|
||||
Subject: Replace WidgetObserver::OnWidgetClosing() with OnWidgetDestroying()
|
||||
|
||||
In some cases, OnWidgetClosing() is not called when the widget is
|
||||
closed, resulting an invalid pointer |widget_| stored in
|
||||
WebContentsDisplayObserverView.
|
||||
|
||||
This CL replaces OnWidgetClosing() with OnWidgetDestroying(), which
|
||||
is recommended in crbug.com/1240365
|
||||
|
||||
(cherry picked from commit 4535fe2334d0713535adb52b641a8cb34e11333c)
|
||||
|
||||
Bug: 1291728
|
||||
Change-Id: I64fef8b30930f60220008809ee00f4385d6c3520
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3425473
|
||||
Auto-Submit: Muyao Xu <muyaoxu@google.com>
|
||||
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#965431}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3435985
|
||||
Reviewed-by: Michael Ershov <miersh@google.com>
|
||||
Owners-Override: Michael Ershov <miersh@google.com>
|
||||
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4664@{#1480}
|
||||
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
|
||||
|
||||
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
|
||||
index 80d33b238cd7455ec5b44d5fd966f42f690946bf..2061c2ecb476cd33ed999f180c0293641f7ac23a 100644
|
||||
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
|
||||
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
|
||||
@@ -65,7 +65,7 @@ void WebContentsDisplayObserverView::OnBrowserSetLastActive(Browser* browser) {
|
||||
}
|
||||
}
|
||||
|
||||
-void WebContentsDisplayObserverView::OnWidgetClosing(views::Widget* widget) {
|
||||
+void WebContentsDisplayObserverView::OnWidgetDestroying(views::Widget* widget) {
|
||||
if (widget_)
|
||||
widget_->RemoveObserver(this);
|
||||
widget_ = nullptr;
|
||||
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
|
||||
index 17a8ca48b1c836a82e2be5e5c605bc1837150cba..b63cf4505318a44c65585b06ec13960bad5d9e32 100644
|
||||
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
|
||||
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
|
||||
@@ -28,7 +28,7 @@ class WebContentsDisplayObserverView : public WebContentsDisplayObserver,
|
||||
void OnBrowserSetLastActive(Browser* browser) override;
|
||||
|
||||
// views::WidgetObserver overrides:
|
||||
- void OnWidgetClosing(views::Widget* widget) override;
|
||||
+ void OnWidgetDestroying(views::Widget* widget) override;
|
||||
void OnWidgetBoundsChanged(views::Widget* widget,
|
||||
const gfx::Rect& new_bounds) override;
|
||||
|
||||
62
patches/chromium/cherry-pick-1a31e2110440.patch
Normal file
62
patches/chromium/cherry-pick-1a31e2110440.patch
Normal file
@@ -0,0 +1,62 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Date: Tue, 5 Apr 2022 20:44:33 +0000
|
||||
Subject: Disallow CSS-wide keywords for StylePropertyMap.set
|
||||
|
||||
We don't support this properly, and the spec does not handle CSS-keywords
|
||||
either. Disallow it until we can add proper support for this.
|
||||
|
||||
(cherry picked from commit 02e4b18febb37de8baea718bc2f62cfb5fe56e23)
|
||||
|
||||
Fixed: 1292905
|
||||
Bug: 1310761
|
||||
Change-Id: Ieb3d20edfea72c2ccb0928536fdfd86d10aad1a9
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3551609
|
||||
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
|
||||
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#986411}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3572186
|
||||
Commit-Queue: Srinivas Sista <srinivassista@chromium.org>
|
||||
Auto-Submit: Srinivas Sista <srinivassista@chromium.org>
|
||||
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4896@{#1041}
|
||||
Cr-Branched-From: 1f63ff4bc27570761b35ffbc7f938f6586f7bee8-refs/heads/main@{#972766}
|
||||
|
||||
diff --git a/third_party/blink/renderer/build/scripts/core/css/templates/cssom_keywords.cc.tmpl b/third_party/blink/renderer/build/scripts/core/css/templates/cssom_keywords.cc.tmpl
|
||||
index 87caef2cf5cf56b7bf72752410648ef1d7bb9f9a..59c505707216362d3a3b662a6a531398b8f5009e 100644
|
||||
--- a/third_party/blink/renderer/build/scripts/core/css/templates/cssom_keywords.cc.tmpl
|
||||
+++ b/third_party/blink/renderer/build/scripts/core/css/templates/cssom_keywords.cc.tmpl
|
||||
@@ -21,8 +21,10 @@ bool CSSOMKeywords::ValidKeywordForProperty(CSSPropertyID id,
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (css_parsing_utils::IsCSSWideKeyword(valueID))
|
||||
- return true;
|
||||
+ if (css_parsing_utils::IsCSSWideKeyword(valueID)) {
|
||||
+ // TODO(crbug.com/1310761): Support CSS-wide keywords in custom props.
|
||||
+ return id != CSSPropertyID::kVariable;
|
||||
+ }
|
||||
|
||||
switch (id) {
|
||||
{% for property in properties if property.keywordIDs and 'Keyword' in property.typedom_types %}
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/set-css-wide-in-custom-property-crash.html b/third_party/blink/web_tests/external/wpt/css/css-typed-om/set-css-wide-in-custom-property-crash.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..bc977c9889889bd8a35eccc48ac28e25871b1ec9
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/set-css-wide-in-custom-property-crash.html
|
||||
@@ -0,0 +1,15 @@
|
||||
+<!DOCTYPE html>
|
||||
+<title>Don't crash when setting a CSS-wide keyword on a custom property</title>
|
||||
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
|
||||
+<link rel="help" href="https://crbug.com/1310761<">
|
||||
+<div id="target">
|
||||
+ Don't crash
|
||||
+</div>
|
||||
+<script>
|
||||
+ for (let keyword of ['initial', 'inherit', 'unset', 'revert', 'revert-layer']) {
|
||||
+ try {
|
||||
+ target.attributeStyleMap.set('--x', new CSSKeywordValue(keyword));
|
||||
+ } catch (e) {
|
||||
+ }
|
||||
+ }
|
||||
+</script>
|
||||
354
patches/chromium/cherry-pick-1a8af2da50e4.patch
Normal file
354
patches/chromium/cherry-pick-1a8af2da50e4.patch
Normal file
@@ -0,0 +1,354 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lukasz Anforowicz <lukasza@chromium.org>
|
||||
Date: Mon, 8 Nov 2021 15:05:30 +0000
|
||||
Subject: Deleting unused field: `FetchEventPreloadHandle::url_loader`.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The `FetchEventPreloadHandle::url_loader` field is not really used - it
|
||||
is only needed to keep the URLLoader alive (and this can be accomplished
|
||||
in a simpler way, by keeping the mojo::PendingRemote in the Browser
|
||||
process).
|
||||
|
||||
This CL removes the `FetchEventPreloadHandle::url_loader` field and the
|
||||
FetchEventPreloadHandle and WebFetchEventPreloadHandle types (collapsing
|
||||
these handle types into their only other remaining field:
|
||||
mojo::PendingReceiver<network::mojom::URLLoaderClient>).
|
||||
|
||||
(cherry picked from commit dbe67ccde52e30acf6a66b1b9cc83768a067fa6a)
|
||||
|
||||
Fixed: 1264477
|
||||
Change-Id: I9c9c54900d79e92ac08eeb43536c938fa84a58f8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3252914
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Reviewed-by: Ben Kelly <wanderview@chromium.org>
|
||||
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
|
||||
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#937895}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3262600
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Commit-Queue: Ben Kelly <wanderview@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4664@{#853}
|
||||
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
|
||||
|
||||
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
|
||||
index 0d034293826354f6d1b7910a6604f241ff1c8988..b980c5a0745eaf7a904c1047cbe6c5e86cef0c67 100644
|
||||
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
|
||||
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
|
||||
@@ -449,8 +449,10 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets
|
||||
// NetworkService.
|
||||
URLLoaderAssets(
|
||||
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
|
||||
+ mojo::PendingRemote<network::mojom::URLLoader> url_loader,
|
||||
std::unique_ptr<DelegatingURLLoaderClient> url_loader_client)
|
||||
: shared_url_loader_factory_(std::move(shared_url_loader_factory)),
|
||||
+ url_loader_(std::move(url_loader)),
|
||||
url_loader_client_(std::move(url_loader_client)) {}
|
||||
|
||||
void MaybeReportToDevTools(std::pair<int, int> worker_id,
|
||||
@@ -467,6 +469,7 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets
|
||||
|
||||
// NetworkService:
|
||||
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
|
||||
+ mojo::PendingRemote<network::mojom::URLLoader> url_loader_;
|
||||
|
||||
// Both:
|
||||
std::unique_ptr<DelegatingURLLoaderClient> url_loader_client_;
|
||||
@@ -633,7 +636,8 @@ void ServiceWorkerFetchDispatcher::DispatchFetchEvent() {
|
||||
auto params = blink::mojom::DispatchFetchEventParams::New();
|
||||
params->request = std::move(request_);
|
||||
params->client_id = client_id_;
|
||||
- params->preload_handle = std::move(preload_handle_);
|
||||
+ params->preload_url_loader_client_receiver =
|
||||
+ std::move(preload_url_loader_client_receiver_);
|
||||
params->is_offline_capability_check = is_offline_capability_check_;
|
||||
|
||||
// TODO(https://crbug.com/900700): Make the remote connected to a receiver
|
||||
@@ -721,13 +725,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
|
||||
// When the fetch event is for an offline capability check, respond to the
|
||||
// navigation preload with a network disconnected error, to simulate offline.
|
||||
if (is_offline_capability_check_) {
|
||||
- mojo::PendingRemote<network::mojom::URLLoader> url_loader_to_pass;
|
||||
mojo::Remote<network::mojom::URLLoaderClient> url_loader_client;
|
||||
- auto dummy_receiver = url_loader_to_pass.InitWithNewPipeAndPassReceiver();
|
||||
|
||||
- preload_handle_ = blink::mojom::FetchEventPreloadHandle::New();
|
||||
- preload_handle_->url_loader = std::move(url_loader_to_pass);
|
||||
- preload_handle_->url_loader_client_receiver =
|
||||
+ preload_url_loader_client_receiver_ =
|
||||
url_loader_client.BindNewPipeAndPassReceiver();
|
||||
|
||||
url_loader_client->OnComplete(
|
||||
@@ -770,12 +770,10 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
|
||||
factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
|
||||
std::move(network_factory));
|
||||
|
||||
- preload_handle_ = blink::mojom::FetchEventPreloadHandle::New();
|
||||
-
|
||||
// Create the DelegatingURLLoaderClient, which becomes the
|
||||
// URLLoaderClient for the navigation preload network request.
|
||||
mojo::PendingRemote<network::mojom::URLLoaderClient> inner_url_loader_client;
|
||||
- preload_handle_->url_loader_client_receiver =
|
||||
+ preload_url_loader_client_receiver_ =
|
||||
inner_url_loader_client.InitWithNewPipeAndPassReceiver();
|
||||
auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
|
||||
std::move(inner_url_loader_client), resource_request);
|
||||
@@ -810,11 +808,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
|
||||
net::MutableNetworkTrafficAnnotationTag(
|
||||
kNavigationPreloadTrafficAnnotation));
|
||||
|
||||
- preload_handle_->url_loader = std::move(url_loader);
|
||||
-
|
||||
DCHECK(!url_loader_assets_);
|
||||
url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
|
||||
- std::move(factory), std::move(url_loader_client));
|
||||
+ std::move(factory), std::move(url_loader), std::move(url_loader_client));
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h
|
||||
index 5b2a45bff25b7f2c35e304385f22935c33d60a05..b96b2de068bf9f6a38b4d995cf137ebfd53735ea 100644
|
||||
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h
|
||||
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
|
||||
@@ -121,10 +121,11 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
|
||||
|
||||
scoped_refptr<URLLoaderAssets> url_loader_assets_;
|
||||
|
||||
- // |preload_handle_| holds the URLLoader and URLLoaderClient for the service
|
||||
- // worker to receive the navigation preload response. It's passed to the
|
||||
- // service worker along with the fetch event.
|
||||
- blink::mojom::FetchEventPreloadHandlePtr preload_handle_;
|
||||
+ // Holds the URLLoaderClient for the service worker to receive the navigation
|
||||
+ // preload response. It's passed to the service worker along with the fetch
|
||||
+ // event.
|
||||
+ mojo::PendingReceiver<network::mojom::URLLoaderClient>
|
||||
+ preload_url_loader_client_receiver_;
|
||||
|
||||
// Whether to dispatch an offline-capability-check fetch event.
|
||||
const bool is_offline_capability_check_ = false;
|
||||
diff --git a/content/renderer/service_worker/navigation_preload_request.cc b/content/renderer/service_worker/navigation_preload_request.cc
|
||||
index c9e9ffd4c68a583569fd5633ca2369e190e2aed7..92f9d4a7de115cac0502aeb9c777605a756b6175 100644
|
||||
--- a/content/renderer/service_worker/navigation_preload_request.cc
|
||||
+++ b/content/renderer/service_worker/navigation_preload_request.cc
|
||||
@@ -19,12 +19,12 @@ NavigationPreloadRequest::NavigationPreloadRequest(
|
||||
ServiceWorkerContextClient* owner,
|
||||
int fetch_event_id,
|
||||
const GURL& url,
|
||||
- blink::mojom::FetchEventPreloadHandlePtr preload_handle)
|
||||
+ mojo::PendingReceiver<network::mojom::URLLoaderClient>
|
||||
+ preload_url_loader_client_receiver)
|
||||
: owner_(owner),
|
||||
fetch_event_id_(fetch_event_id),
|
||||
url_(url),
|
||||
- url_loader_(std::move(preload_handle->url_loader)),
|
||||
- receiver_(this, std::move(preload_handle->url_loader_client_receiver)) {}
|
||||
+ receiver_(this, std::move(preload_url_loader_client_receiver)) {}
|
||||
|
||||
NavigationPreloadRequest::~NavigationPreloadRequest() = default;
|
||||
|
||||
diff --git a/content/renderer/service_worker/navigation_preload_request.h b/content/renderer/service_worker/navigation_preload_request.h
|
||||
index 08cfc4a0dad5777b88f2388da5d07c864d9953fd..f6d19a3d1383767e1c450be7ec29a47ff245ff5a 100644
|
||||
--- a/content/renderer/service_worker/navigation_preload_request.h
|
||||
+++ b/content/renderer/service_worker/navigation_preload_request.h
|
||||
@@ -35,7 +35,8 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient {
|
||||
ServiceWorkerContextClient* owner,
|
||||
int fetch_event_id,
|
||||
const GURL& url,
|
||||
- blink::mojom::FetchEventPreloadHandlePtr preload_handle);
|
||||
+ mojo::PendingReceiver<network::mojom::URLLoaderClient>
|
||||
+ preload_url_loader_client_receiver);
|
||||
~NavigationPreloadRequest() override;
|
||||
|
||||
// network::mojom::URLLoaderClient:
|
||||
@@ -59,11 +60,10 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient {
|
||||
void ReportErrorToOwner(const std::string& message,
|
||||
blink::WebServiceWorkerError::Mode error_mode);
|
||||
|
||||
- ServiceWorkerContextClient* owner_;
|
||||
+ ServiceWorkerContextClient* owner_ = nullptr;
|
||||
|
||||
- const int fetch_event_id_;
|
||||
+ const int fetch_event_id_ = -1;
|
||||
const GURL url_;
|
||||
- mojo::Remote<network::mojom::URLLoader> url_loader_;
|
||||
mojo::Receiver<network::mojom::URLLoaderClient> receiver_;
|
||||
|
||||
std::unique_ptr<blink::WebURLResponse> response_;
|
||||
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
|
||||
index d569c5362c0c3866b333db714d7dd8e7f3344afc..f65f535b5c228ce881a0b0066b67d9847b6168a4 100644
|
||||
--- a/content/renderer/service_worker/service_worker_context_client.cc
|
||||
+++ b/content/renderer/service_worker/service_worker_context_client.cc
|
||||
@@ -476,14 +476,14 @@ void ServiceWorkerContextClient::SendWorkerStarted(
|
||||
void ServiceWorkerContextClient::SetupNavigationPreload(
|
||||
int fetch_event_id,
|
||||
const blink::WebURL& url,
|
||||
- std::unique_ptr<blink::WebFetchEventPreloadHandle> preload_handle) {
|
||||
+ blink::CrossVariantMojoReceiver<
|
||||
+ network::mojom::URLLoaderClientInterfaceBase>
|
||||
+ preload_url_loader_client_receiver) {
|
||||
DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
|
||||
DCHECK(context_);
|
||||
auto preload_request = std::make_unique<NavigationPreloadRequest>(
|
||||
this, fetch_event_id, GURL(url),
|
||||
- blink::mojom::FetchEventPreloadHandle::New(
|
||||
- std::move(preload_handle->url_loader),
|
||||
- std::move(preload_handle->url_loader_client_receiver)));
|
||||
+ std::move(preload_url_loader_client_receiver));
|
||||
context_->preload_requests.AddWithID(std::move(preload_request),
|
||||
fetch_event_id);
|
||||
}
|
||||
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
|
||||
index 8191aaec6ed37c6a64bcbd9beac720777de3075e..5abd533c6c3b1926efa6b8fc158562468cc96e19 100644
|
||||
--- a/content/renderer/service_worker/service_worker_context_client.h
|
||||
+++ b/content/renderer/service_worker/service_worker_context_client.h
|
||||
@@ -159,8 +159,9 @@ class CONTENT_EXPORT ServiceWorkerContextClient
|
||||
const blink::WebString& source_url) override;
|
||||
void SetupNavigationPreload(int fetch_event_id,
|
||||
const blink::WebURL& url,
|
||||
- std::unique_ptr<blink::WebFetchEventPreloadHandle>
|
||||
- preload_handle) override;
|
||||
+ blink::CrossVariantMojoReceiver<
|
||||
+ network::mojom::URLLoaderClientInterfaceBase>
|
||||
+ preload_url_loader_client_receiver) override;
|
||||
void RequestTermination(RequestTerminationCallback callback) override;
|
||||
scoped_refptr<blink::WebServiceWorkerFetchContext>
|
||||
CreateWorkerFetchContextOnInitiatorThread() override;
|
||||
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
|
||||
index b950df5a7733b26ae3a9dbc1bacc208e584fa9e6..334ba1c8fd92aed36dec6993afe38ca91ffcc49a 100644
|
||||
--- a/mojo/public/cpp/bindings/README.md
|
||||
+++ b/mojo/public/cpp/bindings/README.md
|
||||
@@ -1709,6 +1709,9 @@ C++ sources can depend on shared sources only, by referencing the
|
||||
`"${target_name}_shared"` target, e.g. `"//foo/mojom:mojom_shared"` in the
|
||||
example above.
|
||||
|
||||
+For converting between Blink and non-Blink variants, please see
|
||||
+`//third_party/blink/public/platform/cross_variant_mojo_util.h`.
|
||||
+
|
||||
## Versioning Considerations
|
||||
|
||||
For general documentation of versioning in the Mojom IDL see
|
||||
diff --git a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
|
||||
index 382be0b3dd042ceadb73e4d514f93ac7c8624b43..c95a2e255166871ff45b6a4c3a8b206e1dace776 100644
|
||||
--- a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
|
||||
+++ b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom
|
||||
@@ -9,13 +9,6 @@ import "third_party/blink/public/mojom/blob/blob.mojom";
|
||||
import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
|
||||
import "third_party/blink/public/mojom/timing/worker_timing_container.mojom";
|
||||
|
||||
-// Used for service worker navigation preload, to create
|
||||
-// FetchEvent#preloadResponse.
|
||||
-struct FetchEventPreloadHandle {
|
||||
- pending_remote<network.mojom.URLLoader> url_loader;
|
||||
- pending_receiver<network.mojom.URLLoaderClient> url_loader_client_receiver;
|
||||
-};
|
||||
-
|
||||
// Parameters used for dispatching a FetchEvent.
|
||||
struct DispatchFetchEventParams {
|
||||
// FetchEvent#request.
|
||||
@@ -23,8 +16,9 @@ struct DispatchFetchEventParams {
|
||||
|
||||
// FetchEvent#clientId.
|
||||
string client_id;
|
||||
+
|
||||
// FetchEvent#preloadResponse.
|
||||
- FetchEventPreloadHandle? preload_handle;
|
||||
+ pending_receiver<network.mojom.URLLoaderClient>? preload_url_loader_client_receiver;
|
||||
|
||||
// This is currently null for navigation because it's still being implemented.
|
||||
// TODO(https://crbug.com/900700): Make this non-nullable when implementation
|
||||
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
|
||||
index 67c0c9d3cb10478755422b489c97afe8adce1a24..0a8cde9a7f6bab9de2c43f13c1bc0d35375bc2b5 100644
|
||||
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
|
||||
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
|
||||
@@ -31,8 +31,6 @@
|
||||
#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_
|
||||
#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_
|
||||
|
||||
-#include <memory>
|
||||
-
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "services/network/public/mojom/url_loader.mojom-shared.h"
|
||||
#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
|
||||
@@ -53,14 +51,6 @@ namespace blink {
|
||||
class WebServiceWorkerContextProxy;
|
||||
class WebString;
|
||||
|
||||
-// Used to pass the mojom struct blink.mojom.FetchEventPreloadHandle across the
|
||||
-// boundary between //content and Blink.
|
||||
-struct WebFetchEventPreloadHandle {
|
||||
- CrossVariantMojoRemote<network::mojom::URLLoaderInterfaceBase> url_loader;
|
||||
- CrossVariantMojoReceiver<network::mojom::URLLoaderClientInterfaceBase>
|
||||
- url_loader_client_receiver;
|
||||
-};
|
||||
-
|
||||
// WebServiceWorkerContextClient is a "client" of a service worker execution
|
||||
// context. This interface is implemented by the embedder and allows the
|
||||
// embedder to communicate with the service worker execution context. It is
|
||||
@@ -166,7 +156,8 @@ class WebServiceWorkerContextClient {
|
||||
virtual void SetupNavigationPreload(
|
||||
int fetch_event_id,
|
||||
const WebURL& url,
|
||||
- std::unique_ptr<WebFetchEventPreloadHandle> preload_handle) {}
|
||||
+ CrossVariantMojoReceiver<network::mojom::URLLoaderClientInterfaceBase>
|
||||
+ preload_url_loader_client_receiver) {}
|
||||
|
||||
// Called when we need to request to terminate this worker due to idle
|
||||
// timeout.
|
||||
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
|
||||
index 9c2cff1d0433d55c4b08fd4eef83544bd120425b..3e84a0200950a33c93f6e473a2cace4609389aea 100644
|
||||
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
|
||||
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
|
||||
@@ -1514,11 +1514,12 @@ void ServiceWorkerGlobalScope::StartFetchEvent(
|
||||
params->request->url.ElidedString().Utf8());
|
||||
|
||||
// Set up for navigation preload (FetchEvent#preloadResponse) if needed.
|
||||
- const bool navigation_preload_sent = !!params->preload_handle;
|
||||
+ bool navigation_preload_sent = !!params->preload_url_loader_client_receiver;
|
||||
if (navigation_preload_sent) {
|
||||
To<ServiceWorkerGlobalScopeProxy>(ReportingProxy())
|
||||
- .SetupNavigationPreload(event_id, params->request->url,
|
||||
- std::move(params->preload_handle));
|
||||
+ .SetupNavigationPreload(
|
||||
+ event_id, params->request->url,
|
||||
+ std::move(params->preload_url_loader_client_receiver));
|
||||
}
|
||||
|
||||
ScriptState::Scope scope(ScriptController()->GetScriptState());
|
||||
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
|
||||
index b2efbea7c370b7f641cad9c5db75f9826ec705ed..33d11a19b350e1dd12c105403ed513e9a62a76ec 100644
|
||||
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
|
||||
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
|
||||
@@ -257,14 +257,11 @@ bool ServiceWorkerGlobalScopeProxy::IsServiceWorkerGlobalScopeProxy() const {
|
||||
void ServiceWorkerGlobalScopeProxy::SetupNavigationPreload(
|
||||
int fetch_event_id,
|
||||
const KURL& url,
|
||||
- mojom::blink::FetchEventPreloadHandlePtr preload_handle) {
|
||||
+ mojo::PendingReceiver<network::mojom::blink::URLLoaderClient>
|
||||
+ preload_url_loader_client_receiver) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
|
||||
- auto web_preload_handle = std::make_unique<WebFetchEventPreloadHandle>();
|
||||
- web_preload_handle->url_loader = std::move(preload_handle->url_loader);
|
||||
- web_preload_handle->url_loader_client_receiver =
|
||||
- std::move(preload_handle->url_loader_client_receiver);
|
||||
- Client().SetupNavigationPreload(fetch_event_id, url,
|
||||
- std::move(web_preload_handle));
|
||||
+ Client().SetupNavigationPreload(
|
||||
+ fetch_event_id, url, std::move(preload_url_loader_client_receiver));
|
||||
}
|
||||
|
||||
void ServiceWorkerGlobalScopeProxy::RequestTermination(
|
||||
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
|
||||
index 783dbe1919d1282f40117aea22b75a8e54e82d89..d54a2449da63f67930cb3d85cfbb27c35c45a8d3 100644
|
||||
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
|
||||
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
|
||||
@@ -129,7 +129,8 @@ class ServiceWorkerGlobalScopeProxy final : public WebServiceWorkerContextProxy,
|
||||
void SetupNavigationPreload(
|
||||
int fetch_event_id,
|
||||
const KURL& url,
|
||||
- mojom::blink::FetchEventPreloadHandlePtr preload_handle);
|
||||
+ mojo::PendingReceiver<network::mojom::blink::URLLoaderClient>
|
||||
+ preload_url_loader_client_receiver);
|
||||
void RequestTermination(WTF::CrossThreadOnceFunction<void(bool)> callback);
|
||||
|
||||
// Detaches this proxy object entirely from the outside world, clearing out
|
||||
36
patches/chromium/cherry-pick-246c10dede97.patch
Normal file
36
patches/chromium/cherry-pick-246c10dede97.patch
Normal file
@@ -0,0 +1,36 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Herre <toprice@chromium.org>
|
||||
Date: Fri, 18 Feb 2022 13:52:01 +0000
|
||||
Subject: Switch to new RequestPermissionsFromCurrentDocument API method for
|
||||
Media Stream Devices
|
||||
|
||||
Switch away from the deprecated RequestPermissions() API, as a part of removing a bug where the previously provided request.security_origin param might get destroyed during the method execution.
|
||||
|
||||
(cherry picked from commit cb6778fb965e2b010922f157c68480de863c252e)
|
||||
|
||||
Bug: 1283402
|
||||
Change-Id: I512ce910146ec60d4d35fa1a86a71a3b0983a5d1
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3417436
|
||||
Reviewed-by: Florent Castelli <orphis@chromium.org>
|
||||
Commit-Queue: Tony Herre <toprice@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#964535}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3473365
|
||||
Cr-Commit-Position: refs/branch-heads/4844@{#655}
|
||||
Cr-Branched-From: 007241ce2e6c8e5a7b306cc36c730cd07cd38825-refs/heads/main@{#961656}
|
||||
|
||||
diff --git a/components/webrtc/media_stream_devices_controller.cc b/components/webrtc/media_stream_devices_controller.cc
|
||||
index 8eb0e01815f6a5f2f0241554b3e5b93017564242..33468f9f2b1bcc2cda8d98748902984ae82e147d 100644
|
||||
--- a/components/webrtc/media_stream_devices_controller.cc
|
||||
+++ b/components/webrtc/media_stream_devices_controller.cc
|
||||
@@ -139,9 +139,8 @@ void MediaStreamDevicesController::RequestPermissions(
|
||||
}
|
||||
}
|
||||
|
||||
- permission_manager->RequestPermissions(
|
||||
- content_settings_types, rfh, request.security_origin,
|
||||
- request.user_gesture,
|
||||
+ permission_manager->RequestPermissionsFromCurrentDocument(
|
||||
+ content_settings_types, rfh, request.user_gesture,
|
||||
base::BindOnce(
|
||||
&MediaStreamDevicesController::RequestAndroidPermissionsIfNeeded,
|
||||
web_contents, std::move(controller), will_prompt_for_audio,
|
||||
71
patches/chromium/cherry-pick-27eb11a28555.patch
Normal file
71
patches/chromium/cherry-pick-27eb11a28555.patch
Normal file
@@ -0,0 +1,71 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yutaka Hirano <yhirano@chromium.org>
|
||||
Date: Wed, 29 Sep 2021 07:58:26 +0000
|
||||
Subject: Run CORS check for manual redirects
|
||||
|
||||
...to prevent status code leak.
|
||||
|
||||
Bug: 1251179
|
||||
Change-Id: I7fcab0daf49e16305ed53702f42d1d1eacc933e5
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3193481
|
||||
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
|
||||
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#926166}
|
||||
|
||||
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
|
||||
index 89813366845757aaa31a37ba155ad2e50a2f5010..88f9236a91c3b32cd1daabca4d42e47c4a959746 100644
|
||||
--- a/services/network/cors/cors_url_loader.cc
|
||||
+++ b/services/network/cors/cors_url_loader.cc
|
||||
@@ -304,13 +304,6 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info,
|
||||
DCHECK(forwarding_client_);
|
||||
DCHECK(!deferred_redirect_url_);
|
||||
|
||||
- if (request_.redirect_mode == mojom::RedirectMode::kManual) {
|
||||
- deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
|
||||
- forwarding_client_->OnReceiveRedirect(redirect_info,
|
||||
- std::move(response_head));
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
// If |CORS flag| is set and a CORS check for |request| and |response| returns
|
||||
// failure, then return a network error.
|
||||
if (fetch_cors_flag_ && IsCorsEnabledRequestMode(request_.mode)) {
|
||||
@@ -328,6 +321,13 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info,
|
||||
}
|
||||
}
|
||||
|
||||
+ if (request_.redirect_mode == mojom::RedirectMode::kManual) {
|
||||
+ deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
|
||||
+ forwarding_client_->OnReceiveRedirect(redirect_info,
|
||||
+ std::move(response_head));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
timing_allow_failed_flag_ = !PassesTimingAllowOriginCheck(*response_head);
|
||||
|
||||
// Because we initiate a new request on redirect in some cases, we cannot
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
|
||||
index eed44e0414cb8947c9b7c21df6ef288f733f8994..9f1ff98c65af97bcf185867ac6c6e128dbd77715 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
|
||||
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
|
||||
@@ -1,6 +1,7 @@
|
||||
// META: script=/common/get-host-info.sub.js
|
||||
|
||||
var redirectLocation = "cors-top.txt";
|
||||
+const { ORIGIN, REMOTE_ORIGIN } = get_host_info();
|
||||
|
||||
function testRedirect(origin, redirectStatus, redirectMode, corsMode) {
|
||||
var url = new URL("../resources/redirect.py", self.location);
|
||||
@@ -47,4 +48,12 @@ for (var origin of ["same-origin", "cross-origin"]) {
|
||||
}
|
||||
}
|
||||
|
||||
+promise_test(async (t) => {
|
||||
+ const destination = `${ORIGIN}/common/blank.html`;
|
||||
+ // We use /common/redirect.py intentionally, as we want a CORS error.
|
||||
+ const url =
|
||||
+ `${REMOTE_ORIGIN}/common/redirect.py?location=${destination}`;
|
||||
+ await promise_rejects_js(t, TypeError, fetch(url, { redirect: "manual" }));
|
||||
+}, "manual redirect with a CORS error should be rejected");
|
||||
+
|
||||
done();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user