mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
165 Commits
v26.0.0-be
...
v26.6.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13908747ab | ||
|
|
0ebe40354e | ||
|
|
e16d9f99e6 | ||
|
|
682b27f606 | ||
|
|
0b94b5b86f | ||
|
|
0c3113a4c5 | ||
|
|
5917fe9143 | ||
|
|
8638667c66 | ||
|
|
2c7c8b2d44 | ||
|
|
9c7f63cc9c | ||
|
|
6cdb2fb3af | ||
|
|
0d99c8a222 | ||
|
|
783f23bfdb | ||
|
|
9ba6477dcb | ||
|
|
24c06a45ef | ||
|
|
8e074bc1d0 | ||
|
|
eb2173846b | ||
|
|
1813586545 | ||
|
|
d47906c855 | ||
|
|
aa688f9a45 | ||
|
|
4cfc4bf074 | ||
|
|
a0af9e0e3c | ||
|
|
f2ce1ce1b4 | ||
|
|
af61c40ee0 | ||
|
|
917664c68b | ||
|
|
ead3de1ac5 | ||
|
|
44bf2a7a6a | ||
|
|
0337b2c9f5 | ||
|
|
fe0a54f729 | ||
|
|
6799879694 | ||
|
|
696087f29c | ||
|
|
dd6a7503d8 | ||
|
|
ce7d224945 | ||
|
|
66bb063616 | ||
|
|
ddcdad7e4f | ||
|
|
3daa401047 | ||
|
|
aec6ffe4c7 | ||
|
|
35a9e69eaf | ||
|
|
92c934244d | ||
|
|
c00c8debcc | ||
|
|
237d120a04 | ||
|
|
0a1b7196ed | ||
|
|
6f663c78fa | ||
|
|
b77eb9ce86 | ||
|
|
3703625ad7 | ||
|
|
bec47bca0b | ||
|
|
37882e805a | ||
|
|
4be7b10550 | ||
|
|
2270fc8d4d | ||
|
|
e861af712d | ||
|
|
ad34b4b793 | ||
|
|
2793539c9c | ||
|
|
677d05a3d6 | ||
|
|
b8f522b5f2 | ||
|
|
a4f9db0a56 | ||
|
|
0da1d6d4cc | ||
|
|
7985f82f87 | ||
|
|
1d845761f8 | ||
|
|
33c963dac3 | ||
|
|
6228c075f7 | ||
|
|
2ac8897896 | ||
|
|
589a6e427a | ||
|
|
040f3be041 | ||
|
|
d5020a4fff | ||
|
|
a55c4c65c0 | ||
|
|
7f53717e48 | ||
|
|
1091ba2bd2 | ||
|
|
59271e6182 | ||
|
|
d7da2b9561 | ||
|
|
f24346a979 | ||
|
|
13bdefa549 | ||
|
|
74f50e83a5 | ||
|
|
9c2984f7b5 | ||
|
|
0f8e9dec59 | ||
|
|
70231825c7 | ||
|
|
fbc2786c18 | ||
|
|
985f0a441d | ||
|
|
ee1f6c30e7 | ||
|
|
89bf5a2cdc | ||
|
|
1c3d6181a8 | ||
|
|
b9095f5ccf | ||
|
|
46b512407b | ||
|
|
53bf1f3f13 | ||
|
|
8e3189a8ba | ||
|
|
496577d9cd | ||
|
|
90a311dba2 | ||
|
|
77da40381c | ||
|
|
7aa860e938 | ||
|
|
10409ff7a1 | ||
|
|
4e9c583230 | ||
|
|
cbc345892c | ||
|
|
6ecae84da3 | ||
|
|
8d8751106b | ||
|
|
eda2ceda1e | ||
|
|
01aafab563 | ||
|
|
325549ffce | ||
|
|
ab272cb767 | ||
|
|
a3acea9fd6 | ||
|
|
c9d2d69397 | ||
|
|
65f2726851 | ||
|
|
937adf72e5 | ||
|
|
03dd4ae6bb | ||
|
|
b9aee8152c | ||
|
|
5fce729a14 | ||
|
|
3f1fee72b4 | ||
|
|
81bd81667c | ||
|
|
1ddffe909e | ||
|
|
ed6e4e3add | ||
|
|
a89482093f | ||
|
|
1b9842b9b5 | ||
|
|
deb02b9ec6 | ||
|
|
c14487ea98 | ||
|
|
bf1dbaffcc | ||
|
|
1e70e543ce | ||
|
|
a6649ffb61 | ||
|
|
5da1b91546 | ||
|
|
1047532f1d | ||
|
|
054b99634c | ||
|
|
6838404ecb | ||
|
|
ee01054bb5 | ||
|
|
51b074eb5e | ||
|
|
2e27e273ed | ||
|
|
86fc724d97 | ||
|
|
c676293bf4 | ||
|
|
1afcffef53 | ||
|
|
04994de9e6 | ||
|
|
9dea18c1db | ||
|
|
ad76ef17f0 | ||
|
|
3d760afa36 | ||
|
|
0f2df2bf9b | ||
|
|
64c5505b36 | ||
|
|
ad385bf1ce | ||
|
|
0a478f9ef0 | ||
|
|
92c4697662 | ||
|
|
ceb5230395 | ||
|
|
c09ebeac14 | ||
|
|
5f1ada46f5 | ||
|
|
ca899eb3cb | ||
|
|
c709e04bed | ||
|
|
f9e35e4aaa | ||
|
|
d2ca670f3f | ||
|
|
4930f71a76 | ||
|
|
1c458c5eaf | ||
|
|
9c028cd279 | ||
|
|
fd8d4a8b94 | ||
|
|
35126e06b6 | ||
|
|
3e239efd99 | ||
|
|
66f42b3256 | ||
|
|
4586a40bfd | ||
|
|
3c467224d5 | ||
|
|
759329dc62 | ||
|
|
ac867a1b95 | ||
|
|
75b1fd5b4c | ||
|
|
a800965ef6 | ||
|
|
53cb8f5e01 | ||
|
|
7c434a11e4 | ||
|
|
c5faab7a0d | ||
|
|
abd3acd380 | ||
|
|
76a9aab8b5 | ||
|
|
63a60b8eaa | ||
|
|
9a49ac1454 | ||
|
|
102eb176d9 | ||
|
|
87dfd83bf8 | ||
|
|
784b288de0 | ||
|
|
ef8c90a50a |
@@ -65,6 +65,9 @@ jobs:
|
||||
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | DESTDIR=$CIRCLECI_BINARY bash
|
||||
node build.js
|
||||
name: Pack config.yml
|
||||
- run:
|
||||
name: Set params
|
||||
command: node .circleci/config/params.js
|
||||
- continuation/continue:
|
||||
configuration_path: .circleci/config-staging/built.yml
|
||||
parameters: /tmp/pipeline-parameters.json
|
||||
|
||||
@@ -35,6 +35,16 @@ parameters:
|
||||
default: all
|
||||
enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"]
|
||||
|
||||
medium-linux-executor:
|
||||
type: enum
|
||||
default: electronjs/aks-linux-medium
|
||||
enum: ["electronjs/aks-linux-medium", "medium"]
|
||||
|
||||
large-linux-executor:
|
||||
type: enum
|
||||
default: electronjs/aks-linux-large
|
||||
enum: ["electronjs/aks-linux-large", "2xlarge"]
|
||||
|
||||
# Executors
|
||||
executors:
|
||||
linux-docker:
|
||||
@@ -42,7 +52,9 @@ executors:
|
||||
size:
|
||||
description: "Docker executor size"
|
||||
type: enum
|
||||
enum: ["medium", "xlarge", "2xlarge"]
|
||||
# aks-linux-large === 32 core
|
||||
# 2xlarge should not be used directly, use the pipeline param instead
|
||||
enum: ["medium", "electronjs/aks-linux-medium", "xlarge", "electronjs/aks-linux-large", "2xlarge"]
|
||||
docker:
|
||||
- image: ghcr.io/electron/build:e6bebd08a51a0d78ec23e5b3fd7e7c0846412328
|
||||
resource_class: << parameters.size >>
|
||||
@@ -68,12 +80,14 @@ executors:
|
||||
machine: true
|
||||
|
||||
linux-arm:
|
||||
resource_class: electronjs/linux-arm
|
||||
machine: true
|
||||
resource_class: electronjs/aks-linux-arm-test
|
||||
docker:
|
||||
- image: ghcr.io/electron/test:arm32v7-b0dee37de023a8d8a15bb8916325b54a4aebfb0c
|
||||
|
||||
linux-arm64:
|
||||
resource_class: electronjs/linux-arm64
|
||||
machine: true
|
||||
resource_class: electronjs/aks-linux-arm-test
|
||||
docker:
|
||||
- image: ghcr.io/electron/test:arm64v8-b0dee37de023a8d8a15bb8916325b54a4aebfb0c
|
||||
|
||||
# The config expects the following environment variables to be set:
|
||||
# - "SLACK_WEBHOOK" Slack hook URL to send notifications.
|
||||
@@ -252,19 +266,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
|
||||
@@ -352,7 +366,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
exit 1
|
||||
fi
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
echo 'export GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
echo 'export GOMA_FALLBACK_ON_AUTH_FAILURE=true' >> $BASH_ENV
|
||||
cd ..
|
||||
touch "${TMPDIR:=/tmp}"/.goma-ready
|
||||
@@ -629,6 +643,7 @@ step-nodejs-headers-build: &step-nodejs-headers-build
|
||||
step-electron-publish: &step-electron-publish
|
||||
run:
|
||||
name: Publish Electron Dist
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
rm -rf src/out/Default/obj
|
||||
@@ -723,8 +738,8 @@ step-show-goma-stats: &step-show-goma-stats
|
||||
command: |
|
||||
set +e
|
||||
set +o pipefail
|
||||
$LOCAL_GOMA_DIR/goma_ctl.py stat
|
||||
$LOCAL_GOMA_DIR/diagnose_goma_log.py
|
||||
python3 $GOMA_DIR/goma_ctl.py stat
|
||||
python3 $GOMA_DIR/diagnose_goma_log.py
|
||||
true
|
||||
when: always
|
||||
background: true
|
||||
@@ -876,14 +891,26 @@ step-touch-sync-done: &step-touch-sync-done
|
||||
step-maybe-restore-src-cache: &step-maybe-restore-src-cache
|
||||
restore_cache:
|
||||
keys:
|
||||
- v16-src-cache-{{ checksum "src/electron/.depshash" }}
|
||||
- v17-src-cache-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache
|
||||
step-maybe-restore-src-cache-marker: &step-maybe-restore-src-cache-marker
|
||||
restore_cache:
|
||||
keys:
|
||||
- v16-src-cache-marker-{{ checksum "src/electron/.depshash" }}
|
||||
- v17-src-cache-marker-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache marker
|
||||
|
||||
step-maybe-restore-src-cache-aks: &step-maybe-restore-src-cache-aks
|
||||
restore_cache_aks:
|
||||
step-name: Restoring src cache
|
||||
cache_key: v17-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
|
||||
cache_path: /var/portal
|
||||
|
||||
step-maybe-restore-src-cache-marker-aks: &step-maybe-restore-src-cache-marker-aks
|
||||
restore_cache_aks:
|
||||
step-name: Restoring src cache marker
|
||||
cache_key: v17-src-cache-marker-$(shasum src/electron/.depshash | cut -f1 -d' ')
|
||||
cache_path: "."
|
||||
|
||||
# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done
|
||||
# If the src cache was restored above then this will match an empty cache
|
||||
# If the src cache was not restored above then this will match a close git cache
|
||||
@@ -896,6 +923,12 @@ step-maybe-restore-git-cache: &step-maybe-restore-git-cache
|
||||
- v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}
|
||||
name: Conditionally restoring git cache
|
||||
|
||||
step-maybe-restore-git-cache-aks: &step-maybe-restore-git-cache-aks
|
||||
restore_cache_aks:
|
||||
step-name: Conditionally restoring git cache (aks)
|
||||
cache_key: v1-git-cache-$(shasum src/electron/.circle-sync-done | cut -f1 -d' ')-$(shasum src/electron/DEPS | cut -f1 -d' ') v1-git-cache-$(shasum src/electron/.circle-sync-done | cut -f1 -d' ')
|
||||
cache_path: git-cache
|
||||
|
||||
step-set-git-cache-path: &step-set-git-cache-path
|
||||
run:
|
||||
name: Set GIT_CACHE_PATH to make gclient to use the cache
|
||||
@@ -913,6 +946,12 @@ step-save-git-cache: &step-save-git-cache
|
||||
key: v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
|
||||
name: Persisting git cache
|
||||
|
||||
step-save-git-cache-aks: &step-save-git-cache-aks
|
||||
save_cache_aks:
|
||||
step-name: Persisting git cache (AKS)
|
||||
cache_key: v1-git-cache-$(shasum src/electron/.circle-sync-done | cut -f1 -d' ')-$(shasum src/electron/DEPS | cut -f1 -d' ')
|
||||
cache_path: git-cache
|
||||
|
||||
step-run-electron-only-hooks: &step-run-electron-only-hooks
|
||||
run:
|
||||
name: Run Electron Only Hooks
|
||||
@@ -950,7 +989,7 @@ step-save-src-cache: &step-save-src-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /var/portal
|
||||
key: v16-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
key: v17-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
name: Persisting src cache
|
||||
step-make-src-cache-marker: &step-make-src-cache-marker
|
||||
run:
|
||||
@@ -960,7 +999,17 @@ step-save-src-cache-marker: &step-save-src-cache-marker
|
||||
save_cache:
|
||||
paths:
|
||||
- .src-cache-marker
|
||||
key: v16-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
key: v17-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }}
|
||||
step-save-src-cache-aks: &step-save-src-cache-aks
|
||||
save_cache_aks:
|
||||
step-name: Persisting src cache (aks)
|
||||
cache_key: v17-src-cache-$(shasum /var/portal/src/electron/.depshash | cut -f1 -d' ')
|
||||
cache_path: /var/portal
|
||||
step-save-src-cache-marker-aks: &step-save-src-cache-marker-aks
|
||||
save_cache_aks:
|
||||
step-name: Persisting src cache marker (aks)
|
||||
cache_key: v17-src-cache-marker-$(shasum /var/portal/src/electron/.depshash | cut -f1 -d' ')
|
||||
cache_path: .src-cache-marker
|
||||
|
||||
step-maybe-early-exit-no-doc-change: &step-maybe-early-exit-no-doc-change
|
||||
run:
|
||||
@@ -986,15 +1035,6 @@ step-ts-compile: &step-ts-compile
|
||||
done
|
||||
|
||||
# List of all steps.
|
||||
steps-electron-gn-check: &steps-electron-gn-check
|
||||
steps:
|
||||
- *step-setup-goma-for-build
|
||||
- checkout-from-cache
|
||||
- *step-setup-env-for-build
|
||||
- *step-wait-for-goma
|
||||
- *step-gn-gen-default
|
||||
- *step-gn-check
|
||||
|
||||
steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-change
|
||||
steps:
|
||||
# Checkout - Copied from steps-checkout
|
||||
@@ -1006,11 +1046,92 @@ steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-cha
|
||||
|
||||
# Command Aliases
|
||||
commands:
|
||||
aks-specific-step:
|
||||
parameters:
|
||||
circle:
|
||||
type: steps
|
||||
aks:
|
||||
type: steps
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
description: Only set this to true on linux hosts
|
||||
steps:
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
- equal: [<< parameters.could-be-aks >>, false]
|
||||
- equal: [<< pipeline.parameters.large-linux-executor >>, 2xlarge]
|
||||
steps: << parameters.circle >>
|
||||
- when:
|
||||
condition:
|
||||
and:
|
||||
- equal: [<< parameters.could-be-aks >>, true]
|
||||
- equal: [<< pipeline.parameters.large-linux-executor >>, electronjs/aks-linux-large]
|
||||
steps: << parameters.aks >>
|
||||
save_cache_aks:
|
||||
parameters:
|
||||
step-name:
|
||||
type: string
|
||||
cache_key:
|
||||
type: string
|
||||
cache_path:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: << parameters.step-name >>
|
||||
command: |
|
||||
cache_key="<< parameters.cache_key >>"
|
||||
final_cache_path=/mnt/cross-instance-cache/${cache_key}.tar
|
||||
echo "Using cache key: $cache_key"
|
||||
echo "Checking path: $final_cache_path"
|
||||
if [ ! -f "$final_cache_path" ]; then
|
||||
echo "Cache key not founding, storing tarball"
|
||||
tmp_container=/mnt/cross-instance-cache/tmp/$CIRCLE_WORKFLOW_JOB_ID
|
||||
tmp_cache_path=$tmp_container/${cache_key}.tar
|
||||
mkdir -p $tmp_container
|
||||
if [ -f "<< parameters.cache_path >>" ]; then
|
||||
tar -cf $tmp_cache_path -C $(dirname << parameters.cache_path >>) ./$(basename << parameters.cache_path >>)
|
||||
else
|
||||
tar -cf $tmp_cache_path -C << parameters.cache_path >>/ ./
|
||||
fi
|
||||
mv -vn $tmp_cache_path $final_cache_path
|
||||
rm -rf $tmp_container
|
||||
else
|
||||
echo "Cache key already exists, skipping.."
|
||||
fi
|
||||
restore_cache_aks:
|
||||
parameters:
|
||||
step-name:
|
||||
type: string
|
||||
cache_key:
|
||||
type: string
|
||||
cache_path:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: << parameters.step-name >>
|
||||
command: |
|
||||
df -h
|
||||
for cache_key in << parameters.cache_key >>; do
|
||||
cache_path=/mnt/cross-instance-cache/${cache_key}.tar
|
||||
echo "Using cache key: $cache_key"
|
||||
echo "Checking path: $cache_path"
|
||||
if [ ! -f "$cache_path" ]; then
|
||||
echo "Cache key not found, nothing to restore..."
|
||||
else
|
||||
echo "Cache key found, restoring to path..."
|
||||
mkdir -p << parameters.cache_path >>/
|
||||
tar -xf /mnt/cross-instance-cache/${cache_key}.tar -C << parameters.cache_path >>/
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
maybe-restore-portaled-src-cache:
|
||||
parameters:
|
||||
halt-if-successful:
|
||||
type: boolean
|
||||
default: false
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
steps:
|
||||
- run:
|
||||
name: Prepare for cross-OS sync restore
|
||||
@@ -1020,23 +1141,44 @@ commands:
|
||||
- when:
|
||||
condition: << parameters.halt-if-successful >>
|
||||
steps:
|
||||
- *step-maybe-restore-src-cache-marker
|
||||
- aks-specific-step:
|
||||
circle:
|
||||
- *step-maybe-restore-src-cache-marker
|
||||
aks:
|
||||
- *step-maybe-restore-src-cache-marker-aks
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- run:
|
||||
name: Halt the job early if the src cache exists
|
||||
command: |
|
||||
if [ -f ".src-cache-marker" ]; then
|
||||
circleci-agent step halt
|
||||
fi
|
||||
- *step-maybe-restore-src-cache
|
||||
- aks-specific-step:
|
||||
circle:
|
||||
- *step-maybe-restore-src-cache
|
||||
aks:
|
||||
- *step-maybe-restore-src-cache-aks
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- run:
|
||||
name: Fix the src cache restore point on macOS
|
||||
name: Fix the src cache restore point
|
||||
command: |
|
||||
if [ -d "/var/portal/src" ]; then
|
||||
echo Relocating Cache
|
||||
rm -rf src
|
||||
mv /var/portal/src ./
|
||||
fi
|
||||
|
||||
run-gn-check:
|
||||
parameters:
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
steps:
|
||||
- *step-setup-goma-for-build
|
||||
- checkout-from-cache:
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- *step-setup-env-for-build
|
||||
- *step-wait-for-goma
|
||||
- *step-gn-gen-default
|
||||
- *step-gn-check
|
||||
build_and_save_artifacts:
|
||||
parameters:
|
||||
artifact-key:
|
||||
@@ -1150,12 +1292,16 @@ commands:
|
||||
mv_if_exist cross-arch-snapshots src
|
||||
|
||||
checkout-from-cache:
|
||||
parameters:
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
steps:
|
||||
- *step-checkout-electron
|
||||
- *step-depot-tools-get
|
||||
- *step-depot-tools-add-to-path
|
||||
- *step-generate-deps-hash
|
||||
- maybe-restore-portaled-src-cache
|
||||
- maybe-restore-portaled-src-cache:
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- run:
|
||||
name: Ensure src checkout worked
|
||||
command: |
|
||||
@@ -1293,6 +1439,8 @@ commands:
|
||||
after-persist:
|
||||
type: steps
|
||||
default: []
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.attach >>
|
||||
@@ -1310,7 +1458,8 @@ commands:
|
||||
- when:
|
||||
condition: << parameters.checkout-and-assume-cache >>
|
||||
steps:
|
||||
- checkout-from-cache
|
||||
- checkout-from-cache:
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- when:
|
||||
condition: << parameters.checkout >>
|
||||
steps:
|
||||
@@ -1326,8 +1475,15 @@ commands:
|
||||
steps:
|
||||
- maybe-restore-portaled-src-cache:
|
||||
halt-if-successful: << parameters.checkout-to-create-src-cache >>
|
||||
- *step-maybe-restore-git-cache
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- aks-specific-step:
|
||||
circle:
|
||||
- *step-maybe-restore-git-cache
|
||||
aks:
|
||||
- *step-maybe-restore-git-cache-aks
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- *step-set-git-cache-path
|
||||
- *step-fix-known-hosts-linux
|
||||
# This sync call only runs if .circle-sync-done is an EMPTY file
|
||||
- *step-gclient-sync
|
||||
- store_artifacts:
|
||||
@@ -1343,7 +1499,12 @@ commands:
|
||||
- when:
|
||||
condition: << parameters.save-git-cache >>
|
||||
steps:
|
||||
- *step-save-git-cache
|
||||
- aks-specific-step:
|
||||
circle:
|
||||
- *step-save-git-cache
|
||||
aks:
|
||||
- *step-save-git-cache-aks
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
# Mark sync as done _after_ saving the git cache so that it is uploaded
|
||||
# only when the src cache was not present
|
||||
# Their are theoretically two cases for this cache key
|
||||
@@ -1393,9 +1554,19 @@ commands:
|
||||
sudo mkdir -p /var/portal
|
||||
sudo chown -R $(id -u):$(id -g) /var/portal
|
||||
mv ./src /var/portal
|
||||
- *step-save-src-cache
|
||||
- aks-specific-step:
|
||||
circle:
|
||||
- *step-save-src-cache
|
||||
aks:
|
||||
- *step-save-src-cache-aks
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
- *step-make-src-cache-marker
|
||||
- *step-save-src-cache-marker
|
||||
- aks-specific-step:
|
||||
circle:
|
||||
- *step-save-src-cache-marker
|
||||
aks:
|
||||
- *step-save-src-cache-marker-aks
|
||||
could-be-aks: << parameters.could-be-aks >>
|
||||
|
||||
- when:
|
||||
condition: << parameters.build >>
|
||||
@@ -1447,6 +1618,18 @@ commands:
|
||||
condition: << parameters.build >>
|
||||
steps:
|
||||
- *step-maybe-notify-slack-failure
|
||||
- when:
|
||||
condition: << parameters.could-be-aks >>
|
||||
steps:
|
||||
- run:
|
||||
name: Wait for active debug sessions
|
||||
command: |
|
||||
while [ -f /var/.ssh-lock ]
|
||||
do
|
||||
sleep 60
|
||||
done
|
||||
no_output_timeout: 2h
|
||||
when: always
|
||||
|
||||
electron-tests:
|
||||
parameters:
|
||||
@@ -1482,17 +1665,15 @@ commands:
|
||||
export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer
|
||||
export MOCHA_TIMEOUT=180000
|
||||
echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)"
|
||||
(cd electron && (circleci tests glob "spec/*-spec.ts" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings 2>&1)) | $ASAN_SYMBOLIZE
|
||||
(cd electron && (circleci tests glob "spec/*-spec.ts" | xargs -I@ -P4 bash -c "echo $(pwd)/@" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings 2>&1)) | $ASAN_SYMBOLIZE
|
||||
else
|
||||
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true
|
||||
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
|
||||
else
|
||||
if [ "$TARGET_ARCH" == "ia32" ]; then
|
||||
npm_config_arch=x64 node electron/node_modules/dugite/script/download-git.js
|
||||
fi
|
||||
(cd electron && (circleci tests glob "spec/*-spec.ts" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings))
|
||||
fi
|
||||
if [ "$TARGET_ARCH" == "ia32" ]; then
|
||||
npm_config_arch=x64 node electron/node_modules/dugite/script/download-git.js
|
||||
fi
|
||||
(cd electron && (circleci tests glob "spec/*-spec.ts" | xargs -I@ -P4 bash -c "echo $(pwd)/@" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings))
|
||||
fi
|
||||
- store_test_results:
|
||||
path: src/junit
|
||||
@@ -1575,6 +1756,7 @@ commands:
|
||||
- *step-minimize-workspace-size-from-checkout
|
||||
- *step-fix-sync
|
||||
- *step-setup-env-for-build
|
||||
- *step-fix-known-hosts-linux
|
||||
- *step-setup-goma-for-build
|
||||
- *step-wait-for-goma
|
||||
- *step-gn-gen-default
|
||||
@@ -1632,7 +1814,7 @@ jobs:
|
||||
linux-make-src-cache:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
@@ -1645,6 +1827,7 @@ jobs:
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: true
|
||||
|
||||
mac-checkout:
|
||||
executor:
|
||||
@@ -1664,6 +1847,7 @@ jobs:
|
||||
restore-src-cache: false
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: false
|
||||
|
||||
mac-make-src-cache:
|
||||
executor:
|
||||
@@ -1683,12 +1867,13 @@ jobs:
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: false
|
||||
|
||||
# Layer 2: Builds.
|
||||
linux-x64-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-testing-build
|
||||
@@ -1701,11 +1886,12 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
artifact-key: 'linux-x64'
|
||||
build-type: 'Linux'
|
||||
could-be-aks: true
|
||||
|
||||
linux-x64-testing-asan:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-testing-build
|
||||
@@ -1716,15 +1902,17 @@ jobs:
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: true
|
||||
checkout: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
build-nonproprietary-ffmpeg: false
|
||||
artifact-key: 'linux-x64-asan'
|
||||
build-type: 'Linux'
|
||||
could-be-aks: true
|
||||
|
||||
linux-x64-testing-no-run-as-node:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
<<: *env-testing-build
|
||||
@@ -1737,21 +1925,24 @@ jobs:
|
||||
checkout: true
|
||||
artifact-key: 'linux-x64-no-run-as-node'
|
||||
build-type: 'Linux'
|
||||
could-be-aks: true
|
||||
|
||||
linux-x64-testing-gn-check:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: medium
|
||||
size: << pipeline.parameters.medium-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-medium
|
||||
<<: *env-testing-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
<<: *steps-electron-gn-check
|
||||
steps:
|
||||
- run-gn-check:
|
||||
could-be-aks: true
|
||||
|
||||
linux-x64-publish:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-2xlarge-release
|
||||
<<: *env-release-build
|
||||
@@ -1774,7 +1965,7 @@ jobs:
|
||||
linux-arm-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-arm
|
||||
@@ -1790,11 +1981,12 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
artifact-key: 'linux-arm'
|
||||
build-type: 'Linux ARM'
|
||||
could-be-aks: true
|
||||
|
||||
linux-arm-publish:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-2xlarge-release
|
||||
<<: *env-arm
|
||||
@@ -1819,7 +2011,7 @@ jobs:
|
||||
linux-arm64-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-arm64
|
||||
@@ -1835,22 +2027,25 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
artifact-key: 'linux-arm64'
|
||||
build-type: 'Linux ARM64'
|
||||
could-be-aks: true
|
||||
|
||||
linux-arm64-testing-gn-check:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: medium
|
||||
size: << pipeline.parameters.medium-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-medium
|
||||
<<: *env-arm64
|
||||
<<: *env-testing-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
<<: *steps-electron-gn-check
|
||||
steps:
|
||||
- run-gn-check:
|
||||
could-be-aks: true
|
||||
|
||||
linux-arm64-publish:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-linux-2xlarge-release
|
||||
<<: *env-arm64
|
||||
@@ -1905,6 +2100,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- generated_artifacts_mas-x64
|
||||
could-be-aks: false
|
||||
|
||||
osx-testing-x64-gn-check:
|
||||
executor:
|
||||
@@ -1914,7 +2110,9 @@ jobs:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-testing-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
<<: *steps-electron-gn-check
|
||||
steps:
|
||||
- run-gn-check:
|
||||
could-be-aks: false
|
||||
|
||||
osx-publish-x64:
|
||||
executor:
|
||||
@@ -1997,6 +2195,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- generated_artifacts_mas-arm64
|
||||
could-be-aks: false
|
||||
|
||||
mas-publish-x64:
|
||||
executor:
|
||||
@@ -2103,6 +2302,7 @@ jobs:
|
||||
<<: *env-global
|
||||
<<: *env-headless-testing
|
||||
<<: *env-stack-dumping
|
||||
parallelism: 3
|
||||
steps:
|
||||
- electron-tests:
|
||||
artifact-key: linux-arm
|
||||
@@ -2114,6 +2314,7 @@ jobs:
|
||||
<<: *env-global
|
||||
<<: *env-headless-testing
|
||||
<<: *env-stack-dumping
|
||||
parallelism: 3
|
||||
steps:
|
||||
- electron-tests:
|
||||
artifact-key: linux-arm64
|
||||
|
||||
12
.circleci/config/params.js
Normal file
12
.circleci/config/params.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const fs = require('fs');
|
||||
|
||||
const PARAMS_PATH = '/tmp/pipeline-parameters.json';
|
||||
|
||||
const content = JSON.parse(fs.readFileSync(PARAMS_PATH, 'utf-8'));
|
||||
|
||||
// Choose resource class for linux hosts
|
||||
const currentBranch = process.env.CIRCLE_BRANCH || '';
|
||||
content['large-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? '2xlarge' : 'electronjs/aks-linux-large';
|
||||
content['medium-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? 'medium' : 'electronjs/aks-linux-medium';
|
||||
|
||||
fs.writeFileSync(PARAMS_PATH, JSON.stringify(content));
|
||||
@@ -3,5 +3,6 @@
|
||||
set -e
|
||||
|
||||
mkdir -p ~/.ssh
|
||||
echo "|1|B3r+7aO0/x90IdefihIjxIoJrrk=|OJddGDfhbuLFc1bUyy84hhIw57M= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
|1|rGlEvW55DtzNZp+pzw9gvyOyKi4=|LLWr+7qlkAlw3YGGVfLHHxB/kR0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts
|
||||
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ~/.ssh/known_hosts
|
||||
|
||||
1
BUILD.gn
1
BUILD.gn
@@ -791,6 +791,7 @@ if (is_mac) {
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//content/public/browser",
|
||||
"//skia",
|
||||
"//third_party/electron_node:node_lib",
|
||||
"//v8",
|
||||
|
||||
2
DEPS
2
DEPS
@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'116.0.5845.42',
|
||||
'116.0.5845.228',
|
||||
'node_version':
|
||||
'v18.16.1',
|
||||
'nan_version':
|
||||
|
||||
@@ -78,7 +78,7 @@ binary. Use this to spawn Electron from Node scripts:
|
||||
|
||||
```javascript
|
||||
const electron = require('electron')
|
||||
const proc = require('child_process')
|
||||
const proc = require('node:child_process')
|
||||
|
||||
// will print something similar to /Users/maf/.../Electron
|
||||
console.log(electron)
|
||||
|
||||
@@ -72,8 +72,10 @@ for:
|
||||
- ps: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "false"
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"
|
||||
Write-warning "Skipping build for doc-only change"
|
||||
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "true"
|
||||
Exit-AppveyorBuild
|
||||
} else {
|
||||
$global:LASTEXITCODE = 0
|
||||
@@ -114,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 {
|
||||
@@ -164,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
|
||||
@@ -185,6 +187,30 @@ for:
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
if ($env:SHOULD_SKIP_ARTIFACT_VALIDATION -eq 'true') {
|
||||
Write-warning "Skipping artifact validation for doc-only PR"
|
||||
} else {
|
||||
$artifacts_to_validate = 'dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip'
|
||||
foreach($artifact_name in $artifacts_to_validate) {
|
||||
if ($artifact_name -eq 'ffmpeg.zip') {
|
||||
$artifact_file = "out\ffmpeg\ffmpeg.zip"
|
||||
} elseif ($artifact_name -eq 'node_headers.zip') {
|
||||
$artifact_file = $artifact_name
|
||||
} else {
|
||||
$artifact_file = "out\Default\$artifact_name"
|
||||
}
|
||||
if (-not(Test-Path $artifact_file)) {
|
||||
Write-warning "$artifact_name is missing and cannot be added to artifacts"
|
||||
$missing_artifacts = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($missing_artifacts) {
|
||||
throw "Build failed due to missing artifacts"
|
||||
}
|
||||
|
||||
deploy_script:
|
||||
- cd electron
|
||||
@@ -201,28 +227,16 @@ for:
|
||||
on_finish:
|
||||
# Uncomment this lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
$artifacts_to_upload = @('dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip')
|
||||
foreach($artifact_name in $artifacts_to_upload) {
|
||||
if ($artifact_name -eq 'ffmpeg.zip') {
|
||||
$artifact_file = "out\ffmpeg\ffmpeg.zip"
|
||||
} elseif ($artifact_name -eq 'node_headers.zip') {
|
||||
$artifact_file = $artifact_name
|
||||
} else {
|
||||
$artifact_file = "out\Default\$artifact_name"
|
||||
}
|
||||
if (Test-Path $artifact_file) {
|
||||
appveyor-retry appveyor PushArtifact $artifact_file
|
||||
} else {
|
||||
Write-warning "$artifact_name is missing and cannot be added to artifacts"
|
||||
$missing_artifacts = $true
|
||||
}
|
||||
}
|
||||
if ($missing_artifacts) {
|
||||
throw "Build failed due to missing artifacts"
|
||||
}
|
||||
- cd C:\projects\src
|
||||
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
|
||||
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
|
||||
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
|
||||
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
|
||||
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
|
||||
64
appveyor.yml
64
appveyor.yml
@@ -70,8 +70,10 @@ for:
|
||||
- ps: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "false"
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"
|
||||
Write-warning "Skipping build for doc-only change"
|
||||
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "true"
|
||||
Exit-AppveyorBuild
|
||||
} else {
|
||||
$global:LASTEXITCODE = 0
|
||||
@@ -112,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 {
|
||||
@@ -162,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
|
||||
@@ -183,6 +185,30 @@ for:
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
if ($env:SHOULD_SKIP_ARTIFACT_VALIDATION -eq 'true') {
|
||||
Write-warning "Skipping artifact validation for doc-only PR"
|
||||
} else {
|
||||
$artifacts_to_validate = 'dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip'
|
||||
foreach($artifact_name in $artifacts_to_validate) {
|
||||
if ($artifact_name -eq 'ffmpeg.zip') {
|
||||
$artifact_file = "out\ffmpeg\ffmpeg.zip"
|
||||
} elseif ($artifact_name -eq 'node_headers.zip') {
|
||||
$artifact_file = $artifact_name
|
||||
} else {
|
||||
$artifact_file = "out\Default\$artifact_name"
|
||||
}
|
||||
if (-not(Test-Path $artifact_file)) {
|
||||
Write-warning "$artifact_name is missing and cannot be added to artifacts"
|
||||
$missing_artifacts = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($missing_artifacts) {
|
||||
throw "Build failed due to missing artifacts"
|
||||
}
|
||||
|
||||
deploy_script:
|
||||
- cd electron
|
||||
@@ -199,28 +225,16 @@ for:
|
||||
on_finish:
|
||||
# Uncomment this lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
$artifacts_to_upload = @('dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip')
|
||||
foreach($artifact_name in $artifacts_to_upload) {
|
||||
if ($artifact_name -eq 'ffmpeg.zip') {
|
||||
$artifact_file = "out\ffmpeg\ffmpeg.zip"
|
||||
} elseif ($artifact_name -eq 'node_headers.zip') {
|
||||
$artifact_file = $artifact_name
|
||||
} else {
|
||||
$artifact_file = "out\Default\$artifact_name"
|
||||
}
|
||||
if (Test-Path $artifact_file) {
|
||||
appveyor-retry appveyor PushArtifact $artifact_file
|
||||
} else {
|
||||
Write-warning "$artifact_name is missing and cannot be added to artifacts"
|
||||
$missing_artifacts = $true
|
||||
}
|
||||
}
|
||||
if ($missing_artifacts) {
|
||||
throw "Build failed due to missing artifacts"
|
||||
}
|
||||
- cd C:\projects\src
|
||||
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
|
||||
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
|
||||
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
|
||||
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
|
||||
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
|
||||
@@ -52,3 +52,11 @@ use_perfetto_client_library = false
|
||||
|
||||
# Disables the builtins PGO for V8
|
||||
v8_builtins_profiling_log_file = ""
|
||||
|
||||
# Disable threadisolated allocator implementation from gin for partition allocator,
|
||||
# we are seeing crashes for Linux x64 users when node integration is enabled in the
|
||||
# renderer process causing SIGSEGV when the periodic memory reclaimer runs,
|
||||
# Refs https://github.com/electron/electron/issues/39775.
|
||||
# The current only user of this pool is the v8 CFI which is
|
||||
# not enabled on this branch, so it is safe to disable the feature.
|
||||
enable_pkeys = false
|
||||
|
||||
@@ -177,6 +177,10 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc",
|
||||
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h",
|
||||
]
|
||||
sources += [
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.cc",
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.h",
|
||||
]
|
||||
public_deps += [
|
||||
"//components/dbus/menu",
|
||||
"//components/dbus/thread_linux",
|
||||
@@ -329,6 +333,34 @@ static_library("chrome") {
|
||||
"//components/pdf/renderer",
|
||||
]
|
||||
}
|
||||
} else {
|
||||
# These are required by the webRequest module.
|
||||
sources += [
|
||||
"//extensions/browser/api/declarative_net_request/request_action.cc",
|
||||
"//extensions/browser/api/declarative_net_request/request_action.h",
|
||||
"//extensions/browser/api/web_request/form_data_parser.cc",
|
||||
"//extensions/browser/api/web_request/form_data_parser.h",
|
||||
"//extensions/browser/api/web_request/upload_data_presenter.cc",
|
||||
"//extensions/browser/api/web_request/upload_data_presenter.h",
|
||||
"//extensions/browser/api/web_request/web_request_api_constants.cc",
|
||||
"//extensions/browser/api/web_request/web_request_api_constants.h",
|
||||
"//extensions/browser/api/web_request/web_request_info.cc",
|
||||
"//extensions/browser/api/web_request/web_request_info.h",
|
||||
"//extensions/browser/api/web_request/web_request_resource_type.cc",
|
||||
"//extensions/browser/api/web_request/web_request_resource_type.h",
|
||||
"//extensions/browser/extension_api_frame_id_map.cc",
|
||||
"//extensions/browser/extension_api_frame_id_map.h",
|
||||
"//extensions/browser/extension_navigation_ui_data.cc",
|
||||
"//extensions/browser/extension_navigation_ui_data.h",
|
||||
"//extensions/browser/extensions_browser_client.cc",
|
||||
"//extensions/browser/extensions_browser_client.h",
|
||||
"//extensions/browser/guest_view/web_view/web_view_renderer_state.cc",
|
||||
"//extensions/browser/guest_view/web_view/web_view_renderer_state.h",
|
||||
]
|
||||
|
||||
public_deps += [
|
||||
"//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
|
||||
]
|
||||
}
|
||||
|
||||
if (!is_mas_build) {
|
||||
@@ -361,6 +393,7 @@ if (is_mac) {
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//content/public/browser",
|
||||
"//skia",
|
||||
"//third_party/electron_node:node_lib",
|
||||
"//third_party/webrtc_overrides:webrtc_component",
|
||||
|
||||
@@ -413,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.
|
||||
@@ -1146,11 +1135,11 @@ indicates success while any other value indicates failure according to Chromium
|
||||
resolver will attempt to use the system's DNS settings to do DNS lookups
|
||||
itself. Enabled by default on macOS, disabled by default on Windows and
|
||||
Linux.
|
||||
* `secureDnsMode` string (optional) - Can be "off", "automatic" or "secure".
|
||||
Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be
|
||||
performed. When "automatic", DoH lookups will be performed first if DoH is
|
||||
* `secureDnsMode` string (optional) - Can be 'off', 'automatic' or 'secure'.
|
||||
Configures the DNS-over-HTTP mode. When 'off', no DoH lookups will be
|
||||
performed. When 'automatic', DoH lookups will be performed first if DoH is
|
||||
available, and insecure DNS lookups will be performed as a fallback. When
|
||||
"secure", only DoH lookups will be performed. Defaults to "automatic".
|
||||
'secure', only DoH lookups will be performed. Defaults to 'automatic'.
|
||||
* `secureDnsServers` string[] (optional) - A list of DNS-over-HTTP
|
||||
server templates. See [RFC8484 § 3][] for details on the template format.
|
||||
Most servers support the POST method; the template for such servers is
|
||||
@@ -1342,7 +1331,7 @@ application name. For example:
|
||||
|
||||
``` js
|
||||
const { app } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const appFolder = path.dirname(process.execPath)
|
||||
const updateExe = path.resolve(appFolder, '..', 'Update.exe')
|
||||
@@ -1413,7 +1402,7 @@ Returns `Function` - This function **must** be called once you have finished acc
|
||||
|
||||
```js
|
||||
const { app, dialog } = require('electron')
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
|
||||
let filepath
|
||||
let bookmark
|
||||
|
||||
@@ -505,6 +505,10 @@ events.
|
||||
|
||||
A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application.
|
||||
|
||||
#### `win.tabbingIdentifier` _macOS_ _Readonly_
|
||||
|
||||
A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set.
|
||||
|
||||
#### `win.autoHideMenuBar`
|
||||
|
||||
A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key.
|
||||
@@ -820,10 +824,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.
|
||||
@@ -1207,7 +1215,7 @@ const win = new BrowserWindow()
|
||||
const url = require('url').format({
|
||||
protocol: 'file',
|
||||
slashes: true,
|
||||
pathname: require('path').join(__dirname, 'index.html')
|
||||
pathname: require('node:path').join(__dirname, 'index.html')
|
||||
})
|
||||
|
||||
win.loadURL(url)
|
||||
|
||||
@@ -116,14 +116,20 @@ Ignore the connections limit for `domains` list separated by `,`.
|
||||
|
||||
### --js-flags=`flags`
|
||||
|
||||
Specifies the flags passed to the Node.js engine. It has to be passed when starting
|
||||
Electron if you want to enable the `flags` in the main process.
|
||||
Specifies the flags passed to the [V8 engine](https://v8.dev). In order to enable the `flags` in the main process,
|
||||
this switch must be passed on startup.
|
||||
|
||||
```sh
|
||||
$ electron --js-flags="--harmony_proxies --harmony_collections" your-app
|
||||
```
|
||||
|
||||
See the [Node.js documentation][node-cli] or run `node --help` in your terminal for a list of available flags. Additionally, run `node --v8-options` to see a list of flags that specifically refer to Node.js's V8 JavaScript engine.
|
||||
Run `node --v8-options` or `electron --js-flags="--help"` in your terminal for the list of available flags. These can be used to enable early-stage JavaScript features, or log and manipulate garbage collection, among other things.
|
||||
|
||||
For example, to trace V8 optimization and deoptimization:
|
||||
|
||||
```sh
|
||||
$ electron --js-flags="--trace-opt --trace-deopt" your-app
|
||||
```
|
||||
|
||||
### --lang
|
||||
|
||||
@@ -241,19 +247,25 @@ Electron supports some of the [CLI flags][node-cli] supported by Node.js.
|
||||
|
||||
**Note:** Passing unsupported command line switches to Electron when it is not running in `ELECTRON_RUN_AS_NODE` will have no effect.
|
||||
|
||||
### --inspect-brk\[=\[host:]port]
|
||||
### `--inspect-brk\[=\[host:]port]`
|
||||
|
||||
Activate inspector on host:port and break at start of user script. Default host:port is 127.0.0.1:9229.
|
||||
|
||||
Aliased to `--debug-brk=[host:]port`.
|
||||
|
||||
### --inspect-port=\[host:]port
|
||||
#### `--inspect-brk-node[=[host:]port]`
|
||||
|
||||
Activate inspector on `host:port` and break at start of the first internal
|
||||
JavaScript script executed when the inspector is available.
|
||||
Default `host:port` is `127.0.0.1:9229`.
|
||||
|
||||
### `--inspect-port=\[host:]port`
|
||||
|
||||
Set the `host:port` to be used when the inspector is activated. Useful when activating the inspector by sending the SIGUSR1 signal. Default host is `127.0.0.1`.
|
||||
|
||||
Aliased to `--debug-port=[host:]port`.
|
||||
|
||||
### --inspect\[=\[host:]port]
|
||||
### `--inspect\[=\[host:]port]`
|
||||
|
||||
Activate inspector on `host:port`. Default is `127.0.0.1:9229`.
|
||||
|
||||
@@ -263,12 +275,37 @@ See the [Debugging the Main Process][debugging-main-process] guide for more deta
|
||||
|
||||
Aliased to `--debug[=[host:]port`.
|
||||
|
||||
### --inspect-publish-uid=stderr,http
|
||||
### `--inspect-publish-uid=stderr,http`
|
||||
|
||||
Specify ways of the inspector web socket url exposure.
|
||||
|
||||
By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list.
|
||||
|
||||
### `--no-deprecation`
|
||||
|
||||
Silence deprecation warnings.
|
||||
|
||||
### `--throw-deprecation`
|
||||
|
||||
Throw errors for deprecations.
|
||||
|
||||
### `--trace-deprecation`
|
||||
|
||||
Print stack traces for deprecations.
|
||||
|
||||
### `--trace-warnings`
|
||||
|
||||
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
|
||||
|
||||
@@ -147,7 +147,7 @@ Be very cautious about which globals and APIs you expose to untrusted remote con
|
||||
|
||||
```javascript
|
||||
const { contextBridge } = require('electron')
|
||||
const crypto = require('crypto')
|
||||
const crypto = require('node:crypto')
|
||||
contextBridge.exposeInMainWorld('nodeCrypto', {
|
||||
sha256sum (data) {
|
||||
const hash = crypto.createHash('sha256')
|
||||
|
||||
@@ -119,4 +119,8 @@ Removes the cookies matching `url` and `name`
|
||||
|
||||
Returns `Promise<void>` - A promise which resolves when the cookie store has been flushed
|
||||
|
||||
Writes any unwritten cookies data to disk.
|
||||
Writes any unwritten cookies data to disk
|
||||
|
||||
Cookies written by any method will not be written to disk immediately, but will be written every 30 seconds or 512 operations
|
||||
|
||||
Calling this method can cause the cookie to be written to disk immediately.
|
||||
|
||||
@@ -91,7 +91,7 @@ The `desktopCapturer` module has the following methods:
|
||||
|
||||
* `options` Object
|
||||
* `types` string[] - An array of strings that lists the types of desktop sources
|
||||
to be captured, available types are `screen` and `window`.
|
||||
to be captured, available types can be `screen` and `window`.
|
||||
* `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail
|
||||
should be scaled to. Default is `150` x `150`. Set width or height to 0 when you do not need
|
||||
the thumbnails. This will save the processing time required for capturing the content of each
|
||||
|
||||
@@ -40,18 +40,41 @@ We support the following extensions APIs, with some caveats. Other APIs may
|
||||
additionally be supported, but support for any APIs not listed here is
|
||||
provisional and may be removed.
|
||||
|
||||
### Supported Manifest Keys
|
||||
|
||||
- `name`
|
||||
- `version`
|
||||
- `author`
|
||||
- `permissions`
|
||||
- `content_scripts`
|
||||
- `default_locale`
|
||||
- `devtools_page`
|
||||
- `short_name`
|
||||
- `host_permissions` (Manifest V3)
|
||||
- `manifest_version`
|
||||
- `background` (Manifest V2)
|
||||
- `minimum_chrome_version`
|
||||
|
||||
See [Manifest file format](https://developer.chrome.com/docs/extensions/mv3/manifest/) for more information about the purpose of each possible key.
|
||||
|
||||
### `chrome.devtools.inspectedWindow`
|
||||
|
||||
All features of this API are supported.
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_inspectedWindow) for more information.
|
||||
|
||||
### `chrome.devtools.network`
|
||||
|
||||
All features of this API are supported.
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_network) for more information.
|
||||
|
||||
### `chrome.devtools.panels`
|
||||
|
||||
All features of this API are supported.
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/devtools_panels) for more information.
|
||||
|
||||
### `chrome.extension`
|
||||
|
||||
The following properties of `chrome.extension` are supported:
|
||||
@@ -63,6 +86,25 @@ The following methods of `chrome.extension` are supported:
|
||||
- `chrome.extension.getURL`
|
||||
- `chrome.extension.getBackgroundPage`
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/extension) for more information.
|
||||
|
||||
### `chrome.management`
|
||||
|
||||
The following methods of `chrome.management` are supported:
|
||||
|
||||
- `chrome.management.getAll`
|
||||
- `chrome.management.get`
|
||||
- `chrome.management.getSelf`
|
||||
- `chrome.management.getPermissionWarningsById`
|
||||
- `chrome.management.getPermissionWarningsByManifest`
|
||||
|
||||
The following events of `chrome.management` are supported:
|
||||
|
||||
- `chrome.management.onEnabled`
|
||||
- `chrome.management.onDisabled`
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/management) for more information.
|
||||
|
||||
### `chrome.runtime`
|
||||
|
||||
The following properties of `chrome.runtime` are supported:
|
||||
@@ -89,10 +131,23 @@ The following events of `chrome.runtime` are supported:
|
||||
- `chrome.runtime.onConnect`
|
||||
- `chrome.runtime.onMessage`
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/runtime) for more information.
|
||||
|
||||
### `chrome.scripting`
|
||||
|
||||
All features of this API are supported.
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/scripting) for more information.
|
||||
|
||||
### `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.storage.sync` and `chrome.storage.managed` are **not** supported.
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/storage) for more information.
|
||||
|
||||
### `chrome.tabs`
|
||||
|
||||
@@ -101,6 +156,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`.
|
||||
|
||||
@@ -108,20 +165,12 @@ The following methods of `chrome.tabs` are supported:
|
||||
> tab". Since Electron has no such concept, passing `-1` as a tab ID is not
|
||||
> supported and will raise an error.
|
||||
|
||||
### `chrome.management`
|
||||
|
||||
The following methods of `chrome.management` are supported:
|
||||
|
||||
- `chrome.management.getAll`
|
||||
- `chrome.management.get`
|
||||
- `chrome.management.getSelf`
|
||||
- `chrome.management.getPermissionWarningsById`
|
||||
- `chrome.management.getPermissionWarningsByManifest`
|
||||
- `chrome.management.onEnabled`
|
||||
- `chrome.management.onDisabled`
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/tabs) for more information.
|
||||
|
||||
### `chrome.webRequest`
|
||||
|
||||
All features of this API are supported.
|
||||
|
||||
> **NOTE:** Electron's [`webRequest`](web-request.md) module takes precedence over `chrome.webRequest` if there are conflicting handlers.
|
||||
|
||||
See [official documentation](https://developer.chrome.com/docs/extensions/reference/webRequest) for more information.
|
||||
|
||||
@@ -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,7 +109,7 @@ provided to the renderer process. Please refer to
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function<Promise\<void> | any>
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ Returns `NativeImage` - The cropped image.
|
||||
* `width` Integer (optional) - Defaults to the image's width.
|
||||
* `height` Integer (optional) - Defaults to the image's height.
|
||||
* `quality` string (optional) - The desired quality of the resize image.
|
||||
Possible values are `good`, `better`, or `best`. The default is `best`.
|
||||
Possible values include `good`, `better`, or `best`. The default is `best`.
|
||||
These values express a desired quality/speed tradeoff. They are translated
|
||||
into an algorithm-specific method that depends on the capabilities
|
||||
(CPU, GPU) of the underlying platform. It is possible for all three methods
|
||||
|
||||
@@ -85,6 +85,8 @@ Emitted when the notification is closed by manual intervention from the user.
|
||||
This event is not guaranteed to be emitted in all cases where the notification
|
||||
is closed.
|
||||
|
||||
On Windows, the `close` event can be emitted in one of three ways: programmatic dismissal with `notification.close()`, by the user closing the notification, or via system timeout. If a notification is in the Action Center after the initial `close` event is emitted, a call to `notification.close()` will remove the notification from the action center but the `close` event will not be emitted again.
|
||||
|
||||
#### Event: 'reply' _macOS_
|
||||
|
||||
Returns:
|
||||
@@ -127,6 +129,8 @@ shown notification and create a new one with identical properties.
|
||||
|
||||
Dismisses the notification.
|
||||
|
||||
On Windows, calling `notification.close()` while the notification is visible on screen will dismiss the notification and remove it from the Action Center. If `notification.close()` is called after the notification is no longer visible on screen, calling `notification.close()` will try remove it from the Action Center.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `notification.title`
|
||||
|
||||
@@ -49,6 +49,8 @@ is used.
|
||||
|
||||
Stops the specified power save blocker.
|
||||
|
||||
Returns `boolean` - Whether the specified `powerSaveBlocker` has been stopped.
|
||||
|
||||
### `powerSaveBlocker.isStarted(id)`
|
||||
|
||||
* `id` Integer - The power save blocker id returned by `powerSaveBlocker.start`.
|
||||
|
||||
@@ -33,7 +33,7 @@ to register it to that session explicitly.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow, net, protocol, session } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
const url = require('url')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
@@ -122,7 +122,7 @@ Example:
|
||||
|
||||
```js
|
||||
const { app, net, protocol } = require('electron')
|
||||
const { join } = require('path')
|
||||
const { join } = require('node:path')
|
||||
const { pathToFileURL } = require('url')
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
|
||||
@@ -103,7 +103,7 @@ const { session } = require('electron')
|
||||
session.defaultSession.on('will-download', (event, item, webContents) => {
|
||||
event.preventDefault()
|
||||
require('got')(item.getURL()).then((response) => {
|
||||
require('fs').writeFileSync('/somewhere', response.body)
|
||||
require('node:fs').writeFileSync('/somewhere', response.body)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -266,7 +266,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `device` [HIDDevice](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted after `navigator.hid.requestDevice` has been called and
|
||||
@@ -281,7 +281,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `device` [HIDDevice](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted after `navigator.hid.requestDevice` has been called and
|
||||
@@ -296,7 +296,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `device` [HIDDevice](structures/hid-device.md)
|
||||
* `origin` string (optional) - The origin that the device has been revoked from.
|
||||
|
||||
Emitted after `HIDDevice.forget()` has been called. This event can be used
|
||||
@@ -574,11 +574,11 @@ Clears the session’s HTTP cache.
|
||||
* `options` Object (optional)
|
||||
* `origin` string (optional) - Should follow `window.location.origin`’s representation
|
||||
`scheme://host:port`.
|
||||
* `storages` string[] (optional) - The types of storages to clear, can contain:
|
||||
* `storages` string[] (optional) - The types of storages to clear, can be
|
||||
`cookies`, `filesystem`, `indexdb`, `localstorage`,
|
||||
`shadercache`, `websql`, `serviceworkers`, `cachestorage`. If not
|
||||
specified, clear all storage types.
|
||||
* `quotas` string[] (optional) - The types of quotas to clear, can contain:
|
||||
* `quotas` string[] (optional) - The types of quotas to clear, can be
|
||||
`temporary`, `syncable`. If not specified, clear all quotas.
|
||||
|
||||
Returns `Promise<void>` - resolves when the storage data has been cleared.
|
||||
@@ -785,7 +785,7 @@ Returns `Promise<void>` - Resolves when all connections are closed.
|
||||
#### `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)
|
||||
* `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).
|
||||
|
||||
@@ -901,6 +901,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
|
||||
* `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification)
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
|
||||
* `unknown` - An unrecognized permission request.
|
||||
@@ -1113,7 +1114,7 @@ app.whenReady().then(() => {
|
||||
|
||||
* `handler` Function\<string[]> | null
|
||||
* `details` Object
|
||||
* `protectedClasses` string[] - The current list of protected USB classes. Possible class values are:
|
||||
* `protectedClasses` string[] - The current list of protected USB classes. Possible class values include:
|
||||
* `audio`
|
||||
* `audio-video`
|
||||
* `hid`
|
||||
@@ -1193,7 +1194,7 @@ automatically. To clear the handler, call `setBluetoothPairingHandler(null)`.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow, session } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
let bluetoothPinCallback = null
|
||||
@@ -1311,7 +1312,7 @@ 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)`
|
||||
|
||||
@@ -1457,7 +1458,7 @@ extension to be loaded.
|
||||
|
||||
```js
|
||||
const { app, session } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
await session.defaultSession.loadExtension(
|
||||
@@ -1491,7 +1492,7 @@ is emitted.
|
||||
|
||||
* `extensionId` string - ID of extension to query
|
||||
|
||||
Returns `Extension` | `null` - The loaded extension with the given ID.
|
||||
Returns `Extension | null` - The loaded extension with the given ID.
|
||||
|
||||
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||
is emitted.
|
||||
@@ -1544,7 +1545,7 @@ A [`Protocol`](protocol.md) object for this session.
|
||||
|
||||
```javascript
|
||||
const { app, session } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const protocol = session.fromPartition('some-partition').protocol
|
||||
|
||||
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.
|
||||
@@ -6,7 +6,7 @@ Process: [Main](../glossary.md#main-process)
|
||||
|
||||
```javascript
|
||||
const { systemPreferences } = require('electron')
|
||||
console.log(systemPreferences.isDarkMode())
|
||||
console.log(systemPreferences.isAeroGlassEnabled())
|
||||
```
|
||||
|
||||
## Events
|
||||
@@ -47,12 +47,6 @@ Returns:
|
||||
|
||||
## Methods
|
||||
|
||||
### `systemPreferences.isDarkMode()` _macOS_ _Windows_ _Deprecated_
|
||||
|
||||
Returns `boolean` - Whether the system is in Dark Mode.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseDarkColors`](native-theme.md#nativethemeshouldusedarkcolors-readonly) API.
|
||||
|
||||
### `systemPreferences.isSwipeTrackingFromScrollEventsEnabled()` _macOS_
|
||||
|
||||
Returns `boolean` - Whether the Swipe between pages setting is on.
|
||||
@@ -356,18 +350,6 @@ Returns `string` - The standard system color formatted as `#RRGGBBAA`.
|
||||
|
||||
Returns one of several standard system colors that automatically adapt to vibrancy and changes in accessibility settings like 'Increase contrast' and 'Reduce transparency'. See [Apple Documentation](https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#system-colors) for more details.
|
||||
|
||||
### `systemPreferences.isInvertedColorScheme()` _Windows_ _Deprecated_
|
||||
|
||||
Returns `boolean` - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is active, `false` otherwise.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseInvertedColorScheme`](native-theme.md#nativethemeshoulduseinvertedcolorscheme-macos-windows-readonly) API.
|
||||
|
||||
### `systemPreferences.isHighContrastColorScheme()` _macOS_ _Windows_ _Deprecated_
|
||||
|
||||
Returns `boolean` - `true` if a high contrast theme is active, `false` otherwise.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseHighContrastColors`](native-theme.md#nativethemeshouldusehighcontrastcolors-macos-windows-readonly) API.
|
||||
|
||||
### `systemPreferences.getEffectiveAppearance()` _macOS_
|
||||
|
||||
Returns `string` - Can be `dark`, `light` or `unknown`.
|
||||
@@ -453,7 +435,11 @@ Returns an object with system animation settings.
|
||||
|
||||
## Properties
|
||||
|
||||
### `systemPreferences.appLevelAppearance` _macOS_
|
||||
### `systemPreferences.accessibilityDisplayShouldReduceTransparency()` _macOS_
|
||||
|
||||
A `boolean` property which determines whether the app avoids using semitransparent backgrounds. This maps to [NSWorkspace.accessibilityDisplayShouldReduceTransparency](https://developer.apple.com/documentation/appkit/nsworkspace/1533006-accessibilitydisplayshouldreduce)
|
||||
|
||||
### `systemPreferences.appLevelAppearance` _macOS_ _Deprecated_
|
||||
|
||||
A `string` property that can be `dark`, `light` or `unknown`. It determines the macOS appearance setting for
|
||||
your application. This maps to values in: [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). Setting this will override the
|
||||
|
||||
@@ -29,7 +29,7 @@ Process: [Main](../glossary.md#main-process)<br />
|
||||
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit']
|
||||
* `serviceName` string (optional) - Name of the process that will appear in `name` property of
|
||||
[`child-process-gone` event of `app`](app.md#event-child-process-gone).
|
||||
Default is `node.mojom.NodeService`.
|
||||
Default is `Node Utility Process`.
|
||||
* `allowLoadingUnsignedLibraries` boolean (optional) _macOS_ - With this flag, the utility process will be
|
||||
launched via the `Electron Helper (Plugin).app` helper executable on macOS, which can be
|
||||
codesigned with `com.apple.security.cs.disable-library-validation` and
|
||||
|
||||
@@ -479,18 +479,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.
|
||||
@@ -795,7 +784,7 @@ Returns:
|
||||
* `frameCharset` string - The character encoding of the frame on which the
|
||||
menu was invoked.
|
||||
* `inputFieldType` string - If the context menu was invoked on an input
|
||||
field, the type of that field. Possible values are `none`, `plainText`,
|
||||
field, the type of that field. Possible values include `none`, `plainText`,
|
||||
`password`, `other`.
|
||||
* `spellcheckEnabled` boolean - If the context is editable, whether or not spellchecking is enabled.
|
||||
* `menuSourceType` string - Input source that invoked the context menu.
|
||||
@@ -1057,9 +1046,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.
|
||||
@@ -1220,7 +1211,7 @@ Returns `string` - The user agent for this web page.
|
||||
|
||||
* `css` string
|
||||
* `options` Object (optional)
|
||||
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
|
||||
Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`.
|
||||
|
||||
@@ -1646,9 +1637,9 @@ An example of `webContents.printToPDF`:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const os = require('node:os')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
@@ -113,7 +113,7 @@ webFrame.setSpellCheckProvider('en-US', {
|
||||
|
||||
* `css` string
|
||||
* `options` Object (optional)
|
||||
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
|
||||
Returns `string` - A key for the inserted CSS that can later be used to remove
|
||||
the CSS via `webFrame.removeInsertedCSS(key)`.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -983,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'
|
||||
|
||||
@@ -1091,7 +1106,7 @@ Returns:
|
||||
* `frameCharset` string - The character encoding of the frame on which the
|
||||
menu was invoked.
|
||||
* `inputFieldType` string - If the context menu was invoked on an input
|
||||
field, the type of that field. Possible values are `none`, `plainText`,
|
||||
field, the type of that field. Possible values include `none`, `plainText`,
|
||||
`password`, `other`.
|
||||
* `spellcheckEnabled` boolean - If the context is editable, whether or not spellchecking is enabled.
|
||||
* `menuSourceType` string - Input source that invoked the context menu.
|
||||
|
||||
@@ -21,6 +21,59 @@ macOS 10.13 (High Sierra) and macOS 10.14 (Mojave) are no longer supported by [C
|
||||
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 (26.0)
|
||||
|
||||
### Deprecated: `webContents.getPrinters`
|
||||
|
||||
The `webContents.getPrinters` method has been deprecated. Use
|
||||
`webContents.getPrintersAsync` instead.
|
||||
|
||||
```js
|
||||
const w = new BrowserWindow({ show: false })
|
||||
|
||||
// Deprecated
|
||||
console.log(w.webContents.getPrinters())
|
||||
// Replace with
|
||||
w.webContents.getPrintersAsync().then((printers) => {
|
||||
console.log(printers)
|
||||
})
|
||||
```
|
||||
|
||||
### Deprecated: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance`
|
||||
|
||||
The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance`
|
||||
methods have been deprecated, as well as the `systemPreferences.appLevelAppearance` property.
|
||||
Use the `nativeTheme` module instead.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
systemPreferences.getAppLevelAppearance()
|
||||
// Replace with
|
||||
nativeTheme.shouldUseDarkColors
|
||||
|
||||
// Deprecated
|
||||
systemPreferences.appLevelAppearance
|
||||
// Replace with
|
||||
nativeTheme.shouldUseDarkColors
|
||||
|
||||
// Deprecated
|
||||
systemPreferences.setAppLevelAppearance('dark')
|
||||
// Replace with
|
||||
nativeTheme.themeSource = 'dark'
|
||||
```
|
||||
|
||||
### Deprecated: `alternate-selected-control-text` value for `systemPreferences.getColor`
|
||||
|
||||
The `alternate-selected-control-text` value for `systemPreferences.getColor`
|
||||
has been deprecated. Use `selected-content-background` instead.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
systemPreferences.getColor('alternate-selected-control-text')
|
||||
// Replace with
|
||||
systemPreferences.getColor('selected-content-background')
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (25.0)
|
||||
|
||||
### Deprecated: `protocol.{register,intercept}{Buffer,String,Stream,File,Http}Protocol`
|
||||
@@ -542,6 +595,18 @@ to open synchronously scriptable child windows, among other incompatibilities.
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
### Deprecated: `app.runningUnderRosettaTranslation`
|
||||
|
||||
The `app.runningUnderRosettaTranslation` property has been deprecated.
|
||||
Use `app.runningUnderARM64Translation` instead.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
console.log(app.runningUnderRosettaTranslation)
|
||||
// Replace with
|
||||
console.log(app.runningUnderARM64Translation)
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (14.0)
|
||||
|
||||
### Removed: `remote` module
|
||||
|
||||
@@ -42,14 +42,14 @@ $ asar list /path/to/example.asar
|
||||
Read a file in the ASAR archive:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
fs.readFileSync('/path/to/example.asar/file.txt')
|
||||
```
|
||||
|
||||
List all files under the root of the archive:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
fs.readdirSync('/path/to/example.asar')
|
||||
```
|
||||
|
||||
@@ -99,7 +99,7 @@ You can also set `process.noAsar` to `true` to disable the support for `asar` in
|
||||
the `fs` module:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
process.noAsar = true
|
||||
fs.readFileSync('/path/to/example.asar')
|
||||
```
|
||||
|
||||
@@ -123,32 +123,19 @@ support via Electron's support for the [Chrome DevTools Protocol][] (CDP).
|
||||
|
||||
### Install dependencies
|
||||
|
||||
You can install Playwright through your preferred Node.js package manager. The Playwright team
|
||||
recommends using the `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` environment variable to avoid
|
||||
unnecessary browser downloads when testing an Electron app.
|
||||
|
||||
```sh npm2yarn
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --save-dev playwright
|
||||
```
|
||||
|
||||
Playwright also comes with its own test runner, Playwright Test, which is built for end-to-end
|
||||
testing. You can also install it as a dev dependency in your project:
|
||||
You can install Playwright through your preferred Node.js package manager. It comes with its
|
||||
own [test runner][playwright-intro], which is built for end-to-end testing:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev @playwright/test
|
||||
```
|
||||
|
||||
:::caution Dependencies
|
||||
This tutorial was written `playwright@1.16.3` and `@playwright/test@1.16.3`. Check out
|
||||
This tutorial was written with `@playwright/test@1.41.1`. Check out
|
||||
[Playwright's releases][playwright-releases] page to learn about
|
||||
changes that might affect the code below.
|
||||
:::
|
||||
|
||||
:::info Using third-party test runners
|
||||
If you're interested in using an alternative test runner (e.g. Jest or Mocha), check out
|
||||
Playwright's [Third-Party Test Runner][playwright-test-runners] guide.
|
||||
:::
|
||||
|
||||
### Write your tests
|
||||
|
||||
Playwright launches your app in development mode through the `_electron.launch` API.
|
||||
@@ -156,8 +143,7 @@ To point this API to your Electron app, you can pass the path to your main proce
|
||||
entry point (here, it is `main.js`).
|
||||
|
||||
```js {5} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
const { test, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('launch app', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
@@ -169,9 +155,8 @@ test('launch app', async () => {
|
||||
After that, you will access to an instance of Playwright's `ElectronApp` class. This
|
||||
is a powerful class that has access to main process modules for example:
|
||||
|
||||
```js {6-11} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
```js {5-10} @ts-nocheck
|
||||
const { test, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('get isPackaged', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
@@ -190,8 +175,7 @@ It can also create individual [Page][playwright-page] objects from Electron Brow
|
||||
For example, to grab the first BrowserWindow and save a screenshot:
|
||||
|
||||
```js {6-7} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
const { test, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('save screenshot', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
@@ -202,12 +186,11 @@ test('save screenshot', async () => {
|
||||
})
|
||||
```
|
||||
|
||||
Putting all this together using the PlayWright Test runner, let's create a `example.spec.js`
|
||||
Putting all this together using the Playwright test-runner, let's create a `example.spec.js`
|
||||
test file with a single test and assertion:
|
||||
|
||||
```js title='example.spec.js' @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test, expect } = require('@playwright/test')
|
||||
const { test, expect, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('example test', async () => {
|
||||
const electronApp = await electron.launch({ args: ['.'] })
|
||||
@@ -243,6 +226,7 @@ Running 1 test using 1 worker
|
||||
:::info
|
||||
Playwright Test will automatically run any files matching the `.*(test|spec)\.(js|ts|mjs)` regex.
|
||||
You can customize this match in the [Playwright Test configuration options][playwright-test-config].
|
||||
It also works with TypeScript out of the box.
|
||||
:::
|
||||
|
||||
:::tip Further reading
|
||||
@@ -260,7 +244,7 @@ To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.o
|
||||
The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js title='testDriver.js' @ts-nocheck
|
||||
const childProcess = require('child_process')
|
||||
const childProcess = require('node:child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
@@ -400,10 +384,10 @@ test.after.always('cleanup', async t => {
|
||||
|
||||
[chrome-driver]: https://sites.google.com/chromium.org/driver/
|
||||
[Puppeteer]: https://github.com/puppeteer/puppeteer
|
||||
[playwright-intro]: https://playwright.dev/docs/intro
|
||||
[playwright-electron]: https://playwright.dev/docs/api/class-electron/
|
||||
[playwright-electronapplication]: https://playwright.dev/docs/api/class-electronapplication
|
||||
[playwright-page]: https://playwright.dev/docs/api/class-page
|
||||
[playwright-releases]: https://github.com/microsoft/playwright/releases
|
||||
[playwright-releases]: https://playwright.dev/docs/release-notes
|
||||
[playwright-test-config]: https://playwright.dev/docs/api/class-testconfig#test-config-test-match
|
||||
[playwright-test-runners]: https://playwright.dev/docs/test-runners/
|
||||
[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/
|
||||
|
||||
@@ -136,7 +136,7 @@ Finally, the `main.js` file represents the main process and contains the actual
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -35,8 +35,8 @@ Using the [React Developer Tools][react-devtools] as an example:
|
||||
|
||||
```javascript
|
||||
const { app, session } = require('electron')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const path = require('node:path')
|
||||
const os = require('node:os')
|
||||
|
||||
// on macOS
|
||||
const reactDevToolsPath = path.join(
|
||||
|
||||
@@ -9,10 +9,11 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
|
||||
|
||||
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
|
||||
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | TBD | M116 | TBD | ✅ |
|
||||
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | TBD | M118 | TBD | ✅ |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-27 | M116 | v18.16 | ✅ |
|
||||
| 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 | ✅ |
|
||||
| 24.0.0 | 2023-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 | 🚫 |
|
||||
@@ -47,12 +48,6 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
|
||||
* Since Electron 6, Electron major versions have been targeting every other Chromium major version. Each Electron stable should happen on the same day as Chrome stable ([see blog post](https://www.electronjs.org/blog/12-week-cadence)).
|
||||
* Since Electron 16, Electron has been releasing major versions on an 8-week cadence in accordance to Chrome's change to a 4-week release cadence ([see blog post](https://www.electronjs.org/blog/8-week-cadence)).
|
||||
|
||||
:::info Chrome release dates
|
||||
|
||||
Chromium has the own public release schedule [here](https://chromiumdash.appspot.com/schedule).
|
||||
|
||||
:::
|
||||
|
||||
## Version support policy
|
||||
|
||||
:::info
|
||||
@@ -77,6 +72,38 @@ and the version prior to that receives the vast majority of those fixes
|
||||
as time and bandwidth warrants. The oldest supported release line will receive
|
||||
only security fixes directly.
|
||||
|
||||
### Chromium version support
|
||||
|
||||
:::info Chromium release schedule
|
||||
|
||||
Chromium's public release schedule is [here](https://chromiumdash.appspot.com/schedule).
|
||||
|
||||
:::
|
||||
|
||||
Electron targets Chromium even-number versions, releasing every 8 weeks in concert
|
||||
with Chromium's 4-week release schedule. For example, Electron 26 uses Chromium 116, while Electron 27 uses Chromium 118.
|
||||
|
||||
### Node.js version support
|
||||
|
||||
Electron upgrades its `main` branch to even-number versions of Node.js when they enter Active LTS. The schedule
|
||||
is as follows:
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true" alt="Releases">
|
||||
|
||||
As a rule, stable branches of Electron do not receive Node.js upgrades after they have been cut.
|
||||
If Electron has recently updated its `main` branch to a new major version of Node.js, the next stable
|
||||
branch to be cut will be released with the new version.
|
||||
|
||||
Patch upgrades of Node that contain significant security or bug fixes, and are submitted
|
||||
more than 2 weeks prior to a stable release date, will be accepted into an Electron alpha
|
||||
or beta release branch.
|
||||
|
||||
Minor upgrades of Node that contain significant security or bug fixes, and are submitted
|
||||
more than 2 weeks prior to a stable release date may be accepted into an Electron alpha or
|
||||
beta release branch on a case-by-case basis. These requests will be reviewed and voted on
|
||||
by the [Releases Working Group](https://github.com/electron/governance/tree/main/wg-releases),
|
||||
to ensure minimal disruption for developers who may be consuming alpha or beta releases.
|
||||
|
||||
### Breaking API changes
|
||||
|
||||
When an API is changed or removed in a way that breaks existing functionality, the
|
||||
|
||||
@@ -4,15 +4,48 @@ Electron Forge is a tool for packaging and publishing Electron applications.
|
||||
It unifies Electron's build tooling ecosystem into
|
||||
a single extensible interface so that anyone can jump right into making Electron apps.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Alternative tooling</summary>
|
||||
|
||||
If you do not want to use Electron Forge for your project, there are other
|
||||
third-party tools you can use to distribute your app.
|
||||
|
||||
These tools are maintained by members of the Electron community,
|
||||
and do not come with official support from the Electron project.
|
||||
|
||||
**Electron Builder**
|
||||
|
||||
A "complete solution to package and build a ready-for-distribution Electron app"
|
||||
that focuses on an integrated experience. [`electron-builder`](https://github.com/electron-userland/electron-builder) adds a single dependency and manages all further requirements internally.
|
||||
|
||||
`electron-builder` replaces features and modules used by the Electron
|
||||
maintainers (such as the auto-updater) with custom ones.
|
||||
|
||||
**Hydraulic Conveyor**
|
||||
|
||||
A [desktop app deployment tool](https://hydraulic.dev) that supports
|
||||
cross-building/signing of all packages from any OS without the need for
|
||||
multi-platform CI, can do synchronous web-style updates on each start
|
||||
of the app, requires no code changes, can use plain HTTP servers for updates and
|
||||
which focuses on ease of use. Conveyor replaces the Electron auto-updaters
|
||||
with Sparkle on macOS, MSIX on Windows, and Linux package repositories.
|
||||
|
||||
Conveyor is a commercial tool that is free for open source projects. There's
|
||||
an example of [how to package GitHub Desktop](https://hydraulic.dev/blog/8-packaging-electron-apps.html)
|
||||
which can be used for learning.
|
||||
|
||||
</details>
|
||||
|
||||
## Getting started
|
||||
|
||||
The [Electron Forge docs][] contain detailed information on taking your application
|
||||
from source code to your end users' machines.
|
||||
This includes:
|
||||
|
||||
* Packaging your application [(package)][]
|
||||
* Generating executables and installers for each OS [(make)][], and,
|
||||
* Publishing these files to online platforms to download [(publish)][].
|
||||
- Packaging your application [(package)][]
|
||||
- Generating executables and installers for each OS [(make)][], and,
|
||||
- Publishing these files to online platforms to download [(publish)][].
|
||||
|
||||
For beginners, we recommend following through Electron's [tutorial][] to develop, build,
|
||||
package and publish your first Electron app. If you have already developed an app on your machine
|
||||
@@ -20,11 +53,11 @@ and want to start on packaging and distribution, start from [step 5][] of the tu
|
||||
|
||||
## Getting help
|
||||
|
||||
* If you need help with developing your app, our [community Discord server][discord] is a great place
|
||||
to get advice from other Electron app developers.
|
||||
* If you suspect you're running into a bug with Forge, please check the [GitHub issue tracker][]
|
||||
to see if any existing issues match your problem. If not, feel free to fill out our bug report
|
||||
template and submit a new issue.
|
||||
- If you need help with developing your app, our [community Discord server][discord] is a great place
|
||||
to get advice from other Electron app developers.
|
||||
- If you suspect you're running into a bug with Forge, please check the [GitHub issue tracker][]
|
||||
to see if any existing issues match your problem. If not, feel free to fill out our bug report
|
||||
template and submit a new issue.
|
||||
|
||||
[Electron Forge Docs]: https://www.electronforge.io/
|
||||
[step 5]: ./tutorial-5-packaging.md
|
||||
|
||||
@@ -52,7 +52,7 @@ In the main process, set an IPC listener on the `set-title` channel with the `ip
|
||||
|
||||
```javascript {6-10,22} title='main.js (Main Process)'
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
// ...
|
||||
|
||||
@@ -183,7 +183,7 @@ provided to the renderer process. Please refer to
|
||||
|
||||
```javascript {6-13,25} title='main.js (Main Process)'
|
||||
const { app, BrowserWindow, dialog, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
// ...
|
||||
|
||||
@@ -378,7 +378,7 @@ target renderer.
|
||||
|
||||
```javascript {11-26} title='main.js (Main Process)'
|
||||
const { app, BrowserWindow, Menu, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
|
||||
@@ -27,7 +27,7 @@ control our application lifecycle and create a native browser window.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
```
|
||||
|
||||
Next, we will proceed to register our application to handle all "`electron-fiddle://`" protocols.
|
||||
|
||||
@@ -303,7 +303,7 @@ without having to step through the isolated world.
|
||||
|
||||
```js title='main.js (Main Process)'
|
||||
const { BrowserWindow, app, MessageChannelMain } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
// Create a BrowserWindow with contextIsolation enabled.
|
||||
|
||||
@@ -22,7 +22,7 @@ In `preload.js` use the [`contextBridge`][] to inject a method `window.electron.
|
||||
|
||||
```js
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
startDrag: (fileName) => {
|
||||
|
||||
@@ -41,7 +41,7 @@ To enable this mode, GPU acceleration has to be disabled by calling the
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/offscreen-rendering'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
|
||||
app.disableHardwareAcceleration()
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ equally fictitious `foo-parser` module. In traditional Node.js development,
|
||||
you might write code that eagerly loads dependencies:
|
||||
|
||||
```js title='parser.js' @ts-expect-error=[2]
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
const fooParser = require('foo-parser')
|
||||
|
||||
class Parser {
|
||||
@@ -197,7 +197,7 @@ do this work a little later, when `getParsedFiles()` is actually called?
|
||||
|
||||
```js title='parser.js' @ts-expect-error=[20]
|
||||
// "fs" is likely already being loaded, so the `require()` call is cheap
|
||||
const fs = require('fs')
|
||||
const fs = require('node:fs')
|
||||
|
||||
class Parser {
|
||||
async getFiles () {
|
||||
|
||||
@@ -228,6 +228,23 @@ channel with a renderer process using [`MessagePort`][]s. An Electron app can
|
||||
always prefer the [UtilityProcess][] API over Node.js [`child_process.fork`][] API when
|
||||
there is need to fork a child process from the main process.
|
||||
|
||||
## Process-specific module aliases (TypeScript)
|
||||
|
||||
Electron's npm package also exports subpaths that contain a subset of
|
||||
Electron's TypeScript type definitions.
|
||||
|
||||
- `electron/main` includes types for all main process modules.
|
||||
- `electron/renderer` includes types for all renderer process modules.
|
||||
- `electron/common` includes types for modules that can run in main and renderer processes.
|
||||
|
||||
These aliases have no impact on runtime, but can be used for typechecking
|
||||
and autocomplete.
|
||||
|
||||
```js title="Usage example"
|
||||
const { app } = require('electron/main')
|
||||
const { shell } = require('electron/common')
|
||||
```
|
||||
|
||||
[window-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window
|
||||
[`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
||||
[`child_process.fork`]: https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processforkmodulepath-args-options
|
||||
|
||||
@@ -292,7 +292,7 @@ to the `webPreferences.preload` option in your existing `BrowserWindow` construc
|
||||
```js
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
// include the Node.js 'path' module at the top of your file
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
// modify your existing createWindow() function
|
||||
const createWindow = () => {
|
||||
@@ -358,7 +358,7 @@ The full code is available below:
|
||||
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
|
||||
@@ -26,8 +26,8 @@ the application via JumpList or dock menu, respectively.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/recent-documents'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -29,7 +29,7 @@ To set the represented file of window, you can use the
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/represented-file'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const os = require('os')
|
||||
const os = require('node:os')
|
||||
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -222,14 +222,26 @@ with CommonJS module syntax:
|
||||
- [app][app], which controls your application's event lifecycle.
|
||||
- [BrowserWindow][browser-window], which creates and manages app windows.
|
||||
|
||||
:::info Capitalization conventions
|
||||
<details><summary>Module capitalization conventions</summary>
|
||||
|
||||
You might have noticed the capitalization difference between the **a**pp
|
||||
and **B**rowser**W**indow modules. Electron follows typical JavaScript conventions here,
|
||||
where PascalCase modules are instantiable class constructors (e.g. BrowserWindow, Tray,
|
||||
Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRenderer, webContents).
|
||||
|
||||
:::
|
||||
</details>
|
||||
|
||||
<details><summary>Typed import aliases</summary>
|
||||
|
||||
For better type checking when writing TypeScript code, you can choose to import
|
||||
main process modules from <code>electron/main</code>.
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
```
|
||||
|
||||
For more information, see the [Process Model docs](../tutorial/process-model.md#process-specific-module-aliases-typescript).
|
||||
</details>
|
||||
|
||||
:::warning ES Modules in Electron
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ To attach this script to your renderer process, pass its path to the
|
||||
|
||||
```js {2,8-10} title="main.js"
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
@@ -204,7 +204,7 @@ you send out the `invoke` call from the renderer.
|
||||
|
||||
```js {1,15} title="main.js"
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -184,7 +184,7 @@ allowing events such as `mouseleave` to be emitted:
|
||||
|
||||
```javascript title='main.js'
|
||||
const { BrowserWindow, ipcMain } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
|
||||
@@ -126,7 +126,7 @@ following lines:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow, nativeImage } = require('electron')
|
||||
const path = require('path')
|
||||
const path = require('node:path')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ template("electron_extra_paks") {
|
||||
"$root_gen_dir/content/browser/tracing/tracing_resources.pak",
|
||||
"$root_gen_dir/content/browser/webrtc/resources/webrtc_internals_resources.pak",
|
||||
"$root_gen_dir/content/content_resources.pak",
|
||||
"$root_gen_dir/content/gpu_resources.pak",
|
||||
"$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak",
|
||||
"$root_gen_dir/net/net_resources.pak",
|
||||
"$root_gen_dir/third_party/blink/public/resources/blink_resources.pak",
|
||||
@@ -74,6 +75,7 @@ template("electron_extra_paks") {
|
||||
"//chrome/common:resources",
|
||||
"//components/resources",
|
||||
"//content:content_resources",
|
||||
"//content/browser/resources/gpu:resources",
|
||||
"//content/browser/resources/media:resources",
|
||||
"//content/browser/tracing:resources",
|
||||
"//content/browser/webrtc/resources",
|
||||
@@ -174,6 +176,7 @@ template("electron_paks") {
|
||||
}
|
||||
|
||||
source_patterns = [
|
||||
"${root_gen_dir}/chrome/chromium_strings_",
|
||||
"${root_gen_dir}/chrome/locale_settings_",
|
||||
"${root_gen_dir}/chrome/platform_locale_settings_",
|
||||
"${root_gen_dir}/chrome/generated_resources_",
|
||||
@@ -189,6 +192,7 @@ template("electron_paks") {
|
||||
"${root_gen_dir}/ui/strings/ui_strings_",
|
||||
]
|
||||
deps = [
|
||||
"//chrome/app:chromium_strings",
|
||||
"//chrome/app:generated_resources",
|
||||
"//chrome/app/resources:locale_settings",
|
||||
"//chrome/app/resources:platform_locale_settings",
|
||||
|
||||
@@ -115,6 +115,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",
|
||||
|
||||
@@ -193,6 +193,8 @@ filenames = {
|
||||
"shell/common/language_util_mac.mm",
|
||||
"shell/common/mac/main_application_bundle.h",
|
||||
"shell/common/mac/main_application_bundle.mm",
|
||||
"shell/common/mac/codesign_util.cc",
|
||||
"shell/common/mac/codesign_util.h",
|
||||
"shell/common/node_bindings_mac.cc",
|
||||
"shell/common/node_bindings_mac.h",
|
||||
"shell/common/platform_util_mac.mm",
|
||||
@@ -508,6 +510,7 @@ filenames = {
|
||||
"shell/browser/web_contents_preferences.h",
|
||||
"shell/browser/web_contents_zoom_controller.cc",
|
||||
"shell/browser/web_contents_zoom_controller.h",
|
||||
"shell/browser/web_contents_zoom_observer.h",
|
||||
"shell/browser/web_view_guest_delegate.cc",
|
||||
"shell/browser/web_view_guest_delegate.h",
|
||||
"shell/browser/web_view_manager.cc",
|
||||
@@ -689,12 +692,16 @@ filenames = {
|
||||
]
|
||||
|
||||
lib_sources_extensions = [
|
||||
"shell/browser/extensions/api/extension_action/extension_action_api.cc",
|
||||
"shell/browser/extensions/api/extension_action/extension_action_api.h",
|
||||
"shell/browser/extensions/api/management/electron_management_api_delegate.cc",
|
||||
"shell/browser/extensions/api/management/electron_management_api_delegate.h",
|
||||
"shell/browser/extensions/api/resources_private/resources_private_api.cc",
|
||||
"shell/browser/extensions/api/resources_private/resources_private_api.h",
|
||||
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc",
|
||||
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.h",
|
||||
"shell/browser/extensions/api/scripting/scripting_api.cc",
|
||||
"shell/browser/extensions/api/scripting/scripting_api.h",
|
||||
"shell/browser/extensions/api/streams_private/streams_private_api.cc",
|
||||
"shell/browser/extensions/api/streams_private/streams_private_api.h",
|
||||
"shell/browser/extensions/api/tabs/tabs_api.cc",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import { constants } from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
import type * as Crypto from 'crypto';
|
||||
@@ -27,7 +28,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 +40,8 @@ const getOrCreateArchive = (archivePath: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
process._getOrCreateArchive = getOrCreateArchive;
|
||||
|
||||
const asarRe = /\.asar/i;
|
||||
|
||||
// Separate asar package's path from full path.
|
||||
@@ -65,18 +68,22 @@ const gid = process.getgid?.() ?? 0;
|
||||
|
||||
const fakeTime = new Date();
|
||||
|
||||
enum AsarFileType {
|
||||
kFile = (constants as any).UV_DIRENT_FILE,
|
||||
kDirectory = (constants as any).UV_DIRENT_DIR,
|
||||
kLink = (constants as any).UV_DIRENT_LINK,
|
||||
}
|
||||
|
||||
const fileTypeToMode = new Map<AsarFileType, number>([
|
||||
[AsarFileType.kFile, constants.S_IFREG],
|
||||
[AsarFileType.kDirectory, constants.S_IFDIR],
|
||||
[AsarFileType.kLink, constants.S_IFLNK]
|
||||
]);
|
||||
|
||||
const asarStatsToFsStats = function (stats: NodeJS.AsarFileStat) {
|
||||
const { Stats, constants } = require('fs');
|
||||
const { Stats } = require('fs');
|
||||
|
||||
let mode = constants.S_IROTH ^ constants.S_IRGRP ^ constants.S_IRUSR ^ constants.S_IWUSR;
|
||||
|
||||
if (stats.isFile) {
|
||||
mode ^= constants.S_IFREG;
|
||||
} else if (stats.isDirectory) {
|
||||
mode ^= constants.S_IFDIR;
|
||||
} else if (stats.isLink) {
|
||||
mode ^= constants.S_IFLNK;
|
||||
}
|
||||
const mode = constants.S_IROTH | constants.S_IRGRP | constants.S_IRUSR | constants.S_IWUSR | fileTypeToMode.get(stats.type)!;
|
||||
|
||||
return new Stats(
|
||||
1, // dev
|
||||
@@ -239,7 +246,6 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
const logASARAccess = (asarPath: string, filePath: string, offset: number) => {
|
||||
if (!process.env.ELECTRON_LOG_ASAR_READS) return;
|
||||
if (!logFDs.has(asarPath)) {
|
||||
const path = require('path');
|
||||
const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`;
|
||||
const logPath = path.join(require('os').tmpdir(), logFilename);
|
||||
logFDs.set(asarPath, fs.openSync(logPath, 'a'));
|
||||
@@ -655,13 +661,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
nextTick(callback!, [error]);
|
||||
return;
|
||||
}
|
||||
if (stats.isFile) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
|
||||
} else if (stats.isDirectory) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_DIR));
|
||||
} else if (stats.isLink) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_LINK));
|
||||
}
|
||||
dirents.push(new fs.Dirent(file, stats.type));
|
||||
}
|
||||
nextTick(callback!, [null, dirents]);
|
||||
return;
|
||||
@@ -698,13 +698,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
if (!stats) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath });
|
||||
}
|
||||
if (stats.isFile) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
|
||||
} else if (stats.isDirectory) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_DIR));
|
||||
} else if (stats.isLink) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_LINK));
|
||||
}
|
||||
dirents.push(new fs.Dirent(file, stats.type));
|
||||
}
|
||||
return dirents;
|
||||
}
|
||||
@@ -755,7 +749,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
const stats = archive.stat(filePath);
|
||||
if (!stats) return -34;
|
||||
|
||||
return (stats.isDirectory) ? 1 : 0;
|
||||
return (stats.type === AsarFileType.kDirectory) ? 1 : 0;
|
||||
};
|
||||
|
||||
// Calling mkdir for directory inside asar archive should throw ENOTDIR
|
||||
|
||||
@@ -114,5 +114,11 @@ for (const name of events) {
|
||||
}
|
||||
|
||||
// Deprecation.
|
||||
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone');
|
||||
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone');
|
||||
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone', () => {
|
||||
// the old event is still emitted by App::OnGpuProcessCrashed()
|
||||
return undefined;
|
||||
});
|
||||
|
||||
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone', (event: Electron.Event, webContents: Electron.WebContents, details: Electron.RenderProcessGoneDetails) => {
|
||||
return [event, webContents, details.reason === 'killed'];
|
||||
});
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
import * as deprecate from '@electron/internal/common/deprecate';
|
||||
|
||||
const { systemPreferences } = process._linkedBinding('electron_browser_system_preferences');
|
||||
|
||||
if ('getAppLevelAppearance' in systemPreferences) {
|
||||
const nativeALAGetter = systemPreferences.getAppLevelAppearance;
|
||||
const nativeALASetter = systemPreferences.setAppLevelAppearance;
|
||||
const warnALA = deprecate.warnOnce('appLevelAppearance');
|
||||
const warnALAGetter = deprecate.warnOnce('getAppLevelAppearance function');
|
||||
const warnALASetter = deprecate.warnOnce('setAppLevelAppearance function');
|
||||
Object.defineProperty(systemPreferences, 'appLevelAppearance', {
|
||||
get: () => nativeALAGetter.call(systemPreferences),
|
||||
set: (appearance) => nativeALASetter.call(systemPreferences, appearance)
|
||||
get: () => {
|
||||
warnALA();
|
||||
return nativeALAGetter.call(systemPreferences);
|
||||
},
|
||||
set: (appearance) => {
|
||||
warnALA();
|
||||
nativeALASetter.call(systemPreferences, appearance);
|
||||
}
|
||||
});
|
||||
systemPreferences.getAppLevelAppearance = () => {
|
||||
warnALAGetter();
|
||||
return nativeALAGetter.call(systemPreferences);
|
||||
};
|
||||
systemPreferences.setAppLevelAppearance = (appearance) => {
|
||||
warnALASetter();
|
||||
nativeALASetter.call(systemPreferences, appearance);
|
||||
};
|
||||
}
|
||||
|
||||
if ('getEffectiveAppearance' in systemPreferences) {
|
||||
|
||||
@@ -338,49 +338,53 @@ 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 (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');
|
||||
}
|
||||
if (typeof options !== 'object') {
|
||||
throw new Error('webContents.print(): Invalid print settings specified.');
|
||||
}
|
||||
|
||||
// Dimensions in Microns - 1 meter = 10^6 microns
|
||||
const height = Math.ceil(pageSize.height);
|
||||
const width = Math.ceil(pageSize.width);
|
||||
if (!isValidCustomPageSize(width, height)) {
|
||||
throw new Error('height and width properties must be minimum 352 microns.');
|
||||
}
|
||||
const printSettings: Record<string, any> = { ...options };
|
||||
|
||||
options.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
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 {
|
||||
throw new Error(`Unsupported pageSize: ${pageSize}`);
|
||||
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');
|
||||
}
|
||||
|
||||
// Dimensions in Microns - 1 meter = 10^6 microns
|
||||
const height = Math.ceil(pageSize.height);
|
||||
const width = Math.ceil(pageSize.width);
|
||||
if (!isValidCustomPageSize(width, height)) {
|
||||
throw new Error('height and width properties must be minimum 352 microns.');
|
||||
}
|
||||
|
||||
printSettings.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
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];
|
||||
printSettings.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 {
|
||||
throw new Error(`Unsupported pageSize: ${pageSize}`);
|
||||
}
|
||||
|
||||
if (this._print) {
|
||||
if (callback) {
|
||||
this._print(options, callback);
|
||||
this._print(printSettings, callback);
|
||||
} else {
|
||||
this._print(options);
|
||||
this._print(printSettings);
|
||||
}
|
||||
} else {
|
||||
console.error('Error: Printing feature is disabled.');
|
||||
@@ -447,6 +451,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) {
|
||||
@@ -461,6 +466,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;
|
||||
}
|
||||
};
|
||||
@@ -475,17 +481,22 @@ 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);
|
||||
@@ -658,8 +669,8 @@ WebContents.prototype._init = function () {
|
||||
ipcMain.emit(channel, event, message);
|
||||
});
|
||||
|
||||
this.on('crashed', (event, ...args) => {
|
||||
app.emit('renderer-process-crashed', event, this, ...args);
|
||||
deprecate.event(this, 'crashed', 'render-process-gone', (event: Electron.Event, details: Electron.RenderProcessGoneDetails) => {
|
||||
return [event, details.reason === 'killed'];
|
||||
});
|
||||
|
||||
this.on('render-process-gone', (event, details) => {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -66,14 +66,17 @@ export function renameFunction<T extends Function> (fn: T, newName: string): T {
|
||||
}
|
||||
|
||||
// change the name of an event
|
||||
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string) {
|
||||
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string, transformer: (...args: any[]) => any[] | undefined = (...args) => args) {
|
||||
const warn = newName.startsWith('-') /* internal event */
|
||||
? warnOnce(`${oldName} event`)
|
||||
: warnOnce(`${oldName} event`, `${newName} event`);
|
||||
return emitter.on(newName, function (this: NodeJS.EventEmitter, ...args) {
|
||||
if (this.listenerCount(oldName) !== 0) {
|
||||
warn();
|
||||
this.emit(oldName, ...args);
|
||||
const transformedArgs = transformer(...args);
|
||||
if (transformedArgs) {
|
||||
this.emit(oldName, ...transformedArgs);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
4
patches/angle/.patches
Normal file
4
patches/angle/.patches
Normal file
@@ -0,0 +1,4 @@
|
||||
m120_translator_optimize_field-name-collision_check.patch
|
||||
m120_translator_fail_compilation_if_too_many_struct_fields.patch
|
||||
m120_translator_limit_private_variable_size_to_64kb.patch
|
||||
m120_vulkan_don_t_crash_when_glcopyteximage2d_redefines_itself.patch
|
||||
@@ -0,0 +1,215 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 30 Nov 2023 14:12:42 -0500
|
||||
Subject: M120: Translator: Fail compilation if too many struct fields
|
||||
|
||||
If there are too many struct fields, SPIR-V cannot be produced (as it
|
||||
has a hard limit of 16383 fields). The Nvidia GL driver has also been
|
||||
observed to fail when there are too many fields.
|
||||
|
||||
Bug: chromium:1505009
|
||||
Change-Id: I29fd61d180175e89e7db9ca8ba49ab07585b5f9a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143827
|
||||
Reviewed-by: Cody Northrop <cnorthrop@google.com>
|
||||
|
||||
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
|
||||
index 7c90ea4f1d23a8af0cab1d44124eea021a27a16d..e174725beb764407185e471a9916ffd164493cd8 100644
|
||||
--- a/src/compiler/translator/ParseContext.cpp
|
||||
+++ b/src/compiler/translator/ParseContext.cpp
|
||||
@@ -4726,6 +4726,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
|
||||
const TVector<unsigned int> *arraySizes,
|
||||
const TSourceLoc &arraySizesLine)
|
||||
{
|
||||
+ checkDoesNotHaveTooManyFields(blockName, fieldList, nameLine);
|
||||
+
|
||||
// Ensure there are no duplicate field names
|
||||
checkDoesNotHaveDuplicateFieldNames(fieldList, nameLine);
|
||||
|
||||
@@ -6289,6 +6291,21 @@ void TParseContext::checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields
|
||||
}
|
||||
}
|
||||
|
||||
+void TParseContext::checkDoesNotHaveTooManyFields(const ImmutableString &name,
|
||||
+ const TFieldList *fields,
|
||||
+ const TSourceLoc &location)
|
||||
+{
|
||||
+ // Check that there are not too many fields. SPIR-V has a limit of 16383 fields, and it would
|
||||
+ // be reasonable to apply that limit to all outputs. For example, it was observed that 32768
|
||||
+ // fields cause the Nvidia GL driver to fail compilation, so such a limit is not too specific to
|
||||
+ // SPIR-V.
|
||||
+ constexpr size_t kMaxFieldCount = 16383;
|
||||
+ if (fields->size() > kMaxFieldCount)
|
||||
+ {
|
||||
+ error(location, "Too many fields in the struct (limit is 16383)", name);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location)
|
||||
{
|
||||
return fields;
|
||||
@@ -6392,6 +6409,8 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
|
||||
}
|
||||
}
|
||||
|
||||
+ checkDoesNotHaveTooManyFields(structName, fieldList, structLine);
|
||||
+
|
||||
// Ensure there are no duplicate field names
|
||||
checkDoesNotHaveDuplicateFieldNames(fieldList, structLine);
|
||||
|
||||
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
|
||||
index b63dbbadd146d1a004513823de72c89240a31929..c83b73271b557ed122668d7e655deae5aa23bc48 100644
|
||||
--- a/src/compiler/translator/ParseContext.h
|
||||
+++ b/src/compiler/translator/ParseContext.h
|
||||
@@ -355,6 +355,9 @@ class TParseContext : angle::NonCopyable
|
||||
const TVector<unsigned int> *arraySizes);
|
||||
|
||||
void checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields, const TSourceLoc &location);
|
||||
+ void checkDoesNotHaveTooManyFields(const ImmutableString &name,
|
||||
+ const TFieldList *fields,
|
||||
+ const TSourceLoc &location);
|
||||
TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
|
||||
TFieldList *combineStructFieldLists(TFieldList *processedFields,
|
||||
const TFieldList *newlyAddedFields,
|
||||
diff --git a/src/tests/compiler_tests/ExpressionLimit_test.cpp b/src/tests/compiler_tests/ExpressionLimit_test.cpp
|
||||
index d399e1792d97edb76d5e0247e4166e094cecb7e5..e17eace1b4b9a4185d6833fb7895f5fd49ae7679 100644
|
||||
--- a/src/tests/compiler_tests/ExpressionLimit_test.cpp
|
||||
+++ b/src/tests/compiler_tests/ExpressionLimit_test.cpp
|
||||
@@ -16,12 +16,6 @@ class ExpressionLimitTest : public testing::Test
|
||||
static const int kMaxExpressionComplexity = 16;
|
||||
static const int kMaxCallStackDepth = 16;
|
||||
static const int kMaxFunctionParameters = 16;
|
||||
- static const char *kExpressionTooComplex;
|
||||
- static const char *kCallStackTooDeep;
|
||||
- static const char *kHasRecursion;
|
||||
- static const char *kTooManyParameters;
|
||||
- static const char *kTooComplexSwitch;
|
||||
- static const char *kGlobalVariableInit;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
@@ -125,9 +119,7 @@ class ExpressionLimitTest : public testing::Test
|
||||
|
||||
GenerateDeepFunctionStack(length, &ss);
|
||||
|
||||
- ss << "void main() {\n"
|
||||
- << " gl_FragColor = function" << length << "();\n"
|
||||
- << "}";
|
||||
+ ss << "void main() {\n" << " gl_FragColor = function" << length << "();\n" << "}";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
@@ -138,9 +130,7 @@ class ExpressionLimitTest : public testing::Test
|
||||
|
||||
GenerateDeepFunctionStack(length, &ss);
|
||||
|
||||
- ss << "void main() {\n"
|
||||
- << " gl_FragColor = vec4(0,0,0,0);\n"
|
||||
- << "}";
|
||||
+ ss << "void main() {\n" << " gl_FragColor = vec4(0,0,0,0);\n" << "}";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
@@ -149,9 +139,7 @@ class ExpressionLimitTest : public testing::Test
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
- ss << "precision mediump float;\n"
|
||||
- << "\n"
|
||||
- << "float foo(";
|
||||
+ ss << "precision mediump float;\n" << "\n" << "float foo(";
|
||||
for (int i = 0; i < parameters; ++i)
|
||||
{
|
||||
ss << "float f" << i;
|
||||
@@ -244,15 +232,13 @@ class ExpressionLimitTest : public testing::Test
|
||||
ShBuiltInResources resources;
|
||||
};
|
||||
|
||||
-const char *ExpressionLimitTest::kExpressionTooComplex = "Expression too complex";
|
||||
-const char *ExpressionLimitTest::kCallStackTooDeep = "Call stack too deep";
|
||||
-const char *ExpressionLimitTest::kHasRecursion =
|
||||
- "Recursive function call in the following call chain";
|
||||
-const char *ExpressionLimitTest::kTooManyParameters = "Function has too many parameters";
|
||||
-const char *ExpressionLimitTest::kTooComplexSwitch =
|
||||
- "too complex expressions inside a switch statement";
|
||||
-const char *ExpressionLimitTest::kGlobalVariableInit =
|
||||
- "global variable initializers must be constant expressions";
|
||||
+constexpr char kExpressionTooComplex[] = "Expression too complex";
|
||||
+constexpr char kCallStackTooDeep[] = "Call stack too deep";
|
||||
+constexpr char kHasRecursion[] = "Recursive function call in the following call chain";
|
||||
+constexpr char kTooManyParameters[] = "Function has too many parameters";
|
||||
+constexpr char kTooComplexSwitch[] = "too complex expressions inside a switch statement";
|
||||
+constexpr char kGlobalVariableInit[] = "global variable initializers must be constant expressions";
|
||||
+constexpr char kTooManyFields[] = "Too many fields in the struct";
|
||||
|
||||
TEST_F(ExpressionLimitTest, ExpressionComplexity)
|
||||
{
|
||||
@@ -632,3 +618,31 @@ TEST_F(ExpressionLimitTest, NestingInsideGlobalInitializer)
|
||||
compileOptions, nullptr));
|
||||
sh::Destruct(compiler);
|
||||
}
|
||||
+
|
||||
+TEST_F(ExpressionLimitTest, TooManyStructFields)
|
||||
+{
|
||||
+ ShShaderSpec spec = SH_WEBGL2_SPEC;
|
||||
+ ShShaderOutput output = SH_ESSL_OUTPUT;
|
||||
+ ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
|
||||
+ ShCompileOptions compileOptions = {};
|
||||
+
|
||||
+ std::ostringstream fs;
|
||||
+ fs << R"(#version 300 es
|
||||
+precision highp float;
|
||||
+struct TooManyFields
|
||||
+{
|
||||
+)";
|
||||
+ for (uint32_t i = 0; i < (1 << 16); ++i)
|
||||
+ {
|
||||
+ fs << " float field" << i << ";\n";
|
||||
+ }
|
||||
+ fs << R"(};
|
||||
+uniform B { TooManyFields s; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(s.field0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ EXPECT_TRUE(CheckShaderCompilation(compiler, fs.str().c_str(), compileOptions, kTooManyFields));
|
||||
+ sh::Destruct(compiler);
|
||||
+}
|
||||
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
|
||||
index 9b42b6d9221366e9bc7b6263bf8e14b77ca7694d..46f8645e5a56e527223ea4657d14dbc8619cb631 100644
|
||||
--- a/src/tests/gl_tests/GLSLTest.cpp
|
||||
+++ b/src/tests/gl_tests/GLSLTest.cpp
|
||||
@@ -18064,6 +18064,33 @@ void main() {
|
||||
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), fs.str().c_str());
|
||||
}
|
||||
|
||||
+// Test that structs with too many fields are rejected. In SPIR-V, the instruction that defines the
|
||||
+// struct lists the fields which means the length of the instruction is a function of the field
|
||||
+// count. Since SPIR-V instruction sizes are limited to 16 bits, structs with more fields cannot be
|
||||
+// represented.
|
||||
+TEST_P(GLSLTest_ES3, TooManyFieldsInStruct)
|
||||
+{
|
||||
+ std::ostringstream fs;
|
||||
+ fs << R"(#version 300 es
|
||||
+precision highp float;
|
||||
+struct TooManyFields
|
||||
+{
|
||||
+)";
|
||||
+ for (uint32_t i = 0; i < (1 << 16); ++i)
|
||||
+ {
|
||||
+ fs << " float field" << i << ";\n";
|
||||
+ }
|
||||
+ fs << R"(};
|
||||
+uniform B { TooManyFields s; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(s.field0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str());
|
||||
+ EXPECT_EQ(0u, shader);
|
||||
+}
|
||||
+
|
||||
} // anonymous namespace
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);
|
||||
@@ -0,0 +1,416 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 30 Nov 2023 15:42:32 -0500
|
||||
Subject: M120: Translator: Limit private variable size to 64KB
|
||||
|
||||
This is indirectly fixing an issue where passing large arrays in SPIR-V
|
||||
such that an internal cast is needed (such as array inside interface
|
||||
block copied to local varaible) causes an overflow of the instruction
|
||||
length limit (in the absence of OpCopyLogical).
|
||||
|
||||
By limiting the size of private variables to 32KB, this limitation is
|
||||
indirectly enforced. It was observed that all the test shaders added in
|
||||
this CL fail on the Nvidia OpenGL drivers, so such a limit seems to be
|
||||
reasonble.
|
||||
|
||||
Bug: chromium:1505009
|
||||
Change-Id: I75a1e40a538120ffc69ae7edafbdba5830c6b0bb
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143828
|
||||
Reviewed-by: Cody Northrop <cnorthrop@google.com>
|
||||
|
||||
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
|
||||
index 383feeb477d2445d5e599b39e125fe455169da08..8736b3dcfbcb43f9087b78224658a9680d7ee68c 100644
|
||||
--- a/src/compiler/translator/Compiler.cpp
|
||||
+++ b/src/compiler/translator/Compiler.cpp
|
||||
@@ -770,11 +770,6 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (shouldLimitTypeSizes() && !ValidateTypeSizeLimitations(root, &mSymbolTable, &mDiagnostics))
|
||||
- {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
if (!ValidateFragColorAndFragData(mShaderType, mShaderVersion, mSymbolTable, &mDiagnostics))
|
||||
{
|
||||
return false;
|
||||
@@ -1046,6 +1041,13 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
|
||||
return false;
|
||||
}
|
||||
|
||||
+ // Run after RemoveUnreferencedVariables, validate that the shader does not have excessively
|
||||
+ // large variables.
|
||||
+ if (shouldLimitTypeSizes() && !ValidateTypeSizeLimitations(root, &mSymbolTable, &mDiagnostics))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
// Built-in function emulation needs to happen after validateLimitations pass.
|
||||
GetGlobalPoolAllocator()->lock();
|
||||
initBuiltInFunctionEmulator(&mBuiltInFunctionEmulator, compileOptions);
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index f0ff9cb11ac39e62672285300c8f41641f12c617..8f02c65b5ec5fd20b8bcee2bc595cfb278f758b4 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -24,10 +24,11 @@ namespace
|
||||
// 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 (16MB) as that much memory won't fit in
|
||||
+// For local and global variables, the limit is much lower (64KB) 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>(16) * 1024 * 1024;
|
||||
+constexpr size_t kMaxVariableSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
|
||||
+constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(64) * 1024;
|
||||
+constexpr size_t kMaxTotalPrivateVariableSizeInBytes = 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.
|
||||
@@ -70,43 +71,115 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
|
||||
continue;
|
||||
}
|
||||
|
||||
- const TType &variableType = asSymbol->getType();
|
||||
-
|
||||
- // Create a ShaderVariable from which to compute
|
||||
- // (conservative) sizing information.
|
||||
- ShaderVariable shaderVar;
|
||||
- setCommonVariableProperties(variableType, variable, &shaderVar);
|
||||
-
|
||||
- // Compute the std140 layout of this variable, assuming
|
||||
- // it's a member of a block (which it might not be).
|
||||
- Std140BlockEncoder layoutEncoder;
|
||||
- BlockEncoderVisitor visitor("", "", &layoutEncoder);
|
||||
- // Since the size limit's arbitrary, it doesn't matter
|
||||
- // whether the row-major layout is correctly determined.
|
||||
- bool isRowMajorLayout = false;
|
||||
- TraverseShaderVariable(shaderVar, isRowMajorLayout, &visitor);
|
||||
- if (layoutEncoder.getCurrentOffset() > kMaxVariableSizeInBytes)
|
||||
+ if (!validateVariableSize(variable, asSymbol->getLine()))
|
||||
{
|
||||
- error(asSymbol->getLine(),
|
||||
- "Size of declared variable exceeds implementation-defined limit",
|
||||
- asSymbol->getName());
|
||||
return false;
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override
|
||||
+ {
|
||||
+ const TFunction *function = node->getFunction();
|
||||
+ const size_t paramCount = function->getParamCount();
|
||||
+
|
||||
+ for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex)
|
||||
+ {
|
||||
+ validateVariableSize(*function->getParam(paramIndex), node->getLine());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ bool validateVariableSize(const TVariable &variable, const TSourceLoc &location)
|
||||
+ {
|
||||
+ const TType &variableType = variable.getType();
|
||||
+
|
||||
+ // Create a ShaderVariable from which to compute
|
||||
+ // (conservative) sizing information.
|
||||
+ ShaderVariable shaderVar;
|
||||
+ setCommonVariableProperties(variableType, variable, &shaderVar);
|
||||
+
|
||||
+ // Compute the std140 layout of this variable, assuming
|
||||
+ // it's a member of a block (which it might not be).
|
||||
+ Std140BlockEncoder layoutEncoder;
|
||||
+ BlockEncoderVisitor visitor("", "", &layoutEncoder);
|
||||
+ // Since the size limit's arbitrary, it doesn't matter
|
||||
+ // whether the row-major layout is correctly determined.
|
||||
+ bool isRowMajorLayout = false;
|
||||
+ TraverseShaderVariable(shaderVar, isRowMajorLayout, &visitor);
|
||||
+ if (layoutEncoder.getCurrentOffset() > kMaxVariableSizeInBytes)
|
||||
+ {
|
||||
+ error(location, "Size of declared variable exceeds implementation-defined limit",
|
||||
+ variable.name());
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ // Skip over struct declarations. As long as they are not used (or if they are used later
|
||||
+ // in a less-restricted context (such as a UBO or SSBO)), they can be larger than
|
||||
+ // kMaxPrivateVariableSizeInBytes.
|
||||
+ if (variable.symbolType() == SymbolType::Empty && variableType.isStructSpecifier())
|
||||
+ {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ switch (variableType.getQualifier())
|
||||
+ {
|
||||
+ // List of all types that need to be limited (for example because they cause overflows
|
||||
+ // in drivers, or create trouble for the SPIR-V gen as the number of an instruction's
|
||||
+ // arguments cannot be more than 64KB (see OutputSPIRVTraverser::cast)).
|
||||
+
|
||||
+ // Local/global variables
|
||||
+ case EvqTemporary:
|
||||
+ case EvqGlobal:
|
||||
+ case EvqConst:
|
||||
+
|
||||
+ // Function arguments
|
||||
+ case EvqParamIn:
|
||||
+ case EvqParamOut:
|
||||
+ case EvqParamInOut:
|
||||
+ case EvqParamConst:
|
||||
+
|
||||
+ // Varyings
|
||||
+ case EvqVaryingIn:
|
||||
+ case EvqVaryingOut:
|
||||
+ case EvqSmoothOut:
|
||||
+ case EvqFlatOut:
|
||||
+ case EvqNoPerspectiveOut:
|
||||
+ case EvqCentroidOut:
|
||||
+ case EvqSampleOut:
|
||||
+ case EvqNoPerspectiveCentroidOut:
|
||||
+ case EvqNoPerspectiveSampleOut:
|
||||
+ case EvqSmoothIn:
|
||||
+ case EvqFlatIn:
|
||||
+ case EvqNoPerspectiveIn:
|
||||
+ case EvqCentroidIn:
|
||||
+ case EvqNoPerspectiveCentroidIn:
|
||||
+ case EvqNoPerspectiveSampleIn:
|
||||
+ case EvqVertexOut:
|
||||
+ case EvqFragmentIn:
|
||||
+ case EvqGeometryIn:
|
||||
+ case EvqGeometryOut:
|
||||
+ case EvqPerVertexIn:
|
||||
+ case EvqPerVertexOut:
|
||||
+ case EvqPatchIn:
|
||||
+ case EvqPatchOut:
|
||||
+ case EvqTessControlIn:
|
||||
+ case EvqTessControlOut:
|
||||
+ case EvqTessEvaluationIn:
|
||||
+ case EvqTessEvaluationOut:
|
||||
|
||||
- const bool isPrivate = variableType.getQualifier() == EvqTemporary ||
|
||||
- variableType.getQualifier() == EvqGlobal ||
|
||||
- variableType.getQualifier() == EvqConst;
|
||||
- if (isPrivate)
|
||||
- {
|
||||
if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes)
|
||||
{
|
||||
- error(asSymbol->getLine(),
|
||||
+ error(location,
|
||||
"Size of declared private variable exceeds implementation-defined limit",
|
||||
- asSymbol->getName());
|
||||
+ variable.name());
|
||||
return false;
|
||||
}
|
||||
mTotalPrivateVariablesSize += layoutEncoder.getCurrentOffset();
|
||||
- }
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -115,7 +188,7 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
|
||||
void validateTotalPrivateVariableSize()
|
||||
{
|
||||
if (mTotalPrivateVariablesSize.ValueOrDefault(std::numeric_limits<size_t>::max()) >
|
||||
- kMaxPrivateVariableSizeInBytes)
|
||||
+ kMaxTotalPrivateVariableSizeInBytes)
|
||||
{
|
||||
mDiagnostics->error(
|
||||
TSourceLoc{},
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index 3d356609031820b92c230ac7ff836327b78ec834..cfa70eef00a1e8d67f9fbf07ee74928b55da8b92 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -111,6 +111,8 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
|
||||
7872 WIN INTEL OPENGL : VertexAttributeTest.AliasingMatrixAttribLocations/ES2_OpenGL = SKIP
|
||||
7872 WIN INTEL OPENGL : VertexAttributeTest.ShortUnnormalized/ES2_OpenGL = SKIP
|
||||
7872 WIN INTEL OPENGL : ViewportTest.DoubleWindowCentered/ES2_OpenGL = SKIP
|
||||
+8441 WIN INTEL OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
|
||||
+8441 WIN INTEL OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
|
||||
|
||||
// Linux
|
||||
6065 LINUX INTEL VULKAN : SimpleStateChangeTestES31.DrawThenUpdateUBOThenDrawThenDrawIndexed/* = SKIP
|
||||
@@ -147,6 +149,10 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
|
||||
6977 LINUX NVIDIA OpenGL : MipmapTestES31.GenerateLowerMipsWithDraw/* = SKIP
|
||||
7301 LINUX NVIDIA OpenGL : CopyTexImageTest.RGBAToRGB/ES2_OpenGL_EmulateCopyTexImage2DFromRenderbuffers/* = SKIP
|
||||
7371 LINUX NVIDIA OpenGL : FramebufferTest_ES3.SurfaceDimensionsChangeAndFragCoord/* = SKIP
|
||||
+8441 NVIDIA OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
|
||||
+8441 NVIDIA OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
|
||||
+8441 NVIDIA GLES : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
|
||||
+8441 NVIDIA GLES : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
|
||||
|
||||
// Nvidia Vulkan
|
||||
7236 NVIDIA VULKAN : GLSLTest_ES31.TessellationControlShaderMatrixCopyBug/* = SKIP
|
||||
@@ -1046,6 +1052,8 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
|
||||
7389 MAC OPENGL : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP
|
||||
|
||||
8437 MAC OPENGL : GLSLTest_ES3.LotsOfFieldsInStruct/* = SKIP
|
||||
+8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
|
||||
+8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
|
||||
|
||||
// GL, GLES run into issues with cleanup
|
||||
7495 WIN OpenGL : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
|
||||
diff --git a/src/tests/compiler_tests/RecordConstantPrecision_test.cpp b/src/tests/compiler_tests/RecordConstantPrecision_test.cpp
|
||||
index 07923f991423f4ec1ff8cbe81fb822c2b526d149..9446576ac797c0e5db8f9c63d79adff744ea488e 100644
|
||||
--- a/src/tests/compiler_tests/RecordConstantPrecision_test.cpp
|
||||
+++ b/src/tests/compiler_tests/RecordConstantPrecision_test.cpp
|
||||
@@ -141,11 +141,11 @@ TEST_F(RecordConstantPrecisionTest, HigherPrecisionConstantInIndex)
|
||||
uniform mediump float u;
|
||||
void main()
|
||||
{
|
||||
- const highp int a = 33000;
|
||||
- mediump float b[34000];
|
||||
+ const highp int a = 330;
|
||||
+ mediump float b[340];
|
||||
gl_FragColor = vec4(b[a]);
|
||||
})";
|
||||
compile(shaderString);
|
||||
ASSERT_FALSE(foundInCode("const highp int s"));
|
||||
- ASSERT_TRUE(foundInCode("b[33000]"));
|
||||
+ ASSERT_TRUE(foundInCode("b[330]"));
|
||||
}
|
||||
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
|
||||
index 46f8645e5a56e527223ea4657d14dbc8619cb631..344539809b19db18b125a81791117177178de687 100644
|
||||
--- a/src/tests/gl_tests/GLSLTest.cpp
|
||||
+++ b/src/tests/gl_tests/GLSLTest.cpp
|
||||
@@ -18091,6 +18091,138 @@ void main() {
|
||||
EXPECT_EQ(0u, shader);
|
||||
}
|
||||
|
||||
+// Test that passing large arrays to functions are compiled correctly. Regression test for the
|
||||
+// SPIR-V generator that made a copy of the array to pass to the function, by decomposing and
|
||||
+// reconstructing it (in the absence of OpCopyLogical), but the reconstruction instruction has a
|
||||
+// length higher than can fit in SPIR-V.
|
||||
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockArrayPassedToFunction)
|
||||
+{
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+uniform Large { float a[65536]; };
|
||||
+float f(float b[65536])
|
||||
+{
|
||||
+ b[0] = 1.0;
|
||||
+ return b[0] + b[1];
|
||||
+}
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(f(a), 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
|
||||
+ EXPECT_EQ(0u, shader);
|
||||
+}
|
||||
+
|
||||
+// Make sure the shader in LargeInterfaceBlockArrayPassedToFunction works if the large local is
|
||||
+// avoided.
|
||||
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockArray)
|
||||
+{
|
||||
+ int maxUniformBlockSize = 0;
|
||||
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
|
||||
+ ANGLE_SKIP_TEST_IF(maxUniformBlockSize < 16384 * 4);
|
||||
+
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+uniform Large { float a[16384]; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(a[0], 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
|
||||
+}
|
||||
+
|
||||
+// Similar to LargeInterfaceBlockArrayPassedToFunction, but the array is nested in a struct.
|
||||
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArrayPassedToFunction)
|
||||
+{
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+struct S { float a[65536]; };
|
||||
+uniform Large { S s; };
|
||||
+float f(float b[65536])
|
||||
+{
|
||||
+ b[0] = 1.0;
|
||||
+ return b[0] + b[1];
|
||||
+}
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(f(s.a), 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
|
||||
+ EXPECT_EQ(0u, shader);
|
||||
+}
|
||||
+
|
||||
+// Make sure the shader in LargeInterfaceBlockNestedArrayPassedToFunction works if the large local
|
||||
+// is avoided.
|
||||
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArray)
|
||||
+{
|
||||
+ int maxUniformBlockSize = 0;
|
||||
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
|
||||
+ ANGLE_SKIP_TEST_IF(maxUniformBlockSize < 16384 * 4);
|
||||
+
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+struct S { float a[16384]; };
|
||||
+uniform Large { S s; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(s.a[0], 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
|
||||
+}
|
||||
+
|
||||
+// Similar to LargeInterfaceBlockArrayPassedToFunction, but the large array is copied to a local
|
||||
+// variable instead.
|
||||
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockArrayCopiedToLocal)
|
||||
+{
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+uniform Large { float a[65536]; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ float b[65536] = a;
|
||||
+ color = vec4(b[0], 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
|
||||
+ EXPECT_EQ(0u, shader);
|
||||
+}
|
||||
+
|
||||
+// Similar to LargeInterfaceBlockArrayCopiedToLocal, but the array is nested in a struct
|
||||
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArrayCopiedToLocal)
|
||||
+{
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+struct S { float a[65536]; };
|
||||
+uniform Large { S s; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ S s2 = s;
|
||||
+ color = vec4(s2.a[0], 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
|
||||
+ EXPECT_EQ(0u, shader);
|
||||
+}
|
||||
+
|
||||
+// Test that too large varyings are rejected.
|
||||
+TEST_P(GLSLTest_ES3, LargeArrayVarying)
|
||||
+{
|
||||
+ constexpr char kFS[] = R"(#version 300 es
|
||||
+precision highp float;
|
||||
+in float a[65536];
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(a[0], 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
|
||||
+ EXPECT_EQ(0u, shader);
|
||||
+}
|
||||
+
|
||||
} // anonymous namespace
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);
|
||||
@@ -0,0 +1,180 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 30 Nov 2023 13:53:00 -0500
|
||||
Subject: M120: Translator: Optimize field-name-collision check
|
||||
|
||||
As each field of the struct was encountered, its name was linearly
|
||||
checked against previously added fields. That's O(n^2).
|
||||
|
||||
The name collision check is now moved to when the struct is completely
|
||||
defined, and is done with an unordered_map.
|
||||
|
||||
Bug: chromium:1505009
|
||||
Change-Id: I3fbc23493e5a03e61b631af615cffaf9995fd566
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143826
|
||||
Reviewed-by: Cody Northrop <cnorthrop@google.com>
|
||||
|
||||
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
|
||||
index 28ac378cab6cb3812a43b6064733d7354ee694bc..7c90ea4f1d23a8af0cab1d44124eea021a27a16d 100644
|
||||
--- a/src/compiler/translator/ParseContext.cpp
|
||||
+++ b/src/compiler/translator/ParseContext.cpp
|
||||
@@ -4726,6 +4726,9 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
|
||||
const TVector<unsigned int> *arraySizes,
|
||||
const TSourceLoc &arraySizesLine)
|
||||
{
|
||||
+ // Ensure there are no duplicate field names
|
||||
+ checkDoesNotHaveDuplicateFieldNames(fieldList, nameLine);
|
||||
+
|
||||
const bool isGLPerVertex = blockName == "gl_PerVertex";
|
||||
// gl_PerVertex is allowed to be redefined and therefore not reserved
|
||||
if (!isGLPerVertex)
|
||||
@@ -6269,28 +6272,25 @@ TDeclarator *TParseContext::parseStructArrayDeclarator(const ImmutableString &id
|
||||
return new TDeclarator(identifier, arraySizes, loc);
|
||||
}
|
||||
|
||||
-void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
|
||||
- const TFieldList::const_iterator end,
|
||||
- const ImmutableString &name,
|
||||
- const TSourceLoc &location)
|
||||
+void TParseContext::checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields,
|
||||
+ const TSourceLoc &location)
|
||||
{
|
||||
- for (auto fieldIter = begin; fieldIter != end; ++fieldIter)
|
||||
+ TUnorderedMap<ImmutableString, uint32_t, ImmutableString::FowlerNollVoHash<sizeof(size_t)>>
|
||||
+ fieldNames;
|
||||
+ for (TField *field : *fields)
|
||||
{
|
||||
- if ((*fieldIter)->name() == name)
|
||||
+ // Note: operator[] adds this name to the map if it doesn't already exist, and initializes
|
||||
+ // its value to 0.
|
||||
+ uint32_t count = ++fieldNames[field->name()];
|
||||
+ if (count != 1)
|
||||
{
|
||||
- error(location, "duplicate field name in structure", name);
|
||||
+ error(location, "Duplicate field name in structure", field->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location)
|
||||
{
|
||||
- for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end();
|
||||
- ++fieldIter)
|
||||
- {
|
||||
- checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(),
|
||||
- location);
|
||||
- }
|
||||
return fields;
|
||||
}
|
||||
|
||||
@@ -6298,12 +6298,8 @@ TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
|
||||
const TFieldList *newlyAddedFields,
|
||||
const TSourceLoc &location)
|
||||
{
|
||||
- for (TField *field : *newlyAddedFields)
|
||||
- {
|
||||
- checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(),
|
||||
- field->name(), location);
|
||||
- processedFields->push_back(field);
|
||||
- }
|
||||
+ processedFields->insert(processedFields->end(), newlyAddedFields->begin(),
|
||||
+ newlyAddedFields->end());
|
||||
return processedFields;
|
||||
}
|
||||
|
||||
@@ -6396,7 +6392,10 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
|
||||
}
|
||||
}
|
||||
|
||||
- // ensure we do not specify any storage qualifiers on the struct members
|
||||
+ // Ensure there are no duplicate field names
|
||||
+ checkDoesNotHaveDuplicateFieldNames(fieldList, structLine);
|
||||
+
|
||||
+ // Ensure we do not specify any storage qualifiers on the struct members
|
||||
for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
|
||||
{
|
||||
TField &field = *(*fieldList)[typeListIndex];
|
||||
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
|
||||
index 9e1354ef816705fb512b40b329794e0282129807..b63dbbadd146d1a004513823de72c89240a31929 100644
|
||||
--- a/src/compiler/translator/ParseContext.h
|
||||
+++ b/src/compiler/translator/ParseContext.h
|
||||
@@ -354,10 +354,7 @@ class TParseContext : angle::NonCopyable
|
||||
const TSourceLoc &loc,
|
||||
const TVector<unsigned int> *arraySizes);
|
||||
|
||||
- void checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
|
||||
- const TFieldList::const_iterator end,
|
||||
- const ImmutableString &name,
|
||||
- const TSourceLoc &location);
|
||||
+ void checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields, const TSourceLoc &location);
|
||||
TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
|
||||
TFieldList *combineStructFieldLists(TFieldList *processedFields,
|
||||
const TFieldList *newlyAddedFields,
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index cadf4afaed84c10040b87c8936c4a0ebbfd6d514..3d356609031820b92c230ac7ff836327b78ec834 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -1045,6 +1045,8 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
|
||||
7389 SWIFTSHADER : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP
|
||||
7389 MAC OPENGL : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP
|
||||
|
||||
+8437 MAC OPENGL : GLSLTest_ES3.LotsOfFieldsInStruct/* = SKIP
|
||||
+
|
||||
// GL, GLES run into issues with cleanup
|
||||
7495 WIN OpenGL : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
|
||||
7495 WIN GLES : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
|
||||
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
|
||||
index 0d0d3b5468019b897af2487d72112fab829f47da..9b42b6d9221366e9bc7b6263bf8e14b77ca7694d 100644
|
||||
--- a/src/tests/gl_tests/GLSLTest.cpp
|
||||
+++ b/src/tests/gl_tests/GLSLTest.cpp
|
||||
@@ -18020,6 +18020,50 @@ TEST_P(GLSLTest_ES31, ESSL31ExtensionMacros)
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
+// Test that Metal compiler doesn't inline non-const globals
|
||||
+TEST_P(WebGLGLSLTest, InvalidGlobalsNotInlined)
|
||||
+{
|
||||
+ constexpr char kFS[] = R"(#version 100
|
||||
+ precision highp float;
|
||||
+ float v1 = 0.5;
|
||||
+ float v2 = v1;
|
||||
+
|
||||
+ float f1() {
|
||||
+ return v2;
|
||||
+ }
|
||||
+
|
||||
+ void main() {
|
||||
+ gl_FragColor = vec4(v1 + f1(),0.0,0.0, 1.0);
|
||||
+ })";
|
||||
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+}
|
||||
+
|
||||
+// Test that a struct can have lots of fields. Regression test for an inefficient O(n^2) check for
|
||||
+// fields having unique names.
|
||||
+TEST_P(GLSLTest_ES3, LotsOfFieldsInStruct)
|
||||
+{
|
||||
+ std::ostringstream fs;
|
||||
+ fs << R"(#version 300 es
|
||||
+precision highp float;
|
||||
+struct LotsOfFields
|
||||
+{
|
||||
+)";
|
||||
+ // Note: 16383 is the SPIR-V limit for struct member count.
|
||||
+ for (uint32_t i = 0; i < 16383; ++i)
|
||||
+ {
|
||||
+ fs << " float field" << i << ";\n";
|
||||
+ }
|
||||
+ fs << R"(};
|
||||
+uniform B { LotsOfFields s; };
|
||||
+out vec4 color;
|
||||
+void main() {
|
||||
+ color = vec4(s.field0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), fs.str().c_str());
|
||||
+}
|
||||
+
|
||||
} // anonymous namespace
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);
|
||||
@@ -0,0 +1,135 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Tue, 5 Dec 2023 13:36:53 -0500
|
||||
Subject: M120: Vulkan: Don't crash when glCopyTexImage2D redefines itself
|
||||
|
||||
The Vulkan backend marks a level being redefined as such before doing
|
||||
the copy. If a single-level texture was being redefined, it releases it
|
||||
so it can be immediately reallocated. If the source of the copy is the
|
||||
same texture, this causes a crash.
|
||||
|
||||
This can be properly supported by using a temp image to do the copy, but
|
||||
that is not implemented in this change.
|
||||
|
||||
Bug: chromium:1501798
|
||||
Change-Id: I3a902b1e9eec41afd385d9c75a8c95dc986070a8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143829
|
||||
Reviewed-by: Cody Northrop <cnorthrop@google.com>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
index da27d3cfb0932408f14cd2fd6df88294f4b07363..885982b95e70f0c49f89b565fa0f3331333eaac1 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
@@ -723,8 +723,28 @@ angle::Result TextureVk::copyImage(const gl::Context *context,
|
||||
gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
|
||||
const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat);
|
||||
|
||||
+ // The texture level being redefined might be the same as the one bound to the framebuffer.
|
||||
+ // This _could_ be supported by using a temp image before redefining the level (and potentially
|
||||
+ // discarding the image). However, this is currently unimplemented.
|
||||
+ FramebufferVk *framebufferVk = vk::GetImpl(source);
|
||||
+ RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
|
||||
+ vk::ImageHelper *srcImage = &colorReadRT->getImageForCopy();
|
||||
+ const bool isCubeMap = index.getType() == gl::TextureType::CubeMap;
|
||||
+ gl::LevelIndex levelIndex(getNativeImageIndex(index).getLevelIndex());
|
||||
+ const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
|
||||
+ const uint32_t redefinedFace = isCubeMap ? layerIndex : 0;
|
||||
+ const uint32_t sourceFace = isCubeMap ? colorReadRT->getLayerIndex() : 0;
|
||||
+ const bool isSelfCopy = mImage == srcImage && levelIndex == colorReadRT->getLevelIndex() &&
|
||||
+ redefinedFace == sourceFace;
|
||||
+
|
||||
ANGLE_TRY(redefineLevel(context, index, vkFormat, newImageSize));
|
||||
|
||||
+ if (isSelfCopy)
|
||||
+ {
|
||||
+ UNIMPLEMENTED();
|
||||
+ return angle::Result::Continue;
|
||||
+ }
|
||||
+
|
||||
return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo,
|
||||
source);
|
||||
}
|
||||
@@ -1798,7 +1818,8 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
|
||||
mImage->getLevelCount() == 1 && mImage->getFirstAllocatedLevel() == levelIndexGL;
|
||||
|
||||
// If incompatible, and redefining the single-level image, release it so it can be
|
||||
- // recreated immediately. This is an optimization to avoid an extra copy.
|
||||
+ // recreated immediately. This is needed so that the texture can be reallocated with
|
||||
+ // the correct format/size.
|
||||
if (!isCompatibleRedefinition && isUpdateToSingleLevelImage)
|
||||
{
|
||||
releaseImage(contextVk);
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index cfa70eef00a1e8d67f9fbf07ee74928b55da8b92..8b4dac5beab0b8d884116147ba3e61f6133e92a9 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -29,6 +29,8 @@
|
||||
6989 GLES : BlitFramebufferTestES31.OOBResolve/* = SKIP
|
||||
7881 VULKAN : MultithreadingTestES3.UnsynchronizedTextureReads/* = SKIP
|
||||
7881 VULKAN : MultithreadingTestES3.UnsynchronizedTextureReads2/* = SKIP
|
||||
+// Incorrectly handled pretty much in all backends
|
||||
+8446 : CopyTexImageTestES3.RedefineSameLevel/* = SKIP
|
||||
|
||||
6743 OPENGL : SimpleStateChangeTestES3.RespecifyBufferAfterBeginTransformFeedback/* = SKIP
|
||||
6743 GLES : SimpleStateChangeTestES3.RespecifyBufferAfterBeginTransformFeedback/* = SKIP
|
||||
diff --git a/src/tests/gl_tests/CopyTexImageTest.cpp b/src/tests/gl_tests/CopyTexImageTest.cpp
|
||||
index 3d0cf40ab244a5463c2e4b3d53470d6f932e357b..d6949280ed301fc918e397dad26b9efec1c32f23 100644
|
||||
--- a/src/tests/gl_tests/CopyTexImageTest.cpp
|
||||
+++ b/src/tests/gl_tests/CopyTexImageTest.cpp
|
||||
@@ -1262,6 +1262,56 @@ TEST_P(CopyTexImageTestES3, 3DSubImageDrawMismatchedTextureTypes)
|
||||
glBindTexture(GL_TEXTURE_3D, 0);
|
||||
}
|
||||
|
||||
+// Make sure a single-level texture can be redefined through glCopyTexImage2D from a framebuffer
|
||||
+// bound to the same texture. Regression test for a bug in the Vulkan backend where the texture was
|
||||
+// released before the copy.
|
||||
+TEST_P(CopyTexImageTestES3, RedefineSameLevel)
|
||||
+{
|
||||
+ constexpr GLsizei kSize = 32;
|
||||
+ constexpr GLsizei kHalfSize = kSize / 2;
|
||||
+
|
||||
+ // Create a single-level texture with four colors in different regions.
|
||||
+ std::vector<GLColor> initData(kSize * kSize);
|
||||
+ for (GLsizei y = 0; y < kSize; ++y)
|
||||
+ {
|
||||
+ const bool isTop = y < kHalfSize;
|
||||
+ for (GLsizei x = 0; x < kSize; ++x)
|
||||
+ {
|
||||
+ const bool isLeft = x < kHalfSize;
|
||||
+
|
||||
+ GLColor color = isLeft && isTop ? GLColor::red
|
||||
+ : isLeft && !isTop ? GLColor::green
|
||||
+ : !isLeft && isTop ? GLColor::blue
|
||||
+ : GLColor::yellow;
|
||||
+ color.A = 123;
|
||||
+ initData[y * kSize + x] = color;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ GLTexture tex;
|
||||
+ glBindTexture(GL_TEXTURE_2D, tex);
|
||||
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
+ initData.data());
|
||||
+
|
||||
+ // Bind the framebuffer to the same texture
|
||||
+ GLFramebuffer framebuffer;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
|
||||
+
|
||||
+ // Redefine the texture
|
||||
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kHalfSize / 2, kHalfSize / 2, kHalfSize, kHalfSize,
|
||||
+ 0);
|
||||
+
|
||||
+ // Verify copy is done correctly.
|
||||
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, 0, kHalfSize / 2, kHalfSize / 2, GLColor::red);
|
||||
+ EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, 0, kHalfSize / 2, kHalfSize / 2, GLColor::blue);
|
||||
+ EXPECT_PIXEL_RECT_EQ(0, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, GLColor::green);
|
||||
+ EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2,
|
||||
+ GLColor::yellow);
|
||||
+}
|
||||
+
|
||||
ANGLE_INSTANTIATE_TEST(CopyTexImageTest,
|
||||
ANGLE_ALL_TEST_PLATFORMS_ES2,
|
||||
ES2_D3D11_PRESENT_PATH_FAST(),
|
||||
@@ -100,7 +100,6 @@ make_gtk_getlibgtk_public.patch
|
||||
build_disable_print_content_analysis.patch
|
||||
custom_protocols_plzserviceworker.patch
|
||||
feat_filter_out_non-shareable_windows_in_the_current_application_in.patch
|
||||
fix_allow_guest_webcontents_to_enter_fullscreen.patch
|
||||
disable_freezing_flags_after_init_in_node.patch
|
||||
short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch
|
||||
chore_add_electron_deps_to_gitignores.patch
|
||||
@@ -132,3 +131,33 @@ potential_fix_for_flaky_desktopcaptureapitest_delegation_unittest.patch
|
||||
fix_select_the_first_menu_item_when_opened_via_keyboard.patch
|
||||
chore_add_buildflag_guard_around_new_include.patch
|
||||
fix_use_delegated_generic_capturer_when_available.patch
|
||||
revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch
|
||||
cherry-pick-b11e7d07a6f4.patch
|
||||
cherry-pick-f218b4f37018.patch
|
||||
cherry-pick-d756d71a652c.patch
|
||||
parameterize_axtreeserializer_by_vector_type.patch
|
||||
avoid_allocating_recordid_objects_in_elementtiming_and_lcp.patch
|
||||
cherry-pick-80106e31c7ea.patch
|
||||
gpu_use_load_program_shader_shm_count_on_drdc_thread.patch
|
||||
crash_gpu_process_and_clear_shader_cache_when_skia_reports.patch
|
||||
cherry-pick-3df423a5b8de.patch
|
||||
scale_rects_properly_in_syncgetfirstrectforrange.patch
|
||||
cherry-pick-9384cddc7705.patch
|
||||
fix_restore_original_resize_performance_on_macos.patch
|
||||
cherry-pick-3f45b1af5e41.patch
|
||||
cherry-pick-e13061c50998.patch
|
||||
cherry-pick-5fde415e06f9.patch
|
||||
cherry-pick-8d607d3921b8.patch
|
||||
cherry-pick-021598ea43c1.patch
|
||||
cherry-pick-76340163a820.patch
|
||||
cherry-pick-f15cfb9371c4.patch
|
||||
cherry-pick-4ca62c7a8b88.patch
|
||||
cherry-pick-5b2fddadaa12.patch
|
||||
cherry-pick-50a1bddfca85.patch
|
||||
reland_mojom_ts_generator_handle_empty_module_path_identically_to.patch
|
||||
cherry-pick-c1cda70a433a.patch
|
||||
cherry-pick-cc07a95bc309.patch
|
||||
safely_crash_on_dangling_profile.patch
|
||||
cherry-pick-ee0b8769f428.patch
|
||||
cherry-pick-1f8bec968902.patch
|
||||
cherry-pick-4a98f9e304be.patch
|
||||
|
||||
@@ -79,7 +79,7 @@ index 1cada05806cb35a82822507f708d43979d97de61..f8e063397b161b7501308945a7df9fb8
|
||||
if (World().IsMainWorld()) {
|
||||
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 fb229297df448dbe48e5b0ef2978bce2a8affc83..892d971c749b5bf7499c2fc246bc9d5fe5b63b79 100644
|
||||
index 62e611ec3ac95eac88d4665d2640429e9d833594..7bf646d6cd8eaf29267b6136de0952e2545ec503 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
@@ -319,6 +319,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
|
||||
@@ -92,7 +92,7 @@ index fb229297df448dbe48e5b0ef2978bce2a8affc83..892d971c749b5bf7499c2fc246bc9d5f
|
||||
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 fa8c26e31341b2b53879a8760ad8314a569374c6..76ba9e3761d85acdaeeb017f52e24efc3d40e9b7 100644
|
||||
index dbf7fd73a855f7d45eeeeff17582696aac66ff0d..9b489f661f524f380523e38518345e9b22eb8dec 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,7 +110,7 @@ index fa8c26e31341b2b53879a8760ad8314a569374c6..76ba9e3761d85acdaeeb017f52e24efc
|
||||
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 9f6a7e8337a4ade6b902d36919bee58f5e461790..9a73f4ceb6111b7e8bcb607b4e8eb96ebbfb0d42 100644
|
||||
index 28e1c00e05e74d5a79f32897e57a854ff14ce7a9..1cd704b1bb53eaf226d1c72c97e3f765a4b1f10e 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
|
||||
@@ -84,6 +84,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
|
||||
@@ -123,10 +123,10 @@ index 9f6a7e8337a4ade6b902d36919bee58f5e461790..9a73f4ceb6111b7e8bcb607b4e8eb96e
|
||||
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 6b695ab181bc7e8a8b6ecb48ca56145ddc63d6e8..4955c7246498139a20be290a48eee234de44530e 100644
|
||||
index 1934ca82e3e26e0f5c4f2f7b417df6bcd6e66abf..1277b858f2d5b4b0a0dd1c97282eff0d763cdc2b 100644
|
||||
--- a/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
@@ -401,6 +401,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
|
||||
@@ -403,6 +403,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
|
||||
|
||||
void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) override {}
|
||||
|
||||
@@ -33,6 +33,21 @@ index 180abdc9f983887c83fd9d4a596472222e9ab472..00842717a7570561ee9e3eca11190ab5
|
||||
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 9716c8f8a5fe15ffabe4eeedb7b5b35a57b61bac..75796596daeda51d303856ae767e2bae9b9d2d18 100644
|
||||
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
@@ -554,8 +554,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
|
||||
@@ -84,10 +99,20 @@ index 8a18ecf567cd3a6a2fb1627083a5544a93198bf4..8b6436f3ba6c8bfc2cba054e77ab8886
|
||||
// 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 3fd94156edd9868f0d46746227ae40da604bbc2c..ce99c90306bf2988fdb9a92e04d2ed8ec318da78 100644
|
||||
index 3fd94156edd9868f0d46746227ae40da604bbc2c..6ce650e2fc879ae135e5bb731750f8929b592f17 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
@@ -3847,13 +3847,21 @@ PageScheduler* WebViewImpl::Scheduler() const {
|
||||
@@ -2386,6 +2386,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 &&
|
||||
@@ -3847,17 +3850,30 @@ PageScheduler* WebViewImpl::Scheduler() const {
|
||||
return GetPage()->GetPageScheduler();
|
||||
}
|
||||
|
||||
@@ -102,14 +127,29 @@ index 3fd94156edd9868f0d46746227ae40da604bbc2c..ce99c90306bf2988fdb9a92e04d2ed8e
|
||||
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 6a180620e00c77d0f4be346d1296f62feb714abb..c0ccf14faa52ab190c5848e8e9b597bcf637d4c0 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
|
||||
@@ -0,0 +1,655 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yoav Weiss <yoavweiss@chromium.org>
|
||||
Date: Thu, 31 Aug 2023 10:11:57 +0000
|
||||
Subject: Avoid allocating RecordId objects in ElementTiming and LCP
|
||||
|
||||
RecordId objects in current code keep around references to LayoutObject
|
||||
and ImageResourceContent, both GCed objects.
|
||||
Turn out that most of these references are not needed and are only used
|
||||
as hashmap keys that would be better served with an actual hash. The
|
||||
ones that are needed don't need extensive lifetimes and can be stack
|
||||
allocated.
|
||||
|
||||
Bug=1472365,1472366
|
||||
|
||||
Change-Id: I3fd77bed9899932d5bfadc2a8e6403a8e434235f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4821128
|
||||
Commit-Queue: Yoav Weiss <yoavweiss@chromium.org>
|
||||
Reviewed-by: Omer Katz <omerkatz@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1190644}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/paint/DEPS b/third_party/blink/renderer/core/paint/DEPS
|
||||
index c6d60f8f418f03a3dcf1db94ca0e7feb87d85efa..16a5c09a09bf5343e7b05375bd55345f1023a9a3 100644
|
||||
--- a/third_party/blink/renderer/core/paint/DEPS
|
||||
+++ b/third_party/blink/renderer/core/paint/DEPS
|
||||
@@ -4,6 +4,8 @@ include_rules = [
|
||||
"+cc/layers/picture_layer.h",
|
||||
# For DCHECK.
|
||||
"+base/logging.h",
|
||||
+ # Hash function access
|
||||
+ "+base/hash/hash.h",
|
||||
]
|
||||
|
||||
specific_include_rules = {
|
||||
diff --git a/third_party/blink/renderer/core/paint/build.gni b/third_party/blink/renderer/core/paint/build.gni
|
||||
index fd75feaf315977a60b80e66b4a8ecd09d8edb7e4..663cdaf120c579b75b94af835e62d937e9f2a115 100644
|
||||
--- a/third_party/blink/renderer/core/paint/build.gni
|
||||
+++ b/third_party/blink/renderer/core/paint/build.gni
|
||||
@@ -200,6 +200,8 @@ blink_core_sources_paint = [
|
||||
"timing/image_paint_timing_detector.h",
|
||||
"timing/largest_contentful_paint_calculator.cc",
|
||||
"timing/largest_contentful_paint_calculator.h",
|
||||
+ "timing/media_record_id.cc",
|
||||
+ "timing/media_record_id.h",
|
||||
"timing/paint_timing.cc",
|
||||
"timing/paint_timing_detector.cc",
|
||||
"timing/paint_timing_detector.h",
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/image_element_timing.cc b/third_party/blink/renderer/core/paint/timing/image_element_timing.cc
|
||||
index a8501cfcc91e57b3348e3db8ff11256c4d7176b2..21f7a0ac38732e5381da6b82544044b8e6da3a11 100644
|
||||
--- a/third_party/blink/renderer/core/paint/timing/image_element_timing.cc
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/image_element_timing.cc
|
||||
@@ -68,7 +68,7 @@ void ImageElementTiming::NotifyImageFinished(
|
||||
return;
|
||||
|
||||
const auto& insertion_result = images_notified_.insert(
|
||||
- std::make_pair(&layout_object, cached_image), ImageInfo());
|
||||
+ MediaRecordId::GenerateHash(&layout_object, cached_image), ImageInfo());
|
||||
if (insertion_result.is_new_entry)
|
||||
insertion_result.stored_value->value.load_time_ = base::TimeTicks::Now();
|
||||
}
|
||||
@@ -97,8 +97,8 @@ void ImageElementTiming::NotifyImagePainted(
|
||||
if (!internal::IsExplicitlyRegisteredForTiming(layout_object))
|
||||
return;
|
||||
|
||||
- auto it =
|
||||
- images_notified_.find(std::make_pair(&layout_object, &cached_image));
|
||||
+ auto it = images_notified_.find(
|
||||
+ MediaRecordId::GenerateHash(&layout_object, &cached_image));
|
||||
// It is possible that the pair is not in |images_notified_|. See
|
||||
// https://crbug.com/1027948
|
||||
if (it != images_notified_.end() && !it->value.is_painted_) {
|
||||
@@ -218,7 +218,8 @@ void ImageElementTiming::NotifyBackgroundImagePainted(
|
||||
|
||||
ImageInfo& info =
|
||||
images_notified_
|
||||
- .insert(std::make_pair(layout_object, cached_image), ImageInfo())
|
||||
+ .insert(MediaRecordId::GenerateHash(layout_object, cached_image),
|
||||
+ ImageInfo())
|
||||
.stored_value->value;
|
||||
if (!info.is_painted_) {
|
||||
info.is_painted_ = true;
|
||||
@@ -246,7 +247,7 @@ void ImageElementTiming::ReportImagePaintPresentationTime(
|
||||
|
||||
void ImageElementTiming::NotifyImageRemoved(const LayoutObject* layout_object,
|
||||
const ImageResourceContent* image) {
|
||||
- images_notified_.erase(std::make_pair(layout_object, image));
|
||||
+ images_notified_.erase(MediaRecordId::GenerateHash(layout_object, image));
|
||||
}
|
||||
|
||||
void ImageElementTiming::Trace(Visitor* visitor) const {
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/image_element_timing.h b/third_party/blink/renderer/core/paint/timing/image_element_timing.h
|
||||
index 0a152210de91ab69c255be8caa951616afb3df06..7d3f5dd7c9137b277543e52d4d1e327d75b01e84 100644
|
||||
--- a/third_party/blink/renderer/core/paint/timing/image_element_timing.h
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/image_element_timing.h
|
||||
@@ -5,12 +5,11 @@
|
||||
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_IMAGE_ELEMENT_TIMING_H_
|
||||
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_IMAGE_ELEMENT_TIMING_H_
|
||||
|
||||
-#include <utility>
|
||||
-
|
||||
#include "base/time/time.h"
|
||||
#include "third_party/blink/renderer/core/core_export.h"
|
||||
#include "third_party/blink/renderer/core/dom/element.h"
|
||||
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
|
||||
+#include "third_party/blink/renderer/core/paint/timing/media_record_id.h"
|
||||
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
|
||||
#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
|
||||
#include "third_party/blink/renderer/platform/supplementable.h"
|
||||
@@ -123,13 +122,12 @@ class CORE_EXPORT ImageElementTiming final
|
||||
|
||||
DISALLOW_NEW();
|
||||
};
|
||||
- typedef std::pair<const LayoutObject*, const ImageResourceContent*> RecordId;
|
||||
// Hashmap of pairs of elements, LayoutObjects (for the elements) and
|
||||
// ImageResourceContent (for the src) which correspond to either images or
|
||||
// background images whose paint has been observed. For background images,
|
||||
// only the |is_painted_| bit is used, as the timestamp needs to be tracked by
|
||||
// |background_image_timestamps_|.
|
||||
- WTF::HashMap<RecordId, ImageInfo> images_notified_;
|
||||
+ WTF::HashMap<MediaRecordIdHash, ImageInfo> images_notified_;
|
||||
|
||||
// Hashmap of background images which contain information about the load time
|
||||
// of the background image.
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/image_element_timing_test.cc b/third_party/blink/renderer/core/paint/timing/image_element_timing_test.cc
|
||||
index 963493d548df51a704cb332c0df7a70ffa091011..6ed8840f58b0bafd50a67acfd389a41c2b4cc78d 100644
|
||||
--- a/third_party/blink/renderer/core/paint/timing/image_element_timing_test.cc
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/image_element_timing_test.cc
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "third_party/blink/renderer/core/layout/layout_image.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
|
||||
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
|
||||
+#include "third_party/blink/renderer/core/paint/timing/media_record_id.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
|
||||
#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
|
||||
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
|
||||
@@ -60,11 +61,9 @@ class ImageElementTimingTest : public testing::Test,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
- bool ImagesNotifiedContains(
|
||||
- const std::pair<const LayoutObject*, const ImageResourceContent*>&
|
||||
- record_id) {
|
||||
+ bool ImagesNotifiedContains(MediaRecordIdHash record_id_hash) {
|
||||
return ImageElementTiming::From(*GetDoc()->domWindow())
|
||||
- .images_notified_.Contains(record_id);
|
||||
+ .images_notified_.Contains(record_id_hash);
|
||||
}
|
||||
|
||||
unsigned ImagesNotifiedSize() {
|
||||
@@ -159,7 +158,7 @@ TEST_P(ImageElementTimingTest, IgnoresUnmarkedElement) {
|
||||
ASSERT_TRUE(layout_image);
|
||||
UpdateAllLifecyclePhases();
|
||||
EXPECT_FALSE(ImagesNotifiedContains(
|
||||
- std::make_pair(layout_image, layout_image->CachedImage())));
|
||||
+ MediaRecordId::GenerateHash(layout_image, layout_image->CachedImage())));
|
||||
}
|
||||
|
||||
TEST_P(ImageElementTimingTest, ImageInsideSVG) {
|
||||
@@ -179,7 +178,7 @@ TEST_P(ImageElementTimingTest, ImageInsideSVG) {
|
||||
|
||||
// |layout_image| should have had its paint notified to ImageElementTiming.
|
||||
EXPECT_TRUE(ImagesNotifiedContains(
|
||||
- std::make_pair(layout_image, layout_image->CachedImage())));
|
||||
+ MediaRecordId::GenerateHash(layout_image, layout_image->CachedImage())));
|
||||
}
|
||||
|
||||
TEST_P(ImageElementTimingTest, ImageInsideNonRenderedSVG) {
|
||||
@@ -214,7 +213,7 @@ TEST_P(ImageElementTimingTest, ImageRemoved) {
|
||||
ASSERT_TRUE(layout_image);
|
||||
UpdateAllLifecyclePhases();
|
||||
EXPECT_TRUE(ImagesNotifiedContains(
|
||||
- std::make_pair(layout_image, layout_image->CachedImage())));
|
||||
+ MediaRecordId::GenerateHash(layout_image, layout_image->CachedImage())));
|
||||
|
||||
GetDoc()->getElementById("target")->remove();
|
||||
// |layout_image| should no longer be part of |images_notified| since it will
|
||||
@@ -234,7 +233,7 @@ TEST_P(ImageElementTimingTest, SVGImageRemoved) {
|
||||
LayoutSVGImage* layout_image = SetSVGImageResource("target", 5, 5);
|
||||
ASSERT_TRUE(layout_image);
|
||||
UpdateAllLifecyclePhases();
|
||||
- EXPECT_TRUE(ImagesNotifiedContains(std::make_pair(
|
||||
+ EXPECT_TRUE(ImagesNotifiedContains(MediaRecordId::GenerateHash(
|
||||
layout_image, layout_image->ImageResource()->CachedImage())));
|
||||
|
||||
GetDoc()->getElementById("target")->remove();
|
||||
@@ -261,7 +260,8 @@ TEST_P(ImageElementTimingTest, BackgroundImageRemoved) {
|
||||
object->Style()->BackgroundLayers().GetImage()->CachedImage();
|
||||
UpdateAllLifecyclePhases();
|
||||
EXPECT_EQ(ImagesNotifiedSize(), 1u);
|
||||
- EXPECT_TRUE(ImagesNotifiedContains(std::make_pair(object, content)));
|
||||
+ EXPECT_TRUE(
|
||||
+ ImagesNotifiedContains(MediaRecordId::GenerateHash(object, content)));
|
||||
|
||||
GetDoc()->getElementById("target")->remove();
|
||||
EXPECT_EQ(ImagesNotifiedSize(), 0u);
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
|
||||
index b4ed09ccd893b39d4497fc9a237c1ab00bda91fa..e516c2a15a362fa71fcb1d644e8eb61ea2934b1e 100644
|
||||
--- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
|
||||
@@ -231,8 +231,8 @@ void ImagePaintTimingDetector::OnPaintFinished() {
|
||||
void ImagePaintTimingDetector::NotifyImageRemoved(
|
||||
const LayoutObject& object,
|
||||
const MediaTiming* media_timing) {
|
||||
- RecordId record_id = std::make_pair(&object, media_timing);
|
||||
- records_manager_.RemoveRecord(record_id);
|
||||
+ records_manager_.RemoveRecord(
|
||||
+ MediaRecordId::GenerateHash(&object, media_timing));
|
||||
}
|
||||
|
||||
void ImagePaintTimingDetector::StopRecordEntries() {
|
||||
@@ -270,7 +270,7 @@ void ImageRecordsManager::AssignPaintTimeToRegisteredQueuedRecords(
|
||||
unsigned last_queued_frame_index) {
|
||||
while (!images_queued_for_paint_time_.empty()) {
|
||||
const base::WeakPtr<ImageRecord>& record =
|
||||
- images_queued_for_paint_time_.front().first;
|
||||
+ images_queued_for_paint_time_.front().image_record;
|
||||
if (!record) {
|
||||
images_queued_for_paint_time_.pop_front();
|
||||
continue;
|
||||
@@ -282,8 +282,8 @@ void ImageRecordsManager::AssignPaintTimeToRegisteredQueuedRecords(
|
||||
record->first_animated_frame_time = timestamp;
|
||||
record->queue_animated_paint = false;
|
||||
}
|
||||
- auto it =
|
||||
- pending_images_.find(images_queued_for_paint_time_.front().second);
|
||||
+ auto it = pending_images_.find(
|
||||
+ images_queued_for_paint_time_.front().record_id_hash);
|
||||
images_queued_for_paint_time_.pop_front();
|
||||
// A record may be in |images_queued_for_paint_time_| twice, for instance if
|
||||
// is already loaded by the time of its first paint.
|
||||
@@ -319,7 +319,8 @@ bool ImagePaintTimingDetector::RecordImage(
|
||||
if (image_border.IsEmpty())
|
||||
return false;
|
||||
|
||||
- RecordId record_id = std::make_pair(&object, &media_timing);
|
||||
+ MediaRecordId record_id(&object, &media_timing);
|
||||
+ MediaRecordIdHash record_id_hash = record_id.GetHash();
|
||||
|
||||
if (int depth = IgnorePaintTimingScope::IgnoreDepth()) {
|
||||
// Record the largest loaded image that is hidden due to documentElement
|
||||
@@ -340,17 +341,18 @@ bool ImagePaintTimingDetector::RecordImage(
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (records_manager_.IsRecordedImage(record_id)) {
|
||||
+ if (records_manager_.IsRecordedImage(record_id_hash)) {
|
||||
base::WeakPtr<ImageRecord> record =
|
||||
- records_manager_.GetPendingImage(record_id);
|
||||
+ records_manager_.GetPendingImage(record_id_hash);
|
||||
if (!record)
|
||||
return false;
|
||||
if (ShouldReportAnimatedImages() && media_timing.IsPaintedFirstFrame()) {
|
||||
added_entry_in_latest_frame_ |=
|
||||
- records_manager_.OnFirstAnimatedFramePainted(record_id, frame_index_);
|
||||
+ records_manager_.OnFirstAnimatedFramePainted(record_id_hash,
|
||||
+ frame_index_);
|
||||
}
|
||||
if (!record->loaded && media_timing.IsSufficientContentLoadedForPaint()) {
|
||||
- records_manager_.OnImageLoaded(record_id, frame_index_, style_image);
|
||||
+ records_manager_.OnImageLoaded(record_id_hash, frame_index_, style_image);
|
||||
added_entry_in_latest_frame_ = true;
|
||||
if (absl::optional<PaintTimingVisualizer>& visualizer =
|
||||
frame_view_->GetPaintTimingDetector().Visualizer()) {
|
||||
@@ -386,10 +388,11 @@ bool ImagePaintTimingDetector::RecordImage(
|
||||
|
||||
if (ShouldReportAnimatedImages() && media_timing.IsPaintedFirstFrame()) {
|
||||
added_entry_in_latest_frame_ |=
|
||||
- records_manager_.OnFirstAnimatedFramePainted(record_id, frame_index_);
|
||||
+ records_manager_.OnFirstAnimatedFramePainted(record_id_hash,
|
||||
+ frame_index_);
|
||||
}
|
||||
if (media_timing.IsSufficientContentLoadedForPaint()) {
|
||||
- records_manager_.OnImageLoaded(record_id, frame_index_, style_image);
|
||||
+ records_manager_.OnImageLoaded(record_id_hash, frame_index_, style_image);
|
||||
added_entry_in_latest_frame_ = true;
|
||||
return true;
|
||||
}
|
||||
@@ -445,8 +448,8 @@ uint64_t ImagePaintTimingDetector::ComputeImageRectSize(
|
||||
void ImagePaintTimingDetector::NotifyImageFinished(
|
||||
const LayoutObject& object,
|
||||
const MediaTiming* media_timing) {
|
||||
- RecordId record_id = std::make_pair(&object, media_timing);
|
||||
- records_manager_.NotifyImageFinished(record_id);
|
||||
+ records_manager_.NotifyImageFinished(
|
||||
+ MediaRecordId::GenerateHash(&object, media_timing));
|
||||
}
|
||||
|
||||
void ImagePaintTimingDetector::ReportLargestIgnoredImage() {
|
||||
@@ -458,9 +461,9 @@ ImageRecordsManager::ImageRecordsManager(LocalFrameView* frame_view)
|
||||
: size_ordered_set_(&LargeImageFirst), frame_view_(frame_view) {}
|
||||
|
||||
bool ImageRecordsManager::OnFirstAnimatedFramePainted(
|
||||
- const RecordId& record_id,
|
||||
+ MediaRecordIdHash record_id_hash,
|
||||
unsigned current_frame_index) {
|
||||
- base::WeakPtr<ImageRecord> record = GetPendingImage(record_id);
|
||||
+ base::WeakPtr<ImageRecord> record = GetPendingImage(record_id_hash);
|
||||
DCHECK(record);
|
||||
if (record->media_timing &&
|
||||
!record->media_timing->GetFirstVideoFrameTime().is_null()) {
|
||||
@@ -473,19 +476,19 @@ bool ImageRecordsManager::OnFirstAnimatedFramePainted(
|
||||
// Otherwise, this is an animated images, and so we should wait for the
|
||||
// presentation callback to fire to set the first frame presentation time.
|
||||
record->queue_animated_paint = true;
|
||||
- QueueToMeasurePaintTime(record_id, record, current_frame_index);
|
||||
+ QueueToMeasurePaintTime(record_id_hash, record, current_frame_index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
-void ImageRecordsManager::OnImageLoaded(const RecordId& record_id,
|
||||
+void ImageRecordsManager::OnImageLoaded(MediaRecordIdHash record_id_hash,
|
||||
unsigned current_frame_index,
|
||||
const StyleFetchedImage* style_image) {
|
||||
- base::WeakPtr<ImageRecord> record = GetPendingImage(record_id);
|
||||
+ base::WeakPtr<ImageRecord> record = GetPendingImage(record_id_hash);
|
||||
DCHECK(record);
|
||||
if (!style_image) {
|
||||
- auto it = image_finished_times_.find(record_id);
|
||||
+ auto it = image_finished_times_.find(record_id_hash);
|
||||
if (it != image_finished_times_.end()) {
|
||||
record->load_time = it->value;
|
||||
DCHECK(!record->load_time.is_null());
|
||||
@@ -498,7 +501,7 @@ void ImageRecordsManager::OnImageLoaded(const RecordId& record_id,
|
||||
record->origin_clean = style_image->IsOriginClean();
|
||||
}
|
||||
}
|
||||
- OnImageLoadedInternal(record_id, record, current_frame_index);
|
||||
+ OnImageLoadedInternal(record_id_hash, record, current_frame_index);
|
||||
}
|
||||
|
||||
void ImageRecordsManager::ReportLargestIgnoredImage(
|
||||
@@ -518,25 +521,25 @@ void ImageRecordsManager::ReportLargestIgnoredImage(
|
||||
DCHECK(document);
|
||||
PaintTiming::From(*document).MarkFirstContentfulPaint();
|
||||
|
||||
- RecordId record_id = std::make_pair(node->GetLayoutObject(),
|
||||
- largest_ignored_image_->media_timing);
|
||||
- recorded_images_.insert(record_id);
|
||||
+ MediaRecordIdHash record_id_hash = MediaRecordId::GenerateHash(
|
||||
+ node->GetLayoutObject(), largest_ignored_image_->media_timing);
|
||||
+ recorded_images_.insert(record_id_hash);
|
||||
base::WeakPtr<ImageRecord> record = largest_ignored_image_->AsWeakPtr();
|
||||
size_ordered_set_.insert(record);
|
||||
- pending_images_.insert(record_id, std::move(largest_ignored_image_));
|
||||
- OnImageLoadedInternal(record_id, record, current_frame_index);
|
||||
+ pending_images_.insert(record_id_hash, std::move(largest_ignored_image_));
|
||||
+ OnImageLoadedInternal(record_id_hash, record, current_frame_index);
|
||||
}
|
||||
|
||||
void ImageRecordsManager::OnImageLoadedInternal(
|
||||
- const RecordId& record_id,
|
||||
+ MediaRecordIdHash record_id_hash,
|
||||
base::WeakPtr<ImageRecord>& record,
|
||||
unsigned current_frame_index) {
|
||||
SetLoaded(record);
|
||||
- QueueToMeasurePaintTime(record_id, record, current_frame_index);
|
||||
+ QueueToMeasurePaintTime(record_id_hash, record, current_frame_index);
|
||||
}
|
||||
|
||||
void ImageRecordsManager::MaybeUpdateLargestIgnoredImage(
|
||||
- const RecordId& record_id,
|
||||
+ const MediaRecordId& record_id,
|
||||
const uint64_t& visual_size,
|
||||
const gfx::Rect& frame_visual_rect,
|
||||
const gfx::RectF& root_visual_rect,
|
||||
@@ -544,14 +547,14 @@ void ImageRecordsManager::MaybeUpdateLargestIgnoredImage(
|
||||
if (visual_size && (!largest_ignored_image_ ||
|
||||
visual_size > largest_ignored_image_->recorded_size)) {
|
||||
largest_ignored_image_ = CreateImageRecord(
|
||||
- *record_id.first, record_id.second, visual_size, frame_visual_rect,
|
||||
- root_visual_rect, is_loaded_after_mouseover);
|
||||
+ *record_id.GetLayoutObject(), record_id.GetMediaTiming(), visual_size,
|
||||
+ frame_visual_rect, root_visual_rect, is_loaded_after_mouseover);
|
||||
largest_ignored_image_->load_time = base::TimeTicks::Now();
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageRecordsManager::RecordFirstPaintAndReturnIsPending(
|
||||
- const RecordId& record_id,
|
||||
+ const MediaRecordId& record_id,
|
||||
const uint64_t& visual_size,
|
||||
const gfx::Rect& frame_visual_rect,
|
||||
const gfx::RectF& root_visual_rect,
|
||||
@@ -562,7 +565,7 @@ bool ImageRecordsManager::RecordFirstPaintAndReturnIsPending(
|
||||
if (visual_size == 0u) {
|
||||
return false;
|
||||
}
|
||||
- recorded_images_.insert(record_id);
|
||||
+ recorded_images_.insert(record_id.GetHash());
|
||||
// If this cannot become an LCP candidate, no need to do anything else.
|
||||
if (visual_size == 0u ||
|
||||
(largest_painted_image_ &&
|
||||
@@ -588,10 +591,10 @@ bool ImageRecordsManager::RecordFirstPaintAndReturnIsPending(
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageRecord> record = CreateImageRecord(
|
||||
- *record_id.first, record_id.second, visual_size, frame_visual_rect,
|
||||
- root_visual_rect, is_loaded_after_mouseover);
|
||||
+ *record_id.GetLayoutObject(), record_id.GetMediaTiming(), visual_size,
|
||||
+ frame_visual_rect, root_visual_rect, is_loaded_after_mouseover);
|
||||
size_ordered_set_.insert(record->AsWeakPtr());
|
||||
- pending_images_.insert(record_id, std::move(record));
|
||||
+ pending_images_.insert(record_id.GetHash(), std::move(record));
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
|
||||
index 6625edaafdce8697dbe14c86f6a8fba0042a1e5f..188df4392e6409170842147ec4768307869297da 100644
|
||||
--- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.h
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "third_party/blink/renderer/core/core_export.h"
|
||||
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
|
||||
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
|
||||
+#include "third_party/blink/renderer/core/paint/timing/media_record_id.h"
|
||||
#include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h"
|
||||
#include "third_party/blink/renderer/platform/allow_discouraged_type.h"
|
||||
#include "third_party/blink/renderer/platform/loader/fetch/media_timing.h"
|
||||
@@ -91,8 +92,6 @@ class ImageRecord : public base::SupportsWeakPtr<ImageRecord> {
|
||||
bool is_loaded_after_mouseover = false;
|
||||
};
|
||||
|
||||
-typedef std::pair<const LayoutObject*, const MediaTiming*> RecordId;
|
||||
-
|
||||
// |ImageRecordsManager| is the manager of all of the images that Largest
|
||||
// Image Paint cares about. Note that an image does not necessarily correspond
|
||||
// to a node; it can also be one of the background images attached to a node.
|
||||
@@ -116,10 +115,10 @@ class CORE_EXPORT ImageRecordsManager {
|
||||
ImageRecordsManager& operator=(const ImageRecordsManager&) = delete;
|
||||
ImageRecord* LargestImage() const;
|
||||
|
||||
- inline void RemoveRecord(const RecordId& record_id) {
|
||||
- recorded_images_.erase(record_id);
|
||||
- image_finished_times_.erase(record_id);
|
||||
- auto it = pending_images_.find(record_id);
|
||||
+ inline void RemoveRecord(MediaRecordIdHash record_id_hash) {
|
||||
+ recorded_images_.erase(record_id_hash);
|
||||
+ image_finished_times_.erase(record_id_hash);
|
||||
+ auto it = pending_images_.find(record_id_hash);
|
||||
if (it != pending_images_.end()) {
|
||||
size_ordered_set_.erase(it->value->AsWeakPtr());
|
||||
pending_images_.erase(it);
|
||||
@@ -129,41 +128,42 @@ class CORE_EXPORT ImageRecordsManager {
|
||||
}
|
||||
}
|
||||
// Returns whether an image was added to |pending_images_|.
|
||||
- bool RecordFirstPaintAndReturnIsPending(const RecordId& record_id,
|
||||
+ bool RecordFirstPaintAndReturnIsPending(const MediaRecordId& record_id,
|
||||
const uint64_t& visual_size,
|
||||
const gfx::Rect& frame_visual_rect,
|
||||
const gfx::RectF& root_visual_rect,
|
||||
double bpp,
|
||||
bool is_loaded_after_mouseover);
|
||||
- bool IsRecordedImage(const RecordId& record_id) const {
|
||||
- return recorded_images_.Contains(record_id);
|
||||
+ bool IsRecordedImage(MediaRecordIdHash record_id_hash) const {
|
||||
+ return recorded_images_.Contains(record_id_hash);
|
||||
}
|
||||
|
||||
- void NotifyImageFinished(const RecordId& record_id) {
|
||||
+ void NotifyImageFinished(MediaRecordIdHash record_id_hash) {
|
||||
// TODO(npm): Ideally NotifyImageFinished() would only be called when the
|
||||
// record has not yet been inserted in |image_finished_times_| but that's
|
||||
// not currently the case. If we plumb some information from
|
||||
// MediaTiming we may be able to ensure that this call does not
|
||||
// require the Contains() check, which would save time.
|
||||
- if (!image_finished_times_.Contains(record_id)) {
|
||||
- image_finished_times_.insert(record_id, base::TimeTicks::Now());
|
||||
+ if (!image_finished_times_.Contains(record_id_hash)) {
|
||||
+ image_finished_times_.insert(record_id_hash, base::TimeTicks::Now());
|
||||
}
|
||||
}
|
||||
|
||||
- inline base::WeakPtr<ImageRecord> GetPendingImage(const RecordId& record_id) {
|
||||
- auto it = pending_images_.find(record_id);
|
||||
+ inline base::WeakPtr<ImageRecord> GetPendingImage(
|
||||
+ MediaRecordIdHash record_id_hash) {
|
||||
+ auto it = pending_images_.find(record_id_hash);
|
||||
return it == pending_images_.end() ? nullptr : it->value->AsWeakPtr();
|
||||
}
|
||||
- bool OnFirstAnimatedFramePainted(const RecordId&,
|
||||
+ bool OnFirstAnimatedFramePainted(MediaRecordIdHash,
|
||||
unsigned current_frame_index);
|
||||
- void OnImageLoaded(const RecordId&,
|
||||
+ void OnImageLoaded(MediaRecordIdHash,
|
||||
unsigned current_frame_index,
|
||||
const StyleFetchedImage*);
|
||||
|
||||
// Receives a candidate image painted under opacity 0 but without nested
|
||||
// opacity. May update |largest_ignored_image_| if the new candidate has a
|
||||
// larger size.
|
||||
- void MaybeUpdateLargestIgnoredImage(const RecordId&,
|
||||
+ void MaybeUpdateLargestIgnoredImage(const MediaRecordId&,
|
||||
const uint64_t& visual_size,
|
||||
const gfx::Rect& frame_visual_rect,
|
||||
const gfx::RectF& root_visual_rect,
|
||||
@@ -187,19 +187,31 @@ class CORE_EXPORT ImageRecordsManager {
|
||||
const gfx::Rect& frame_visual_rect,
|
||||
const gfx::RectF& root_visual_rect,
|
||||
bool is_loaded_after_mouseover);
|
||||
- inline void QueueToMeasurePaintTime(const RecordId& record_id,
|
||||
+ inline void QueueToMeasurePaintTime(MediaRecordIdHash record_id_hash,
|
||||
base::WeakPtr<ImageRecord>& record,
|
||||
unsigned current_frame_index) {
|
||||
record->frame_index = current_frame_index;
|
||||
- images_queued_for_paint_time_.push_back(std::make_pair(record, record_id));
|
||||
+ images_queued_for_paint_time_.push_back(
|
||||
+ ImageRecordAndHashPair(record, record_id_hash));
|
||||
}
|
||||
inline void SetLoaded(base::WeakPtr<ImageRecord>& record) {
|
||||
record->loaded = true;
|
||||
}
|
||||
- void OnImageLoadedInternal(const RecordId&,
|
||||
+ void OnImageLoadedInternal(MediaRecordIdHash,
|
||||
base::WeakPtr<ImageRecord>&,
|
||||
unsigned current_frame_index);
|
||||
|
||||
+ struct ImageRecordAndHashPair {
|
||||
+ ImageRecordAndHashPair(base::WeakPtr<ImageRecord>& record,
|
||||
+ MediaRecordIdHash id_hash) {
|
||||
+ image_record = record;
|
||||
+ record_id_hash = id_hash;
|
||||
+ }
|
||||
+
|
||||
+ base::WeakPtr<ImageRecord> image_record;
|
||||
+ MediaRecordIdHash record_id_hash;
|
||||
+ };
|
||||
+
|
||||
// The ImageRecord corresponding to the largest image that has been loaded and
|
||||
// painted.
|
||||
std::unique_ptr<ImageRecord> largest_painted_image_;
|
||||
@@ -208,24 +220,23 @@ class CORE_EXPORT ImageRecordsManager {
|
||||
// timestamp, ordered by size.
|
||||
ImageRecordSet size_ordered_set_;
|
||||
|
||||
- // RecordId for images for which we have seen a first paint. A RecordId is
|
||||
- // added to this set regardless of whether the image could be an LCP
|
||||
- // candidate.
|
||||
- HashSet<RecordId> recorded_images_;
|
||||
+ // MediaRecordId for images for which we have seen a first paint. A
|
||||
+ // MediaRecordId is added to this set regardless of whether the image could be
|
||||
+ // an LCP candidate.
|
||||
+ HashSet<MediaRecordIdHash> recorded_images_;
|
||||
|
||||
- // Map of RecordId to ImageRecord for images for which the first paint has
|
||||
- // been seen but which do not have the paint time set yet. This may contain
|
||||
- // only images which are potential LCP candidates.
|
||||
- HashMap<RecordId, std::unique_ptr<ImageRecord>> pending_images_;
|
||||
+ // Map of MediaRecordId to ImageRecord for images for which the first paint
|
||||
+ // has been seen but which do not have the paint time set yet. This may
|
||||
+ // contain only images which are potential LCP candidates.
|
||||
+ HashMap<MediaRecordIdHash, std::unique_ptr<ImageRecord>> pending_images_;
|
||||
|
||||
// |ImageRecord|s waiting for paint time are stored in this map
|
||||
// until they get a presentation time.
|
||||
- Deque<std::pair<base::WeakPtr<ImageRecord>, RecordId>>
|
||||
- images_queued_for_paint_time_;
|
||||
+ Deque<ImageRecordAndHashPair> images_queued_for_paint_time_;
|
||||
|
||||
// Map containing timestamps of when LayoutObject::ImageNotifyFinished is
|
||||
// first called.
|
||||
- HashMap<RecordId, base::TimeTicks> image_finished_times_;
|
||||
+ HashMap<MediaRecordIdHash, base::TimeTicks> image_finished_times_;
|
||||
|
||||
Member<LocalFrameView> frame_view_;
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/media_record_id.cc b/third_party/blink/renderer/core/paint/timing/media_record_id.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e49c898d1111015d80a71ddc11bd791bb2a0dca1
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/media_record_id.cc
|
||||
@@ -0,0 +1,27 @@
|
||||
+// Copyright 2023 The Chromium Authors
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "third_party/blink/renderer/core/paint/timing/media_record_id.h"
|
||||
+
|
||||
+#include "base/hash/hash.h"
|
||||
+
|
||||
+namespace blink {
|
||||
+
|
||||
+MediaRecordId::MediaRecordId(const LayoutObject* layout,
|
||||
+ const MediaTiming* media)
|
||||
+ : layout_object_(layout),
|
||||
+ media_timing_(media),
|
||||
+ hash_(GenerateHash(layout, media)) {}
|
||||
+
|
||||
+// This hash is used as a key where previously MediaRecordId was used directly.
|
||||
+// That helps us avoid storing references to the GCed LayoutObject and
|
||||
+// MediaTiming, as that can be unsafe when using regular WTF containers. It also
|
||||
+// helps us avoid needlessly allocating MediaRecordId on the heap.
|
||||
+MediaRecordIdHash MediaRecordId::GenerateHash(const LayoutObject* layout,
|
||||
+ const MediaTiming* media) {
|
||||
+ return base::HashInts(reinterpret_cast<MediaRecordIdHash>(layout),
|
||||
+ reinterpret_cast<MediaRecordIdHash>(media));
|
||||
+}
|
||||
+
|
||||
+} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/core/paint/timing/media_record_id.h b/third_party/blink/renderer/core/paint/timing/media_record_id.h
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..32952101e8463e31617d1b5f67c36abf04303c4a
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/renderer/core/paint/timing/media_record_id.h
|
||||
@@ -0,0 +1,37 @@
|
||||
+// Copyright 2023 The Chromium Authors
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_MEDIA_RECORD_ID_H_
|
||||
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TIMING_MEDIA_RECORD_ID_H_
|
||||
+
|
||||
+#include "third_party/blink/renderer/core/core_export.h"
|
||||
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
|
||||
+
|
||||
+namespace blink {
|
||||
+class LayoutObject;
|
||||
+class MediaTiming;
|
||||
+
|
||||
+using MediaRecordIdHash = size_t;
|
||||
+
|
||||
+class MediaRecordId {
|
||||
+ STACK_ALLOCATED();
|
||||
+
|
||||
+ public:
|
||||
+ static MediaRecordIdHash CORE_EXPORT GenerateHash(const LayoutObject* layout,
|
||||
+ const MediaTiming* media);
|
||||
+
|
||||
+ MediaRecordId(const LayoutObject* layout, const MediaTiming* media);
|
||||
+
|
||||
+ MediaRecordIdHash GetHash() const { return hash_; }
|
||||
+ const LayoutObject* GetLayoutObject() const { return layout_object_; }
|
||||
+ const MediaTiming* GetMediaTiming() const { return media_timing_; }
|
||||
+
|
||||
+ private:
|
||||
+ const LayoutObject* const layout_object_;
|
||||
+ const MediaTiming* const media_timing_;
|
||||
+ const MediaRecordIdHash hash_;
|
||||
+};
|
||||
+
|
||||
+} // namespace blink
|
||||
+#endif
|
||||
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
|
||||
index 408a2916a00bb2a871f3a680215de54e7be2077c..caa3d8277acbecbeb25b3449719866e061a82761 100755
|
||||
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
|
||||
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
|
||||
@@ -67,6 +67,7 @@ _CONFIG = [
|
||||
'base::DefaultTickClock',
|
||||
'base::ElapsedTimer',
|
||||
'base::EnumSet',
|
||||
+ 'base::HashInts',
|
||||
'base::JobDelegate',
|
||||
'base::JobHandle',
|
||||
'base::PostJob',
|
||||
@@ -33,10 +33,10 @@ index 884bccba58c66861b43b3b50a7535cba543302e2..82e7bf534aa6b998cee8df53be3ca7db
|
||||
"//base",
|
||||
"//build:branding_buildflags",
|
||||
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
|
||||
index 93184ddac697404d22156015e039b710813ce3a5..0a92a4dac5ce0b2d95ae7f45b76bf45e83420d6b 100644
|
||||
index 01194da83fe3f14c5f84671a186ed01fdbd2dc1e..191766f5e9cf2a0f3c43a6abb2d7e0139d1b666c 100644
|
||||
--- a/chrome/browser/BUILD.gn
|
||||
+++ b/chrome/browser/BUILD.gn
|
||||
@@ -4615,7 +4615,7 @@ static_library("browser") {
|
||||
@@ -4618,7 +4618,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 93184ddac697404d22156015e039b710813ce3a5..0a92a4dac5ce0b2d95ae7f45b76bf45e
|
||||
sources += [ "certificate_viewer_stub.cc" ]
|
||||
}
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index a6b47cee220af2083461bf8c25e9b37defae9c1f..ac514a50b6c7d19acf94da04d2ead46275b7d105 100644
|
||||
index 1029220fce0773fffc4fd8259f09e3659daa1979..bbe49d76df9287fe2561a674c1d8acb622508057 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -6587,7 +6587,6 @@ test("unit_tests") {
|
||||
@@ -6589,7 +6589,6 @@ test("unit_tests") {
|
||||
|
||||
deps += [
|
||||
"//chrome:other_version",
|
||||
@@ -57,7 +57,7 @@ index a6b47cee220af2083461bf8c25e9b37defae9c1f..ac514a50b6c7d19acf94da04d2ead462
|
||||
"//chrome//services/util_win:unit_tests",
|
||||
"//chrome/app:chrome_dll_resources",
|
||||
"//chrome/app:win_unit_tests",
|
||||
@@ -6613,6 +6612,10 @@ test("unit_tests") {
|
||||
@@ -6615,6 +6614,10 @@ test("unit_tests") {
|
||||
"//ui/resources",
|
||||
]
|
||||
|
||||
@@ -68,7 +68,7 @@ index a6b47cee220af2083461bf8c25e9b37defae9c1f..ac514a50b6c7d19acf94da04d2ead462
|
||||
ldflags = [
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
|
||||
@@ -7539,7 +7542,6 @@ test("unit_tests") {
|
||||
@@ -7542,7 +7545,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
@@ -76,7 +76,7 @@ index a6b47cee220af2083461bf8c25e9b37defae9c1f..ac514a50b6c7d19acf94da04d2ead462
|
||||
"//chrome/browser/apps:icon_standardizer",
|
||||
"//chrome/browser/apps/app_service",
|
||||
"//chrome/browser/apps/app_service:test_support",
|
||||
@@ -7626,6 +7628,10 @@ test("unit_tests") {
|
||||
@@ -7629,6 +7631,10 @@ test("unit_tests") {
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings",
|
||||
]
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ index 65714a5dca013794527640645d8eb2ce36049ac6..b2df50b4cd64816ddf9c5b7e222c47b6
|
||||
|
||||
public_deps = [
|
||||
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
|
||||
index dd42e72891b3cc5f32d8b69dba7cb9230efd033a..c8c6770a2382904edbffba0682b36747595f8754 100644
|
||||
index 027fa679e34298ec627282796355b6284876520f..14fc5a7c899145872d0df98d7eab019a320da984 100644
|
||||
--- a/content/test/BUILD.gn
|
||||
+++ b/content/test/BUILD.gn
|
||||
@@ -475,6 +475,7 @@ static_library("test_support") {
|
||||
|
||||
@@ -9,7 +9,7 @@ potentially prevent a window from being created.
|
||||
TODO(loc): this patch is currently broken.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 9f7b9d04cefd48539d8c62cb74c3aac084e116e6..0faa1fba5cea7e301b7497aca5838f761d9e02bd 100644
|
||||
index 23f8f5f1042cbc85e630d57e26624963d9cbc71c..544f2bcf906ad40769e5961d97211fbba549d03a 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -7836,6 +7836,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
@@ -21,10 +21,10 @@ index 9f7b9d04cefd48539d8c62cb74c3aac084e116e6..0faa1fba5cea7e301b7497aca5838f76
|
||||
&no_javascript_access);
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 4efa2e72fdc340624ce888e93ffd4359e20c0973..5018e17e0f56efd54529ef3e9ae1de5e223aed68 100644
|
||||
index c9b13be94c531a528cdbc8046d80d43fe704ef36..4b53b6060e6d7aae818a3d81faa0a1ae673ea59e 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -4206,6 +4206,12 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -4212,6 +4212,12 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
|
||||
auto* new_contents_impl = new_contents.get();
|
||||
|
||||
@@ -37,7 +37,7 @@ index 4efa2e72fdc340624ce888e93ffd4359e20c0973..5018e17e0f56efd54529ef3e9ae1de5e
|
||||
// If the new frame has a name, make sure any SiteInstances that can find
|
||||
// this named frame have proxies for it. Must be called after
|
||||
// SetSessionStorageNamespace, since this calls CreateRenderView, which uses
|
||||
@@ -4247,12 +4253,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -4253,12 +4259,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
AddWebContentsDestructionObserver(new_contents_impl);
|
||||
}
|
||||
|
||||
|
||||
69
patches/chromium/cherry-pick-021598ea43c1.patch
Normal file
69
patches/chromium/cherry-pick-021598ea43c1.patch
Normal file
@@ -0,0 +1,69 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Mon, 4 Dec 2023 23:00:41 +0000
|
||||
Subject: Drop frames received on the wrong task runner
|
||||
|
||||
It can happen during transfer that a frame is posted from the
|
||||
background media thread to the task runner of the old execution
|
||||
context, which can lead to races and UAF.
|
||||
|
||||
This CL makes underlying sources drop frames received on the
|
||||
wrong task runner to avoid the problem.
|
||||
|
||||
(cherry picked from commit 9d042e0d498356185fe9eb33c53b69fab33d06bf)
|
||||
|
||||
Bug: 1505708
|
||||
Change-Id: I686228d88cb1c48bdf8c0b6bf85edd280a54300a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5077845
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Reviewed-by: Tony Herre <toprice@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1231802}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5082444
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Auto-Submit: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1370}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
|
||||
index b5a2f71bae81bba6e61d8f303d24a9df874ae885..4c7b0b982e3d314749e39178eb0fca706d11bd85 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
|
||||
@@ -58,7 +58,15 @@ void RTCEncodedAudioUnderlyingSource::Trace(Visitor* visitor) const {
|
||||
|
||||
void RTCEncodedAudioUnderlyingSource::OnFrameFromSource(
|
||||
std::unique_ptr<webrtc::TransformableAudioFrameInterface> webrtc_frame) {
|
||||
- DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
+ // It can happen that a frame is posted to the task runner of the old
|
||||
+ // execution context during a stream transfer to a new context.
|
||||
+ // TODO(https://crbug.com/1506631): Make the state updates related to the
|
||||
+ // transfer atomic and turn this into a DCHECK.
|
||||
+ if (!task_runner_->BelongsToCurrentThread()) {
|
||||
+ DVLOG(1) << "Dropped frame posted to incorrect task runner. This can "
|
||||
+ "happen during transfer.";
|
||||
+ return;
|
||||
+ }
|
||||
// If the source is canceled or there are too many queued frames,
|
||||
// drop the new frame.
|
||||
if (!disconnect_callback_ || !GetExecutionContext()) {
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
|
||||
index 54ca7d1529b1772200c3691b56e847acc42d086d..8fb1d8460e289cd5e6764271f79dada7f121cb1b 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
|
||||
@@ -58,7 +58,15 @@ void RTCEncodedVideoUnderlyingSource::Trace(Visitor* visitor) const {
|
||||
|
||||
void RTCEncodedVideoUnderlyingSource::OnFrameFromSource(
|
||||
std::unique_ptr<webrtc::TransformableVideoFrameInterface> webrtc_frame) {
|
||||
- DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
+ // It can happen that a frame is posted to the task runner of the old
|
||||
+ // execution context during a stream transfer to a new context.
|
||||
+ // TODO(https://crbug.com/1506631): Make the state updates related to the
|
||||
+ // transfer atomic and turn this into a DCHECK.
|
||||
+ if (!task_runner_->BelongsToCurrentThread()) {
|
||||
+ DVLOG(1) << "Dropped frame posted to incorrect task runner. This can "
|
||||
+ "happen during transfer.";
|
||||
+ return;
|
||||
+ }
|
||||
// If the source is canceled or there are too many queued frames,
|
||||
// drop the new frame.
|
||||
if (!disconnect_callback_ || !GetExecutionContext()) {
|
||||
125
patches/chromium/cherry-pick-1f8bec968902.patch
Normal file
125
patches/chromium/cherry-pick-1f8bec968902.patch
Normal file
@@ -0,0 +1,125 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tsuyoshi Horo <horo@chromium.org>
|
||||
Date: Wed, 24 Jan 2024 02:04:24 +0000
|
||||
Subject: Fix UAF in SourceStreamToDataPipe
|
||||
|
||||
SourceStreamToDataPipe::ReadMore() is passing a callback with
|
||||
Unretained(this) to net::SourceStream::Read(). But this callback may be
|
||||
called even after the SourceStream is destructed. This is causing UAF
|
||||
issue (crbug.com/1511085).
|
||||
|
||||
To solve this problem, this CL changes ReadMore() method to pass a
|
||||
callback with a weak ptr of this.
|
||||
|
||||
(cherry picked from commit 6e36a69da1b73f9aea9c54bfbe6c5b9cb2c672a5)
|
||||
|
||||
Bug: 1511085
|
||||
Change-Id: Idd4e34ff300ff5db2de1de7b303841c7db3a964a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5179746
|
||||
Reviewed-by: Adam Rice <ricea@chromium.org>
|
||||
Commit-Queue: Tsuyoshi Horo <horo@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1244526}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5231558
|
||||
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1860}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/services/network/public/cpp/source_stream_to_data_pipe.cc b/services/network/public/cpp/source_stream_to_data_pipe.cc
|
||||
index bfd85b1a00b216b52ae816ca29cb66ddabe20b6d..07afd58a40f92485ded07c535092a891c5140c7b 100644
|
||||
--- a/services/network/public/cpp/source_stream_to_data_pipe.cc
|
||||
+++ b/services/network/public/cpp/source_stream_to_data_pipe.cc
|
||||
@@ -55,9 +55,9 @@ void SourceStreamToDataPipe::ReadMore() {
|
||||
|
||||
scoped_refptr<net::IOBuffer> buffer(
|
||||
new network::NetToMojoIOBuffer(pending_write_.get()));
|
||||
- int result = source_->Read(
|
||||
- buffer.get(), base::checked_cast<int>(num_bytes),
|
||||
- base::BindOnce(&SourceStreamToDataPipe::DidRead, base::Unretained(this)));
|
||||
+ int result = source_->Read(buffer.get(), base::checked_cast<int>(num_bytes),
|
||||
+ base::BindOnce(&SourceStreamToDataPipe::DidRead,
|
||||
+ weak_factory_.GetWeakPtr()));
|
||||
|
||||
if (result != net::ERR_IO_PENDING)
|
||||
DidRead(result);
|
||||
diff --git a/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc b/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
|
||||
index 7061418c5141d936f04b1193c98e66efc5e72ac5..54159df39afa7cf6e2faa51da185dc034b923209 100644
|
||||
--- a/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
|
||||
+++ b/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
|
||||
@@ -6,7 +6,9 @@
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
+#include "base/test/bind.h"
|
||||
#include "base/test/task_environment.h"
|
||||
+#include "net/base/net_errors.h"
|
||||
#include "net/filter/mock_source_stream.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
@@ -42,6 +44,33 @@ struct SourceStreamToDataPipeTestParam {
|
||||
const ReadResultType read_result_type;
|
||||
};
|
||||
|
||||
+class DummyPendingSourceStream : public net::SourceStream {
|
||||
+ public:
|
||||
+ DummyPendingSourceStream() : net::SourceStream(SourceStream::TYPE_NONE) {}
|
||||
+ ~DummyPendingSourceStream() override = default;
|
||||
+
|
||||
+ DummyPendingSourceStream(const DummyPendingSourceStream&) = delete;
|
||||
+ DummyPendingSourceStream& operator=(const DummyPendingSourceStream&) = delete;
|
||||
+
|
||||
+ // SourceStream implementation
|
||||
+ int Read(net::IOBuffer* dest_buffer,
|
||||
+ int buffer_size,
|
||||
+ net::CompletionOnceCallback callback) override {
|
||||
+ callback_ = std::move(callback);
|
||||
+ return net::ERR_IO_PENDING;
|
||||
+ }
|
||||
+ std::string Description() const override { return ""; }
|
||||
+ bool MayHaveMoreBytes() const override { return true; }
|
||||
+
|
||||
+ net::CompletionOnceCallback TakeCompletionCallback() {
|
||||
+ CHECK(callback_);
|
||||
+ return std::move(callback_);
|
||||
+ }
|
||||
+
|
||||
+ private:
|
||||
+ net::CompletionOnceCallback callback_;
|
||||
+};
|
||||
+
|
||||
} // namespace
|
||||
|
||||
class SourceStreamToDataPipeTest
|
||||
@@ -212,4 +241,33 @@ TEST_P(SourceStreamToDataPipeTest, MayHaveMoreBytes) {
|
||||
EXPECT_EQ(ReadPipe(&output), net::OK);
|
||||
EXPECT_EQ(output, message);
|
||||
}
|
||||
+
|
||||
+TEST(SourceStreamToDataPipeCallbackTest, CompletionCallbackAfterDestructed) {
|
||||
+ base::test::TaskEnvironment task_environment;
|
||||
+
|
||||
+ std::unique_ptr<DummyPendingSourceStream> source =
|
||||
+ std::make_unique<DummyPendingSourceStream>();
|
||||
+ DummyPendingSourceStream* source_ptr = source.get();
|
||||
+ const MojoCreateDataPipeOptions data_pipe_options{
|
||||
+ sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 1};
|
||||
+ mojo::ScopedDataPipeProducerHandle producer_end;
|
||||
+ mojo::ScopedDataPipeConsumerHandle consumer_end;
|
||||
+ CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&data_pipe_options,
|
||||
+ producer_end, consumer_end));
|
||||
+
|
||||
+ std::unique_ptr<SourceStreamToDataPipe> adapter =
|
||||
+ std::make_unique<SourceStreamToDataPipe>(std::move(source),
|
||||
+ std::move(producer_end));
|
||||
+ bool callback_called = false;
|
||||
+ adapter->Start(
|
||||
+ base::BindLambdaForTesting([&](int result) { callback_called = true; }));
|
||||
+ net::CompletionOnceCallback callback = source_ptr->TakeCompletionCallback();
|
||||
+ adapter.reset();
|
||||
+
|
||||
+ // Test that calling `callback` after deleting `adapter` must not cause UAF
|
||||
+ // (crbug.com/1511085).
|
||||
+ std::move(callback).Run(net::ERR_FAILED);
|
||||
+ EXPECT_FALSE(callback_called);
|
||||
+}
|
||||
+
|
||||
} // namespace network
|
||||
57
patches/chromium/cherry-pick-3df423a5b8de.patch
Normal file
57
patches/chromium/cherry-pick-3df423a5b8de.patch
Normal file
@@ -0,0 +1,57 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Hongchan Choi <hongchan@chromium.org>
|
||||
Date: Fri, 3 Nov 2023 16:39:55 +0000
|
||||
Subject: Check context status before recreating platform destination
|
||||
|
||||
Changing the channel count in the RealtimeAudioDestinationHandler will
|
||||
trigger the recreation of the platform destination. This in turn can
|
||||
activate the audio rendering thread.
|
||||
|
||||
This CL adds a check to prevent this from happening after the handler
|
||||
is garbage collected.
|
||||
|
||||
(cherry picked from commit 4997f2ba263ff7e1dbc7987dd3665459be14dffe)
|
||||
|
||||
Bug: 1497859
|
||||
Test: Locally confirmed with ASAN
|
||||
Change-Id: I5d2649f3fd3639779ae40b0ca4ef2fe305653421
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4995928
|
||||
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
|
||||
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1217868}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5004961
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5993@{#1520}
|
||||
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
|
||||
index 6781dcff462db872d1f5a786aef0c89f43189100..2e4757d155800700b7c6a8b7cbf2e02250cfce65 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
|
||||
@@ -118,12 +118,21 @@ void RealtimeAudioDestinationHandler::SetChannelCount(
|
||||
uint32_t old_channel_count = ChannelCount();
|
||||
AudioHandler::SetChannelCount(channel_count, exception_state);
|
||||
|
||||
- // Stop, re-create and start the destination to apply the new channel count.
|
||||
- if (ChannelCount() != old_channel_count && !exception_state.HadException()) {
|
||||
- StopPlatformDestination();
|
||||
- CreatePlatformDestination();
|
||||
- StartPlatformDestination();
|
||||
+ // After the context is closed, changing channel count will be ignored
|
||||
+ // because it will trigger the recreation of the platform destination. This
|
||||
+ // in turn can activate the audio rendering thread.
|
||||
+ AudioContext* context = static_cast<AudioContext*>(Context());
|
||||
+ CHECK(context);
|
||||
+ if (context->ContextState() == AudioContext::kClosed ||
|
||||
+ ChannelCount() == old_channel_count ||
|
||||
+ exception_state.HadException()) {
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ // Stop, re-create and start the destination to apply the new channel count.
|
||||
+ StopPlatformDestination();
|
||||
+ CreatePlatformDestination();
|
||||
+ StartPlatformDestination();
|
||||
}
|
||||
|
||||
void RealtimeAudioDestinationHandler::StartRendering() {
|
||||
48
patches/chromium/cherry-pick-3f45b1af5e41.patch
Normal file
48
patches/chromium/cherry-pick-3f45b1af5e41.patch
Normal file
@@ -0,0 +1,48 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Alvin Ji <alvinji@chromium.org>
|
||||
Date: Mon, 13 Nov 2023 20:24:24 +0000
|
||||
Subject: Check context status before creating new platform destination
|
||||
|
||||
RealtimeAudioDestinationHandler::SetSinkDescriptor creates new
|
||||
destination platofrm without validating context status. This can
|
||||
reactivate the audio rendering thread when AudioContext is already in
|
||||
closed state.
|
||||
|
||||
(cherry picked from commit 0f9bb9a1083865d4e51059e588f27f729ab32753)
|
||||
|
||||
Bug: 1500856
|
||||
Change-Id: If1fd531324b56fcdc38d315fd84d4cec577a14bc
|
||||
Test: Locally confirmed with ASAN
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5021160
|
||||
Reviewed-by: Alvin Ji <alvinji@chromium.org>
|
||||
Commit-Queue: Alvin Ji <alvinji@chromium.org>
|
||||
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1223168}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5026373
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#607}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
|
||||
index 2e4757d155800700b7c6a8b7cbf2e02250cfce65..c27eb3ac07f22a4cd1ae2f86da896d255a761292 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
|
||||
@@ -405,6 +405,17 @@ void RealtimeAudioDestinationHandler::SetSinkDescriptor(
|
||||
GetCallbackBufferSize()));
|
||||
DCHECK(IsMainThread());
|
||||
|
||||
+ // After the context is closed, `SetSinkDescriptor` request will be ignored
|
||||
+ // because it will trigger the recreation of the platform destination. This in
|
||||
+ // turn can activate the audio rendering thread.
|
||||
+ AudioContext* context = static_cast<AudioContext*>(Context());
|
||||
+ CHECK(context);
|
||||
+ if (context->ContextState() == AudioContext::kClosed) {
|
||||
+ std::move(callback).Run(
|
||||
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// Create a pending AudioDestination to replace the current one.
|
||||
scoped_refptr<AudioDestination> pending_platform_destination =
|
||||
AudioDestination::Create(
|
||||
67
patches/chromium/cherry-pick-4a98f9e304be.patch
Normal file
67
patches/chromium/cherry-pick-4a98f9e304be.patch
Normal file
@@ -0,0 +1,67 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= <pbos@chromium.org>
|
||||
Date: Fri, 26 Jan 2024 19:37:57 +0000
|
||||
Subject: Speculatively fix race in mojo ShutDownOnIOThread
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This acquires `write_lock_` before resetting handles used by WriteNoLock
|
||||
(which is called under the same lock in another thread). We also set
|
||||
`reject_writes_` to prevent future write attempts after shutdown. That
|
||||
seems strictly more correct.
|
||||
|
||||
We also acquire `fds_to_close_lock_` before clearing the FDs.
|
||||
|
||||
I was unable to repro locally as content_browsertests just times out
|
||||
in my local setup without reporting anything interesting. This seems
|
||||
strictly more correct though.
|
||||
|
||||
(cherry picked from commit 9755d9d81e4a8cb5b4f76b23b761457479dbb06b)
|
||||
|
||||
Bug: 1519980
|
||||
Change-Id: I96279936ca908ecb98eddd381df20d61597cba43
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5226127
|
||||
Auto-Submit: Peter Boström <pbos@chromium.org>
|
||||
Reviewed-by: Ken Rockot <rockot@google.com>
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Commit-Queue: Peter Boström <pbos@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1250580}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5239564
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1883}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/mojo/core/channel_posix.cc b/mojo/core/channel_posix.cc
|
||||
index 0a3596382d0e9a40c72bfb4ead6f0338a61253d6..eae6b0768463679b5043514dc5745da52b80ae10 100644
|
||||
--- a/mojo/core/channel_posix.cc
|
||||
+++ b/mojo/core/channel_posix.cc
|
||||
@@ -246,16 +246,21 @@ void ChannelPosix::WaitForWriteOnIOThreadNoLock() {
|
||||
void ChannelPosix::ShutDownOnIOThread() {
|
||||
base::CurrentThread::Get()->RemoveDestructionObserver(this);
|
||||
|
||||
- read_watcher_.reset();
|
||||
- write_watcher_.reset();
|
||||
- if (leak_handle_) {
|
||||
- std::ignore = socket_.release();
|
||||
- } else {
|
||||
- socket_.reset();
|
||||
- }
|
||||
+ {
|
||||
+ base::AutoLock lock(write_lock_);
|
||||
+ reject_writes_ = true;
|
||||
+ read_watcher_.reset();
|
||||
+ write_watcher_.reset();
|
||||
+ if (leak_handle_) {
|
||||
+ std::ignore = socket_.release();
|
||||
+ } else {
|
||||
+ socket_.reset();
|
||||
+ }
|
||||
#if BUILDFLAG(IS_IOS)
|
||||
- fds_to_close_.clear();
|
||||
+ base::AutoLock fd_lock(fds_to_close_lock_);
|
||||
+ fds_to_close_.clear();
|
||||
#endif
|
||||
+ }
|
||||
|
||||
// May destroy the |this| if it was the last reference.
|
||||
self_ = nullptr;
|
||||
43
patches/chromium/cherry-pick-4ca62c7a8b88.patch
Normal file
43
patches/chromium/cherry-pick-4ca62c7a8b88.patch
Normal file
@@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Vasiliy Telezhnikov <vasilyt@chromium.org>
|
||||
Date: Thu, 7 Dec 2023 16:56:57 +0000
|
||||
Subject: Check for slugs count before deserializing Slugs in DrawSlugOp
|
||||
|
||||
Count is part of serialized data and while we never serialize values
|
||||
less then 1, it can be any value when coming over IPC, we should check
|
||||
that it's positive before substacting one.
|
||||
|
||||
(cherry picked from commit 0527e0d5b08a13d63f4f1eeefa1b86ecfd0cb63b)
|
||||
|
||||
Bug: 1506726
|
||||
Change-Id: I244f50a682f2e852b22ba88f1e9cddddb0fdfcb9
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5078779
|
||||
Reviewed-by: Peng Huang <penghuang@chromium.org>
|
||||
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1232013}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5096809
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1428}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/cc/paint/paint_op.cc b/cc/paint/paint_op.cc
|
||||
index ea103192096b1316f2a9a31cf3478e6dafe66788..5ff86b59f7b7b27e21bfdb95da637fed9cee0420 100644
|
||||
--- a/cc/paint/paint_op.cc
|
||||
+++ b/cc/paint/paint_op.cc
|
||||
@@ -974,10 +974,12 @@ PaintOp* DrawSlugOp::Deserialize(PaintOpReader& reader, void* output) {
|
||||
reader.Read(&op->flags);
|
||||
unsigned int count = 0;
|
||||
reader.Read(&count);
|
||||
- reader.Read(&op->slug);
|
||||
- op->extra_slugs.resize(count - 1);
|
||||
- for (auto& extra_slug : op->extra_slugs) {
|
||||
- reader.Read(&extra_slug);
|
||||
+ if (count > 0) {
|
||||
+ reader.Read(&op->slug);
|
||||
+ op->extra_slugs.resize(count - 1);
|
||||
+ for (auto& extra_slug : op->extra_slugs) {
|
||||
+ reader.Read(&extra_slug);
|
||||
+ }
|
||||
}
|
||||
return op;
|
||||
}
|
||||
117
patches/chromium/cherry-pick-50a1bddfca85.patch
Normal file
117
patches/chromium/cherry-pick-50a1bddfca85.patch
Normal file
@@ -0,0 +1,117 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Austin Eng <enga@chromium.org>
|
||||
Date: Tue, 19 Dec 2023 17:25:51 +0000
|
||||
Subject: Use cross thread handles to bind args for async webgpu context
|
||||
creation
|
||||
|
||||
(cherry picked from commit 542b278a0c1de7202f4bf5e3e5cbdc2dd6c337d4)
|
||||
|
||||
Fixed: 1506923
|
||||
Change-Id: I174703cbd993471e3afb39c0cfa4cce2770755f7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5113019
|
||||
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
|
||||
Commit-Queue: Austin Eng <enga@chromium.org>
|
||||
Reviewed-by: Stephen White <senorblanco@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1237179}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5133239
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1551}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
|
||||
index dbe8ab27798ca1a9aa80f34cbfc88f52adfe3b84..9627347a3b495dffa20f3aa0cfbcaa524eced686 100644
|
||||
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
|
||||
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
|
||||
@@ -39,11 +39,13 @@
|
||||
#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_callback.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h"
|
||||
+#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
|
||||
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
|
||||
#include "third_party/blink/renderer/platform/heap/thread_state.h"
|
||||
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
|
||||
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
|
||||
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
|
||||
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
@@ -300,9 +302,19 @@ void GPU::RequestAdapterImpl(ScriptState* script_state,
|
||||
CreateWebGPUGraphicsContext3DProviderAsync(
|
||||
execution_context->Url(),
|
||||
execution_context->GetTaskRunner(TaskType::kWebGPU),
|
||||
- WTF::BindOnce(
|
||||
- [](GPU* gpu, ExecutionContext* execution_context,
|
||||
+ CrossThreadBindOnce(
|
||||
+ [](CrossThreadHandle<GPU> gpu_handle,
|
||||
+ CrossThreadHandle<ExecutionContext> execution_context_handle,
|
||||
std::unique_ptr<WebGraphicsContext3DProvider> context_provider) {
|
||||
+ auto unwrap_gpu = MakeUnwrappingCrossThreadHandle(gpu_handle);
|
||||
+ auto unwrap_execution_context =
|
||||
+ MakeUnwrappingCrossThreadHandle(execution_context_handle);
|
||||
+ if (!unwrap_gpu || !unwrap_execution_context) {
|
||||
+ return;
|
||||
+ }
|
||||
+ auto* gpu = unwrap_gpu.GetOnCreationThread();
|
||||
+ auto* execution_context =
|
||||
+ unwrap_execution_context.GetOnCreationThread();
|
||||
const KURL& url = execution_context->Url();
|
||||
context_provider =
|
||||
CheckContextProvider(url, std::move(context_provider));
|
||||
@@ -324,7 +336,8 @@ void GPU::RequestAdapterImpl(ScriptState* script_state,
|
||||
std::move(callback).Run();
|
||||
}
|
||||
},
|
||||
- WrapPersistent(this), WrapPersistent(execution_context)));
|
||||
+ MakeCrossThreadHandle(this),
|
||||
+ MakeCrossThreadHandle(execution_context)));
|
||||
return;
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc
|
||||
index f859f3e62c54d26453a145321f697c5116c13348..3d9890b9b4a58a30a11e501fdb9297f4a57b601b 100644
|
||||
--- a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc
|
||||
+++ b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc
|
||||
@@ -121,8 +121,8 @@ CreateWebGPUGraphicsContext3DProvider(const KURL& url) {
|
||||
void CreateWebGPUGraphicsContext3DProviderAsync(
|
||||
const KURL& url,
|
||||
scoped_refptr<base::SingleThreadTaskRunner> current_thread_task_runner,
|
||||
- base::OnceCallback<void(std::unique_ptr<WebGraphicsContext3DProvider>)>
|
||||
- callback) {
|
||||
+ WTF::CrossThreadOnceFunction<
|
||||
+ void(std::unique_ptr<WebGraphicsContext3DProvider>)> callback) {
|
||||
if (IsMainThread()) {
|
||||
std::move(callback).Run(
|
||||
Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url));
|
||||
@@ -140,8 +140,7 @@ void CreateWebGPUGraphicsContext3DProviderAsync(
|
||||
AccessMainThreadForWebGraphicsContext3DProvider()),
|
||||
FROM_HERE,
|
||||
CrossThreadBindOnce(&CreateWebGPUGraphicsContextOnMainThreadAsync, url,
|
||||
- current_thread_task_runner,
|
||||
- CrossThreadBindOnce(std::move(callback))));
|
||||
+ current_thread_task_runner, std::move(callback)));
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h
|
||||
index 8fcab24bfec2c9b2e9edf9885b66de4f99949b35..8b785cc30acdfffed0f59eb53b073d0cdedc2151 100644
|
||||
--- a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h
|
||||
+++ b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
|
||||
#include "third_party/blink/renderer/platform/platform_export.h"
|
||||
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
|
||||
+#include "third_party/blink/renderer/platform/wtf/functional.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
@@ -42,8 +43,8 @@ CreateWebGPUGraphicsContext3DProvider(const KURL& url);
|
||||
PLATFORM_EXPORT void CreateWebGPUGraphicsContext3DProviderAsync(
|
||||
const KURL& url,
|
||||
scoped_refptr<base::SingleThreadTaskRunner> current_thread_task_runner,
|
||||
- base::OnceCallback<void(std::unique_ptr<WebGraphicsContext3DProvider>)>
|
||||
- callback);
|
||||
+ WTF::CrossThreadOnceFunction<
|
||||
+ void(std::unique_ptr<WebGraphicsContext3DProvider>)> callback);
|
||||
|
||||
} // namespace blink
|
||||
|
||||
61
patches/chromium/cherry-pick-5b2fddadaa12.patch
Normal file
61
patches/chromium/cherry-pick-5b2fddadaa12.patch
Normal file
@@ -0,0 +1,61 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Hongchan Choi <hongchan@chromium.org>
|
||||
Date: Tue, 12 Dec 2023 02:34:29 +0000
|
||||
Subject: Clamp the input value correctly before scheduling an AudioParam event
|
||||
|
||||
When the AudioParam value is set via the setter, it internally calls
|
||||
the setValueAtTime() function to schedule the change. However, the
|
||||
current code does not correctly clamp the value within the nominal
|
||||
range. This CL fixes the problem.
|
||||
|
||||
(cherry picked from commit c97b506c1e32951dd39e11e453e1ecc29cc0b35c)
|
||||
|
||||
Bug: 1505086
|
||||
Test: Locally confirmed with both negative and positive param values.
|
||||
Change-Id: Ibb0aae168161af9ea95c5e11a929b3aa2c621c73
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5100625
|
||||
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
|
||||
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1235028}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5112838
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Auto-Submit: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1497}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
|
||||
index 8c7b9d07bb68ec51d21ea2132cc5ecbc39e5cd95..95a40d39c9214fd6555523bd7e7bd91e36d2c6c0 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
|
||||
@@ -120,12 +120,15 @@ void AudioParam::setValue(float value) {
|
||||
void AudioParam::setValue(float value, ExceptionState& exception_state) {
|
||||
WarnIfOutsideRange("value", value);
|
||||
|
||||
- // This is to signal any errors, if necessary, about conflicting
|
||||
- // automations.
|
||||
- setValueAtTime(value, Context()->currentTime(), exception_state);
|
||||
- // This is to change the value so that an immediate query for the
|
||||
- // value returns the expected values.
|
||||
+ // Change the intrinsic value so that an immediate query for the value
|
||||
+ // returns the value that the user code provided. It also clamps the value
|
||||
+ // to the nominal range.
|
||||
Handler().SetValue(value);
|
||||
+
|
||||
+ // Use the intrinsic value (after clamping) to schedule the actual
|
||||
+ // automation event.
|
||||
+ setValueAtTime(Handler().IntrinsicValue(), Context()->currentTime(),
|
||||
+ exception_state);
|
||||
}
|
||||
|
||||
float AudioParam::defaultValue() const {
|
||||
diff --git a/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt b/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt
|
||||
index 7bb2d0aec7feaed69424f209a2e3e031c7a9e512..ebe05a2c239d35be4729cc187aa77de6a44f5a41 100644
|
||||
--- a/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt
|
||||
+++ b/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt
|
||||
@@ -1,5 +1,4 @@
|
||||
CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.value 99 outside nominal range [0, 1]; value will be clamped.
|
||||
-CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.setValueAtTime value 99 outside nominal range [0, 1]; value will be clamped.
|
||||
CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.setValueAtTime value -1 outside nominal range [0, 1]; value will be clamped.
|
||||
CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.linearRampToValueAtTime value 5 outside nominal range [0, 1]; value will be clamped.
|
||||
This is a testharness.js-based test.
|
||||
73
patches/chromium/cherry-pick-5fde415e06f9.patch
Normal file
73
patches/chromium/cherry-pick-5fde415e06f9.patch
Normal file
@@ -0,0 +1,73 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Fri, 10 Nov 2023 20:46:57 +0000
|
||||
Subject: Use KeepAlive to prevent lifetime race with audio delivery
|
||||
|
||||
(cherry picked from commit 186dad16ae69183f02730fb26d84e1d53f9f1b04)
|
||||
|
||||
Bug: 1497984
|
||||
Change-Id: Ic22729b2ef9690203bbb09555d32238959e93a0f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5009864
|
||||
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1221614}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5018212
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#500}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
|
||||
index f68c265271b48f92ff67a752cf2bedac183bd2fc..a53053b12925b6aaa4fb201e7de2c00d4203bb2a 100644
|
||||
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
|
||||
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
|
||||
@@ -142,12 +142,12 @@ bool MediaStreamAudioTrackUnderlyingSource::StartFrameDelivery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (added_to_track_) {
|
||||
+ if (is_connected_to_track_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
WebMediaStreamAudioSink::AddToAudioTrack(this, WebMediaStreamTrack(track_));
|
||||
- added_to_track_ = true;
|
||||
+ is_connected_to_track_ = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ void MediaStreamAudioTrackUnderlyingSource::DisconnectFromTrack() {
|
||||
|
||||
WebMediaStreamAudioSink::RemoveFromAudioTrack(this,
|
||||
WebMediaStreamTrack(track_));
|
||||
- added_to_track_ = false;
|
||||
+ is_connected_to_track_.Clear();
|
||||
track_.Clear();
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
|
||||
index 334da29c2b210f92e9ee191275651406487601c3..4e7d22959dc8947c12d9ee2bb7acd814cc4db6b3 100644
|
||||
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
|
||||
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h"
|
||||
#include "third_party/blink/renderer/modules/modules_export.h"
|
||||
#include "third_party/blink/renderer/platform/heap/prefinalizer.h"
|
||||
+#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
@@ -80,10 +81,13 @@ class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSource
|
||||
const Member<ScriptWrappable> media_stream_track_processor_;
|
||||
|
||||
Member<MediaStreamComponent> track_;
|
||||
- bool added_to_track_ = false;
|
||||
|
||||
std::unique_ptr<AudioBufferPool> buffer_pool_;
|
||||
|
||||
+ // This prevents collection of this object while it is still connected to a
|
||||
+ // platform MediaStreamTrack.
|
||||
+ SelfKeepAlive<MediaStreamAudioTrackUnderlyingSource> is_connected_to_track_;
|
||||
+
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
};
|
||||
|
||||
37
patches/chromium/cherry-pick-76340163a820.patch
Normal file
37
patches/chromium/cherry-pick-76340163a820.patch
Normal file
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Paul Semel <paulsemel@chromium.org>
|
||||
Date: Wed, 6 Dec 2023 15:52:56 +0000
|
||||
Subject: ImageBitmapFactory: fix empty context dcheck
|
||||
|
||||
Approved by:
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=1502102#c34
|
||||
|
||||
(cherry picked from commit c4d2f15b8f97076c8fd0f9aa5814b94db698b75c)
|
||||
|
||||
Fixed: 1502102
|
||||
Change-Id: Ib42d2897d62136ae835561bcf56884b5624060a5
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5071252
|
||||
Commit-Queue: Paul Semel <paulsemel@chromium.org>
|
||||
Reviewed-by: Jean-Philippe Gravel <jpgravel@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1230617}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5088373
|
||||
Auto-Submit: Arthur Sonzogni <arthursonzogni@google.com>
|
||||
Reviewed-by: Paul Semel <paulsemel@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1416}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
|
||||
index 20d95536a945c67b9aba082c0ad1ff4aa46c240d..5028d3744619a14e23bba4006bf958478b5b53f8 100644
|
||||
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
|
||||
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
|
||||
@@ -155,7 +155,9 @@ ScriptPromise ImageBitmapFactories::CreateImageBitmapFromBlob(
|
||||
ImageBitmapSource* bitmap_source,
|
||||
absl::optional<gfx::Rect> crop_rect,
|
||||
const ImageBitmapOptions* options) {
|
||||
- DCHECK(script_state->ContextIsValid());
|
||||
+ if (!script_state->ContextIsValid()) {
|
||||
+ return ScriptPromise();
|
||||
+ }
|
||||
|
||||
// imageOrientation: 'from-image' will be used to replace imageOrientation:
|
||||
// 'none'. Adding a deprecation warning when 'none' is called in
|
||||
428
patches/chromium/cherry-pick-80106e31c7ea.patch
Normal file
428
patches/chromium/cherry-pick-80106e31c7ea.patch
Normal file
@@ -0,0 +1,428 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Reynolds <mattreynolds@google.com>
|
||||
Date: Wed, 25 Oct 2023 00:56:26 +0000
|
||||
Subject: usb: Validate isochronous transfer packet lengths
|
||||
|
||||
USBDevice.isochronousTransferIn and
|
||||
USBDevice.isochronousTransferOut take a parameter containing
|
||||
a list of packet lengths. This CL adds validation that the
|
||||
total packet length does not exceed the maximum buffer size.
|
||||
For isochronousTransferOut, it also checks that the total
|
||||
length of all packets in bytes is equal to the size of the
|
||||
data buffer.
|
||||
|
||||
Passing invalid packet lengths causes the promise to be
|
||||
rejected with a DataError.
|
||||
|
||||
(cherry picked from commit bb36f739e7e0a3722beeb2744744195c22fd6143)
|
||||
|
||||
Bug: 1492381, 1492384
|
||||
Change-Id: Id9ae16c7e6f1c417e0fc4f21d53e9de11560b2b7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4944690
|
||||
Reviewed-by: Reilly Grant <reillyg@chromium.org>
|
||||
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1212916}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4974416
|
||||
Commit-Queue: Reilly Grant <reillyg@chromium.org>
|
||||
Auto-Submit: Matt Reynolds <mattreynolds@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5993@{#1425}
|
||||
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
|
||||
|
||||
diff --git a/services/device/usb/mojo/device_impl.cc b/services/device/usb/mojo/device_impl.cc
|
||||
index 34cc1f360a0340fa235ee0e086f5f5b2ee56309d..a44cb3b262203cc519012e60465cc01af9b4260c 100644
|
||||
--- a/services/device/usb/mojo/device_impl.cc
|
||||
+++ b/services/device/usb/mojo/device_impl.cc
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "base/ranges/algorithm.h"
|
||||
#include "services/device/public/cpp/usb/usb_utils.h"
|
||||
#include "services/device/usb/usb_device.h"
|
||||
+#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
@@ -89,6 +90,20 @@ bool IsAndroidSecurityKeyRequest(
|
||||
memcmp(data.data(), magic, strlen(magic)) == 0;
|
||||
}
|
||||
|
||||
+// Returns the sum of `packet_lengths`, or nullopt if the sum would overflow.
|
||||
+absl::optional<uint32_t> TotalPacketLength(
|
||||
+ base::span<const uint32_t> packet_lengths) {
|
||||
+ uint32_t total_bytes = 0;
|
||||
+ for (const uint32_t packet_length : packet_lengths) {
|
||||
+ // Check for overflow.
|
||||
+ if (std::numeric_limits<uint32_t>::max() - total_bytes < packet_length) {
|
||||
+ return absl::nullopt;
|
||||
+ }
|
||||
+ total_bytes += packet_length;
|
||||
+ }
|
||||
+ return total_bytes;
|
||||
+}
|
||||
+
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@@ -397,6 +412,15 @@ void DeviceImpl::IsochronousTransferIn(
|
||||
return;
|
||||
}
|
||||
|
||||
+ absl::optional<uint32_t> total_bytes = TotalPacketLength(packet_lengths);
|
||||
+ if (!total_bytes.has_value()) {
|
||||
+ mojo::ReportBadMessage("Invalid isochronous packet lengths.");
|
||||
+ std::move(callback).Run(
|
||||
+ {}, BuildIsochronousPacketArray(
|
||||
+ packet_lengths, mojom::UsbTransferStatus::TRANSFER_ERROR));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
uint8_t endpoint_address = endpoint_number | 0x80;
|
||||
device_handle_->IsochronousTransferIn(
|
||||
endpoint_address, packet_lengths, timeout,
|
||||
@@ -415,6 +439,14 @@ void DeviceImpl::IsochronousTransferOut(
|
||||
return;
|
||||
}
|
||||
|
||||
+ absl::optional<uint32_t> total_bytes = TotalPacketLength(packet_lengths);
|
||||
+ if (!total_bytes.has_value() || total_bytes.value() != data.size()) {
|
||||
+ mojo::ReportBadMessage("Invalid isochronous packet lengths.");
|
||||
+ std::move(callback).Run(BuildIsochronousPacketArray(
|
||||
+ packet_lengths, mojom::UsbTransferStatus::TRANSFER_ERROR));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
uint8_t endpoint_address = endpoint_number;
|
||||
auto buffer = base::MakeRefCounted<base::RefCountedBytes>(data);
|
||||
device_handle_->IsochronousTransferOut(
|
||||
diff --git a/services/device/usb/mojo/device_impl_unittest.cc b/services/device/usb/mojo/device_impl_unittest.cc
|
||||
index b23918682064047f644344f96c7a13ccbbe7d95d..2d401f70b2b9d827153adb8b14a5acb6d4a9a8de 100644
|
||||
--- a/services/device/usb/mojo/device_impl_unittest.cc
|
||||
+++ b/services/device/usb/mojo/device_impl_unittest.cc
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
-#include <numeric>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -54,8 +53,11 @@ MATCHER_P(BufferSizeIs, size, "") {
|
||||
|
||||
class ConfigBuilder {
|
||||
public:
|
||||
- explicit ConfigBuilder(uint8_t value)
|
||||
- : config_(BuildUsbConfigurationInfoPtr(value, false, false, 0)) {}
|
||||
+ explicit ConfigBuilder(uint8_t configuration_value)
|
||||
+ : config_(BuildUsbConfigurationInfoPtr(configuration_value,
|
||||
+ /*self_powered=*/false,
|
||||
+ /*remote_wakeup=*/false,
|
||||
+ /*maximum_power=*/0)) {}
|
||||
|
||||
ConfigBuilder(const ConfigBuilder&) = delete;
|
||||
ConfigBuilder& operator=(const ConfigBuilder&) = delete;
|
||||
@@ -413,8 +415,10 @@ class USBDeviceImplTest : public testing::Test {
|
||||
|
||||
ASSERT_EQ(packets.size(), packet_lengths.size());
|
||||
for (size_t i = 0; i < packets.size(); ++i) {
|
||||
- EXPECT_EQ(packets[i]->length, packet_lengths[i])
|
||||
- << "Packet lengths differ at index: " << i;
|
||||
+ if (packets[i]->status == mojom::UsbTransferStatus::COMPLETED) {
|
||||
+ EXPECT_EQ(packets[i]->length, packet_lengths[i])
|
||||
+ << "Packet lengths differ at index: " << i;
|
||||
+ }
|
||||
}
|
||||
|
||||
std::move(callback).Run(buffer, std::move(packets));
|
||||
@@ -428,10 +432,8 @@ class USBDeviceImplTest : public testing::Test {
|
||||
UsbDeviceHandle::IsochronousTransferCallback& callback) {
|
||||
ASSERT_FALSE(mock_outbound_data_.empty());
|
||||
const std::vector<uint8_t>& bytes = mock_outbound_data_.front();
|
||||
- size_t length =
|
||||
- std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
|
||||
- ASSERT_EQ(bytes.size(), length);
|
||||
- for (size_t i = 0; i < length; ++i) {
|
||||
+ ASSERT_EQ(buffer->size(), bytes.size());
|
||||
+ for (size_t i = 0; i < bytes.size(); ++i) {
|
||||
EXPECT_EQ(bytes[i], buffer->front()[i])
|
||||
<< "Contents differ at index: " << i;
|
||||
}
|
||||
@@ -444,8 +446,10 @@ class USBDeviceImplTest : public testing::Test {
|
||||
|
||||
ASSERT_EQ(packets.size(), packet_lengths.size());
|
||||
for (size_t i = 0; i < packets.size(); ++i) {
|
||||
- EXPECT_EQ(packets[i]->length, packet_lengths[i])
|
||||
- << "Packet lengths differ at index: " << i;
|
||||
+ if (packets[i]->status == mojom::UsbTransferStatus::COMPLETED) {
|
||||
+ EXPECT_EQ(packets[i]->length, packet_lengths[i])
|
||||
+ << "Packet lengths differ at index: " << i;
|
||||
+ }
|
||||
}
|
||||
|
||||
std::move(callback).Run(buffer, std::move(packets));
|
||||
@@ -1084,6 +1088,122 @@ TEST_F(USBDeviceImplTest, IsochronousTransfer) {
|
||||
EXPECT_CALL(mock_handle(), Close());
|
||||
}
|
||||
|
||||
+TEST_F(USBDeviceImplTest, IsochronousTransferOutBufferSizeMismatch) {
|
||||
+ mojo::Remote<mojom::UsbDevice> device = GetMockDeviceProxy();
|
||||
+
|
||||
+ EXPECT_CALL(mock_device(), OpenInternal);
|
||||
+
|
||||
+ base::test::TestFuture<mojom::UsbOpenDeviceResultPtr> open_future;
|
||||
+ device->Open(open_future.GetCallback());
|
||||
+ EXPECT_TRUE(open_future.Get()->is_success());
|
||||
+
|
||||
+ constexpr size_t kPacketCount = 4;
|
||||
+ constexpr size_t kPacketLength = 8;
|
||||
+ std::vector<UsbIsochronousPacketPtr> fake_packets;
|
||||
+ for (size_t i = 0; i < kPacketCount; ++i) {
|
||||
+ fake_packets.push_back(mojom::UsbIsochronousPacket::New(
|
||||
+ kPacketLength, kPacketLength, UsbTransferStatus::TRANSFER_ERROR));
|
||||
+ }
|
||||
+
|
||||
+ std::string outbound_data = "aaaaaaaabbbbbbbbccccccccdddddddd";
|
||||
+ std::vector<uint8_t> fake_outbound_data(outbound_data.size());
|
||||
+ base::ranges::copy(outbound_data, fake_outbound_data.begin());
|
||||
+
|
||||
+ std::string inbound_data = "ddddddddccccccccbbbbbbbbaaaaaaaa";
|
||||
+ std::vector<uint8_t> fake_inbound_data(inbound_data.size());
|
||||
+ base::ranges::copy(inbound_data, fake_inbound_data.begin());
|
||||
+
|
||||
+ AddMockConfig(ConfigBuilder(/*configuration_value=*/1)
|
||||
+ .AddInterface(/*interface_number=*/7,
|
||||
+ /*alternate_setting=*/0, /*class_code=*/1,
|
||||
+ /*subclass_code=*/2, /*protocol_code=*/3)
|
||||
+ .Build());
|
||||
+ AddMockOutboundPackets(fake_outbound_data, mojo::Clone(fake_packets));
|
||||
+ AddMockInboundPackets(fake_inbound_data, mojo::Clone(fake_packets));
|
||||
+
|
||||
+ // The `packet_lengths` parameter for IsochronousTransferOut describes the
|
||||
+ // number of bytes in each packet. Set the size of the last packet one byte
|
||||
+ // shorter than the buffer size and check that the returned packets indicate
|
||||
+ // a transfer error.
|
||||
+ std::vector<uint32_t> short_packet_lengths(kPacketCount, kPacketLength);
|
||||
+ short_packet_lengths.back() = kPacketLength - 1;
|
||||
+
|
||||
+ base::test::TestFuture<std::vector<UsbIsochronousPacketPtr>>
|
||||
+ transfer_out_future;
|
||||
+ device->IsochronousTransferOut(
|
||||
+ /*endpoint_number=*/1, fake_outbound_data, short_packet_lengths,
|
||||
+ /*timeout=*/0, transfer_out_future.GetCallback());
|
||||
+ ASSERT_EQ(kPacketCount, transfer_out_future.Get().size());
|
||||
+ for (const auto& packet : transfer_out_future.Get()) {
|
||||
+ EXPECT_EQ(packet->status, UsbTransferStatus::TRANSFER_ERROR);
|
||||
+ }
|
||||
+
|
||||
+ EXPECT_CALL(mock_handle(), Close);
|
||||
+}
|
||||
+
|
||||
+TEST_F(USBDeviceImplTest, IsochronousTransferPacketLengthsOverflow) {
|
||||
+ mojo::Remote<mojom::UsbDevice> device = GetMockDeviceProxy();
|
||||
+
|
||||
+ EXPECT_CALL(mock_device(), OpenInternal);
|
||||
+
|
||||
+ base::test::TestFuture<mojom::UsbOpenDeviceResultPtr> open_future;
|
||||
+ device->Open(open_future.GetCallback());
|
||||
+ EXPECT_TRUE(open_future.Get()->is_success());
|
||||
+
|
||||
+ constexpr size_t kPacketCount = 2;
|
||||
+ constexpr size_t kPacketLength = 8;
|
||||
+ std::vector<UsbIsochronousPacketPtr> fake_packets;
|
||||
+ for (size_t i = 0; i < kPacketCount; ++i) {
|
||||
+ fake_packets.push_back(mojom::UsbIsochronousPacket::New(
|
||||
+ kPacketLength, kPacketLength, UsbTransferStatus::TRANSFER_ERROR));
|
||||
+ }
|
||||
+
|
||||
+ std::string outbound_data = "aaaaaaaabbbbbbbb";
|
||||
+ std::vector<uint8_t> fake_outbound_data(outbound_data.size());
|
||||
+ base::ranges::copy(outbound_data, fake_outbound_data.begin());
|
||||
+
|
||||
+ std::string inbound_data = "bbbbbbbbaaaaaaaa";
|
||||
+ std::vector<uint8_t> fake_inbound_data(inbound_data.size());
|
||||
+ base::ranges::copy(inbound_data, fake_inbound_data.begin());
|
||||
+
|
||||
+ AddMockConfig(ConfigBuilder(/*configuration_value=*/1)
|
||||
+ .AddInterface(/*interface_number=*/7,
|
||||
+ /*alternate_setting=*/0, /*class_code=*/1,
|
||||
+ /*subclass_code=*/2, /*protocol_code=*/3)
|
||||
+ .Build());
|
||||
+ AddMockOutboundPackets(fake_outbound_data, mojo::Clone(fake_packets));
|
||||
+ AddMockInboundPackets(fake_inbound_data, mojo::Clone(fake_packets));
|
||||
+
|
||||
+ // The `packet_lengths` parameter for IsochronousTransferOut and
|
||||
+ // IsochronousTransferIn describes the number of bytes in each packet. Set
|
||||
+ // the packet sizes so the total will exceed the maximum value for uint32_t
|
||||
+ // and check that the returned packets indicate a transfer error.
|
||||
+ std::vector<uint32_t> overflow_packet_lengths = {0xffffffff, 1};
|
||||
+
|
||||
+ base::test::TestFuture<std::vector<UsbIsochronousPacketPtr>>
|
||||
+ transfer_out_future;
|
||||
+ device->IsochronousTransferOut(
|
||||
+ /*endpoint_number=*/1, fake_outbound_data, overflow_packet_lengths,
|
||||
+ /*timeout=*/0, transfer_out_future.GetCallback());
|
||||
+ ASSERT_EQ(kPacketCount, transfer_out_future.Get().size());
|
||||
+ for (const auto& packet : transfer_out_future.Get()) {
|
||||
+ EXPECT_EQ(packet->status, UsbTransferStatus::TRANSFER_ERROR);
|
||||
+ }
|
||||
+
|
||||
+ base::test::TestFuture<base::span<const uint8_t>,
|
||||
+ std::vector<UsbIsochronousPacketPtr>>
|
||||
+ transfer_in_future;
|
||||
+ device->IsochronousTransferIn(
|
||||
+ /*endpoint_number=*/1, overflow_packet_lengths, /*timeout=*/0,
|
||||
+ transfer_in_future.GetCallback());
|
||||
+ ASSERT_EQ(kPacketCount, transfer_in_future.Get<1>().size());
|
||||
+ for (const auto& packet : transfer_in_future.Get<1>()) {
|
||||
+ EXPECT_EQ(packet->status, UsbTransferStatus::TRANSFER_ERROR);
|
||||
+ }
|
||||
+
|
||||
+ EXPECT_CALL(mock_handle(), Close);
|
||||
+}
|
||||
+
|
||||
class USBDeviceImplSecurityKeyTest : public USBDeviceImplTest,
|
||||
public testing::WithParamInterface<bool> {
|
||||
};
|
||||
diff --git a/third_party/blink/renderer/modules/webusb/usb_device.cc b/third_party/blink/renderer/modules/webusb/usb_device.cc
|
||||
index 3d562fa22bd84dc438abfe9fa883eff6f5846b1b..c64c7fb1b15f7f523b37671abca2ab50655cf4d8 100644
|
||||
--- a/third_party/blink/renderer/modules/webusb/usb_device.cc
|
||||
+++ b/third_party/blink/renderer/modules/webusb/usb_device.cc
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include "third_party/blink/renderer/modules/webusb/usb_device.h"
|
||||
|
||||
+#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
+#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "third_party/blink/public/platform/platform.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
|
||||
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
|
||||
@@ -43,6 +45,10 @@ namespace {
|
||||
|
||||
const char kAccessDeniedError[] = "Access denied.";
|
||||
const char kBufferTooBig[] = "The data buffer exceeded its maximum size.";
|
||||
+const char kPacketLengthsTooBig[] =
|
||||
+ "The total packet length exceeded the maximum size.";
|
||||
+const char kBufferSizeMismatch[] =
|
||||
+ "The data buffer size must match the total packet length.";
|
||||
const char kDetachedBuffer[] = "The data buffer has been detached.";
|
||||
const char kDeviceStateChangeInProgress[] =
|
||||
"An operation that changes the device state is in progress.";
|
||||
@@ -106,6 +112,20 @@ String ConvertTransferStatus(const UsbTransferStatus& status) {
|
||||
}
|
||||
}
|
||||
|
||||
+// Returns the sum of `packet_lengths`, or nullopt if the sum would overflow.
|
||||
+absl::optional<uint32_t> TotalPacketLength(
|
||||
+ const Vector<unsigned>& packet_lengths) {
|
||||
+ uint32_t total_bytes = 0;
|
||||
+ for (const auto packet_length : packet_lengths) {
|
||||
+ // Check for overflow.
|
||||
+ if (std::numeric_limits<uint32_t>::max() - total_bytes < packet_length) {
|
||||
+ return absl::nullopt;
|
||||
+ }
|
||||
+ total_bytes += packet_length;
|
||||
+ }
|
||||
+ return total_bytes;
|
||||
+}
|
||||
+
|
||||
} // namespace
|
||||
|
||||
USBDevice::USBDevice(USB* parent,
|
||||
@@ -555,6 +575,13 @@ ScriptPromise USBDevice::isochronousTransferIn(
|
||||
if (exception_state.HadException())
|
||||
return ScriptPromise();
|
||||
|
||||
+ absl::optional<uint32_t> total_bytes = TotalPacketLength(packet_lengths);
|
||||
+ if (!total_bytes.has_value()) {
|
||||
+ exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
|
||||
+ kPacketLengthsTooBig);
|
||||
+ return ScriptPromise();
|
||||
+ }
|
||||
+
|
||||
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(
|
||||
script_state, exception_state.GetContext());
|
||||
ScriptPromise promise = resolver->Promise();
|
||||
@@ -586,6 +613,18 @@ ScriptPromise USBDevice::isochronousTransferOut(
|
||||
return ScriptPromise();
|
||||
}
|
||||
|
||||
+ absl::optional<uint32_t> total_bytes = TotalPacketLength(packet_lengths);
|
||||
+ if (!total_bytes.has_value()) {
|
||||
+ exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
|
||||
+ kPacketLengthsTooBig);
|
||||
+ return ScriptPromise();
|
||||
+ }
|
||||
+ if (total_bytes.value() != data.ByteLength()) {
|
||||
+ exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
|
||||
+ kBufferSizeMismatch);
|
||||
+ return ScriptPromise();
|
||||
+ }
|
||||
+
|
||||
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(
|
||||
script_state, exception_state.GetContext());
|
||||
ScriptPromise promise = resolver->Promise();
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js b/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js
|
||||
index b1b0c133ce160a314ea392514ac5b38e4cac136d..804af2afb9db3a0d5fafbeb26aed64f89badb1b3 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js
|
||||
+++ b/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js
|
||||
@@ -1247,3 +1247,60 @@ usb_test((t) => {
|
||||
.then(() => promise_rejects_dom(t, 'NotFoundError', device.reset()));
|
||||
});
|
||||
}, 'resetDevice rejects when called on a disconnected device');
|
||||
+
|
||||
+usb_test(async (t) => {
|
||||
+ const PACKET_COUNT = 4;
|
||||
+ const PACKET_LENGTH = 8;
|
||||
+ const {device, fakeDevice} = await getFakeDevice();
|
||||
+ await device.open();
|
||||
+ await device.selectConfiguration(2);
|
||||
+ await device.claimInterface(0);
|
||||
+ await device.selectAlternateInterface(0, 1);
|
||||
+ const buffer = new Uint8Array(PACKET_COUNT * PACKET_LENGTH);
|
||||
+ const packetLengths = new Array(PACKET_COUNT).fill(PACKET_LENGTH);
|
||||
+ packetLengths[0] = PACKET_LENGTH - 1;
|
||||
+ await promise_rejects_dom(
|
||||
+ t, 'DataError', device.isochronousTransferOut(1, buffer, packetLengths));
|
||||
+}, 'isochronousTransferOut rejects when buffer size exceeds packet lengths');
|
||||
+
|
||||
+usb_test(async (t) => {
|
||||
+ const PACKET_COUNT = 4;
|
||||
+ const PACKET_LENGTH = 8;
|
||||
+ const {device, fakeDevice} = await getFakeDevice();
|
||||
+ await device.open();
|
||||
+ await device.selectConfiguration(2);
|
||||
+ await device.claimInterface(0);
|
||||
+ await device.selectAlternateInterface(0, 1);
|
||||
+ const buffer = new Uint8Array(PACKET_COUNT * PACKET_LENGTH);
|
||||
+ const packetLengths = new Array(PACKET_COUNT).fill(PACKET_LENGTH);
|
||||
+ packetLengths[0] = PACKET_LENGTH + 1;
|
||||
+ await promise_rejects_dom(
|
||||
+ t, 'DataError', device.isochronousTransferOut(1, buffer, packetLengths));
|
||||
+}, 'isochronousTransferOut rejects when packet lengths exceed buffer size');
|
||||
+
|
||||
+usb_test(async (t) => {
|
||||
+ const PACKET_COUNT = 2;
|
||||
+ const PACKET_LENGTH = 8;
|
||||
+ const {device, fakeDevice} = await getFakeDevice();
|
||||
+ await device.open();
|
||||
+ await device.selectConfiguration(2);
|
||||
+ await device.claimInterface(0);
|
||||
+ await device.selectAlternateInterface(0, 1);
|
||||
+ const packetLengths = [0xffffffff, 1];
|
||||
+ await promise_rejects_dom(
|
||||
+ t, 'DataError', device.isochronousTransferIn(1, packetLengths));
|
||||
+}, 'isochronousTransferIn rejects when packet lengths exceed maximum size');
|
||||
+
|
||||
+usb_test(async (t) => {
|
||||
+ const PACKET_COUNT = 2;
|
||||
+ const PACKET_LENGTH = 8;
|
||||
+ const {device, fakeDevice} = await getFakeDevice();
|
||||
+ await device.open();
|
||||
+ await device.selectConfiguration(2);
|
||||
+ await device.claimInterface(0);
|
||||
+ await device.selectAlternateInterface(0, 1);
|
||||
+ const buffer = new Uint8Array(PACKET_LENGTH * PACKET_COUNT);
|
||||
+ const packetLengths = [0xffffffff, 1];
|
||||
+ await promise_rejects_dom(
|
||||
+ t, 'DataError', device.isochronousTransferOut(1, buffer, packetLengths));
|
||||
+}, 'isochronousTransferOut rejects when packet lengths exceed maximum size');
|
||||
33
patches/chromium/cherry-pick-8d607d3921b8.patch
Normal file
33
patches/chromium/cherry-pick-8d607d3921b8.patch
Normal file
@@ -0,0 +1,33 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gustaf Ullberg <gustaf@chromium.org>
|
||||
Date: Wed, 20 Dec 2023 16:59:29 +0000
|
||||
Subject: WebRtcAudioSink: Stop on invalid configuration
|
||||
|
||||
(cherry picked from commit 340b7e300d380460a039a07b90f62d1febae9da5)
|
||||
|
||||
Bug: 1513170
|
||||
Change-Id: Ia4ca55e9eafb81789b28b8b8c54e615ac28df633
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5136295
|
||||
Reviewed-by: Harald Alvestrand <hta@chromium.org>
|
||||
Commit-Queue: Gustaf Ullberg <gustaf@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1239233}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5136708
|
||||
Owners-Override: Krishna Govind <govind@chromium.org>
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Reviewed-by: Krishna Govind <govind@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1566}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
|
||||
index cd9f2edbf6ef456bd9389c697b921b41981e338d..209a2277056aeabca94bbd41ad7d4216798ad578 100644
|
||||
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
|
||||
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
|
||||
@@ -121,7 +121,7 @@ void WebRtcAudioSink::OnData(const media::AudioBus& audio_bus,
|
||||
}
|
||||
|
||||
void WebRtcAudioSink::OnSetFormat(const media::AudioParameters& params) {
|
||||
- DCHECK(params.IsValid());
|
||||
+ CHECK(params.IsValid());
|
||||
SendLogMessage(base::StringPrintf("OnSetFormat([label=%s] {params=[%s]})",
|
||||
adapter_->label().c_str(),
|
||||
params.AsHumanReadableString().c_str()));
|
||||
42
patches/chromium/cherry-pick-9384cddc7705.patch
Normal file
42
patches/chromium/cherry-pick-9384cddc7705.patch
Normal file
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nidhi Jaju <nidhijaju@chromium.org>
|
||||
Date: Wed, 8 Nov 2023 04:19:31 +0000
|
||||
Subject: Make URLSearchParams persistent to avoid UaF
|
||||
|
||||
The URLSearchParams::Create() function returns an on-heap object, but it
|
||||
can be garbage collected, so making it a persistent variable in
|
||||
DidFetchDataLoadedString() mitigates the issue.
|
||||
|
||||
(cherry picked from commit 8b1bd7726a1394e2fe287f6a882822d8ee9d4e96)
|
||||
|
||||
Bug: 1497997
|
||||
Change-Id: I4ae0f93fccc561cd8a088d3fa0bf2968bf298acf
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4996929
|
||||
Reviewed-by: Adam Rice <ricea@chromium.org>
|
||||
Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1218682}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5007484
|
||||
Commit-Queue: Adam Rice <ricea@chromium.org>
|
||||
Auto-Submit: Nidhi Jaju <nidhijaju@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5993@{#1546}
|
||||
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/fetch/body.cc b/third_party/blink/renderer/core/fetch/body.cc
|
||||
index 86aac83becddb7aad0b8172311ccf2cd182bc7e6..4f396c124a1e33772e447e8f8000f31937a57fa6 100644
|
||||
--- a/third_party/blink/renderer/core/fetch/body.cc
|
||||
+++ b/third_party/blink/renderer/core/fetch/body.cc
|
||||
@@ -135,8 +135,13 @@ class BodyFormDataConsumer final : public BodyConsumerBase {
|
||||
|
||||
void DidFetchDataLoadedString(const String& string) override {
|
||||
auto* formData = MakeGarbageCollected<FormData>();
|
||||
- for (const auto& pair : URLSearchParams::Create(string)->Params())
|
||||
+ // URLSearchParams::Create() returns an on-heap object, but it can be
|
||||
+ // garbage collected, so making it a persistent variable on the stack
|
||||
+ // mitigates use-after-free scenarios. See crbug.com/1497997.
|
||||
+ Persistent<URLSearchParams> search_params = URLSearchParams::Create(string);
|
||||
+ for (const auto& pair : search_params->Params()) {
|
||||
formData->append(pair.first, pair.second);
|
||||
+ }
|
||||
DidFetchDataLoadedFormData(formData);
|
||||
}
|
||||
};
|
||||
40
patches/chromium/cherry-pick-b11e7d07a6f4.patch
Normal file
40
patches/chromium/cherry-pick-b11e7d07a6f4.patch
Normal file
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lei Zhang <thestig@chromium.org>
|
||||
Date: Wed, 13 Sep 2023 23:32:40 +0000
|
||||
Subject: M117: Check for object destruction in PdfViewWebPlugin::UpdateFocus()
|
||||
|
||||
PdfViewWebPlugin::UpdateFocus() can potentially triggers its own
|
||||
destruction. Add a check for this and bail out.
|
||||
|
||||
(cherry picked from commit cacf485a202b342526374d444375b80a044add76)
|
||||
|
||||
Bug: 1480184
|
||||
Change-Id: I5e7760ed541a2bffb9dd1ebeb522f10650049033
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4852346
|
||||
Reviewed-by: Tom Sepez <tsepez@chromium.org>
|
||||
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
|
||||
Commit-Queue: Lei Zhang <thestig@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1194210}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4863395
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5938@{#1286}
|
||||
Cr-Branched-From: 2b50cb4bcc2318034581a816714d9535dc38966d-refs/heads/main@{#1181205}
|
||||
|
||||
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
|
||||
index ff6c55728c83cadbce6c7cc9387ccdf8a57d1306..e4bd28814c2b2d8c9fa12a1e48dab979c8f671c8 100644
|
||||
--- a/pdf/pdf_view_web_plugin.cc
|
||||
+++ b/pdf/pdf_view_web_plugin.cc
|
||||
@@ -517,7 +517,13 @@ void PdfViewWebPlugin::UpdateFocus(bool focused,
|
||||
if (has_focus_ != focused) {
|
||||
engine_->UpdateFocus(focused);
|
||||
client_->UpdateTextInputState();
|
||||
+
|
||||
+ // Make sure `this` is still alive after the UpdateSelectionBounds() call.
|
||||
+ auto weak_this = weak_factory_.GetWeakPtr();
|
||||
client_->UpdateSelectionBounds();
|
||||
+ if (!weak_this) {
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
has_focus_ = focused;
|
||||
|
||||
31
patches/chromium/cherry-pick-c1cda70a433a.patch
Normal file
31
patches/chromium/cherry-pick-c1cda70a433a.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Wasserman <msw@chromium.org>
|
||||
Date: Thu, 21 Dec 2023 22:33:05 +0000
|
||||
Subject: Speculative fix for UAF in
|
||||
content::WebContentsImpl::ExitFullscreenMode
|
||||
|
||||
Bug: 1506535, 854815
|
||||
Change-Id: Iace64d63f8cea2dbfbc761ad233db42451ec101c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5146875
|
||||
Commit-Queue: John Abd-El-Malek <jam@chromium.org>
|
||||
Auto-Submit: Mike Wasserman <msw@chromium.org>
|
||||
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1240353}
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 69d07fb1eed22ffab2556107f3520b19a8f066f2..23f68b9f9c108fd74bcba15289c1a2082a53c486 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3672,7 +3672,12 @@ void WebContentsImpl::ExitFullscreenMode(bool will_cause_resize) {
|
||||
static_cast<RenderWidgetHostViewBase*>(view)->ExitFullscreenMode();
|
||||
|
||||
if (delegate_) {
|
||||
+ // This may spin the message loop and destroy this object crbug.com/1506535
|
||||
+ base::WeakPtr<WebContentsImpl> weak_ptr = weak_factory_.GetWeakPtr();
|
||||
delegate_->ExitFullscreenModeForTab(this);
|
||||
+ if (!weak_ptr) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (keyboard_lock_widget_)
|
||||
delegate_->CancelKeyboardLockRequest(this);
|
||||
150
patches/chromium/cherry-pick-cc07a95bc309.patch
Normal file
150
patches/chromium/cherry-pick-cc07a95bc309.patch
Normal file
@@ -0,0 +1,150 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Hongchan Choi <hongchan@chromium.org>
|
||||
Date: Fri, 19 Jan 2024 19:17:18 +0000
|
||||
Subject: Update rendering state of automatic pull nodes before graph rendering
|
||||
|
||||
In rare cases, the rendering fan out count of automatic pull node
|
||||
does not match the main thread fan out count after recreating
|
||||
a platform destination followed by disconnection.
|
||||
|
||||
This CL forces the update of the rendering state of automatic
|
||||
pull nodes before graph rendering to make sure that fan out counts
|
||||
are synchronized before executing the audio processing function call.
|
||||
|
||||
NOTE: This change makes 2 WPTs fail. The follow-up work is planned
|
||||
to address them once this patch is merged.
|
||||
|
||||
(cherry picked from commit f4bffa09b46c21147431179e1e6dd2b27bc35fbc)
|
||||
|
||||
Bug: 1505080
|
||||
Test: Locally confirmed that ASAN doesn't crash on all repro cases.
|
||||
Change-Id: I6768cd8bc64525ea9d56a19b9c58439e9cdab9a8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5131958
|
||||
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
|
||||
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1246718}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5214669
|
||||
Auto-Submit: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1833}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
|
||||
index a3ef095cdeba50edc14b278cfc802a306e2719e8..3c885957ed5ef5f88de7c40c33160461391843fe 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
|
||||
@@ -39,9 +39,14 @@ AnalyserHandler::~AnalyserHandler() {
|
||||
}
|
||||
|
||||
void AnalyserHandler::Process(uint32_t frames_to_process) {
|
||||
- AudioBus* output_bus = Output(0).Bus();
|
||||
+ DCHECK(Context()->IsAudioThread());
|
||||
|
||||
- if (!IsInitialized()) {
|
||||
+ // It's possible that output is not connected. Assign nullptr to indicate
|
||||
+ // such case.
|
||||
+ AudioBus* output_bus = Output(0).RenderingFanOutCount() > 0
|
||||
+ ? Output(0).Bus() : nullptr;
|
||||
+
|
||||
+ if (!IsInitialized() && output_bus) {
|
||||
output_bus->Zero();
|
||||
return;
|
||||
}
|
||||
@@ -53,6 +58,11 @@ void AnalyserHandler::Process(uint32_t frames_to_process) {
|
||||
// Analyser reflects the current input.
|
||||
analyser_.WriteInput(input_bus.get(), frames_to_process);
|
||||
|
||||
+ // Subsequent steps require `output_bus` to be valid.
|
||||
+ if (!output_bus) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!Input(0).IsConnected()) {
|
||||
// No inputs, so clear the output, and propagate the silence hint.
|
||||
output_bus->Zero();
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
|
||||
index 0bf86b7d659533e0acd9cd0c902c6dd68b51e1e6..903e8172d7c381da2e2cb8e9962ea601c76b375a 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
|
||||
@@ -119,12 +119,14 @@ void AudioWorkletHandler::Process(uint32_t frames_to_process) {
|
||||
return;
|
||||
}
|
||||
|
||||
- // If the input is not connected, inform the processor with nullptr.
|
||||
+ // If the input or the output is not connected, inform the processor with
|
||||
+ // nullptr.
|
||||
for (unsigned i = 0; i < NumberOfInputs(); ++i) {
|
||||
inputs_[i] = Input(i).IsConnected() ? Input(i).Bus() : nullptr;
|
||||
}
|
||||
for (unsigned i = 0; i < NumberOfOutputs(); ++i) {
|
||||
- outputs_[i] = WrapRefCounted(Output(i).Bus());
|
||||
+ outputs_[i] = Output(i).RenderingFanOutCount() > 0
|
||||
+ ? WrapRefCounted(Output(i).Bus()) : nullptr;
|
||||
}
|
||||
|
||||
for (const auto& param_name : param_value_map_.Keys()) {
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
|
||||
index 181dfa92723843d5ce9ae3e7399215870ac1dc80..c3c53d7a7099d67a6bb76df55a6c71965ca3bf02 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
|
||||
@@ -376,6 +376,12 @@ void AudioWorkletProcessor::CopyArrayBuffersToPort(
|
||||
|
||||
for (uint32_t bus_index = 0; bus_index < audio_port.size(); ++bus_index) {
|
||||
const scoped_refptr<AudioBus>& audio_bus = audio_port[bus_index];
|
||||
+
|
||||
+ // nullptr indicates the output bus is not connected. Do not proceed.
|
||||
+ if (!audio_bus) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
for (uint32_t channel_index = 0;
|
||||
channel_index < audio_bus->NumberOfChannels(); ++channel_index) {
|
||||
auto backing_store = array_buffers[bus_index][channel_index]
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
|
||||
index fa1de8f37b9be681f7ac447bc3e3859e8909216d..4730383dafa957c2e84c009387d15d6fe479e5ba 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
|
||||
@@ -172,6 +172,16 @@ void DeferredTaskHandler::UpdateAutomaticPullNodes() {
|
||||
base::AutoTryLock try_locker(automatic_pull_handlers_lock_);
|
||||
if (try_locker.is_acquired()) {
|
||||
rendering_automatic_pull_handlers_.assign(automatic_pull_handlers_);
|
||||
+
|
||||
+ // In rare cases, it is possible for automatic pull nodes' output bus
|
||||
+ // to become stale. Make sure update their rendering output counts.
|
||||
+ // crbug.com/1505080.
|
||||
+ for (auto& handler : rendering_automatic_pull_handlers_) {
|
||||
+ for (unsigned i = 0; i < handler->NumberOfOutputs(); ++i) {
|
||||
+ handler->Output(i).UpdateRenderingState();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
automatic_pull_handlers_need_updating_ = false;
|
||||
}
|
||||
}
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
|
||||
index 33627204a6f538eba77bd8346952404814e4affa..ce0cfa40b691d859d372c9e6da7ff54fe64bbbe1 100644
|
||||
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
|
||||
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
|
||||
@@ -43,7 +43,10 @@
|
||||
if (actual.done)
|
||||
task.done();
|
||||
};
|
||||
- sourceNode.connect(workletNode);
|
||||
+ // To have valid ArrayBuffers for both input and output, we need
|
||||
+ // both connections.
|
||||
+ // See: https://github.com/WebAudio/web-audio-api/issues/2566
|
||||
+ sourceNode.connect(workletNode).connect(context.destination);
|
||||
sourceNode.start();
|
||||
});
|
||||
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fbac76d9b865bfdec552bf280e4a19ae1743ef4a
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt
|
||||
@@ -0,0 +1,6 @@
|
||||
+This is a testharness.js-based test.
|
||||
+[PASS] 3 inputs; 0 outputs
|
||||
+[FAIL] 0 inputs; 3 outputs
|
||||
+ assert_equals: outputs[0].length expected 1 but got 0
|
||||
+Harness: the test ran to completion.
|
||||
+
|
||||
201
patches/chromium/cherry-pick-d756d71a652c.patch
Normal file
201
patches/chromium/cherry-pick-d756d71a652c.patch
Normal file
@@ -0,0 +1,201 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Alex Moshchuk <alexmos@chromium.org>
|
||||
Date: Mon, 9 Oct 2023 17:14:13 +0000
|
||||
Subject: Fix RFHI::pending_navigate_ cleanup after crashes and early RFH
|
||||
swaps.
|
||||
|
||||
When resuming a navigation that had been saved into
|
||||
RenderFrameHostImpl::pending_navigate_, we need to account for the
|
||||
fact that OnBeginNavigation() calls GetFrameHostForNavigation() which
|
||||
may perform an early RenderFrameHost swap and synchronously destroy
|
||||
the old RFH.
|
||||
|
||||
There's also no need to keep a pending_navigate_ around after the
|
||||
corresponding renderer process crashes, so this CL also adds logic to
|
||||
clear it. Resuming such a navigation would require additional work,
|
||||
since the NavigationClient stashed in pending_navigate_ is no longer
|
||||
usable and would just immediately call the disconnect handler and
|
||||
cancel the navigation. But there isn't really any benefit to adding
|
||||
that complexity, and we already cancel the RFH's other ongoing
|
||||
navigations when its renderer process dies.
|
||||
|
||||
This CL also tweaks the logic in RenderWidgetHostImpl to allow the
|
||||
resuming logic (ResumeLoadingCreatedWebContents) to work without
|
||||
hitting DCHECKs, if it's called after a renderer process crash. This
|
||||
case never worked cleanly before, but is supported now (and allows the
|
||||
new test to work without crashing).
|
||||
|
||||
(cherry picked from commit 093daae65d50511c2027d01f9188681749b5a1be)
|
||||
|
||||
Bug: 1487110
|
||||
Change-Id: Icd6a55002e52729e6ee966210efba1a5ce23eb55
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4908270
|
||||
Commit-Queue: Alex Moshchuk <alexmos@chromium.org>
|
||||
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1205927}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4923011
|
||||
Owners-Override: Krishna Govind <govind@chromium.org>
|
||||
Reviewed-by: Krishna Govind <govind@chromium.org>
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5993@{#1208}
|
||||
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 2c5a63a85ba37573182ab9b8731f70948c2cc0e6..505ae0be1155585a19deb29e0c6734e9878f46c2 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -3119,6 +3119,13 @@ void RenderFrameHostImpl::RenderProcessGone(
|
||||
ResetOwnedNavigationRequests(NavigationDiscardReason::kRenderProcessGone);
|
||||
ResetLoadingState();
|
||||
|
||||
+ // Also, clear any pending navigations that have been blocked while the
|
||||
+ // embedder is processing window.open() requests. This is consistent
|
||||
+ // with clearing NavigationRequests and loading state above, and it also
|
||||
+ // makes sense because certain parts of `pending_navigate_`, like the
|
||||
+ // NavigationClient remote interface, can no longer be used.
|
||||
+ pending_navigate_.reset();
|
||||
+
|
||||
// Any future UpdateState or UpdateTitle messages from this or a recreated
|
||||
// process should be ignored until the next commit.
|
||||
set_nav_entry_id(0);
|
||||
@@ -3528,14 +3535,25 @@ void RenderFrameHostImpl::Init() {
|
||||
// BeginNavigation() should only be triggered when the navigation is
|
||||
// initiated by a document in the same process.
|
||||
const int initiator_process_id = GetProcess()->GetID();
|
||||
+
|
||||
+ // Transfer `pending_navigate_` to a local variable, to avoid resetting it
|
||||
+ // after OnBeginNavigation since `this` might already be destroyed (see
|
||||
+ // below).
|
||||
+ //
|
||||
+ // This shouldn't matter for early RFH swaps out of crashed frames, since
|
||||
+ // `pending_navigate_` is cleared when the renderer process dies, but it
|
||||
+ // may matter for other current/future use cases of the early RFH swap.
|
||||
+ std::unique_ptr<PendingNavigation> pending_navigation =
|
||||
+ std::move(pending_navigate_);
|
||||
frame_tree_node()->navigator().OnBeginNavigation(
|
||||
- frame_tree_node(), std::move(pending_navigate_->common_params),
|
||||
- std::move(pending_navigate_->begin_navigation_params),
|
||||
- std::move(pending_navigate_->blob_url_loader_factory),
|
||||
- std::move(pending_navigate_->navigation_client),
|
||||
+ frame_tree_node(), std::move(pending_navigation->common_params),
|
||||
+ std::move(pending_navigation->begin_navigation_params),
|
||||
+ std::move(pending_navigation->blob_url_loader_factory),
|
||||
+ std::move(pending_navigation->navigation_client),
|
||||
EnsurePrefetchedSignedExchangeCache(), initiator_process_id,
|
||||
- std::move(pending_navigate_->renderer_cancellation_listener));
|
||||
- pending_navigate_.reset();
|
||||
+ std::move(pending_navigation->renderer_cancellation_listener));
|
||||
+ // DO NOT ADD CODE after this, as `this` might be deleted if an early
|
||||
+ // RenderFrameHost swap was performed when starting the navigation above.
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
|
||||
index 7107c17a8f36688d245b4cad5ee92dfcedd2485e..94a726acd9a65fdddd0eed81f064d5f17d536aa3 100644
|
||||
--- a/content/browser/renderer_host/render_widget_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
|
||||
@@ -757,9 +757,15 @@ void RenderWidgetHostImpl::RendererWidgetCreated(bool for_frame_widget) {
|
||||
}
|
||||
|
||||
void RenderWidgetHostImpl::Init() {
|
||||
- DCHECK(renderer_widget_created_);
|
||||
- DCHECK(waiting_for_init_);
|
||||
+ // Note that this may be called after a renderer crash. In this case, we can
|
||||
+ // just exit early, as there is nothing else to do. Note that
|
||||
+ // `waiting_for_init_` should've already been reset to false in that case.
|
||||
+ if (!renderer_widget_created_) {
|
||||
+ DCHECK(!waiting_for_init_);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
+ DCHECK(waiting_for_init_);
|
||||
waiting_for_init_ = false;
|
||||
|
||||
// These two methods avoid running while we are `waiting_for_init_`, so we
|
||||
@@ -2277,6 +2283,10 @@ void RenderWidgetHostImpl::RendererExited() {
|
||||
|
||||
blink_widget_.reset();
|
||||
|
||||
+ // No need to perform a deferred show after the renderer crashes, and this
|
||||
+ // wouldn't work anyway as it requires a valid `blink_widget_`.
|
||||
+ pending_show_params_.reset();
|
||||
+
|
||||
// After the renderer crashes, the view is destroyed and so the
|
||||
// RenderWidgetHost cannot track its visibility anymore. We assume such
|
||||
// RenderWidgetHost to be invisible for the sake of internal accounting - be
|
||||
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
|
||||
index c3aebce8b6aeefd85b6e87d50272cf3a798923bb..9a06710dd0998f852f0440c2652d88fc612b4560 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
|
||||
@@ -81,6 +81,7 @@
|
||||
#include "content/public/test/fenced_frame_test_util.h"
|
||||
#include "content/public/test/mock_client_hints_controller_delegate.h"
|
||||
#include "content/public/test/mock_web_contents_observer.h"
|
||||
+#include "content/public/test/navigation_handle_observer.h"
|
||||
#include "content/public/test/no_renderer_crashes_assertion.h"
|
||||
#include "content/public/test/prerender_test_util.h"
|
||||
#include "content/public/test/resource_load_observer.h"
|
||||
@@ -5573,6 +5574,63 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
|
||||
EXPECT_FALSE(shell()->web_contents()->IsCrashed());
|
||||
}
|
||||
|
||||
+// Check that there's no crash if a new window is set to defer navigations (for
|
||||
+// example, this is done on Android Webview and for <webview> guests), then the
|
||||
+// renderer process crashes while there's a deferred new window navigation in
|
||||
+// place, and then navigations are resumed. Prior to fixing
|
||||
+// https://crbug.com/1487110, the deferred navigation was allowed to proceed,
|
||||
+// performing an early RenderFrameHost swap and hitting a bug while clearing
|
||||
+// the deferred navigation state. Now, the deferred navigation should be
|
||||
+// canceled when the renderer process dies.
|
||||
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
|
||||
+ DeferredWindowOpenNavigationIsResumedWithEarlySwap) {
|
||||
+ // Force WebContents in a new Shell to defer new navigations until the
|
||||
+ // delegate is set.
|
||||
+ shell()->set_delay_popup_contents_delegate_for_testing(true);
|
||||
+
|
||||
+ // Load an initial page.
|
||||
+ ASSERT_TRUE(embedded_test_server()->Start());
|
||||
+ GURL url(embedded_test_server()->GetURL("/title1.html"));
|
||||
+ EXPECT_TRUE(NavigateToURL(shell(), url));
|
||||
+
|
||||
+ // Open a popup to a same-site URL via window.open.
|
||||
+ ShellAddedObserver new_shell_observer;
|
||||
+ EXPECT_TRUE(ExecJs(shell(), JsReplace("window.open($1);", url)));
|
||||
+ Shell* new_shell = new_shell_observer.GetShell();
|
||||
+ WebContents* new_contents = new_shell->web_contents();
|
||||
+
|
||||
+ // The navigation in the new popup should be deferred.
|
||||
+ EXPECT_TRUE(WaitForLoadStop(new_contents));
|
||||
+ EXPECT_TRUE(new_contents->GetController().IsInitialBlankNavigation());
|
||||
+ EXPECT_TRUE(new_contents->GetLastCommittedURL().is_empty());
|
||||
+
|
||||
+ // Set the new shell's delegate now. This doesn't resume the navigation just
|
||||
+ // yet.
|
||||
+ EXPECT_FALSE(new_contents->GetDelegate());
|
||||
+ new_contents->SetDelegate(new_shell);
|
||||
+
|
||||
+ // Crash the renderer process. This should clear the deferred navigation
|
||||
+ // state. If this wasn't done due to a bug, it would also force the resumed
|
||||
+ // navigation to use the early RenderFrameHost swap.
|
||||
+ {
|
||||
+ RenderProcessHost* popup_process =
|
||||
+ new_contents->GetPrimaryMainFrame()->GetProcess();
|
||||
+ RenderProcessHostWatcher crash_observer(
|
||||
+ popup_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
|
||||
+ EXPECT_TRUE(popup_process->Shutdown(0));
|
||||
+ crash_observer.Wait();
|
||||
+ }
|
||||
+
|
||||
+ // Resume the navigation and verify that it gets canceled. Ensure this
|
||||
+ // doesn't crash.
|
||||
+ NavigationHandleObserver handle_observer(new_contents, url);
|
||||
+ new_contents->ResumeLoadingCreatedWebContents();
|
||||
+ EXPECT_TRUE(WaitForLoadStop(new_contents));
|
||||
+ EXPECT_FALSE(handle_observer.has_committed());
|
||||
+ EXPECT_TRUE(new_contents->GetController().IsInitialBlankNavigation());
|
||||
+ EXPECT_TRUE(new_contents->GetLastCommittedURL().is_empty());
|
||||
+}
|
||||
+
|
||||
namespace {
|
||||
|
||||
class MediaWaiter : public WebContentsObserver {
|
||||
116
patches/chromium/cherry-pick-e13061c50998.patch
Normal file
116
patches/chromium/cherry-pick-e13061c50998.patch
Normal file
@@ -0,0 +1,116 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Rockot <rockot@google.com>
|
||||
Date: Thu, 16 Nov 2023 23:44:43 +0000
|
||||
Subject: Reland: Fix IPC Channel pipe teardown
|
||||
|
||||
This is a reland with the new test temporarily disabled on Android
|
||||
until it can run without disrupting other tests.
|
||||
|
||||
(cherry picked from commit cd4c1f165c16c6d8161b5372ef7f61c715e01a42)
|
||||
|
||||
Fixed: 1494461
|
||||
Change-Id: If1d83c2dce62020f78dd50abc460973759002a1a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5015115
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Reviewed-by: Robert Sesek <rsesek@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1221953}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5037764
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Auto-Submit: Ken Rockot <rockot@google.com>
|
||||
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5993@{#1618}
|
||||
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
|
||||
|
||||
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc
|
||||
index 2ab03807d102d8f4e2a22119210d5cb669338c3b..5fa17e2ff108909a8987665dd21bc490118f1147 100644
|
||||
--- a/ipc/ipc_mojo_bootstrap.cc
|
||||
+++ b/ipc/ipc_mojo_bootstrap.cc
|
||||
@@ -787,13 +787,12 @@ class ChannelAssociatedGroupController
|
||||
// handle.
|
||||
DCHECK(!endpoint->client());
|
||||
DCHECK(endpoint->peer_closed());
|
||||
- MarkClosedAndMaybeRemove(endpoint);
|
||||
+ MarkClosed(endpoint);
|
||||
} else {
|
||||
- MarkPeerClosedAndMaybeRemove(endpoint);
|
||||
+ MarkPeerClosed(endpoint);
|
||||
}
|
||||
}
|
||||
-
|
||||
- DCHECK(endpoints_.empty());
|
||||
+ endpoints_.clear();
|
||||
|
||||
GetMemoryDumpProvider().RemoveController(this);
|
||||
}
|
||||
@@ -838,15 +837,19 @@ class ChannelAssociatedGroupController
|
||||
base::AutoLock locker(lock_);
|
||||
encountered_error_ = true;
|
||||
|
||||
+ std::vector<uint32_t> endpoints_to_remove;
|
||||
std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
|
||||
for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
|
||||
Endpoint* endpoint = iter->second.get();
|
||||
++iter;
|
||||
|
||||
- if (endpoint->client())
|
||||
+ if (endpoint->client()) {
|
||||
endpoints_to_notify.push_back(endpoint);
|
||||
+ }
|
||||
|
||||
- MarkPeerClosedAndMaybeRemove(endpoint);
|
||||
+ if (MarkPeerClosed(endpoint)) {
|
||||
+ endpoints_to_remove.push_back(endpoint->id());
|
||||
+ }
|
||||
}
|
||||
|
||||
for (auto& endpoint : endpoints_to_notify) {
|
||||
@@ -855,6 +858,10 @@ class ChannelAssociatedGroupController
|
||||
if (endpoint->client())
|
||||
NotifyEndpointOfError(endpoint.get(), false /* force_async */);
|
||||
}
|
||||
+
|
||||
+ for (uint32_t id : endpoints_to_remove) {
|
||||
+ endpoints_.erase(id);
|
||||
+ }
|
||||
}
|
||||
|
||||
void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
|
||||
@@ -893,19 +900,33 @@ class ChannelAssociatedGroupController
|
||||
NotifyEndpointOfError(endpoint, false /* force_async */);
|
||||
}
|
||||
|
||||
- void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
|
||||
+ // Marks `endpoint` as closed and returns true if and only if its peer was
|
||||
+ // also already closed.
|
||||
+ bool MarkClosed(Endpoint* endpoint) {
|
||||
lock_.AssertAcquired();
|
||||
endpoint->set_closed();
|
||||
- if (endpoint->closed() && endpoint->peer_closed())
|
||||
- endpoints_.erase(endpoint->id());
|
||||
+ return endpoint->peer_closed();
|
||||
}
|
||||
|
||||
- void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
|
||||
+ // Marks `endpoint` as having a closed peer and returns true if and only if
|
||||
+ // `endpoint` itself was also already closed.
|
||||
+ bool MarkPeerClosed(Endpoint* endpoint) {
|
||||
lock_.AssertAcquired();
|
||||
endpoint->set_peer_closed();
|
||||
endpoint->SignalSyncMessageEvent();
|
||||
- if (endpoint->closed() && endpoint->peer_closed())
|
||||
+ return endpoint->closed();
|
||||
+ }
|
||||
+
|
||||
+ void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
|
||||
+ if (MarkClosed(endpoint)) {
|
||||
endpoints_.erase(endpoint->id());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
|
||||
+ if (MarkPeerClosed(endpoint)) {
|
||||
+ endpoints_.erase(endpoint->id());
|
||||
+ }
|
||||
}
|
||||
|
||||
Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
|
||||
72
patches/chromium/cherry-pick-ee0b8769f428.patch
Normal file
72
patches/chromium/cherry-pick-ee0b8769f428.patch
Normal file
@@ -0,0 +1,72 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Wed, 24 Jan 2024 18:40:01 +0000
|
||||
Subject: Exit early from RTCPeerConnectionHandler
|
||||
|
||||
For certain operations that require a live client
|
||||
(i.e., RTCPeerConnection, which is garbage collected),
|
||||
PeerConnectionHandler keeps a pointer to the client on the stack
|
||||
to prevent garbage collection.
|
||||
|
||||
In some cases, the client may have already been garbage collected
|
||||
(the client is null). In that case, there is no point in doing the
|
||||
operation and it should exit early to avoid UAF/crashes.
|
||||
|
||||
This CL adds early exit to the cases that do not already have it.
|
||||
|
||||
(cherry picked from commit 8755f76bec326c654370de6dd68eea693df74ede)
|
||||
|
||||
Bug: 1514777
|
||||
Change-Id: I27e9541cfaa74d978799c03e2832a0980f9e5710
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5210359
|
||||
Reviewed-by: Tomas Gunnarsson <tommi@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1248826}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5233883
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Auto-Submit: Guido Urdaneta <guidou@chromium.org>
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1867}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
|
||||
index 76fa93800543ff134859c8fc0c0fa63123cf9772..9e5ce0572cfd1d2dd729e5f560b021aba05653f3 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
|
||||
@@ -1057,15 +1057,19 @@ bool RTCPeerConnectionHandler::Initialize(
|
||||
WebLocalFrame* frame,
|
||||
ExceptionState& exception_state) {
|
||||
DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
- DCHECK(frame);
|
||||
DCHECK(dependency_factory_);
|
||||
- frame_ = frame;
|
||||
|
||||
CHECK(!initialize_called_);
|
||||
initialize_called_ = true;
|
||||
|
||||
// Prevent garbage collection of client_ during processing.
|
||||
auto* client_on_stack = client_;
|
||||
+ if (!client_on_stack) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ DCHECK(frame);
|
||||
+ frame_ = frame;
|
||||
peer_connection_tracker_ = PeerConnectionTracker::From(*frame);
|
||||
|
||||
configuration_ = server_configuration;
|
||||
@@ -2312,10 +2316,13 @@ void RTCPeerConnectionHandler::OnIceCandidate(const String& sdp,
|
||||
int sdp_mline_index,
|
||||
int component,
|
||||
int address_family) {
|
||||
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
// In order to ensure that the RTCPeerConnection is not garbage collected
|
||||
// from under the function, we keep a pointer to it on the stack.
|
||||
auto* client_on_stack = client_;
|
||||
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
+ if (!client_on_stack) {
|
||||
+ return;
|
||||
+ }
|
||||
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateImpl");
|
||||
// This line can cause garbage collection.
|
||||
auto* platform_candidate = MakeGarbageCollected<RTCIceCandidatePlatform>(
|
||||
181
patches/chromium/cherry-pick-f15cfb9371c4.patch
Normal file
181
patches/chromium/cherry-pick-f15cfb9371c4.patch
Normal file
@@ -0,0 +1,181 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kai Ninomiya <kainino@chromium.org>
|
||||
Date: Thu, 7 Dec 2023 14:31:32 +0000
|
||||
Subject: Fix reinit order in
|
||||
ContextProviderCommandBuffer::BindToCurrentSequence
|
||||
|
||||
See comments for explanation.
|
||||
|
||||
(cherry picked from commit 7d8400ceb56db5fd97249f787251fe8b3928e6fd)
|
||||
|
||||
Bug: 1505632
|
||||
Change-Id: I0f43821a9708af91303048332e9fae5e100deee5
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5069480
|
||||
Reviewed-by: Saifuddin Hitawala <hitawala@chromium.org>
|
||||
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
|
||||
Reviewed-by: Brendon Tiszka <tiszka@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1230735}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5095795
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Commit-Queue: Saifuddin Hitawala <hitawala@chromium.org>
|
||||
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#1424}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
|
||||
index 5f0966ef839fae01ddadff64b9bde819dbfc7141..2bd94a0c94cd1aafe6ad21a8a7f2cb1f3afd8110 100644
|
||||
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
|
||||
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
|
||||
@@ -172,13 +172,13 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
}
|
||||
|
||||
// The transfer buffer is used to serialize Dawn commands
|
||||
- transfer_buffer_ =
|
||||
+ auto transfer_buffer =
|
||||
std::make_unique<gpu::TransferBuffer>(webgpu_helper.get());
|
||||
|
||||
// The WebGPUImplementation exposes the WebGPUInterface, as well as the
|
||||
// gpu::ContextSupport interface.
|
||||
auto webgpu_impl = std::make_unique<gpu::webgpu::WebGPUImplementation>(
|
||||
- webgpu_helper.get(), transfer_buffer_.get(), command_buffer_.get());
|
||||
+ webgpu_helper.get(), transfer_buffer.get(), command_buffer_.get());
|
||||
bind_result_ = webgpu_impl->Initialize(memory_limits_);
|
||||
if (bind_result_ != gpu::ContextResult::kSuccess) {
|
||||
DLOG(ERROR) << "Failed to initialize WebGPUImplementation.";
|
||||
@@ -190,8 +190,11 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
std::string unique_context_name =
|
||||
base::StringPrintf("%s-%p", type_name.c_str(), webgpu_impl.get());
|
||||
|
||||
+ // IMPORTANT: These hold raw_ptrs to each other, so must be set together.
|
||||
+ // See note in the header (and keep it up to date if things change).
|
||||
impl_ = webgpu_impl.get();
|
||||
webgpu_interface_ = std::move(webgpu_impl);
|
||||
+ transfer_buffer_ = std::move(transfer_buffer);
|
||||
helper_ = std::move(webgpu_helper);
|
||||
} else if (attributes_.enable_raster_interface &&
|
||||
!attributes_.enable_gles2_interface &&
|
||||
@@ -209,14 +212,14 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
}
|
||||
// The transfer buffer is used to copy resources between the client
|
||||
// process and the GPU process.
|
||||
- transfer_buffer_ =
|
||||
+ auto transfer_buffer =
|
||||
std::make_unique<gpu::TransferBuffer>(raster_helper.get());
|
||||
|
||||
// The RasterImplementation exposes the RasterInterface, as well as the
|
||||
// gpu::ContextSupport interface.
|
||||
DCHECK(channel_);
|
||||
auto raster_impl = std::make_unique<gpu::raster::RasterImplementation>(
|
||||
- raster_helper.get(), transfer_buffer_.get(),
|
||||
+ raster_helper.get(), transfer_buffer.get(),
|
||||
attributes_.bind_generates_resource,
|
||||
attributes_.lose_context_when_out_of_memory, command_buffer_.get(),
|
||||
channel_->image_decode_accelerator_proxy());
|
||||
@@ -233,8 +236,11 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
raster_impl->TraceBeginCHROMIUM("gpu_toplevel",
|
||||
unique_context_name.c_str());
|
||||
|
||||
+ // IMPORTANT: These hold raw_ptrs to each other, so must be set together.
|
||||
+ // See note in the header (and keep it up to date if things change).
|
||||
impl_ = raster_impl.get();
|
||||
raster_interface_ = std::move(raster_impl);
|
||||
+ transfer_buffer_ = std::move(transfer_buffer);
|
||||
helper_ = std::move(raster_helper);
|
||||
} else {
|
||||
// The GLES2 helper writes the command buffer protocol.
|
||||
@@ -249,7 +255,7 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
|
||||
// The transfer buffer is used to copy resources between the client
|
||||
// process and the GPU process.
|
||||
- transfer_buffer_ =
|
||||
+ auto transfer_buffer =
|
||||
std::make_unique<gpu::TransferBuffer>(gles2_helper.get());
|
||||
|
||||
// The GLES2Implementation exposes the OpenGLES2 API, as well as the
|
||||
@@ -262,13 +268,13 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
// we only use it if grcontext_support was requested.
|
||||
gles2_impl = std::make_unique<
|
||||
skia_bindings::GLES2ImplementationWithGrContextSupport>(
|
||||
- gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer_.get(),
|
||||
+ gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer.get(),
|
||||
attributes_.bind_generates_resource,
|
||||
attributes_.lose_context_when_out_of_memory,
|
||||
support_client_side_arrays, command_buffer_.get());
|
||||
} else {
|
||||
gles2_impl = std::make_unique<gpu::gles2::GLES2Implementation>(
|
||||
- gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer_.get(),
|
||||
+ gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer.get(),
|
||||
attributes_.bind_generates_resource,
|
||||
attributes_.lose_context_when_out_of_memory,
|
||||
support_client_side_arrays, command_buffer_.get());
|
||||
@@ -279,8 +285,11 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
return bind_result_;
|
||||
}
|
||||
|
||||
+ // IMPORTANT: These hold raw_ptrs to each other, so must be set together.
|
||||
+ // See note in the header (and keep it up to date if things change).
|
||||
impl_ = gles2_impl.get();
|
||||
gles2_impl_ = std::move(gles2_impl);
|
||||
+ transfer_buffer_ = std::move(transfer_buffer);
|
||||
helper_ = std::move(gles2_helper);
|
||||
}
|
||||
|
||||
@@ -314,6 +323,7 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
|
||||
switches::kEnableGpuClientTracing)) {
|
||||
// This wraps the real GLES2Implementation and we should always use this
|
||||
// instead when it's present.
|
||||
+ // IMPORTANT: This holds a raw_ptr to gles2_impl_.
|
||||
trace_impl_ = std::make_unique<gpu::gles2::GLES2TraceImplementation>(
|
||||
gles2_impl_.get());
|
||||
gl = trace_impl_.get();
|
||||
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.h b/services/viz/public/cpp/gpu/context_provider_command_buffer.h
|
||||
index 93fd2dbd47fc8aca19ac8baffe62911cdc9efb6c..78aaa2b759e350a7a8ed58273cf910ab91c235ea 100644
|
||||
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.h
|
||||
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.h
|
||||
@@ -159,19 +159,42 @@ class ContextProviderCommandBuffer
|
||||
// associated shared images are destroyed.
|
||||
std::unique_ptr<gpu::ClientSharedImageInterface> shared_image_interface_;
|
||||
|
||||
- base::Lock context_lock_; // Referenced by command_buffer_.
|
||||
+ //////////////////////////////////////////////////////////////////////////////
|
||||
+ // IMPORTANT NOTE: All of the objects in this block are part of a complex //
|
||||
+ // graph of raw pointers (holder or pointee of various raw_ptrs). They are //
|
||||
+ // defined in topological order: only later items point to earlier items. //
|
||||
+ // - When writing any member, always ensure its pointers to earlier members
|
||||
+ // are guaranteed to stay alive.
|
||||
+ // - When clearing OR overwriting any member, always ensure objects that
|
||||
+ // point to it have already been cleared.
|
||||
+ // - The topological order of definitions guarantees that the
|
||||
+ // destructors will be called in the correct order (bottom to top).
|
||||
+ // - When overwriting multiple members, similarly do so in reverse order.
|
||||
+ //
|
||||
+ // Please note these comments are likely not to stay perfectly up-to-date.
|
||||
+
|
||||
+ base::Lock context_lock_;
|
||||
+ // Points to the context_lock_ field of `this`.
|
||||
std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_;
|
||||
+
|
||||
+ // Points to command_buffer_.
|
||||
std::unique_ptr<gpu::CommandBufferHelper> helper_;
|
||||
+ // Points to helper_.
|
||||
std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
|
||||
|
||||
+ // Points to transfer_buffer_, helper_, and command_buffer_.
|
||||
std::unique_ptr<gpu::gles2::GLES2Implementation> gles2_impl_;
|
||||
+ // Points to gles2_impl_.
|
||||
std::unique_ptr<gpu::gles2::GLES2TraceImplementation> trace_impl_;
|
||||
+ // Points to transfer_buffer_, helper_, and command_buffer_.
|
||||
std::unique_ptr<gpu::raster::RasterInterface> raster_interface_;
|
||||
+ // Points to transfer_buffer_, helper_, and command_buffer_.
|
||||
std::unique_ptr<gpu::webgpu::WebGPUInterface> webgpu_interface_;
|
||||
+ // This is an alias for gles2_impl_, raster_interface_, or webgpu_interface_.
|
||||
+ raw_ptr<gpu::ImplementationBase> impl_ = nullptr;
|
||||
|
||||
- // Owned by one of gles2_impl_, raster_interface_, or webgpu_interface_. It
|
||||
- // must be declared last and cleared first.
|
||||
- raw_ptr<gpu::ImplementationBase> impl_;
|
||||
+ // END IMPORTANT NOTE //
|
||||
+ //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;
|
||||
|
||||
56
patches/chromium/cherry-pick-f218b4f37018.patch
Normal file
56
patches/chromium/cherry-pick-f218b4f37018.patch
Normal file
@@ -0,0 +1,56 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Pawlicki <waffles@chromium.org>
|
||||
Date: Fri, 29 Sep 2023 22:25:20 +0000
|
||||
Subject: update_client: Check string length before calling front().
|
||||
|
||||
(cherry picked from commit 6581c6b7c4b7b627b32b09cdbe9e84d2dd9ec018)
|
||||
|
||||
Fixed: 1486316
|
||||
Change-Id: I7be04ea0c8e040b5a67364925fc06d4ee9167242
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4892838
|
||||
Commit-Queue: Joshua Pawlicki <waffles@chromium.org>
|
||||
Auto-Submit: Joshua Pawlicki <waffles@chromium.org>
|
||||
Reviewed-by: Sorin Jianu <sorin@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1201617}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4902697
|
||||
Cr-Commit-Position: refs/branch-heads/5993@{#978}
|
||||
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
|
||||
|
||||
diff --git a/components/update_client/protocol_parser_json.cc b/components/update_client/protocol_parser_json.cc
|
||||
index 9858ba06290675ae39d2606fbe4aea34f2efe655..ba1aeba747d990bc97977bebb60f1141e3981517 100644
|
||||
--- a/components/update_client/protocol_parser_json.cc
|
||||
+++ b/components/update_client/protocol_parser_json.cc
|
||||
@@ -196,7 +196,7 @@ bool ParseUpdateCheck(const base::Value& updatecheck_node_val,
|
||||
const base::Value::Dict& updatecheck_node = updatecheck_node_val.GetDict();
|
||||
|
||||
for (auto kv : updatecheck_node) {
|
||||
- if (kv.first.front() == '_' && kv.second.is_string()) {
|
||||
+ if (!kv.first.empty() && kv.first.front() == '_' && kv.second.is_string()) {
|
||||
result->custom_attributes[kv.first] = kv.second.GetString();
|
||||
}
|
||||
}
|
||||
diff --git a/components/update_client/protocol_parser_json_unittest.cc b/components/update_client/protocol_parser_json_unittest.cc
|
||||
index 606c6ddc8f906e4bcd0722828ab34f5c77e73e5d..c59bf8ab7b1f7751c2e78396712f0de283c3b00d 100644
|
||||
--- a/components/update_client/protocol_parser_json_unittest.cc
|
||||
+++ b/components/update_client/protocol_parser_json_unittest.cc
|
||||
@@ -393,6 +393,10 @@ const char* kJSONCustomAttributes = R"()]}'
|
||||
]
|
||||
}})";
|
||||
|
||||
+const char* kBadJSONBadAppIdNoNewlinesBadUCKey =
|
||||
+ R"()]}'{"response":{"app":[{"appid":";","updatecheck":{"":1}}],)"
|
||||
+ R"("protocol":"3.1"}})";
|
||||
+
|
||||
TEST(UpdateClientProtocolParserJSONTest, Parse) {
|
||||
const auto parser = std::make_unique<ProtocolParserJSON>();
|
||||
|
||||
@@ -610,4 +614,9 @@ TEST(UpdateClientProtocolParserJSONTest, ParseAttrs) {
|
||||
}
|
||||
}
|
||||
|
||||
+TEST(UpdateClientProtocolParserJSONTest, ParseBadJSONNoCrash) {
|
||||
+ const auto parser = std::make_unique<ProtocolParserJSON>();
|
||||
+ EXPECT_TRUE(parser->Parse(kBadJSONBadAppIdNoNewlinesBadUCKey));
|
||||
+}
|
||||
+
|
||||
} // namespace update_client
|
||||
@@ -218,10 +218,10 @@ index 4e32d708ecf4afd3913d86ec1602ef2dc9a60998..1dd2f50fba1387b5eeb554dd540957d7
|
||||
void AddNewContents(content::WebContents* source,
|
||||
std::unique_ptr<content::WebContents> new_contents,
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 865414f0994a4e29f297532538486f780edd51d3..3a60a59497571a33bba8efa7654a32403ab99978 100644
|
||||
index d4dd0e24538b2282de207a63aef7486c30525ed9..1d1aac31f051e17d10c2f776c685dd74958cb35f 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -4113,8 +4113,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -4119,8 +4119,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
|
||||
if (delegate_ && delegate_->IsWebContentsCreationOverridden(
|
||||
source_site_instance, params.window_container_type,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Sun, 5 Nov 2023 21:05:04 +0900
|
||||
Subject: Crash GPU process and clear shader cache when skia reports
|
||||
compileError.
|
||||
|
||||
Refs https://chromium-review.googlesource.com/c/chromium/src/+/4988290
|
||||
|
||||
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
|
||||
index c0d19ba3e2ba35d801d33240d9c845eb7cdb4fc1..c37f24925cb59a265e7bbbf03a3f16ca550287d5 100644
|
||||
--- a/gpu/command_buffer/service/shared_context_state.cc
|
||||
+++ b/gpu/command_buffer/service/shared_context_state.cc
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "gpu/command_buffer/service/shared_context_state.h"
|
||||
|
||||
+#include "base/immediate_crash.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/system/sys_info.h"
|
||||
@@ -84,6 +85,12 @@ void SharedContextState::compileError(const char* shader, const char* errors) {
|
||||
<< "------------------------\n"
|
||||
<< shader << "\nErrors:\n"
|
||||
<< errors;
|
||||
+ // Increase shader cache shm count and crash the GPU process so that the
|
||||
+ // browser process would clear the cache.
|
||||
+ GpuProcessActivityFlags::ScopedSetFlag set_flag(
|
||||
+ activity_flags_.get(), ActivityFlagsBase::FLAG_LOADING_PROGRAM_BINARY);
|
||||
+
|
||||
+ base::ImmediateCrash();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +280,7 @@ bool SharedContextState::InitializeGanesh(
|
||||
gl::ProgressReporter* progress_reporter) {
|
||||
progress_reporter_ = progress_reporter;
|
||||
gr_shader_cache_ = cache;
|
||||
+ activity_flags_ = activity_flags;
|
||||
|
||||
size_t max_resource_cache_bytes;
|
||||
size_t glyph_cache_max_texture_bytes;
|
||||
diff --git a/gpu/command_buffer/service/shared_context_state.h b/gpu/command_buffer/service/shared_context_state.h
|
||||
index b493316b8667ca1ff66e07eacc4b42091b7b212b..6ffd0bb55cf2f6e4eb66e4ba2ad19b29a014c21d 100644
|
||||
--- a/gpu/command_buffer/service/shared_context_state.h
|
||||
+++ b/gpu/command_buffer/service/shared_context_state.h
|
||||
@@ -387,6 +387,8 @@ class GPU_GLES2_EXPORT SharedContextState
|
||||
std::vector<uint8_t> scratch_deserialization_buffer_;
|
||||
raw_ptr<gpu::raster::GrShaderCache, DanglingUntriaged> gr_shader_cache_ =
|
||||
nullptr;
|
||||
+ raw_ptr<GpuProcessActivityFlags, DanglingUntriaged> activity_flags_ =
|
||||
+ nullptr;
|
||||
|
||||
// |need_context_state_reset| is set whenever Skia may have altered the
|
||||
// driver's GL state.
|
||||
@@ -8,7 +8,7 @@ Allow registering custom protocols to handle service worker main script fetching
|
||||
Refs https://bugs.chromium.org/p/chromium/issues/detail?id=996511
|
||||
|
||||
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
|
||||
index 698c94642b98b03570fef8f7a5956486eacacbdc..7983abad9a78a115dfd7b9513c6f57be2cd40811 100644
|
||||
index 6fbb7d75b9bf37371a7d40a1849c606bb17f5df8..a69b304809e09d85df62365087f01fbab6376048 100644
|
||||
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
|
||||
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
|
||||
@@ -1839,6 +1839,26 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
|
||||
@@ -36,7 +36,7 @@ index 698c94642b98b03570fef8f7a5956486eacacbdc..7983abad9a78a115dfd7b9513c6f57be
|
||||
+ }
|
||||
+
|
||||
if (auto* config = content::WebUIConfigMap::GetInstance().GetConfig(
|
||||
browser_context(), scope_origin)) {
|
||||
browser_context(), scope)) {
|
||||
// If this is a Service Worker for a WebUI, the WebUI's URLDataSource
|
||||
@@ -1858,9 +1878,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
|
||||
features::kEnableServiceWorkersForChromeScheme) &&
|
||||
|
||||
@@ -35,10 +35,10 @@ index 256f599f8ad93578a7b56697070b1d0630b04897..3c1723ed20ab6a673df7e0ebf0119c21
|
||||
// If we are likely to software composite the resource, we use sRGB because
|
||||
// software compositing is unable to perform color conversion.
|
||||
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
|
||||
index 0d966e045669ee0423d6a486fa8e619938a32de2..1e46ecc1aa8447b3fd0f4e5a66f92ca5ef148887 100644
|
||||
index 7ddbd0ac756c4374d938b422623ea21c7d5c3daf..eb76e4ba51f1ff30b094c941adf776437f7d7b42 100644
|
||||
--- a/cc/trees/layer_tree_settings.h
|
||||
+++ b/cc/trees/layer_tree_settings.h
|
||||
@@ -96,6 +96,8 @@ class CC_EXPORT LayerTreeSettings {
|
||||
@@ -104,6 +104,8 @@ class CC_EXPORT LayerTreeSettings {
|
||||
bool use_rgba_4444 = false;
|
||||
bool unpremultiply_and_dither_low_bit_depth_tiles = false;
|
||||
|
||||
@@ -148,10 +148,10 @@ index 318005b66e04ed03ce6d44931d9360c0e009cb94..0d622fddb95720141ccf8a285ace4714
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
|
||||
index 2a31606b1f5814d57ffe59026cc5735fa7cee597..272ae9f414f8d0873e30479b5bfd237c13a69dd9 100644
|
||||
index e8efcceb7aefbedb6b02bfef9defb52c6dc68f0e..8aa9f586bbe3f33b4ba433b7d177a4217ac877d7 100644
|
||||
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
|
||||
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
|
||||
@@ -25,6 +25,7 @@
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
|
||||
#include "ui/base/ui_base_features.h"
|
||||
#include "ui/base/ui_base_switches.h"
|
||||
@@ -159,7 +159,7 @@ index 2a31606b1f5814d57ffe59026cc5735fa7cee597..272ae9f414f8d0873e30479b5bfd237c
|
||||
#include "ui/native_theme/native_theme_features.h"
|
||||
#include "ui/native_theme/overlay_scrollbar_constants_aura.h"
|
||||
|
||||
@@ -210,6 +211,9 @@ cc::LayerTreeSettings GenerateLayerTreeSettings(
|
||||
@@ -230,6 +231,9 @@ cc::LayerTreeSettings GenerateLayerTreeSettings(
|
||||
settings.main_frame_before_activation_enabled =
|
||||
cmd.HasSwitch(cc::switches::kEnableMainFrameBeforeActivation);
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ index 0ab8187b0db8ae6db46d81738f653a2bc4c566f6..de3d55e85c22317f7f9375eb94d0d5d4
|
||||
|
||||
} // namespace net
|
||||
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
|
||||
index 0ffa0ec042bd59de5d28fad53dee2b6321d64b18..a6570cb144952a1bb7eca124bb4cbb33e249ef15 100644
|
||||
index 2d823eeb8a09d4bca7a800558cd6123df8950576..0c04ff37f77f9ef1ca53339d892db6ea7a4d5aff 100644
|
||||
--- a/services/network/network_context.cc
|
||||
+++ b/services/network/network_context.cc
|
||||
@@ -1491,6 +1491,13 @@ void NetworkContext::SetNetworkConditions(
|
||||
@@ -1502,6 +1502,13 @@ void NetworkContext::SetNetworkConditions(
|
||||
std::move(network_conditions));
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ index 0ffa0ec042bd59de5d28fad53dee2b6321d64b18..a6570cb144952a1bb7eca124bb4cbb33
|
||||
// This may only be called on NetworkContexts created with the constructor
|
||||
// that calls MakeURLRequestContext().
|
||||
diff --git a/services/network/network_context.h b/services/network/network_context.h
|
||||
index f10414f382b48ecc162b22d9638d948e3e719733..47d13dbe9efd501efabe096607e53cb80744cd42 100644
|
||||
index 07c516a63a391fd9eec2d2f6b9868c5da9d8f5c5..65f2c721f3d793126ead04dc812e2372b4399627 100644
|
||||
--- a/services/network/network_context.h
|
||||
+++ b/services/network/network_context.h
|
||||
@@ -316,6 +316,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
|
||||
|
||||
@@ -12,7 +12,7 @@ Ideally we could add an embedder observer pattern here but that can be
|
||||
done in future work.
|
||||
|
||||
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 ce99c90306bf2988fdb9a92e04d2ed8ec318da78..77f90f35ebad0655af1bd063d9a942964db48017 100644
|
||||
index 6ce650e2fc879ae135e5bb731750f8929b592f17..ae95b544e2a1f731766299129f429900fa55b4d1 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
|
||||
@@ -166,6 +166,7 @@
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <sattard@salesforce.com>
|
||||
Date: Mon, 6 Jun 2022 14:25:15 -0700
|
||||
Subject: fix: allow guest webcontents to enter fullscreen
|
||||
|
||||
This can be upstreamed, a guest webcontents can't technically become the focused webContents. This DCHECK should allow all guest webContents to request fullscreen entrance.
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 0582143a5466afb3ba618e848ff23ffa23e5ca70..7a7f74778d0d9118d01a2dc8b916fada56a8dfaa 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3633,7 +3633,7 @@ void WebContentsImpl::EnterFullscreenMode(
|
||||
OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::EnterFullscreenMode");
|
||||
DCHECK(CanEnterFullscreenMode(requesting_frame, options));
|
||||
DCHECK(requesting_frame->IsActive());
|
||||
- DCHECK(ContainsOrIsFocusedWebContents());
|
||||
+ DCHECK(ContainsOrIsFocusedWebContents() || IsGuest());
|
||||
|
||||
// When WebView is the `delegate_` we can end up with VisualProperties changes
|
||||
// synchronously. Notify the view ahead so it can handle the transition.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user