mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
378 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc3ce65dd5 | ||
|
|
9faee48070 | ||
|
|
69b8ebc7f4 | ||
|
|
2e8177c839 | ||
|
|
7a3d7b5c95 | ||
|
|
84b863d399 | ||
|
|
149f314e38 | ||
|
|
0c450f8c89 | ||
|
|
3a99edbbdb | ||
|
|
4d371b067b | ||
|
|
84d7f7f071 | ||
|
|
4cefd54143 | ||
|
|
c7fde250bb | ||
|
|
1c7de7e5ee | ||
|
|
4ad7e5f648 | ||
|
|
3bb93c472d | ||
|
|
0412b07612 | ||
|
|
f818ec3295 | ||
|
|
437a0a2c6e | ||
|
|
2d4c150a99 | ||
|
|
31aa0dacee | ||
|
|
39bdf64347 | ||
|
|
1f3161b2ce | ||
|
|
e3f64e7b1f | ||
|
|
6fb688889d | ||
|
|
92371e7231 | ||
|
|
417f2fd3f1 | ||
|
|
e033c294fc | ||
|
|
f138d464b2 | ||
|
|
dfd80db886 | ||
|
|
74d019463a | ||
|
|
a56fbc563a | ||
|
|
00fa1e8404 | ||
|
|
34be316c40 | ||
|
|
cde60dff6a | ||
|
|
7970dc2c0e | ||
|
|
ea2d902de8 | ||
|
|
c697368d14 | ||
|
|
174696e604 | ||
|
|
9b01cedffd | ||
|
|
7e60fc4922 | ||
|
|
e90f6e2e38 | ||
|
|
5c23f17d16 | ||
|
|
a3c129d5d0 | ||
|
|
efa09d8da2 | ||
|
|
d219fcc8b6 | ||
|
|
762ce69066 | ||
|
|
57ce0704e3 | ||
|
|
1f20e4c284 | ||
|
|
b8f05c3648 | ||
|
|
990fb72e35 | ||
|
|
c18e5bae5f | ||
|
|
b71a50e2d3 | ||
|
|
38ce1d68d6 | ||
|
|
eb8dcb52aa | ||
|
|
3d07626ddf | ||
|
|
9caade81c4 | ||
|
|
8c89a771b2 | ||
|
|
b5c8af02f5 | ||
|
|
db7acc9fc0 | ||
|
|
eccc08e653 | ||
|
|
c50975f664 | ||
|
|
20a551ba94 | ||
|
|
8926e4e93d | ||
|
|
bca09956f3 | ||
|
|
5fa67613d9 | ||
|
|
974dbc167c | ||
|
|
1fae9d5ac0 | ||
|
|
6978a722d4 | ||
|
|
b68143a9be | ||
|
|
910cafd785 | ||
|
|
b1223100f5 | ||
|
|
4a20042b5e | ||
|
|
0e5725b4a1 | ||
|
|
95aa5405e7 | ||
|
|
3c75dd1684 | ||
|
|
81fb39f154 | ||
|
|
2448993d1c | ||
|
|
deb0f6ecc0 | ||
|
|
476c925660 | ||
|
|
2b355f8ab3 | ||
|
|
dadb872c3d | ||
|
|
5305596f02 | ||
|
|
9281a34f8b | ||
|
|
35cf190ab9 | ||
|
|
6c7e9b861d | ||
|
|
37df7c5170 | ||
|
|
2fdfa0b662 | ||
|
|
0034868d6c | ||
|
|
1b626b805b | ||
|
|
a597775259 | ||
|
|
71d9362819 | ||
|
|
32eb8c9336 | ||
|
|
1c0936897e | ||
|
|
7e401f4828 | ||
|
|
679f4732bd | ||
|
|
fcab6c6705 | ||
|
|
32d4d01b3c | ||
|
|
cc01109491 | ||
|
|
3505270a2a | ||
|
|
fc5a7dd023 | ||
|
|
1cb343e079 | ||
|
|
11c6f1f684 | ||
|
|
c5e5b13003 | ||
|
|
f44be42478 | ||
|
|
70fe0d9a07 | ||
|
|
cea70deb8a | ||
|
|
31b0daaa91 | ||
|
|
4249800e9c | ||
|
|
2ba9860a5a | ||
|
|
7c65388483 | ||
|
|
96ae5c107e | ||
|
|
6dc122fe5a | ||
|
|
160d48f0f2 | ||
|
|
605d6c9f41 | ||
|
|
b606a98b77 | ||
|
|
4779d565d2 | ||
|
|
a7bb6de466 | ||
|
|
8f9f1cc2fe | ||
|
|
90040360c3 | ||
|
|
b452c7fab4 | ||
|
|
b1cddb0dc8 | ||
|
|
f755b2579f | ||
|
|
7bca7f2c0f | ||
|
|
ed328d8987 | ||
|
|
1a7c546c3a | ||
|
|
748c4bfbcb | ||
|
|
9ec8b1d21c | ||
|
|
32138c6405 | ||
|
|
bc458c97dc | ||
|
|
06ac9d989f | ||
|
|
e8ef5f4ae4 | ||
|
|
6c136d5582 | ||
|
|
7ddb80fbb1 | ||
|
|
3a2306d9e4 | ||
|
|
38d83cfefc | ||
|
|
d61f6309a2 | ||
|
|
126897bd6b | ||
|
|
d3f0970964 | ||
|
|
012774a0eb | ||
|
|
a546545a53 | ||
|
|
742bd735e6 | ||
|
|
a54725b6b5 | ||
|
|
be61126d30 | ||
|
|
7fbc867eaf | ||
|
|
0c4134fefe | ||
|
|
b19a3a65a4 | ||
|
|
563a0622d9 | ||
|
|
6a5bd8dc28 | ||
|
|
b78c30a6d8 | ||
|
|
9ecd8910de | ||
|
|
da87a471fe | ||
|
|
6544df1992 | ||
|
|
c9f7ebf821 | ||
|
|
d3a0a255b1 | ||
|
|
2d3819e2a8 | ||
|
|
bd384b5301 | ||
|
|
1e13475e89 | ||
|
|
8ce23c425d | ||
|
|
c891980848 | ||
|
|
15f4e8ef88 | ||
|
|
b6b4971da0 | ||
|
|
14918767d8 | ||
|
|
f7a16f33a8 | ||
|
|
662fa261da | ||
|
|
8ceb20c75c | ||
|
|
e0e824f069 | ||
|
|
ab0a13eed6 | ||
|
|
7910ace135 | ||
|
|
eb8eb6fae2 | ||
|
|
c9bea8b712 | ||
|
|
71ee04a3e2 | ||
|
|
f7f55d096a | ||
|
|
ad6155f08e | ||
|
|
37caca046f | ||
|
|
ea6a8eea22 | ||
|
|
d314b4e18b | ||
|
|
1bc8549ce5 | ||
|
|
8e6c8cc384 | ||
|
|
5c13da7c40 | ||
|
|
45a5827e09 | ||
|
|
e809a5a043 | ||
|
|
4f2e369bdc | ||
|
|
eef9787c48 | ||
|
|
81fe8993ec | ||
|
|
55b5c85f92 | ||
|
|
a0e6ca8dab | ||
|
|
e30b25269d | ||
|
|
319d77a4ee | ||
|
|
e22767b1e7 | ||
|
|
5008e3ecab | ||
|
|
d69776bfb0 | ||
|
|
b56e4287d3 | ||
|
|
1254a684dd | ||
|
|
99a81e4ef0 | ||
|
|
36d5706ea9 | ||
|
|
2ae9588e1c | ||
|
|
320415edf9 | ||
|
|
dd59115ac6 | ||
|
|
80a378a9de | ||
|
|
8d2530437e | ||
|
|
dde3a0f1ba | ||
|
|
ce079c02bc | ||
|
|
f23df11352 | ||
|
|
abb86a7ea1 | ||
|
|
8f96b2192a | ||
|
|
977a7eb1d0 | ||
|
|
504588c861 | ||
|
|
5bc09dda1a | ||
|
|
6b72837203 | ||
|
|
9f2bef9a65 | ||
|
|
d0273d83ef | ||
|
|
248dc89217 | ||
|
|
a75a867997 | ||
|
|
0d82286a23 | ||
|
|
4553ec2a2a | ||
|
|
62f64f9f03 | ||
|
|
f35adf303b | ||
|
|
f236478b2b | ||
|
|
b69de7c412 | ||
|
|
8c3bbded4f | ||
|
|
d9019fc54b | ||
|
|
7c624c17fa | ||
|
|
3e336d2923 | ||
|
|
95b727ccdb | ||
|
|
382b19f816 | ||
|
|
a1b3b506d7 | ||
|
|
9b25d6b91b | ||
|
|
b113c5d583 | ||
|
|
a36e44c973 | ||
|
|
8ae741102d | ||
|
|
666e8f9647 | ||
|
|
fdceacce44 | ||
|
|
0ad8ffa3d2 | ||
|
|
031283003c | ||
|
|
63fdcba0c8 | ||
|
|
251e567eff | ||
|
|
6bfef67aae | ||
|
|
db27b9f433 | ||
|
|
be32740991 | ||
|
|
b8a21dbcd7 | ||
|
|
58f3c0ee37 | ||
|
|
3f42040a1b | ||
|
|
e9d5c3517c | ||
|
|
91f62ae73f | ||
|
|
4c8583c365 | ||
|
|
0b4ef2b1e5 | ||
|
|
4ba5723aed | ||
|
|
652d603e69 | ||
|
|
f40bd2da23 | ||
|
|
e31f101712 | ||
|
|
4415b7638a | ||
|
|
f7c6545eab | ||
|
|
ef657bdc9d | ||
|
|
6012172187 | ||
|
|
a75b892e90 | ||
|
|
7c4f4c537e | ||
|
|
4ca6fb3c4e | ||
|
|
3fa03977c7 | ||
|
|
75919e28b8 | ||
|
|
ac58607605 | ||
|
|
835ace243c | ||
|
|
8f3ef39f1e | ||
|
|
48e13fde80 | ||
|
|
bb6648b79e | ||
|
|
2b9dae4b06 | ||
|
|
2e1f803f37 | ||
|
|
4c6092e151 | ||
|
|
b72f81ab5b | ||
|
|
97b19a7946 | ||
|
|
b27e4cae21 | ||
|
|
1e106c8aa4 | ||
|
|
fda8ea9277 | ||
|
|
6a6908c4c8 | ||
|
|
42e7cd9b3f | ||
|
|
8cf03f5661 | ||
|
|
916861036d | ||
|
|
52481bc923 | ||
|
|
5023b49713 | ||
|
|
2ac9ff1f20 | ||
|
|
46d3c4e04f | ||
|
|
0f77fec9d9 | ||
|
|
94f701edb8 | ||
|
|
caa5989eed | ||
|
|
e0c348a2f8 | ||
|
|
eb613ef3d4 | ||
|
|
7ed3c7a359 | ||
|
|
64b39dce14 | ||
|
|
5261e08d0c | ||
|
|
9611b641c9 | ||
|
|
095f9067a7 | ||
|
|
b8f970c1c7 | ||
|
|
48d0b09ad9 | ||
|
|
c5fc5efc00 | ||
|
|
6dc46e5bcf | ||
|
|
061e2e5e73 | ||
|
|
bf1cc1aeb2 | ||
|
|
e480cb7103 | ||
|
|
3b69a542fb | ||
|
|
82456c6915 | ||
|
|
e58f0411d9 | ||
|
|
e61728beb9 | ||
|
|
feaf18e371 | ||
|
|
8ee58e18fd | ||
|
|
f33bf2a271 | ||
|
|
77bd80dfb2 | ||
|
|
0d3aee26b9 | ||
|
|
efde7a140b | ||
|
|
4e85bb921b | ||
|
|
512e56baf7 | ||
|
|
c8f715f9a1 | ||
|
|
829fb4f586 | ||
|
|
17ccb3c6ec | ||
|
|
6bd9ee6988 | ||
|
|
76c825d619 | ||
|
|
692876c737 | ||
|
|
c3f06ef037 | ||
|
|
9b20b3a722 | ||
|
|
8f2917db01 | ||
|
|
49df19214e | ||
|
|
5e25d23794 | ||
|
|
8fb0f43030 | ||
|
|
1f390119fe | ||
|
|
87f2a1d572 | ||
|
|
2e03bdb9b6 | ||
|
|
3a5ae28c95 | ||
|
|
ed7b5c44a2 | ||
|
|
edf887bdc5 | ||
|
|
1ff7f098f1 | ||
|
|
fb100e8f49 | ||
|
|
3384908da1 | ||
|
|
73bd9a3155 | ||
|
|
e27905c765 | ||
|
|
a3e3efe4c4 | ||
|
|
46c8b9c728 | ||
|
|
6395898a79 | ||
|
|
32c60b29bb | ||
|
|
868676aa5c | ||
|
|
85cf56d80b | ||
|
|
a92fd2aa05 | ||
|
|
ee966ad6ec | ||
|
|
872d1fe05a | ||
|
|
63f94f2359 | ||
|
|
67a6fbf265 | ||
|
|
f97d68c4bf | ||
|
|
969665eaa2 | ||
|
|
0d8dd61257 | ||
|
|
cf10c19c33 | ||
|
|
fcfbcbc7e1 | ||
|
|
e34cc6f48c | ||
|
|
ee87438d28 | ||
|
|
0de1012280 | ||
|
|
0a5e634736 | ||
|
|
73b7aac6a4 | ||
|
|
ea848bc1c5 | ||
|
|
a44e76fb70 | ||
|
|
3138acc377 | ||
|
|
beed240454 | ||
|
|
fdab0799fe | ||
|
|
17ea7f42fc | ||
|
|
d0cf9c4b08 | ||
|
|
fe7c535a3f | ||
|
|
8eee4f2df1 | ||
|
|
4d6f230d21 | ||
|
|
889859df5b | ||
|
|
cb03c6516b | ||
|
|
2e8114aea3 | ||
|
|
a38b711fb1 | ||
|
|
3972073116 | ||
|
|
8c986ff194 | ||
|
|
71944f2c3b | ||
|
|
8b3e498436 | ||
|
|
cf80994729 | ||
|
|
01f1522cbd | ||
|
|
a37f572388 | ||
|
|
3180312595 | ||
|
|
ff60fe25c1 | ||
|
|
12ed401ca2 |
@@ -51,7 +51,7 @@ jobs:
|
||||
steps:
|
||||
- checkout
|
||||
- path-filtering/set-parameters:
|
||||
base-revision: origin/24-x-y
|
||||
base-revision: main
|
||||
mapping: |
|
||||
^((?!docs/).)*$ run-build-mac true
|
||||
^((?!docs/).)*$ run-build-linux true
|
||||
|
||||
@@ -52,9 +52,14 @@ executors:
|
||||
size:
|
||||
description: "macOS executor size"
|
||||
type: enum
|
||||
enum: ["macos.x86.medium.gen2", "large"]
|
||||
enum: ["macos.x86.medium.gen2"]
|
||||
version:
|
||||
description: "xcode version"
|
||||
type: enum
|
||||
enum: ["14.3.0", "14.0.0"]
|
||||
default: 14.3.0
|
||||
macos:
|
||||
xcode: 14.0.0
|
||||
xcode: << parameters.version >>
|
||||
resource_class: << parameters.size >>
|
||||
|
||||
# Electron Runners
|
||||
@@ -108,7 +113,7 @@ env-unittests: &env-unittests
|
||||
TESTS_CONFIG: src/electron/spec/configs/unittests.yml
|
||||
|
||||
env-arm: &env-arm
|
||||
GN_EXTRA_ARGS: 'target_cpu = "arm" clang_use_chrome_plugins = false'
|
||||
GN_EXTRA_ARGS: 'target_cpu = "arm"'
|
||||
MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm
|
||||
BUILD_NATIVE_MKSNAPSHOT: 1
|
||||
TARGET_ARCH: arm
|
||||
@@ -247,19 +252,19 @@ step-depot-tools-get: &step-depot-tools-get
|
||||
cd depot_tools
|
||||
cat > gclient.diff \<< 'EOF'
|
||||
diff --git a/gclient.py b/gclient.py
|
||||
index 3a9c5c6..f222043 100755
|
||||
index c305c248..e6e0fbdc 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -712,7 +712,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
|
||||
if dep_type == 'cipd':
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
+ for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')):
|
||||
deps_to_add.append(
|
||||
CipdDependency(
|
||||
parent=self,
|
||||
@@ -735,7 +735,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
|
||||
if dep_type == 'cipd':
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
+ for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')):
|
||||
deps_to_add.append(
|
||||
CipdDependency(parent=self,
|
||||
name=name,
|
||||
EOF
|
||||
git apply --3way gclient.diff
|
||||
fi
|
||||
@@ -341,8 +346,8 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
export GOMA_FALLBACK_ON_AUTH_FAILURE=true
|
||||
python3 third_party/goma/goma_ctl.py ensure_start
|
||||
if [ ! -z "$RAW_GOMA_AUTH" ] && [ "`python3 third_party/goma/goma_auth.py info`" != "Login as Fermi Planck" ]; then
|
||||
third_party/goma/goma_ctl.py ensure_start
|
||||
if [ ! -z "$RAW_GOMA_AUTH" ] && [ "`third_party/goma/goma_auth.py info`" != "Login as Fermi Planck" ]; then
|
||||
echo "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."
|
||||
exit 1
|
||||
fi
|
||||
@@ -370,14 +375,14 @@ step-restore-brew-cache: &step-restore-brew-cache
|
||||
- /usr/local/Cellar/gnu-tar
|
||||
- /usr/local/bin/gtar
|
||||
keys:
|
||||
- v7-brew-cache-{{ arch }}
|
||||
- v6-brew-cache-{{ arch }}
|
||||
|
||||
step-save-brew-cache: &step-save-brew-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /usr/local/Cellar/gnu-tar
|
||||
- /usr/local/bin/gtar
|
||||
key: v7-brew-cache-{{ arch }}
|
||||
key: v6-brew-cache-{{ arch }}
|
||||
name: Persisting brew cache
|
||||
|
||||
step-get-more-space-on-mac: &step-get-more-space-on-mac
|
||||
@@ -537,18 +542,6 @@ step-fix-sync: &step-fix-sync
|
||||
mv .git/config.backup .git/config
|
||||
git fetch
|
||||
|
||||
step-fix-clang: &step-fix-clang
|
||||
run:
|
||||
name: Fix Clang on 32-bit Linux ARM
|
||||
command: |
|
||||
if [ "$TARGET_ARCH" == "arm" ]; then
|
||||
# The following custom clang needed on 32-bit Linux ARM due to https://crbug.com/1431201.
|
||||
# Once https://crbug.com/1425409 has been resolved this workaround can be remove
|
||||
cd src/third_party/llvm-build/Release+Asserts
|
||||
curl -O https://dev-cdn.electronjs.org/clang/clang-llvmorg-17-init-4759-g547e3456-2.tar.xz
|
||||
tar xvf clang-llvmorg-17-init-4759-g547e3456-2.tar.xz
|
||||
fi
|
||||
|
||||
step-install-signing-cert-on-mac: &step-install-signing-cert-on-mac
|
||||
run:
|
||||
name: Import and trust self-signed codesigning cert on MacOS
|
||||
@@ -1055,7 +1048,6 @@ commands:
|
||||
default: true
|
||||
steps:
|
||||
- *step-gn-gen-default
|
||||
- *step-fix-clang
|
||||
- ninja_build_electron:
|
||||
clean-prebuilt-snapshot: false
|
||||
build-type: << parameters.build-type >>
|
||||
@@ -1595,7 +1587,6 @@ commands:
|
||||
- *step-setup-goma-for-build
|
||||
- *step-wait-for-goma
|
||||
- *step-gn-gen-default
|
||||
- *step-fix-clang
|
||||
|
||||
# Electron app
|
||||
- ninja_build_electron:
|
||||
@@ -2140,6 +2131,7 @@ jobs:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
version: 14.0.0
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
@@ -2163,6 +2155,7 @@ jobs:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
version: 14.0.0
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
|
||||
@@ -4,37 +4,6 @@
|
||||
"onCreateCommand": ".devcontainer/on-create-command.sh",
|
||||
"updateContentCommand": ".devcontainer/update-content-command.sh",
|
||||
"workspaceFolder": "/workspaces/gclient/src/electron",
|
||||
"extensions": [
|
||||
"joeleinbinder.mojom-language",
|
||||
"rafaelmaiolla.diff",
|
||||
"surajbarkale.ninja",
|
||||
"ms-vscode.cpptools",
|
||||
"mutantdino.resourcemonitor",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"shakram02.bash-beautify",
|
||||
"marshallofsound.gnls-electron",
|
||||
"CircleCI.circleci"
|
||||
],
|
||||
"settings": {
|
||||
"editor.tabSize": 2,
|
||||
"bashBeautify.tabSize": 2,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"[gn]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
},
|
||||
"javascript.preferences.quoteStyle": "single",
|
||||
"typescript.preferences.quoteStyle": "single"
|
||||
},
|
||||
"forwardPorts": [8088, 6080, 5901],
|
||||
"portsAttributes": {
|
||||
"8088": {
|
||||
@@ -60,6 +29,38 @@
|
||||
"openFiles": [
|
||||
".devcontainer/README.md"
|
||||
]
|
||||
},
|
||||
"vscode": {
|
||||
"extensions": ["joeleinbinder.mojom-language",
|
||||
"rafaelmaiolla.diff",
|
||||
"surajbarkale.ninja",
|
||||
"ms-vscode.cpptools",
|
||||
"mutantdino.resourcemonitor",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"shakram02.bash-beautify",
|
||||
"marshallofsound.gnls-electron",
|
||||
"CircleCI.circleci"
|
||||
],
|
||||
"settings": {
|
||||
"editor.tabSize": 2,
|
||||
"bashBeautify.tabSize": 2,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"[gn]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
},
|
||||
"javascript.preferences.quoteStyle": "single",
|
||||
"typescript.preferences.quoteStyle": "single"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -11,4 +11,5 @@ patches/**/.patches merge=union
|
||||
*.ts text eol=lf
|
||||
*.py text eol=lf
|
||||
*.ps1 text eol=lf
|
||||
*.html text eol=lf
|
||||
*.md text eol=lf
|
||||
|
||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -8,6 +8,7 @@
|
||||
DEPS @electron/wg-upgrades
|
||||
|
||||
# Releases WG
|
||||
/docs/breaking-changes.md @electron/wg-releases
|
||||
/npm/ @electron/wg-releases
|
||||
/script/release @electron/wg-releases
|
||||
|
||||
|
||||
14
.github/config.yml
vendored
14
.github/config.yml
vendored
@@ -25,17 +25,3 @@ newPRWelcomeComment: |
|
||||
# Comment to be posted to on pull requests merged by a first time user
|
||||
firstPRMergeComment: >
|
||||
Congrats on merging your first pull request! 🎉🎉🎉
|
||||
|
||||
# Users authorized to run manual trop backports
|
||||
authorizedUsers:
|
||||
- alexeykuzmin
|
||||
- ckerr
|
||||
- codebytere
|
||||
- deepak1556
|
||||
- jkleinsc
|
||||
- loc
|
||||
- MarshallOfSound
|
||||
- miniak
|
||||
- mlaurencin
|
||||
- nornagon
|
||||
- zcbenz
|
||||
|
||||
2
.github/workflows/semantic.yml
vendored
2
.github/workflows/semantic.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: "Check Semantic Commit"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
|
||||
13
.github/workflows/update_appveyor_image.yml
vendored
13
.github/workflows/update_appveyor_image.yml
vendored
@@ -40,13 +40,21 @@ jobs:
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
uses: mikefarah/yq@1c7dc0e88aad311c89889bc5ce5d8f96931a1bd0 # v4.27.2
|
||||
with:
|
||||
cmd: yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml"
|
||||
cmd: |
|
||||
yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml"
|
||||
yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor-woa.yml" > "appveyor-woa2.yml"
|
||||
- name: (Optionally) Generate Commit Diff
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
run: |
|
||||
diff -w -B appveyor.yml appveyor2.yml > appveyor.diff || true
|
||||
patch -f appveyor.yml < appveyor.diff
|
||||
rm appveyor2.yml appveyor.diff
|
||||
- name: (Optionally) Generate Commit Diff for WOA
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
run: |
|
||||
diff -w -B appveyor-woa.yml appveyor-woa2.yml > appveyor-woa.diff || true
|
||||
patch -f appveyor-woa.yml < appveyor-woa.diff
|
||||
rm appveyor-woa2.yml appveyor-woa.diff
|
||||
- name: (Optionally) Commit and Pull Request
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04 # v4.2.3
|
||||
@@ -60,4 +68,5 @@ jobs:
|
||||
delete-branch: true
|
||||
title: 'build: update appveyor image to latest version'
|
||||
body: |
|
||||
This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.
|
||||
This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.
|
||||
Notes: none
|
||||
6
BUILD.gn
6
BUILD.gn
@@ -1,7 +1,7 @@
|
||||
import("//build/config/locales.gni")
|
||||
import("//build/config/ui.gni")
|
||||
import("//build/config/win/manifest.gni")
|
||||
import("//components/os_crypt/features.gni")
|
||||
import("//components/os_crypt/sync/features.gni")
|
||||
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||
import("//content/public/app/mac_helpers.gni")
|
||||
import("//extensions/buildflags/buildflags.gni")
|
||||
@@ -433,7 +433,7 @@ source_set("electron_lib") {
|
||||
"//components/network_hints/renderer",
|
||||
"//components/network_session_configurator/common",
|
||||
"//components/omnibox/browser:buildflags",
|
||||
"//components/os_crypt",
|
||||
"//components/os_crypt/sync",
|
||||
"//components/pref_registry",
|
||||
"//components/prefs",
|
||||
"//components/security_state/content",
|
||||
@@ -772,6 +772,8 @@ source_set("electron_lib") {
|
||||
sources += [
|
||||
"shell/browser/electron_pdf_web_contents_helper_client.cc",
|
||||
"shell/browser/electron_pdf_web_contents_helper_client.h",
|
||||
"shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc",
|
||||
"shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
5
DEPS
5
DEPS
@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'112.0.5615.204',
|
||||
'114.0.5735.289',
|
||||
'node_version':
|
||||
'v18.14.0',
|
||||
'v18.15.0',
|
||||
'nan_version':
|
||||
'16fa32231e2ccd89d2804b3f765319128b20c4ac',
|
||||
'squirrel.mac_version':
|
||||
@@ -155,5 +155,4 @@ hooks = [
|
||||
|
||||
recursedeps = [
|
||||
'src',
|
||||
'src/third_party/squirrel.mac',
|
||||
]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-112.0.5615.29
|
||||
image: e-112.0.5607.0-vs2022
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# - "GN_CONFIG" Build type. One of {'testing', 'release'}.
|
||||
# - "GN_EXTRA_ARGS" Additional gn arguments for a build config,
|
||||
# e.g. 'target_cpu="x86"' to build for a 32bit platform.
|
||||
# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu
|
||||
# https://gn.googlesource.com/gn/+/main/docs/reference.md#var_target_cpu
|
||||
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
|
||||
# if you pass a custom value for 'target_cpu'.
|
||||
# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success.
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-112.0.5615.29
|
||||
image: e-114.0.5735.16-bust-cache
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 1
|
||||
ELECTRON_ALSO_LOG_TO_STDERR: 1
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
|
||||
MOCHA_MULTI_REPORTERS: "@marshallofsound/mocha-appveyor-reporter, tap"
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
|
||||
PYTHONIOENCODING: UTF-8
|
||||
@@ -116,7 +116,7 @@ for:
|
||||
- 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
|
||||
$goma_login = python3 $env:LOCAL_GOMA_DIR\goma_auth.py info
|
||||
if ($goma_login -eq 'Login as Fermi Planck') {
|
||||
Write-warning "Goma authentication is correct";
|
||||
} else {
|
||||
@@ -166,7 +166,7 @@ for:
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- ps: >-
|
||||
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 | Out-File -Encoding utf8 -FilePath .\installed_software.json
|
||||
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -6,7 +6,7 @@
|
||||
# - "GN_CONFIG" Build type. One of {'testing', 'release'}.
|
||||
# - "GN_EXTRA_ARGS" Additional gn arguments for a build config,
|
||||
# e.g. 'target_cpu="x86"' to build for a 32bit platform.
|
||||
# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu
|
||||
# https://gn.googlesource.com/gn/+/main/docs/reference.md#var_target_cpu
|
||||
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
|
||||
# if you pass a custom value for 'target_cpu'.
|
||||
# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success.
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-112.0.5615.29
|
||||
image: e-114.0.5735.16-bust-cache
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 1
|
||||
ELECTRON_ALSO_LOG_TO_STDERR: 1
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
|
||||
MOCHA_MULTI_REPORTERS: "@marshallofsound/mocha-appveyor-reporter, tap"
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
|
||||
PYTHONIOENCODING: UTF-8
|
||||
@@ -114,7 +114,7 @@ for:
|
||||
- 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
|
||||
$goma_login = python3 $env:LOCAL_GOMA_DIR\goma_auth.py info
|
||||
if ($goma_login -eq 'Login as Fermi Planck') {
|
||||
Write-warning "Goma authentication is correct";
|
||||
} else {
|
||||
@@ -164,7 +164,7 @@ for:
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- ps: >-
|
||||
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 | Out-File -Encoding utf8 -FilePath .\installed_software.json
|
||||
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
is_electron_build = true
|
||||
root_extra_deps = [ "//electron" ]
|
||||
|
||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
|
||||
node_module_version = 114
|
||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json
|
||||
node_module_version = 116
|
||||
|
||||
v8_promise_internal_field_count = 1
|
||||
v8_embedder_string = "-electron.0"
|
||||
@@ -45,3 +45,13 @@ is_cfi = false
|
||||
|
||||
# TODO: fix this once sysroots have been updated.
|
||||
use_qt = false
|
||||
|
||||
# https://chromium-review.googlesource.com/c/chromium/src/+/4365718
|
||||
# TODO(codebytere): fix perfetto incompatibility with Node.js.
|
||||
use_perfetto_client_library = false
|
||||
|
||||
# Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4402277
|
||||
enable_check_raw_ptr_fields = false
|
||||
|
||||
# Disables the builtins PGO for V8
|
||||
v8_builtins_profiling_log_file = ""
|
||||
|
||||
@@ -55,7 +55,7 @@ The `Super` (or `Meta`) key is mapped to the `Windows` key on Windows and Linux
|
||||
* `0` to `9`
|
||||
* `A` to `Z`
|
||||
* `F1` to `F24`
|
||||
* Punctuation like `~`, `!`, `@`, `#`, `$`, etc.
|
||||
* Various Punctuation: `)`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `:`, `;`, `:`, `+`, `=`, `<`, `,`, `_`, `-`, `>`, `.`, `?`, `/`, `~`, `` ` ``, `{`, `]`, `[`, `|`, `\`, `}`, `"`
|
||||
* `Plus`
|
||||
* `Space`
|
||||
* `Tab`
|
||||
|
||||
@@ -150,9 +150,20 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
Emitted when mac application become active. Difference from `activate` event is
|
||||
Emitted when the application becomes active. This differs from the `activate` event in
|
||||
that `did-become-active` is emitted every time the app becomes active, not only
|
||||
when Dock icon is clicked or application is re-launched.
|
||||
when Dock icon is clicked or application is re-launched. It is also emitted when a user
|
||||
switches to the app via the macOS App Switcher.
|
||||
|
||||
### Event: 'did-resign-active' _macOS_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
Emitted when the app is no longer active and doesn’t have focus. This can be triggered,
|
||||
for example, by clicking on another application or by using the macOS App Switcher to
|
||||
switch to another application.
|
||||
|
||||
### Event: 'continue-activity' _macOS_
|
||||
|
||||
@@ -402,18 +413,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `details` Object
|
||||
* `reason` string - The reason the render process is gone. Possible values:
|
||||
* `clean-exit` - Process exited with an exit code of zero
|
||||
* `abnormal-exit` - Process exited with a non-zero exit code
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failed` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
* `exitCode` Integer - The exit code of the process, unless `reason` is
|
||||
`launch-failed`, in which case `exitCode` will be a platform-specific
|
||||
launch failure error code.
|
||||
* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md)
|
||||
|
||||
Emitted when the renderer process unexpectedly disappears. This is normally
|
||||
because it was crashed or killed.
|
||||
|
||||
@@ -1110,10 +1110,14 @@ win.setBounds({ width: 100 })
|
||||
console.log(win.getBounds())
|
||||
```
|
||||
|
||||
**Note:** On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray.
|
||||
|
||||
#### `win.getBounds()`
|
||||
|
||||
Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`.
|
||||
|
||||
**Note:** On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`.
|
||||
|
||||
#### `win.getBackgroundColor()`
|
||||
|
||||
Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format.
|
||||
@@ -1854,17 +1858,6 @@ will remove the vibrancy effect on the window.
|
||||
Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been
|
||||
deprecated and will be removed in an upcoming version of macOS.
|
||||
|
||||
#### `win.setTrafficLightPosition(position)` _macOS_
|
||||
|
||||
* `position` [Point](structures/point.md)
|
||||
|
||||
Set a custom position for the traffic light buttons in frameless window.
|
||||
|
||||
#### `win.getTrafficLightPosition()` _macOS_
|
||||
|
||||
Returns `Point` - The custom position for the traffic light buttons in
|
||||
frameless window.
|
||||
|
||||
#### `win.setBackgroundMaterial(material)` _Windows_
|
||||
|
||||
* `material` string
|
||||
@@ -1880,6 +1873,37 @@ See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/
|
||||
|
||||
**Note:** This method is only supported on Windows 11 22H2 and up.
|
||||
|
||||
#### `win.setWindowButtonPosition(position)` _macOS_
|
||||
|
||||
* `position` [Point](structures/point.md) | null
|
||||
|
||||
Set a custom position for the traffic light buttons in frameless window.
|
||||
Passing `null` will reset the position to default.
|
||||
|
||||
#### `win.getWindowButtonPosition()` _macOS_
|
||||
|
||||
Returns `Point | null` - The custom position for the traffic light buttons in
|
||||
frameless window, `null` will be returned when there is no custom position.
|
||||
|
||||
#### `win.setTrafficLightPosition(position)` _macOS_ _Deprecated_
|
||||
|
||||
* `position` [Point](structures/point.md)
|
||||
|
||||
Set a custom position for the traffic light buttons in frameless window.
|
||||
Passing `{ x: 0, y: 0 }` will reset the position to default.
|
||||
|
||||
> **Note**
|
||||
> This function is deprecated. Use [setWindowButtonPosition](#winsetwindowbuttonpositionposition-macos) instead.
|
||||
|
||||
#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_
|
||||
|
||||
Returns `Point` - The custom position for the traffic light buttons in
|
||||
frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom
|
||||
position.
|
||||
|
||||
> **Note**
|
||||
> This function is deprecated. Use [getWindowButtonPosition](#wingetwindowbuttonposition-macos) instead.
|
||||
|
||||
#### `win.setTouchBar(touchBar)` _macOS_
|
||||
|
||||
* `touchBar` TouchBar | null
|
||||
|
||||
@@ -23,12 +23,14 @@ following properties:
|
||||
with which the request is associated. Defaults to the empty string. The
|
||||
`session` option supersedes `partition`. Thus if a `session` is explicitly
|
||||
specified, `partition` is ignored.
|
||||
* `credentials` string (optional) - Can be `include` or `omit`. Whether to
|
||||
send [credentials](https://fetch.spec.whatwg.org/#credentials) with this
|
||||
* `credentials` string (optional) - Can be `include`, `omit` or
|
||||
`same-origin`. Whether to send
|
||||
[credentials](https://fetch.spec.whatwg.org/#credentials) with this
|
||||
request. If set to `include`, credentials from the session associated with
|
||||
the request will be used. If set to `omit`, credentials will not be sent
|
||||
with the request (and the `'login'` event will not be triggered in the
|
||||
event of a 401). This matches the behavior of the
|
||||
event of a 401). If set to `same-origin`, `origin` must also be specified.
|
||||
This matches the behavior of the
|
||||
[fetch](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
|
||||
option of the same name. If this option is not specified, authentication
|
||||
data from the session will be sent, and cookies will not be sent (unless
|
||||
@@ -49,6 +51,13 @@ following properties:
|
||||
[`request.followRedirect`](#requestfollowredirect) is invoked synchronously
|
||||
during the [`redirect`](#event-redirect) event. Defaults to `follow`.
|
||||
* `origin` string (optional) - The origin URL of the request.
|
||||
* `referrerPolicy` string (optional) - can be `""`, `no-referrer`,
|
||||
`no-referrer-when-downgrade`, `origin`, `origin-when-cross-origin`,
|
||||
`unsafe-url`, `same-origin`, `strict-origin`, or
|
||||
`strict-origin-when-cross-origin`. Defaults to
|
||||
`strict-origin-when-cross-origin`.
|
||||
* `cache` string (optional) - can be `default`, `no-store`, `reload`,
|
||||
`no-cache`, `force-cache` or `only-if-cached`.
|
||||
|
||||
`options` properties such as `protocol`, `host`, `hostname`, `port` and `path`
|
||||
strictly follow the Node.js model as described in the
|
||||
@@ -234,6 +243,8 @@ it is not allowed to add or remove a custom header.
|
||||
* `encoding` string (optional)
|
||||
* `callback` Function (optional)
|
||||
|
||||
Returns `this`.
|
||||
|
||||
Sends the last chunk of the request data. Subsequent write or end operations
|
||||
will not be allowed. The `finish` event is emitted just after the end operation.
|
||||
|
||||
|
||||
@@ -297,6 +297,15 @@ Print stack traces for deprecations.
|
||||
|
||||
Print stack traces for process warnings (including deprecations).
|
||||
|
||||
### `--dns-result-order=order`
|
||||
|
||||
Set the default value of the `verbatim` parameter in the Node.js [`dns.lookup()`](https://nodejs.org/api/dns.html#dnslookuphostname-options-callback) and [`dnsPromises.lookup()`](https://nodejs.org/api/dns.html#dnspromiseslookuphostname-options) functions. The value could be:
|
||||
|
||||
* `ipv4first`: sets default `verbatim` `false`.
|
||||
* `verbatim`: sets default `verbatim` `true`.
|
||||
|
||||
The default is `verbatim` and `dns.setDefaultResultOrder()` have higher priority than `--dns-result-order`.
|
||||
|
||||
[app]: app.md
|
||||
[append-switch]: command-line.md#commandlineappendswitchswitch-value
|
||||
[debugging-main-process]: ../tutorial/debugging-main-process.md
|
||||
|
||||
@@ -91,8 +91,9 @@ The following events of `chrome.runtime` are supported:
|
||||
|
||||
### `chrome.storage`
|
||||
|
||||
Only `chrome.storage.local` is supported; `chrome.storage.sync` and
|
||||
`chrome.storage.managed` are not.
|
||||
The following methods of `chrome.storage` are supported:
|
||||
|
||||
- `chrome.storage.local`
|
||||
|
||||
### `chrome.tabs`
|
||||
|
||||
@@ -101,6 +102,8 @@ The following methods of `chrome.tabs` are supported:
|
||||
- `chrome.tabs.sendMessage`
|
||||
- `chrome.tabs.reload`
|
||||
- `chrome.tabs.executeScript`
|
||||
- `chrome.tabs.query` (partial support)
|
||||
- supported properties: `url`, `title`, `audible`, `active`, `muted`.
|
||||
- `chrome.tabs.update` (partial support)
|
||||
- supported properties: `url`, `muted`.
|
||||
|
||||
@@ -117,6 +120,9 @@ The following methods of `chrome.management` are supported:
|
||||
- `chrome.management.getSelf`
|
||||
- `chrome.management.getPermissionWarningsById`
|
||||
- `chrome.management.getPermissionWarningsByManifest`
|
||||
|
||||
The following events of `chrome.management` are supported:
|
||||
|
||||
- `chrome.management.onEnabled`
|
||||
- `chrome.management.onDisabled`
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ Removes listeners of the specified `channel`.
|
||||
### `ipcMain.handle(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function<Promise\<void> | any>
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
@@ -109,8 +109,8 @@ provided to the renderer process. Please refer to
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function<Promise\<void> | any>
|
||||
* `event` IpcMainInvokeEvent
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
Handles a single `invoke`able IPC message, then removes the listener. See
|
||||
@@ -122,17 +122,6 @@ Handles a single `invoke`able IPC message, then removes the listener. See
|
||||
|
||||
Removes any handler for `channel`, if present.
|
||||
|
||||
## IpcMainEvent object
|
||||
|
||||
The documentation for the `event` object passed to the `callback` can be found
|
||||
in the [`ipc-main-event`][ipc-main-event] structure docs.
|
||||
|
||||
## IpcMainInvokeEvent object
|
||||
|
||||
The documentation for the `event` object passed to `handle` callbacks can be
|
||||
found in the [`ipc-main-invoke-event`][ipc-main-invoke-event]
|
||||
structure docs.
|
||||
|
||||
[IPC tutorial]: ../tutorial/ipc.md
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[web-contents-send]: ../api/web-contents.md#contentssendchannel-args
|
||||
|
||||
@@ -26,7 +26,7 @@ The `ipcRenderer` module has the following method to listen for events and send
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` IpcRendererEvent
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
* `...args` any[]
|
||||
|
||||
Listens to `channel`, when a new message arrives `listener` would be called with
|
||||
@@ -36,7 +36,7 @@ Listens to `channel`, when a new message arrives `listener` would be called with
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` IpcRendererEvent
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
* `...args` any[]
|
||||
|
||||
Adds a one time `listener` function for the event. This `listener` is invoked
|
||||
@@ -208,12 +208,8 @@ Sends a message to a window with `webContentsId` via `channel`.
|
||||
Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in
|
||||
the host page instead of the main process.
|
||||
|
||||
## Event object
|
||||
|
||||
The documentation for the `event` object passed to the `callback` can be found
|
||||
in the [`ipc-renderer-event`](./structures/ipc-renderer-event.md) structure docs.
|
||||
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
||||
[`window.postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
|
||||
[`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
||||
[ipc-renderer-event]: ./structures/ipc-renderer-event.md
|
||||
|
||||
@@ -63,6 +63,62 @@ Creates a [`ClientRequest`](./client-request.md) instance using the provided
|
||||
The `net.request` method would be used to issue both secure and insecure HTTP
|
||||
requests according to the specified protocol scheme in the `options` object.
|
||||
|
||||
### `net.fetch(input[, init])`
|
||||
|
||||
* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & { bypassCustomProtocolHandlers?: boolean } (optional)
|
||||
|
||||
Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
||||
|
||||
Sends a request, similarly to how `fetch()` works in the renderer, using
|
||||
Chrome's network stack. This differs from Node's `fetch()`, which uses
|
||||
Node.js's HTTP stack.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
async function example () {
|
||||
const response = await net.fetch('https://my.app')
|
||||
if (response.ok) {
|
||||
const body = await response.json()
|
||||
// ... use the result.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This method will issue requests from the [default
|
||||
session](session.md#sessiondefaultsession). To send a `fetch` request from
|
||||
another session, use [ses.fetch()](session.md#sesfetchinput-init).
|
||||
|
||||
See the MDN documentation for
|
||||
[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) for more
|
||||
details.
|
||||
|
||||
Limitations:
|
||||
|
||||
* `net.fetch()` does not support the `data:` or `blob:` schemes.
|
||||
* The value of the `integrity` option is ignored.
|
||||
* The `.type` and `.url` values of the returned `Response` object are
|
||||
incorrect.
|
||||
|
||||
By default, requests made with `net.fetch` can be made to [custom
|
||||
protocols](protocol.md) as well as `file:`, and will trigger
|
||||
[webRequest](web-request.md) handlers if present. When the non-standard
|
||||
`bypassCustomProtocolHandlers` option is set in RequestInit, custom protocol
|
||||
handlers will not be called for this request. This allows forwarding an
|
||||
intercepted request to the built-in handler. [webRequest](web-request.md)
|
||||
handlers will still be triggered when bypassing custom protocols.
|
||||
|
||||
```js
|
||||
protocol.handle('https', (req) => {
|
||||
if (req.url === 'https://my-app.com') {
|
||||
return new Response('<body>my app</body>')
|
||||
} else {
|
||||
return net.fetch(req, { bypassCustomProtocolHandlers: true })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### `net.isOnline()`
|
||||
|
||||
Returns `boolean` - Whether there is currently internet connection.
|
||||
|
||||
@@ -49,8 +49,11 @@ beginning to load the web page or the main script.
|
||||
|
||||
### `process.defaultApp` _Readonly_
|
||||
|
||||
A `boolean`. When app is started by being passed as parameter to the default app, this
|
||||
A `boolean`. When the app is started by being passed as parameter to the default Electron executable, this
|
||||
property is `true` in the main process, otherwise it is `undefined`.
|
||||
For example when running the app with `electron .`, it is `true`,
|
||||
even if the app is packaged ([`isPackaged`](app.md#appispackaged-readonly)) is `true`.
|
||||
This can be useful to determine how many arguments will need to be sliced off from `process.argv`.
|
||||
|
||||
### `process.isMainFrame` _Readonly_
|
||||
|
||||
|
||||
@@ -8,15 +8,11 @@ An example of implementing a protocol that has the same effect as the
|
||||
`file://` protocol:
|
||||
|
||||
```javascript
|
||||
const { app, protocol } = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
const { app, protocol, net } = require('electron')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const filePath = url.fileURLToPath('file://' + request.url.slice('atom://'.length))
|
||||
callback(filePath)
|
||||
})
|
||||
protocol.handle('atom', (request) =>
|
||||
net.fetch('file://' + request.url.slice('atom://'.length)))
|
||||
})
|
||||
```
|
||||
|
||||
@@ -38,14 +34,15 @@ to register it to that session explicitly.
|
||||
```javascript
|
||||
const { app, BrowserWindow, net, protocol, session } = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const partition = 'persist:example'
|
||||
const ses = session.fromPartition(partition)
|
||||
|
||||
ses.protocol.registerFileProtocol('atom', (request, callback) => {
|
||||
const url = request.url.substr(7)
|
||||
callback({ path: path.normalize(path.join(__dirname, url)) })
|
||||
ses.protocol.handle('atom', (request) => {
|
||||
const filePath = request.url.slice('atom://'.length)
|
||||
return net.fetch(url.pathToFileURL(path.join(__dirname, filePath)).toString())
|
||||
})
|
||||
|
||||
const mainWindow = new BrowserWindow({ webPreferences: { partition } })
|
||||
@@ -109,7 +106,74 @@ The `<video>` and `<audio>` HTML elements expect protocols to buffer their
|
||||
responses by default. The `stream` flag configures those elements to correctly
|
||||
expect streaming responses.
|
||||
|
||||
### `protocol.registerFileProtocol(scheme, handler)`
|
||||
### `protocol.handle(scheme, handler)`
|
||||
|
||||
* `scheme` string - scheme to handle, for example `https` or `my-app`. This is
|
||||
the bit before the `:` in a URL.
|
||||
* `handler` Function<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise<GlobalResponse>>
|
||||
* `request` [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
|
||||
Register a protocol handler for `scheme`. Requests made to URLs with this
|
||||
scheme will delegate to this handler to determine what response should be sent.
|
||||
|
||||
Either a `Response` or a `Promise<Response>` can be returned.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
const { app, net, protocol } = require('electron')
|
||||
const { join } = require('path')
|
||||
const { pathToFileURL } = require('url')
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme: 'app',
|
||||
privileges: {
|
||||
standard: true,
|
||||
secure: true,
|
||||
supportFetchAPI: true
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
app.whenReady().then(() => {
|
||||
protocol.handle('app', (req) => {
|
||||
const { host, pathname } = new URL(req.url)
|
||||
if (host === 'bundle') {
|
||||
if (pathname === '/') {
|
||||
return new Response('<h1>hello, world</h1>', {
|
||||
headers: { 'content-type': 'text/html' }
|
||||
})
|
||||
}
|
||||
// NB, this does not check for paths that escape the bundle, e.g.
|
||||
// app://bundle/../../secret_file.txt
|
||||
return net.fetch(pathToFileURL(join(__dirname, pathname)).toString())
|
||||
} else if (host === 'api') {
|
||||
return net.fetch('https://api.my-server.com/' + pathname, {
|
||||
method: req.method,
|
||||
headers: req.headers,
|
||||
body: req.body
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
See the MDN docs for [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) for more details.
|
||||
|
||||
### `protocol.unhandle(scheme)`
|
||||
|
||||
* `scheme` string - scheme for which to remove the handler.
|
||||
|
||||
Removes a protocol handler registered with `protocol.handle`.
|
||||
|
||||
### `protocol.isProtocolHandled(scheme)`
|
||||
|
||||
* `scheme` string
|
||||
|
||||
Returns `boolean` - Whether `scheme` is already handled.
|
||||
|
||||
### `protocol.registerFileProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -130,7 +194,7 @@ path or an object that has a `path` property, e.g. `callback(filePath)` or
|
||||
By default the `scheme` is treated like `http:`, which is parsed differently
|
||||
from protocols that follow the "generic URI syntax" like `file:`.
|
||||
|
||||
### `protocol.registerBufferProtocol(scheme, handler)`
|
||||
### `protocol.registerBufferProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -154,7 +218,7 @@ protocol.registerBufferProtocol('atom', (request, callback) => {
|
||||
})
|
||||
```
|
||||
|
||||
### `protocol.registerStringProtocol(scheme, handler)`
|
||||
### `protocol.registerStringProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -170,7 +234,7 @@ The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with either a `string` or an object that has the `data`
|
||||
property.
|
||||
|
||||
### `protocol.registerHttpProtocol(scheme, handler)`
|
||||
### `protocol.registerHttpProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -185,7 +249,7 @@ Registers a protocol of `scheme` that will send an HTTP request as a response.
|
||||
The usage is the same with `registerFileProtocol`, except that the `callback`
|
||||
should be called with an object that has the `url` property.
|
||||
|
||||
### `protocol.registerStreamProtocol(scheme, handler)`
|
||||
### `protocol.registerStreamProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -234,7 +298,7 @@ protocol.registerStreamProtocol('atom', (request, callback) => {
|
||||
})
|
||||
```
|
||||
|
||||
### `protocol.unregisterProtocol(scheme)`
|
||||
### `protocol.unregisterProtocol(scheme)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
|
||||
@@ -242,13 +306,13 @@ Returns `boolean` - Whether the protocol was successfully unregistered
|
||||
|
||||
Unregisters the custom protocol of `scheme`.
|
||||
|
||||
### `protocol.isProtocolRegistered(scheme)`
|
||||
### `protocol.isProtocolRegistered(scheme)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
|
||||
Returns `boolean` - Whether `scheme` is already registered.
|
||||
|
||||
### `protocol.interceptFileProtocol(scheme, handler)`
|
||||
### `protocol.interceptFileProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -261,7 +325,7 @@ Returns `boolean` - Whether the protocol was successfully intercepted
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a file as a response.
|
||||
|
||||
### `protocol.interceptStringProtocol(scheme, handler)`
|
||||
### `protocol.interceptStringProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -274,7 +338,7 @@ Returns `boolean` - Whether the protocol was successfully intercepted
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a `string` as a response.
|
||||
|
||||
### `protocol.interceptBufferProtocol(scheme, handler)`
|
||||
### `protocol.interceptBufferProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -287,7 +351,7 @@ Returns `boolean` - Whether the protocol was successfully intercepted
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a `Buffer` as a response.
|
||||
|
||||
### `protocol.interceptHttpProtocol(scheme, handler)`
|
||||
### `protocol.interceptHttpProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -300,7 +364,7 @@ Returns `boolean` - Whether the protocol was successfully intercepted
|
||||
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
|
||||
which sends a new HTTP request as a response.
|
||||
|
||||
### `protocol.interceptStreamProtocol(scheme, handler)`
|
||||
### `protocol.interceptStreamProtocol(scheme, handler)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
* `handler` Function
|
||||
@@ -313,7 +377,7 @@ Returns `boolean` - Whether the protocol was successfully intercepted
|
||||
Same as `protocol.registerStreamProtocol`, except that it replaces an existing
|
||||
protocol handler.
|
||||
|
||||
### `protocol.uninterceptProtocol(scheme)`
|
||||
### `protocol.uninterceptProtocol(scheme)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
|
||||
@@ -321,7 +385,7 @@ Returns `boolean` - Whether the protocol was successfully unintercepted
|
||||
|
||||
Remove the interceptor installed for `scheme` and restore its original handler.
|
||||
|
||||
### `protocol.isProtocolIntercepted(scheme)`
|
||||
### `protocol.isProtocolIntercepted(scheme)` _Deprecated_
|
||||
|
||||
* `scheme` string
|
||||
|
||||
|
||||
@@ -38,3 +38,31 @@ Returns `string` - the decrypted string. Decrypts the encrypted buffer
|
||||
obtained with `safeStorage.encryptString` back into a string.
|
||||
|
||||
This function will throw an error if decryption fails.
|
||||
|
||||
### `safeStorage.setUsePlainTextEncryption(usePlainText)`
|
||||
|
||||
* `usePlainText` boolean
|
||||
|
||||
This function on Linux will force the module to use an in memory password for creating
|
||||
symmetric key that is used for encrypt/decrypt functions when a valid OS password
|
||||
manager cannot be determined for the current active desktop environment. This function
|
||||
is a no-op on Windows and MacOS.
|
||||
|
||||
### `safeStorage.getSelectedStorageBackend()` _Linux_
|
||||
|
||||
Returns `string` - User friendly name of the password manager selected on Linux.
|
||||
|
||||
This function will return one of the following values:
|
||||
|
||||
* `basic_text` - When the desktop environment is not recognised or if the following
|
||||
command line flag is provided `--password-store="basic"`.
|
||||
* `gnome_any` - When the desktop environment is `X-Cinnamon`, `Deepin`, `GNOME`, `Pantheon`, `XFCE`, `UKUI`, `unity` or if the following command line flag is provided `--password-store="gnome"`. When this value is present the application
|
||||
will first try to use `libsecret` backend and if it fails will attempt to use `libgnome_keyring`.
|
||||
* `gnome_libsecret` - When the following command line flag is provided `--password-store="gnome-libsecret"`.
|
||||
* `gnome_keyring` - When the following command line flag is provided `--password-store="gnome-keyring"`.
|
||||
* `kwallet` - When the desktop session is `kde4` or if the following command line flag
|
||||
is provided `--password-store="kwallet"`.
|
||||
* `kwallet5` - When the desktop session is `kde5` or if the following command line flag
|
||||
is provided `--password-store="kwallet5"`.
|
||||
* `kwallet6` - When the desktop session is `kde6`.
|
||||
* `unknown` - When the function is called before app has emitted the `ready` event.
|
||||
|
||||
@@ -42,6 +42,22 @@ To create a `Session` with `options`, you have to ensure the `Session` with the
|
||||
`partition` has never been used before. There is no way to change the `options`
|
||||
of an existing `Session` object.
|
||||
|
||||
### `session.fromPath(path[, options])`
|
||||
|
||||
* `path` string
|
||||
* `options` Object (optional)
|
||||
* `cache` boolean - Whether to enable cache.
|
||||
|
||||
Returns `Session` - A session instance from the absolute path as specified by the `path`
|
||||
string. When there is an existing `Session` with the same absolute path, it
|
||||
will be returned; otherwise a new `Session` instance will be created with `options`. The
|
||||
call will throw an error if the path is not an absolute path. Additionally, an error will
|
||||
be thrown if an empty string is provided.
|
||||
|
||||
To create a `Session` with `options`, you have to ensure the `Session` with the
|
||||
`path` has never been used before. There is no way to change the `options`
|
||||
of an existing `Session` object.
|
||||
|
||||
## Properties
|
||||
|
||||
The `session` module has the following properties:
|
||||
@@ -503,9 +519,8 @@ app.whenReady().then(() => {
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [USBDevice](structures/usb-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
* `device` [USBDevice](structures/usb-device.md)
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Emitted after `navigator.usb.requestDevice` has been called and
|
||||
`select-usb-device` has fired if a new device becomes available before
|
||||
@@ -518,9 +533,8 @@ with the newly added device.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [USBDevice](structures/usb-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
* `device` [USBDevice](structures/usb-device.md)
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Emitted after `navigator.usb.requestDevice` has been called and
|
||||
`select-usb-device` has fired if a device has been removed before the callback
|
||||
@@ -534,7 +548,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [USBDevice[]](structures/usb-device.md)
|
||||
* `device` [USBDevice](structures/usb-device.md)
|
||||
* `origin` string (optional) - The origin that the device has been revoked from.
|
||||
|
||||
Emitted after `USBDevice.forget()` has been called. This event can be used
|
||||
@@ -768,6 +782,61 @@ Returns `Promise<void>` - Resolves when all connections are closed.
|
||||
|
||||
**Note:** It will terminate / fail all requests currently in flight.
|
||||
|
||||
#### `ses.fetch(input[, init])`
|
||||
|
||||
* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) (optional)
|
||||
|
||||
Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
||||
|
||||
Sends a request, similarly to how `fetch()` works in the renderer, using
|
||||
Chrome's network stack. This differs from Node's `fetch()`, which uses
|
||||
Node.js's HTTP stack.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
async function example () {
|
||||
const response = await net.fetch('https://my.app')
|
||||
if (response.ok) {
|
||||
const body = await response.json()
|
||||
// ... use the result.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See also [`net.fetch()`](net.md#netfetchinput-init), a convenience method which
|
||||
issues requests from the [default session](#sessiondefaultsession).
|
||||
|
||||
See the MDN documentation for
|
||||
[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) for more
|
||||
details.
|
||||
|
||||
Limitations:
|
||||
|
||||
* `net.fetch()` does not support the `data:` or `blob:` schemes.
|
||||
* The value of the `integrity` option is ignored.
|
||||
* The `.type` and `.url` values of the returned `Response` object are
|
||||
incorrect.
|
||||
|
||||
By default, requests made with `net.fetch` can be made to [custom
|
||||
protocols](protocol.md) as well as `file:`, and will trigger
|
||||
[webRequest](web-request.md) handlers if present. When the non-standard
|
||||
`bypassCustomProtocolHandlers` option is set in RequestInit, custom protocol
|
||||
handlers will not be called for this request. This allows forwarding an
|
||||
intercepted request to the built-in handler. [webRequest](web-request.md)
|
||||
handlers will still be triggered when bypassing custom protocols.
|
||||
|
||||
```js
|
||||
protocol.handle('https', (req) => {
|
||||
if (req.url === 'https://my-app.com') {
|
||||
return new Response('<body>my app</body>')
|
||||
} else {
|
||||
return net.fetch(req, { bypassCustomProtocolHandlers: true })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### `ses.disableNetworkEmulation()`
|
||||
|
||||
Disables any network emulation already active for the `session`. Resets to
|
||||
@@ -1231,16 +1300,18 @@ reused for new connections.
|
||||
|
||||
Returns `Promise<Buffer>` - resolves with blob data.
|
||||
|
||||
#### `ses.downloadURL(url)`
|
||||
#### `ses.downloadURL(url[, options])`
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url`.
|
||||
The API will generate a [DownloadItem](download-item.md) that can be accessed
|
||||
with the [will-download](#event-will-download) event.
|
||||
|
||||
**Note:** This does not perform any security checks that relate to a page's origin,
|
||||
unlike [`webContents.downloadURL`](web-contents.md#contentsdownloadurlurl).
|
||||
unlike [`webContents.downloadURL`](web-contents.md#contentsdownloadurlurl-options).
|
||||
|
||||
#### `ses.createInterruptedDownload(options)`
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Event Object extends `GlobalEvent`
|
||||
|
||||
* `preventDefault` VoidFunction
|
||||
13
docs/api/structures/render-process-gone-details.md
Normal file
13
docs/api/structures/render-process-gone-details.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# RenderProcessGoneDetails Object
|
||||
|
||||
* `reason` string - The reason the render process is gone. Possible values:
|
||||
* `clean-exit` - Process exited with an exit code of zero
|
||||
* `abnormal-exit` - Process exited with a non-zero exit code
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failed` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
* `exitCode` Integer - The exit code of the process, unless `reason` is
|
||||
`launch-failed`, in which case `exitCode` will be a platform-specific
|
||||
launch failure error code.
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
* `type` 'file' - `file`.
|
||||
* `filePath` string - Path of file to be uploaded.
|
||||
* `offset` Integer - Defaults to `0`.
|
||||
* `length` Integer - Number of bytes to read from `offset`.
|
||||
* `offset` Integer (optional) - Defaults to `0`.
|
||||
* `length` Integer (optional) - Number of bytes to read from `offset`.
|
||||
Defaults to `0`.
|
||||
* `modificationTime` Double - Last Modification time in
|
||||
number of seconds since the UNIX epoch.
|
||||
* `modificationTime` Double (optional) - Last Modification time in
|
||||
number of seconds since the UNIX epoch. Defaults to `0`.
|
||||
|
||||
@@ -291,7 +291,7 @@ This API is only available on macOS 10.14 Mojave or newer.
|
||||
* `window-frame` - Window frame.
|
||||
* `window-text` - Text in windows.
|
||||
* On **macOS**
|
||||
* `alternate-selected-control-text` - The text on a selected surface in a list or table. _deprecated_
|
||||
* `alternate-selected-control-text` - The text on a selected surface in a list or table. _Deprecated_
|
||||
* `control-background` - The background of a large interface element, such as a browser or table.
|
||||
* `control` - The surface of a control.
|
||||
* `control-text` -The text of a control that isn’t disabled.
|
||||
|
||||
@@ -19,6 +19,36 @@ const contents = win.webContents
|
||||
console.log(contents)
|
||||
```
|
||||
|
||||
## Navigation Events
|
||||
|
||||
Several events can be used to monitor navigations as they occur within a `webContents`.
|
||||
|
||||
### Document Navigations
|
||||
|
||||
When a `webContents` navigates to another page (as opposed to an [in-page navigation](web-contents.md#in-page-navigation)), the following events will be fired.
|
||||
|
||||
* [`did-start-navigation`](web-contents.md#event-did-start-navigation)
|
||||
* [`will-frame-navigate`](web-contents.md#event-will-frame-navigate)
|
||||
* [`will-navigate`](web-contents.md#event-will-navigate) (only fired when main frame navigates)
|
||||
* [`will-redirect`](web-contents.md#event-will-redirect) (only fired when a redirect happens during navigation)
|
||||
* [`did-redirect-navigation`](web-contents.md#event-did-redirect-navigation) (only fired when a redirect happens during navigation)
|
||||
* [`did-frame-navigate`](web-contents.md#event-did-frame-navigate)
|
||||
* [`did-navigate`](web-contents.md#event-did-navigate) (only fired when main frame navigates)
|
||||
|
||||
Subsequent events will not fire if `event.preventDefault()` is called on any of the cancellable events.
|
||||
|
||||
### In-page Navigation
|
||||
|
||||
In-page navigations don't cause the page to reload, but instead navigate to a location within the current page. These events are not cancellable. For an in-page navigations, the following events will fire in this order:
|
||||
|
||||
* [`did-start-navigation`](web-contents.md#event-did-start-navigation)
|
||||
* [`did-navigate-in-page`](web-contents.md#event-did-navigate-in-page)
|
||||
|
||||
### Frame Navigation
|
||||
|
||||
The [`will-navigate`](web-contents.md#event-will-navigate) and [`did-navigate`](web-contents.md#event-did-navigate) events only fire when the [mainFrame](web-contents.md#contentsmainframe-readonly) navigates.
|
||||
If you want to also observe navigations in `<iframe>`s, use [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) and [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) events.
|
||||
|
||||
## Methods
|
||||
|
||||
These methods can be accessed from the `webContents` module:
|
||||
@@ -207,10 +237,25 @@ See [`window.open()`](window-open.md) for more details and how to use this in co
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `url` string
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
navigations, pushState/replaceState, and same page history navigation.
|
||||
* `isMainFrame` boolean - True if the navigation is taking place in a main frame.
|
||||
* `frame` WebFrameMain - The frame to be navigated.
|
||||
* `initiator` WebFrameMain (optional) - The frame which initiated the
|
||||
navigation, which can be a parent frame (e.g. via `window.open` with a
|
||||
frame's name), or null if the navigation was not initiated by a frame. This
|
||||
can also be null if the initiating frame was deleted before the event was
|
||||
emitted.
|
||||
* `url` string _Deprecated_
|
||||
* `isInPlace` boolean _Deprecated_
|
||||
* `isMainFrame` boolean _Deprecated_
|
||||
* `frameProcessId` Integer _Deprecated_
|
||||
* `frameRoutingId` Integer _Deprecated_
|
||||
|
||||
Emitted when a user or the page wants to start navigation. It can happen when
|
||||
Emitted when a user or the page wants to start navigation on the main frame. It can happen when
|
||||
the `window.location` object is changed or a user clicks a link in the page.
|
||||
|
||||
This event will not emit when the navigation is started programmatically with
|
||||
@@ -222,30 +267,79 @@ this purpose.
|
||||
|
||||
Calling `event.preventDefault()` will prevent the navigation.
|
||||
|
||||
#### Event: 'will-frame-navigate'
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isMainFrame` boolean - True if the navigation is taking place in a main frame.
|
||||
* `frame` WebFrameMain - The frame to be navigated.
|
||||
* `initiator` WebFrameMain (optional) - The frame which initiated the
|
||||
navigation, which can be a parent frame (e.g. via `window.open` with a
|
||||
frame's name), or null if the navigation was not initiated by a frame. This
|
||||
can also be null if the initiating frame was deleted before the event was
|
||||
emitted.
|
||||
|
||||
Emitted when a user or the page wants to start navigation in any frame. It can happen when
|
||||
the `window.location` object is changed or a user clicks a link in the page.
|
||||
|
||||
Unlike `will-navigate`, `will-frame-navigate` is fired when the main frame or any of its subframes attempts to navigate. When the navigation event comes from the main frame, `isMainFrame` will be `true`.
|
||||
|
||||
This event will not emit when the navigation is started programmatically with
|
||||
APIs like `webContents.loadURL` and `webContents.back`.
|
||||
|
||||
It is also not emitted for in-page navigations, such as clicking anchor links
|
||||
or updating the `window.location.hash`. Use `did-navigate-in-page` event for
|
||||
this purpose.
|
||||
|
||||
Calling `event.preventDefault()` will prevent the navigation.
|
||||
|
||||
#### Event: 'did-start-navigation'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `url` string
|
||||
* `isInPlace` boolean
|
||||
* `isMainFrame` boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
navigations, pushState/replaceState, and same page history navigation.
|
||||
* `isMainFrame` boolean - True if the navigation is taking place in a main frame.
|
||||
* `frame` WebFrameMain - The frame to be navigated.
|
||||
* `initiator` WebFrameMain (optional) - The frame which initiated the
|
||||
navigation, which can be a parent frame (e.g. via `window.open` with a
|
||||
frame's name), or null if the navigation was not initiated by a frame. This
|
||||
can also be null if the initiating frame was deleted before the event was
|
||||
emitted.
|
||||
* `url` string _Deprecated_
|
||||
* `isInPlace` boolean _Deprecated_
|
||||
* `isMainFrame` boolean _Deprecated_
|
||||
* `frameProcessId` Integer _Deprecated_
|
||||
* `frameRoutingId` Integer _Deprecated_
|
||||
|
||||
Emitted when any frame (including main) starts navigating. `isInPlace` will be
|
||||
`true` for in-page navigations.
|
||||
Emitted when any frame (including main) starts navigating.
|
||||
|
||||
#### Event: 'will-redirect'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `url` string
|
||||
* `isInPlace` boolean
|
||||
* `isMainFrame` boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
navigations, pushState/replaceState, and same page history navigation.
|
||||
* `isMainFrame` boolean - True if the navigation is taking place in a main frame.
|
||||
* `frame` WebFrameMain - The frame to be navigated.
|
||||
* `initiator` WebFrameMain (optional) - The frame which initiated the
|
||||
navigation, which can be a parent frame (e.g. via `window.open` with a
|
||||
frame's name), or null if the navigation was not initiated by a frame. This
|
||||
can also be null if the initiating frame was deleted before the event was
|
||||
emitted.
|
||||
* `url` string _Deprecated_
|
||||
* `isInPlace` boolean _Deprecated_
|
||||
* `isMainFrame` boolean _Deprecated_
|
||||
* `frameProcessId` Integer _Deprecated_
|
||||
* `frameRoutingId` Integer _Deprecated_
|
||||
|
||||
Emitted when a server side redirect occurs during navigation. For example a 302
|
||||
redirect.
|
||||
@@ -260,12 +354,23 @@ redirect).
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `url` string
|
||||
* `isInPlace` boolean
|
||||
* `isMainFrame` boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
navigations, pushState/replaceState, and same page history navigation.
|
||||
* `isMainFrame` boolean - True if the navigation is taking place in a main frame.
|
||||
* `frame` WebFrameMain - The frame to be navigated.
|
||||
* `initiator` WebFrameMain (optional) - The frame which initiated the
|
||||
navigation, which can be a parent frame (e.g. via `window.open` with a
|
||||
frame's name), or null if the navigation was not initiated by a frame. This
|
||||
can also be null if the initiating frame was deleted before the event was
|
||||
emitted.
|
||||
* `url` string _Deprecated_
|
||||
* `isInPlace` boolean _Deprecated_
|
||||
* `isMainFrame` boolean _Deprecated_
|
||||
* `frameProcessId` Integer _Deprecated_
|
||||
* `frameRoutingId` Integer _Deprecated_
|
||||
|
||||
Emitted after a server side redirect occurs during navigation. For example a 302
|
||||
redirect.
|
||||
@@ -373,18 +478,7 @@ checking `reason === 'killed'` when you switch to that event.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `reason` string - The reason the render process is gone. Possible values:
|
||||
* `clean-exit` - Process exited with an exit code of zero
|
||||
* `abnormal-exit` - Process exited with a non-zero exit code
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failed` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
* `exitCode` Integer - The exit code of the process, unless `reason` is
|
||||
`launch-failed`, in which case `exitCode` will be a platform-specific
|
||||
launch failure error code.
|
||||
* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md)
|
||||
|
||||
Emitted when the renderer process unexpectedly disappears. This is normally
|
||||
because it was crashed or killed.
|
||||
@@ -589,6 +683,15 @@ Emitted when media starts playing.
|
||||
|
||||
Emitted when media is paused or done playing.
|
||||
|
||||
#### Event: 'audio-state-changed'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event<>
|
||||
* `audible` boolean - True if one or more frames or child `webContents` are emitting audio.
|
||||
|
||||
Emitted when media becomes audible or inaudible.
|
||||
|
||||
#### Event: 'did-change-theme-color'
|
||||
|
||||
Returns:
|
||||
@@ -841,7 +944,7 @@ Emitted when the preload script `preloadPath` throws an unhandled exception `err
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `event` [IpcMainEvent](structures/ipc-main-event.md)
|
||||
* `channel` string
|
||||
* `...args` any[]
|
||||
|
||||
@@ -853,7 +956,7 @@ See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `event` [IpcMainEvent](structures/ipc-main-event.md)
|
||||
* `channel` string
|
||||
* `...args` any[]
|
||||
|
||||
@@ -942,9 +1045,11 @@ const win = new BrowserWindow()
|
||||
win.loadFile('src/index.html')
|
||||
```
|
||||
|
||||
#### `contents.downloadURL(url)`
|
||||
#### `contents.downloadURL(url[, options])`
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url` without navigating. The
|
||||
`will-download` event of `session` will be triggered.
|
||||
@@ -1287,6 +1392,10 @@ Executes the editing command `cut` in web page.
|
||||
|
||||
Executes the editing command `copy` in web page.
|
||||
|
||||
#### `contents.centerSelection()`
|
||||
|
||||
Centers the current text selection in web page.
|
||||
|
||||
#### `contents.copyImageAt(x, y)`
|
||||
|
||||
* `x` Integer
|
||||
@@ -1314,6 +1423,46 @@ Executes the editing command `selectAll` in web page.
|
||||
|
||||
Executes the editing command `unselect` in web page.
|
||||
|
||||
#### `contents.scrollToTop()`
|
||||
|
||||
Scrolls to the top of the current `webContents`.
|
||||
|
||||
#### `contents.scrollToBottom()`
|
||||
|
||||
Scrolls to the bottom of the current `webContents`.
|
||||
|
||||
#### `contents.adjustSelection(options)`
|
||||
|
||||
* `options` Object
|
||||
* `start` Number (optional) - Amount to shift the start index of the current selection.
|
||||
* `end` Number (optional) - Amount to shift the end index of the current selection.
|
||||
|
||||
Adjusts the current text selection starting and ending points in the focused frame by the given amounts. A negative amount moves the selection towards the beginning of the document, and a positive amount moves the selection towards the end of the document.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
const win = new BrowserWindow()
|
||||
|
||||
// Adjusts the beginning of the selection 1 letter forward,
|
||||
// and the end of the selection 5 letters forward.
|
||||
win.webContents.adjustSelection({ start: 1, end: 5 })
|
||||
|
||||
// Adjusts the beginning of the selection 2 letters forward,
|
||||
// and the end of the selection 3 letters backward.
|
||||
win.webContents.adjustSelection({ start: 2, end: -3 })
|
||||
```
|
||||
|
||||
For a call of `win.webContents.adjustSelection({ start: 1, end: 5 })`
|
||||
|
||||
Before:
|
||||
|
||||
<img width="487" alt="Image Before Text Selection Adjustment" src="../images/web-contents-text-selection-before.png"/>
|
||||
|
||||
After:
|
||||
|
||||
<img width="487" alt="Image After Text Selection Adjustment" src="../images/web-contents-text-selection-after.png"/>
|
||||
|
||||
#### `contents.replace(text)`
|
||||
|
||||
* `text` string
|
||||
|
||||
@@ -280,9 +280,11 @@ if the page fails to load (see
|
||||
Loads the `url` in the webview, the `url` must contain the protocol prefix,
|
||||
e.g. the `http://` or `file://`.
|
||||
|
||||
### `<webview>.downloadURL(url)`
|
||||
### `<webview>.downloadURL(url[, options])`
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url` without navigating.
|
||||
|
||||
@@ -465,6 +467,10 @@ Executes editing command `cut` in page.
|
||||
|
||||
Executes editing command `copy` in page.
|
||||
|
||||
#### `<webview>.centerSelection()`
|
||||
|
||||
Centers the current text selection in page.
|
||||
|
||||
### `<webview>.paste()`
|
||||
|
||||
Executes editing command `paste` in page.
|
||||
@@ -485,6 +491,25 @@ Executes editing command `selectAll` in page.
|
||||
|
||||
Executes editing command `unselect` in page.
|
||||
|
||||
#### `<webview>.scrollToTop()`
|
||||
|
||||
Scrolls to the top of the current `<webview>`.
|
||||
|
||||
#### `<webview>.scrollToBottom()`
|
||||
|
||||
Scrolls to the bottom of the current `<webview>`.
|
||||
|
||||
#### `<webview>.adjustSelection(options)`
|
||||
|
||||
* `options` Object
|
||||
* `start` Number (optional) - Amount to shift the start index of the current selection.
|
||||
* `end` Number (optional) - Amount to shift the end index of the current selection.
|
||||
|
||||
Adjusts the current text selection starting and ending points in the focused frame by the given amounts. A negative amount moves the selection towards the beginning of the document, and a positive amount moves the selection towards the end of the document.
|
||||
|
||||
See [`webContents.adjustSelection`](web-contents.md#contentsadjustselectionoptions) for
|
||||
examples.
|
||||
|
||||
### `<webview>.replace(text)`
|
||||
|
||||
* `text` string
|
||||
@@ -825,6 +850,28 @@ this purpose.
|
||||
|
||||
Calling `event.preventDefault()` does **NOT** have any effect.
|
||||
|
||||
### Event: 'will-frame-navigate'
|
||||
|
||||
Returns:
|
||||
|
||||
* `url` string
|
||||
* `isMainFrame` boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
|
||||
Emitted when a user or the page wants to start navigation anywhere in the `<webview>`
|
||||
or any frames embedded within. It can happen when the `window.location` object is
|
||||
changed or a user clicks a link in the page.
|
||||
|
||||
This event will not emit when the navigation is started programmatically with
|
||||
APIs like `<webview>.loadURL` and `<webview>.back`.
|
||||
|
||||
It is also not emitted during in-page navigation, such as clicking anchor links
|
||||
or updating the `window.location.hash`. Use `did-navigate-in-page` event for
|
||||
this purpose.
|
||||
|
||||
Calling `event.preventDefault()` does **NOT** have any effect.
|
||||
|
||||
### Event: 'did-start-navigation'
|
||||
|
||||
Returns:
|
||||
@@ -938,9 +985,22 @@ ipcRenderer.on('ping', () => {
|
||||
})
|
||||
```
|
||||
|
||||
### Event: 'crashed'
|
||||
### Event: 'crashed' _Deprecated_
|
||||
|
||||
Fired when the renderer process is crashed.
|
||||
Fired when the renderer process crashes or is killed.
|
||||
|
||||
**Deprecated:** This event is superceded by the `render-process-gone` event
|
||||
which contains more information about why the render process disappeared. It
|
||||
isn't always because it crashed.
|
||||
|
||||
### Event: 'render-process-gone'
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md)
|
||||
|
||||
Fired when the renderer process unexpectedly disappears. This is normally
|
||||
because it was crashed or killed.
|
||||
|
||||
### Event: 'plugin-crashed'
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
|
||||
* Non-standard features (that are not handled by Chromium or Electron) given in
|
||||
`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).
|
||||
* `frameName` follows the specification of `target` 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.
|
||||
|
||||
@@ -12,6 +12,102 @@ 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 (27.0)
|
||||
|
||||
### Removed: macOS 10.13 / 10.14 support
|
||||
|
||||
macOS 10.13 (High Sierra) and macOS 10.14 (Mojave) are no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/4629466).
|
||||
|
||||
Older versions of Electron will continue to run on these operating systems, but macOS 10.15 (Catalina)
|
||||
or later will be required to run Electron v27.0.0 and higher.
|
||||
|
||||
## Planned Breaking API Changes (25.0)
|
||||
|
||||
### Deprecated: `protocol.{register,intercept}{Buffer,String,Stream,File,Http}Protocol`
|
||||
|
||||
The `protocol.register*Protocol` and `protocol.intercept*Protocol` methods have
|
||||
been replaced with [`protocol.handle`](api/protocol.md#protocolhandlescheme-handler).
|
||||
|
||||
The new method can either register a new protocol or intercept an existing
|
||||
protocol, and responses can be of any type.
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 25
|
||||
protocol.registerBufferProtocol('some-protocol', () => {
|
||||
callback({ mimeType: 'text/html', data: Buffer.from('<h5>Response</h5>') })
|
||||
})
|
||||
|
||||
// Replace with
|
||||
protocol.handle('some-protocol', () => {
|
||||
return new Response(
|
||||
Buffer.from('<h5>Response</h5>'), // Could also be a string or ReadableStream.
|
||||
{ headers: { 'content-type': 'text/html' } }
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 25
|
||||
protocol.registerHttpProtocol('some-protocol', () => {
|
||||
callback({ url: 'https://electronjs.org' })
|
||||
})
|
||||
|
||||
// Replace with
|
||||
protocol.handle('some-protocol', () => {
|
||||
return net.fetch('https://electronjs.org')
|
||||
})
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 25
|
||||
protocol.registerFileProtocol('some-protocol', () => {
|
||||
callback({ filePath: '/path/to/my/file' })
|
||||
})
|
||||
|
||||
// Replace with
|
||||
protocol.handle('some-protocol', () => {
|
||||
return net.fetch('file:///path/to/my/file')
|
||||
})
|
||||
```
|
||||
|
||||
### Deprecated: `BrowserWindow.setTrafficLightPosition(position)`
|
||||
|
||||
`BrowserWindow.setTrafficLightPosition(position)` has been deprecated, the
|
||||
`BrowserWindow.setWindowButtonPosition(position)` API should be used instead
|
||||
which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to
|
||||
system default.
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 25
|
||||
win.setTrafficLightPosition({ x: 10, y: 10 })
|
||||
win.setTrafficLightPosition({ x: 0, y: 0 })
|
||||
|
||||
// Replace with
|
||||
win.setWindowButtonPosition({ x: 10, y: 10 })
|
||||
win.setWindowButtonPosition(null)
|
||||
```
|
||||
|
||||
### Deprecated: `BrowserWindow.getTrafficLightPosition()`
|
||||
|
||||
`BrowserWindow.getTrafficLightPosition()` has been deprecated, the
|
||||
`BrowserWindow.getWindowButtonPosition()` API should be used instead
|
||||
which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom
|
||||
position.
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 25
|
||||
const pos = win.getTrafficLightPosition()
|
||||
if (pos.x === 0 && pos.y === 0) {
|
||||
// No custom position.
|
||||
}
|
||||
|
||||
// Replace with
|
||||
const ret = win.getWindowButtonPosition()
|
||||
if (ret === null) {
|
||||
// No custom position.
|
||||
}
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (24.0)
|
||||
|
||||
### API Changed: `nativeImage.createThumbnailFromPath(path, size)`
|
||||
|
||||
@@ -1,128 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Customize Menus</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Customize Menus</h1>
|
||||
|
||||
<h3>
|
||||
The <code>Menu</code> and <code>MenuItem</code> modules can be used to
|
||||
create custom native menus.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
There are two kinds of menus: the application (top) menu and context
|
||||
(right-click) menu.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/menu"
|
||||
>full API documentation<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Create an application menu</h2>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
The <code>Menu</code> and <code>MenuItem</code> modules allow you to
|
||||
customize your application menu. If you don't set any menu, Electron
|
||||
will generate a minimal menu for your app by default.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you click the 'View' option in the application menu and then the
|
||||
'App Menu Demo', you'll see an information box displayed.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Know operating system menu differences.</strong>
|
||||
<p>
|
||||
When designing an app for multiple operating systems it's
|
||||
important to be mindful of the ways application menu conventions
|
||||
differ on each operating system.
|
||||
</p>
|
||||
<p>
|
||||
For instance, on Windows, accelerators are set with an
|
||||
<code>&</code>. Naming conventions also vary, like between
|
||||
"Settings" or "Preferences". Below are resources for learning
|
||||
operating system specific standards.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://developer.apple.com/macos/human-interface-guidelines/menus/menu-anatomy/"
|
||||
>macOS<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://learn.microsoft.com/en-us/previous-versions/windows/desktop/bb226797"
|
||||
>Windows<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://developer.gnome.org/hig/stable/menu-bars.html.en"
|
||||
>Linux<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Create a context menu</h2>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<button id="context-menu">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
A context, or right-click, menu can be created with the
|
||||
<code>Menu</code> and <code>MenuItem</code> modules as well. You can
|
||||
right-click anywhere in this app or click the demo button to see an
|
||||
example context menu.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this demo we use the <code>ipcRenderer</code> module to show the
|
||||
context menu when explicitly calling it from the renderer process.
|
||||
</p>
|
||||
<p>
|
||||
See the full
|
||||
<a
|
||||
href="https://electronjs.org/docs/api/web-contents/#event-context-menu"
|
||||
>context-menu event documentation</a
|
||||
>
|
||||
for all the available properties.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Customize Menus</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Customize Menus</h1>
|
||||
|
||||
<h3>
|
||||
The <code>Menu</code> and <code>MenuItem</code> modules can be used to
|
||||
create custom native menus.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
There are two kinds of menus: the application (top) menu and context
|
||||
(right-click) menu.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/menu"
|
||||
>full API documentation<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Create an application menu</h2>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
The <code>Menu</code> and <code>MenuItem</code> modules allow you to
|
||||
customize your application menu. If you don't set any menu, Electron
|
||||
will generate a minimal menu for your app by default.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you click the 'View' option in the application menu and then the
|
||||
'App Menu Demo', you'll see an information box displayed.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Know operating system menu differences.</strong>
|
||||
<p>
|
||||
When designing an app for multiple operating systems it's
|
||||
important to be mindful of the ways application menu conventions
|
||||
differ on each operating system.
|
||||
</p>
|
||||
<p>
|
||||
For instance, on Windows, accelerators are set with an
|
||||
<code>&</code>. Naming conventions also vary, like between
|
||||
"Settings" or "Preferences". Below are resources for learning
|
||||
operating system specific standards.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://developer.apple.com/macos/human-interface-guidelines/menus/menu-anatomy/"
|
||||
>macOS<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://learn.microsoft.com/en-us/previous-versions/windows/desktop/bb226797"
|
||||
>Windows<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://developer.gnome.org/hig/stable/menu-bars.html.en"
|
||||
>Linux<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Create a context menu</h2>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<button id="context-menu">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
A context, or right-click, menu can be created with the
|
||||
<code>Menu</code> and <code>MenuItem</code> modules as well. You can
|
||||
right-click anywhere in this app or click the demo button to see an
|
||||
example context menu.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this demo we use the <code>ipcRenderer</code> module to show the
|
||||
context menu when explicitly calling it from the renderer process.
|
||||
</p>
|
||||
<p>
|
||||
See the full
|
||||
<a
|
||||
href="https://electronjs.org/docs/api/web-contents/#event-context-menu"
|
||||
>context-menu event documentation</a
|
||||
>
|
||||
for all the available properties.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Keyboard Shortcuts</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Keyboard Shortcuts</h1>
|
||||
|
||||
<h3>The <code>globalShortcut</code> and <code>Menu</code> modules can be used to define keyboard shortcuts.</h3>
|
||||
|
||||
<p>
|
||||
In Electron, keyboard shortcuts are called accelerators.
|
||||
They can be assigned to actions in your application's Menu,
|
||||
or they can be assigned globally so they'll be triggered even when
|
||||
your app doesn't have keyboard focus.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the full documentation for the
|
||||
<a href="https://electronjs.org/docs/api/menu">Menu</a>,
|
||||
<a href="https://electronjs.org/docs/api/accelerator">Accelerator</a>,
|
||||
and
|
||||
<a href="https://electronjs.org/docs/api/global-shortcut">globalShortcut</a>
|
||||
APIs in your browser.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
To try this demo, press <kbd>CommandOrControl+Alt+K</kbd> on your
|
||||
keyboard.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Global shortcuts are detected even when the app doesn't have
|
||||
keyboard focus, and they must be registered after the app's
|
||||
`ready` event is emitted.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Avoid overriding system-wide keyboard shortcuts.</strong>
|
||||
<p>
|
||||
When registering global shortcuts, it's important to be aware of
|
||||
existing defaults in the target operating system, so as not to
|
||||
override any existing behaviors. For an overview of each
|
||||
operating system's keyboard shortcuts, view these documents:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a
|
||||
href="https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/Keyboard.html">macOS</a>
|
||||
</li>
|
||||
<li><a
|
||||
href="http://windows.microsoft.com/en-us/windows-10/keyboard-shortcuts">Windows</a></li>
|
||||
<li><a
|
||||
href="https://developer.gnome.org/hig/stable/keyboard-input.html.en">Linux</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Keyboard Shortcuts</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Keyboard Shortcuts</h1>
|
||||
|
||||
<h3>The <code>globalShortcut</code> and <code>Menu</code> modules can be used to define keyboard shortcuts.</h3>
|
||||
|
||||
<p>
|
||||
In Electron, keyboard shortcuts are called accelerators.
|
||||
They can be assigned to actions in your application's Menu,
|
||||
or they can be assigned globally so they'll be triggered even when
|
||||
your app doesn't have keyboard focus.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the full documentation for the
|
||||
<a href="https://electronjs.org/docs/api/menu">Menu</a>,
|
||||
<a href="https://electronjs.org/docs/api/accelerator">Accelerator</a>,
|
||||
and
|
||||
<a href="https://electronjs.org/docs/api/global-shortcut">globalShortcut</a>
|
||||
APIs in your browser.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
To try this demo, press <kbd>CommandOrControl+Alt+K</kbd> on your
|
||||
keyboard.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Global shortcuts are detected even when the app doesn't have
|
||||
keyboard focus, and they must be registered after the app's
|
||||
`ready` event is emitted.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Avoid overriding system-wide keyboard shortcuts.</strong>
|
||||
<p>
|
||||
When registering global shortcuts, it's important to be aware of
|
||||
existing defaults in the target operating system, so as not to
|
||||
override any existing behaviors. For an overview of each
|
||||
operating system's keyboard shortcuts, view these documents:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a
|
||||
href="https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/Keyboard.html">macOS</a>
|
||||
</li>
|
||||
<li><a
|
||||
href="http://windows.microsoft.com/en-us/windows-10/keyboard-shortcuts">Windows</a></li>
|
||||
<li><a
|
||||
href="https://developer.gnome.org/hig/stable/keyboard-input.html.en">Linux</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Error Dialog</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Error Dialog</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="error-dialog">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
error dialog.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can use an error dialog before the app's
|
||||
<code>ready</code> event, which is useful for showing errors upon
|
||||
startup.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const errorBtn = document.getElementById('error-dialog')
|
||||
|
||||
errorBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('open-error-dialog')
|
||||
})
|
||||
</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('open-error-dialog', (event) => {
|
||||
dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Error Dialog</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Error Dialog</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="error-dialog">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
error dialog.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can use an error dialog before the app's
|
||||
<code>ready</code> event, which is useful for showing errors upon
|
||||
startup.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const errorBtn = document.getElementById('error-dialog')
|
||||
|
||||
errorBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('open-error-dialog')
|
||||
})
|
||||
</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('open-error-dialog', (event) => {
|
||||
dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,104 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Information Dialog</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="section-wrapper">
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Information Dialog</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="information-dialog">
|
||||
View Demo
|
||||
</button>
|
||||
<span id="info-selection"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
information dialog. Options may be provided for responses which can
|
||||
then be relayed back to the renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note: The <code>title</code> property is not displayed in macOS.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An information dialog can contain an icon, your choice of buttons,
|
||||
title and message.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const informationBtn = document.getElementById('information-dialog')
|
||||
|
||||
informationBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('open-information-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('information-dialog-selection', (event, index) => {
|
||||
let message = 'You selected '
|
||||
if (index === 0) message += 'yes.'
|
||||
else message += 'no.'
|
||||
document.getElementById('info-selection').innerHTML = message
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('open-information-dialog', (event) => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, (index) => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Information Dialog</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="section-wrapper">
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Information Dialog</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="information-dialog">
|
||||
View Demo
|
||||
</button>
|
||||
<span id="info-selection"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
information dialog. Options may be provided for responses which can
|
||||
then be relayed back to the renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note: The <code>title</code> property is not displayed in macOS.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An information dialog can contain an icon, your choice of buttons,
|
||||
title and message.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const informationBtn = document.getElementById('information-dialog')
|
||||
|
||||
informationBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('open-information-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('information-dialog-selection', (event, index) => {
|
||||
let message = 'You selected '
|
||||
if (index === 0) message += 'yes.'
|
||||
else message += 'no.'
|
||||
document.getElementById('info-selection').innerHTML = message
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('open-information-dialog', (event) => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, (index) => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,108 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Open File or Directory</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="section-wrapper">
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Open a File or Directory</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="select-directory">View Demo</button>
|
||||
<span id="selected-file"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
open file (or directory) dialog. If a file is selected, the main
|
||||
process can send that information back to the renderer process.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const selectDirBtn = document.getElementById('select-directory')
|
||||
|
||||
selectDirBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('open-file-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('selected-directory', (event, path) => {
|
||||
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('open-file-dialog', (event) => {
|
||||
dialog.showOpenDialog({
|
||||
properties: ['openFile', 'openDirectory']
|
||||
}, (files) => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
})
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>The sheet-style dialog on macOS.</strong>
|
||||
<p>
|
||||
On macOS you can choose between a "sheet" dialog or a default
|
||||
dialog. The sheet version descends from the top of the window. To
|
||||
use sheet version, pass the <code>window</code> as the first
|
||||
argument in the dialog method.
|
||||
</p>
|
||||
<pre><code class="language-js">const ipc = require('electron').ipcMain
|
||||
const dialog = require('electron').dialog
|
||||
const BrowserWindow = require('electron').BrowserWindow
|
||||
|
||||
|
||||
ipc.on('open-file-dialog-sheet', function (event) {
|
||||
const window = BrowserWindow.fromWebContents(event.sender)
|
||||
const files = dialog.showOpenDialog(window, { properties: [ 'openFile' ]})
|
||||
})</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Open File or Directory</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="section-wrapper">
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Open a File or Directory</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="select-directory">View Demo</button>
|
||||
<span id="selected-file"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
open file (or directory) dialog. If a file is selected, the main
|
||||
process can send that information back to the renderer process.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const selectDirBtn = document.getElementById('select-directory')
|
||||
|
||||
selectDirBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('open-file-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('selected-directory', (event, path) => {
|
||||
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('open-file-dialog', (event) => {
|
||||
dialog.showOpenDialog({
|
||||
properties: ['openFile', 'openDirectory']
|
||||
}, (files) => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
})
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>The sheet-style dialog on macOS.</strong>
|
||||
<p>
|
||||
On macOS you can choose between a "sheet" dialog or a default
|
||||
dialog. The sheet version descends from the top of the window. To
|
||||
use sheet version, pass the <code>window</code> as the first
|
||||
argument in the dialog method.
|
||||
</p>
|
||||
<pre><code class="language-js">const ipc = require('electron').ipcMain
|
||||
const dialog = require('electron').dialog
|
||||
const BrowserWindow = require('electron').BrowserWindow
|
||||
|
||||
|
||||
ipc.on('open-file-dialog-sheet', function (event) {
|
||||
const window = BrowserWindow.fromWebContents(event.sender)
|
||||
const files = dialog.showOpenDialog(window, { properties: [ 'openFile' ]})
|
||||
})</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Save Dialog</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Save Dialog</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button button id="save-dialog">View Demo</button>
|
||||
<span id="file-saved"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
save dialog. It returns the path selected by the user which can be
|
||||
relayed back to the renderer process.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const saveBtn = document.getElementById('save-dialog')
|
||||
|
||||
saveBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('save-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('saved-file', (event, path) => {
|
||||
if (!path) path = 'No path'
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('save-dialog', (event) => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [
|
||||
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }
|
||||
]
|
||||
}
|
||||
dialog.showSaveDialog(options, (filename) => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Save Dialog</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Use system dialogs</h1>
|
||||
|
||||
<h3>
|
||||
The <code>dialog</code> module in Electron allows you to use native
|
||||
system dialogs for opening files or directories, saving a file or
|
||||
displaying informational messages.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
This is a main process module because this process is more efficient
|
||||
with native utilities and it allows the call to happen without
|
||||
interrupting the visible elements in your page's renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/dialog/">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Save Dialog</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button button id="save-dialog">View Demo</button>
|
||||
<span id="file-saved"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, the <code>ipc</code> module is used to send a message
|
||||
from the renderer process instructing the main process to launch the
|
||||
save dialog. It returns the path selected by the user which can be
|
||||
relayed back to the renderer process.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const saveBtn = document.getElementById('save-dialog')
|
||||
|
||||
saveBtn.addEventListener('click', (event) => {
|
||||
ipcRenderer.send('save-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('saved-file', (event, path) => {
|
||||
if (!path) path = 'No path'
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain, dialog} = require('electron')
|
||||
|
||||
ipcMain.on('save-dialog', (event) => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [
|
||||
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }
|
||||
]
|
||||
}
|
||||
dialog.showSaveDialog(options, (filename) => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Drag and drop files</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Drag and drop files</h1>
|
||||
<div>Supports: Win, macOS, Linux <span>|</span> Process: Both</div>
|
||||
<h3>
|
||||
Electron supports dragging files and content out from web content into
|
||||
the operating system's world.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/tutorial/native-file-drag-drop">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Dragging files</h2>
|
||||
<div>
|
||||
<div>
|
||||
<a href="#" id="drag-file-link">Drag Demo</a>
|
||||
</div>
|
||||
<p>
|
||||
Click and drag the link above to copy the renderer process
|
||||
javascript file on to your machine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this demo, the <code>webContents.startDrag()</code> API is called
|
||||
in response to the <code>ondragstart</code> event.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const dragFileLink = document.getElementById('drag-file-link')
|
||||
|
||||
dragFileLink.addEventListener('dragstart', (event) => {
|
||||
event.preventDefault()
|
||||
ipcRenderer.send('ondragstart', __filename)
|
||||
})
|
||||
</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
ipcMain.on('ondragstart', (event, filepath) => {
|
||||
const iconName = 'codeIcon.png'
|
||||
event.sender.startDrag({
|
||||
file: filepath,
|
||||
icon: path.join(__dirname, iconName)
|
||||
})
|
||||
})
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Drag and drop files</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Drag and drop files</h1>
|
||||
<div>Supports: Win, macOS, Linux <span>|</span> Process: Both</div>
|
||||
<h3>
|
||||
Electron supports dragging files and content out from web content into
|
||||
the operating system's world.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/tutorial/native-file-drag-drop">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Dragging files</h2>
|
||||
<div>
|
||||
<div>
|
||||
<a href="#" id="drag-file-link">Drag Demo</a>
|
||||
</div>
|
||||
<p>
|
||||
Click and drag the link above to copy the renderer process
|
||||
javascript file on to your machine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this demo, the <code>webContents.startDrag()</code> API is called
|
||||
in response to the <code>ondragstart</code> event.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code>
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const dragFileLink = document.getElementById('drag-file-link')
|
||||
|
||||
dragFileLink.addEventListener('dragstart', (event) => {
|
||||
event.preventDefault()
|
||||
ipcRenderer.send('ondragstart', __filename)
|
||||
})
|
||||
</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const {ipcMain} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
ipcMain.on('ondragstart', (event, filepath) => {
|
||||
const iconName = 'codeIcon.png'
|
||||
event.sender.startDrag({
|
||||
file: filepath,
|
||||
icon: path.join(__dirname, iconName)
|
||||
})
|
||||
})
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,104 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Open external links and the file manager</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>
|
||||
Open external links and the file manager
|
||||
</h1>
|
||||
<h3>
|
||||
The <code>shell</code> module in Electron allows you to access certain
|
||||
native elements like the file manager and default web browser.
|
||||
</h3>
|
||||
|
||||
<p>This module works in both the main and renderer process.</p>
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/shell">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Open Path in File Manager</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="open-file-manager">
|
||||
View Demo
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
This demonstrates using the <code>shell</code> module to open the
|
||||
system file manager at a particular location.
|
||||
</p>
|
||||
<p>
|
||||
Clicking the demo button will open your file manager at the root.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Open External Links</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="open-ex-links">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
If you do not want your app to open website links
|
||||
<em>within</em> the app, you can use the <code>shell</code> module
|
||||
to open them externally. When clicked, the links will open outside
|
||||
of your app and in the user's default web browser.
|
||||
</p>
|
||||
<p>
|
||||
When the demo button is clicked, the electron website will open in
|
||||
your browser.
|
||||
</p>
|
||||
<p></p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Open all outbound links externally.</strong>
|
||||
<p>
|
||||
You may want to open all <code>http</code> and
|
||||
<code>https</code> links outside of your app. To do this, query
|
||||
the document and loop through each link and add a listener. This
|
||||
app uses the code below which is located in
|
||||
<code>assets/ex-links.js</code>.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const shell = require('electron').shell
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Open external links and the file manager</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>
|
||||
Open external links and the file manager
|
||||
</h1>
|
||||
<h3>
|
||||
The <code>shell</code> module in Electron allows you to access certain
|
||||
native elements like the file manager and default web browser.
|
||||
</h3>
|
||||
|
||||
<p>This module works in both the main and renderer process.</p>
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/shell">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Open Path in File Manager</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="open-file-manager">
|
||||
View Demo
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
This demonstrates using the <code>shell</code> module to open the
|
||||
system file manager at a particular location.
|
||||
</p>
|
||||
<p>
|
||||
Clicking the demo button will open your file manager at the root.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Open External Links</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="open-ex-links">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
If you do not want your app to open website links
|
||||
<em>within</em> the app, you can use the <code>shell</code> module
|
||||
to open them externally. When clicked, the links will open outside
|
||||
of your app and in the user's default web browser.
|
||||
</p>
|
||||
<p>
|
||||
When the demo button is clicked, the electron website will open in
|
||||
your browser.
|
||||
</p>
|
||||
<p></p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Open all outbound links externally.</strong>
|
||||
<p>
|
||||
You may want to open all <code>http</code> and
|
||||
<code>https</code> links outside of your app. To do this, query
|
||||
the document and loop through each link and add a listener. This
|
||||
app uses the code below which is located in
|
||||
<code>assets/ex-links.js</code>.
|
||||
</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const shell = require('electron').shell
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,67 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Desktop notifications</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>Desktop notifications</h1>
|
||||
<h3>
|
||||
The <code>notification</code> module in Electron allows you to add basic
|
||||
desktop notifications.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Electron conveniently allows developers to send notifications with the
|
||||
<a href="https://notifications.spec.whatwg.org/">HTML5 Notification API</a>,
|
||||
using the currently running operating system’s native notification
|
||||
APIs to display it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> Since this is an HTML5 API it is only available in the
|
||||
renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/all/#notifications-windows-linux-macos">
|
||||
full API documentation<span>(opens in new window)</span>
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Basic notification</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="basic-noti">View demo</button>
|
||||
</div>
|
||||
<p>This demo demonstrates a basic notification. Text only.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Notification with image</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="advanced-noti">View demo</button>
|
||||
</div>
|
||||
<p>
|
||||
This demo demonstrates a basic notification. Both text and a image
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Desktop notifications</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>Desktop notifications</h1>
|
||||
<h3>
|
||||
The <code>notification</code> module in Electron allows you to add basic
|
||||
desktop notifications.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Electron conveniently allows developers to send notifications with the
|
||||
<a href="https://notifications.spec.whatwg.org/">HTML5 Notification API</a>,
|
||||
using the currently running operating system’s native notification
|
||||
APIs to display it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> Since this is an HTML5 API it is only available in the
|
||||
renderer process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/all/#notifications-windows-linux-macos">
|
||||
full API documentation<span>(opens in new window)</span>
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Basic notification</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="basic-noti">View demo</button>
|
||||
</div>
|
||||
<p>This demo demonstrates a basic notification. Text only.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Notification with image</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="advanced-noti">View demo</button>
|
||||
</div>
|
||||
<p>
|
||||
This demo demonstrates a basic notification. Both text and a image
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Tray</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>Tray</h1>
|
||||
<h3>
|
||||
The <code>tray</code> module allows you to create an icon in the
|
||||
operating system's notification area.
|
||||
</h3>
|
||||
<p>This icon can also have a context menu attached.</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/tray">
|
||||
full API documentation
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Tray support in Linux.</strong>
|
||||
<p>
|
||||
On Linux distributions that only have app indicator support, users
|
||||
will need to install <code>libappindicator1</code> to make the
|
||||
tray icon work. See the
|
||||
<a href="https://electronjs.org/docs/api/tray">
|
||||
full API documentation
|
||||
</a>
|
||||
for more details about using Tray on Linux.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Tray</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>Tray</h1>
|
||||
<h3>
|
||||
The <code>tray</code> module allows you to create an icon in the
|
||||
operating system's notification area.
|
||||
</h3>
|
||||
<p>This icon can also have a context menu attached.</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/tray">
|
||||
full API documentation
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Tray support in Linux.</strong>
|
||||
<p>
|
||||
On Linux distributions that only have app indicator support, users
|
||||
will need to install <code>libappindicator1</code> to make the
|
||||
tray icon work. See the
|
||||
<a href="https://electronjs.org/docs/api/tray">
|
||||
full API documentation
|
||||
</a>
|
||||
for more details about using Tray on Linux.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Frameless window</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Create and Manage Windows</h1>
|
||||
|
||||
<h3>
|
||||
The <code>BrowserWindow</code> module in Electron allows you to create a
|
||||
new browser window or manage an existing one.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Each browser window is a separate process, known as the renderer
|
||||
process. This process, like the main process that controls the life
|
||||
cycle of the app, has full access to the Node.js APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Create a frameless window</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="frameless-window">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
A frameless window is a window that has no
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Glossary/Chrome">
|
||||
"chrome"
|
||||
</a>
|
||||
, such as toolbars, title bars, status bars, borders, etc. You can
|
||||
make a browser window frameless by setting <code>frame</code> to
|
||||
<code>false</code> when creating the window.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Windows can have a transparent background, too. By setting the
|
||||
<code>transparent</code> option to <code>true</code>, you can also
|
||||
make your frameless window transparent:
|
||||
</p>
|
||||
<pre>
|
||||
<code class="language-js">var win = new BrowserWindow({
|
||||
transparent: true,
|
||||
frame: false
|
||||
})</code></pre>
|
||||
|
||||
<p>
|
||||
For more details, see the
|
||||
<a href="https://electronjs.org/docs/tutorial/window-customization/">
|
||||
Window Customization
|
||||
|
||||
</a>
|
||||
documentation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Frameless window</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Create and Manage Windows</h1>
|
||||
|
||||
<h3>
|
||||
The <code>BrowserWindow</code> module in Electron allows you to create a
|
||||
new browser window or manage an existing one.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Each browser window is a separate process, known as the renderer
|
||||
process. This process, like the main process that controls the life
|
||||
cycle of the app, has full access to the Node.js APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Create a frameless window</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="frameless-window">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
A frameless window is a window that has no
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Glossary/Chrome">
|
||||
"chrome"
|
||||
</a>
|
||||
, such as toolbars, title bars, status bars, borders, etc. You can
|
||||
make a browser window frameless by setting <code>frame</code> to
|
||||
<code>false</code> when creating the window.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Windows can have a transparent background, too. By setting the
|
||||
<code>transparent</code> option to <code>true</code>, you can also
|
||||
make your frameless window transparent:
|
||||
</p>
|
||||
<pre>
|
||||
<code class="language-js">var win = new BrowserWindow({
|
||||
transparent: true,
|
||||
frame: false
|
||||
})</code></pre>
|
||||
|
||||
<p>
|
||||
For more details, see the
|
||||
<a href="https://electronjs.org/docs/tutorial/window-customization/">
|
||||
Window Customization
|
||||
|
||||
</a>
|
||||
documentation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Manage window state</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Create and Manage Windows</h1>
|
||||
|
||||
<h3>
|
||||
The <code>BrowserWindow</code> module in Electron allows you to create a
|
||||
new browser window or manage an existing one.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Each browser window is a separate process, known as the renderer
|
||||
process. This process, like the main process that controls the life
|
||||
cycle of the app, has full access to the Node.js APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Manage window state</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="manage-window">View Demo</button>
|
||||
<span id="manage-window-reply"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo we create a new window and listen for
|
||||
<code>move</code> and <code>resize</code> events on it. Click the
|
||||
demo button, change the new window and see the dimensions and
|
||||
position update here, above.
|
||||
</p>
|
||||
<p>
|
||||
There are a lot of methods for controlling the state of the window
|
||||
such as the size, location, and focus status as well as events to
|
||||
listen to for window changes. Visit the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
documentation (opens in new window)
|
||||
</a>
|
||||
for the full list.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Manage window state</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Create and Manage Windows</h1>
|
||||
|
||||
<h3>
|
||||
The <code>BrowserWindow</code> module in Electron allows you to create a
|
||||
new browser window or manage an existing one.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Each browser window is a separate process, known as the renderer
|
||||
process. This process, like the main process that controls the life
|
||||
cycle of the app, has full access to the Node.js APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Manage window state</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="manage-window">View Demo</button>
|
||||
<span id="manage-window-reply"></span>
|
||||
</div>
|
||||
<p>
|
||||
In this demo we create a new window and listen for
|
||||
<code>move</code> and <code>resize</code> events on it. Click the
|
||||
demo button, change the new window and see the dimensions and
|
||||
position update here, above.
|
||||
</p>
|
||||
<p>
|
||||
There are a lot of methods for controlling the state of the window
|
||||
such as the size, location, and focus status as well as events to
|
||||
listen to for window changes. Visit the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
documentation (opens in new window)
|
||||
</a>
|
||||
for the full list.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Window events</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Create and Manage Windows</h1>
|
||||
|
||||
<h3>
|
||||
The <code>BrowserWindow</code> module in Electron allows you to create a
|
||||
new browser window or manage an existing one.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Each browser window is a separate process, known as the renderer
|
||||
process. This process, like the main process that controls the life
|
||||
cycle of the app, has full access to the Node.js APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Window events</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="listen-to-window">View Demo</button>
|
||||
<button id="focus-on-modal-window">
|
||||
Focus on Demo
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, we create a new window and listen for
|
||||
<code>blur</code> event on it. Click the demo button to create a new
|
||||
modal window, and switch focus back to the parent window by clicking
|
||||
on it. You can click the <i>Focus on Demo</i> button to switch focus
|
||||
to the modal window again.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Window events</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Create and Manage Windows</h1>
|
||||
|
||||
<h3>
|
||||
The <code>BrowserWindow</code> module in Electron allows you to create a
|
||||
new browser window or manage an existing one.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
Each browser window is a separate process, known as the renderer
|
||||
process. This process, like the main process that controls the life
|
||||
cycle of the app, has full access to the Node.js APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/browser-window">
|
||||
full API documentation (opens in new window)
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h2>Window events</h2>
|
||||
<div>
|
||||
<div>
|
||||
<button id="listen-to-window">View Demo</button>
|
||||
<button id="focus-on-modal-window">
|
||||
Focus on Demo
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
In this demo, we create a new window and listen for
|
||||
<code>blur</code> event on it. Click the demo button to create a new
|
||||
modal window, and switch focus back to the parent window by clicking
|
||||
on it. You can click the <i>Focus on Demo</i> button to switch focus
|
||||
to the modal window again.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
docs/images/web-contents-text-selection-after.png
Normal file
BIN
docs/images/web-contents-text-selection-after.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/images/web-contents-text-selection-before.png
Normal file
BIN
docs/images/web-contents-text-selection-before.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -41,7 +41,9 @@ Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of t
|
||||
ASAR integrity checking is currently disabled by default and can be enabled by toggling a fuse. See [Electron Fuses](fuses.md) for more information on what Electron Fuses are and how they work. When enabling this fuse you typically also want to enable the `onlyLoadAppFromAsar` fuse otherwise the validity checking can be bypassed via the Electron app code search path.
|
||||
|
||||
```js @ts-nocheck
|
||||
require('@electron/fuses').flipFuses(
|
||||
const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses')
|
||||
|
||||
flipFuses(
|
||||
// E.g. /a/b/Foo.app
|
||||
pathToPackagedApp,
|
||||
{
|
||||
|
||||
@@ -9,10 +9,11 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
|
||||
|
||||
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
|
||||
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
|
||||
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2023-Dec-05 | M114 | TBD | ✅ |
|
||||
| 24.0.0 | 2022-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-03 | M112 | v18.14 | ✅ |
|
||||
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-08 | M110 | v18.12 | ✅ |
|
||||
| 22.0.0 | 2022-Sep-29 | 2022-Oct-25 | 2022-Nov-29 | 2023-May-30 | M108 | v16.17 | ✅ |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | TBD | M116 | TBD | ✅ |
|
||||
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2024-Jan-02 | M114 | v18.15 | ✅ |
|
||||
| 24.0.0 | 2022-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | ✅ |
|
||||
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-15 | M110 | v18.12 | ✅ |
|
||||
| 22.0.0 | 2022-Sep-29 | 2022-Oct-25 | 2022-Nov-29 | 2023-Oct-10 | M108 | v16.17 | ✅ |
|
||||
| 21.0.0 | 2022-Aug-04 | 2022-Aug-30 | 2022-Sep-27 | 2023-Apr-04 | M106 | v16.16 | 🚫 |
|
||||
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | 2023-Feb-07 | M104 | v16.15 | 🚫 |
|
||||
| 19.0.0 | 2022-Mar-31 | 2022-Apr-26 | 2022-May-24 | 2022-Nov-29 | M102 | v16.14 | 🚫 |
|
||||
@@ -56,12 +57,12 @@ Chromium has the own public release schedule [here](https://chromiumdash.appspot
|
||||
|
||||
:::info
|
||||
|
||||
Beginning in September 2021 (Electron 15), the Electron team
|
||||
will temporarily support the latest **four** stable major versions. This
|
||||
extended support is intended to help Electron developers transition to
|
||||
the [new 8-week release cadence](https://electronjs.org/blog/8-week-cadence),
|
||||
and will continue until the release of Electron 19. At that time,
|
||||
the Electron team will drop support back to the latest three stable major versions.
|
||||
The Electron team will temporarily support Electron 22 until October 10, 2023.
|
||||
This extended support is intended to help Electron developers who still need
|
||||
support for Windows 7/8/8.1, which ended support in Electron 23. The October
|
||||
support date follows the extended support dates from both Chromium and Microsoft.
|
||||
On October 11, the Electron team will drop support back to the latest three
|
||||
stable major versions.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@@ -68,7 +68,9 @@ The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is
|
||||
We've made a handy module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases.
|
||||
|
||||
```js @ts-nocheck
|
||||
require('@electron/fuses').flipFuses(
|
||||
const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses')
|
||||
|
||||
flipFuses(
|
||||
// Path to electron
|
||||
require('electron'),
|
||||
// Fuses to flip
|
||||
@@ -82,7 +84,7 @@ require('@electron/fuses').flipFuses(
|
||||
You can validate the fuses have been flipped or check the fuse status of an arbitrary Electron app using the fuses CLI.
|
||||
|
||||
```bash
|
||||
npx @electron/fuses read --app /Applications/Foo.app
|
||||
npx @electron/fuses read --app /Applications/Foo.app
|
||||
```
|
||||
|
||||
### The hard way
|
||||
|
||||
@@ -63,9 +63,9 @@ const createWindow = () => {
|
||||
|
||||
In this next step, we will create our `BrowserWindow` and tell our application how to handle an event in which an external protocol is clicked.
|
||||
|
||||
This code will be different in Windows compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same Electron instance. Read more about this [here](../api/app.md#apprequestsingleinstancelockadditionaldata).
|
||||
This code will be different in Windows and Linux compared to MacOS. This is due to both platforms emitting the `second-instance` event rather than the `open-url` event and Windows requiring additional code in order to open the contents of the protocol link within the same Electron instance. Read more about this [here](../api/app.md#apprequestsingleinstancelockadditionaldata).
|
||||
|
||||
#### Windows code:
|
||||
#### Windows and Linux code:
|
||||
|
||||
```javascript @ts-type={mainWindow:Electron.BrowserWindow} @ts-type={createWindow:()=>void}
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
@@ -80,8 +80,7 @@ if (!gotTheLock) {
|
||||
mainWindow.focus()
|
||||
}
|
||||
// the commandLine is array of strings in which last element is deep link url
|
||||
// the url str ends with /
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop().slice(0, -1)}`)
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop()}`)
|
||||
})
|
||||
|
||||
// Create mainWindow, load the rest of the app, etc...
|
||||
@@ -91,7 +90,7 @@ if (!gotTheLock) {
|
||||
}
|
||||
```
|
||||
|
||||
#### MacOS and Linux code:
|
||||
#### MacOS code:
|
||||
|
||||
```javascript @ts-type={createWindow:()=>void}
|
||||
// This method will be called when Electron has finished
|
||||
|
||||
@@ -150,7 +150,7 @@ renderer.
|
||||
|
||||
```js title='renderer.js (Renderer Process)' @ts-nocheck
|
||||
// elsewhere in your code to send a message to the other renderers message handler
|
||||
window.electronMessagePort.postmessage('ping')
|
||||
window.electronMessagePort.postMessage('ping')
|
||||
```
|
||||
|
||||
### Worker process
|
||||
|
||||
@@ -202,7 +202,7 @@ Then, set up your `handle` listener in the main process. We do this _before_
|
||||
loading the HTML file so that the handler is guaranteed to be ready before
|
||||
you send out the `invoke` call from the renderer.
|
||||
|
||||
```js {1,12} title="main.js"
|
||||
```js {1,15} title="main.js"
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
@@ -214,10 +214,12 @@ const createWindow = () => {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
ipcMain.handle('ping', () => 'pong')
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
app.whenReady().then(createWindow)
|
||||
app.whenReady().then(() => {
|
||||
ipcMain.handle('ping', () => 'pong')
|
||||
createWindow()
|
||||
})
|
||||
```
|
||||
|
||||
Once you have the sender and receiver set up, you can now send messages from the renderer
|
||||
|
||||
@@ -115,7 +115,7 @@ const win = new BrowserWindow({
|
||||
})
|
||||
```
|
||||
|
||||
On either platform `titleBarOverlay` can also be an object. On both macOS and Windows, the height of the overlay can be specified with the `height` property. On Windows, the color of the overlay and its symbols can be specified using the `color` and `symbolColor` properties respectively.
|
||||
On either platform `titleBarOverlay` can also be an object. On both macOS and Windows, the height of the overlay can be specified with the `height` property. On Windows, the color of the overlay and its symbols can be specified using the `color` and `symbolColor` properties respectively. `rgba()`, `hsla()`, and `#RRGGBBAA` color formats are supported to apply transparency.
|
||||
|
||||
If a color option is not specified, the color will default to its system color for the window control buttons. Similarly, if the height option is not specified it will default to the default height:
|
||||
|
||||
@@ -136,10 +136,6 @@ const win = new BrowserWindow({
|
||||
> 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].
|
||||
|
||||
### Limitations
|
||||
|
||||
* Transparent colors are currently not supported. Progress updates for this feature can be found in PR [#33567](https://github.com/electron/electron/issues/33567).
|
||||
|
||||
## Create transparent windows
|
||||
|
||||
By setting the `transparent` option to `true`, you can make a fully transparent window.
|
||||
|
||||
@@ -78,7 +78,6 @@ auto_filenames = {
|
||||
"docs/api/structures/custom-scheme.md",
|
||||
"docs/api/structures/desktop-capturer-source.md",
|
||||
"docs/api/structures/display.md",
|
||||
"docs/api/structures/event.md",
|
||||
"docs/api/structures/extension-info.md",
|
||||
"docs/api/structures/extension.md",
|
||||
"docs/api/structures/file-filter.md",
|
||||
@@ -115,6 +114,7 @@ auto_filenames = {
|
||||
"docs/api/structures/protocol-response.md",
|
||||
"docs/api/structures/rectangle.md",
|
||||
"docs/api/structures/referrer.md",
|
||||
"docs/api/structures/render-process-gone-details.md",
|
||||
"docs/api/structures/resolved-endpoint.md",
|
||||
"docs/api/structures/resolved-host.md",
|
||||
"docs/api/structures/scrubber-item.md",
|
||||
@@ -210,6 +210,8 @@ auto_filenames = {
|
||||
"lib/browser/api/message-channel.ts",
|
||||
"lib/browser/api/module-list.ts",
|
||||
"lib/browser/api/native-theme.ts",
|
||||
"lib/browser/api/net-client-request.ts",
|
||||
"lib/browser/api/net-fetch.ts",
|
||||
"lib/browser/api/net-log.ts",
|
||||
"lib/browser/api/net.ts",
|
||||
"lib/browser/api/notification.ts",
|
||||
|
||||
@@ -265,7 +265,6 @@ filenames = {
|
||||
"shell/browser/api/electron_api_dialog.cc",
|
||||
"shell/browser/api/electron_api_download_item.cc",
|
||||
"shell/browser/api/electron_api_download_item.h",
|
||||
"shell/browser/api/electron_api_event.cc",
|
||||
"shell/browser/api/electron_api_event_emitter.cc",
|
||||
"shell/browser/api/electron_api_event_emitter.h",
|
||||
"shell/browser/api/electron_api_global_shortcut.cc",
|
||||
@@ -318,8 +317,6 @@ filenames = {
|
||||
"shell/browser/api/electron_api_web_request.cc",
|
||||
"shell/browser/api/electron_api_web_request.h",
|
||||
"shell/browser/api/electron_api_web_view_manager.cc",
|
||||
"shell/browser/api/event.cc",
|
||||
"shell/browser/api/event.h",
|
||||
"shell/browser/api/frame_subscriber.cc",
|
||||
"shell/browser/api/frame_subscriber.h",
|
||||
"shell/browser/api/gpu_info_enumerator.cc",
|
||||
@@ -380,7 +377,6 @@ filenames = {
|
||||
"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",
|
||||
"shell/browser/event_emitter_mixin.h",
|
||||
"shell/browser/extended_web_contents_observer.h",
|
||||
"shell/browser/feature_list.cc",
|
||||
@@ -586,6 +582,7 @@ filenames = {
|
||||
"shell/common/gin_converters/native_window_converter.h",
|
||||
"shell/common/gin_converters/net_converter.cc",
|
||||
"shell/common/gin_converters/net_converter.h",
|
||||
"shell/common/gin_converters/optional_converter.h",
|
||||
"shell/common/gin_converters/serial_port_info_converter.h",
|
||||
"shell/common/gin_converters/std_converter.h",
|
||||
"shell/common/gin_converters/time_converter.cc",
|
||||
@@ -606,10 +603,13 @@ filenames = {
|
||||
"shell/common/gin_helper/dictionary.h",
|
||||
"shell/common/gin_helper/error_thrower.cc",
|
||||
"shell/common/gin_helper/error_thrower.h",
|
||||
"shell/common/gin_helper/event_emitter.cc",
|
||||
"shell/common/gin_helper/event.cc",
|
||||
"shell/common/gin_helper/event.h",
|
||||
"shell/common/gin_helper/event_emitter.h",
|
||||
"shell/common/gin_helper/event_emitter_caller.cc",
|
||||
"shell/common/gin_helper/event_emitter_caller.h",
|
||||
"shell/common/gin_helper/event_emitter_template.cc",
|
||||
"shell/common/gin_helper/event_emitter_template.h",
|
||||
"shell/common/gin_helper/function_template.cc",
|
||||
"shell/common/gin_helper/function_template.h",
|
||||
"shell/common/gin_helper/function_template_extensions.h",
|
||||
|
||||
@@ -226,10 +226,15 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/__bsd_locale_defaults.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__bsd_locale_fallbacks.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/chars_format.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/from_chars_integral.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/from_chars_result.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/tables.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars_base_10.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars_floating_point.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars_integral.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars_result.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__charconv/traits.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__chrono/calendar.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__chrono/concepts.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__chrono/convert_to_timespec.h",
|
||||
@@ -290,6 +295,7 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/__concepts/semiregular.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__concepts/swappable.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__concepts/totally_ordered.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__condition_variable/condition_variable.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__config",
|
||||
"//buildtools/third_party/libc++/trunk/include/__config_site.in",
|
||||
"//buildtools/third_party/libc++/trunk/include/__coroutine/coroutine_handle.h",
|
||||
@@ -298,7 +304,11 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/__coroutine/trivial_awaitables.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__debug",
|
||||
"//buildtools/third_party/libc++/trunk/include/__debug_utils/randomize_range.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__errc",
|
||||
"//buildtools/third_party/libc++/trunk/include/__exception/exception.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__exception/exception_ptr.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__exception/nested_exception.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__exception/operations.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__exception/terminate.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__expected/bad_expected_access.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__expected/expected.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__expected/unexpect.h",
|
||||
@@ -466,7 +476,10 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/__memory_resource/pool_options.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__memory_resource/synchronized_pool_resource.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__memory_resource/unsynchronized_pool_resource.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__mutex_base",
|
||||
"//buildtools/third_party/libc++/trunk/include/__mutex/lock_guard.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__mutex/mutex.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__mutex/tag_types.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__mutex/unique_lock.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__node_handle",
|
||||
"//buildtools/third_party/libc++/trunk/include/__numeric/accumulate.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__numeric/adjacent_difference.h",
|
||||
@@ -557,7 +570,6 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/__ranges/views.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__ranges/zip_view.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__split_buffer",
|
||||
"//buildtools/third_party/libc++/trunk/include/__std_stream",
|
||||
"//buildtools/third_party/libc++/trunk/include/__string/char_traits.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__string/constexpr_c_functions.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__string/extern_template_lists.h",
|
||||
@@ -577,20 +589,25 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/__support/xlocale/__nop_locale_mgmt.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__support/xlocale/__posix_l_fallback.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__support/xlocale/__strtonum_fallback.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__system_error/errc.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__system_error/error_category.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__system_error/error_code.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__system_error/error_condition.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__system_error/system_error.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__thread/poll_with_backoff.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__thread/timed_backoff_policy.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__threading_support",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tree",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/apply_cv.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/make_tuple_types.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/pair_like.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/sfinae_helpers.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/tuple_element.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/tuple_indices.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/tuple_like.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/tuple_like_ext.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/tuple_size.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple_dir/tuple_types.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/apply_cv.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/make_tuple_types.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/pair_like.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/sfinae_helpers.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/tuple_element.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/tuple_indices.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/tuple_like.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/tuple_like_ext.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/tuple_size.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__tuple/tuple_types.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_const.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_cv.h",
|
||||
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_lvalue_reference.h",
|
||||
@@ -794,10 +811,8 @@ libcxx_headers = [
|
||||
"//buildtools/third_party/libc++/trunk/include/expected",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/__config",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/__memory",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/algorithm",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/deque",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/forward_list",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/functional",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/iterator",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/list",
|
||||
"//buildtools/third_party/libc++/trunk/include/experimental/map",
|
||||
|
||||
@@ -27,7 +27,7 @@ const cachedArchives = new Map<string, NodeJS.AsarArchive>();
|
||||
const getOrCreateArchive = (archivePath: string) => {
|
||||
const isCached = cachedArchives.has(archivePath);
|
||||
if (isCached) {
|
||||
return cachedArchives.get(archivePath);
|
||||
return cachedArchives.get(archivePath)!;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -39,6 +39,8 @@ const getOrCreateArchive = (archivePath: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
process._getOrCreateArchive = getOrCreateArchive;
|
||||
|
||||
const asarRe = /\.asar/i;
|
||||
|
||||
// Separate asar package's path from full path.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import type { BaseWindow as TLWT } from 'electron/main';
|
||||
import * as deprecate from '@electron/internal/common/deprecate';
|
||||
const { BaseWindow } = process._linkedBinding('electron_browser_base_window') as { BaseWindow: typeof TLWT };
|
||||
|
||||
Object.setPrototypeOf(BaseWindow.prototype, EventEmitter.prototype);
|
||||
@@ -15,6 +16,25 @@ BaseWindow.prototype._init = function () {
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecation.
|
||||
const setTrafficLightPositionDeprecated = deprecate.warnOnce('setTrafficLightPosition', 'setWindowButtonPosition');
|
||||
// Converting to any as the methods are defined under BrowserWindow in our docs.
|
||||
(BaseWindow as any).prototype.setTrafficLightPosition = function (pos: Electron.Point) {
|
||||
setTrafficLightPositionDeprecated();
|
||||
if (typeof pos === 'object' && pos.x === 0 && pos.y === 0) {
|
||||
this.setWindowButtonPosition(null);
|
||||
} else {
|
||||
this.setWindowButtonPosition(pos);
|
||||
}
|
||||
};
|
||||
|
||||
const getTrafficLightPositionDeprecated = deprecate.warnOnce('getTrafficLightPosition', 'getWindowButtonPosition');
|
||||
(BaseWindow as any).prototype.getTrafficLightPosition = function () {
|
||||
getTrafficLightPositionDeprecated();
|
||||
const pos = this.getWindowButtonPosition();
|
||||
return pos === null ? { x: 0, y: 0 } : pos;
|
||||
};
|
||||
|
||||
// Properties
|
||||
|
||||
Object.defineProperty(BaseWindow.prototype, 'autoHideMenuBar', {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseWindow, WebContents, Event, BrowserView, TouchBar } from 'electron/main';
|
||||
import { BaseWindow, WebContents, BrowserView, TouchBar } from 'electron/main';
|
||||
import type { BrowserWindow as BWT } from 'electron/main';
|
||||
import * as deprecate from '@electron/internal/common/deprecate';
|
||||
const { BrowserWindow } = process._linkedBinding('electron_browser_window') as { BrowserWindow: typeof BWT };
|
||||
@@ -30,10 +30,10 @@ BrowserWindow.prototype._init = function (this: BWT) {
|
||||
};
|
||||
|
||||
// Redirect focus/blur event to app instance too.
|
||||
this.on('blur', (event: Event) => {
|
||||
this.on('blur', (event: Electron.Event) => {
|
||||
app.emit('browser-window-blur', event, this);
|
||||
});
|
||||
this.on('focus', (event: Event) => {
|
||||
this.on('focus', (event: Electron.Event) => {
|
||||
app.emit('browser-window-focus', event, this);
|
||||
});
|
||||
|
||||
@@ -76,8 +76,7 @@ BrowserWindow.prototype._init = function (this: BWT) {
|
||||
});
|
||||
|
||||
// Notify the creation of the window.
|
||||
const event = process._linkedBinding('electron_browser_event').createEmpty();
|
||||
app.emit('browser-window-created', event, this);
|
||||
app.emit('browser-window-created', { preventDefault () {} }, this);
|
||||
|
||||
Object.defineProperty(this, 'devToolsWebContents', {
|
||||
enumerable: true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as roles from '@electron/internal/browser/api/menu-item-roles';
|
||||
import { Menu, Event, BrowserWindow, WebContents } from 'electron/main';
|
||||
import { Menu, BrowserWindow, WebContents, KeyboardEvent } from 'electron/main';
|
||||
|
||||
let nextCommandId = 0;
|
||||
|
||||
@@ -53,7 +53,7 @@ const MenuItem = function (this: any, options: any) {
|
||||
});
|
||||
|
||||
const click = options.click;
|
||||
this.click = (event: Event, focusedWindow: BrowserWindow, focusedWebContents: WebContents) => {
|
||||
this.click = (event: KeyboardEvent, focusedWindow: BrowserWindow, focusedWebContents: WebContents) => {
|
||||
// Manually flip the checked flags when clicked.
|
||||
if (!roles.shouldOverrideCheckStatus(this.role) &&
|
||||
(this.type === 'checkbox' || this.type === 'radio')) {
|
||||
|
||||
537
lib/browser/api/net-client-request.ts
Normal file
537
lib/browser/api/net-client-request.ts
Normal file
@@ -0,0 +1,537 @@
|
||||
import * as url from 'url';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import { app } from 'electron/main';
|
||||
import type { ClientRequestConstructorOptions, UploadProgress } from 'electron/main';
|
||||
|
||||
const {
|
||||
isValidHeaderName,
|
||||
isValidHeaderValue,
|
||||
createURLLoader
|
||||
} = process._linkedBinding('electron_browser_net');
|
||||
const { Session } = process._linkedBinding('electron_browser_session');
|
||||
|
||||
const kHttpProtocols = new Set(['http:', 'https:']);
|
||||
|
||||
// set of headers that Node.js discards duplicates for
|
||||
// see https://nodejs.org/api/http.html#http_message_headers
|
||||
const discardableDuplicateHeaders = new Set([
|
||||
'content-type',
|
||||
'content-length',
|
||||
'user-agent',
|
||||
'referer',
|
||||
'host',
|
||||
'authorization',
|
||||
'proxy-authorization',
|
||||
'if-modified-since',
|
||||
'if-unmodified-since',
|
||||
'from',
|
||||
'location',
|
||||
'max-forwards',
|
||||
'retry-after',
|
||||
'etag',
|
||||
'last-modified',
|
||||
'server',
|
||||
'age',
|
||||
'expires'
|
||||
]);
|
||||
|
||||
class IncomingMessage extends Readable {
|
||||
_shouldPush: boolean = false;
|
||||
_data: (Buffer | null)[] = [];
|
||||
_responseHead: NodeJS.ResponseHead;
|
||||
_resume: (() => void) | null = null;
|
||||
|
||||
constructor (responseHead: NodeJS.ResponseHead) {
|
||||
super();
|
||||
this._responseHead = responseHead;
|
||||
}
|
||||
|
||||
get statusCode () {
|
||||
return this._responseHead.statusCode;
|
||||
}
|
||||
|
||||
get statusMessage () {
|
||||
return this._responseHead.statusMessage;
|
||||
}
|
||||
|
||||
get headers () {
|
||||
const filteredHeaders: Record<string, string | string[]> = {};
|
||||
const { headers, rawHeaders } = this._responseHead;
|
||||
for (const [name, values] of Object.entries(headers)) {
|
||||
filteredHeaders[name] = discardableDuplicateHeaders.has(name) ? values[0] : values.join(', ');
|
||||
}
|
||||
const cookies = rawHeaders.filter(({ key }) => key.toLowerCase() === 'set-cookie').map(({ value }) => value);
|
||||
// keep set-cookie as an array per Node.js rules
|
||||
// see https://nodejs.org/api/http.html#http_message_headers
|
||||
if (cookies.length) { filteredHeaders['set-cookie'] = cookies; }
|
||||
return filteredHeaders;
|
||||
}
|
||||
|
||||
get rawHeaders () {
|
||||
const rawHeadersArr: string[] = [];
|
||||
const { rawHeaders } = this._responseHead;
|
||||
rawHeaders.forEach(header => {
|
||||
rawHeadersArr.push(header.key, header.value);
|
||||
});
|
||||
return rawHeadersArr;
|
||||
}
|
||||
|
||||
get httpVersion () {
|
||||
return `${this.httpVersionMajor}.${this.httpVersionMinor}`;
|
||||
}
|
||||
|
||||
get httpVersionMajor () {
|
||||
return this._responseHead.httpVersion.major;
|
||||
}
|
||||
|
||||
get httpVersionMinor () {
|
||||
return this._responseHead.httpVersion.minor;
|
||||
}
|
||||
|
||||
get rawTrailers () {
|
||||
throw new Error('HTTP trailers are not supported');
|
||||
}
|
||||
|
||||
get trailers () {
|
||||
throw new Error('HTTP trailers are not supported');
|
||||
}
|
||||
|
||||
_storeInternalData (chunk: Buffer | null, resume: (() => void) | null) {
|
||||
// save the network callback for use in _pushInternalData
|
||||
this._resume = resume;
|
||||
this._data.push(chunk);
|
||||
this._pushInternalData();
|
||||
}
|
||||
|
||||
_pushInternalData () {
|
||||
while (this._shouldPush && this._data.length > 0) {
|
||||
const chunk = this._data.shift();
|
||||
this._shouldPush = this.push(chunk);
|
||||
}
|
||||
if (this._shouldPush && this._resume) {
|
||||
// Reset the callback, so that a new one is used for each
|
||||
// batch of throttled data. Do this before calling resume to avoid a
|
||||
// potential race-condition
|
||||
const resume = this._resume;
|
||||
this._resume = null;
|
||||
|
||||
resume();
|
||||
}
|
||||
}
|
||||
|
||||
_read () {
|
||||
this._shouldPush = true;
|
||||
this._pushInternalData();
|
||||
}
|
||||
}
|
||||
|
||||
/** Writable stream that buffers up everything written to it. */
|
||||
class SlurpStream extends Writable {
|
||||
_data: Buffer;
|
||||
constructor () {
|
||||
super();
|
||||
this._data = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, encoding: string, callback: () => void) {
|
||||
this._data = Buffer.concat([this._data, chunk]);
|
||||
callback();
|
||||
}
|
||||
|
||||
data () { return this._data; }
|
||||
}
|
||||
|
||||
class ChunkedBodyStream extends Writable {
|
||||
_pendingChunk: Buffer | undefined;
|
||||
_downstream?: NodeJS.DataPipe;
|
||||
_pendingCallback?: (error?: Error) => void;
|
||||
_clientRequest: ClientRequest;
|
||||
|
||||
constructor (clientRequest: ClientRequest) {
|
||||
super();
|
||||
this._clientRequest = clientRequest;
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, encoding: string, callback: () => void) {
|
||||
if (this._downstream) {
|
||||
this._downstream.write(chunk).then(callback, callback);
|
||||
} else {
|
||||
// the contract of _write is that we won't be called again until we call
|
||||
// the callback, so we're good to just save a single chunk.
|
||||
this._pendingChunk = chunk;
|
||||
this._pendingCallback = callback;
|
||||
|
||||
// The first write to a chunked body stream begins the request.
|
||||
this._clientRequest._startRequest();
|
||||
}
|
||||
}
|
||||
|
||||
_final (callback: () => void) {
|
||||
this._downstream!.done();
|
||||
callback();
|
||||
}
|
||||
|
||||
startReading (pipe: NodeJS.DataPipe) {
|
||||
if (this._downstream) {
|
||||
throw new Error('two startReading calls???');
|
||||
}
|
||||
this._downstream = pipe;
|
||||
if (this._pendingChunk) {
|
||||
const doneWriting = (maybeError: Error | void) => {
|
||||
// If the underlying request has been aborted, we honestly don't care about the error
|
||||
// all work should cease as soon as we abort anyway, this error is probably a
|
||||
// "mojo pipe disconnected" error (code=9)
|
||||
if (this._clientRequest._aborted) return;
|
||||
|
||||
const cb = this._pendingCallback!;
|
||||
delete this._pendingCallback;
|
||||
delete this._pendingChunk;
|
||||
cb(maybeError || undefined);
|
||||
};
|
||||
this._downstream.write(this._pendingChunk).then(doneWriting, doneWriting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type RedirectPolicy = 'manual' | 'follow' | 'error';
|
||||
|
||||
const kAllowNonHttpProtocols = Symbol('kAllowNonHttpProtocols');
|
||||
export function allowAnyProtocol (opts: ClientRequestConstructorOptions): ClientRequestConstructorOptions {
|
||||
return {
|
||||
...opts,
|
||||
[kAllowNonHttpProtocols]: true
|
||||
} as any;
|
||||
}
|
||||
|
||||
type ExtraURLLoaderOptions = {
|
||||
redirectPolicy: RedirectPolicy;
|
||||
headers: Record<string, { name: string, value: string | string[] }>;
|
||||
allowNonHttpProtocols: boolean;
|
||||
}
|
||||
function parseOptions (optionsIn: ClientRequestConstructorOptions | string): NodeJS.CreateURLLoaderOptions & ExtraURLLoaderOptions {
|
||||
const options: any = typeof optionsIn === 'string' ? url.parse(optionsIn) : { ...optionsIn };
|
||||
|
||||
let urlStr: string = options.url;
|
||||
|
||||
if (!urlStr) {
|
||||
const urlObj: url.UrlObject = {};
|
||||
const protocol = options.protocol || 'http:';
|
||||
urlObj.protocol = protocol;
|
||||
|
||||
if (options.host) {
|
||||
urlObj.host = options.host;
|
||||
} else {
|
||||
if (options.hostname) {
|
||||
urlObj.hostname = options.hostname;
|
||||
} else {
|
||||
urlObj.hostname = 'localhost';
|
||||
}
|
||||
|
||||
if (options.port) {
|
||||
urlObj.port = options.port;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.path && / /.test(options.path)) {
|
||||
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
||||
// with an additional rule for ignoring percentage-escaped characters
|
||||
// but that's a) hard to capture in a regular expression that performs
|
||||
// well, and b) possibly too restrictive for real-world usage. That's
|
||||
// why it only scans for spaces because those are guaranteed to create
|
||||
// an invalid request.
|
||||
throw new TypeError('Request path contains unescaped characters');
|
||||
}
|
||||
const pathObj = url.parse(options.path || '/');
|
||||
urlObj.pathname = pathObj.pathname;
|
||||
urlObj.search = pathObj.search;
|
||||
urlObj.hash = pathObj.hash;
|
||||
urlStr = url.format(urlObj);
|
||||
}
|
||||
|
||||
const redirectPolicy = options.redirect || 'follow';
|
||||
if (!['follow', 'error', 'manual'].includes(redirectPolicy)) {
|
||||
throw new Error('redirect mode should be one of follow, error or manual');
|
||||
}
|
||||
|
||||
if (options.headers != null && typeof options.headers !== 'object') {
|
||||
throw new TypeError('headers must be an object');
|
||||
}
|
||||
|
||||
const urlLoaderOptions: NodeJS.CreateURLLoaderOptions & { redirectPolicy: RedirectPolicy, headers: Record<string, { name: string, value: string | string[] }>, allowNonHttpProtocols: boolean } = {
|
||||
method: (options.method || 'GET').toUpperCase(),
|
||||
url: urlStr,
|
||||
redirectPolicy,
|
||||
headers: {},
|
||||
body: null as any,
|
||||
useSessionCookies: options.useSessionCookies,
|
||||
credentials: options.credentials,
|
||||
origin: options.origin,
|
||||
referrerPolicy: options.referrerPolicy,
|
||||
cache: options.cache,
|
||||
allowNonHttpProtocols: Object.prototype.hasOwnProperty.call(options, kAllowNonHttpProtocols)
|
||||
};
|
||||
const headers: Record<string, string | string[]> = options.headers || {};
|
||||
for (const [name, value] of Object.entries(headers)) {
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
const key = name.toLowerCase();
|
||||
urlLoaderOptions.headers[key] = { name, value };
|
||||
}
|
||||
if (options.session) {
|
||||
if (!(options.session instanceof Session)) { throw new TypeError('`session` should be an instance of the Session class'); }
|
||||
urlLoaderOptions.session = options.session;
|
||||
} else if (options.partition) {
|
||||
if (typeof options.partition === 'string') {
|
||||
urlLoaderOptions.partition = options.partition;
|
||||
} else {
|
||||
throw new TypeError('`partition` should be a string');
|
||||
}
|
||||
}
|
||||
return urlLoaderOptions;
|
||||
}
|
||||
|
||||
export class ClientRequest extends Writable implements Electron.ClientRequest {
|
||||
_started: boolean = false;
|
||||
_firstWrite: boolean = false;
|
||||
_aborted: boolean = false;
|
||||
_chunkedEncoding: boolean | undefined;
|
||||
_body: Writable | undefined;
|
||||
_urlLoaderOptions: NodeJS.CreateURLLoaderOptions & { headers: Record<string, { name: string, value: string | string[] }> };
|
||||
_redirectPolicy: RedirectPolicy;
|
||||
_followRedirectCb?: () => void;
|
||||
_uploadProgress?: { active: boolean, started: boolean, current: number, total: number };
|
||||
_urlLoader?: NodeJS.URLLoader;
|
||||
_response?: IncomingMessage;
|
||||
|
||||
constructor (options: ClientRequestConstructorOptions | string, callback?: (message: IncomingMessage) => void) {
|
||||
super({ autoDestroy: true });
|
||||
|
||||
if (!app.isReady()) {
|
||||
throw new Error('net module can only be used after app is ready');
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
this.once('response', callback);
|
||||
}
|
||||
|
||||
const { redirectPolicy, ...urlLoaderOptions } = parseOptions(options);
|
||||
const urlObj = new URL(urlLoaderOptions.url);
|
||||
if (!urlLoaderOptions.allowNonHttpProtocols && !kHttpProtocols.has(urlObj.protocol)) {
|
||||
throw new Error('ClientRequest only supports http: and https: protocols');
|
||||
}
|
||||
if (urlLoaderOptions.credentials === 'same-origin' && !urlLoaderOptions.origin) { throw new Error('credentials: same-origin requires origin to be set'); }
|
||||
this._urlLoaderOptions = urlLoaderOptions;
|
||||
this._redirectPolicy = redirectPolicy;
|
||||
}
|
||||
|
||||
get chunkedEncoding () {
|
||||
return this._chunkedEncoding || false;
|
||||
}
|
||||
|
||||
set chunkedEncoding (value: boolean) {
|
||||
if (this._started) {
|
||||
throw new Error('chunkedEncoding can only be set before the request is started');
|
||||
}
|
||||
if (typeof this._chunkedEncoding !== 'undefined') {
|
||||
throw new Error('chunkedEncoding can only be set once');
|
||||
}
|
||||
this._chunkedEncoding = !!value;
|
||||
if (this._chunkedEncoding) {
|
||||
this._body = new ChunkedBodyStream(this);
|
||||
this._urlLoaderOptions.body = (pipe: NodeJS.DataPipe) => {
|
||||
(this._body! as ChunkedBodyStream).startReading(pipe);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setHeader (name: string, value: string) {
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('`name` should be a string in setHeader(name, value)');
|
||||
}
|
||||
if (value == null) {
|
||||
throw new Error('`value` required in setHeader("' + name + '", value)');
|
||||
}
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t set headers after they are sent');
|
||||
}
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
this._urlLoaderOptions.headers[key] = { name, value };
|
||||
}
|
||||
|
||||
getHeader (name: string) {
|
||||
if (name == null) {
|
||||
throw new Error('`name` is required for getHeader(name)');
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
const header = this._urlLoaderOptions.headers[key];
|
||||
return header && header.value as any;
|
||||
}
|
||||
|
||||
removeHeader (name: string) {
|
||||
if (name == null) {
|
||||
throw new Error('`name` is required for removeHeader(name)');
|
||||
}
|
||||
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t remove headers after they are sent');
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
delete this._urlLoaderOptions.headers[key];
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, encoding: BufferEncoding, callback: () => void) {
|
||||
this._firstWrite = true;
|
||||
if (!this._body) {
|
||||
this._body = new SlurpStream();
|
||||
this._body.on('finish', () => {
|
||||
this._urlLoaderOptions.body = (this._body as SlurpStream).data();
|
||||
this._startRequest();
|
||||
});
|
||||
}
|
||||
// TODO: is this the right way to forward to another stream?
|
||||
this._body.write(chunk, encoding, callback);
|
||||
}
|
||||
|
||||
_final (callback: () => void) {
|
||||
if (this._body) {
|
||||
// TODO: is this the right way to forward to another stream?
|
||||
this._body.end(callback);
|
||||
} else {
|
||||
// end() called without a body, go ahead and start the request
|
||||
this._startRequest();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
_startRequest () {
|
||||
this._started = true;
|
||||
const stringifyValues = (obj: Record<string, { name: string, value: string | string[] }>) => {
|
||||
const ret: Record<string, string> = {};
|
||||
for (const k of Object.keys(obj)) {
|
||||
const kv = obj[k];
|
||||
ret[kv.name] = kv.value.toString();
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
this._urlLoaderOptions.referrer = this.getHeader('referer') || '';
|
||||
this._urlLoaderOptions.origin = this._urlLoaderOptions.origin || this.getHeader('origin') || '';
|
||||
this._urlLoaderOptions.hasUserActivation = this.getHeader('sec-fetch-user') === '?1';
|
||||
this._urlLoaderOptions.mode = this.getHeader('sec-fetch-mode') || '';
|
||||
this._urlLoaderOptions.destination = this.getHeader('sec-fetch-dest') || '';
|
||||
const opts = { ...this._urlLoaderOptions, extraHeaders: stringifyValues(this._urlLoaderOptions.headers) };
|
||||
this._urlLoader = createURLLoader(opts);
|
||||
this._urlLoader.on('response-started', (event, finalUrl, responseHead) => {
|
||||
const response = this._response = new IncomingMessage(responseHead);
|
||||
this.emit('response', response);
|
||||
});
|
||||
this._urlLoader.on('data', (event, data, resume) => {
|
||||
this._response!._storeInternalData(Buffer.from(data), resume);
|
||||
});
|
||||
this._urlLoader.on('complete', () => {
|
||||
if (this._response) { this._response._storeInternalData(null, null); }
|
||||
});
|
||||
this._urlLoader.on('error', (event, netErrorString) => {
|
||||
const error = new Error(netErrorString);
|
||||
if (this._response) this._response.destroy(error);
|
||||
this._die(error);
|
||||
});
|
||||
|
||||
this._urlLoader.on('login', (event, authInfo, callback) => {
|
||||
const handled = this.emit('login', authInfo, callback);
|
||||
if (!handled) {
|
||||
// If there were no listeners, cancel the authentication request.
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
this._urlLoader.on('redirect', (event, redirectInfo, headers) => {
|
||||
const { statusCode, newMethod, newUrl } = redirectInfo;
|
||||
if (this._redirectPolicy === 'error') {
|
||||
this._die(new Error('Attempted to redirect, but redirect policy was \'error\''));
|
||||
} else if (this._redirectPolicy === 'manual') {
|
||||
let _followRedirect = false;
|
||||
this._followRedirectCb = () => { _followRedirect = true; };
|
||||
try {
|
||||
this.emit('redirect', statusCode, newMethod, newUrl, headers);
|
||||
} finally {
|
||||
this._followRedirectCb = undefined;
|
||||
if (!_followRedirect && !this._aborted) {
|
||||
this._die(new Error('Redirect was cancelled'));
|
||||
}
|
||||
}
|
||||
} else if (this._redirectPolicy === 'follow') {
|
||||
// Calling followRedirect() when the redirect policy is 'follow' is
|
||||
// allowed but does nothing. (Perhaps it should throw an error
|
||||
// though...? Since the redirect will happen regardless.)
|
||||
try {
|
||||
this._followRedirectCb = () => {};
|
||||
this.emit('redirect', statusCode, newMethod, newUrl, headers);
|
||||
} finally {
|
||||
this._followRedirectCb = undefined;
|
||||
}
|
||||
} else {
|
||||
this._die(new Error(`Unexpected redirect policy '${this._redirectPolicy}'`));
|
||||
}
|
||||
});
|
||||
|
||||
this._urlLoader.on('upload-progress', (event, position, total) => {
|
||||
this._uploadProgress = { active: true, started: true, current: position, total };
|
||||
this.emit('upload-progress', position, total); // Undocumented, for now
|
||||
});
|
||||
|
||||
this._urlLoader.on('download-progress', (event, current) => {
|
||||
if (this._response) {
|
||||
this._response.emit('download-progress', current); // Undocumented, for now
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
followRedirect () {
|
||||
if (this._followRedirectCb) {
|
||||
this._followRedirectCb();
|
||||
} else {
|
||||
throw new Error('followRedirect() called, but was not waiting for a redirect');
|
||||
}
|
||||
}
|
||||
|
||||
abort () {
|
||||
if (!this._aborted) {
|
||||
process.nextTick(() => { this.emit('abort'); });
|
||||
}
|
||||
this._aborted = true;
|
||||
this._die();
|
||||
}
|
||||
|
||||
_die (err?: Error) {
|
||||
// Node.js assumes that any stream which is ended is no longer capable of emitted events
|
||||
// which is a faulty assumption for the case of an object that is acting like a stream
|
||||
// (our urlRequest). If we don't emit here, this causes errors since we *do* expect
|
||||
// that error events can be emitted after urlRequest.end().
|
||||
if ((this as any)._writableState.destroyed && err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
this.destroy(err);
|
||||
if (this._urlLoader) {
|
||||
this._urlLoader.cancel();
|
||||
if (this._response) this._response.destroy(err);
|
||||
}
|
||||
}
|
||||
|
||||
getUploadProgress (): UploadProgress {
|
||||
return this._uploadProgress ? { ...this._uploadProgress } : { active: false, started: false, current: 0, total: 0 };
|
||||
}
|
||||
}
|
||||
120
lib/browser/api/net-fetch.ts
Normal file
120
lib/browser/api/net-fetch.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { net, IncomingMessage, Session as SessionT } from 'electron/main';
|
||||
import { Readable, Writable, isReadable } from 'stream';
|
||||
import { allowAnyProtocol } from '@electron/internal/browser/api/net-client-request';
|
||||
|
||||
function createDeferredPromise<T, E extends Error = Error> (): { promise: Promise<T>; resolve: (x: T) => void; reject: (e: E) => void; } {
|
||||
let res: (x: T) => void;
|
||||
let rej: (e: E) => void;
|
||||
const promise = new Promise<T>((resolve, reject) => {
|
||||
res = resolve;
|
||||
rej = reject;
|
||||
});
|
||||
|
||||
return { promise, resolve: res!, reject: rej! };
|
||||
}
|
||||
|
||||
export function fetchWithSession (input: RequestInfo, init: (RequestInit & {bypassCustomProtocolHandlers?: boolean}) | undefined, session: SessionT): Promise<Response> {
|
||||
const p = createDeferredPromise<Response>();
|
||||
let req: Request;
|
||||
try {
|
||||
req = new Request(input, init);
|
||||
} catch (e: any) {
|
||||
p.reject(e);
|
||||
return p.promise;
|
||||
}
|
||||
|
||||
if (req.signal.aborted) {
|
||||
// 1. Abort the fetch() call with p, request, null, and
|
||||
// requestObject’s signal’s abort reason.
|
||||
const error = (req.signal as any).reason ?? new DOMException('The operation was aborted.', 'AbortError');
|
||||
p.reject(error);
|
||||
|
||||
if (req.body != null && isReadable(req.body as unknown as NodeJS.ReadableStream)) {
|
||||
req.body.cancel(error).catch((err) => {
|
||||
if (err.code === 'ERR_INVALID_STATE') {
|
||||
// Node bug?
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Return p.
|
||||
return p.promise;
|
||||
}
|
||||
|
||||
let locallyAborted = false;
|
||||
req.signal.addEventListener(
|
||||
'abort',
|
||||
() => {
|
||||
// 1. Set locallyAborted to true.
|
||||
locallyAborted = true;
|
||||
|
||||
// 2. Abort the fetch() call with p, request, responseObject,
|
||||
// and requestObject’s signal’s abort reason.
|
||||
const error = (req.signal as any).reason ?? new DOMException('The operation was aborted.', 'AbortError');
|
||||
p.reject(error);
|
||||
if (req.body != null && isReadable(req.body as unknown as NodeJS.ReadableStream)) {
|
||||
req.body.cancel(error).catch((err) => {
|
||||
if (err.code === 'ERR_INVALID_STATE') {
|
||||
// Node bug?
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
r.abort();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
const origin = req.headers.get('origin') ?? undefined;
|
||||
// We can't set credentials to same-origin unless there's an origin set.
|
||||
const credentials = req.credentials === 'same-origin' && !origin ? 'include' : req.credentials;
|
||||
|
||||
const r = net.request(allowAnyProtocol({
|
||||
session,
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
origin,
|
||||
credentials,
|
||||
cache: req.cache,
|
||||
referrerPolicy: req.referrerPolicy,
|
||||
redirect: req.redirect
|
||||
}));
|
||||
|
||||
(r as any)._urlLoaderOptions.bypassCustomProtocolHandlers = !!init?.bypassCustomProtocolHandlers;
|
||||
|
||||
// cors is the default mode, but we can't set mode=cors without an origin.
|
||||
if (req.mode && (req.mode !== 'cors' || origin)) {
|
||||
r.setHeader('Sec-Fetch-Mode', req.mode);
|
||||
}
|
||||
|
||||
for (const [k, v] of req.headers) {
|
||||
r.setHeader(k, v);
|
||||
}
|
||||
|
||||
r.on('response', (resp: IncomingMessage) => {
|
||||
if (locallyAborted) return;
|
||||
const headers = new Headers();
|
||||
for (const [k, v] of Object.entries(resp.headers)) { headers.set(k, Array.isArray(v) ? v.join(', ') : v); }
|
||||
const nullBodyStatus = [101, 204, 205, 304];
|
||||
const body = nullBodyStatus.includes(resp.statusCode) || req.method === 'HEAD' ? null : Readable.toWeb(resp as unknown as Readable) as ReadableStream;
|
||||
const rResp = new Response(body, {
|
||||
headers,
|
||||
status: resp.statusCode,
|
||||
statusText: resp.statusMessage
|
||||
});
|
||||
(rResp as any).__original_resp = resp;
|
||||
p.resolve(rResp);
|
||||
});
|
||||
|
||||
r.on('error', (err) => {
|
||||
p.reject(err);
|
||||
});
|
||||
|
||||
if (!req.body?.pipeTo(Writable.toWeb(r as unknown as Writable)).then(() => r.end())) { r.end(); }
|
||||
|
||||
return p.promise;
|
||||
}
|
||||
@@ -1,531 +1,17 @@
|
||||
import * as url from 'url';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import { app, session } from 'electron/main';
|
||||
import type { ClientRequestConstructorOptions, UploadProgress } from 'electron/main';
|
||||
import { IncomingMessage, session } from 'electron/main';
|
||||
import type { ClientRequestConstructorOptions } from 'electron/main';
|
||||
import { ClientRequest } from '@electron/internal/browser/api/net-client-request';
|
||||
|
||||
const {
|
||||
isOnline,
|
||||
isValidHeaderName,
|
||||
isValidHeaderValue,
|
||||
createURLLoader
|
||||
} = process._linkedBinding('electron_browser_net');
|
||||
|
||||
const kSupportedProtocols = new Set(['http:', 'https:']);
|
||||
|
||||
// set of headers that Node.js discards duplicates for
|
||||
// see https://nodejs.org/api/http.html#http_message_headers
|
||||
const discardableDuplicateHeaders = new Set([
|
||||
'content-type',
|
||||
'content-length',
|
||||
'user-agent',
|
||||
'referer',
|
||||
'host',
|
||||
'authorization',
|
||||
'proxy-authorization',
|
||||
'if-modified-since',
|
||||
'if-unmodified-since',
|
||||
'from',
|
||||
'location',
|
||||
'max-forwards',
|
||||
'retry-after',
|
||||
'etag',
|
||||
'last-modified',
|
||||
'server',
|
||||
'age',
|
||||
'expires'
|
||||
]);
|
||||
|
||||
class IncomingMessage extends Readable {
|
||||
_shouldPush: boolean = false;
|
||||
_data: (Buffer | null)[] = [];
|
||||
_responseHead: NodeJS.ResponseHead;
|
||||
_resume: (() => void) | null = null;
|
||||
|
||||
constructor (responseHead: NodeJS.ResponseHead) {
|
||||
super();
|
||||
this._responseHead = responseHead;
|
||||
}
|
||||
|
||||
get statusCode () {
|
||||
return this._responseHead.statusCode;
|
||||
}
|
||||
|
||||
get statusMessage () {
|
||||
return this._responseHead.statusMessage;
|
||||
}
|
||||
|
||||
get headers () {
|
||||
const filteredHeaders: Record<string, string | string[]> = {};
|
||||
const { headers, rawHeaders } = this._responseHead;
|
||||
for (const [name, values] of Object.entries(headers)) {
|
||||
filteredHeaders[name] = discardableDuplicateHeaders.has(name) ? values[0] : values.join(', ');
|
||||
}
|
||||
const cookies = rawHeaders.filter(({ key }) => key.toLowerCase() === 'set-cookie').map(({ value }) => value);
|
||||
// keep set-cookie as an array per Node.js rules
|
||||
// see https://nodejs.org/api/http.html#http_message_headers
|
||||
if (cookies.length) { filteredHeaders['set-cookie'] = cookies; }
|
||||
return filteredHeaders;
|
||||
}
|
||||
|
||||
get rawHeaders () {
|
||||
const rawHeadersArr: string[] = [];
|
||||
const { rawHeaders } = this._responseHead;
|
||||
rawHeaders.forEach(header => {
|
||||
rawHeadersArr.push(header.key, header.value);
|
||||
});
|
||||
return rawHeadersArr;
|
||||
}
|
||||
|
||||
get httpVersion () {
|
||||
return `${this.httpVersionMajor}.${this.httpVersionMinor}`;
|
||||
}
|
||||
|
||||
get httpVersionMajor () {
|
||||
return this._responseHead.httpVersion.major;
|
||||
}
|
||||
|
||||
get httpVersionMinor () {
|
||||
return this._responseHead.httpVersion.minor;
|
||||
}
|
||||
|
||||
get rawTrailers () {
|
||||
throw new Error('HTTP trailers are not supported');
|
||||
}
|
||||
|
||||
get trailers () {
|
||||
throw new Error('HTTP trailers are not supported');
|
||||
}
|
||||
|
||||
_storeInternalData (chunk: Buffer | null, resume: (() => void) | null) {
|
||||
// save the network callback for use in _pushInternalData
|
||||
this._resume = resume;
|
||||
this._data.push(chunk);
|
||||
this._pushInternalData();
|
||||
}
|
||||
|
||||
_pushInternalData () {
|
||||
while (this._shouldPush && this._data.length > 0) {
|
||||
const chunk = this._data.shift();
|
||||
this._shouldPush = this.push(chunk);
|
||||
}
|
||||
if (this._shouldPush && this._resume) {
|
||||
// Reset the callback, so that a new one is used for each
|
||||
// batch of throttled data. Do this before calling resume to avoid a
|
||||
// potential race-condition
|
||||
const resume = this._resume;
|
||||
this._resume = null;
|
||||
|
||||
resume();
|
||||
}
|
||||
}
|
||||
|
||||
_read () {
|
||||
this._shouldPush = true;
|
||||
this._pushInternalData();
|
||||
}
|
||||
}
|
||||
|
||||
/** Writable stream that buffers up everything written to it. */
|
||||
class SlurpStream extends Writable {
|
||||
_data: Buffer;
|
||||
constructor () {
|
||||
super();
|
||||
this._data = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, encoding: string, callback: () => void) {
|
||||
this._data = Buffer.concat([this._data, chunk]);
|
||||
callback();
|
||||
}
|
||||
|
||||
data () { return this._data; }
|
||||
}
|
||||
|
||||
class ChunkedBodyStream extends Writable {
|
||||
_pendingChunk: Buffer | undefined;
|
||||
_downstream?: NodeJS.DataPipe;
|
||||
_pendingCallback?: (error?: Error) => void;
|
||||
_clientRequest: ClientRequest;
|
||||
|
||||
constructor (clientRequest: ClientRequest) {
|
||||
super();
|
||||
this._clientRequest = clientRequest;
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, encoding: string, callback: () => void) {
|
||||
if (this._downstream) {
|
||||
this._downstream.write(chunk).then(callback, callback);
|
||||
} else {
|
||||
// the contract of _write is that we won't be called again until we call
|
||||
// the callback, so we're good to just save a single chunk.
|
||||
this._pendingChunk = chunk;
|
||||
this._pendingCallback = callback;
|
||||
|
||||
// The first write to a chunked body stream begins the request.
|
||||
this._clientRequest._startRequest();
|
||||
}
|
||||
}
|
||||
|
||||
_final (callback: () => void) {
|
||||
this._downstream!.done();
|
||||
callback();
|
||||
}
|
||||
|
||||
startReading (pipe: NodeJS.DataPipe) {
|
||||
if (this._downstream) {
|
||||
throw new Error('two startReading calls???');
|
||||
}
|
||||
this._downstream = pipe;
|
||||
if (this._pendingChunk) {
|
||||
const doneWriting = (maybeError: Error | void) => {
|
||||
// If the underlying request has been aborted, we honestly don't care about the error
|
||||
// all work should cease as soon as we abort anyway, this error is probably a
|
||||
// "mojo pipe disconnected" error (code=9)
|
||||
if (this._clientRequest._aborted) return;
|
||||
|
||||
const cb = this._pendingCallback!;
|
||||
delete this._pendingCallback;
|
||||
delete this._pendingChunk;
|
||||
cb(maybeError || undefined);
|
||||
};
|
||||
this._downstream.write(this._pendingChunk).then(doneWriting, doneWriting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type RedirectPolicy = 'manual' | 'follow' | 'error';
|
||||
|
||||
function parseOptions (optionsIn: ClientRequestConstructorOptions | string): NodeJS.CreateURLLoaderOptions & { redirectPolicy: RedirectPolicy, headers: Record<string, { name: string, value: string | string[] }> } {
|
||||
const options: any = typeof optionsIn === 'string' ? url.parse(optionsIn) : { ...optionsIn };
|
||||
|
||||
let urlStr: string = options.url;
|
||||
|
||||
if (!urlStr) {
|
||||
const urlObj: url.UrlObject = {};
|
||||
const protocol = options.protocol || 'http:';
|
||||
if (!kSupportedProtocols.has(protocol)) {
|
||||
throw new Error('Protocol "' + protocol + '" not supported');
|
||||
}
|
||||
urlObj.protocol = protocol;
|
||||
|
||||
if (options.host) {
|
||||
urlObj.host = options.host;
|
||||
} else {
|
||||
if (options.hostname) {
|
||||
urlObj.hostname = options.hostname;
|
||||
} else {
|
||||
urlObj.hostname = 'localhost';
|
||||
}
|
||||
|
||||
if (options.port) {
|
||||
urlObj.port = options.port;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.path && / /.test(options.path)) {
|
||||
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
||||
// with an additional rule for ignoring percentage-escaped characters
|
||||
// but that's a) hard to capture in a regular expression that performs
|
||||
// well, and b) possibly too restrictive for real-world usage. That's
|
||||
// why it only scans for spaces because those are guaranteed to create
|
||||
// an invalid request.
|
||||
throw new TypeError('Request path contains unescaped characters');
|
||||
}
|
||||
const pathObj = url.parse(options.path || '/');
|
||||
urlObj.pathname = pathObj.pathname;
|
||||
urlObj.search = pathObj.search;
|
||||
urlObj.hash = pathObj.hash;
|
||||
urlStr = url.format(urlObj);
|
||||
}
|
||||
|
||||
const redirectPolicy = options.redirect || 'follow';
|
||||
if (!['follow', 'error', 'manual'].includes(redirectPolicy)) {
|
||||
throw new Error('redirect mode should be one of follow, error or manual');
|
||||
}
|
||||
|
||||
if (options.headers != null && typeof options.headers !== 'object') {
|
||||
throw new TypeError('headers must be an object');
|
||||
}
|
||||
|
||||
const urlLoaderOptions: NodeJS.CreateURLLoaderOptions & { redirectPolicy: RedirectPolicy, headers: Record<string, { name: string, value: string | string[] }> } = {
|
||||
method: (options.method || 'GET').toUpperCase(),
|
||||
url: urlStr,
|
||||
redirectPolicy,
|
||||
headers: {},
|
||||
body: null as any,
|
||||
useSessionCookies: options.useSessionCookies,
|
||||
credentials: options.credentials,
|
||||
origin: options.origin
|
||||
};
|
||||
const headers: Record<string, string | string[]> = options.headers || {};
|
||||
for (const [name, value] of Object.entries(headers)) {
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
const key = name.toLowerCase();
|
||||
urlLoaderOptions.headers[key] = { name, value };
|
||||
}
|
||||
if (options.session) {
|
||||
// Weak check, but it should be enough to catch 99% of accidental misuses.
|
||||
if (options.session.constructor && options.session.constructor.name === 'Session') {
|
||||
urlLoaderOptions.session = options.session;
|
||||
} else {
|
||||
throw new TypeError('`session` should be an instance of the Session class');
|
||||
}
|
||||
} else if (options.partition) {
|
||||
if (typeof options.partition === 'string') {
|
||||
urlLoaderOptions.partition = options.partition;
|
||||
} else {
|
||||
throw new TypeError('`partition` should be a string');
|
||||
}
|
||||
}
|
||||
return urlLoaderOptions;
|
||||
}
|
||||
|
||||
export class ClientRequest extends Writable implements Electron.ClientRequest {
|
||||
_started: boolean = false;
|
||||
_firstWrite: boolean = false;
|
||||
_aborted: boolean = false;
|
||||
_chunkedEncoding: boolean | undefined;
|
||||
_body: Writable | undefined;
|
||||
_urlLoaderOptions: NodeJS.CreateURLLoaderOptions & { headers: Record<string, { name: string, value: string | string[] }> };
|
||||
_redirectPolicy: RedirectPolicy;
|
||||
_followRedirectCb?: () => void;
|
||||
_uploadProgress?: { active: boolean, started: boolean, current: number, total: number };
|
||||
_urlLoader?: NodeJS.URLLoader;
|
||||
_response?: IncomingMessage;
|
||||
|
||||
constructor (options: ClientRequestConstructorOptions | string, callback?: (message: IncomingMessage) => void) {
|
||||
super({ autoDestroy: true });
|
||||
|
||||
if (!app.isReady()) {
|
||||
throw new Error('net module can only be used after app is ready');
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
this.once('response', callback);
|
||||
}
|
||||
|
||||
const { redirectPolicy, ...urlLoaderOptions } = parseOptions(options);
|
||||
this._urlLoaderOptions = urlLoaderOptions;
|
||||
this._redirectPolicy = redirectPolicy;
|
||||
}
|
||||
|
||||
get chunkedEncoding () {
|
||||
return this._chunkedEncoding || false;
|
||||
}
|
||||
|
||||
set chunkedEncoding (value: boolean) {
|
||||
if (this._started) {
|
||||
throw new Error('chunkedEncoding can only be set before the request is started');
|
||||
}
|
||||
if (typeof this._chunkedEncoding !== 'undefined') {
|
||||
throw new Error('chunkedEncoding can only be set once');
|
||||
}
|
||||
this._chunkedEncoding = !!value;
|
||||
if (this._chunkedEncoding) {
|
||||
this._body = new ChunkedBodyStream(this);
|
||||
this._urlLoaderOptions.body = (pipe: NodeJS.DataPipe) => {
|
||||
(this._body! as ChunkedBodyStream).startReading(pipe);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setHeader (name: string, value: string) {
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('`name` should be a string in setHeader(name, value)');
|
||||
}
|
||||
if (value == null) {
|
||||
throw new Error('`value` required in setHeader("' + name + '", value)');
|
||||
}
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t set headers after they are sent');
|
||||
}
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
this._urlLoaderOptions.headers[key] = { name, value };
|
||||
}
|
||||
|
||||
getHeader (name: string) {
|
||||
if (name == null) {
|
||||
throw new Error('`name` is required for getHeader(name)');
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
const header = this._urlLoaderOptions.headers[key];
|
||||
return header && header.value as any;
|
||||
}
|
||||
|
||||
removeHeader (name: string) {
|
||||
if (name == null) {
|
||||
throw new Error('`name` is required for removeHeader(name)');
|
||||
}
|
||||
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t remove headers after they are sent');
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
delete this._urlLoaderOptions.headers[key];
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, encoding: BufferEncoding, callback: () => void) {
|
||||
this._firstWrite = true;
|
||||
if (!this._body) {
|
||||
this._body = new SlurpStream();
|
||||
this._body.on('finish', () => {
|
||||
this._urlLoaderOptions.body = (this._body as SlurpStream).data();
|
||||
this._startRequest();
|
||||
});
|
||||
}
|
||||
// TODO: is this the right way to forward to another stream?
|
||||
this._body.write(chunk, encoding, callback);
|
||||
}
|
||||
|
||||
_final (callback: () => void) {
|
||||
if (this._body) {
|
||||
// TODO: is this the right way to forward to another stream?
|
||||
this._body.end(callback);
|
||||
} else {
|
||||
// end() called without a body, go ahead and start the request
|
||||
this._startRequest();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
_startRequest () {
|
||||
this._started = true;
|
||||
const stringifyValues = (obj: Record<string, { name: string, value: string | string[] }>) => {
|
||||
const ret: Record<string, string> = {};
|
||||
for (const k of Object.keys(obj)) {
|
||||
const kv = obj[k];
|
||||
ret[kv.name] = kv.value.toString();
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
this._urlLoaderOptions.referrer = this.getHeader('referer') || '';
|
||||
this._urlLoaderOptions.origin = this._urlLoaderOptions.origin || this.getHeader('origin') || '';
|
||||
this._urlLoaderOptions.hasUserActivation = this.getHeader('sec-fetch-user') === '?1';
|
||||
this._urlLoaderOptions.mode = this.getHeader('sec-fetch-mode') || '';
|
||||
this._urlLoaderOptions.destination = this.getHeader('sec-fetch-dest') || '';
|
||||
const opts = { ...this._urlLoaderOptions, extraHeaders: stringifyValues(this._urlLoaderOptions.headers) };
|
||||
this._urlLoader = createURLLoader(opts);
|
||||
this._urlLoader.on('response-started', (event, finalUrl, responseHead) => {
|
||||
const response = this._response = new IncomingMessage(responseHead);
|
||||
this.emit('response', response);
|
||||
});
|
||||
this._urlLoader.on('data', (event, data, resume) => {
|
||||
this._response!._storeInternalData(Buffer.from(data), resume);
|
||||
});
|
||||
this._urlLoader.on('complete', () => {
|
||||
if (this._response) { this._response._storeInternalData(null, null); }
|
||||
});
|
||||
this._urlLoader.on('error', (event, netErrorString) => {
|
||||
const error = new Error(netErrorString);
|
||||
if (this._response) this._response.destroy(error);
|
||||
this._die(error);
|
||||
});
|
||||
|
||||
this._urlLoader.on('login', (event, authInfo, callback) => {
|
||||
const handled = this.emit('login', authInfo, callback);
|
||||
if (!handled) {
|
||||
// If there were no listeners, cancel the authentication request.
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
this._urlLoader.on('redirect', (event, redirectInfo, headers) => {
|
||||
const { statusCode, newMethod, newUrl } = redirectInfo;
|
||||
if (this._redirectPolicy === 'error') {
|
||||
this._die(new Error('Attempted to redirect, but redirect policy was \'error\''));
|
||||
} else if (this._redirectPolicy === 'manual') {
|
||||
let _followRedirect = false;
|
||||
this._followRedirectCb = () => { _followRedirect = true; };
|
||||
try {
|
||||
this.emit('redirect', statusCode, newMethod, newUrl, headers);
|
||||
} finally {
|
||||
this._followRedirectCb = undefined;
|
||||
if (!_followRedirect && !this._aborted) {
|
||||
this._die(new Error('Redirect was cancelled'));
|
||||
}
|
||||
}
|
||||
} else if (this._redirectPolicy === 'follow') {
|
||||
// Calling followRedirect() when the redirect policy is 'follow' is
|
||||
// allowed but does nothing. (Perhaps it should throw an error
|
||||
// though...? Since the redirect will happen regardless.)
|
||||
try {
|
||||
this._followRedirectCb = () => {};
|
||||
this.emit('redirect', statusCode, newMethod, newUrl, headers);
|
||||
} finally {
|
||||
this._followRedirectCb = undefined;
|
||||
}
|
||||
} else {
|
||||
this._die(new Error(`Unexpected redirect policy '${this._redirectPolicy}'`));
|
||||
}
|
||||
});
|
||||
|
||||
this._urlLoader.on('upload-progress', (event, position, total) => {
|
||||
this._uploadProgress = { active: true, started: true, current: position, total };
|
||||
this.emit('upload-progress', position, total); // Undocumented, for now
|
||||
});
|
||||
|
||||
this._urlLoader.on('download-progress', (event, current) => {
|
||||
if (this._response) {
|
||||
this._response.emit('download-progress', current); // Undocumented, for now
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
followRedirect () {
|
||||
if (this._followRedirectCb) {
|
||||
this._followRedirectCb();
|
||||
} else {
|
||||
throw new Error('followRedirect() called, but was not waiting for a redirect');
|
||||
}
|
||||
}
|
||||
|
||||
abort () {
|
||||
if (!this._aborted) {
|
||||
process.nextTick(() => { this.emit('abort'); });
|
||||
}
|
||||
this._aborted = true;
|
||||
this._die();
|
||||
}
|
||||
|
||||
_die (err?: Error) {
|
||||
// Node.js assumes that any stream which is ended is no longer capable of emitted events
|
||||
// which is a faulty assumption for the case of an object that is acting like a stream
|
||||
// (our urlRequest). If we don't emit here, this causes errors since we *do* expect
|
||||
// that error events can be emitted after urlRequest.end().
|
||||
if ((this as any)._writableState.destroyed && err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
this.destroy(err);
|
||||
if (this._urlLoader) {
|
||||
this._urlLoader.cancel();
|
||||
if (this._response) this._response.destroy(err);
|
||||
}
|
||||
}
|
||||
|
||||
getUploadProgress (): UploadProgress {
|
||||
return this._uploadProgress ? { ...this._uploadProgress } : { active: false, started: false, current: 0, total: 0 };
|
||||
}
|
||||
}
|
||||
const { isOnline } = process._linkedBinding('electron_browser_net');
|
||||
|
||||
export function request (options: ClientRequestConstructorOptions | string, callback?: (message: IncomingMessage) => void) {
|
||||
return new ClientRequest(options, callback);
|
||||
}
|
||||
|
||||
export function fetch (input: RequestInfo, init?: RequestInit): Promise<Response> {
|
||||
return session.defaultSession.fetch(input, init);
|
||||
}
|
||||
|
||||
export function resolveHost (host: string, options?: Electron.ResolveHostOptions): Promise<Electron.ResolvedHost> {
|
||||
return session.defaultSession.resolveHost(host, options);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,151 @@
|
||||
import { app, session } from 'electron/main';
|
||||
import { ProtocolRequest, session } from 'electron/main';
|
||||
import { createReadStream } from 'fs';
|
||||
import { Readable } from 'stream';
|
||||
import { ReadableStream } from 'stream/web';
|
||||
|
||||
// Global protocol APIs.
|
||||
const protocol = process._linkedBinding('electron_browser_protocol');
|
||||
const { registerSchemesAsPrivileged, getStandardSchemes, Protocol } = process._linkedBinding('electron_browser_protocol');
|
||||
|
||||
// Fallback protocol APIs of default session.
|
||||
Object.setPrototypeOf(protocol, new Proxy({}, {
|
||||
get (_target, property) {
|
||||
if (!app.isReady()) return;
|
||||
const ERR_FAILED = -2;
|
||||
const ERR_UNEXPECTED = -9;
|
||||
|
||||
const protocol = session.defaultSession!.protocol;
|
||||
if (!Object.prototype.hasOwnProperty.call(protocol, property)) return;
|
||||
const isBuiltInScheme = (scheme: string) => ['http', 'https', 'file'].includes(scheme);
|
||||
|
||||
// Returning a native function directly would throw error.
|
||||
return (...args: any[]) => (protocol[property as keyof Electron.Protocol] as Function)(...args);
|
||||
},
|
||||
function makeStreamFromPipe (pipe: any): ReadableStream {
|
||||
const buf = new Uint8Array(1024 * 1024 /* 1 MB */);
|
||||
return new ReadableStream({
|
||||
async pull (controller) {
|
||||
try {
|
||||
const rv = await pipe.read(buf);
|
||||
if (rv > 0) {
|
||||
controller.enqueue(buf.subarray(0, rv));
|
||||
} else {
|
||||
controller.close();
|
||||
}
|
||||
} catch (e) {
|
||||
controller.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ownKeys () {
|
||||
if (!app.isReady()) return [];
|
||||
return Reflect.ownKeys(session.defaultSession!.protocol);
|
||||
},
|
||||
function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] {
|
||||
if (!uploadData) return null;
|
||||
// Optimization: skip creating a stream if the request is just a single buffer.
|
||||
if (uploadData.length === 1 && (uploadData[0] as any).type === 'rawData') return uploadData[0].bytes;
|
||||
|
||||
has: (target, property: string) => {
|
||||
if (!app.isReady()) return false;
|
||||
return Reflect.has(session.defaultSession!.protocol, property);
|
||||
},
|
||||
const chunks = [...uploadData] as any[]; // TODO: types are wrong
|
||||
let current: ReadableStreamDefaultReader | null = null;
|
||||
return new ReadableStream({
|
||||
pull (controller) {
|
||||
if (current) {
|
||||
current.read().then(({ done, value }) => {
|
||||
controller.enqueue(value);
|
||||
if (done) current = null;
|
||||
}, (err) => {
|
||||
controller.error(err);
|
||||
});
|
||||
} else {
|
||||
if (!chunks.length) { return controller.close(); }
|
||||
const chunk = chunks.shift()!;
|
||||
if (chunk.type === 'rawData') { controller.enqueue(chunk.bytes); } else if (chunk.type === 'file') {
|
||||
current = Readable.toWeb(createReadStream(chunk.filePath, { start: chunk.offset ?? 0, end: chunk.length >= 0 ? chunk.offset + chunk.length : undefined })).getReader();
|
||||
this.pull!(controller);
|
||||
} else if (chunk.type === 'stream') {
|
||||
current = makeStreamFromPipe(chunk.body).getReader();
|
||||
this.pull!(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}) as RequestInit['body'];
|
||||
}
|
||||
|
||||
getOwnPropertyDescriptor () {
|
||||
return { configurable: true, enumerable: true };
|
||||
// TODO(codebytere): Use Object.hasOwn() once we update to ECMAScript 2022.
|
||||
function validateResponse (res: Response) {
|
||||
if (!res || typeof res !== 'object') return false;
|
||||
|
||||
if (res.type === 'error') return true;
|
||||
|
||||
const exists = (key: string) => Object.prototype.hasOwnProperty.call(res, key);
|
||||
|
||||
if (exists('status') && typeof res.status !== 'number') return false;
|
||||
if (exists('statusText') && typeof res.statusText !== 'string') return false;
|
||||
if (exists('headers') && typeof res.headers !== 'object') return false;
|
||||
|
||||
if (exists('body')) {
|
||||
if (typeof res.body !== 'object') return false;
|
||||
if (res.body !== null && !(res.body instanceof ReadableStream)) return false;
|
||||
}
|
||||
}));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, handler: (req: Request) => Response | Promise<Response>) {
|
||||
const register = isBuiltInScheme(scheme) ? this.interceptProtocol : this.registerProtocol;
|
||||
const success = register.call(this, scheme, async (preq: ProtocolRequest, cb: any) => {
|
||||
try {
|
||||
const body = convertToRequestBody(preq.uploadData);
|
||||
const req = new Request(preq.url, {
|
||||
headers: preq.headers,
|
||||
method: preq.method,
|
||||
referrer: preq.referrer,
|
||||
body,
|
||||
duplex: body instanceof ReadableStream ? 'half' : undefined
|
||||
} as any);
|
||||
const res = await handler(req);
|
||||
if (!validateResponse(res)) {
|
||||
return cb({ error: ERR_UNEXPECTED });
|
||||
} else if (res.type === 'error') {
|
||||
cb({ error: ERR_FAILED });
|
||||
} else {
|
||||
cb({
|
||||
data: res.body ? Readable.fromWeb(res.body as ReadableStream<ArrayBufferView>) : null,
|
||||
headers: res.headers ? Object.fromEntries(res.headers) : {},
|
||||
statusCode: res.status,
|
||||
statusText: res.statusText,
|
||||
mimeType: (res as any).__original_resp?._responseHead?.mimeType
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
cb({ error: ERR_UNEXPECTED });
|
||||
}
|
||||
});
|
||||
if (!success) throw new Error(`Failed to register protocol: ${scheme}`);
|
||||
};
|
||||
|
||||
Protocol.prototype.unhandle = function (this: Electron.Protocol, scheme: string) {
|
||||
const unregister = isBuiltInScheme(scheme) ? this.uninterceptProtocol : this.unregisterProtocol;
|
||||
if (!unregister.call(this, scheme)) { throw new Error(`Failed to unhandle protocol: ${scheme}`); }
|
||||
};
|
||||
|
||||
Protocol.prototype.isProtocolHandled = function (this: Electron.Protocol, scheme: string) {
|
||||
const isRegistered = isBuiltInScheme(scheme) ? this.isProtocolIntercepted : this.isProtocolRegistered;
|
||||
return isRegistered.call(this, scheme);
|
||||
};
|
||||
|
||||
const protocol = {
|
||||
registerSchemesAsPrivileged,
|
||||
getStandardSchemes,
|
||||
registerStringProtocol: (...args) => session.defaultSession.protocol.registerStringProtocol(...args),
|
||||
registerBufferProtocol: (...args) => session.defaultSession.protocol.registerBufferProtocol(...args),
|
||||
registerStreamProtocol: (...args) => session.defaultSession.protocol.registerStreamProtocol(...args),
|
||||
registerFileProtocol: (...args) => session.defaultSession.protocol.registerFileProtocol(...args),
|
||||
registerHttpProtocol: (...args) => session.defaultSession.protocol.registerHttpProtocol(...args),
|
||||
registerProtocol: (...args) => session.defaultSession.protocol.registerProtocol(...args),
|
||||
unregisterProtocol: (...args) => session.defaultSession.protocol.unregisterProtocol(...args),
|
||||
isProtocolRegistered: (...args) => session.defaultSession.protocol.isProtocolRegistered(...args),
|
||||
interceptStringProtocol: (...args) => session.defaultSession.protocol.interceptStringProtocol(...args),
|
||||
interceptBufferProtocol: (...args) => session.defaultSession.protocol.interceptBufferProtocol(...args),
|
||||
interceptStreamProtocol: (...args) => session.defaultSession.protocol.interceptStreamProtocol(...args),
|
||||
interceptFileProtocol: (...args) => session.defaultSession.protocol.interceptFileProtocol(...args),
|
||||
interceptHttpProtocol: (...args) => session.defaultSession.protocol.interceptHttpProtocol(...args),
|
||||
interceptProtocol: (...args) => session.defaultSession.protocol.interceptProtocol(...args),
|
||||
uninterceptProtocol: (...args) => session.defaultSession.protocol.uninterceptProtocol(...args),
|
||||
isProtocolIntercepted: (...args) => session.defaultSession.protocol.isProtocolIntercepted(...args),
|
||||
handle: (...args) => session.defaultSession.protocol.handle(...args),
|
||||
unhandle: (...args) => session.defaultSession.protocol.unhandle(...args),
|
||||
isProtocolHandled: (...args) => session.defaultSession.protocol.isProtocolHandled(...args)
|
||||
} as typeof Electron.protocol;
|
||||
|
||||
export default protocol;
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
const { fromPartition } = process._linkedBinding('electron_browser_session');
|
||||
import { fetchWithSession } from '@electron/internal/browser/api/net-fetch';
|
||||
const { fromPartition, fromPath, Session } = process._linkedBinding('electron_browser_session');
|
||||
|
||||
Session.prototype.fetch = function (input: RequestInfo, init?: RequestInit) {
|
||||
return fetchWithSession(input, init, this);
|
||||
};
|
||||
|
||||
export default {
|
||||
fromPartition,
|
||||
fromPath,
|
||||
get defaultSession () {
|
||||
return fromPartition('');
|
||||
}
|
||||
|
||||
@@ -337,10 +337,9 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
|
||||
// TODO(codebytere): deduplicate argument sanitization by moving rest of
|
||||
// print param logic into new file shared between printToPDF and print
|
||||
WebContents.prototype.print = function (printOptions: ElectronInternal.WebContentsPrintOptions, callback) {
|
||||
const options = printOptions ?? {};
|
||||
if (options.pageSize) {
|
||||
const pageSize = options.pageSize;
|
||||
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions, callback) {
|
||||
if (typeof options === 'object') {
|
||||
const pageSize = options.pageSize ?? 'A4';
|
||||
if (typeof pageSize === 'object') {
|
||||
if (!pageSize.height || !pageSize.width) {
|
||||
throw new Error('height and width properties are required for pageSize');
|
||||
@@ -357,10 +356,21 @@ WebContents.prototype.print = function (printOptions: ElectronInternal.WebConten
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
width_microns: width
|
||||
width_microns: width,
|
||||
imageable_area_left_microns: 0,
|
||||
imageable_area_bottom_microns: 0,
|
||||
imageable_area_right_microns: width,
|
||||
imageable_area_top_microns: height
|
||||
};
|
||||
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
|
||||
const mediaSize = PDFPageSizes[pageSize];
|
||||
options.mediaSize = {
|
||||
...mediaSize,
|
||||
imageable_area_left_microns: 0,
|
||||
imageable_area_bottom_microns: 0,
|
||||
imageable_area_right_microns: mediaSize.width_microns,
|
||||
imageable_area_top_microns: mediaSize.height_microns
|
||||
};
|
||||
} else if (PDFPageSizes[pageSize]) {
|
||||
options.mediaSize = PDFPageSizes[pageSize];
|
||||
} else {
|
||||
throw new Error(`Unsupported pageSize: ${pageSize}`);
|
||||
}
|
||||
@@ -416,10 +426,6 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||
};
|
||||
|
||||
WebContents.prototype.loadURL = function (url, options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
const resolveAndCleanup = () => {
|
||||
removeListeners();
|
||||
@@ -441,6 +447,7 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
};
|
||||
|
||||
let navigationStarted = false;
|
||||
let browserInitiatedInPageNavigation = false;
|
||||
const navigationListener = (event: Electron.Event, url: string, isSameDocument: boolean, isMainFrame: boolean) => {
|
||||
if (isMainFrame) {
|
||||
if (navigationStarted && !isSameDocument) {
|
||||
@@ -455,6 +462,7 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
// as the routing does not leave the document
|
||||
return rejectAndCleanup(-3, 'ERR_ABORTED', url);
|
||||
}
|
||||
browserInitiatedInPageNavigation = navigationStarted && isSameDocument;
|
||||
navigationStarted = true;
|
||||
}
|
||||
};
|
||||
@@ -469,24 +477,29 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
// would be more appropriate.
|
||||
rejectAndCleanup(-2, 'ERR_FAILED', url);
|
||||
};
|
||||
const finishListenerWhenUserInitiatedNavigation = () => {
|
||||
if (!browserInitiatedInPageNavigation) {
|
||||
finishListener();
|
||||
}
|
||||
};
|
||||
const removeListeners = () => {
|
||||
this.removeListener('did-finish-load', finishListener);
|
||||
this.removeListener('did-fail-load', failListener);
|
||||
this.removeListener('did-navigate-in-page', finishListener);
|
||||
this.removeListener('did-navigate-in-page', finishListenerWhenUserInitiatedNavigation);
|
||||
this.removeListener('did-start-navigation', navigationListener);
|
||||
this.removeListener('did-stop-loading', stopLoadingListener);
|
||||
this.removeListener('destroyed', stopLoadingListener);
|
||||
};
|
||||
this.on('did-finish-load', finishListener);
|
||||
this.on('did-fail-load', failListener);
|
||||
this.on('did-navigate-in-page', finishListener);
|
||||
this.on('did-navigate-in-page', finishListenerWhenUserInitiatedNavigation);
|
||||
this.on('did-start-navigation', navigationListener);
|
||||
this.on('did-stop-loading', stopLoadingListener);
|
||||
this.on('destroyed', stopLoadingListener);
|
||||
});
|
||||
// Add a no-op rejection handler to silence the unhandled rejection error.
|
||||
p.catch(() => {});
|
||||
this._loadURL(url, options);
|
||||
this._loadURL(url, options ?? {});
|
||||
return p;
|
||||
};
|
||||
|
||||
@@ -539,7 +552,8 @@ const addReplyToEvent = (event: Electron.IpcMainEvent) => {
|
||||
};
|
||||
};
|
||||
|
||||
const addSenderFrameToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent) => {
|
||||
const addSenderToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent, sender: Electron.WebContents) => {
|
||||
event.sender = sender;
|
||||
const { processId, frameId } = event;
|
||||
Object.defineProperty(event, 'senderFrame', {
|
||||
get: () => webFrameMain.fromId(processId, frameId)
|
||||
@@ -548,7 +562,7 @@ const addSenderFrameToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainIn
|
||||
|
||||
const addReturnValueToEvent = (event: Electron.IpcMainEvent) => {
|
||||
Object.defineProperty(event, 'returnValue', {
|
||||
set: (value) => event.sendReply(value),
|
||||
set: (value) => event._replyChannel.sendReply(value),
|
||||
get: () => {}
|
||||
});
|
||||
};
|
||||
@@ -589,7 +603,7 @@ WebContents.prototype._init = function () {
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
addSenderToEvent(event, this);
|
||||
if (internal) {
|
||||
ipcMainInternal.emit(channel, event, ...args);
|
||||
} else {
|
||||
@@ -602,25 +616,30 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
});
|
||||
|
||||
this.on('-ipc-invoke' as any, function (event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
event._reply = (result: any) => event.sendReply({ result });
|
||||
event._throw = (error: Error) => {
|
||||
this.on('-ipc-invoke' as any, async function (this: Electron.WebContents, event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderToEvent(event, this);
|
||||
const replyWithResult = (result: any) => event._replyChannel.sendReply({ result });
|
||||
const replyWithError = (error: Error) => {
|
||||
console.error(`Error occurred in handler for '${channel}':`, error);
|
||||
event.sendReply({ error: error.toString() });
|
||||
event._replyChannel.sendReply({ error: error.toString() });
|
||||
};
|
||||
const maybeWebFrame = getWebFrameForEvent(event);
|
||||
const targets: (ElectronInternal.IpcMainInternal| undefined)[] = internal ? [ipcMainInternal] : [maybeWebFrame?.ipc, ipc, ipcMain];
|
||||
const target = targets.find(target => target && (target as any)._invokeHandlers.has(channel));
|
||||
if (target) {
|
||||
(target as any)._invokeHandlers.get(channel)(event, ...args);
|
||||
const handler = (target as any)._invokeHandlers.get(channel);
|
||||
try {
|
||||
replyWithResult(await Promise.resolve(handler(event, ...args)));
|
||||
} catch (err) {
|
||||
replyWithError(err as Error);
|
||||
}
|
||||
} else {
|
||||
event._throw(`No handler registered for '${channel}'`);
|
||||
replyWithError(new Error(`No handler registered for '${channel}'`));
|
||||
}
|
||||
});
|
||||
|
||||
this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
addSenderToEvent(event, this);
|
||||
addReturnValueToEvent(event);
|
||||
if (internal) {
|
||||
ipcMainInternal.emit(channel, event, ...args);
|
||||
@@ -637,8 +656,8 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
});
|
||||
|
||||
this.on('-ipc-ports' as any, function (event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
this.on('-ipc-ports' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
|
||||
addSenderToEvent(event, this);
|
||||
event.ports = ports.map(p => new MessagePortMain(p));
|
||||
const maybeWebFrame = getWebFrameForEvent(event);
|
||||
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, message);
|
||||
@@ -666,7 +685,7 @@ WebContents.prototype._init = function () {
|
||||
|
||||
if (this.getType() !== 'remote') {
|
||||
// Make new windows requested by links behave like "window.open".
|
||||
this.on('-new-window' as any, (event: ElectronInternal.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
|
||||
this.on('-new-window' as any, (event: Electron.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
|
||||
rawFeatures: string, referrer: Electron.Referrer, postData: PostData) => {
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
@@ -692,7 +711,7 @@ WebContents.prototype._init = function () {
|
||||
const options = result.browserWindowConstructorOptions;
|
||||
if (!event.defaultPrevented) {
|
||||
openGuestWindow({
|
||||
embedder: event.sender,
|
||||
embedder: this,
|
||||
disposition,
|
||||
referrer,
|
||||
postData,
|
||||
@@ -705,7 +724,7 @@ WebContents.prototype._init = function () {
|
||||
|
||||
let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
|
||||
let windowOpenOutlivesOpenerOption: boolean = false;
|
||||
this.on('-will-add-new-contents' as any, (event: ElectronInternal.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
|
||||
this.on('-will-add-new-contents' as any, (event: Electron.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
...parseContentTypeFormat(postData)
|
||||
@@ -740,7 +759,7 @@ WebContents.prototype._init = function () {
|
||||
} : undefined;
|
||||
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
|
||||
const webPreferences = makeWebPreferences({
|
||||
embedder: event.sender,
|
||||
embedder: this,
|
||||
insecureParsedWebPreferences: parsedWebPreferences,
|
||||
secureOverrideWebPreferences
|
||||
});
|
||||
@@ -753,7 +772,7 @@ WebContents.prototype._init = function () {
|
||||
});
|
||||
|
||||
// Create a new browser window for "window.open"
|
||||
this.on('-add-new-contents' as any, (event: ElectronInternal.Event, webContents: Electron.WebContents, disposition: string,
|
||||
this.on('-add-new-contents' as any, (event: Electron.Event, webContents: Electron.WebContents, disposition: string,
|
||||
_userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string,
|
||||
referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => {
|
||||
const overriddenOptions = windowOpenOverriddenOptions || undefined;
|
||||
@@ -769,7 +788,7 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
|
||||
openGuestWindow({
|
||||
embedder: event.sender,
|
||||
embedder: this,
|
||||
guest: webContents,
|
||||
overrideBrowserWindowOptions: overriddenOptions,
|
||||
disposition,
|
||||
@@ -806,8 +825,7 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
});
|
||||
|
||||
const event = process._linkedBinding('electron_browser_event').createEmpty();
|
||||
app.emit('web-contents-created', event, this);
|
||||
app.emit('web-contents-created', { sender: this, preventDefault () {}, get defaultPrevented () { return false; } }, this);
|
||||
|
||||
// Properties
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ interface GuestInstance {
|
||||
}
|
||||
|
||||
const webViewManager = process._linkedBinding('electron_browser_web_view_manager');
|
||||
const eventBinding = process._linkedBinding('electron_browser_event');
|
||||
const netBinding = process._linkedBinding('electron_browser_net');
|
||||
|
||||
const supportedWebViewEvents = Object.keys(webViewEvents);
|
||||
@@ -82,7 +81,13 @@ function makeLoadURLOptions (params: Record<string, any>) {
|
||||
// Create a new guest instance.
|
||||
const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
|
||||
const webPreferences = makeWebPreferences(embedder, params);
|
||||
const event = eventBinding.createWithSender(embedder);
|
||||
const event = {
|
||||
sender: embedder,
|
||||
preventDefault () {
|
||||
this.defaultPrevented = true;
|
||||
},
|
||||
defaultPrevented: false
|
||||
};
|
||||
|
||||
const { instanceId } = params;
|
||||
|
||||
@@ -158,6 +163,16 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||
});
|
||||
});
|
||||
|
||||
// Dispatch guest's frame navigation event to embedder.
|
||||
guest.on('will-frame-navigate', function (event: Electron.WebContentsWillFrameNavigateEventParams) {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'will-frame-navigate', {
|
||||
url: event.url,
|
||||
isMainFrame: event.isMainFrame,
|
||||
frameProcessId: event.frame.processId,
|
||||
frameRoutingId: event.frame.routingId
|
||||
});
|
||||
});
|
||||
|
||||
// Notify guest of embedder window visibility when it is ready
|
||||
// FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
|
||||
guest.on('dom-ready', function () {
|
||||
|
||||
@@ -84,11 +84,20 @@ const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
let packagePath = null;
|
||||
let packageJson = null;
|
||||
const searchPaths: string[] = v8Util.getHiddenValue(global, 'appSearchPaths');
|
||||
const searchPathsOnlyLoadASAR: boolean = v8Util.getHiddenValue(global, 'appSearchPathsOnlyLoadASAR');
|
||||
// Borrow the _getOrCreateArchive asar helper
|
||||
const getOrCreateArchive = process._getOrCreateArchive;
|
||||
delete process._getOrCreateArchive;
|
||||
|
||||
if (process.resourcesPath) {
|
||||
for (packagePath of searchPaths) {
|
||||
try {
|
||||
packagePath = path.join(process.resourcesPath, packagePath);
|
||||
if (searchPathsOnlyLoadASAR) {
|
||||
if (!getOrCreateArchive?.(packagePath)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
packageJson = Module._load(path.join(packagePath, 'package.json'));
|
||||
break;
|
||||
} catch {
|
||||
|
||||
@@ -18,13 +18,7 @@ export class IpcMainImpl extends EventEmitter {
|
||||
if (typeof fn !== 'function') {
|
||||
throw new Error(`Expected handler to be a function, but found type '${typeof fn}'`);
|
||||
}
|
||||
this._invokeHandlers.set(method, async (e, ...args) => {
|
||||
try {
|
||||
e._reply(await Promise.resolve(fn(e, ...args)));
|
||||
} catch (err) {
|
||||
e._throw(err as Error);
|
||||
}
|
||||
});
|
||||
this._invokeHandlers.set(method, fn);
|
||||
}
|
||||
|
||||
handleOnce: Electron.IpcMain['handleOnce'] = (method, fn) => {
|
||||
|
||||
@@ -31,11 +31,15 @@ export const syncMethods = new Set([
|
||||
'redo',
|
||||
'cut',
|
||||
'copy',
|
||||
'centerSelection',
|
||||
'paste',
|
||||
'pasteAndMatchStyle',
|
||||
'delete',
|
||||
'selectAll',
|
||||
'unselect',
|
||||
'scrollToTop',
|
||||
'scrollToBottom',
|
||||
'adjustSelection',
|
||||
'replace',
|
||||
'replaceMisspelling',
|
||||
'findInPage',
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"devDependencies": {
|
||||
"@azure/storage-blob": "^12.9.0",
|
||||
"@electron/asar": "^3.2.1",
|
||||
"@electron/docs-parser": "^1.0.0",
|
||||
"@electron/docs-parser": "^1.1.0",
|
||||
"@electron/fiddle-core": "^1.0.4",
|
||||
"@electron/github-app-auth": "^2.0.0",
|
||||
"@electron/lint-roller": "^1.5.0",
|
||||
"@electron/typescript-definitions": "^8.10.0",
|
||||
"@electron/typescript-definitions": "^8.14.0",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@primer/octicons": "^10.0.0",
|
||||
"@types/basic-auth": "^1.1.3",
|
||||
@@ -73,7 +73,7 @@
|
||||
"ts-loader": "^8.0.2",
|
||||
"ts-node": "6.2.0",
|
||||
"typescript": "^4.5.5",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"wrapper-webpack-plugin": "^2.2.0"
|
||||
},
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
fix_rename_webswapcgllayer_to_webswapcgllayerchromium.patch
|
||||
cherry-pick-d0ee0197ddff.patch
|
||||
cherry-pick-285c7712c506.patch
|
||||
cherry-pick-2bf945775fe6.patch
|
||||
cherry-pick-cafe56b591ed.patch
|
||||
cherry-pick-5486190be556.patch
|
||||
cherry-pick-e4669a74888d.patch
|
||||
|
||||
153
patches/angle/cherry-pick-285c7712c506.patch
Normal file
153
patches/angle/cherry-pick-285c7712c506.patch
Normal file
@@ -0,0 +1,153 @@
|
||||
From 285c7712c50654e3d7238b059c4631bc91285514 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 13 Jul 2023 15:23:49 -0400
|
||||
Subject: [PATCH] M116: Translator: Unconditionally limit variable sizes
|
||||
|
||||
... instead of just for WebGL. This is to avoid hitting driver bugs
|
||||
that were prevented with this check for WebGL on a compromised renderer
|
||||
that can create non-WebGL contexts.
|
||||
|
||||
Bug: chromium:1464682
|
||||
Change-Id: I2b1c5a8c51f06225f5f850109d30778d97e574c7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4717371
|
||||
Reviewed-by: Roman Lavrov <romanl@google.com>
|
||||
---
|
||||
|
||||
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
|
||||
index 7b1ac4e..383feeb 100644
|
||||
--- a/src/compiler/translator/Compiler.cpp
|
||||
+++ b/src/compiler/translator/Compiler.cpp
|
||||
@@ -397,9 +397,10 @@
|
||||
|
||||
bool TCompiler::shouldLimitTypeSizes() const
|
||||
{
|
||||
- // WebGL shaders limit the size of variables' types in shaders,
|
||||
- // including arrays, structs and interface blocks.
|
||||
- return IsWebGLBasedSpec(mShaderSpec);
|
||||
+ // Prevent unrealistically large variable sizes in shaders. This works around driver bugs
|
||||
+ // around int-size limits (such as 2GB). The limits are generously large enough that no real
|
||||
+ // shader should ever hit it.
|
||||
+ return true;
|
||||
}
|
||||
|
||||
bool TCompiler::Init(const ShBuiltInResources &resources)
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index 2a033ad..19a4821 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -23,10 +23,10 @@
|
||||
// Arbitrarily enforce that all types declared with a size in bytes of over 2 GB will cause
|
||||
// compilation failure.
|
||||
//
|
||||
-// For local and global variables, the limit is much lower (1MB) as that much memory won't fit in
|
||||
+// For local and global variables, the limit is much lower (16MB) as that much memory won't fit in
|
||||
// the GPU registers anyway.
|
||||
constexpr size_t kMaxVariableSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
|
||||
-constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(1) * 1024 * 1024;
|
||||
+constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(16) * 1024 * 1024;
|
||||
|
||||
// Traverses intermediate tree to ensure that the shader does not
|
||||
// exceed certain implementation-defined limits on the sizes of types.
|
||||
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
|
||||
index a91f8b0..a866b25 100644
|
||||
--- a/src/compiler/translator/util.cpp
|
||||
+++ b/src/compiler/translator/util.cpp
|
||||
@@ -282,6 +282,9 @@
|
||||
|
||||
return kBoolGLType[type.getNominalSize() - 1];
|
||||
|
||||
+ case EbtYuvCscStandardEXT:
|
||||
+ return GL_UNSIGNED_INT;
|
||||
+
|
||||
case EbtSampler2D:
|
||||
return GL_SAMPLER_2D;
|
||||
case EbtSampler3D:
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index 9ae56f5..a8d2ce4 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5284,8 +5284,8 @@
|
||||
|
||||
constexpr char kVSArrayTooLarge[] =
|
||||
R"(varying vec4 color;
|
||||
-// 1 MB / 32 aligned bytes per mat2 = 32768
|
||||
-const int array_size = 32769;
|
||||
+// 16 MB / 32 aligned bytes per mat2 = 524288
|
||||
+const int array_size = 524289;
|
||||
void main()
|
||||
{
|
||||
mat2 array[array_size];
|
||||
@@ -5297,7 +5297,7 @@
|
||||
|
||||
constexpr char kVSArrayMuchTooLarge[] =
|
||||
R"(varying vec4 color;
|
||||
-const int array_size = 55600;
|
||||
+const int array_size = 757000;
|
||||
void main()
|
||||
{
|
||||
mat2 array[array_size];
|
||||
@@ -5361,9 +5361,9 @@
|
||||
constexpr char kTooLargeGlobalMemory1[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32768];
|
||||
-vec4 array2[32769];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524288];
|
||||
+vec4 array2[524289];
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -5376,9 +5376,9 @@
|
||||
constexpr char kTooLargeGlobalMemory2[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32767];
|
||||
-vec4 array2[32767];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524287];
|
||||
+vec4 array2[524287];
|
||||
vec4 x, y, z;
|
||||
|
||||
void main()
|
||||
@@ -5392,12 +5392,12 @@
|
||||
constexpr char kTooLargeGlobalAndLocalMemory1[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32768];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524288];
|
||||
|
||||
void main()
|
||||
{
|
||||
- vec4 array2[32769];
|
||||
+ vec4 array2[524289];
|
||||
if (array[0].x + array[1].x == 2.0)
|
||||
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
else
|
||||
@@ -5408,18 +5408,18 @@
|
||||
constexpr char kTooLargeGlobalAndLocalMemory2[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32768];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524288];
|
||||
|
||||
float f()
|
||||
{
|
||||
- vec4 array2[16384];
|
||||
+ vec4 array2[524288];
|
||||
return array2[0].x;
|
||||
}
|
||||
|
||||
float g()
|
||||
{
|
||||
- vec4 array3[16383];
|
||||
+ vec4 array3[524287];
|
||||
return array3[0].x;
|
||||
}
|
||||
|
||||
197
patches/angle/cherry-pick-2bf945775fe6.patch
Normal file
197
patches/angle/cherry-pick-2bf945775fe6.patch
Normal file
@@ -0,0 +1,197 @@
|
||||
From 2bf945775fe634eb9e420c2263dae6043bbb5ece Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Fri, 14 Jul 2023 12:30:15 -0400
|
||||
Subject: [PATCH] M116: Translator: Limit variable sizes vs uint overflow
|
||||
|
||||
Bug: chromium:1464680
|
||||
Change-Id: Iee41a2da7a7a330e6cc4d6da59a6e9836ee9dd36
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4717372
|
||||
Reviewed-by: Roman Lavrov <romanl@google.com>
|
||||
---
|
||||
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index 19a4821..f0ff9cb 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "compiler/translator/ValidateTypeSizeLimitations.h"
|
||||
|
||||
#include "angle_gl.h"
|
||||
+#include "common/mathutil.h"
|
||||
#include "compiler/translator/Diagnostics.h"
|
||||
#include "compiler/translator/Symbol.h"
|
||||
#include "compiler/translator/SymbolTable.h"
|
||||
@@ -113,7 +114,8 @@
|
||||
|
||||
void validateTotalPrivateVariableSize()
|
||||
{
|
||||
- if (mTotalPrivateVariablesSize > kMaxPrivateVariableSizeInBytes)
|
||||
+ if (mTotalPrivateVariablesSize.ValueOrDefault(std::numeric_limits<size_t>::max()) >
|
||||
+ kMaxPrivateVariableSizeInBytes)
|
||||
{
|
||||
mDiagnostics->error(
|
||||
TSourceLoc{},
|
||||
@@ -231,7 +233,7 @@
|
||||
TDiagnostics *mDiagnostics;
|
||||
std::vector<int> mLoopSymbolIds;
|
||||
|
||||
- size_t mTotalPrivateVariablesSize;
|
||||
+ angle::base::CheckedNumeric<size_t> mTotalPrivateVariablesSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index a8d2ce4..542d49f 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5426,7 +5426,7 @@
|
||||
float h()
|
||||
{
|
||||
vec4 value;
|
||||
- float value2
|
||||
+ float value2;
|
||||
return value.x + value2;
|
||||
}
|
||||
|
||||
@@ -5438,6 +5438,131 @@
|
||||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
})";
|
||||
|
||||
+ constexpr char kTooLargeGlobalMemoryOverflow[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+// Create 256 arrays so each is small, but the total overflows a 32-bit number
|
||||
+vec4 array[1048576], array2[1048576], array3[1048576], array4[1048576], array5[1048576];
|
||||
+vec4 array6[1048576], array7[1048576], array8[1048576], array9[1048576], array10[1048576];
|
||||
+vec4 array11[1048576], array12[1048576], array13[1048576], array14[1048576], array15[1048576];
|
||||
+vec4 array16[1048576], array17[1048576], array18[1048576], array19[1048576], array20[1048576];
|
||||
+vec4 array21[1048576], array22[1048576], array23[1048576], array24[1048576], array25[1048576];
|
||||
+vec4 array26[1048576], array27[1048576], array28[1048576], array29[1048576], array30[1048576];
|
||||
+vec4 array31[1048576], array32[1048576], array33[1048576], array34[1048576], array35[1048576];
|
||||
+vec4 array36[1048576], array37[1048576], array38[1048576], array39[1048576], array40[1048576];
|
||||
+vec4 array41[1048576], array42[1048576], array43[1048576], array44[1048576], array45[1048576];
|
||||
+vec4 array46[1048576], array47[1048576], array48[1048576], array49[1048576], array50[1048576];
|
||||
+vec4 array51[1048576], array52[1048576], array53[1048576], array54[1048576], array55[1048576];
|
||||
+vec4 array56[1048576], array57[1048576], array58[1048576], array59[1048576], array60[1048576];
|
||||
+vec4 array61[1048576], array62[1048576], array63[1048576], array64[1048576], array65[1048576];
|
||||
+vec4 array66[1048576], array67[1048576], array68[1048576], array69[1048576], array70[1048576];
|
||||
+vec4 array71[1048576], array72[1048576], array73[1048576], array74[1048576], array75[1048576];
|
||||
+vec4 array76[1048576], array77[1048576], array78[1048576], array79[1048576], array80[1048576];
|
||||
+vec4 array81[1048576], array82[1048576], array83[1048576], array84[1048576], array85[1048576];
|
||||
+vec4 array86[1048576], array87[1048576], array88[1048576], array89[1048576], array90[1048576];
|
||||
+vec4 array91[1048576], array92[1048576], array93[1048576], array94[1048576], array95[1048576];
|
||||
+vec4 array96[1048576], array97[1048576], array98[1048576], array99[1048576], array100[1048576];
|
||||
+vec4 array101[1048576], array102[1048576], array103[1048576], array104[1048576], array105[1048576];
|
||||
+vec4 array106[1048576], array107[1048576], array108[1048576], array109[1048576], array110[1048576];
|
||||
+vec4 array111[1048576], array112[1048576], array113[1048576], array114[1048576], array115[1048576];
|
||||
+vec4 array116[1048576], array117[1048576], array118[1048576], array119[1048576], array120[1048576];
|
||||
+vec4 array121[1048576], array122[1048576], array123[1048576], array124[1048576], array125[1048576];
|
||||
+vec4 array126[1048576], array127[1048576], array128[1048576], array129[1048576], array130[1048576];
|
||||
+vec4 array131[1048576], array132[1048576], array133[1048576], array134[1048576], array135[1048576];
|
||||
+vec4 array136[1048576], array137[1048576], array138[1048576], array139[1048576], array140[1048576];
|
||||
+vec4 array141[1048576], array142[1048576], array143[1048576], array144[1048576], array145[1048576];
|
||||
+vec4 array146[1048576], array147[1048576], array148[1048576], array149[1048576], array150[1048576];
|
||||
+vec4 array151[1048576], array152[1048576], array153[1048576], array154[1048576], array155[1048576];
|
||||
+vec4 array156[1048576], array157[1048576], array158[1048576], array159[1048576], array160[1048576];
|
||||
+vec4 array161[1048576], array162[1048576], array163[1048576], array164[1048576], array165[1048576];
|
||||
+vec4 array166[1048576], array167[1048576], array168[1048576], array169[1048576], array170[1048576];
|
||||
+vec4 array171[1048576], array172[1048576], array173[1048576], array174[1048576], array175[1048576];
|
||||
+vec4 array176[1048576], array177[1048576], array178[1048576], array179[1048576], array180[1048576];
|
||||
+vec4 array181[1048576], array182[1048576], array183[1048576], array184[1048576], array185[1048576];
|
||||
+vec4 array186[1048576], array187[1048576], array188[1048576], array189[1048576], array190[1048576];
|
||||
+vec4 array191[1048576], array192[1048576], array193[1048576], array194[1048576], array195[1048576];
|
||||
+vec4 array196[1048576], array197[1048576], array198[1048576], array199[1048576], array200[1048576];
|
||||
+vec4 array201[1048576], array202[1048576], array203[1048576], array204[1048576], array205[1048576];
|
||||
+vec4 array206[1048576], array207[1048576], array208[1048576], array209[1048576], array210[1048576];
|
||||
+vec4 array211[1048576], array212[1048576], array213[1048576], array214[1048576], array215[1048576];
|
||||
+vec4 array216[1048576], array217[1048576], array218[1048576], array219[1048576], array220[1048576];
|
||||
+vec4 array221[1048576], array222[1048576], array223[1048576], array224[1048576], array225[1048576];
|
||||
+vec4 array226[1048576], array227[1048576], array228[1048576], array229[1048576], array230[1048576];
|
||||
+vec4 array231[1048576], array232[1048576], array233[1048576], array234[1048576], array235[1048576];
|
||||
+vec4 array236[1048576], array237[1048576], array238[1048576], array239[1048576], array240[1048576];
|
||||
+vec4 array241[1048576], array242[1048576], array243[1048576], array244[1048576], array245[1048576];
|
||||
+vec4 array246[1048576], array247[1048576], array248[1048576], array249[1048576], array250[1048576];
|
||||
+vec4 array251[1048576], array252[1048576], array253[1048576], array254[1048576], array255[1048576];
|
||||
+vec4 array256[1048576];
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ float f = array[0].x; f += array2[0].x; f += array3[0].x; f += array4[0].x; f += array5[0].x;
|
||||
+ f += array6[0].x; f += array7[0].x; f += array8[0].x; f += array9[0].x; f += array10[0].x;
|
||||
+ f += array11[0].x; f += array12[0].x; f += array13[0].x; f += array14[0].x; f += array15[0].x;
|
||||
+ f += array16[0].x; f += array17[0].x; f += array18[0].x; f += array19[0].x; f += array20[0].x;
|
||||
+ f += array21[0].x; f += array22[0].x; f += array23[0].x; f += array24[0].x; f += array25[0].x;
|
||||
+ f += array26[0].x; f += array27[0].x; f += array28[0].x; f += array29[0].x; f += array30[0].x;
|
||||
+ f += array31[0].x; f += array32[0].x; f += array33[0].x; f += array34[0].x; f += array35[0].x;
|
||||
+ f += array36[0].x; f += array37[0].x; f += array38[0].x; f += array39[0].x; f += array40[0].x;
|
||||
+ f += array41[0].x; f += array42[0].x; f += array43[0].x; f += array44[0].x; f += array45[0].x;
|
||||
+ f += array46[0].x; f += array47[0].x; f += array48[0].x; f += array49[0].x; f += array50[0].x;
|
||||
+ f += array51[0].x; f += array52[0].x; f += array53[0].x; f += array54[0].x; f += array55[0].x;
|
||||
+ f += array56[0].x; f += array57[0].x; f += array58[0].x; f += array59[0].x; f += array60[0].x;
|
||||
+ f += array61[0].x; f += array62[0].x; f += array63[0].x; f += array64[0].x; f += array65[0].x;
|
||||
+ f += array66[0].x; f += array67[0].x; f += array68[0].x; f += array69[0].x; f += array70[0].x;
|
||||
+ f += array71[0].x; f += array72[0].x; f += array73[0].x; f += array74[0].x; f += array75[0].x;
|
||||
+ f += array76[0].x; f += array77[0].x; f += array78[0].x; f += array79[0].x; f += array80[0].x;
|
||||
+ f += array81[0].x; f += array82[0].x; f += array83[0].x; f += array84[0].x; f += array85[0].x;
|
||||
+ f += array86[0].x; f += array87[0].x; f += array88[0].x; f += array89[0].x; f += array90[0].x;
|
||||
+ f += array91[0].x; f += array92[0].x; f += array93[0].x; f += array94[0].x; f += array95[0].x;
|
||||
+ f += array96[0].x; f += array97[0].x; f += array98[0].x; f += array99[0].x; f += array100[0].x;
|
||||
+ f += array101[0].x; f += array102[0].x; f += array103[0].x; f += array104[0].x;
|
||||
+ f += array105[0].x; f += array106[0].x; f += array107[0].x; f += array108[0].x;
|
||||
+ f += array109[0].x; f += array110[0].x; f += array111[0].x; f += array112[0].x;
|
||||
+ f += array113[0].x; f += array114[0].x; f += array115[0].x; f += array116[0].x;
|
||||
+ f += array117[0].x; f += array118[0].x; f += array119[0].x; f += array120[0].x;
|
||||
+ f += array121[0].x; f += array122[0].x; f += array123[0].x; f += array124[0].x;
|
||||
+ f += array125[0].x; f += array126[0].x; f += array127[0].x; f += array128[0].x;
|
||||
+ f += array129[0].x; f += array130[0].x; f += array131[0].x; f += array132[0].x;
|
||||
+ f += array133[0].x; f += array134[0].x; f += array135[0].x; f += array136[0].x;
|
||||
+ f += array137[0].x; f += array138[0].x; f += array139[0].x; f += array140[0].x;
|
||||
+ f += array141[0].x; f += array142[0].x; f += array143[0].x; f += array144[0].x;
|
||||
+ f += array145[0].x; f += array146[0].x; f += array147[0].x; f += array148[0].x;
|
||||
+ f += array149[0].x; f += array150[0].x; f += array151[0].x; f += array152[0].x;
|
||||
+ f += array153[0].x; f += array154[0].x; f += array155[0].x; f += array156[0].x;
|
||||
+ f += array157[0].x; f += array158[0].x; f += array159[0].x; f += array160[0].x;
|
||||
+ f += array161[0].x; f += array162[0].x; f += array163[0].x; f += array164[0].x;
|
||||
+ f += array165[0].x; f += array166[0].x; f += array167[0].x; f += array168[0].x;
|
||||
+ f += array169[0].x; f += array170[0].x; f += array171[0].x; f += array172[0].x;
|
||||
+ f += array173[0].x; f += array174[0].x; f += array175[0].x; f += array176[0].x;
|
||||
+ f += array177[0].x; f += array178[0].x; f += array179[0].x; f += array180[0].x;
|
||||
+ f += array181[0].x; f += array182[0].x; f += array183[0].x; f += array184[0].x;
|
||||
+ f += array185[0].x; f += array186[0].x; f += array187[0].x; f += array188[0].x;
|
||||
+ f += array189[0].x; f += array190[0].x; f += array191[0].x; f += array192[0].x;
|
||||
+ f += array193[0].x; f += array194[0].x; f += array195[0].x; f += array196[0].x;
|
||||
+ f += array197[0].x; f += array198[0].x; f += array199[0].x; f += array200[0].x;
|
||||
+ f += array201[0].x; f += array202[0].x; f += array203[0].x; f += array204[0].x;
|
||||
+ f += array205[0].x; f += array206[0].x; f += array207[0].x; f += array208[0].x;
|
||||
+ f += array209[0].x; f += array210[0].x; f += array211[0].x; f += array212[0].x;
|
||||
+ f += array213[0].x; f += array214[0].x; f += array215[0].x; f += array216[0].x;
|
||||
+ f += array217[0].x; f += array218[0].x; f += array219[0].x; f += array220[0].x;
|
||||
+ f += array221[0].x; f += array222[0].x; f += array223[0].x; f += array224[0].x;
|
||||
+ f += array225[0].x; f += array226[0].x; f += array227[0].x; f += array228[0].x;
|
||||
+ f += array229[0].x; f += array230[0].x; f += array231[0].x; f += array232[0].x;
|
||||
+ f += array233[0].x; f += array234[0].x; f += array235[0].x; f += array236[0].x;
|
||||
+ f += array237[0].x; f += array238[0].x; f += array239[0].x; f += array240[0].x;
|
||||
+ f += array241[0].x; f += array242[0].x; f += array243[0].x; f += array244[0].x;
|
||||
+ f += array245[0].x; f += array246[0].x; f += array247[0].x; f += array248[0].x;
|
||||
+ f += array249[0].x; f += array250[0].x; f += array251[0].x; f += array252[0].x;
|
||||
+ f += array253[0].x; f += array254[0].x; f += array255[0].x; f += array256[0].x;
|
||||
+ if (f == 2.0)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1);
|
||||
EXPECT_EQ(0u, program);
|
||||
|
||||
@@ -5449,6 +5574,9 @@
|
||||
|
||||
program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
|
||||
EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemoryOverflow);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
}
|
||||
|
||||
// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
|
||||
42
patches/angle/cherry-pick-5486190be556.patch
Normal file
42
patches/angle/cherry-pick-5486190be556.patch
Normal file
@@ -0,0 +1,42 @@
|
||||
From 5486190be5565f9b5567fbd252a10425af3d59ee Mon Sep 17 00:00:00 2001
|
||||
From: Geoff Lang <geofflang@chromium.org>
|
||||
Date: Fri, 21 Jul 2023 13:45:52 -0400
|
||||
Subject: [PATCH] [M114-LTS] Fix read size validation for RGBX formats.
|
||||
|
||||
GL_RGBX8_ANGLE is the only format where the upload format is 3-channel
|
||||
RGB, whilethe download format is 4-channel RGBX. As such, the internal
|
||||
format corresponding to format+type expects 3-byte input/output. The
|
||||
format is fixed here for readPixels to output 4 bytes per pixel.
|
||||
|
||||
Bug: chromium:1458046
|
||||
Change-Id: Iec737ed64bade003cfab50dc5f595eb4875e81e4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4706957
|
||||
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
(cherry picked from commit 430a4f559cbc2bcd5d026e8b36ee46ddd80e9651)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4765136
|
||||
Commit-Queue: Daniel Yip <danielyip@google.com>
|
||||
Auto-Submit: Daniel Yip <danielyip@google.com>
|
||||
(cherry picked from commit 4a372ad49ceddea6c13f79adb212a777ec770a66)
|
||||
---
|
||||
|
||||
diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp
|
||||
index f2845dc..bb1389aaa 100644
|
||||
--- a/src/libANGLE/formatutils.cpp
|
||||
+++ b/src/libANGLE/formatutils.cpp
|
||||
@@ -1702,7 +1702,15 @@
|
||||
GLuint InternalFormat::computePixelBytes(GLenum formatType) const
|
||||
{
|
||||
const auto &typeInfo = GetTypeInfo(formatType);
|
||||
- GLuint components = typeInfo.specialInterpretation ? 1u : componentCount;
|
||||
+ GLuint components = componentCount;
|
||||
+ if (sizedInternalFormat == GL_RGBX8_ANGLE)
|
||||
+ {
|
||||
+ components = 4;
|
||||
+ }
|
||||
+ else if (typeInfo.specialInterpretation)
|
||||
+ {
|
||||
+ components = 1;
|
||||
+ }
|
||||
return components * typeInfo.bytes;
|
||||
}
|
||||
|
||||
286
patches/angle/cherry-pick-cafe56b591ed.patch
Normal file
286
patches/angle/cherry-pick-cafe56b591ed.patch
Normal file
@@ -0,0 +1,286 @@
|
||||
From cafe56b591edb77f041be70b58cac3a61565644a Mon Sep 17 00:00:00 2001
|
||||
From: Geoff Lang <geofflang@chromium.org>
|
||||
Date: Fri, 23 Jun 2023 14:46:28 -0400
|
||||
Subject: [PATCH] M116: GL: Ensure all instanced attributes have a buffer with data
|
||||
|
||||
Apple OpenGL drivers sometimes crash when given an instanced draw with
|
||||
a buffer that has never been given data.
|
||||
|
||||
It's not efficient to check if the attribute is both zero-sized and
|
||||
instanced so just ensure that every time a zero-sized buffer is bound
|
||||
to an attribute, it gets initialized with some data.
|
||||
|
||||
Bug: chromium:1456243
|
||||
Change-Id: I66b7c7017843153db2df3bc50010cba765d03c5f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4642048
|
||||
Commit-Queue: Geoff Lang <geofflang@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
(cherry picked from commit 4e6124dae892690204f8e5996aeaad14f45e0a97)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4727452
|
||||
---
|
||||
|
||||
diff --git a/include/platform/FeaturesGL_autogen.h b/include/platform/FeaturesGL_autogen.h
|
||||
index aa0565c..2f6e094 100644
|
||||
--- a/include/platform/FeaturesGL_autogen.h
|
||||
+++ b/include/platform/FeaturesGL_autogen.h
|
||||
@@ -501,6 +501,12 @@
|
||||
"supportsShaderPixelLocalStorageEXT", FeatureCategory::OpenGLFeatures,
|
||||
"Backend GL context supports EXT_shader_pixel_local_storage extension", &members,
|
||||
"http://anglebug.com/7279"};
|
||||
+
|
||||
+ FeatureInfo ensureNonEmptyBufferIsBoundForDraw = {
|
||||
+ "ensureNonEmptyBufferIsBoundForDraw", FeatureCategory::OpenGLFeatures,
|
||||
+ "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero "
|
||||
+ "divisor.",
|
||||
+ &members, "http://crbug.com/1456243"};
|
||||
};
|
||||
|
||||
inline FeaturesGL::FeaturesGL() = default;
|
||||
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json
|
||||
index 032f29a..b358cea 100644
|
||||
--- a/include/platform/gl_features.json
|
||||
+++ b/include/platform/gl_features.json
|
||||
@@ -699,6 +699,14 @@
|
||||
"Backend GL context supports EXT_shader_pixel_local_storage extension"
|
||||
],
|
||||
"issue": "http://anglebug.com/7279"
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "ensure_non_empty_buffer_is_bound_for_draw",
|
||||
+ "category": "Features",
|
||||
+ "description": [
|
||||
+ "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero divisor."
|
||||
+ ],
|
||||
+ "issue": "http://crbug.com/1456243"
|
||||
}
|
||||
]
|
||||
}
|
||||
diff --git a/scripts/code_generation_hashes/ANGLE_features.json b/scripts/code_generation_hashes/ANGLE_features.json
|
||||
index d4576c2..503001c 100644
|
||||
--- a/scripts/code_generation_hashes/ANGLE_features.json
|
||||
+++ b/scripts/code_generation_hashes/ANGLE_features.json
|
||||
@@ -2,7 +2,7 @@
|
||||
"include/platform/FeaturesD3D_autogen.h":
|
||||
"9923fb44d0a6f31948d0c8f46ee1d9e2",
|
||||
"include/platform/FeaturesGL_autogen.h":
|
||||
- "a795a806d71b0e6d1f9e6d95c6e11971",
|
||||
+ "fef16ab3946346a2a7d5b76bb39471a4",
|
||||
"include/platform/FeaturesMtl_autogen.h":
|
||||
"407426c8874de9295482ace9c94bd812",
|
||||
"include/platform/FeaturesVk_autogen.h":
|
||||
@@ -16,13 +16,13 @@
|
||||
"include/platform/gen_features.py":
|
||||
"062989f7a8f3ff3b383f98fc8908dc33",
|
||||
"include/platform/gl_features.json":
|
||||
- "3335055a70e35ebb7bf74c6d7c58897b",
|
||||
+ "c9aead89696e7fd0c8bfe5c5ca85ca63",
|
||||
"include/platform/mtl_features.json":
|
||||
"c66d170e7a8eb3448030f4c423ed0133",
|
||||
"include/platform/vk_features.json":
|
||||
"416bbb28b9fa1a3c4ef141f243c0a9e6",
|
||||
"util/angle_features_autogen.cpp":
|
||||
- "73169f63c755192c3b4bd27d6f4096ca",
|
||||
+ "288daaec490eb816883d744f108d74c9",
|
||||
"util/angle_features_autogen.h":
|
||||
- "7aa8120eb8f8fd335946b8c27074745d"
|
||||
+ "daf25d3e4ffea143d1c082416513f7e7"
|
||||
}
|
||||
\ No newline at end of file
|
||||
diff --git a/src/libANGLE/renderer/gl/BufferGL.cpp b/src/libANGLE/renderer/gl/BufferGL.cpp
|
||||
index c99fd5d..9651838 100644
|
||||
--- a/src/libANGLE/renderer/gl/BufferGL.cpp
|
||||
+++ b/src/libANGLE/renderer/gl/BufferGL.cpp
|
||||
@@ -296,6 +296,11 @@
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
+size_t BufferGL::getBufferSize() const
|
||||
+{
|
||||
+ return mBufferSize;
|
||||
+}
|
||||
+
|
||||
GLuint BufferGL::getBufferID() const
|
||||
{
|
||||
return mBufferID;
|
||||
diff --git a/src/libANGLE/renderer/gl/BufferGL.h b/src/libANGLE/renderer/gl/BufferGL.h
|
||||
index 7b57594..fe9138e 100644
|
||||
--- a/src/libANGLE/renderer/gl/BufferGL.h
|
||||
+++ b/src/libANGLE/renderer/gl/BufferGL.h
|
||||
@@ -56,6 +56,7 @@
|
||||
bool primitiveRestartEnabled,
|
||||
gl::IndexRange *outRange) override;
|
||||
|
||||
+ size_t getBufferSize() const;
|
||||
GLuint getBufferID() const;
|
||||
|
||||
private:
|
||||
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
|
||||
index dc981de..fda9099 100644
|
||||
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
|
||||
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
|
||||
@@ -646,6 +646,7 @@
|
||||
|
||||
angle::Result VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
|
||||
{
|
||||
+ const angle::FeaturesGL &features = GetFeaturesGL(context);
|
||||
|
||||
const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
|
||||
|
||||
@@ -687,8 +688,16 @@
|
||||
// is not NULL.
|
||||
|
||||
StateManagerGL *stateManager = GetStateManagerGL(context);
|
||||
- GLuint bufferId = GetNativeBufferID(arrayBuffer);
|
||||
+ BufferGL *bufferGL = GetImplAs<BufferGL>(arrayBuffer);
|
||||
+ GLuint bufferId = bufferGL->getBufferID();
|
||||
stateManager->bindBuffer(gl::BufferBinding::Array, bufferId);
|
||||
+ if (features.ensureNonEmptyBufferIsBoundForDraw.enabled && bufferGL->getBufferSize() == 0)
|
||||
+ {
|
||||
+ constexpr uint32_t data = 0;
|
||||
+ ANGLE_TRY(bufferGL->setData(context, gl::BufferBinding::Array, &data, sizeof(data),
|
||||
+ gl::BufferUsage::StaticDraw));
|
||||
+ ASSERT(bufferGL->getBufferSize() > 0);
|
||||
+ }
|
||||
ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(attribIndex), attrib,
|
||||
binding.getStride(), binding.getOffset()));
|
||||
|
||||
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
|
||||
index 6911247..ab2a608 100644
|
||||
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
|
||||
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
|
||||
@@ -2465,6 +2465,9 @@
|
||||
// EXT_shader_pixel_local_storage
|
||||
ANGLE_FEATURE_CONDITION(features, supportsShaderPixelLocalStorageEXT,
|
||||
functions->hasGLESExtension("GL_EXT_shader_pixel_local_storage"));
|
||||
+
|
||||
+ // http://crbug.com/1456243
|
||||
+ ANGLE_FEATURE_CONDITION(features, ensureNonEmptyBufferIsBoundForDraw, IsApple() || IsAndroid());
|
||||
}
|
||||
|
||||
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index 59ec7c2..44ff3e4 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -380,6 +380,7 @@
|
||||
7294 WIN D3D11 : StateChangeTestES3.StencilWriteMask/* = SKIP
|
||||
7316 WIN D3D11 : StateChangeTestES3.StencilTestAndFunc/* = SKIP
|
||||
7329 WIN D3D11 : StateChangeTestES3.PrimitiveRestart/* = SKIP
|
||||
+1456243 WIN D3D11 : WebGL2CompatibilityTest.DrawWithZeroSizedBuffer/* = SKIP
|
||||
|
||||
// Android
|
||||
6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index 7dc56cd..bd7ecd1 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -1632,10 +1632,10 @@
|
||||
|
||||
constexpr GLuint kMaxIntAsGLuint = static_cast<GLuint>(std::numeric_limits<GLint>::max());
|
||||
constexpr GLuint kIndexData[] = {
|
||||
- kMaxIntAsGLuint,
|
||||
- kMaxIntAsGLuint + 1,
|
||||
- kMaxIntAsGLuint + 2,
|
||||
- kMaxIntAsGLuint + 3,
|
||||
+ kMaxIntAsGLuint,
|
||||
+ kMaxIntAsGLuint + 1,
|
||||
+ kMaxIntAsGLuint + 2,
|
||||
+ kMaxIntAsGLuint + 3,
|
||||
};
|
||||
|
||||
GLBuffer indexBuffer;
|
||||
@@ -3687,8 +3687,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -3748,8 +3748,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -3811,8 +3811,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -3874,8 +3874,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -5803,6 +5803,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
+// Test for a mishandling of instanced vertex attributes with zero-sized buffers bound on Apple
|
||||
+// OpenGL drivers.
|
||||
+TEST_P(WebGL2CompatibilityTest, DrawWithZeroSizedBuffer)
|
||||
+{
|
||||
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
|
||||
+ glUseProgram(program);
|
||||
+
|
||||
+ GLBuffer buffer;
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
+
|
||||
+ GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
|
||||
+ glEnableVertexAttribArray(posLocation);
|
||||
+
|
||||
+ glVertexAttribDivisor(posLocation, 1);
|
||||
+ glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 9,
|
||||
+ reinterpret_cast<void *>(0x41424344));
|
||||
+
|
||||
+ glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
+}
|
||||
+
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest);
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2CompatibilityTest);
|
||||
diff --git a/util/angle_features_autogen.cpp b/util/angle_features_autogen.cpp
|
||||
index adb9610..a060dd2 100644
|
||||
--- a/util/angle_features_autogen.cpp
|
||||
+++ b/util/angle_features_autogen.cpp
|
||||
@@ -118,6 +118,7 @@
|
||||
{Feature::EnablePrecisionQualifiers, "enablePrecisionQualifiers"},
|
||||
{Feature::EnablePreRotateSurfaces, "enablePreRotateSurfaces"},
|
||||
{Feature::EnableProgramBinaryForCapture, "enableProgramBinaryForCapture"},
|
||||
+ {Feature::EnsureNonEmptyBufferIsBoundForDraw, "ensureNonEmptyBufferIsBoundForDraw"},
|
||||
{Feature::ExpandIntegerPowExpressions, "expandIntegerPowExpressions"},
|
||||
{Feature::ExplicitlyEnablePerSampleShading, "explicitlyEnablePerSampleShading"},
|
||||
{Feature::ExposeNonConformantExtensionsAndVersions, "exposeNonConformantExtensionsAndVersions"},
|
||||
diff --git a/util/angle_features_autogen.h b/util/angle_features_autogen.h
|
||||
index 3d8c47f..4064425 100644
|
||||
--- a/util/angle_features_autogen.h
|
||||
+++ b/util/angle_features_autogen.h
|
||||
@@ -112,6 +112,7 @@
|
||||
EnablePrecisionQualifiers,
|
||||
EnablePreRotateSurfaces,
|
||||
EnableProgramBinaryForCapture,
|
||||
+ EnsureNonEmptyBufferIsBoundForDraw,
|
||||
ExpandIntegerPowExpressions,
|
||||
ExplicitlyEnablePerSampleShading,
|
||||
ExposeNonConformantExtensionsAndVersions,
|
||||
208
patches/angle/cherry-pick-d0ee0197ddff.patch
Normal file
208
patches/angle/cherry-pick-d0ee0197ddff.patch
Normal file
@@ -0,0 +1,208 @@
|
||||
From d0ee0197ddff25fe1a9876511c07542ac483702d Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Wed, 03 May 2023 13:41:36 -0400
|
||||
Subject: [PATCH] WebGL: Limit total size of private data
|
||||
|
||||
... not just individual arrays.
|
||||
|
||||
Bug: chromium:1431761
|
||||
Change-Id: I721e29aeceeaf12c3f6a67b668abffb8dfbc89b0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4503753
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
---
|
||||
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index 6097b6d..2a033ad 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -35,7 +35,9 @@
|
||||
{
|
||||
public:
|
||||
ValidateTypeSizeLimitationsTraverser(TSymbolTable *symbolTable, TDiagnostics *diagnostics)
|
||||
- : TIntermTraverser(true, false, false, symbolTable), mDiagnostics(diagnostics)
|
||||
+ : TIntermTraverser(true, false, false, symbolTable),
|
||||
+ mDiagnostics(diagnostics),
|
||||
+ mTotalPrivateVariablesSize(0)
|
||||
{
|
||||
ASSERT(diagnostics);
|
||||
}
|
||||
@@ -93,18 +95,33 @@
|
||||
const bool isPrivate = variableType.getQualifier() == EvqTemporary ||
|
||||
variableType.getQualifier() == EvqGlobal ||
|
||||
variableType.getQualifier() == EvqConst;
|
||||
- if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes && isPrivate)
|
||||
+ if (isPrivate)
|
||||
{
|
||||
- error(asSymbol->getLine(),
|
||||
- "Size of declared private variable exceeds implementation-defined limit",
|
||||
- asSymbol->getName());
|
||||
- return false;
|
||||
+ if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes)
|
||||
+ {
|
||||
+ error(asSymbol->getLine(),
|
||||
+ "Size of declared private variable exceeds implementation-defined limit",
|
||||
+ asSymbol->getName());
|
||||
+ return false;
|
||||
+ }
|
||||
+ mTotalPrivateVariablesSize += layoutEncoder.getCurrentOffset();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+ void validateTotalPrivateVariableSize()
|
||||
+ {
|
||||
+ if (mTotalPrivateVariablesSize > kMaxPrivateVariableSizeInBytes)
|
||||
+ {
|
||||
+ mDiagnostics->error(
|
||||
+ TSourceLoc{},
|
||||
+ "Total size of declared private variables exceeds implementation-defined limit",
|
||||
+ "");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
void error(TSourceLoc loc, const char *reason, const ImmutableString &token)
|
||||
{
|
||||
@@ -213,6 +230,8 @@
|
||||
|
||||
TDiagnostics *mDiagnostics;
|
||||
std::vector<int> mLoopSymbolIds;
|
||||
+
|
||||
+ size_t mTotalPrivateVariablesSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -223,6 +242,7 @@
|
||||
{
|
||||
ValidateTypeSizeLimitationsTraverser validate(symbolTable, diagnostics);
|
||||
root->traverse(&validate);
|
||||
+ validate.validateTotalPrivateVariableSize();
|
||||
return diagnostics->numErrors() == 0;
|
||||
}
|
||||
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index e62c8fb..996bad1 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5271,11 +5271,12 @@
|
||||
// fairly small array.
|
||||
constexpr char kVSArrayOK[] =
|
||||
R"(varying vec4 color;
|
||||
-const int array_size = 1000;
|
||||
+const int array_size = 500;
|
||||
void main()
|
||||
{
|
||||
mat2 array[array_size];
|
||||
- if (array[0][0][0] == 2.0)
|
||||
+ mat2 array2[array_size];
|
||||
+ if (array[0][0][0] + array2[0][0][0] == 2.0)
|
||||
color = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
else
|
||||
color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
@@ -5353,6 +5354,103 @@
|
||||
EXPECT_EQ(0u, program);
|
||||
}
|
||||
|
||||
+// Reject attempts to allocate too much private memory.
|
||||
+// This is an implementation-defined limit - crbug.com/1431761.
|
||||
+TEST_P(WebGLCompatibilityTest, ValidateTotalPrivateSize)
|
||||
+{
|
||||
+ constexpr char kTooLargeGlobalMemory1[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32768];
|
||||
+vec4 array2[32769];
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ if (array[0].x + array[1].x == 0.)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ constexpr char kTooLargeGlobalMemory2[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32767];
|
||||
+vec4 array2[32767];
|
||||
+vec4 x, y, z;
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ if (array[0].x + array[1].x == x.w + y.w + z.w)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ constexpr char kTooLargeGlobalAndLocalMemory1[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32768];
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ vec4 array2[32769];
|
||||
+ if (array[0].x + array[1].x == 2.0)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ // Note: The call stack is not taken into account for the purposes of total memory calculation.
|
||||
+ constexpr char kTooLargeGlobalAndLocalMemory2[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32768];
|
||||
+
|
||||
+float f()
|
||||
+{
|
||||
+ vec4 array2[16384];
|
||||
+ return array2[0].x;
|
||||
+}
|
||||
+
|
||||
+float g()
|
||||
+{
|
||||
+ vec4 array3[16383];
|
||||
+ return array3[0].x;
|
||||
+}
|
||||
+
|
||||
+float h()
|
||||
+{
|
||||
+ vec4 value;
|
||||
+ float value2
|
||||
+ return value.x + value2;
|
||||
+}
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ if (array[0].x + f() + g() + h() == 2.0)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory2);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory1);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+}
|
||||
+
|
||||
// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
|
||||
// qualifiers.
|
||||
TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
|
||||
396
patches/angle/cherry-pick-e4669a74888d.patch
Normal file
396
patches/angle/cherry-pick-e4669a74888d.patch
Normal file
@@ -0,0 +1,396 @@
|
||||
From e4669a74888d7f9bd93d79f72829d576776dfb8a Mon Sep 17 00:00:00 2001
|
||||
From: Charlie Lao <cclao@google.com>
|
||||
Date: Tue, 08 Aug 2023 10:14:47 -0700
|
||||
Subject: [PATCH] [M114-LTS] Vulkan: Fix data race with DynamicDescriptorPool
|
||||
|
||||
Right now DynamicDescriptorPool::destroyCachedDescriptorSet can be
|
||||
called from garbage clean up thread, while simultaneously accessed from
|
||||
context main thread, and data race will happen and cause bugs. This can
|
||||
only happen when the buffer is not being suballocated. In this case,
|
||||
suballocation owns the bufferBlock and bufferBlock gets destroyed when
|
||||
suballocation is destroyed from garbage collection thread. If buffer is
|
||||
suballocated, the shared group owns pool which owns bufferBlocks and
|
||||
they gets destroyed from shared group with the share group lock. This CL
|
||||
avoids this race problem by release the shared cacheKey when the buffer
|
||||
is released, while we still had the shared group lock.
|
||||
|
||||
Bug: chromium:1469542
|
||||
Change-Id: Ie6235fcfb77dee2a12b2ebde44042c3845fc0aca
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4790523
|
||||
(cherry picked from commit b48983ab8c74d2fcd9ef17c80727affb9e690c53)
|
||||
---
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp
|
||||
index 2e07deb..93a1092 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/BufferVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp
|
||||
@@ -305,7 +305,7 @@
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
if (mBuffer.valid())
|
||||
{
|
||||
- mBuffer.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ mBuffer.releaseBufferAndDescriptorSetCache(renderer);
|
||||
}
|
||||
if (mStagingBuffer.valid())
|
||||
{
|
||||
@@ -623,7 +623,7 @@
|
||||
memcpy(dstMapPtr, srcMapPtr, static_cast<size_t>(mState.getSize()));
|
||||
}
|
||||
|
||||
- src.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ src.releaseBufferAndDescriptorSetCache(contextVk->getRenderer());
|
||||
|
||||
// Return the already mapped pointer with the offset adjustment to avoid the call to unmap().
|
||||
*mapPtr = dstMapPtr + offset;
|
||||
@@ -1029,7 +1029,7 @@
|
||||
|
||||
if (prevBuffer.valid())
|
||||
{
|
||||
- prevBuffer.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ prevBuffer.releaseBufferAndDescriptorSetCache(contextVk->getRenderer());
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
@@ -1151,7 +1151,7 @@
|
||||
|
||||
if (mBuffer.valid())
|
||||
{
|
||||
- mBuffer.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ mBuffer.releaseBufferAndDescriptorSetCache(renderer);
|
||||
}
|
||||
|
||||
// Allocate the buffer directly
|
||||
diff --git a/src/libANGLE/renderer/vulkan/Suballocation.h b/src/libANGLE/renderer/vulkan/Suballocation.h
|
||||
index d25481b..276f6b4 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/Suballocation.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/Suballocation.h
|
||||
@@ -86,6 +86,13 @@
|
||||
{
|
||||
mDescriptorSetCacheManager.addKey(sharedCacheKey);
|
||||
}
|
||||
+ void releaseAllCachedDescriptorSetCacheKeys(RendererVk *renderer)
|
||||
+ {
|
||||
+ if (!mDescriptorSetCacheManager.empty())
|
||||
+ {
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
private:
|
||||
mutable std::mutex mVirtualBlockMutex;
|
||||
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
index d43c172..5e6419f 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
@@ -1623,7 +1623,7 @@
|
||||
onStateChange(angle::SubjectMessage::SubjectChanged);
|
||||
}
|
||||
mRedefinedLevels.reset();
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(contextVk->getRenderer());
|
||||
}
|
||||
|
||||
void TextureVk::initImageUsageFlags(ContextVk *contextVk, angle::FormatID actualFormatID)
|
||||
@@ -2857,7 +2857,7 @@
|
||||
|
||||
mBufferViews.release(contextVk);
|
||||
mBufferViews.init(renderer, offset, size);
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -3300,7 +3300,7 @@
|
||||
{
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
|
||||
if (mImage == nullptr)
|
||||
{
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
|
||||
index f750428..ae86b29 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
|
||||
@@ -2589,11 +2589,19 @@
|
||||
{
|
||||
contextVk->getShareGroup()->getFramebufferCache().erase(contextVk, desc);
|
||||
}
|
||||
+void ReleaseCachedObject(RendererVk *renderer, const FramebufferDesc &desc)
|
||||
+{
|
||||
+ UNREACHABLE();
|
||||
+}
|
||||
|
||||
void ReleaseCachedObject(ContextVk *contextVk, const DescriptorSetDescAndPool &descAndPool)
|
||||
{
|
||||
+ UNREACHABLE();
|
||||
+}
|
||||
+void ReleaseCachedObject(RendererVk *renderer, const DescriptorSetDescAndPool &descAndPool)
|
||||
+{
|
||||
ASSERT(descAndPool.mPool != nullptr);
|
||||
- descAndPool.mPool->releaseCachedDescriptorSet(contextVk, descAndPool.mDesc);
|
||||
+ descAndPool.mPool->releaseCachedDescriptorSet(renderer, descAndPool.mDesc);
|
||||
}
|
||||
|
||||
void DestroyCachedObject(RendererVk *renderer, const FramebufferDesc &desc)
|
||||
@@ -6261,6 +6269,22 @@
|
||||
}
|
||||
|
||||
template <class SharedCacheKeyT>
|
||||
+void SharedCacheKeyManager<SharedCacheKeyT>::releaseKeys(RendererVk *renderer)
|
||||
+{
|
||||
+ for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
|
||||
+ {
|
||||
+ if (*sharedCacheKey.get() != nullptr)
|
||||
+ {
|
||||
+ // Immediate destroy the cached object and the key itself when first releaseKeys call is
|
||||
+ // made
|
||||
+ ReleaseCachedObject(renderer, *(*sharedCacheKey.get()));
|
||||
+ *sharedCacheKey.get() = nullptr;
|
||||
+ }
|
||||
+ }
|
||||
+ mSharedCacheKeys.clear();
|
||||
+}
|
||||
+
|
||||
+template <class SharedCacheKeyT>
|
||||
void SharedCacheKeyManager<SharedCacheKeyT>::destroyKeys(RendererVk *renderer)
|
||||
{
|
||||
for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.h b/src/libANGLE/renderer/vulkan/vk_cache_utils.h
|
||||
index 8c9d452..f85459a 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_cache_utils.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.h
|
||||
@@ -1932,6 +1932,7 @@
|
||||
void addKey(const SharedCacheKeyT &key);
|
||||
// Iterate over the descriptor array and release the descriptor and cache.
|
||||
void releaseKeys(ContextVk *contextVk);
|
||||
+ void releaseKeys(RendererVk *rendererVk);
|
||||
// Iterate over the descriptor array and destroy the descriptor and cache.
|
||||
void destroyKeys(RendererVk *renderer);
|
||||
void clear();
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
index 9088e09bf..8bc027d 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
@@ -3798,7 +3798,7 @@
|
||||
return mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool);
|
||||
}
|
||||
|
||||
-void DynamicDescriptorPool::releaseCachedDescriptorSet(ContextVk *contextVk,
|
||||
+void DynamicDescriptorPool::releaseCachedDescriptorSet(RendererVk *renderer,
|
||||
const DescriptorSetDesc &desc)
|
||||
{
|
||||
VkDescriptorSet descriptorSet;
|
||||
@@ -3812,7 +3812,7 @@
|
||||
// Wrap it with helper object so that it can be GPU tracked and add it to resource list.
|
||||
DescriptorSetHelper descriptorSetHelper(poolOut->get().getResourceUse(), descriptorSet);
|
||||
poolOut->get().addGarbage(std::move(descriptorSetHelper));
|
||||
- checkAndReleaseUnusedPool(contextVk->getRenderer(), poolOut);
|
||||
+ checkAndReleaseUnusedPool(renderer, poolOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5016,6 +5016,12 @@
|
||||
|
||||
if (mSuballocation.valid())
|
||||
{
|
||||
+ if (!mSuballocation.isSuballocated())
|
||||
+ {
|
||||
+ // Destroy cacheKeys now to avoid getting into situation that having to destroy
|
||||
+ // descriptorSet from garbage collection thread.
|
||||
+ mSuballocation.getBufferBlock()->releaseAllCachedDescriptorSetCacheKeys(renderer);
|
||||
+ }
|
||||
renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
|
||||
std::move(mBufferForVertexArray));
|
||||
}
|
||||
@@ -5024,17 +5030,15 @@
|
||||
ASSERT(!mBufferForVertexArray.valid());
|
||||
}
|
||||
|
||||
-void BufferHelper::releaseBufferAndDescriptorSetCache(ContextVk *contextVk)
|
||||
+void BufferHelper::releaseBufferAndDescriptorSetCache(RendererVk *renderer)
|
||||
{
|
||||
- RendererVk *renderer = contextVk->getRenderer();
|
||||
-
|
||||
if (renderer->hasResourceUseFinished(getResourceUse()))
|
||||
{
|
||||
mDescriptorSetCacheManager.destroyKeys(renderer);
|
||||
}
|
||||
else
|
||||
{
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
}
|
||||
|
||||
release(renderer);
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
|
||||
index d2405b6..962dfe8 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
|
||||
@@ -252,7 +252,7 @@
|
||||
VkDescriptorSet *descriptorSetOut,
|
||||
SharedDescriptorSetCacheKey *sharedCacheKeyOut);
|
||||
|
||||
- void releaseCachedDescriptorSet(ContextVk *contextVk, const DescriptorSetDesc &desc);
|
||||
+ void releaseCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc);
|
||||
void destroyCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc);
|
||||
|
||||
template <typename Accumulator>
|
||||
@@ -777,7 +777,7 @@
|
||||
|
||||
void destroy(RendererVk *renderer);
|
||||
void release(RendererVk *renderer);
|
||||
- void releaseBufferAndDescriptorSetCache(ContextVk *contextVk);
|
||||
+ void releaseBufferAndDescriptorSetCache(RendererVk *renderer);
|
||||
|
||||
BufferSerial getBufferSerial() const { return mSerial; }
|
||||
BufferSerial getBlockSerial() const
|
||||
diff --git a/src/tests/gl_tests/TransformFeedbackTest.cpp b/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
index ea3eeea..226eb1f 100644
|
||||
--- a/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
+++ b/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
@@ -507,8 +507,8 @@
|
||||
|
||||
const std::array<uint32_t, 12> kInitialData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
const std::array<uint32_t, 12> kUpdateData = {
|
||||
- 0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u, 0x23456781u, 0xABCDEF09u,
|
||||
- 0x3579BDF1u, 0x468ACE02u, 0x34567812u, 0xBCDEF09Au, 0x579BDF13u, 0x68ACE024u,
|
||||
+ 0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u, 0x23456781u, 0xABCDEF09u,
|
||||
+ 0x3579BDF1u, 0x468ACE02u, 0x34567812u, 0xBCDEF09Au, 0x579BDF13u, 0x68ACE024u,
|
||||
};
|
||||
|
||||
GLBuffer buffer;
|
||||
@@ -3749,9 +3749,9 @@
|
||||
constexpr size_t kCapturedVaryingsCount = 3;
|
||||
constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {8, 9, 4};
|
||||
const std::vector<float> kExpected[kCapturedVaryingsCount] = {
|
||||
- {0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48},
|
||||
- {0.63, 0.66, 0.69, 0.72, 0.75, 0.78, 0.81, 0.84, 0.87},
|
||||
- {0.25, 0.5, 0.75, 1.0},
|
||||
+ {0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48},
|
||||
+ {0.63, 0.66, 0.69, 0.72, 0.75, 0.78, 0.81, 0.84, 0.87},
|
||||
+ {0.25, 0.5, 0.75, 1.0},
|
||||
};
|
||||
|
||||
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
|
||||
@@ -3848,9 +3848,9 @@
|
||||
constexpr size_t kCapturedVaryingsCount = 3;
|
||||
constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {1, 2, 1};
|
||||
const std::vector<float> kExpected[kCapturedVaryingsCount] = {
|
||||
- {0.25},
|
||||
- {0.5, 0.75},
|
||||
- {1.0},
|
||||
+ {0.25},
|
||||
+ {0.5, 0.75},
|
||||
+ {1.0},
|
||||
};
|
||||
|
||||
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_SEPARATE_ATTRIBS);
|
||||
@@ -4392,6 +4392,51 @@
|
||||
glEndTransformFeedback();
|
||||
}
|
||||
|
||||
+// Test bufferData call and transform feedback.
|
||||
+TEST_P(TransformFeedbackTest, BufferDataAndTransformFeedback)
|
||||
+{
|
||||
+ const char kVS[] = R"(#version 300 es
|
||||
+flat out highp int var;
|
||||
+void main() {
|
||||
+var = 1;
|
||||
+})";
|
||||
+
|
||||
+ const char kFS[] = R"(#version 300 es
|
||||
+flat in highp int var;
|
||||
+out highp int color;
|
||||
+void main() {
|
||||
+color = var;
|
||||
+})";
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
|
||||
+
|
||||
+ GLTexture texture;
|
||||
+ glBindTexture(GL_TEXTURE_2D, texture);
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, 1, 1);
|
||||
+
|
||||
+ GLFramebuffer fbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
+ EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ constexpr int kClearColor[] = {123, 0, 0, 0};
|
||||
+ glClearBufferiv(GL_COLOR, 0, kClearColor);
|
||||
+ glDrawArrays(GL_POINTS, 0, 1);
|
||||
+
|
||||
+ const char *kVarying = "var";
|
||||
+ glTransformFeedbackVaryings(program, 1, &kVarying, GL_INTERLEAVED_ATTRIBS);
|
||||
+ glLinkProgram(program);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+
|
||||
+ GLBuffer buffer;
|
||||
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer);
|
||||
+ glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 0x7ffc * 10000, nullptr, GL_DYNAMIC_READ);
|
||||
+ glBeginTransformFeedback(GL_POINTS);
|
||||
+ glDrawArrays(GL_POINTS, 0, 1);
|
||||
+ glEndTransformFeedback();
|
||||
+ glFlush();
|
||||
+}
|
||||
+
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTest);
|
||||
ANGLE_INSTANTIATE_TEST_ES3_AND(TransformFeedbackTest,
|
||||
ES3_VULKAN()
|
||||
diff --git a/src/tests/gl_tests/UniformBufferTest.cpp b/src/tests/gl_tests/UniformBufferTest.cpp
|
||||
index 4d005c0..71b8504 100644
|
||||
--- a/src/tests/gl_tests/UniformBufferTest.cpp
|
||||
+++ b/src/tests/gl_tests/UniformBufferTest.cpp
|
||||
@@ -3422,6 +3422,50 @@
|
||||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
|
||||
}
|
||||
|
||||
+// Calling BufferData and use it in a loop to force descriptorSet creation and destroy.
|
||||
+TEST_P(UniformBufferTest, BufferDataInLoop)
|
||||
+{
|
||||
+ glClear(GL_COLOR_BUFFER_BIT);
|
||||
+
|
||||
+ // Use large buffer size to get around suballocation, so that we will gets a new buffer with
|
||||
+ // bufferData call.
|
||||
+ static constexpr size_t kBufferSize = 4 * 1024 * 1024;
|
||||
+ std::vector<float> floatData;
|
||||
+ floatData.resize(kBufferSize / (sizeof(float)), 0.0f);
|
||||
+ floatData[0] = 0.5f;
|
||||
+ floatData[1] = 0.75f;
|
||||
+ floatData[2] = 0.25f;
|
||||
+ floatData[3] = 1.0f;
|
||||
+
|
||||
+ GLTexture textures[2];
|
||||
+ GLFramebuffer fbos[2];
|
||||
+ for (int i = 0; i < 2; i++)
|
||||
+ {
|
||||
+ glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
|
||||
+
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[i], 0);
|
||||
+ EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+ }
|
||||
+
|
||||
+ for (int loop = 0; loop < 10; loop++)
|
||||
+ {
|
||||
+ int i = loop & 0x1;
|
||||
+ // Switch FBO to get around deferred flush
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
|
||||
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
|
||||
+ glBufferData(GL_UNIFORM_BUFFER, kBufferSize, floatData.data(), GL_STATIC_DRAW);
|
||||
+
|
||||
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
|
||||
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
|
||||
+ drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
|
||||
+ glFlush();
|
||||
+ }
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
|
||||
+}
|
||||
+
|
||||
class WebGL2UniformBufferTest : public UniformBufferTest
|
||||
{
|
||||
protected:
|
||||
@@ -1,66 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Burda <milan.burda@gmail.com>
|
||||
Date: Mon, 10 Oct 2022 15:11:08 +0400
|
||||
Subject: fix: rename WebSwapCGLLayer to WebSwapCGLLayerChromium
|
||||
|
||||
Class WebSwapCGLLayer is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/Versions/A/Frameworks/libANGLE-shared.dylib (0x23c589b50)
|
||||
and src/out/testing/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib (0x1123f8488).
|
||||
One of the two will be used. Which one is undefined.
|
||||
|
||||
diff --git a/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h b/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h
|
||||
index 7101cd271c07e604c6f5241d1a22f59f446c0033..98a89976f87e32a66bd504951698204fad938d57 100644
|
||||
--- a/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h
|
||||
+++ b/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h
|
||||
@@ -18,7 +18,7 @@ struct __IOSurface;
|
||||
typedef __IOSurface *IOSurfaceRef;
|
||||
|
||||
// WebKit's build process requires that every Objective-C class name has the prefix "Web".
|
||||
-@class WebSwapCGLLayer;
|
||||
+@class WebSwapCGLLayerChromium;
|
||||
|
||||
namespace rx
|
||||
{
|
||||
@@ -89,7 +89,7 @@ class WindowSurfaceCGL : public SurfaceGL
|
||||
gl::Framebuffer *framebuffer) override;
|
||||
|
||||
private:
|
||||
- WebSwapCGLLayer *mSwapLayer;
|
||||
+ WebSwapCGLLayerChromium *mSwapLayer;
|
||||
SharedSwapState mSwapState;
|
||||
uint64_t mCurrentSwapId;
|
||||
|
||||
diff --git a/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm b/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm
|
||||
index 27990e9c2facbbe0e30f4b275e0778a6474fb9ce..84f9fa9b6d31fb0e85a4c4270dff4d935f855c26 100644
|
||||
--- a/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm
|
||||
+++ b/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm
|
||||
@@ -24,7 +24,7 @@
|
||||
# include "libANGLE/renderer/gl/StateManagerGL.h"
|
||||
# include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
|
||||
|
||||
-@interface WebSwapCGLLayer : CAOpenGLLayer {
|
||||
+@interface WebSwapCGLLayerChromium : CAOpenGLLayer {
|
||||
CGLContextObj mDisplayContext;
|
||||
|
||||
bool initialized;
|
||||
@@ -38,7 +38,7 @@ - (id)initWithSharedState:(rx::SharedSwapState *)swapState
|
||||
withFunctions:(const rx::FunctionsGL *)functions;
|
||||
@end
|
||||
|
||||
-@implementation WebSwapCGLLayer
|
||||
+@implementation WebSwapCGLLayerChromium
|
||||
- (id)initWithSharedState:(rx::SharedSwapState *)swapState
|
||||
withContext:(CGLContextObj)displayContext
|
||||
withFunctions:(const rx::FunctionsGL *)functions
|
||||
@@ -220,9 +220,9 @@ - (void)drawInCGLContext:(CGLContextObj)glContext
|
||||
mSwapState.lastRendered = &mSwapState.textures[1];
|
||||
mSwapState.beingPresented = &mSwapState.textures[2];
|
||||
|
||||
- mSwapLayer = [[WebSwapCGLLayer alloc] initWithSharedState:&mSwapState
|
||||
- withContext:mContext
|
||||
- withFunctions:mFunctions];
|
||||
+ mSwapLayer = [[WebSwapCGLLayerChromium alloc] initWithSharedState:&mSwapState
|
||||
+ withContext:mContext
|
||||
+ withFunctions:mFunctions];
|
||||
[mLayer addSublayer:mSwapLayer];
|
||||
[mSwapLayer setContentsScale:[mLayer contentsScale]];
|
||||
|
||||
@@ -20,10 +20,10 @@ index 2ca14efae5ea478f43794a81883b00dfdb1a37b0..d73055fbf39334925ef4b4804bbaca57
|
||||
|
||||
case ssl_open_record_error:
|
||||
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
|
||||
index 86e8eb33e2f99b9a6173550027cfd0812a39614e..f2aac85c096bef42a015135b02936e3d4e9a4c56 100644
|
||||
index 6b4549633585f8a65fb7b285a9be4ba83db355db..f9367d3c050f89011a09b847c29df31f321ffd09 100644
|
||||
--- a/ssl/ssl_lib.cc
|
||||
+++ b/ssl/ssl_lib.cc
|
||||
@@ -1320,7 +1320,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) {
|
||||
@@ -1335,7 +1335,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) {
|
||||
}
|
||||
|
||||
if (ret_code == 0) {
|
||||
@@ -32,7 +32,7 @@ index 86e8eb33e2f99b9a6173550027cfd0812a39614e..f2aac85c096bef42a015135b02936e3d
|
||||
return SSL_ERROR_ZERO_RETURN;
|
||||
}
|
||||
// An EOF was observed which violates the protocol, and the underlying
|
||||
@@ -2597,13 +2597,7 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) {
|
||||
@@ -2624,13 +2624,7 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) {
|
||||
return CRYPTO_get_ex_data(&ctx->ex_data, idx);
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ index 86e8eb33e2f99b9a6173550027cfd0812a39614e..f2aac85c096bef42a015135b02936e3d
|
||||
void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
|
||||
RSA *(*cb)(SSL *ssl, int is_export,
|
||||
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
|
||||
index f51c11efc12209377773204808b85c9cbf5d3bff..d19fd1f9643f99fdd56753a942fccefff08728ac 100644
|
||||
index 854068f44b2bb8f738e41fab059b62ced9309fce..a080edd8b5ec48e433afa45d6246b30e9f7221f0 100644
|
||||
--- a/ssl/ssl_test.cc
|
||||
+++ b/ssl/ssl_test.cc
|
||||
@@ -8460,11 +8460,6 @@ TEST(SSLTest, ErrorSyscallAfterCloseNotify) {
|
||||
@@ -8459,11 +8459,6 @@ TEST(SSLTest, ErrorSyscallAfterCloseNotify) {
|
||||
EXPECT_EQ(ret, 0);
|
||||
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_ZERO_RETURN);
|
||||
|
||||
@@ -63,7 +63,7 @@ index f51c11efc12209377773204808b85c9cbf5d3bff..d19fd1f9643f99fdd56753a942fcceff
|
||||
// Although the client has seen close_notify, it should continue to report
|
||||
// |SSL_ERROR_SYSCALL| when its writes fail.
|
||||
ret = SSL_write(client.get(), data, sizeof(data));
|
||||
@@ -8472,22 +8467,6 @@ TEST(SSLTest, ErrorSyscallAfterCloseNotify) {
|
||||
@@ -8471,22 +8466,6 @@ TEST(SSLTest, ErrorSyscallAfterCloseNotify) {
|
||||
EXPECT_EQ(SSL_get_error(client.get(), ret), SSL_ERROR_SYSCALL);
|
||||
EXPECT_TRUE(write_failed);
|
||||
write_failed = false;
|
||||
|
||||
@@ -124,18 +124,18 @@ chore_introduce_blocking_api_for_electron.patch
|
||||
chore_patch_out_partition_attribute_dcheck_for_webviews.patch
|
||||
expose_v8initializer_codegenerationcheckcallbackinmainthread.patch
|
||||
chore_patch_out_profile_methods_in_profile_selections_cc.patch
|
||||
fix_x11_window_restore_minimized_maximized_window.patch
|
||||
add_gin_converter_support_for_arraybufferview.patch
|
||||
chore_defer_usb_service_getdevices_request_until_usb_service_is.patch
|
||||
revert_x11_keep_windowcache_alive_for_a_time_interval.patch
|
||||
cherry-pick-ec53103cc72d.patch
|
||||
cherry-pick-94af9d13a14b.patch
|
||||
cherry-pick-ea1cd76358e0.patch
|
||||
m114_merge_fix_a_crash_caused_by_calling_trace_event.patch
|
||||
mojoipcz_copy_incoming_messages_early.patch
|
||||
base_do_not_use_va_args_twice_in_asprintf.patch
|
||||
cherry-pick-85beff6fd302.patch
|
||||
cherry-pick-60b93798c991.patch
|
||||
cherry-pick-933b9fad3a53.patch
|
||||
cherry-pick-b03973561862.patch
|
||||
cherry-pick-c60a1ab717c7.patch
|
||||
cherry-pick-48a136e77e6d.patch
|
||||
cherry-pick-e6e23ba00379.patch
|
||||
fix_crash_on_nativetheme_change_during_context_menu_close.patch
|
||||
cherry-pick-aa23556ff213.patch
|
||||
cherry-pick-abb3ebd3d2ef.patch
|
||||
cherry-pick-83b0bdb696d8.patch
|
||||
cherry-pick-e40cb330b645.patch
|
||||
networkcontext_don_t_access_url_loader_factories_during_destruction.patch
|
||||
cherry-pick-1939f7b78eda.patch
|
||||
cherry-pick-37447eb52a74.patch
|
||||
cherry-pick-35c06406a658.patch
|
||||
cherry-pick-74a2eb9c8cb2.patch
|
||||
cherry-pick-26175b0903d8.patch
|
||||
|
||||
@@ -10,10 +10,10 @@ Allows Electron to restore WER when ELECTRON_DEFAULT_ERROR_MODE is set.
|
||||
This should be upstreamed.
|
||||
|
||||
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
|
||||
index 7bf09dd8870040e74cd1a7653665d0806910378c..ec6d1554075ee5454f79e98d0e2e539395499dbe 100644
|
||||
index a399e1ba0e6728aa8d2869864d3c328ba61e779b..b7dd5e0e48af2a88aad11139f5951d917d8d4f9d 100644
|
||||
--- a/content/gpu/gpu_main.cc
|
||||
+++ b/content/gpu/gpu_main.cc
|
||||
@@ -243,6 +243,10 @@ int GpuMain(MainFunctionParams parameters) {
|
||||
@@ -258,6 +258,10 @@ int GpuMain(MainFunctionParams parameters) {
|
||||
// to the GpuProcessHost once the GpuServiceImpl has started.
|
||||
viz::GpuServiceImpl::InstallPreInitializeLogHandler();
|
||||
|
||||
@@ -24,7 +24,7 @@ index 7bf09dd8870040e74cd1a7653665d0806910378c..ec6d1554075ee5454f79e98d0e2e5393
|
||||
// We are experiencing what appear to be memory-stomp issues in the GPU
|
||||
// process. These issues seem to be impacting the task executor and listeners
|
||||
// registered to it. Create the task executor on the heap to guard against
|
||||
@@ -327,7 +331,6 @@ int GpuMain(MainFunctionParams parameters) {
|
||||
@@ -342,7 +346,6 @@ int GpuMain(MainFunctionParams parameters) {
|
||||
const_cast<base::CommandLine*>(&command_line), gpu_preferences);
|
||||
const bool dead_on_arrival = !init_success;
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ DidCreateScriptContext is called, not all JS APIs are available in the
|
||||
context, which can cause some preload scripts to trip.
|
||||
|
||||
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
|
||||
index 6c92a2856e447bdda11c7ed2c64b79b93a0eca26..03dedde2d83e6b09fb7e90be7dfdce246f301d8f 100644
|
||||
index fef4c8e02067c44ed804c8b53db1007fae2d2a76..b36304ee0a832c5e1e2fd3af6151b7b03fd98ec4 100644
|
||||
--- a/content/public/renderer/render_frame_observer.h
|
||||
+++ b/content/public/renderer/render_frame_observer.h
|
||||
@@ -136,6 +136,8 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener,
|
||||
@@ -137,6 +137,8 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener,
|
||||
virtual void DidHandleOnloadEvents() {}
|
||||
virtual void DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
int32_t world_id) {}
|
||||
@@ -23,10 +23,10 @@ index 6c92a2856e447bdda11c7ed2c64b79b93a0eca26..03dedde2d83e6b09fb7e90be7dfdce24
|
||||
int32_t world_id) {}
|
||||
virtual void DidClearWindowObject() {}
|
||||
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
|
||||
index dab59cd51f1f66ff9e712955a880f73ef9e34fd2..0fa592bd37cfef925a8af9aa8ff19177c8e91ae1 100644
|
||||
index 026a6934997f0825c3f2c0a40551ce7784a7b828..5bceb2baec943a2f58416c0ca6093014f9d68d7c 100644
|
||||
--- a/content/renderer/render_frame_impl.cc
|
||||
+++ b/content/renderer/render_frame_impl.cc
|
||||
@@ -4361,6 +4361,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
@@ -4417,6 +4417,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
observer.DidCreateScriptContext(context, world_id);
|
||||
}
|
||||
|
||||
@@ -40,10 +40,10 @@ index dab59cd51f1f66ff9e712955a880f73ef9e34fd2..0fa592bd37cfef925a8af9aa8ff19177
|
||||
int world_id) {
|
||||
for (auto& observer : observers_)
|
||||
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
|
||||
index ff1a05ac05d2df7db3ba3579ddf0d2d329d9782c..72806c4947b7187b54c79a1cd05200183e56d4d1 100644
|
||||
index 516a8140f79cc7f8ffe4b0665184d7d3d6111da9..fce2608070d2bf31b6b02de47102aff870c8229f 100644
|
||||
--- a/content/renderer/render_frame_impl.h
|
||||
+++ b/content/renderer/render_frame_impl.h
|
||||
@@ -605,6 +605,8 @@ class CONTENT_EXPORT RenderFrameImpl
|
||||
@@ -608,6 +608,8 @@ class CONTENT_EXPORT RenderFrameImpl
|
||||
void DidObserveLayoutShift(double score, bool after_input_or_scroll) override;
|
||||
void DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
int world_id) override;
|
||||
@@ -53,10 +53,10 @@ index ff1a05ac05d2df7db3ba3579ddf0d2d329d9782c..72806c4947b7187b54c79a1cd0520018
|
||||
int world_id) override;
|
||||
void DidChangeScrollOffset() override;
|
||||
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
|
||||
index d6bb89671f9d71baa087d6f5cd2ef8d1b048b5ca..44dd685fa2d97451c3c8c06788d8d7384d554bb8 100644
|
||||
index dfd33eede0a8b0935a06eeb8f505a8d0738afa19..06827403830cb730b2521c715ec06aedbf7339c6 100644
|
||||
--- a/third_party/blink/public/web/web_local_frame_client.h
|
||||
+++ b/third_party/blink/public/web/web_local_frame_client.h
|
||||
@@ -599,6 +599,9 @@ class BLINK_EXPORT WebLocalFrameClient {
|
||||
@@ -606,6 +606,9 @@ class BLINK_EXPORT WebLocalFrameClient {
|
||||
virtual void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) {}
|
||||
|
||||
@@ -67,22 +67,22 @@ index d6bb89671f9d71baa087d6f5cd2ef8d1b048b5ca..44dd685fa2d97451c3c8c06788d8d738
|
||||
virtual void WillReleaseScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) {}
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
||||
index 9736b31c03a32635fb8fde581321cc10ec11b11a..c9fd2170a25a7970648b8210ebe94e225f4ee3aa 100644
|
||||
index e7d4256fa96f5bc8ad71bd13b6b33feef32b443f..0dfeda68a4dbfd6b442f8d8f928c8cb871dd6aa4 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
||||
@@ -197,6 +197,7 @@ void LocalWindowProxy::Initialize() {
|
||||
@@ -198,6 +198,7 @@ void LocalWindowProxy::Initialize() {
|
||||
}
|
||||
|
||||
InstallConditionalFeatures();
|
||||
+ GetFrame()->Client()->DidInstallConditionalFeatures(context, world_->GetWorldId());
|
||||
|
||||
if (World().IsMainWorld()) {
|
||||
GetFrame()->Loader().DispatchDidClearWindowObjectInMainWorld();
|
||||
probe::DidCreateMainWorldContext(GetFrame());
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
index 553afb55280410392699855f167d51d2831ac3ca..a9a99e669689b433ce4c63b3c549676ee15255a4 100644
|
||||
index 2c526726ff1ed7008152086210b25103ce308d5b..c62ab44289bf32ac9d40d3df45f6363409f0dea9 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
@@ -317,6 +317,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
|
||||
@@ -315,6 +315,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
|
||||
|
||||
virtual void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) = 0;
|
||||
@@ -92,7 +92,7 @@ index 553afb55280410392699855f167d51d2831ac3ca..a9a99e669689b433ce4c63b3c549676e
|
||||
int32_t world_id) = 0;
|
||||
virtual bool AllowScriptExtensions() = 0;
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
|
||||
index c4a593326e3de8b0c2462a54e13304d14dd7b56a..97bec4188d3aee81d6a22d487ce5364c4120d4b8 100644
|
||||
index 56ad2a8f3fabe03b2c285231d0e99dbcbaf2a9d2..130423e45f17998bf5a28c719115715941ae6620 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
|
||||
@@ -283,6 +283,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
|
||||
@@ -110,10 +110,10 @@ index c4a593326e3de8b0c2462a54e13304d14dd7b56a..97bec4188d3aee81d6a22d487ce5364c
|
||||
v8::Local<v8::Context> context,
|
||||
int32_t world_id) {
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
|
||||
index 5d2c6425dd568b663ff68a31da510784ecf103ab..f1215d23c679aeec484e6f64c41b6df71a75e805 100644
|
||||
index cd3cc4ea62f8956b87c711362520308f062de76e..75dd52f5eb3e6a06cd6185d590ba20e17b7e4e1d 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
|
||||
@@ -82,6 +82,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
|
||||
@@ -83,6 +83,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
|
||||
|
||||
void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) override;
|
||||
@@ -123,10 +123,10 @@ index 5d2c6425dd568b663ff68a31da510784ecf103ab..f1215d23c679aeec484e6f64c41b6df7
|
||||
int32_t world_id) override;
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
index 84e9886e4a27b21ee6d25186a2a7e4039bb81e18..33b23b8d913f94022966dc14e6978dc0481ea231 100644
|
||||
index ca0c223d248a2ae247429059be8a6a139006e55b..20439262e08e74318035460a0f92c981fa6758e1 100644
|
||||
--- a/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
@@ -374,6 +374,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
|
||||
@@ -405,6 +405,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
|
||||
|
||||
void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) override {}
|
||||
|
||||
@@ -7,7 +7,7 @@ Ensure that licenses for the dependencies introduced by Electron
|
||||
are included in `LICENSES.chromium.html`
|
||||
|
||||
diff --git a/tools/licenses/licenses.py b/tools/licenses/licenses.py
|
||||
index e56688f7ab2a8b0ee59d0b7389e4c87370c8fad2..0e09b173574d48a3c7388315fef83f3ec74fe71a 100755
|
||||
index d775931a09f38db3eb472d095d461b50c5ef76f0..9d844edc8f7c2f526fa99804e8a072da1f47c656 100755
|
||||
--- a/tools/licenses/licenses.py
|
||||
+++ b/tools/licenses/licenses.py
|
||||
@@ -383,6 +383,31 @@ SPECIAL_CASES = {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Rose <japthorp@slack-corp.com>
|
||||
Date: Wed, 8 Mar 2023 14:53:17 -0800
|
||||
Subject: add gin::Converter support for ArrayBufferView
|
||||
|
||||
This should be upstreamed.
|
||||
|
||||
diff --git a/gin/converter.cc b/gin/converter.cc
|
||||
index 4eb8c3d8c8392512eeb235bc18012589549b872b..d0432f6fff09cdcebed55ccf03a6524a445ef346 100644
|
||||
--- a/gin/converter.cc
|
||||
+++ b/gin/converter.cc
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "v8/include/v8-value.h"
|
||||
|
||||
using v8::ArrayBuffer;
|
||||
+using v8::ArrayBufferView;
|
||||
using v8::External;
|
||||
using v8::Function;
|
||||
using v8::Int32;
|
||||
@@ -244,6 +245,20 @@ bool Converter<Local<ArrayBuffer>>::FromV8(Isolate* isolate,
|
||||
return true;
|
||||
}
|
||||
|
||||
+Local<Value> Converter<Local<ArrayBufferView>>::ToV8(Isolate* isolate,
|
||||
+ Local<ArrayBufferView> val) {
|
||||
+ return val.As<Value>();
|
||||
+}
|
||||
+
|
||||
+bool Converter<Local<ArrayBufferView>>::FromV8(Isolate* isolate,
|
||||
+ Local<Value> val,
|
||||
+ Local<ArrayBufferView>* out) {
|
||||
+ if (!val->IsArrayBufferView())
|
||||
+ return false;
|
||||
+ *out = Local<ArrayBufferView>::Cast(val);
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
Local<Value> Converter<Local<External>>::ToV8(Isolate* isolate,
|
||||
Local<External> val) {
|
||||
return val.As<Value>();
|
||||
diff --git a/gin/converter.h b/gin/converter.h
|
||||
index eb704fcd56dee861e18e9cd64a857d68dea6f415..d32a8c26403cf32f3333ed85c23292915e6f0681 100644
|
||||
--- a/gin/converter.h
|
||||
+++ b/gin/converter.h
|
||||
@@ -180,6 +180,15 @@ struct GIN_EXPORT Converter<v8::Local<v8::ArrayBuffer> > {
|
||||
v8::Local<v8::ArrayBuffer>* out);
|
||||
};
|
||||
|
||||
+template<>
|
||||
+struct GIN_EXPORT Converter<v8::Local<v8::ArrayBufferView> > {
|
||||
+ static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
+ v8::Local<v8::ArrayBufferView> val);
|
||||
+ static bool FromV8(v8::Isolate* isolate,
|
||||
+ v8::Local<v8::Value> val,
|
||||
+ v8::Local<v8::ArrayBufferView>* out);
|
||||
+};
|
||||
+
|
||||
template<>
|
||||
struct GIN_EXPORT Converter<v8::Local<v8::External> > {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
@@ -8,10 +8,10 @@ decorations in maximized mode where needed, preventing empty space caused
|
||||
by decoration shadows and rounded titlebars around the window while maximized.
|
||||
|
||||
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc
|
||||
index 47a773cb11d59f6edfdb9302ce76fcfaab4eb172..5283069de57e3d13e179862f635453bef6d88681 100644
|
||||
index 99d3dc38ca60dbdc68bcb679067e8fd64e43b06a..7f5c3b103da21d213aa19fe8a4320bec0b7ebeb5 100644
|
||||
--- a/ui/gtk/gtk_ui.cc
|
||||
+++ b/ui/gtk/gtk_ui.cc
|
||||
@@ -480,11 +480,13 @@ std::unique_ptr<ui::NavButtonProvider> GtkUi::CreateNavButtonProvider() {
|
||||
@@ -480,12 +480,13 @@ std::unique_ptr<ui::NavButtonProvider> GtkUi::CreateNavButtonProvider() {
|
||||
return std::make_unique<gtk::NavButtonProviderGtk>();
|
||||
}
|
||||
|
||||
@@ -19,17 +19,19 @@ index 47a773cb11d59f6edfdb9302ce76fcfaab4eb172..5283069de57e3d13e179862f635453be
|
||||
+ui::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame, bool maximized) {
|
||||
auto& provider =
|
||||
- solid_frame ? solid_frame_provider_ : transparent_frame_provider_;
|
||||
- if (!provider) {
|
||||
- provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame);
|
||||
- }
|
||||
+ maximized
|
||||
+ ? (solid_frame ? solid_maximized_frame_provider_ : transparent_maximized_frame_provider_)
|
||||
+ : (solid_frame ? solid_frame_provider_ : transparent_frame_provider_);
|
||||
if (!provider) {
|
||||
- provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame);
|
||||
+ if (!provider)
|
||||
+ provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame, maximized);
|
||||
}
|
||||
return provider.get();
|
||||
}
|
||||
|
||||
diff --git a/ui/gtk/gtk_ui.h b/ui/gtk/gtk_ui.h
|
||||
index adf91ed69c33c5da4ba8cf55d7cbfc482d0762ba..d2fe3b7f0de0fcf848c2be4abc3728d73ee17f5b 100644
|
||||
index adf91ed69c33c5da4ba8cf55d7cbfc482d0762ba..404fccbbe6957ba9309955ef5e7498cdcd0411f0 100644
|
||||
--- a/ui/gtk/gtk_ui.h
|
||||
+++ b/ui/gtk/gtk_ui.h
|
||||
@@ -106,7 +106,7 @@ class GtkUi : public ui::LinuxUiAndTheme {
|
||||
@@ -41,7 +43,7 @@ index adf91ed69c33c5da4ba8cf55d7cbfc482d0762ba..d2fe3b7f0de0fcf848c2be4abc3728d7
|
||||
|
||||
private:
|
||||
using TintMap = std::map<int, color_utils::HSL>;
|
||||
@@ -195,10 +195,13 @@ class GtkUi : public ui::LinuxUiAndTheme {
|
||||
@@ -195,6 +195,8 @@ class GtkUi : public ui::LinuxUiAndTheme {
|
||||
// while Chrome is running.
|
||||
std::unique_ptr<ui::WindowFrameProvider> solid_frame_provider_;
|
||||
std::unique_ptr<ui::WindowFrameProvider> transparent_frame_provider_;
|
||||
@@ -50,13 +52,8 @@ index adf91ed69c33c5da4ba8cf55d7cbfc482d0762ba..d2fe3b7f0de0fcf848c2be4abc3728d7
|
||||
|
||||
// Objects to notify when the window frame button order changes.
|
||||
base::ObserverList<ui::WindowButtonOrderObserver>::Unchecked
|
||||
window_button_order_observer_list_;
|
||||
+
|
||||
};
|
||||
|
||||
} // namespace gtk
|
||||
diff --git a/ui/gtk/window_frame_provider_gtk.cc b/ui/gtk/window_frame_provider_gtk.cc
|
||||
index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c9f1b94fa 100644
|
||||
index 1925c1a2763b8dd720f5d0a630bc98ec5d16b9a0..a4986477b46aef555d526851cf191650d2972238 100644
|
||||
--- a/ui/gtk/window_frame_provider_gtk.cc
|
||||
+++ b/ui/gtk/window_frame_provider_gtk.cc
|
||||
@@ -39,16 +39,18 @@ std::string GetThemeName() {
|
||||
@@ -65,7 +62,7 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
|
||||
-GtkCssContext WindowContext(bool solid_frame, bool focused) {
|
||||
+GtkCssContext WindowContext(bool solid_frame, bool maximized, bool focused) {
|
||||
std::string selector = "#window.background.";
|
||||
std::string selector = "window.background.";
|
||||
selector += solid_frame ? "solid-csd" : "csd";
|
||||
+ if (maximized)
|
||||
+ selector += ".maximized";
|
||||
@@ -80,7 +77,7 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
+ auto context = WindowContext(solid_frame, maximized, focused);
|
||||
// GTK4 renders the decoration directly on the window.
|
||||
if (!GtkCheckVersion(4))
|
||||
context = AppendCssNodeToStyleContext(context, "#decoration");
|
||||
context = AppendCssNodeToStyleContext(context, "decoration");
|
||||
@@ -65,8 +67,8 @@ GtkCssContext DecorationContext(bool solid_frame, bool focused) {
|
||||
return context;
|
||||
}
|
||||
@@ -90,9 +87,9 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
+GtkCssContext HeaderContext(bool solid_frame, bool maximized, bool focused) {
|
||||
+ auto context = WindowContext(solid_frame, maximized, focused);
|
||||
context =
|
||||
AppendCssNodeToStyleContext(context, "#headerbar.header-bar.titlebar");
|
||||
AppendCssNodeToStyleContext(context, "headerbar.header-bar.titlebar");
|
||||
if (!focused)
|
||||
@@ -111,8 +113,8 @@ int ComputeTopCornerRadius() {
|
||||
@@ -121,8 +123,8 @@ int ComputeTopCornerRadius() {
|
||||
// need to experimentally determine the corner radius by rendering a sample.
|
||||
// Additionally, in GTK4, the headerbar corners get clipped by the window
|
||||
// rather than the headerbar having its own rounded corners.
|
||||
@@ -103,16 +100,16 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
ApplyCssToContext(context, R"(window, headerbar {
|
||||
background-image: none;
|
||||
background-color: black;
|
||||
@@ -145,7 +147,7 @@ int ComputeTopCornerRadius() {
|
||||
@@ -155,7 +157,7 @@ int ComputeTopCornerRadius() {
|
||||
bool HeaderIsTranslucent() {
|
||||
// The arbitrary square size to render a sample header.
|
||||
constexpr int kHeaderSize = 32;
|
||||
- auto context = HeaderContext(false, false);
|
||||
+ auto context = HeaderContext(false, false, false);
|
||||
ApplyCssToContext(context, R"(window, headerbar {
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
@@ -197,8 +199,8 @@ void WindowFrameProviderGtk::Asset::CloneFrom(
|
||||
double opacity = 1.0f;
|
||||
GtkStyleContextGet(context, "opacity", &opacity, nullptr);
|
||||
if (opacity < 1.0f)
|
||||
@@ -211,8 +213,8 @@ void WindowFrameProviderGtk::Asset::CloneFrom(
|
||||
unfocused_bitmap = src.unfocused_bitmap;
|
||||
}
|
||||
|
||||
@@ -123,7 +120,7 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
|
||||
WindowFrameProviderGtk::~WindowFrameProviderGtk() = default;
|
||||
|
||||
@@ -305,7 +307,7 @@ void WindowFrameProviderGtk::PaintWindowFrame(
|
||||
@@ -319,7 +321,7 @@ void WindowFrameProviderGtk::PaintWindowFrame(
|
||||
top_area_height_dip * scale - effective_frame_thickness_px.top();
|
||||
|
||||
auto header = PaintHeaderbar({client_bounds_px.width(), top_area_height_px},
|
||||
@@ -132,7 +129,7 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
image = gfx::ImageSkia::CreateFrom1xBitmap(header);
|
||||
// In GTK4, the headerbar gets clipped by the window.
|
||||
if (GtkCheckVersion(4)) {
|
||||
@@ -337,7 +339,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
|
||||
@@ -351,7 +353,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
|
||||
|
||||
gfx::Rect frame_bounds_dip(kMaxFrameSizeDip, kMaxFrameSizeDip,
|
||||
2 * kMaxFrameSizeDip, 2 * kMaxFrameSizeDip);
|
||||
@@ -141,7 +138,7 @@ index e866f32a06abd8b9ee70f2972822b37756878259..d55229238fed1fedba65a969495c9b5c
|
||||
frame_bounds_dip.Inset(-GtkStyleContextGetPadding(focused_context));
|
||||
frame_bounds_dip.Inset(-GtkStyleContextGetBorder(focused_context));
|
||||
gfx::Size bitmap_size(BitmapSizePx(asset), BitmapSizePx(asset));
|
||||
@@ -345,7 +347,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
|
||||
@@ -359,7 +361,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
|
||||
PaintBitmap(bitmap_size, frame_bounds_dip, focused_context, scale);
|
||||
asset.unfocused_bitmap =
|
||||
PaintBitmap(bitmap_size, frame_bounds_dip,
|
||||
@@ -174,10 +171,10 @@ index 32c3d63ae4598339965c58443a8c2d12b99fb89a..91496d957b8291cd37948e237a1cc4bf
|
||||
|
||||
} // namespace gtk
|
||||
diff --git a/ui/linux/fallback_linux_ui.cc b/ui/linux/fallback_linux_ui.cc
|
||||
index ee3e7b96eba0ade61e229aea05f5417e7822a5f5..b393cc2fbc039afa062a8b3ab880c7ff9db8b681 100644
|
||||
index 5f5abeeb78372785d57315056fa61fc65a3848a9..f52f436d674ad54c9973488eec59e26d02866847 100644
|
||||
--- a/ui/linux/fallback_linux_ui.cc
|
||||
+++ b/ui/linux/fallback_linux_ui.cc
|
||||
@@ -134,7 +134,7 @@ FallbackLinuxUi::CreateNavButtonProvider() {
|
||||
@@ -136,7 +136,7 @@ FallbackLinuxUi::CreateNavButtonProvider() {
|
||||
}
|
||||
|
||||
ui::WindowFrameProvider* FallbackLinuxUi::GetWindowFrameProvider(
|
||||
|
||||
@@ -8,10 +8,10 @@ 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 069a4481ca6318215dd8a86b71aa7cacfb635173..605c5b8f8a7e50a22c94c6818cbdd95ced14fc15 100644
|
||||
index 0aef31c1e881fdcb5bfe09fd5ba47b1c5bd861bc..0864450bdcb5577b3ccdf2b6bd97198f283db295 100644
|
||||
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
|
||||
@@ -232,6 +232,16 @@ void ScopedClipboardWriter::WriteEncodedDataTransferEndpointForTesting(
|
||||
@@ -249,6 +249,16 @@ void ScopedClipboardWriter::WriteEncodedDataTransferEndpointForTesting(
|
||||
}
|
||||
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
|
||||
@@ -29,10 +29,10 @@ index 069a4481ca6318215dd8a86b71aa7cacfb635173..605c5b8f8a7e50a22c94c6818cbdd95c
|
||||
objects_.clear();
|
||||
platform_representations_.clear();
|
||||
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
index 2a9964f12a3a17103cd473de74a039d01e117041..873cd66831b7cb4d762d3b7abf5fd08623d3d73b 100644
|
||||
index 569aa7f3673f16c126e7c0b8ea34cac483c7b38d..e494fcc56d4182175943ce0f4190f23a86b9f3a5 100644
|
||||
--- a/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
|
||||
@@ -87,6 +87,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter {
|
||||
@@ -91,6 +91,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);
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: allow disabling blink scheduler throttling per RenderView
|
||||
This allows us to disable throttling for hidden windows.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
|
||||
index 39bd6ef7be6ecb0f22692ace3c77845d76a59391..d51a7418fe874102f0458d1aedbca26e85669da6 100644
|
||||
index 43c8a9913c4b3a4fe0c3151d885c5a13a9fdc74b..0cd8005e743d3bb662c2d439b552a17b1db9b0ab 100644
|
||||
--- a/content/browser/renderer_host/render_view_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_view_host_impl.cc
|
||||
@@ -689,6 +689,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
|
||||
@@ -695,6 +695,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
|
||||
GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ index 39bd6ef7be6ecb0f22692ace3c77845d76a59391..d51a7418fe874102f0458d1aedbca26e
|
||||
return is_active();
|
||||
}
|
||||
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
|
||||
index 574e1f33f7eb9302fc6b64efca23426676821afc..c8509989003da8ca3bbfd13c802f5bd8b81460e5 100644
|
||||
index 180abdc9f983887c83fd9d4a596472222e9ab472..00842717a7570561ee9e3eca11190ab5e1c76fb8 100644
|
||||
--- a/content/browser/renderer_host/render_view_host_impl.h
|
||||
+++ b/content/browser/renderer_host/render_view_host_impl.h
|
||||
@@ -136,6 +136,7 @@ class CONTENT_EXPORT RenderViewHostImpl
|
||||
@@ -33,6 +33,21 @@ index 574e1f33f7eb9302fc6b64efca23426676821afc..c8509989003da8ca3bbfd13c802f5bd8
|
||||
void SendWebPreferencesToRenderer();
|
||||
void SendRendererPreferencesToRenderer(
|
||||
const blink::RendererPreferences& preferences);
|
||||
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
index b69ec986a4d8a96677d785cb6768f0c0d154ff2a..047d1c96a2603fccc3adf645b08575230060d5f7 100644
|
||||
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
@@ -555,8 +555,8 @@ void RenderWidgetHostViewAura::ShowImpl(PageVisibilityState page_visibility) {
|
||||
// OnShowWithPageVisibility will not call NotifyHostAndDelegateOnWasShown,
|
||||
// which updates `visibility_`, unless the host is hidden. Make sure no update
|
||||
// is needed.
|
||||
- DCHECK(host_->is_hidden() || visibility_ == Visibility::VISIBLE);
|
||||
- OnShowWithPageVisibility(page_visibility);
|
||||
+ if (host_->is_hidden() || visibility_ == Visibility::VISIBLE)
|
||||
+ OnShowWithPageVisibility(page_visibility);
|
||||
}
|
||||
|
||||
void RenderWidgetHostViewAura::NotifyHostAndDelegateOnWasShown(
|
||||
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
|
||||
index 9979c25ecd57e68331b628a518368635db5c2027..32733bf951af3eff7da5fd5758bbcbaa49ff0e3c 100644
|
||||
--- a/content/public/browser/render_view_host.h
|
||||
@@ -48,10 +63,10 @@ index 9979c25ecd57e68331b628a518368635db5c2027..32733bf951af3eff7da5fd5758bbcbaa
|
||||
// This interface should only be implemented inside content.
|
||||
friend class RenderViewHostImpl;
|
||||
diff --git a/third_party/blink/public/mojom/page/page.mojom b/third_party/blink/public/mojom/page/page.mojom
|
||||
index 4f543309beff68f67ca310a968b6c0efefdf28cb..e1f132606d2b8c478207b13fdd1464347486cc0b 100644
|
||||
index d18c66114870de83c7eef21578e9e2b8d5606a8b..e1defb3992289427df85963f44a705e3d9257342 100644
|
||||
--- a/third_party/blink/public/mojom/page/page.mojom
|
||||
+++ b/third_party/blink/public/mojom/page/page.mojom
|
||||
@@ -141,4 +141,7 @@ interface PageBroadcast {
|
||||
@@ -149,4 +149,7 @@ interface PageBroadcast {
|
||||
mojo_base.mojom.UnguessableToken devtools_frame_token,
|
||||
RemoteFrameInterfacesFromBrowser remote_frame_interfaces,
|
||||
RemoteMainFrameInterfaces remote_main_frame_interfaces);
|
||||
@@ -60,10 +75,10 @@ index 4f543309beff68f67ca310a968b6c0efefdf28cb..e1f132606d2b8c478207b13fdd146434
|
||||
+ SetSchedulerThrottling(bool allowed);
|
||||
};
|
||||
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
|
||||
index c8655d9270b812df04f27025ff29a2fb6d2a4066..2f83e5ce40f8217ff5d53f7205299ad7ac4d2013 100644
|
||||
index 2c3930e849719dce3871c12b073966ca370e5e43..990f88a20320a2f6f58cf2e0b4d37e398d5f7fda 100644
|
||||
--- a/third_party/blink/public/web/web_view.h
|
||||
+++ b/third_party/blink/public/web/web_view.h
|
||||
@@ -367,6 +367,7 @@ class BLINK_EXPORT WebView {
|
||||
@@ -369,6 +369,7 @@ class BLINK_EXPORT WebView {
|
||||
// Scheduling -----------------------------------------------------------
|
||||
|
||||
virtual PageScheduler* Scheduler() const = 0;
|
||||
@@ -72,10 +87,20 @@ index c8655d9270b812df04f27025ff29a2fb6d2a4066..2f83e5ce40f8217ff5d53f7205299ad7
|
||||
// Visibility -----------------------------------------------------------
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
index 823d6d2ab3772c29b75e60794862a4e02fc62495..0dd3a74473fc73a75b7bb3dfe8a10844ebc34079 100644
|
||||
index 4f99cf1e984cb7411703e3e586203834bf218afe..a7d788610a3611877afe8d0e8b3f3d7507c71aab 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
@@ -3875,13 +3875,21 @@ PageScheduler* WebViewImpl::Scheduler() const {
|
||||
@@ -2446,6 +2446,9 @@ void WebViewImpl::SetPageLifecycleStateInternal(
|
||||
TRACE_EVENT2("navigation", "WebViewImpl::SetPageLifecycleStateInternal",
|
||||
"old_state", old_state, "new_state", new_state);
|
||||
|
||||
+ if (!scheduler_throttling_allowed_)
|
||||
+ new_state->visibility = mojom::blink::PageVisibilityState::kVisible;
|
||||
+
|
||||
bool storing_in_bfcache = new_state->is_in_back_forward_cache &&
|
||||
!old_state->is_in_back_forward_cache;
|
||||
bool restoring_from_bfcache = !new_state->is_in_back_forward_cache &&
|
||||
@@ -3895,17 +3898,30 @@ PageScheduler* WebViewImpl::Scheduler() const {
|
||||
return GetPage()->GetPageScheduler();
|
||||
}
|
||||
|
||||
@@ -90,19 +115,34 @@ index 823d6d2ab3772c29b75e60794862a4e02fc62495..0dd3a74473fc73a75b7bb3dfe8a10844
|
||||
mojom::blink::PageVisibilityState visibility_state,
|
||||
bool is_initial_state) {
|
||||
DCHECK(GetPage());
|
||||
GetPage()->SetVisibilityState(visibility_state, is_initial_state);
|
||||
GetPage()->GetPageScheduler()->SetPageVisible(
|
||||
- GetPage()->SetVisibilityState(visibility_state, is_initial_state);
|
||||
- GetPage()->GetPageScheduler()->SetPageVisible(
|
||||
- visibility_state == mojom::blink::PageVisibilityState::kVisible);
|
||||
+ scheduler_throttling_allowed_ ?
|
||||
+ (visibility_state == mojom::blink::PageVisibilityState::kVisible) : true);
|
||||
// Notify observers of the change.
|
||||
if (!is_initial_state) {
|
||||
for (auto& observer : observers_)
|
||||
- // Notify observers of the change.
|
||||
- if (!is_initial_state) {
|
||||
- for (auto& observer : observers_)
|
||||
- observer.OnPageVisibilityChanged(visibility_state);
|
||||
+ // If backgroundThrottling is disabled, the page is always visible.
|
||||
+ if (!scheduler_throttling_allowed_) {
|
||||
+ GetPage()->SetVisibilityState(mojom::blink::PageVisibilityState::kVisible, is_initial_state);
|
||||
+ GetPage()->GetPageScheduler()->SetPageVisible(true);
|
||||
+ } else {
|
||||
+ bool is_visible = visibility_state == mojom::blink::PageVisibilityState::kVisible;
|
||||
+ GetPage()->SetVisibilityState(visibility_state, is_initial_state);
|
||||
+ GetPage()->GetPageScheduler()->SetPageVisible(is_visible);
|
||||
+ // Notify observers of the change.
|
||||
+ if (!is_initial_state) {
|
||||
+ for (auto& observer : observers_)
|
||||
+ observer.OnPageVisibilityChanged(visibility_state);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
index dcd53ce7503b010c3449b70011d701b069286259..ceb78b07455179ec9a7d59940710858d2991b086 100644
|
||||
index 421ca0b15eea5958d18e52118613c388aeef7dce..c3751889cc1289f237f9f8e0e22f321e8e793778 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
@@ -440,6 +440,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
@@ -441,6 +441,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
LocalDOMWindow* PagePopupWindow() const;
|
||||
|
||||
PageScheduler* Scheduler() const override;
|
||||
@@ -110,7 +150,7 @@ index dcd53ce7503b010c3449b70011d701b069286259..ceb78b07455179ec9a7d59940710858d
|
||||
void SetVisibilityState(mojom::blink::PageVisibilityState visibility_state,
|
||||
bool is_initial_state) override;
|
||||
mojom::blink::PageVisibilityState GetVisibilityState() override;
|
||||
@@ -902,6 +903,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
@@ -904,6 +905,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
// If true, we send IPC messages when |preferred_size_| changes.
|
||||
bool send_preferred_size_changes_ = false;
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ WebPreferences of in-process child windows, rather than relying on
|
||||
process-level command line switches, as before.
|
||||
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
index 8be73a1f7b89613a9d0a0012e9b072efd7d3df95..71d5bf4ddde3d19a89f96a2de0bdce9c7ac8a19e 100644
|
||||
index 0997787979ba293e78211783d8d9993af50ac1c8..2e25e32d0e46470bc4d1a2254fc6737d848791ef 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
@@ -142,6 +142,19 @@ WebPreferences::WebPreferences()
|
||||
@@ -144,6 +144,19 @@ WebPreferences::WebPreferences()
|
||||
v8_cache_options(blink::mojom::V8CacheOptions::kDefault),
|
||||
record_whole_document(false),
|
||||
stylus_handwriting_enabled(false),
|
||||
@@ -32,10 +32,10 @@ index 8be73a1f7b89613a9d0a0012e9b072efd7d3df95..71d5bf4ddde3d19a89f96a2de0bdce9c
|
||||
accelerated_video_decode_enabled(false),
|
||||
animation_policy(
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
index 22220de13b6d7b88cfe0b02367836f7bd5e139b5..4aad04688926066c75d07aea9a6d2a5932e37979 100644
|
||||
index d557c270b484c3152830b0678c90691c983538ad..de0a4e4ab43072d0a815724a772aa42006f63fd5 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
@@ -148,6 +148,19 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
@@ -152,6 +152,19 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
out->v8_cache_options = data.v8_cache_options();
|
||||
out->record_whole_document = data.record_whole_document();
|
||||
out->stylus_handwriting_enabled = data.stylus_handwriting_enabled();
|
||||
@@ -56,7 +56,7 @@ index 22220de13b6d7b88cfe0b02367836f7bd5e139b5..4aad04688926066c75d07aea9a6d2a59
|
||||
out->accelerated_video_decode_enabled =
|
||||
data.accelerated_video_decode_enabled();
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
index 418233a0c46fa0837c9bd11e360d5279c1b1ff6d..b47ba60ec901460db3b1a8a2f81f5b7a9006c647 100644
|
||||
index 2ab2f3af95aaa1b1ed8f0530c6e13b8d62ed9ded..72c03d606d5c5ef0e5a699bc9380d573631f5518 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
@@ -10,6 +10,7 @@
|
||||
@@ -67,7 +67,7 @@ index 418233a0c46fa0837c9bd11e360d5279c1b1ff6d..b47ba60ec901460db3b1a8a2f81f5b7a
|
||||
#include "net/nqe/effective_connection_type.h"
|
||||
#include "third_party/blink/public/common/common_export.h"
|
||||
#include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-shared.h"
|
||||
@@ -158,6 +159,19 @@ struct BLINK_COMMON_EXPORT WebPreferences {
|
||||
@@ -159,6 +160,19 @@ struct BLINK_COMMON_EXPORT WebPreferences {
|
||||
// If true, stylus handwriting recognition to text input will be available in
|
||||
// editable input fields which are non-password type.
|
||||
bool stylus_handwriting_enabled;
|
||||
@@ -88,7 +88,7 @@ index 418233a0c46fa0837c9bd11e360d5279c1b1ff6d..b47ba60ec901460db3b1a8a2f81f5b7a
|
||||
// This flags corresponds to a Page's Settings' setCookieEnabled state. It
|
||||
// only controls whether or not the "document.cookie" field is properly
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
index 625db31846992c54083b30b2990fb359e6a3b3cd..1ccf341ecce1cf2ca17e3d4f7d5c42b8309caf96 100644
|
||||
index 0222f3671842c3a707e2dd9aeaec72a6f94afe7c..882556b4bdea1dc9cb418e0e9f3cc32966111a67 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
@@ -6,6 +6,7 @@
|
||||
@@ -99,7 +99,7 @@ index 625db31846992c54083b30b2990fb359e6a3b3cd..1ccf341ecce1cf2ca17e3d4f7d5c42b8
|
||||
#include "mojo/public/cpp/bindings/struct_traits.h"
|
||||
#include "net/nqe/effective_connection_type.h"
|
||||
#include "third_party/blink/public/common/common_export.h"
|
||||
@@ -434,6 +435,52 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
@@ -439,6 +440,52 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
return r.stylus_handwriting_enabled;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ index 625db31846992c54083b30b2990fb359e6a3b3cd..1ccf341ecce1cf2ca17e3d4f7d5c42b8
|
||||
return r.cookie_enabled;
|
||||
}
|
||||
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
index 5d764552d3f8bc30b6d6efa83ca3ff120dba4b54..cbd2f58730c107eafba6358b12517e7d55bbdf0c 100644
|
||||
index 1e04b372e8a7839a05b2304ead80a04689cd850c..ead0401600b38d362aec21ee77b3c71f1d13649f 100644
|
||||
--- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
+++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
@@ -9,6 +9,7 @@ import "third_party/blink/public/mojom/css/preferred_contrast.mojom";
|
||||
@@ -164,7 +164,7 @@ index 5d764552d3f8bc30b6d6efa83ca3ff120dba4b54..cbd2f58730c107eafba6358b12517e7d
|
||||
|
||||
enum PointerType {
|
||||
kPointerNone = 1, // 1 << 0
|
||||
@@ -208,6 +209,19 @@ struct WebPreferences {
|
||||
@@ -218,6 +219,19 @@ struct WebPreferences {
|
||||
// If true, stylus handwriting recognition to text input will be available in
|
||||
// editable input fields which are non-password type.
|
||||
bool stylus_handwriting_enabled;
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benoit Lize <lizeb@chromium.org>
|
||||
Date: Fri, 9 Jun 2023 17:59:08 +0000
|
||||
Subject: Do not use va_args twice in asprintf()
|
||||
|
||||
(cherry picked from commit 3cff0cb19a6d01cbdd9932f43dabaaeda9c0330a)
|
||||
|
||||
Bug: 1450536
|
||||
Change-Id: Ib34d96935278869a63897f9a1c66afc98865d90f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4579347
|
||||
Reviewed-by: Egor Pasko <pasko@chromium.org>
|
||||
Commit-Queue: Benoit Lize <lizeb@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1151796}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4604070
|
||||
Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1224}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
index 621873126602463a09efca1bf1548ed10910d323..de2af6d7d54e254b9e7b8264b53d30a338fb13e8 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
@@ -123,13 +123,21 @@ SHIM_ALWAYS_EXPORT char* __wrap_getcwd(char* buffer, size_t size) {
|
||||
SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
const char* fmt,
|
||||
va_list va_args) {
|
||||
+ // There are cases where we need to use the list of arguments twice, namely
|
||||
+ // when the original buffer is too small. It is not allowed to walk the list
|
||||
+ // twice, so make a copy for the second invocation of vsnprintf().
|
||||
+ va_list va_args_copy;
|
||||
+ va_copy(va_args_copy, va_args);
|
||||
+
|
||||
constexpr int kInitialSize = 128;
|
||||
*strp = static_cast<char*>(
|
||||
malloc(kInitialSize)); // Our malloc() doesn't return nullptr.
|
||||
|
||||
int actual_size = vsnprintf(*strp, kInitialSize, fmt, va_args);
|
||||
- if (actual_size < 0)
|
||||
+ if (actual_size < 0) {
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
+ }
|
||||
*strp =
|
||||
static_cast<char*>(realloc(*strp, static_cast<size_t>(actual_size + 1)));
|
||||
|
||||
@@ -139,9 +147,14 @@ SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
//
|
||||
// This is very lightly used in Chromium in practice, see crbug.com/116558 for
|
||||
// details.
|
||||
- if (actual_size >= kInitialSize)
|
||||
- return vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt, va_args);
|
||||
-
|
||||
+ if (actual_size >= kInitialSize) {
|
||||
+ int ret = vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt,
|
||||
+ va_args_copy);
|
||||
+ va_end(va_args_copy);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
index dcf26fa5fc6d51de6276aa6fdcc4691f781c4bfd..fd46a15799864acaf58ef57315606bf515b48b15 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
@@ -734,6 +734,28 @@ TEST_F(AllocatorShimTest, InterceptVasprintf) {
|
||||
// Should not crash.
|
||||
}
|
||||
|
||||
+TEST_F(AllocatorShimTest, InterceptLongVasprintf) {
|
||||
+ char* str = nullptr;
|
||||
+ const char* lorem_ipsum =
|
||||
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. "
|
||||
+ "Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, "
|
||||
+ "ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula "
|
||||
+ "massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci "
|
||||
+ "nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit "
|
||||
+ "amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat "
|
||||
+ "in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero "
|
||||
+ "pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo "
|
||||
+ "in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue "
|
||||
+ "blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus "
|
||||
+ "et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed "
|
||||
+ "pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales "
|
||||
+ "hendrerit.";
|
||||
+ int err = asprintf(&str, "%s", lorem_ipsum);
|
||||
+ EXPECT_EQ(err, static_cast<int>(strlen(lorem_ipsum)));
|
||||
+ EXPECT_TRUE(str);
|
||||
+ free(str);
|
||||
+}
|
||||
+
|
||||
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
|
||||
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
@@ -15,10 +15,10 @@ Refs changes in:
|
||||
This patch reverts the changes to fix associated crashes in Electron.
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc
|
||||
index b2115232fe81f47d3fe3441bcab53d09543d0a84..c836a400dfaccd276e90549a8cae38346e88909f 100644
|
||||
index 22c4d4e9718a503d9c7ca26a40c97149b0f8986a..6bdc2757c96a28022fda9e6f5e3b74a08332a4ce 100644
|
||||
--- a/third_party/blink/renderer/core/frame/frame.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/frame.cc
|
||||
@@ -124,14 +124,6 @@ bool Frame::Detach(FrameDetachType type) {
|
||||
@@ -125,14 +125,6 @@ bool Frame::Detach(FrameDetachType type) {
|
||||
|
||||
DCHECK(!IsDetached());
|
||||
|
||||
@@ -33,7 +33,7 @@ index b2115232fe81f47d3fe3441bcab53d09543d0a84..c836a400dfaccd276e90549a8cae3834
|
||||
if (type == FrameDetachType::kRemove) {
|
||||
if (provisional_frame_) {
|
||||
provisional_frame_->Detach(FrameDetachType::kRemove);
|
||||
@@ -155,6 +147,14 @@ bool Frame::Detach(FrameDetachType type) {
|
||||
@@ -156,6 +148,14 @@ bool Frame::Detach(FrameDetachType type) {
|
||||
GetWindowProxyManager()->ClearForSwap();
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ index b2115232fe81f47d3fe3441bcab53d09543d0a84..c836a400dfaccd276e90549a8cae3834
|
||||
// its owning reference back to our owning LocalFrame.
|
||||
client_->Detached(type);
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
index d3a43f5675bc3e8937c6f7d689be8e1b470ac9f7..d2391ca06d31ac96313cf3383fa2e550a78ece18 100644
|
||||
index b2e5817c437c16705a74ea3d5094e9626fe3814f..d76f9ea410a2e6dd7a38bd4a17ca409b6ff87b84 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
@@ -630,10 +630,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
|
||||
@@ -625,10 +625,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
|
||||
}
|
||||
DCHECK(!view_ || !view_->IsAttached());
|
||||
|
||||
@@ -63,7 +63,7 @@ index d3a43f5675bc3e8937c6f7d689be8e1b470ac9f7..d2391ca06d31ac96313cf3383fa2e550
|
||||
if (!Client())
|
||||
return false;
|
||||
|
||||
@@ -681,6 +677,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
|
||||
@@ -676,6 +672,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
|
||||
DCHECK(!view_->IsAttached());
|
||||
Client()->WillBeDetached();
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: boringssl BUILD.gn
|
||||
Build BoringSSL with some extra functions that nodejs needs.
|
||||
|
||||
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
|
||||
index 40073723173388015f0c78899214ba155e7cdc53..72978c43a522e5716ba06e8b989710cc99bd8773 100644
|
||||
index 6fb13437c6bcca2aff102b04f3a46d2ad6a791c5..c61c60c7cb968c2b730a14de9ac0629aaceb73d3 100644
|
||||
--- a/third_party/boringssl/BUILD.gn
|
||||
+++ b/third_party/boringssl/BUILD.gn
|
||||
@@ -44,6 +44,20 @@ config("no_asm_config") {
|
||||
@@ -49,6 +49,20 @@ config("no_asm_config") {
|
||||
|
||||
all_sources = crypto_sources + ssl_sources
|
||||
all_headers = crypto_headers + ssl_headers
|
||||
@@ -28,5 +28,5 @@ index 40073723173388015f0c78899214ba155e7cdc53..72978c43a522e5716ba06e8b989710cc
|
||||
+ ]
|
||||
+}
|
||||
|
||||
# Windows' assembly is built with NASM. The other platforms use the platform
|
||||
# assembler. Exclude Windows ARM64 because NASM targets x86 and x64 only.
|
||||
if (enable_rust_boringssl) {
|
||||
rust_bindgen("raw_bssl_sys_bindings") {
|
||||
|
||||
@@ -8,10 +8,10 @@ categories in use are known / declared. This patch is required for us
|
||||
to introduce a new Electron category for Electron-specific tracing.
|
||||
|
||||
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
|
||||
index ee17e77330c498864c710eb6e0b2d8d67722bda9..6c7d1b40bd53337df4ce0bb92fb6bd610bd11c1b 100644
|
||||
index 3c8faea2c2391a0172504d524129702cb3c43cf0..b561f3e09d294e74b41a22ab22e8bbe5be05a116 100644
|
||||
--- a/base/trace_event/builtin_categories.h
|
||||
+++ b/base/trace_event/builtin_categories.h
|
||||
@@ -81,6 +81,7 @@
|
||||
@@ -80,6 +80,7 @@
|
||||
X("drmcursor") \
|
||||
X("dwrite") \
|
||||
X("DXVA_Decoding") \
|
||||
|
||||
@@ -9,10 +9,10 @@ and can be removed when the crash in fork is resolved.
|
||||
Related issue: https://github.com/electron/electron/issues/32718
|
||||
|
||||
diff --git a/build_overrides/partition_alloc.gni b/build_overrides/partition_alloc.gni
|
||||
index e90ccba879dc5823c15acf35869cd5bd211b717b..a95d2b46b37e007405cd472bd9f882c1d180d809 100644
|
||||
index 0574216aabe93171e8f59eedc480178a0e1ac3ce..a6c5dc4b48b83c965e04fa0c31b36e009f76798f 100644
|
||||
--- a/build_overrides/partition_alloc.gni
|
||||
+++ b/build_overrides/partition_alloc.gni
|
||||
@@ -46,7 +46,7 @@ _disable_partition_alloc_everywhere = is_component_build || (is_win && is_debug)
|
||||
@@ -51,7 +51,7 @@ _disable_partition_alloc_everywhere =
|
||||
if (is_ios) {
|
||||
_is_partition_alloc_everywhere_platform = ios_partition_alloc_enabled
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,7 @@ This patch can be removed when enable_print_content_analysis can be more
|
||||
easily enabled or disabled by default with buildflags.
|
||||
|
||||
diff --git a/printing/buildflags/buildflags.gni b/printing/buildflags/buildflags.gni
|
||||
index 8a688b2d196070caf8076bc5621eca2649a6f136..c148f511628ac13f0b50faab01f7308538f102a9 100644
|
||||
index e617f46226d9c1c43353db51d6e4764ec8ed66e8..b7c99a725eda84d1c3f7b334633c19be67714363 100644
|
||||
--- a/printing/buildflags/buildflags.gni
|
||||
+++ b/printing/buildflags/buildflags.gni
|
||||
@@ -44,7 +44,7 @@ declare_args() {
|
||||
|
||||
@@ -11,32 +11,32 @@ if we ever align our .pak file generation with Chrome we can remove this
|
||||
patch.
|
||||
|
||||
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
|
||||
index 53363189fe649fa92040811ee9e858e9363f29e7..48883669d54ec7b7421b88fcaf7776e7b3d55bee 100644
|
||||
index f9e148eb5b5a9a1da534f5db19227e327282eac0..d95ba090ae13b036b694724d95834e5a62a3fff9 100644
|
||||
--- a/chrome/BUILD.gn
|
||||
+++ b/chrome/BUILD.gn
|
||||
@@ -187,11 +187,16 @@ if (!is_android && !is_mac) {
|
||||
"common/crash_keys.h",
|
||||
]
|
||||
@@ -193,11 +193,16 @@ if (!is_android && !is_mac) {
|
||||
"common/crash_keys.h",
|
||||
]
|
||||
|
||||
+ if (!is_electron_build) {
|
||||
+ deps = [
|
||||
+ ":packed_resources_integrity",
|
||||
+ ]
|
||||
+ }
|
||||
+ if (!is_electron_build) {
|
||||
+ deps = [
|
||||
+ ":packed_resources_integrity",
|
||||
+ ]
|
||||
+ }
|
||||
+
|
||||
deps += [
|
||||
":chrome_dll",
|
||||
":chrome_exe_version",
|
||||
":copy_first_run",
|
||||
- ":packed_resources_integrity",
|
||||
":visual_elements_resources",
|
||||
"//base",
|
||||
"//build:branding_buildflags",
|
||||
deps += [
|
||||
":chrome_dll",
|
||||
":chrome_exe_version",
|
||||
":copy_first_run",
|
||||
- ":packed_resources_integrity",
|
||||
":visual_elements_resources",
|
||||
"//base",
|
||||
"//build:branding_buildflags",
|
||||
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
|
||||
index 0ddbd541f7ef4041aecc5693a366e6c87f74f313..a97f4cba4512ae1e7d34f9f29c33b366420b0822 100644
|
||||
index acf48b7ffd061192c202893ebd1ba09b4df00187..27f5760aadd3a6892175a007b0ed71950bca2983 100644
|
||||
--- a/chrome/browser/BUILD.gn
|
||||
+++ b/chrome/browser/BUILD.gn
|
||||
@@ -4591,7 +4591,7 @@ static_library("browser") {
|
||||
@@ -4595,7 +4595,7 @@ static_library("browser") {
|
||||
|
||||
# On Windows, the hashes are embedded in //chrome:chrome_initial rather
|
||||
# than here in :chrome_dll.
|
||||
@@ -46,10 +46,10 @@ index 0ddbd541f7ef4041aecc5693a366e6c87f74f313..a97f4cba4512ae1e7d34f9f29c33b366
|
||||
sources += [ "certificate_viewer_stub.cc" ]
|
||||
}
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index 9bd4a7f817389a1e6256b0570864ab5de5f541fb..66c42163f0d99eb447df4279eba47f4f50da3172 100644
|
||||
index d6515aedf07677dd10c85acecb17877b041abb7f..15197af41fff21200f70cb6b88448cf173785474 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -6297,7 +6297,6 @@ test("unit_tests") {
|
||||
@@ -6423,7 +6423,6 @@ test("unit_tests") {
|
||||
|
||||
deps += [
|
||||
"//chrome:other_version",
|
||||
@@ -57,7 +57,7 @@ index 9bd4a7f817389a1e6256b0570864ab5de5f541fb..66c42163f0d99eb447df4279eba47f4f
|
||||
"//chrome//services/util_win:unit_tests",
|
||||
"//chrome/app:chrome_dll_resources",
|
||||
"//chrome/app:win_unit_tests",
|
||||
@@ -6323,6 +6322,10 @@ test("unit_tests") {
|
||||
@@ -6449,6 +6448,10 @@ test("unit_tests") {
|
||||
"//ui/resources",
|
||||
]
|
||||
|
||||
@@ -68,23 +68,22 @@ index 9bd4a7f817389a1e6256b0570864ab5de5f541fb..66c42163f0d99eb447df4279eba47f4f
|
||||
ldflags = [
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
|
||||
@@ -7240,7 +7243,7 @@ test("unit_tests") {
|
||||
@@ -7389,7 +7392,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
- "//chrome:packed_resources_integrity_hash",
|
||||
+ # "//chrome:packed_resources_integrity_hash",
|
||||
"//chrome/browser/apps:icon_standardizer",
|
||||
"//chrome/browser/apps/app_service",
|
||||
"//chrome/browser/apps/app_service:test_support",
|
||||
"//chrome/browser/enterprise/connectors/analysis:features",
|
||||
@@ -7370,6 +7373,10 @@ test("unit_tests") {
|
||||
}
|
||||
}
|
||||
@@ -7470,6 +7472,10 @@ test("unit_tests") {
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings",
|
||||
]
|
||||
|
||||
+ if (!is_electron_build) {
|
||||
+ deps += [ "//chrome:packed_resources_integrity_hash" ]
|
||||
+ }
|
||||
+ if (!is_electron_build) {
|
||||
+ deps += [ "//chrome:packed_resources_integrity_hash" ]
|
||||
+ }
|
||||
+
|
||||
if (is_chromeos_ash) {
|
||||
sources -= [
|
||||
"../browser/policy/cloud/user_policy_signin_service_unittest.cc",
|
||||
data += [ "//ash/components/arc/test/data/icons/" ]
|
||||
|
||||
if (include_js_tests) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user