mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
118 Commits
v26.0.0-be
...
v26.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 >>
|
||||
@@ -252,19 +264,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 +364,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
|
||||
@@ -723,8 +735,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 +888,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 +920,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 +943,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 +986,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 +996,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 +1032,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 +1043,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 +1138,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 +1289,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 +1436,8 @@ commands:
|
||||
after-persist:
|
||||
type: steps
|
||||
default: []
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.attach >>
|
||||
@@ -1310,7 +1455,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 +1472,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 +1496,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 +1551,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 +1615,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:
|
||||
@@ -1575,6 +1755,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 +1813,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 +1826,7 @@ jobs:
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: true
|
||||
|
||||
mac-checkout:
|
||||
executor:
|
||||
@@ -1664,6 +1846,7 @@ jobs:
|
||||
restore-src-cache: false
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: false
|
||||
|
||||
mac-make-src-cache:
|
||||
executor:
|
||||
@@ -1683,12 +1866,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 +1885,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 +1901,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 +1924,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 +1964,7 @@ jobs:
|
||||
linux-arm-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-arm
|
||||
@@ -1790,11 +1980,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 +2010,7 @@ jobs:
|
||||
linux-arm64-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-arm64
|
||||
@@ -1835,22 +2026,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 +2099,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- generated_artifacts_mas-x64
|
||||
could-be-aks: false
|
||||
|
||||
osx-testing-x64-gn-check:
|
||||
executor:
|
||||
@@ -1914,7 +2109,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 +2194,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- generated_artifacts_mas-arm64
|
||||
could-be-aks: false
|
||||
|
||||
mas-publish-x64:
|
||||
executor:
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -820,10 +820,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 +1211,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)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -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.
|
||||
@@ -1113,7 +1113,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 +1193,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 +1311,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 +1457,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 +1491,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 +1544,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
|
||||
|
||||
@@ -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')
|
||||
```
|
||||
|
||||
@@ -260,7 +260,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
|
||||
|
||||
@@ -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 | 🚫 |
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -508,6 +508,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",
|
||||
@@ -695,6 +696,8 @@ filenames = {
|
||||
"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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
3
patches/angle/.patches
Normal file
3
patches/angle/.patches
Normal file
@@ -0,0 +1,3 @@
|
||||
cherry-pick-285c7712c506.patch
|
||||
cherry-pick-2bf945775fe6.patch
|
||||
cherry-pick-cafe56b591ed.patch
|
||||
153
patches/angle/cherry-pick-285c7712c506.patch
Normal file
153
patches/angle/cherry-pick-285c7712c506.patch
Normal file
@@ -0,0 +1,153 @@
|
||||
From 285c7712c50654e3d7238b059c4631bc91285514 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 13 Jul 2023 15:23:49 -0400
|
||||
Subject: [PATCH] M116: Translator: Unconditionally limit variable sizes
|
||||
|
||||
... instead of just for WebGL. This is to avoid hitting driver bugs
|
||||
that were prevented with this check for WebGL on a compromised renderer
|
||||
that can create non-WebGL contexts.
|
||||
|
||||
Bug: chromium:1464682
|
||||
Change-Id: I2b1c5a8c51f06225f5f850109d30778d97e574c7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4717371
|
||||
Reviewed-by: Roman Lavrov <romanl@google.com>
|
||||
---
|
||||
|
||||
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
|
||||
index 7b1ac4e..383feeb 100644
|
||||
--- a/src/compiler/translator/Compiler.cpp
|
||||
+++ b/src/compiler/translator/Compiler.cpp
|
||||
@@ -397,9 +397,10 @@
|
||||
|
||||
bool TCompiler::shouldLimitTypeSizes() const
|
||||
{
|
||||
- // WebGL shaders limit the size of variables' types in shaders,
|
||||
- // including arrays, structs and interface blocks.
|
||||
- return IsWebGLBasedSpec(mShaderSpec);
|
||||
+ // Prevent unrealistically large variable sizes in shaders. This works around driver bugs
|
||||
+ // around int-size limits (such as 2GB). The limits are generously large enough that no real
|
||||
+ // shader should ever hit it.
|
||||
+ return true;
|
||||
}
|
||||
|
||||
bool TCompiler::Init(const ShBuiltInResources &resources)
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index 2a033ad..19a4821 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -23,10 +23,10 @@
|
||||
// Arbitrarily enforce that all types declared with a size in bytes of over 2 GB will cause
|
||||
// compilation failure.
|
||||
//
|
||||
-// For local and global variables, the limit is much lower (1MB) as that much memory won't fit in
|
||||
+// For local and global variables, the limit is much lower (16MB) as that much memory won't fit in
|
||||
// the GPU registers anyway.
|
||||
constexpr size_t kMaxVariableSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
|
||||
-constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(1) * 1024 * 1024;
|
||||
+constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(16) * 1024 * 1024;
|
||||
|
||||
// Traverses intermediate tree to ensure that the shader does not
|
||||
// exceed certain implementation-defined limits on the sizes of types.
|
||||
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
|
||||
index a91f8b0..a866b25 100644
|
||||
--- a/src/compiler/translator/util.cpp
|
||||
+++ b/src/compiler/translator/util.cpp
|
||||
@@ -282,6 +282,9 @@
|
||||
|
||||
return kBoolGLType[type.getNominalSize() - 1];
|
||||
|
||||
+ case EbtYuvCscStandardEXT:
|
||||
+ return GL_UNSIGNED_INT;
|
||||
+
|
||||
case EbtSampler2D:
|
||||
return GL_SAMPLER_2D;
|
||||
case EbtSampler3D:
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index 9ae56f5..a8d2ce4 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5284,8 +5284,8 @@
|
||||
|
||||
constexpr char kVSArrayTooLarge[] =
|
||||
R"(varying vec4 color;
|
||||
-// 1 MB / 32 aligned bytes per mat2 = 32768
|
||||
-const int array_size = 32769;
|
||||
+// 16 MB / 32 aligned bytes per mat2 = 524288
|
||||
+const int array_size = 524289;
|
||||
void main()
|
||||
{
|
||||
mat2 array[array_size];
|
||||
@@ -5297,7 +5297,7 @@
|
||||
|
||||
constexpr char kVSArrayMuchTooLarge[] =
|
||||
R"(varying vec4 color;
|
||||
-const int array_size = 55600;
|
||||
+const int array_size = 757000;
|
||||
void main()
|
||||
{
|
||||
mat2 array[array_size];
|
||||
@@ -5361,9 +5361,9 @@
|
||||
constexpr char kTooLargeGlobalMemory1[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32768];
|
||||
-vec4 array2[32769];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524288];
|
||||
+vec4 array2[524289];
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -5376,9 +5376,9 @@
|
||||
constexpr char kTooLargeGlobalMemory2[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32767];
|
||||
-vec4 array2[32767];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524287];
|
||||
+vec4 array2[524287];
|
||||
vec4 x, y, z;
|
||||
|
||||
void main()
|
||||
@@ -5392,12 +5392,12 @@
|
||||
constexpr char kTooLargeGlobalAndLocalMemory1[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32768];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524288];
|
||||
|
||||
void main()
|
||||
{
|
||||
- vec4 array2[32769];
|
||||
+ vec4 array2[524289];
|
||||
if (array[0].x + array[1].x == 2.0)
|
||||
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
else
|
||||
@@ -5408,18 +5408,18 @@
|
||||
constexpr char kTooLargeGlobalAndLocalMemory2[] =
|
||||
R"(precision mediump float;
|
||||
|
||||
-// 1 MB / 16 bytes per vec4 = 65536
|
||||
-vec4 array[32768];
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+vec4 array[524288];
|
||||
|
||||
float f()
|
||||
{
|
||||
- vec4 array2[16384];
|
||||
+ vec4 array2[524288];
|
||||
return array2[0].x;
|
||||
}
|
||||
|
||||
float g()
|
||||
{
|
||||
- vec4 array3[16383];
|
||||
+ vec4 array3[524287];
|
||||
return array3[0].x;
|
||||
}
|
||||
|
||||
197
patches/angle/cherry-pick-2bf945775fe6.patch
Normal file
197
patches/angle/cherry-pick-2bf945775fe6.patch
Normal file
@@ -0,0 +1,197 @@
|
||||
From 2bf945775fe634eb9e420c2263dae6043bbb5ece Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Fri, 14 Jul 2023 12:30:15 -0400
|
||||
Subject: [PATCH] M116: Translator: Limit variable sizes vs uint overflow
|
||||
|
||||
Bug: chromium:1464680
|
||||
Change-Id: Iee41a2da7a7a330e6cc4d6da59a6e9836ee9dd36
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4717372
|
||||
Reviewed-by: Roman Lavrov <romanl@google.com>
|
||||
---
|
||||
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index 19a4821..f0ff9cb 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "compiler/translator/ValidateTypeSizeLimitations.h"
|
||||
|
||||
#include "angle_gl.h"
|
||||
+#include "common/mathutil.h"
|
||||
#include "compiler/translator/Diagnostics.h"
|
||||
#include "compiler/translator/Symbol.h"
|
||||
#include "compiler/translator/SymbolTable.h"
|
||||
@@ -113,7 +114,8 @@
|
||||
|
||||
void validateTotalPrivateVariableSize()
|
||||
{
|
||||
- if (mTotalPrivateVariablesSize > kMaxPrivateVariableSizeInBytes)
|
||||
+ if (mTotalPrivateVariablesSize.ValueOrDefault(std::numeric_limits<size_t>::max()) >
|
||||
+ kMaxPrivateVariableSizeInBytes)
|
||||
{
|
||||
mDiagnostics->error(
|
||||
TSourceLoc{},
|
||||
@@ -231,7 +233,7 @@
|
||||
TDiagnostics *mDiagnostics;
|
||||
std::vector<int> mLoopSymbolIds;
|
||||
|
||||
- size_t mTotalPrivateVariablesSize;
|
||||
+ angle::base::CheckedNumeric<size_t> mTotalPrivateVariablesSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index a8d2ce4..542d49f 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5426,7 +5426,7 @@
|
||||
float h()
|
||||
{
|
||||
vec4 value;
|
||||
- float value2
|
||||
+ float value2;
|
||||
return value.x + value2;
|
||||
}
|
||||
|
||||
@@ -5438,6 +5438,131 @@
|
||||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
})";
|
||||
|
||||
+ constexpr char kTooLargeGlobalMemoryOverflow[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 16 MB / 16 bytes per vec4 = 1048576
|
||||
+// Create 256 arrays so each is small, but the total overflows a 32-bit number
|
||||
+vec4 array[1048576], array2[1048576], array3[1048576], array4[1048576], array5[1048576];
|
||||
+vec4 array6[1048576], array7[1048576], array8[1048576], array9[1048576], array10[1048576];
|
||||
+vec4 array11[1048576], array12[1048576], array13[1048576], array14[1048576], array15[1048576];
|
||||
+vec4 array16[1048576], array17[1048576], array18[1048576], array19[1048576], array20[1048576];
|
||||
+vec4 array21[1048576], array22[1048576], array23[1048576], array24[1048576], array25[1048576];
|
||||
+vec4 array26[1048576], array27[1048576], array28[1048576], array29[1048576], array30[1048576];
|
||||
+vec4 array31[1048576], array32[1048576], array33[1048576], array34[1048576], array35[1048576];
|
||||
+vec4 array36[1048576], array37[1048576], array38[1048576], array39[1048576], array40[1048576];
|
||||
+vec4 array41[1048576], array42[1048576], array43[1048576], array44[1048576], array45[1048576];
|
||||
+vec4 array46[1048576], array47[1048576], array48[1048576], array49[1048576], array50[1048576];
|
||||
+vec4 array51[1048576], array52[1048576], array53[1048576], array54[1048576], array55[1048576];
|
||||
+vec4 array56[1048576], array57[1048576], array58[1048576], array59[1048576], array60[1048576];
|
||||
+vec4 array61[1048576], array62[1048576], array63[1048576], array64[1048576], array65[1048576];
|
||||
+vec4 array66[1048576], array67[1048576], array68[1048576], array69[1048576], array70[1048576];
|
||||
+vec4 array71[1048576], array72[1048576], array73[1048576], array74[1048576], array75[1048576];
|
||||
+vec4 array76[1048576], array77[1048576], array78[1048576], array79[1048576], array80[1048576];
|
||||
+vec4 array81[1048576], array82[1048576], array83[1048576], array84[1048576], array85[1048576];
|
||||
+vec4 array86[1048576], array87[1048576], array88[1048576], array89[1048576], array90[1048576];
|
||||
+vec4 array91[1048576], array92[1048576], array93[1048576], array94[1048576], array95[1048576];
|
||||
+vec4 array96[1048576], array97[1048576], array98[1048576], array99[1048576], array100[1048576];
|
||||
+vec4 array101[1048576], array102[1048576], array103[1048576], array104[1048576], array105[1048576];
|
||||
+vec4 array106[1048576], array107[1048576], array108[1048576], array109[1048576], array110[1048576];
|
||||
+vec4 array111[1048576], array112[1048576], array113[1048576], array114[1048576], array115[1048576];
|
||||
+vec4 array116[1048576], array117[1048576], array118[1048576], array119[1048576], array120[1048576];
|
||||
+vec4 array121[1048576], array122[1048576], array123[1048576], array124[1048576], array125[1048576];
|
||||
+vec4 array126[1048576], array127[1048576], array128[1048576], array129[1048576], array130[1048576];
|
||||
+vec4 array131[1048576], array132[1048576], array133[1048576], array134[1048576], array135[1048576];
|
||||
+vec4 array136[1048576], array137[1048576], array138[1048576], array139[1048576], array140[1048576];
|
||||
+vec4 array141[1048576], array142[1048576], array143[1048576], array144[1048576], array145[1048576];
|
||||
+vec4 array146[1048576], array147[1048576], array148[1048576], array149[1048576], array150[1048576];
|
||||
+vec4 array151[1048576], array152[1048576], array153[1048576], array154[1048576], array155[1048576];
|
||||
+vec4 array156[1048576], array157[1048576], array158[1048576], array159[1048576], array160[1048576];
|
||||
+vec4 array161[1048576], array162[1048576], array163[1048576], array164[1048576], array165[1048576];
|
||||
+vec4 array166[1048576], array167[1048576], array168[1048576], array169[1048576], array170[1048576];
|
||||
+vec4 array171[1048576], array172[1048576], array173[1048576], array174[1048576], array175[1048576];
|
||||
+vec4 array176[1048576], array177[1048576], array178[1048576], array179[1048576], array180[1048576];
|
||||
+vec4 array181[1048576], array182[1048576], array183[1048576], array184[1048576], array185[1048576];
|
||||
+vec4 array186[1048576], array187[1048576], array188[1048576], array189[1048576], array190[1048576];
|
||||
+vec4 array191[1048576], array192[1048576], array193[1048576], array194[1048576], array195[1048576];
|
||||
+vec4 array196[1048576], array197[1048576], array198[1048576], array199[1048576], array200[1048576];
|
||||
+vec4 array201[1048576], array202[1048576], array203[1048576], array204[1048576], array205[1048576];
|
||||
+vec4 array206[1048576], array207[1048576], array208[1048576], array209[1048576], array210[1048576];
|
||||
+vec4 array211[1048576], array212[1048576], array213[1048576], array214[1048576], array215[1048576];
|
||||
+vec4 array216[1048576], array217[1048576], array218[1048576], array219[1048576], array220[1048576];
|
||||
+vec4 array221[1048576], array222[1048576], array223[1048576], array224[1048576], array225[1048576];
|
||||
+vec4 array226[1048576], array227[1048576], array228[1048576], array229[1048576], array230[1048576];
|
||||
+vec4 array231[1048576], array232[1048576], array233[1048576], array234[1048576], array235[1048576];
|
||||
+vec4 array236[1048576], array237[1048576], array238[1048576], array239[1048576], array240[1048576];
|
||||
+vec4 array241[1048576], array242[1048576], array243[1048576], array244[1048576], array245[1048576];
|
||||
+vec4 array246[1048576], array247[1048576], array248[1048576], array249[1048576], array250[1048576];
|
||||
+vec4 array251[1048576], array252[1048576], array253[1048576], array254[1048576], array255[1048576];
|
||||
+vec4 array256[1048576];
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ float f = array[0].x; f += array2[0].x; f += array3[0].x; f += array4[0].x; f += array5[0].x;
|
||||
+ f += array6[0].x; f += array7[0].x; f += array8[0].x; f += array9[0].x; f += array10[0].x;
|
||||
+ f += array11[0].x; f += array12[0].x; f += array13[0].x; f += array14[0].x; f += array15[0].x;
|
||||
+ f += array16[0].x; f += array17[0].x; f += array18[0].x; f += array19[0].x; f += array20[0].x;
|
||||
+ f += array21[0].x; f += array22[0].x; f += array23[0].x; f += array24[0].x; f += array25[0].x;
|
||||
+ f += array26[0].x; f += array27[0].x; f += array28[0].x; f += array29[0].x; f += array30[0].x;
|
||||
+ f += array31[0].x; f += array32[0].x; f += array33[0].x; f += array34[0].x; f += array35[0].x;
|
||||
+ f += array36[0].x; f += array37[0].x; f += array38[0].x; f += array39[0].x; f += array40[0].x;
|
||||
+ f += array41[0].x; f += array42[0].x; f += array43[0].x; f += array44[0].x; f += array45[0].x;
|
||||
+ f += array46[0].x; f += array47[0].x; f += array48[0].x; f += array49[0].x; f += array50[0].x;
|
||||
+ f += array51[0].x; f += array52[0].x; f += array53[0].x; f += array54[0].x; f += array55[0].x;
|
||||
+ f += array56[0].x; f += array57[0].x; f += array58[0].x; f += array59[0].x; f += array60[0].x;
|
||||
+ f += array61[0].x; f += array62[0].x; f += array63[0].x; f += array64[0].x; f += array65[0].x;
|
||||
+ f += array66[0].x; f += array67[0].x; f += array68[0].x; f += array69[0].x; f += array70[0].x;
|
||||
+ f += array71[0].x; f += array72[0].x; f += array73[0].x; f += array74[0].x; f += array75[0].x;
|
||||
+ f += array76[0].x; f += array77[0].x; f += array78[0].x; f += array79[0].x; f += array80[0].x;
|
||||
+ f += array81[0].x; f += array82[0].x; f += array83[0].x; f += array84[0].x; f += array85[0].x;
|
||||
+ f += array86[0].x; f += array87[0].x; f += array88[0].x; f += array89[0].x; f += array90[0].x;
|
||||
+ f += array91[0].x; f += array92[0].x; f += array93[0].x; f += array94[0].x; f += array95[0].x;
|
||||
+ f += array96[0].x; f += array97[0].x; f += array98[0].x; f += array99[0].x; f += array100[0].x;
|
||||
+ f += array101[0].x; f += array102[0].x; f += array103[0].x; f += array104[0].x;
|
||||
+ f += array105[0].x; f += array106[0].x; f += array107[0].x; f += array108[0].x;
|
||||
+ f += array109[0].x; f += array110[0].x; f += array111[0].x; f += array112[0].x;
|
||||
+ f += array113[0].x; f += array114[0].x; f += array115[0].x; f += array116[0].x;
|
||||
+ f += array117[0].x; f += array118[0].x; f += array119[0].x; f += array120[0].x;
|
||||
+ f += array121[0].x; f += array122[0].x; f += array123[0].x; f += array124[0].x;
|
||||
+ f += array125[0].x; f += array126[0].x; f += array127[0].x; f += array128[0].x;
|
||||
+ f += array129[0].x; f += array130[0].x; f += array131[0].x; f += array132[0].x;
|
||||
+ f += array133[0].x; f += array134[0].x; f += array135[0].x; f += array136[0].x;
|
||||
+ f += array137[0].x; f += array138[0].x; f += array139[0].x; f += array140[0].x;
|
||||
+ f += array141[0].x; f += array142[0].x; f += array143[0].x; f += array144[0].x;
|
||||
+ f += array145[0].x; f += array146[0].x; f += array147[0].x; f += array148[0].x;
|
||||
+ f += array149[0].x; f += array150[0].x; f += array151[0].x; f += array152[0].x;
|
||||
+ f += array153[0].x; f += array154[0].x; f += array155[0].x; f += array156[0].x;
|
||||
+ f += array157[0].x; f += array158[0].x; f += array159[0].x; f += array160[0].x;
|
||||
+ f += array161[0].x; f += array162[0].x; f += array163[0].x; f += array164[0].x;
|
||||
+ f += array165[0].x; f += array166[0].x; f += array167[0].x; f += array168[0].x;
|
||||
+ f += array169[0].x; f += array170[0].x; f += array171[0].x; f += array172[0].x;
|
||||
+ f += array173[0].x; f += array174[0].x; f += array175[0].x; f += array176[0].x;
|
||||
+ f += array177[0].x; f += array178[0].x; f += array179[0].x; f += array180[0].x;
|
||||
+ f += array181[0].x; f += array182[0].x; f += array183[0].x; f += array184[0].x;
|
||||
+ f += array185[0].x; f += array186[0].x; f += array187[0].x; f += array188[0].x;
|
||||
+ f += array189[0].x; f += array190[0].x; f += array191[0].x; f += array192[0].x;
|
||||
+ f += array193[0].x; f += array194[0].x; f += array195[0].x; f += array196[0].x;
|
||||
+ f += array197[0].x; f += array198[0].x; f += array199[0].x; f += array200[0].x;
|
||||
+ f += array201[0].x; f += array202[0].x; f += array203[0].x; f += array204[0].x;
|
||||
+ f += array205[0].x; f += array206[0].x; f += array207[0].x; f += array208[0].x;
|
||||
+ f += array209[0].x; f += array210[0].x; f += array211[0].x; f += array212[0].x;
|
||||
+ f += array213[0].x; f += array214[0].x; f += array215[0].x; f += array216[0].x;
|
||||
+ f += array217[0].x; f += array218[0].x; f += array219[0].x; f += array220[0].x;
|
||||
+ f += array221[0].x; f += array222[0].x; f += array223[0].x; f += array224[0].x;
|
||||
+ f += array225[0].x; f += array226[0].x; f += array227[0].x; f += array228[0].x;
|
||||
+ f += array229[0].x; f += array230[0].x; f += array231[0].x; f += array232[0].x;
|
||||
+ f += array233[0].x; f += array234[0].x; f += array235[0].x; f += array236[0].x;
|
||||
+ f += array237[0].x; f += array238[0].x; f += array239[0].x; f += array240[0].x;
|
||||
+ f += array241[0].x; f += array242[0].x; f += array243[0].x; f += array244[0].x;
|
||||
+ f += array245[0].x; f += array246[0].x; f += array247[0].x; f += array248[0].x;
|
||||
+ f += array249[0].x; f += array250[0].x; f += array251[0].x; f += array252[0].x;
|
||||
+ f += array253[0].x; f += array254[0].x; f += array255[0].x; f += array256[0].x;
|
||||
+ if (f == 2.0)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1);
|
||||
EXPECT_EQ(0u, program);
|
||||
|
||||
@@ -5449,6 +5574,9 @@
|
||||
|
||||
program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
|
||||
EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemoryOverflow);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
}
|
||||
|
||||
// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
|
||||
286
patches/angle/cherry-pick-cafe56b591ed.patch
Normal file
286
patches/angle/cherry-pick-cafe56b591ed.patch
Normal file
@@ -0,0 +1,286 @@
|
||||
From cafe56b591edb77f041be70b58cac3a61565644a Mon Sep 17 00:00:00 2001
|
||||
From: Geoff Lang <geofflang@chromium.org>
|
||||
Date: Fri, 23 Jun 2023 14:46:28 -0400
|
||||
Subject: [PATCH] M116: GL: Ensure all instanced attributes have a buffer with data
|
||||
|
||||
Apple OpenGL drivers sometimes crash when given an instanced draw with
|
||||
a buffer that has never been given data.
|
||||
|
||||
It's not efficient to check if the attribute is both zero-sized and
|
||||
instanced so just ensure that every time a zero-sized buffer is bound
|
||||
to an attribute, it gets initialized with some data.
|
||||
|
||||
Bug: chromium:1456243
|
||||
Change-Id: I66b7c7017843153db2df3bc50010cba765d03c5f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4642048
|
||||
Commit-Queue: Geoff Lang <geofflang@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
(cherry picked from commit 4e6124dae892690204f8e5996aeaad14f45e0a97)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4727452
|
||||
---
|
||||
|
||||
diff --git a/include/platform/FeaturesGL_autogen.h b/include/platform/FeaturesGL_autogen.h
|
||||
index aa0565c..2f6e094 100644
|
||||
--- a/include/platform/FeaturesGL_autogen.h
|
||||
+++ b/include/platform/FeaturesGL_autogen.h
|
||||
@@ -501,6 +501,12 @@
|
||||
"supportsShaderPixelLocalStorageEXT", FeatureCategory::OpenGLFeatures,
|
||||
"Backend GL context supports EXT_shader_pixel_local_storage extension", &members,
|
||||
"http://anglebug.com/7279"};
|
||||
+
|
||||
+ FeatureInfo ensureNonEmptyBufferIsBoundForDraw = {
|
||||
+ "ensureNonEmptyBufferIsBoundForDraw", FeatureCategory::OpenGLFeatures,
|
||||
+ "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero "
|
||||
+ "divisor.",
|
||||
+ &members, "http://crbug.com/1456243"};
|
||||
};
|
||||
|
||||
inline FeaturesGL::FeaturesGL() = default;
|
||||
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json
|
||||
index 032f29a..b358cea 100644
|
||||
--- a/include/platform/gl_features.json
|
||||
+++ b/include/platform/gl_features.json
|
||||
@@ -699,6 +699,14 @@
|
||||
"Backend GL context supports EXT_shader_pixel_local_storage extension"
|
||||
],
|
||||
"issue": "http://anglebug.com/7279"
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "ensure_non_empty_buffer_is_bound_for_draw",
|
||||
+ "category": "Features",
|
||||
+ "description": [
|
||||
+ "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero divisor."
|
||||
+ ],
|
||||
+ "issue": "http://crbug.com/1456243"
|
||||
}
|
||||
]
|
||||
}
|
||||
diff --git a/scripts/code_generation_hashes/ANGLE_features.json b/scripts/code_generation_hashes/ANGLE_features.json
|
||||
index d4576c2..503001c 100644
|
||||
--- a/scripts/code_generation_hashes/ANGLE_features.json
|
||||
+++ b/scripts/code_generation_hashes/ANGLE_features.json
|
||||
@@ -2,7 +2,7 @@
|
||||
"include/platform/FeaturesD3D_autogen.h":
|
||||
"9923fb44d0a6f31948d0c8f46ee1d9e2",
|
||||
"include/platform/FeaturesGL_autogen.h":
|
||||
- "a795a806d71b0e6d1f9e6d95c6e11971",
|
||||
+ "fef16ab3946346a2a7d5b76bb39471a4",
|
||||
"include/platform/FeaturesMtl_autogen.h":
|
||||
"407426c8874de9295482ace9c94bd812",
|
||||
"include/platform/FeaturesVk_autogen.h":
|
||||
@@ -16,13 +16,13 @@
|
||||
"include/platform/gen_features.py":
|
||||
"062989f7a8f3ff3b383f98fc8908dc33",
|
||||
"include/platform/gl_features.json":
|
||||
- "3335055a70e35ebb7bf74c6d7c58897b",
|
||||
+ "c9aead89696e7fd0c8bfe5c5ca85ca63",
|
||||
"include/platform/mtl_features.json":
|
||||
"c66d170e7a8eb3448030f4c423ed0133",
|
||||
"include/platform/vk_features.json":
|
||||
"416bbb28b9fa1a3c4ef141f243c0a9e6",
|
||||
"util/angle_features_autogen.cpp":
|
||||
- "73169f63c755192c3b4bd27d6f4096ca",
|
||||
+ "288daaec490eb816883d744f108d74c9",
|
||||
"util/angle_features_autogen.h":
|
||||
- "7aa8120eb8f8fd335946b8c27074745d"
|
||||
+ "daf25d3e4ffea143d1c082416513f7e7"
|
||||
}
|
||||
\ No newline at end of file
|
||||
diff --git a/src/libANGLE/renderer/gl/BufferGL.cpp b/src/libANGLE/renderer/gl/BufferGL.cpp
|
||||
index c99fd5d..9651838 100644
|
||||
--- a/src/libANGLE/renderer/gl/BufferGL.cpp
|
||||
+++ b/src/libANGLE/renderer/gl/BufferGL.cpp
|
||||
@@ -296,6 +296,11 @@
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
+size_t BufferGL::getBufferSize() const
|
||||
+{
|
||||
+ return mBufferSize;
|
||||
+}
|
||||
+
|
||||
GLuint BufferGL::getBufferID() const
|
||||
{
|
||||
return mBufferID;
|
||||
diff --git a/src/libANGLE/renderer/gl/BufferGL.h b/src/libANGLE/renderer/gl/BufferGL.h
|
||||
index 7b57594..fe9138e 100644
|
||||
--- a/src/libANGLE/renderer/gl/BufferGL.h
|
||||
+++ b/src/libANGLE/renderer/gl/BufferGL.h
|
||||
@@ -56,6 +56,7 @@
|
||||
bool primitiveRestartEnabled,
|
||||
gl::IndexRange *outRange) override;
|
||||
|
||||
+ size_t getBufferSize() const;
|
||||
GLuint getBufferID() const;
|
||||
|
||||
private:
|
||||
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
|
||||
index dc981de..fda9099 100644
|
||||
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
|
||||
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
|
||||
@@ -646,6 +646,7 @@
|
||||
|
||||
angle::Result VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
|
||||
{
|
||||
+ const angle::FeaturesGL &features = GetFeaturesGL(context);
|
||||
|
||||
const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
|
||||
|
||||
@@ -687,8 +688,16 @@
|
||||
// is not NULL.
|
||||
|
||||
StateManagerGL *stateManager = GetStateManagerGL(context);
|
||||
- GLuint bufferId = GetNativeBufferID(arrayBuffer);
|
||||
+ BufferGL *bufferGL = GetImplAs<BufferGL>(arrayBuffer);
|
||||
+ GLuint bufferId = bufferGL->getBufferID();
|
||||
stateManager->bindBuffer(gl::BufferBinding::Array, bufferId);
|
||||
+ if (features.ensureNonEmptyBufferIsBoundForDraw.enabled && bufferGL->getBufferSize() == 0)
|
||||
+ {
|
||||
+ constexpr uint32_t data = 0;
|
||||
+ ANGLE_TRY(bufferGL->setData(context, gl::BufferBinding::Array, &data, sizeof(data),
|
||||
+ gl::BufferUsage::StaticDraw));
|
||||
+ ASSERT(bufferGL->getBufferSize() > 0);
|
||||
+ }
|
||||
ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(attribIndex), attrib,
|
||||
binding.getStride(), binding.getOffset()));
|
||||
|
||||
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
|
||||
index 6911247..ab2a608 100644
|
||||
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
|
||||
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
|
||||
@@ -2465,6 +2465,9 @@
|
||||
// EXT_shader_pixel_local_storage
|
||||
ANGLE_FEATURE_CONDITION(features, supportsShaderPixelLocalStorageEXT,
|
||||
functions->hasGLESExtension("GL_EXT_shader_pixel_local_storage"));
|
||||
+
|
||||
+ // http://crbug.com/1456243
|
||||
+ ANGLE_FEATURE_CONDITION(features, ensureNonEmptyBufferIsBoundForDraw, IsApple() || IsAndroid());
|
||||
}
|
||||
|
||||
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
|
||||
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
|
||||
index 59ec7c2..44ff3e4 100644
|
||||
--- a/src/tests/angle_end2end_tests_expectations.txt
|
||||
+++ b/src/tests/angle_end2end_tests_expectations.txt
|
||||
@@ -380,6 +380,7 @@
|
||||
7294 WIN D3D11 : StateChangeTestES3.StencilWriteMask/* = SKIP
|
||||
7316 WIN D3D11 : StateChangeTestES3.StencilTestAndFunc/* = SKIP
|
||||
7329 WIN D3D11 : StateChangeTestES3.PrimitiveRestart/* = SKIP
|
||||
+1456243 WIN D3D11 : WebGL2CompatibilityTest.DrawWithZeroSizedBuffer/* = SKIP
|
||||
|
||||
// Android
|
||||
6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index 7dc56cd..bd7ecd1 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -1632,10 +1632,10 @@
|
||||
|
||||
constexpr GLuint kMaxIntAsGLuint = static_cast<GLuint>(std::numeric_limits<GLint>::max());
|
||||
constexpr GLuint kIndexData[] = {
|
||||
- kMaxIntAsGLuint,
|
||||
- kMaxIntAsGLuint + 1,
|
||||
- kMaxIntAsGLuint + 2,
|
||||
- kMaxIntAsGLuint + 3,
|
||||
+ kMaxIntAsGLuint,
|
||||
+ kMaxIntAsGLuint + 1,
|
||||
+ kMaxIntAsGLuint + 2,
|
||||
+ kMaxIntAsGLuint + 3,
|
||||
};
|
||||
|
||||
GLBuffer indexBuffer;
|
||||
@@ -3687,8 +3687,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -3748,8 +3748,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -3811,8 +3811,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -3874,8 +3874,8 @@
|
||||
|
||||
constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
|
||||
const GLushort textureData[] = {
|
||||
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
|
||||
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
|
||||
|
||||
for (auto extension : FloatingPointTextureExtensions)
|
||||
{
|
||||
@@ -5803,6 +5803,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
+// Test for a mishandling of instanced vertex attributes with zero-sized buffers bound on Apple
|
||||
+// OpenGL drivers.
|
||||
+TEST_P(WebGL2CompatibilityTest, DrawWithZeroSizedBuffer)
|
||||
+{
|
||||
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
|
||||
+ glUseProgram(program);
|
||||
+
|
||||
+ GLBuffer buffer;
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
+
|
||||
+ GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
|
||||
+ glEnableVertexAttribArray(posLocation);
|
||||
+
|
||||
+ glVertexAttribDivisor(posLocation, 1);
|
||||
+ glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 9,
|
||||
+ reinterpret_cast<void *>(0x41424344));
|
||||
+
|
||||
+ glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
+}
|
||||
+
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest);
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2CompatibilityTest);
|
||||
diff --git a/util/angle_features_autogen.cpp b/util/angle_features_autogen.cpp
|
||||
index adb9610..a060dd2 100644
|
||||
--- a/util/angle_features_autogen.cpp
|
||||
+++ b/util/angle_features_autogen.cpp
|
||||
@@ -118,6 +118,7 @@
|
||||
{Feature::EnablePrecisionQualifiers, "enablePrecisionQualifiers"},
|
||||
{Feature::EnablePreRotateSurfaces, "enablePreRotateSurfaces"},
|
||||
{Feature::EnableProgramBinaryForCapture, "enableProgramBinaryForCapture"},
|
||||
+ {Feature::EnsureNonEmptyBufferIsBoundForDraw, "ensureNonEmptyBufferIsBoundForDraw"},
|
||||
{Feature::ExpandIntegerPowExpressions, "expandIntegerPowExpressions"},
|
||||
{Feature::ExplicitlyEnablePerSampleShading, "explicitlyEnablePerSampleShading"},
|
||||
{Feature::ExposeNonConformantExtensionsAndVersions, "exposeNonConformantExtensionsAndVersions"},
|
||||
diff --git a/util/angle_features_autogen.h b/util/angle_features_autogen.h
|
||||
index 3d8c47f..4064425 100644
|
||||
--- a/util/angle_features_autogen.h
|
||||
+++ b/util/angle_features_autogen.h
|
||||
@@ -112,6 +112,7 @@
|
||||
EnablePrecisionQualifiers,
|
||||
EnablePreRotateSurfaces,
|
||||
EnableProgramBinaryForCapture,
|
||||
+ EnsureNonEmptyBufferIsBoundForDraw,
|
||||
ExpandIntegerPowExpressions,
|
||||
ExplicitlyEnablePerSampleShading,
|
||||
ExposeNonConformantExtensionsAndVersions,
|
||||
@@ -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,9 @@ 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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 {
|
||||
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,
|
||||
|
||||
@@ -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.
|
||||
@@ -17,10 +17,10 @@ policy->CanCommitOriginAndUrl.
|
||||
Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3856266.
|
||||
|
||||
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
|
||||
index 76a53ed5fcae948a3b2e950d484ffebd1939fd6c..fdce51afdbb8759fb52bf2ae570de3e4da7dd752 100644
|
||||
index a09b5bc4973fc3abdfc02627be515f7eaf87f2c1..15eabc215f6d31450c788145f99cd1e88cce6d89 100644
|
||||
--- a/content/browser/renderer_host/navigation_request.cc
|
||||
+++ b/content/browser/renderer_host/navigation_request.cc
|
||||
@@ -7345,10 +7345,11 @@ NavigationRequest::GetOriginForURLLoaderFactoryAfterResponseWithDebugInfo() {
|
||||
@@ -7428,10 +7428,11 @@ NavigationRequest::GetOriginForURLLoaderFactoryAfterResponseWithDebugInfo() {
|
||||
if (IsForMhtmlSubframe())
|
||||
return origin_with_debug_info;
|
||||
|
||||
@@ -37,10 +37,10 @@ index 76a53ed5fcae948a3b2e950d484ffebd1939fd6c..fdce51afdbb8759fb52bf2ae570de3e4
|
||||
}
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
|
||||
index dcdb5a391827be8d5b3558242ced27cefc54a6e3..17bd5123e6713ed19baa23b72d1b2dc3c3448701 100644
|
||||
index f2a1f119815728fb8b4d2c595369f78981f2347e..2bf7e3f851abf3f5979fb5fbc0d2d829e4c90190 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.h
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.h
|
||||
@@ -2930,6 +2930,17 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
@@ -2937,6 +2937,17 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
// last committed document.
|
||||
CookieChangeListener::CookieChangeInfo GetCookieChangeInfo();
|
||||
|
||||
@@ -58,7 +58,7 @@ index dcdb5a391827be8d5b3558242ced27cefc54a6e3..17bd5123e6713ed19baa23b72d1b2dc3
|
||||
// Sets a ResourceCache in the renderer. `this` must be active and there must
|
||||
// be no pending navigation. `remote` must have the same and process
|
||||
// isolation policy.
|
||||
@@ -3307,17 +3318,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
@@ -3314,17 +3325,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
// relevant.
|
||||
void ResetWaitingState();
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ This should be upstreamed, as other uses of MenuController in this
|
||||
file do check for menu controller being null.
|
||||
|
||||
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
|
||||
index 76bb4863858fb1bde1288b3d1b1d07f151a2f801..dc0dd45da0097330612a0810fcd2bd18f5c42be4 100644
|
||||
index 3ff9bc06e51c4c8e3d9cee8d18b31b7dff96528b..5106cc20c0e706095ac00279ebc215102ef581b0 100644
|
||||
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
|
||||
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
|
||||
@@ -402,8 +402,7 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
|
||||
|
||||
@@ -45,10 +45,10 @@ index ed0641b888c6421b1791c086466bd9c158e9109d..3760b3823d5af3325017bb53f5b1d38e
|
||||
// RenderFrameMetadataProvider::Observer implementation.
|
||||
void OnRenderFrameMetadataChangedBeforeActivation(
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 7a7f74778d0d9118d01a2dc8b916fada56a8dfaa..96bd0573473d9f401791125cd18cb24e76fab0db 100644
|
||||
index 98471a78e68722d207fde77e4545dfe21f12e19a..69d07fb1eed22ffab2556107f3520b19a8f066f2 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -8163,7 +8163,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
|
||||
@@ -8173,7 +8173,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
|
||||
"WebContentsImpl::OnFocusedElementChangedInFrame",
|
||||
"render_frame_host", frame);
|
||||
RenderWidgetHostViewBase* root_view =
|
||||
|
||||
@@ -98,7 +98,7 @@ index bc24bbc46d829946da255a74947dc3e5d4685dd3..c5a02b325dae7beb8ebebca49c93b8aa
|
||||
mojom::blink::WantResultOption,
|
||||
mojom::blink::PromiseResultOption);
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
|
||||
index 4a40473c167290328b6c2c0e9029c3d7c073fe44..f91e9eaab57aef9c202be8342281fa7d65fcbb8b 100644
|
||||
index 57e1e45f9c8aa0dbae982ab4e921d2a785841c22..e2cdf0c00cf165cbd8f7f2279ddffcd2b71c0fda 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
|
||||
@@ -935,6 +935,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld(
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: fix: select the first menu item when opened via keyboard
|
||||
This fixes an accessibility issue where the root view is 'focused' to the screen reader instead of the first menu item as with all other native menus. This patch will be upstreamed.
|
||||
|
||||
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
|
||||
index f8b3ded1dba82259f7d536ed5bab1a972d182419..b095843c8b28783bf51c0bf7becb111010651486 100644
|
||||
index 63c4954542acf9303f814c3be5f84cc52f393604..6901b7305462c31b26ef241933f8deaf89f40153 100644
|
||||
--- a/ui/views/controls/menu/menu_controller.cc
|
||||
+++ b/ui/views/controls/menu/menu_controller.cc
|
||||
@@ -563,6 +563,7 @@ void MenuController::Run(Widget* parent,
|
||||
@@ -561,6 +561,7 @@ void MenuController::Run(Widget* parent,
|
||||
MenuAnchorPosition position,
|
||||
bool context_menu,
|
||||
bool is_nested_drag,
|
||||
@@ -17,7 +17,7 @@ index f8b3ded1dba82259f7d536ed5bab1a972d182419..b095843c8b28783bf51c0bf7becb1110
|
||||
gfx::NativeView native_view_for_gestures) {
|
||||
exit_type_ = ExitType::kNone;
|
||||
possible_drag_ = false;
|
||||
@@ -627,6 +628,14 @@ void MenuController::Run(Widget* parent,
|
||||
@@ -625,6 +626,14 @@ void MenuController::Run(Widget* parent,
|
||||
// Set the selection, which opens the initial menu.
|
||||
SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
|
||||
|
||||
@@ -32,7 +32,7 @@ index f8b3ded1dba82259f7d536ed5bab1a972d182419..b095843c8b28783bf51c0bf7becb1110
|
||||
if (button_controller) {
|
||||
pressed_lock_ = button_controller->TakeLock(
|
||||
false, ui::LocatedEvent::FromIfValid(event));
|
||||
@@ -2262,19 +2271,15 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
|
||||
@@ -2254,19 +2263,15 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
|
||||
}
|
||||
item->GetSubmenu()->ShowAt(params);
|
||||
|
||||
@@ -83,7 +83,7 @@ index adb22671b94fa16854773baad0e6bff1322c6646..fae32722f1209151fa1da59d0c7892ab
|
||||
|
||||
bool MenuRunner::IsRunning() const {
|
||||
diff --git a/ui/views/controls/menu/menu_runner_impl.cc b/ui/views/controls/menu/menu_runner_impl.cc
|
||||
index c2513d2889a2baabb1464a53b6b0a32176d52d0c..54f4f863d9ecdf22e3087944f773a866e6c50024 100644
|
||||
index e82249ad5e887180bb5785d06a4084857e0bfe98..3dd47b1c2d9f517939fd8ec92787fb60f58ed5f7 100644
|
||||
--- a/ui/views/controls/menu/menu_runner_impl.cc
|
||||
+++ b/ui/views/controls/menu/menu_runner_impl.cc
|
||||
@@ -116,6 +116,7 @@ void MenuRunnerImpl::RunMenuAt(Widget* parent,
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: frame_host_manager.patch
|
||||
Allows embedder to intercept site instances created by chromium.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
index 02c8f132c266a599c335f83474b3322700a0e5d1..19f731476a2a2beacef7c4493a586c4a6cd69dd0 100644
|
||||
index c63f0f796dea518d04a85e7aa29d6c97bfc8c6dc..835e04d1223f185380c3cb5f9f50b7179f982a1c 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
@@ -3984,6 +3984,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||
@@ -4046,6 +4046,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||
request->ResetStateForSiteInstanceChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ This adds a callback from the network service that's used to implement
|
||||
session.setCertificateVerifyCallback.
|
||||
|
||||
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
|
||||
index d553d31e90ca7f3ea9a540d0eda7aaa6801f007b..0ffa0ec042bd59de5d28fad53dee2b6321d64b18 100644
|
||||
index 4156311dfec3f86f95e3a0b56190090e4de9a8a0..2d823eeb8a09d4bca7a800558cd6123df8950576 100644
|
||||
--- a/services/network/network_context.cc
|
||||
+++ b/services/network/network_context.cc
|
||||
@@ -142,6 +142,11 @@
|
||||
@@ -122,7 +122,7 @@ index d553d31e90ca7f3ea9a540d0eda7aaa6801f007b..0ffa0ec042bd59de5d28fad53dee2b63
|
||||
constexpr uint32_t NetworkContext::kMaxOutstandingRequestsPerProcess;
|
||||
|
||||
NetworkContext::PendingCertVerify::PendingCertVerify() = default;
|
||||
@@ -756,6 +854,13 @@ void NetworkContext::SetClient(
|
||||
@@ -764,6 +862,13 @@ void NetworkContext::SetClient(
|
||||
client_.Bind(std::move(client));
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ index d553d31e90ca7f3ea9a540d0eda7aaa6801f007b..0ffa0ec042bd59de5d28fad53dee2b63
|
||||
void NetworkContext::CreateURLLoaderFactory(
|
||||
mojo::PendingReceiver<mojom::URLLoaderFactory> receiver,
|
||||
mojom::URLLoaderFactoryParamsPtr params) {
|
||||
@@ -2289,6 +2394,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
|
||||
@@ -2300,6 +2405,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
|
||||
std::move(cert_verifier));
|
||||
cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_.get());
|
||||
#endif // BUILDFLAG(IS_CHROMEOS)
|
||||
@@ -147,7 +147,7 @@ index d553d31e90ca7f3ea9a540d0eda7aaa6801f007b..0ffa0ec042bd59de5d28fad53dee2b63
|
||||
|
||||
builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
|
||||
diff --git a/services/network/network_context.h b/services/network/network_context.h
|
||||
index 9cac607573e5411c6dd8c2a6309ae78c2a1784f4..f10414f382b48ecc162b22d9638d948e3e719733 100644
|
||||
index 6fe92667a76415a10fbd4756dcf58245c73752ed..07c516a63a391fd9eec2d2f6b9868c5da9d8f5c5 100644
|
||||
--- a/services/network/network_context.h
|
||||
+++ b/services/network/network_context.h
|
||||
@@ -114,6 +114,7 @@ class URLMatcher;
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Harrelson <chrishtr@chromium.org>
|
||||
Date: Fri, 25 Aug 2023 17:55:16 +0000
|
||||
Subject: Parameterize AXTreeSerializer by vector type
|
||||
|
||||
This enables us to use HeapVector in Blink, which is necessary because
|
||||
AXObject is a garbage-collected type.
|
||||
|
||||
Bug: 1472368
|
||||
|
||||
Change-Id: Idf6fee18827f2914452be49f61de0b6a36b19678
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4811206
|
||||
Reviewed-by: Aaron Leventhal <aleventhal@chromium.org>
|
||||
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
|
||||
Reviewed-by: Mark Schillaci <mschillaci@google.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#1188419}
|
||||
|
||||
diff --git a/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc b/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
|
||||
index f973c8c0c2c4b1f96a4ab7e22a924b3d85b44f35..e26827761686946669e21ba6459b24b571bdb4c0 100644
|
||||
--- a/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
|
||||
+++ b/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
|
||||
@@ -33,7 +33,9 @@ using views::Textfield;
|
||||
using views::View;
|
||||
using views::Widget;
|
||||
|
||||
-using AuraAXTreeSerializer = ui::AXTreeSerializer<views::AXAuraObjWrapper*>;
|
||||
+using AuraAXTreeSerializer =
|
||||
+ ui::AXTreeSerializer<views::AXAuraObjWrapper*,
|
||||
+ std::vector<views::AXAuraObjWrapper*>>;
|
||||
|
||||
// Helper to count the number of nodes in a tree.
|
||||
size_t GetSize(AXAuraObjWrapper* tree) {
|
||||
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
|
||||
index 498488f27e7fc273a0797063b6388576dfc5cd93..4d0ae2b291ce5bd607117288b0bfc1d3ce8e1c13 100644
|
||||
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
|
||||
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
|
||||
@@ -33,7 +33,9 @@ class AXAuraObjWrapper;
|
||||
class View;
|
||||
} // namespace views
|
||||
|
||||
-using AuraAXTreeSerializer = ui::AXTreeSerializer<views::AXAuraObjWrapper*>;
|
||||
+using AuraAXTreeSerializer =
|
||||
+ ui::AXTreeSerializer<views::AXAuraObjWrapper*,
|
||||
+ std::vector<views::AXAuraObjWrapper*>>;
|
||||
|
||||
// Manages a tree of automation nodes backed by aura constructs.
|
||||
class AutomationManagerAura : public ui::AXActionHandler,
|
||||
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc
|
||||
index a98413201e6fd3f683ba1bc4a55fe6f12fb7d802..c396e02dff92e14f8e876f2a213c376d53a47922 100644
|
||||
--- a/chrome/renderer/accessibility/read_anything_app_controller.cc
|
||||
+++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
|
||||
@@ -456,7 +456,8 @@ void ReadAnythingAppController::Distill() {
|
||||
model_.GetTreeFromId(model_.active_tree_id()).get();
|
||||
std::unique_ptr<ui::AXTreeSource<const ui::AXNode*>> tree_source(
|
||||
tree->CreateTreeSource());
|
||||
- ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
|
||||
+ ui::AXTreeSerializer<const ui::AXNode*, std::vector<const ui::AXNode*>>
|
||||
+ serializer(tree_source.get());
|
||||
ui::AXTreeUpdate snapshot;
|
||||
CHECK(serializer.SerializeChanges(tree->root(), &snapshot));
|
||||
model_.SetDistillationInProgress(true);
|
||||
diff --git a/components/services/screen_ai/screen_ai_ax_tree_serializer.cc b/components/services/screen_ai/screen_ai_ax_tree_serializer.cc
|
||||
index ecd818228f31dfefdc436302be9dcb47415b684c..6f921bd47e8dfb585da81cefdbdcf870f420b305 100644
|
||||
--- a/components/services/screen_ai/screen_ai_ax_tree_serializer.cc
|
||||
+++ b/components/services/screen_ai/screen_ai_ax_tree_serializer.cc
|
||||
@@ -43,7 +43,8 @@ ScreenAIAXTreeSerializer::ScreenAIAXTreeSerializer(
|
||||
tree_source_ = base::WrapUnique<ui::AXTreeSource<const ui::AXNode*>>(
|
||||
tree_->CreateTreeSource());
|
||||
DCHECK(tree_source_);
|
||||
- serializer_ = std::make_unique<ui::AXTreeSerializer<const ui::AXNode*>>(
|
||||
+ serializer_ = std::make_unique<
|
||||
+ ui::AXTreeSerializer<const ui::AXNode*, std::vector<const ui::AXNode*>>>(
|
||||
tree_source_.get(), /* crash_on_error */ true);
|
||||
}
|
||||
|
||||
diff --git a/components/services/screen_ai/screen_ai_ax_tree_serializer.h b/components/services/screen_ai/screen_ai_ax_tree_serializer.h
|
||||
index e522698819c4fe80bfd9da0b49934def0d2abb66..38fd5e2391a4a899f0f46069b42d6056d42f1e01 100644
|
||||
--- a/components/services/screen_ai/screen_ai_ax_tree_serializer.h
|
||||
+++ b/components/services/screen_ai/screen_ai_ax_tree_serializer.h
|
||||
@@ -41,7 +41,9 @@ class ScreenAIAXTreeSerializer final {
|
||||
private:
|
||||
const std::unique_ptr<ui::AXSerializableTree> tree_;
|
||||
std::unique_ptr<ui::AXTreeSource<const ui::AXNode*>> tree_source_;
|
||||
- mutable std::unique_ptr<ui::AXTreeSerializer<const ui::AXNode*>> serializer_;
|
||||
+ mutable std::unique_ptr<
|
||||
+ ui::AXTreeSerializer<const ui::AXNode*, std::vector<const ui::AXNode*>>>
|
||||
+ serializer_;
|
||||
};
|
||||
|
||||
} // namespace screen_ai
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
|
||||
index adf2816b5c9dde53745f6ca6eb8ba57cd7f44065..83b9859119f575894abf26423b298a13b79390f1 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_manager.cc
|
||||
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
|
||||
@@ -1645,7 +1645,8 @@ bool BrowserAccessibilityManager::IsRootFrameManager() const {
|
||||
ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
|
||||
std::unique_ptr<ui::AXTreeSource<const ui::AXNode*>> tree_source(
|
||||
ax_serializable_tree()->CreateTreeSource());
|
||||
- ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
|
||||
+ ui::AXTreeSerializer<const ui::AXNode*, std::vector<const ui::AXNode*>>
|
||||
+ serializer(tree_source.get());
|
||||
ui::AXTreeUpdate update;
|
||||
serializer.SerializeChanges(GetRoot(), &update);
|
||||
return update;
|
||||
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h
|
||||
index ddd8273fb0384d326f5ee2c78de23e3e03afe520..088edf542ef06c17e0e149ba5927fae16ee38817 100644
|
||||
--- a/content/renderer/accessibility/render_accessibility_impl.h
|
||||
+++ b/content/renderer/accessibility/render_accessibility_impl.h
|
||||
@@ -278,7 +278,8 @@ class CONTENT_EXPORT RenderAccessibilityImpl : public RenderAccessibility,
|
||||
// Manages the automatic image annotations, if enabled.
|
||||
std::unique_ptr<AXImageAnnotator> ax_image_annotator_;
|
||||
|
||||
- using PluginAXTreeSerializer = ui::AXTreeSerializer<const ui::AXNode*>;
|
||||
+ using PluginAXTreeSerializer =
|
||||
+ ui::AXTreeSerializer<const ui::AXNode*, std::vector<const ui::AXNode*>>;
|
||||
std::unique_ptr<PluginAXTreeSerializer> plugin_serializer_;
|
||||
PluginAXTreeSource* plugin_tree_source_;
|
||||
|
||||
diff --git a/services/accessibility/android/ax_tree_source_android.h b/services/accessibility/android/ax_tree_source_android.h
|
||||
index 5b9db486776a3133abb637637835ff4b77d1db0e..2b36a21eff98c692359d6a54a61a79eb229887f3 100644
|
||||
--- a/services/accessibility/android/ax_tree_source_android.h
|
||||
+++ b/services/accessibility/android/ax_tree_source_android.h
|
||||
@@ -30,7 +30,9 @@ class Window;
|
||||
namespace ax::android {
|
||||
class AXTreeSourceAndroidTest;
|
||||
|
||||
-using AXTreeArcSerializer = ui::AXTreeSerializer<AccessibilityInfoDataWrapper*>;
|
||||
+using AXTreeArcSerializer =
|
||||
+ ui::AXTreeSerializer<AccessibilityInfoDataWrapper*,
|
||||
+ std::vector<AccessibilityInfoDataWrapper*>>;
|
||||
|
||||
// This class represents the accessibility tree from the focused ARC window.
|
||||
class AXTreeSourceAndroid
|
||||
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
|
||||
index b63ece6af1fcd68a0da934d49b6cea201f7f6a6f..595d08aea99c02c155ca33f33b3a3c7e3e91db16 100644
|
||||
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
|
||||
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
|
||||
@@ -695,9 +695,11 @@ AXObjectCacheImpl::AXObjectCacheImpl(Document& document,
|
||||
permission_observer_receiver_(this, document.GetExecutionContext()),
|
||||
render_accessibility_host_(document.GetExecutionContext()),
|
||||
ax_tree_source_(BlinkAXTreeSource::Create(*this)),
|
||||
- ax_tree_serializer_(std::make_unique<ui::AXTreeSerializer<AXObject*>>(
|
||||
- ax_tree_source_,
|
||||
- /*crash_on_error*/ true)) {
|
||||
+ ax_tree_serializer_(
|
||||
+ std::make_unique<
|
||||
+ ui::AXTreeSerializer<AXObject*, HeapVector<AXObject*>>>(
|
||||
+ ax_tree_source_,
|
||||
+ /*crash_on_error*/ true)) {
|
||||
use_ax_menu_list_ = GetSettings()->GetUseAXMenuList();
|
||||
}
|
||||
|
||||
@@ -4095,7 +4097,8 @@ bool AXObjectCacheImpl::SerializeEntireTree(size_t max_node_count,
|
||||
// or a partial accessibility tree. AXTreeSerializer is stateful, but the
|
||||
// first time you serialize from a brand-new tree you're guaranteed to get a
|
||||
// complete tree.
|
||||
- ui::AXTreeSerializer<AXObject*> serializer(tree_source);
|
||||
+ ui::AXTreeSerializer<AXObject*, HeapVector<AXObject*>> serializer(
|
||||
+ tree_source);
|
||||
|
||||
if (max_node_count)
|
||||
serializer.set_max_node_count(max_node_count);
|
||||
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
|
||||
index 92a0af02d53e97456bbb7e032819ea8fc9f79331..fc4d9fa8882ee555e9598416cf497dd2b0fe5205 100644
|
||||
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
|
||||
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
|
||||
@@ -950,7 +950,8 @@ class MODULES_EXPORT AXObjectCacheImpl
|
||||
render_accessibility_host_;
|
||||
|
||||
Member<BlinkAXTreeSource> ax_tree_source_;
|
||||
- std::unique_ptr<ui::AXTreeSerializer<AXObject*>> ax_tree_serializer_;
|
||||
+ std::unique_ptr<ui::AXTreeSerializer<AXObject*, HeapVector<AXObject*>>>
|
||||
+ ax_tree_serializer_;
|
||||
|
||||
HeapDeque<Member<AXDirtyObject>> dirty_objects_;
|
||||
|
||||
diff --git a/ui/accessibility/ax_generated_tree_unittest.cc b/ui/accessibility/ax_generated_tree_unittest.cc
|
||||
index 2e24152f026a1f6962af348c96744218c783561c..cea591f9a9315ec6476ddec5411a04bb04f49df3 100644
|
||||
--- a/ui/accessibility/ax_generated_tree_unittest.cc
|
||||
+++ b/ui/accessibility/ax_generated_tree_unittest.cc
|
||||
@@ -75,7 +75,8 @@ std::string TreeToString(const AXTree& tree) {
|
||||
AXTreeUpdate SerializeEntireTree(AXSerializableTree& tree) {
|
||||
std::unique_ptr<AXTreeSource<const AXNode*>> tree_source(
|
||||
tree.CreateTreeSource());
|
||||
- AXTreeSerializer<const AXNode*> serializer(tree_source.get());
|
||||
+ AXTreeSerializer<const AXNode*, std::vector<const AXNode*>> serializer(
|
||||
+ tree_source.get());
|
||||
AXTreeUpdate update;
|
||||
CHECK(serializer.SerializeChanges(tree.root(), &update));
|
||||
return update;
|
||||
@@ -270,7 +271,8 @@ TEST_P(SerializeGeneratedTreesTest, SerializeGeneratedTrees) {
|
||||
// empty tree |dst_tree|.
|
||||
std::unique_ptr<AXTreeSource<const AXNode*>> tree0_source(
|
||||
tree0.CreateTreeSource());
|
||||
- AXTreeSerializer<const AXNode*> serializer(tree0_source.get());
|
||||
+ AXTreeSerializer<const AXNode*, std::vector<const AXNode*>>
|
||||
+ serializer(tree0_source.get());
|
||||
AXTreeUpdate update0;
|
||||
ASSERT_TRUE(serializer.SerializeChanges(tree0.root(), &update0));
|
||||
|
||||
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h
|
||||
index 0fb9303c39c979ab80c572769c2344701478f7e3..7874a5575823489aef2afa03b7f325e56ab689d1 100644
|
||||
--- a/ui/accessibility/ax_tree_serializer.h
|
||||
+++ b/ui/accessibility/ax_tree_serializer.h
|
||||
@@ -64,7 +64,7 @@ struct ClientTreeNode;
|
||||
// because AXTreeSerializer always keeps track of what updates it's sent,
|
||||
// it will never send an invalid update and the client tree will not break,
|
||||
// it just may not contain all of the changes.
|
||||
-template <typename AXSourceNode>
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
class AXTreeSerializer {
|
||||
public:
|
||||
explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree,
|
||||
@@ -260,14 +260,14 @@ struct AX_EXPORT ClientTreeNode {
|
||||
bool in_dirty_subtree;
|
||||
};
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::AXTreeSerializer(
|
||||
AXTreeSource<AXSourceNode>* tree,
|
||||
bool crash_on_error)
|
||||
: tree_(tree), crash_on_error_(crash_on_error) {}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::~AXTreeSerializer() {
|
||||
// Clear |tree_| to prevent any additional calls to the tree source
|
||||
// during teardown.
|
||||
// TODO(accessibility) How would that happen?
|
||||
@@ -276,14 +276,14 @@ AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::Reset() {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::Reset() {
|
||||
InternalReset();
|
||||
did_reset_ = true;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::InternalReset() {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::InternalReset() {
|
||||
client_tree_data_ = AXTreeData();
|
||||
|
||||
// Normally we use DeleteClientSubtree to remove nodes from the tree,
|
||||
@@ -296,26 +296,28 @@ void AXTreeSerializer<AXSourceNode>::InternalReset() {
|
||||
client_root_ = nullptr;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting(
|
||||
- AXTreeSource<AXSourceNode>* new_tree) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::
|
||||
+ ChangeTreeSourceForTesting(AXTreeSource<AXSourceNode>* new_tree) {
|
||||
tree_ = new_tree;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-size_t AXTreeSerializer<AXSourceNode>::ClientTreeNodeCount() const {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+size_t AXTreeSerializer<AXSourceNode,
|
||||
+ AXSourceNodeVectorType>::ClientTreeNodeCount() const {
|
||||
return client_id_map_.size();
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+AXSourceNode
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::LeastCommonAncestor(
|
||||
AXSourceNode node,
|
||||
ClientTreeNode* client_node) {
|
||||
if (!node || client_node == nullptr) {
|
||||
return tree_->GetNull();
|
||||
}
|
||||
|
||||
- std::vector<AXSourceNode> ancestors;
|
||||
+ AXSourceNodeVectorType ancestors;
|
||||
while (node) {
|
||||
ancestors.push_back(node);
|
||||
node = tree_->GetParent(node);
|
||||
@@ -334,17 +336,18 @@ AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
|
||||
for (size_t source_index = ancestors.size(),
|
||||
client_index = client_ancestors.size();
|
||||
source_index > 0 && client_index > 0; --source_index, --client_index) {
|
||||
- if (tree_->GetId(ancestors[source_index - 1]) !=
|
||||
+ if (tree_->GetId(ancestors[(unsigned int)(source_index - 1)]) !=
|
||||
client_ancestors[client_index - 1]->id) {
|
||||
return lca;
|
||||
}
|
||||
- lca = ancestors[source_index - 1];
|
||||
+ lca = ancestors[(unsigned int)(source_index - 1)];
|
||||
}
|
||||
return lca;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+AXSourceNode
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::LeastCommonAncestor(
|
||||
AXSourceNode node) {
|
||||
// Walk up the tree until the source node's id also exists in the
|
||||
// client tree, whose parent is not invalid, then call LeastCommonAncestor
|
||||
@@ -371,10 +374,9 @@ AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
|
||||
return LeastCommonAncestor(node, client_node);
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
|
||||
- AXSourceNode node,
|
||||
- AXSourceNode* out_lca) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+bool AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::
|
||||
+ AnyDescendantWasReparented(AXSourceNode node, AXSourceNode* out_lca) {
|
||||
bool result = false;
|
||||
int id = tree_->GetId(node);
|
||||
tree_->CacheChildrenIfNeeded(node);
|
||||
@@ -422,8 +424,9 @@ bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
|
||||
return result;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+ClientTreeNode*
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::ClientTreeNodeById(
|
||||
AXNodeID id) {
|
||||
std::map<AXNodeID, ClientTreeNode*>::iterator iter = client_id_map_.find(id);
|
||||
if (iter != client_id_map_.end())
|
||||
@@ -431,8 +434,9 @@ ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-ClientTreeNode* AXTreeSerializer<AXSourceNode>::GetClientTreeNodeParent(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+ClientTreeNode*
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::GetClientTreeNodeParent(
|
||||
ClientTreeNode* obj) {
|
||||
ClientTreeNode* parent = obj->parent;
|
||||
if (!parent)
|
||||
@@ -457,8 +461,8 @@ ClientTreeNode* AXTreeSerializer<AXSourceNode>::GetClientTreeNodeParent(
|
||||
return parent;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-bool AXTreeSerializer<AXSourceNode>::SerializeChanges(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+bool AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::SerializeChanges(
|
||||
AXSourceNode node,
|
||||
AXTreeUpdate* out_update) {
|
||||
if (!timeout_.is_zero())
|
||||
@@ -540,33 +544,37 @@ bool AXTreeSerializer<AXSourceNode>::SerializeChanges(
|
||||
return true;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-std::vector<AXNodeID> AXTreeSerializer<AXSourceNode>::GetIncompleteNodeIds() {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+std::vector<AXNodeID>
|
||||
+AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::GetIncompleteNodeIds() {
|
||||
DCHECK(max_node_count_ > 0 || !timeout_.is_zero());
|
||||
return incomplete_node_ids_;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::MarkSubtreeDirty(AXSourceNode node) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::MarkSubtreeDirty(
|
||||
+ AXSourceNode node) {
|
||||
ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
|
||||
if (client_node)
|
||||
MarkClientSubtreeDirty(client_node);
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-bool AXTreeSerializer<AXSourceNode>::IsInClientTree(AXSourceNode node) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+bool AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::IsInClientTree(
|
||||
+ AXSourceNode node) {
|
||||
return ClientTreeNodeById(tree_->GetId(node));
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-bool AXTreeSerializer<AXSourceNode>::IsDirty(AXSourceNode node) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+bool AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::IsDirty(
|
||||
+ AXSourceNode node) {
|
||||
ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
|
||||
return client_node ? client_node->in_dirty_subtree : false;
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::MarkClientSubtreeDirty(
|
||||
- ClientTreeNode* client_node) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::
|
||||
+ MarkClientSubtreeDirty(ClientTreeNode* client_node) {
|
||||
// Return early if already marked dirty, in order to avoid duplicate work in
|
||||
// subtree, as the only method that marks nodes dirty is this one.
|
||||
if (client_node->in_dirty_subtree) {
|
||||
@@ -578,9 +586,9 @@ void AXTreeSerializer<AXSourceNode>::MarkClientSubtreeDirty(
|
||||
}
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
|
||||
- ClientTreeNode* client_node) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::
|
||||
+ DeleteClientSubtree(ClientTreeNode* client_node) {
|
||||
if (client_node == client_root_) {
|
||||
Reset(); // Do not try to reuse a bad root later.
|
||||
// A heuristic for this condition rather than an explicit Reset() from a
|
||||
@@ -601,18 +609,17 @@ void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
|
||||
}
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-void AXTreeSerializer<AXSourceNode>::DeleteDescendants(
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+void AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::DeleteDescendants(
|
||||
ClientTreeNode* client_node) {
|
||||
for (size_t i = 0; i < client_node->children.size(); ++i)
|
||||
DeleteClientSubtree(client_node->children[i]);
|
||||
client_node->children.clear();
|
||||
}
|
||||
|
||||
-template <typename AXSourceNode>
|
||||
-bool AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
|
||||
- AXSourceNode node,
|
||||
- AXTreeUpdate* out_update) {
|
||||
+template <typename AXSourceNode, typename AXSourceNodeVectorType>
|
||||
+bool AXTreeSerializer<AXSourceNode, AXSourceNodeVectorType>::
|
||||
+ SerializeChangedNodes(AXSourceNode node, AXTreeUpdate* out_update) {
|
||||
// This method has three responsibilities:
|
||||
// 1. Serialize |node| into an AXNodeData, and append it to
|
||||
// the AXTreeUpdate to be sent to the client.
|
||||
diff --git a/ui/accessibility/ax_tree_serializer_unittest.cc b/ui/accessibility/ax_tree_serializer_unittest.cc
|
||||
index 3955a06f31795d0941d76976d8ae0a5c3204eedd..126e43a2bdcb1f9780baac6657201f26b3bd3244 100644
|
||||
--- a/ui/accessibility/ax_tree_serializer_unittest.cc
|
||||
+++ b/ui/accessibility/ax_tree_serializer_unittest.cc
|
||||
@@ -21,7 +21,8 @@ using testing::UnorderedElementsAre;
|
||||
|
||||
namespace ui {
|
||||
|
||||
-using BasicAXTreeSerializer = AXTreeSerializer<const AXNode*>;
|
||||
+using BasicAXTreeSerializer =
|
||||
+ AXTreeSerializer<const AXNode*, std::vector<const AXNode*>>;
|
||||
|
||||
// The framework for these tests is that each test sets up |treedata0_|
|
||||
// and |treedata1_| and then calls GetTreeSerializer, which creates a
|
||||
@@ -535,7 +536,7 @@ TEST_F(AXTreeSerializerTest, TestPartialSerialization) {
|
||||
// The result should be indistinguishable from the source tree.
|
||||
std::unique_ptr<AXTreeSource<const AXNode*>> dst_tree_source(
|
||||
dst_tree.CreateTreeSource());
|
||||
- AXTreeSerializer<const AXNode*> serializer(dst_tree_source.get());
|
||||
+ BasicAXTreeSerializer serializer(dst_tree_source.get());
|
||||
AXTreeUpdate dst_update;
|
||||
CHECK(serializer.SerializeChanges(dst_tree.root(), &dst_update));
|
||||
ASSERT_EQ(treedata1_.ToString(), dst_update.ToString());
|
||||
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
|
||||
index 910c03370446e228692aed4e356d06db3d0ec574..bbd9fa9bafc2003204be9ac05c9044e7fc851b1d 100644
|
||||
--- a/ui/accessibility/ax_tree_unittest.cc
|
||||
+++ b/ui/accessibility/ax_tree_unittest.cc
|
||||
@@ -333,7 +333,8 @@ TEST(AXTreeTest, SerializeSimpleAXTree) {
|
||||
|
||||
std::unique_ptr<AXTreeSource<const AXNode*>> tree_source(
|
||||
src_tree.CreateTreeSource());
|
||||
- AXTreeSerializer<const AXNode*> serializer(tree_source.get());
|
||||
+ AXTreeSerializer<const AXNode*, std::vector<const AXNode*>> serializer(
|
||||
+ tree_source.get());
|
||||
AXTreeUpdate update;
|
||||
serializer.SerializeChanges(src_tree.root(), &update);
|
||||
|
||||
diff --git a/ui/views/accessibility/ax_aura_obj_cache_unittest.cc b/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
|
||||
index 42e505a548edab06ebd31c298791959fe1b55867..68f6b64b1e96a18549d78c88a7adff804c9b2da2 100644
|
||||
--- a/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
|
||||
+++ b/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
|
||||
@@ -216,7 +216,8 @@ TEST_F(AXAuraObjCacheTest, ValidTree) {
|
||||
ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
|
||||
AXTreeSourceViews tree_source(
|
||||
cache.GetOrCreate(parent_widget->GetNativeWindow()), tree_id, &cache);
|
||||
- ui::AXTreeSerializer<AXAuraObjWrapper*> serializer(&tree_source);
|
||||
+ ui::AXTreeSerializer<AXAuraObjWrapper*, std::vector<AXAuraObjWrapper*>>
|
||||
+ serializer(&tree_source);
|
||||
ui::AXTreeUpdate serialized_tree;
|
||||
serializer.SerializeChanges(tree_source.GetRoot(), &serialized_tree);
|
||||
|
||||
diff --git a/ui/views/accessibility/views_ax_tree_manager.h b/ui/views/accessibility/views_ax_tree_manager.h
|
||||
index 0caff17e0568762d61c7f2fdc6b94c01bc3d9e30..00fe01d00e17b51d7d37d099a8f21549669e69a0 100644
|
||||
--- a/ui/views/accessibility/views_ax_tree_manager.h
|
||||
+++ b/ui/views/accessibility/views_ax_tree_manager.h
|
||||
@@ -93,7 +93,8 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager,
|
||||
void OnWidgetDestroyed(Widget* widget) override;
|
||||
|
||||
private:
|
||||
- using ViewsAXTreeSerializer = ui::AXTreeSerializer<AXAuraObjWrapper*>;
|
||||
+ using ViewsAXTreeSerializer =
|
||||
+ ui::AXTreeSerializer<AXAuraObjWrapper*, std::vector<AXAuraObjWrapper*>>;
|
||||
|
||||
void SerializeTreeUpdates();
|
||||
void UnserializeTreeUpdates(const std::vector<ui::AXTreeUpdate>& updates);
|
||||
@@ -44,10 +44,10 @@ index 2d705b183b1014a6f8dc89672b327d619ac52b1a..7107c17a8f36688d245b4cad5ee92dfc
|
||||
|
||||
void RenderWidgetHostImpl::ShowContextMenuAtPoint(
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 5018e17e0f56efd54529ef3e9ae1de5e223aed68..865414f0994a4e29f297532538486f780edd51d3 100644
|
||||
index 4b53b6060e6d7aae818a3d81faa0a1ae673ea59e..d4dd0e24538b2282de207a63aef7486c30525ed9 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -4798,6 +4798,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
|
||||
@@ -4804,6 +4804,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
|
||||
return text_input_manager_.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <samuel.r.attard@gmail.com>
|
||||
Date: Tue, 5 Sep 2023 13:22:31 -0700
|
||||
Subject: Revert "Remove the AllowAggressiveThrottlingWithWebSocket feature."
|
||||
|
||||
This reverts commit 615c1810a187840ffeb04096087efff86edb37de.
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
|
||||
index 98a78f1a7b6a5005f7d5da4ac279e38b61fac4dc..330e1e37b2d9f154ccc360d1102375efded12ff9 100644
|
||||
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
|
||||
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
|
||||
@@ -94,6 +94,17 @@ enum WebSocketOpCode {
|
||||
kOpCodeBinary = 0x2,
|
||||
};
|
||||
|
||||
+// When enabled, a page can be aggressively throttled even if it uses a
|
||||
+// WebSocket. Aggressive throttling does not affect the execution of WebSocket
|
||||
+// event handlers, so there is little reason to disable it on pages using a
|
||||
+// WebSocket.
|
||||
+//
|
||||
+// TODO(crbug.com/1121725): Cleanup this feature in June 2021, when it becomes
|
||||
+// enabled by default on Stable.
|
||||
+BASE_FEATURE(kAllowAggressiveThrottlingWithWebSocket,
|
||||
+ "AllowAggressiveThrottlingWithWebSocket",
|
||||
+ base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
+
|
||||
} // namespace
|
||||
|
||||
void WebSocketChannelImpl::MessageDataDeleter::operator()(char* p) const {
|
||||
@@ -284,7 +295,10 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) {
|
||||
// even if the `WebSocketChannel` is closed.
|
||||
feature_handle_for_scheduler_ = scheduler->RegisterFeature(
|
||||
SchedulingPolicy::Feature::kWebSocket,
|
||||
- SchedulingPolicy{SchedulingPolicy::DisableBackForwardCache()});
|
||||
+ base::FeatureList::IsEnabled(kAllowAggressiveThrottlingWithWebSocket)
|
||||
+ ? SchedulingPolicy{SchedulingPolicy::DisableBackForwardCache()}
|
||||
+ : SchedulingPolicy{SchedulingPolicy::DisableAggressiveThrottling(),
|
||||
+ SchedulingPolicy::DisableBackForwardCache()});
|
||||
scheduler->RegisterStickyFeature(
|
||||
SchedulingPolicy::Feature::kWebSocketSticky,
|
||||
SchedulingPolicy{SchedulingPolicy::DisableBackForwardCache()});
|
||||
@@ -9,10 +9,10 @@ is needed for OSR.
|
||||
Originally landed in https://github.com/electron/libchromiumcontent/pull/226.
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 3a60a59497571a33bba8efa7654a32403ab99978..0582143a5466afb3ba618e848ff23ffa23e5ca70 100644
|
||||
index 1d1aac31f051e17d10c2f776c685dd74958cb35f..699e13391bd408aff3c862820d531c968e05743a 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3242,6 +3242,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
|
||||
@@ -3248,6 +3248,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
|
||||
params.main_frame_name, GetOpener(), primary_main_frame_policy,
|
||||
base::UnguessableToken::Create());
|
||||
|
||||
@@ -26,7 +26,7 @@ index 3a60a59497571a33bba8efa7654a32403ab99978..0582143a5466afb3ba618e848ff23ffa
|
||||
std::unique_ptr<WebContentsViewDelegate> delegate =
|
||||
GetContentClient()->browser()->GetWebContentsViewDelegate(this);
|
||||
|
||||
@@ -3252,6 +3259,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
|
||||
@@ -3258,6 +3265,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
|
||||
view_ = CreateWebContentsView(this, std::move(delegate),
|
||||
&render_view_host_delegate_view_);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ the parent frame should also enter fullscreen mode too. Chromium handles
|
||||
this for iframes, but not for webviews as they are essentially main
|
||||
frames instead of child frames.
|
||||
|
||||
This patch makes webviews propagate the fullscreen state to embedder.
|
||||
This patch makes webviews propagate the fullscreen state to embedder.It also handles a
|
||||
DCHECK preventing guest webcontents from becoming the focused webContents.
|
||||
|
||||
Note that we also need to manually update embedder's
|
||||
`api::WebContents::IsFullscreenForTabOrPending` value.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 0faa1fba5cea7e301b7497aca5838f761d9e02bd..b87ce268fd12e7bcedd0739548a14d6c6aedbc1d 100644
|
||||
index 544f2bcf906ad40769e5961d97211fbba549d03a..2c5a63a85ba37573182ab9b8731f70948c2cc0e6 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -7053,6 +7053,17 @@ void RenderFrameHostImpl::EnterFullscreen(
|
||||
@@ -35,3 +36,67 @@ index 0faa1fba5cea7e301b7497aca5838f761d9e02bd..b87ce268fd12e7bcedd0739548a14d6c
|
||||
// Focus the window if another frame may have delegated the capability.
|
||||
if (had_fullscreen_token && !GetView()->HasFocus())
|
||||
GetView()->Focus();
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 699e13391bd408aff3c862820d531c968e05743a..98471a78e68722d207fde77e4545dfe21f12e19a 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3493,21 +3493,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent(
|
||||
const NativeWebKeyboardEvent& event) {
|
||||
OPTIONAL_TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("content.verbose"),
|
||||
"WebContentsImpl::PreHandleKeyboardEvent");
|
||||
- auto* outermost_contents = GetOutermostWebContents();
|
||||
- // TODO(wjmaclean): Generalize this to forward all key events to the outermost
|
||||
- // delegate's handler.
|
||||
- if (outermost_contents != this && IsFullscreen() &&
|
||||
- event.windows_key_code == ui::VKEY_ESCAPE) {
|
||||
- // When an inner WebContents has focus and is fullscreen, redirect <esc>
|
||||
- // key events to the outermost WebContents so it can be handled by that
|
||||
- // WebContents' delegate.
|
||||
- if (outermost_contents->PreHandleKeyboardEvent(event) ==
|
||||
- KeyboardEventProcessingResult::HANDLED) {
|
||||
+
|
||||
+ auto handled = delegate_ ? delegate_->PreHandleKeyboardEvent(this, event)
|
||||
+ : KeyboardEventProcessingResult::NOT_HANDLED;
|
||||
+
|
||||
+ if (IsFullscreen() && event.windows_key_code == ui::VKEY_ESCAPE) {
|
||||
+ if (handled == KeyboardEventProcessingResult::HANDLED)
|
||||
return KeyboardEventProcessingResult::HANDLED;
|
||||
+
|
||||
+ // When an inner WebContents has focus and is fullscreen, traverse through
|
||||
+ // containing webcontents to any that may handle the escape key.
|
||||
+ while (auto* outer_web_contents = GetOuterWebContents()) {
|
||||
+ auto result = outer_web_contents->PreHandleKeyboardEvent(event);
|
||||
+ if (result == KeyboardEventProcessingResult::HANDLED) {
|
||||
+ return KeyboardEventProcessingResult::HANDLED;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
- return delegate_ ? delegate_->PreHandleKeyboardEvent(this, event)
|
||||
- : KeyboardEventProcessingResult::NOT_HANDLED;
|
||||
+
|
||||
+ return handled;
|
||||
}
|
||||
|
||||
bool WebContentsImpl::HandleMouseEvent(const blink::WebMouseEvent& event) {
|
||||
@@ -3639,7 +3643,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.
|
||||
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
|
||||
index 1d4fc3f0ffe1f74a57df49e644e49e6b25b5e2c4..85f4190f0de44d919e82483536b28bf1f069ec63 100644
|
||||
--- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc
|
||||
+++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
|
||||
@@ -99,7 +99,7 @@ void FullscreenElementChanged(Document& document,
|
||||
// is the iframe element for the out-of-process frame that contains the
|
||||
// fullscreen element. Hence, it must match :-webkit-full-screen-ancestor.
|
||||
if (new_request_type & FullscreenRequestType::kForCrossProcessDescendant) {
|
||||
- DCHECK(IsA<HTMLIFrameElement>(new_element));
|
||||
+ // DCHECK(IsA<HTMLIFrameElement>(new_element));
|
||||
new_element->SetContainsFullScreenElement(true);
|
||||
}
|
||||
new_element->SetContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(
|
||||
|
||||
0
patches/libvpx/.patches
Normal file
0
patches/libvpx/.patches
Normal file
@@ -37,3 +37,11 @@ chore_remove_--no-harmony-atomics_related_code.patch
|
||||
fix_account_for_createexternalizablestring_v8_global.patch
|
||||
fix_wunreachable-code_warning_in_ares_init_rand_engine.patch
|
||||
fix_do_not_resolve_electron_entrypoints.patch
|
||||
dns_expose_getdefaultresultorder.patch
|
||||
fix_assert_module_in_the_renderer_process.patch
|
||||
tls_ensure_tls_sockets_are_closed_if_the_underlying_wrap_closes.patch
|
||||
test_deflake_test-tls-socket-close.patch
|
||||
net_fix_crash_due_to_simultaneous_close_shutdown_on_js_stream.patch
|
||||
net_use_asserts_in_js_socket_stream_to_catch_races_in_future.patch
|
||||
lib_fix_broadcastchannel_initialization_location.patch
|
||||
win_process_avoid_assert_after_spawning_store_app_4152.patch
|
||||
|
||||
141
patches/node/dns_expose_getdefaultresultorder.patch
Normal file
141
patches/node/dns_expose_getdefaultresultorder.patch
Normal file
@@ -0,0 +1,141 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: btea <2356281422@qq.com>
|
||||
Date: Wed, 26 Apr 2023 16:56:04 +0800
|
||||
Subject: dns: expose getDefaultResultOrder
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/46973
|
||||
Fixes: https://github.com/nodejs/node/issues/46919
|
||||
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
||||
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
|
||||
|
||||
diff --git a/doc/api/dns.md b/doc/api/dns.md
|
||||
index 59a56c7d1c2aa87b4786c5b6397978b195af1f83..2bb997bb0a2b4ebdbb9ae5625762e8c3184ace8d 100644
|
||||
--- a/doc/api/dns.md
|
||||
+++ b/doc/api/dns.md
|
||||
@@ -792,6 +792,18 @@ priority than [`--dns-result-order`][]. When using [worker threads][],
|
||||
[`dns.setDefaultResultOrder()`][] from the main thread won't affect the default
|
||||
dns orders in workers.
|
||||
|
||||
+## `dns.getDefaultResultOrder()`
|
||||
+
|
||||
+<!-- YAML
|
||||
+added: REPLACEME
|
||||
+-->
|
||||
+
|
||||
+Get the default value for `verbatim` in [`dns.lookup()`][] and
|
||||
+[`dnsPromises.lookup()`][]. The value could be:
|
||||
+
|
||||
+* `ipv4first`: for `verbatim` defaulting to `false`.
|
||||
+* `verbatim`: for `verbatim` defaulting to `true`.
|
||||
+
|
||||
## `dns.setServers(servers)`
|
||||
|
||||
<!-- YAML
|
||||
@@ -1351,6 +1363,14 @@ higher priority than [`--dns-result-order`][]. When using [worker threads][],
|
||||
[`dnsPromises.setDefaultResultOrder()`][] from the main thread won't affect the
|
||||
default dns orders in workers.
|
||||
|
||||
+### `dnsPromises.getDefaultResultOrder()`
|
||||
+
|
||||
+<!-- YAML
|
||||
+added: REPLACEME
|
||||
+-->
|
||||
+
|
||||
+Get the value of `dnsOrder`.
|
||||
+
|
||||
### `dnsPromises.setServers(servers)`
|
||||
|
||||
<!-- YAML
|
||||
diff --git a/lib/dns.js b/lib/dns.js
|
||||
index c0e6a3332e4d21d85279955ea0514548cc4fd171..ae0e14bab3097d7170d47adedf4fff8ca8871c93 100644
|
||||
--- a/lib/dns.js
|
||||
+++ b/lib/dns.js
|
||||
@@ -38,6 +38,7 @@ const {
|
||||
validateHints,
|
||||
emitInvalidHostnameWarning,
|
||||
getDefaultVerbatim,
|
||||
+ getDefaultResultOrder,
|
||||
setDefaultResultOrder,
|
||||
errorCodes: dnsErrorCodes,
|
||||
} = require('internal/dns/utils');
|
||||
@@ -305,6 +306,7 @@ module.exports = {
|
||||
lookupService,
|
||||
|
||||
Resolver,
|
||||
+ getDefaultResultOrder,
|
||||
setDefaultResultOrder,
|
||||
setServers: defaultResolverSetServers,
|
||||
|
||||
diff --git a/lib/internal/dns/promises.js b/lib/internal/dns/promises.js
|
||||
index 494c7ecb242c7b5f14ef136c2caf07711c11f9a5..df41d1267ef4215a44d5119afb01dbbb1211a2c3 100644
|
||||
--- a/lib/internal/dns/promises.js
|
||||
+++ b/lib/internal/dns/promises.js
|
||||
@@ -14,6 +14,7 @@ const {
|
||||
emitInvalidHostnameWarning,
|
||||
getDefaultVerbatim,
|
||||
errorCodes: dnsErrorCodes,
|
||||
+ getDefaultResultOrder,
|
||||
setDefaultResultOrder,
|
||||
setDefaultResolver,
|
||||
} = require('internal/dns/utils');
|
||||
@@ -335,6 +336,7 @@ module.exports = {
|
||||
lookup,
|
||||
lookupService,
|
||||
Resolver,
|
||||
+ getDefaultResultOrder,
|
||||
setDefaultResultOrder,
|
||||
setServers: defaultResolverSetServers,
|
||||
|
||||
diff --git a/lib/internal/dns/utils.js b/lib/internal/dns/utils.js
|
||||
index e2b96011df94f20874aa2a39a7daf29bd8efa85e..56b2b3930b2f6e928eae8b9ab8047a08d6083441 100644
|
||||
--- a/lib/internal/dns/utils.js
|
||||
+++ b/lib/internal/dns/utils.js
|
||||
@@ -283,6 +283,10 @@ function setDefaultResultOrder(value) {
|
||||
dnsOrder = value;
|
||||
}
|
||||
|
||||
+function getDefaultResultOrder() {
|
||||
+ return dnsOrder;
|
||||
+}
|
||||
+
|
||||
function createResolverClass(resolver) {
|
||||
const resolveMap = ObjectCreate(null);
|
||||
|
||||
@@ -345,6 +349,7 @@ module.exports = {
|
||||
validateTries,
|
||||
emitInvalidHostnameWarning,
|
||||
getDefaultVerbatim,
|
||||
+ getDefaultResultOrder,
|
||||
setDefaultResultOrder,
|
||||
errorCodes,
|
||||
createResolverClass,
|
||||
diff --git a/test/internet/test-dns-getDefaultResultOrder.js b/test/internet/test-dns-getDefaultResultOrder.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ae176f1264508b847ae5dd18f2593d607b2f1a98
|
||||
--- /dev/null
|
||||
+++ b/test/internet/test-dns-getDefaultResultOrder.js
|
||||
@@ -0,0 +1,24 @@
|
||||
+'use strict';
|
||||
+
|
||||
+const common = require('../common');
|
||||
+
|
||||
+const assert = require('assert');
|
||||
+const dns = require('dns');
|
||||
+
|
||||
+dns.setDefaultResultOrder('ipv4first');
|
||||
+let dnsOrder = dns.getDefaultResultOrder();
|
||||
+assert.ok(dnsOrder === 'ipv4first');
|
||||
+dns.setDefaultResultOrder('verbatim');
|
||||
+dnsOrder = dns.getDefaultResultOrder();
|
||||
+assert.ok(dnsOrder === 'verbatim');
|
||||
+
|
||||
+{
|
||||
+ (async function() {
|
||||
+ const result = await dns.promises.lookup('localhost');
|
||||
+ const result1 = await dns.promises.lookup('localhost', { verbatim: true });
|
||||
+ assert.ok(result !== undefined);
|
||||
+ assert.ok(result1 !== undefined);
|
||||
+ assert.ok(result.address === result1.address);
|
||||
+ assert.ok(result.family === result1.family);
|
||||
+ })().then(common.mustCall());
|
||||
+}
|
||||
75
patches/node/fix_assert_module_in_the_renderer_process.patch
Normal file
75
patches/node/fix_assert_module_in_the_renderer_process.patch
Normal file
@@ -0,0 +1,75 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Wed, 16 Aug 2023 19:15:29 +0200
|
||||
Subject: fix: assert module in the renderer process
|
||||
|
||||
When creating a Node.js Environment, embedders have the option to disable Node.js'
|
||||
default overriding of Error.prepareStackTrace. However, the assert module depends on
|
||||
a WeakMap that is populated with the error stacktraces in the overridden function.
|
||||
|
||||
This adds handling to fall back to the default implementation if Error.prepareStackTrace
|
||||
if the override has been disabled.
|
||||
|
||||
This will be upstreamed.
|
||||
|
||||
diff --git a/lib/assert.js b/lib/assert.js
|
||||
index 04c2dd3bfcfdfbb4b8079c306e1d80aa48027787..34658819d09cc20f372798caec79e19c4a36565d 100644
|
||||
--- a/lib/assert.js
|
||||
+++ b/lib/assert.js
|
||||
@@ -66,6 +66,7 @@ const { inspect } = require('internal/util/inspect');
|
||||
const { isPromise, isRegExp } = require('internal/util/types');
|
||||
const { EOL } = require('internal/constants');
|
||||
const { BuiltinModule } = require('internal/bootstrap/loaders');
|
||||
+const { getEmbedderOptions } = require('internal/options');
|
||||
const { isError } = require('internal/util');
|
||||
|
||||
const errorCache = new SafeMap();
|
||||
@@ -293,8 +294,16 @@ function getErrMessage(message, fn) {
|
||||
ErrorCaptureStackTrace(err, fn);
|
||||
if (errorStackTraceLimitIsWritable) Error.stackTraceLimit = tmpLimit;
|
||||
|
||||
- overrideStackTrace.set(err, (_, stack) => stack);
|
||||
- const call = err.stack[0];
|
||||
+ let call;
|
||||
+ if (getEmbedderOptions().hasPrepareStackTraceCallback) {
|
||||
+ overrideStackTrace.set(err, (_, stack) => stack);
|
||||
+ call = err.stack[0];
|
||||
+ } else {
|
||||
+ const tmpPrepare = Error.prepareStackTrace;
|
||||
+ Error.prepareStackTrace = (_, stack) => stack;
|
||||
+ call = err.stack[0];
|
||||
+ Error.prepareStackTrace = tmpPrepare;
|
||||
+ }
|
||||
|
||||
const filename = call.getFileName();
|
||||
const line = call.getLineNumber() - 1;
|
||||
diff --git a/src/api/environment.cc b/src/api/environment.cc
|
||||
index 53db99ed5d2d9811eef2db26021c982890cc9cbe..7732f17c48a1e9db71b6c4dacfe08d686182c174 100644
|
||||
--- a/src/api/environment.cc
|
||||
+++ b/src/api/environment.cc
|
||||
@@ -262,6 +262,9 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
|
||||
auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
|
||||
s.prepare_stack_trace_callback : PrepareStackTraceCallback;
|
||||
isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
|
||||
+ } else {
|
||||
+ auto env = Environment::GetCurrent(isolate);
|
||||
+ env->set_prepare_stack_trace_callback(Local<Function>());
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/node_options.cc b/src/node_options.cc
|
||||
index 8bbee83ddb32a31ada18d7a6e8be7cdf33321b69..8765936e97a0fb2a3cf6ed4f2ae6ef539d778da1 100644
|
||||
--- a/src/node_options.cc
|
||||
+++ b/src/node_options.cc
|
||||
@@ -1211,6 +1211,11 @@ void GetEmbedderOptions(const FunctionCallbackInfo<Value>& args) {
|
||||
Local<Context> context = env->context();
|
||||
Local<Object> ret = Object::New(isolate);
|
||||
|
||||
+ if (ret->Set(context,
|
||||
+ FIXED_ONE_BYTE_STRING(env->isolate(), "hasPrepareStackTraceCallback"),
|
||||
+ Boolean::New(isolate, !env->prepare_stack_trace_callback().IsEmpty()))
|
||||
+ .IsNothing()) return;
|
||||
+
|
||||
if (ret->Set(context,
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "shouldNotRegisterESMLoader"),
|
||||
Boolean::New(isolate, env->should_not_register_esm_loader()))
|
||||
@@ -6,19 +6,42 @@ Subject: fix: do not resolve electron entrypoints
|
||||
This wastes fs cycles and can result in strange behavior if this path actually exists on disk
|
||||
|
||||
diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js
|
||||
index 5a50d5d6afab6e6648f72a1c0efa1df4cd80bcd9..0be45309028b00a6957ee473322a9452a7fa7d67 100644
|
||||
index 5a50d5d6afab6e6648f72a1c0efa1df4cd80bcd9..ebc9999358ccf16689dc02322eb1aeb86355f39b 100644
|
||||
--- a/lib/internal/modules/run_main.js
|
||||
+++ b/lib/internal/modules/run_main.js
|
||||
@@ -13,6 +13,12 @@ const {
|
||||
@@ -3,6 +3,7 @@
|
||||
const {
|
||||
ObjectCreate,
|
||||
StringPrototypeEndsWith,
|
||||
+ StringPrototypeStartsWith,
|
||||
} = primordials;
|
||||
const CJSLoader = require('internal/modules/cjs/loader');
|
||||
const { Module, toRealPath, readPackageScope } = CJSLoader;
|
||||
@@ -13,6 +14,13 @@ const {
|
||||
} = require('internal/modules/esm/handle_process_exit');
|
||||
|
||||
function resolveMainPath(main) {
|
||||
+ // For built-in modules used as the main entry point we _never_
|
||||
+ // want to waste cycles resolving them to file paths on disk
|
||||
+ // that actually might exist
|
||||
+ if (typeof main === 'string' && main.startsWith('electron/js2c')) {
|
||||
+ if (typeof main === 'string' && StringPrototypeStartsWith(main, 'electron/js2c')) {
|
||||
+ return main;
|
||||
+ }
|
||||
+
|
||||
// Note extension resolution for the main entry point can be deprecated in a
|
||||
// future major.
|
||||
// Module._findPath is monkey-patchable here.
|
||||
@@ -28,6 +36,13 @@ function resolveMainPath(main) {
|
||||
}
|
||||
|
||||
function shouldUseESMLoader(mainPath) {
|
||||
+ // For built-in modules used as the main entry point we _never_
|
||||
+ // want to waste cycles resolving them to file paths on disk
|
||||
+ // that actually might exist
|
||||
+ if (typeof mainPath === 'string' && StringPrototypeStartsWith(mainPath, 'electron/js2c')) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* @type {string[]} userLoaders A list of custom loaders registered by the user
|
||||
* (or an empty list when none have been registered).
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 27 Feb 2023 12:56:15 +0100
|
||||
Subject: lib: fix BroadcastChannel initialization location
|
||||
|
||||
Refs https://github.com/nodejs/node/pull/40532.
|
||||
|
||||
Fixes a bug in the above, wherein BroadcastChannel should have been
|
||||
initialized in bootstrap/browser instead of bootstrap/node. That
|
||||
inadvertently made it such that there was incorrect handling of the
|
||||
DOM vs Node.js implementations of BroadcastChannel.
|
||||
|
||||
This will be upstreamed.
|
||||
|
||||
diff --git a/lib/internal/bootstrap/browser.js b/lib/internal/bootstrap/browser.js
|
||||
index 5be4dd6176482c724455cbbeeaa9680e849a091b..29ccee75d77da072735032f0a25363ac88a023ba 100644
|
||||
--- a/lib/internal/bootstrap/browser.js
|
||||
+++ b/lib/internal/bootstrap/browser.js
|
||||
@@ -12,6 +12,10 @@ const {
|
||||
} = require('internal/util');
|
||||
const config = internalBinding('config');
|
||||
|
||||
+// Non-standard extensions:
|
||||
+const { BroadcastChannel } = require('internal/worker/io');
|
||||
+exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
|
||||
+
|
||||
// https://console.spec.whatwg.org/#console-namespace
|
||||
exposeNamespace(globalThis, 'console',
|
||||
createGlobalConsole());
|
||||
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
|
||||
index 13ea68c96fd415f976aab0f291a1b7c688db1c58..0ca3de08fffb344c0330ce0f8d28b2d3d0b24350 100644
|
||||
--- a/lib/internal/bootstrap/node.js
|
||||
+++ b/lib/internal/bootstrap/node.js
|
||||
@@ -238,10 +238,6 @@ const {
|
||||
queueMicrotask,
|
||||
} = require('internal/process/task_queues');
|
||||
|
||||
-// Non-standard extensions:
|
||||
-const { BroadcastChannel } = require('internal/worker/io');
|
||||
-exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
|
||||
-
|
||||
defineOperation(globalThis, 'queueMicrotask', queueMicrotask);
|
||||
|
||||
const timers = require('timers');
|
||||
@@ -0,0 +1,171 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tim Perry <pimterry@gmail.com>
|
||||
Date: Thu, 24 Aug 2023 16:05:02 +0100
|
||||
Subject: net: fix crash due to simultaneous close/shutdown on JS Stream
|
||||
Sockets
|
||||
|
||||
A JS stream socket wraps a stream, exposing it as a socket for something
|
||||
on top which needs a socket specifically (e.g. an HTTP server).
|
||||
|
||||
If the internal stream is closed in the same tick as the layer on top
|
||||
attempts to close this stream, the race between doShutdown and doClose
|
||||
results in an uncatchable exception. A similar race can happen with
|
||||
doClose and doWrite.
|
||||
|
||||
It seems legitimate these can happen in parallel, so this resolves that
|
||||
by explicitly detecting and handling that situation: if a close is in
|
||||
progress, both doShutdown & doWrite allow doClose to run
|
||||
finishShutdown/Write for them, cancelling the operation, without trying
|
||||
to use this._handle (which will be null) in the meantime.
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/49400
|
||||
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
||||
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
|
||||
|
||||
diff --git a/lib/internal/js_stream_socket.js b/lib/internal/js_stream_socket.js
|
||||
index 8bc19296620b3fd0e5487165743f0f1bc2d342e7..68e1802a63b012b59418b79a0e68de5147543a23 100644
|
||||
--- a/lib/internal/js_stream_socket.js
|
||||
+++ b/lib/internal/js_stream_socket.js
|
||||
@@ -21,6 +21,7 @@ const { ERR_STREAM_WRAP } = require('internal/errors').codes;
|
||||
const kCurrentWriteRequest = Symbol('kCurrentWriteRequest');
|
||||
const kCurrentShutdownRequest = Symbol('kCurrentShutdownRequest');
|
||||
const kPendingShutdownRequest = Symbol('kPendingShutdownRequest');
|
||||
+const kPendingClose = Symbol('kPendingClose');
|
||||
|
||||
function isClosing() { return this[owner_symbol].isClosing(); }
|
||||
|
||||
@@ -94,6 +95,7 @@ class JSStreamSocket extends Socket {
|
||||
this[kCurrentWriteRequest] = null;
|
||||
this[kCurrentShutdownRequest] = null;
|
||||
this[kPendingShutdownRequest] = null;
|
||||
+ this[kPendingClose] = false;
|
||||
this.readable = stream.readable;
|
||||
this.writable = stream.writable;
|
||||
|
||||
@@ -135,10 +137,17 @@ class JSStreamSocket extends Socket {
|
||||
this[kPendingShutdownRequest] = req;
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
assert(this[kCurrentWriteRequest] === null);
|
||||
assert(this[kCurrentShutdownRequest] === null);
|
||||
this[kCurrentShutdownRequest] = req;
|
||||
|
||||
+ if (this[kPendingClose]) {
|
||||
+ // If doClose is pending, the stream & this._handle are gone. We can't do
|
||||
+ // anything. doClose will call finishShutdown with ECANCELED for us shortly.
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
const handle = this._handle;
|
||||
|
||||
process.nextTick(() => {
|
||||
@@ -164,6 +173,13 @@ class JSStreamSocket extends Socket {
|
||||
assert(this[kCurrentWriteRequest] === null);
|
||||
assert(this[kCurrentShutdownRequest] === null);
|
||||
|
||||
+ if (this[kPendingClose]) {
|
||||
+ // If doClose is pending, the stream & this._handle are gone. We can't do
|
||||
+ // anything. doClose will call finishWrite with ECANCELED for us shortly.
|
||||
+ this[kCurrentWriteRequest] = req; // Store req, for doClose to cancel
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
const handle = this._handle;
|
||||
const self = this;
|
||||
|
||||
@@ -217,6 +233,8 @@ class JSStreamSocket extends Socket {
|
||||
}
|
||||
|
||||
doClose(cb) {
|
||||
+ this[kPendingClose] = true;
|
||||
+
|
||||
const handle = this._handle;
|
||||
|
||||
// When sockets of the "net" module destroyed, they will call
|
||||
@@ -234,6 +252,8 @@ class JSStreamSocket extends Socket {
|
||||
this.finishWrite(handle, uv.UV_ECANCELED);
|
||||
this.finishShutdown(handle, uv.UV_ECANCELED);
|
||||
|
||||
+ this[kPendingClose] = false;
|
||||
+
|
||||
cb();
|
||||
});
|
||||
}
|
||||
diff --git a/test/parallel/test-http2-client-connection-tunnelling.js b/test/parallel/test-http2-client-connection-tunnelling.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6e04121ca71ea81f49c7f50ec11d7fac735c80a9
|
||||
--- /dev/null
|
||||
+++ b/test/parallel/test-http2-client-connection-tunnelling.js
|
||||
@@ -0,0 +1,71 @@
|
||||
+'use strict';
|
||||
+
|
||||
+const common = require('../common');
|
||||
+const fixtures = require('../common/fixtures');
|
||||
+if (!common.hasCrypto)
|
||||
+ common.skip('missing crypto');
|
||||
+const assert = require('assert');
|
||||
+const net = require('net');
|
||||
+const tls = require('tls');
|
||||
+const h2 = require('http2');
|
||||
+
|
||||
+// This test sets up an H2 proxy server, and tunnels a request over one of its streams
|
||||
+// back to itself, via TLS, and then closes the TLS connection. On some Node versions
|
||||
+// (v18 & v20 up to 20.5.1) the resulting JS Stream Socket fails to shutdown correctly
|
||||
+// in this case, and crashes due to a null pointer in finishShutdown.
|
||||
+
|
||||
+const tlsOptions = {
|
||||
+ key: fixtures.readKey('agent1-key.pem'),
|
||||
+ cert: fixtures.readKey('agent1-cert.pem'),
|
||||
+ ALPNProtocols: ['h2']
|
||||
+};
|
||||
+
|
||||
+const netServer = net.createServer((socket) => {
|
||||
+ socket.allowHalfOpen = false;
|
||||
+ // ^ This allows us to trigger this reliably, but it's not strictly required
|
||||
+ // for the bug and crash to happen, skipping this just fails elsewhere later.
|
||||
+
|
||||
+ h2Server.emit('connection', socket);
|
||||
+});
|
||||
+
|
||||
+const h2Server = h2.createSecureServer(tlsOptions, (req, res) => {
|
||||
+ res.writeHead(200);
|
||||
+ res.end();
|
||||
+});
|
||||
+
|
||||
+h2Server.on('connect', (req, res) => {
|
||||
+ res.writeHead(200, {});
|
||||
+ netServer.emit('connection', res.stream);
|
||||
+});
|
||||
+
|
||||
+netServer.listen(0, common.mustCall(() => {
|
||||
+ const proxyClient = h2.connect(`https://localhost:${netServer.address().port}`, {
|
||||
+ rejectUnauthorized: false
|
||||
+ });
|
||||
+
|
||||
+ const proxyReq = proxyClient.request({
|
||||
+ ':method': 'CONNECT',
|
||||
+ ':authority': 'example.com:443'
|
||||
+ });
|
||||
+
|
||||
+ proxyReq.on('response', common.mustCall((response) => {
|
||||
+ assert.strictEqual(response[':status'], 200);
|
||||
+
|
||||
+ // Create a TLS socket within the tunnel, and start sending a request:
|
||||
+ const tlsSocket = tls.connect({
|
||||
+ socket: proxyReq,
|
||||
+ ALPNProtocols: ['h2'],
|
||||
+ rejectUnauthorized: false
|
||||
+ });
|
||||
+
|
||||
+ proxyReq.on('close', common.mustCall(() => {
|
||||
+ proxyClient.close();
|
||||
+ netServer.close();
|
||||
+ }));
|
||||
+
|
||||
+ // Forcibly kill the TLS socket
|
||||
+ tlsSocket.destroy();
|
||||
+
|
||||
+ // This results in an async error in affected Node versions, before the 'close' event
|
||||
+ }));
|
||||
+}));
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tim Perry <pimterry@gmail.com>
|
||||
Date: Fri, 25 Aug 2023 14:16:35 +0100
|
||||
Subject: net: use asserts in JS Socket Stream to catch races in future
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/49400
|
||||
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
||||
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
|
||||
|
||||
diff --git a/lib/internal/js_stream_socket.js b/lib/internal/js_stream_socket.js
|
||||
index 68e1802a63b012b59418b79a0e68de5147543a23..70d6d03069f3f1e85e66864c6c1e6de6084f5ea6 100644
|
||||
--- a/lib/internal/js_stream_socket.js
|
||||
+++ b/lib/internal/js_stream_socket.js
|
||||
@@ -149,6 +149,7 @@ class JSStreamSocket extends Socket {
|
||||
}
|
||||
|
||||
const handle = this._handle;
|
||||
+ assert(handle !== null);
|
||||
|
||||
process.nextTick(() => {
|
||||
// Ensure that write is dispatched asynchronously.
|
||||
@@ -181,6 +182,8 @@ class JSStreamSocket extends Socket {
|
||||
}
|
||||
|
||||
const handle = this._handle;
|
||||
+ assert(handle !== null);
|
||||
+
|
||||
const self = this;
|
||||
|
||||
let pending = bufs.length;
|
||||
28
patches/node/test_deflake_test-tls-socket-close.patch
Normal file
28
patches/node/test_deflake_test-tls-socket-close.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Luigi Pinca <luigipinca@gmail.com>
|
||||
Date: Wed, 13 Sep 2023 08:04:39 +0200
|
||||
Subject: test: deflake test-tls-socket-close
|
||||
|
||||
Move the check for the destroyed state of the remote socket to the inner
|
||||
`setImmediate()`.
|
||||
|
||||
Refs: https://github.com/nodejs/node/pull/49327#issuecomment-1712525257
|
||||
PR-URL: https://github.com/nodejs/node/pull/49575
|
||||
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
|
||||
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
|
||||
|
||||
diff --git a/test/parallel/test-tls-socket-close.js b/test/parallel/test-tls-socket-close.js
|
||||
index 667b291309a4c5636a2c658fa8204b32c2e4df46..70af760d53bb4ddab62c99180d505e943ec269f6 100644
|
||||
--- a/test/parallel/test-tls-socket-close.js
|
||||
+++ b/test/parallel/test-tls-socket-close.js
|
||||
@@ -44,9 +44,9 @@ function connectClient(server) {
|
||||
|
||||
setImmediate(() => {
|
||||
assert.strictEqual(netSocket.destroyed, true);
|
||||
- assert.strictEqual(clientTlsSocket.destroyed, true);
|
||||
|
||||
setImmediate(() => {
|
||||
+ assert.strictEqual(clientTlsSocket.destroyed, true);
|
||||
assert.strictEqual(serverTlsSocket.destroyed, true);
|
||||
|
||||
tlsServer.close();
|
||||
@@ -7,10 +7,10 @@ Instead of disabling the tests, flag them as flaky so they still run
|
||||
but don't cause CI failures on flakes.
|
||||
|
||||
diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status
|
||||
index 1cbcefb9712fae45b9a0ec7ed361bfe4ec7790be..6a6b52e9ae4150e7215e3587d8ddb41ce4374780 100644
|
||||
index 1cbcefb9712fae45b9a0ec7ed361bfe4ec7790be..8494423d152c5d4f1bf5162a544c61bdba2a5c5c 100644
|
||||
--- a/test/parallel/parallel.status
|
||||
+++ b/test/parallel/parallel.status
|
||||
@@ -5,6 +5,12 @@ prefix parallel
|
||||
@@ -5,6 +5,13 @@ prefix parallel
|
||||
# sample-test : PASS,FLAKY
|
||||
|
||||
[true] # This section applies to all platforms
|
||||
@@ -20,6 +20,7 @@ index 1cbcefb9712fae45b9a0ec7ed361bfe4ec7790be..6a6b52e9ae4150e7215e3587d8ddb41c
|
||||
+test-fetch: PASS, FLAKY
|
||||
+test-cluster-bind-privileged-port: PASS, FLAKY
|
||||
+test-cluster-shared-handle-bind-privileged-port: PASS, FLAKY
|
||||
+test-debugger-random-port-with-inspect-port: PASS, FLAKY
|
||||
|
||||
[$system==win32]
|
||||
# https://github.com/nodejs/node/issues/24497
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tim Perry <1526883+pimterry@users.noreply.github.com>
|
||||
Date: Fri, 1 Sep 2023 09:00:05 +0200
|
||||
Subject: tls: ensure TLS Sockets are closed if the underlying wrap closes
|
||||
|
||||
This fixes a potential segfault, among various other likely-related
|
||||
issues, which all occur because TLSSockets were not informed if their
|
||||
underlying stream was closed in many cases.
|
||||
|
||||
This also significantly modifies an existing TLS test. With this change
|
||||
in place, that test no longer works, as it tries to mess with internals
|
||||
to trigger a race, and those internals are now cleaned up earlier. This
|
||||
test has been simplified to a more general TLS shutdown test.
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/49327
|
||||
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
||||
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
|
||||
|
||||
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
|
||||
index 819dac9c431a8b50b5da8944fecaa6c4e56662b5..93025fe09e13d78ddf3d95263dfd90ebac96b3e6 100644
|
||||
--- a/lib/_tls_wrap.js
|
||||
+++ b/lib/_tls_wrap.js
|
||||
@@ -629,6 +629,9 @@ TLSSocket.prototype._wrapHandle = function(wrap, handle) {
|
||||
defineHandleReading(this, handle);
|
||||
|
||||
this.on('close', onSocketCloseDestroySSL);
|
||||
+ if (wrap) {
|
||||
+ wrap.on('close', () => this.destroy());
|
||||
+ }
|
||||
|
||||
return res;
|
||||
};
|
||||
diff --git a/test/parallel/test-http2-socket-close.js b/test/parallel/test-http2-socket-close.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..02db77bcf8480c79c77175ba802f9fe10ffc4efe
|
||||
--- /dev/null
|
||||
+++ b/test/parallel/test-http2-socket-close.js
|
||||
@@ -0,0 +1,67 @@
|
||||
+'use strict';
|
||||
+
|
||||
+const common = require('../common');
|
||||
+const fixtures = require('../common/fixtures');
|
||||
+if (!common.hasCrypto)
|
||||
+ common.skip('missing crypto');
|
||||
+const assert = require('assert');
|
||||
+const net = require('net');
|
||||
+const h2 = require('http2');
|
||||
+
|
||||
+const tlsOptions = {
|
||||
+ key: fixtures.readKey('agent1-key.pem'),
|
||||
+ cert: fixtures.readKey('agent1-cert.pem'),
|
||||
+ ALPNProtocols: ['h2']
|
||||
+};
|
||||
+
|
||||
+// Create a net server that upgrades sockets to HTTP/2 manually, handles the
|
||||
+// request, and then shuts down via a short socket timeout and a longer H2 session
|
||||
+// timeout. This is an unconventional way to shut down a session (the underlying
|
||||
+// socket closing first) but it should work - critically, it shouldn't segfault
|
||||
+// (as it did until Node v20.5.1).
|
||||
+
|
||||
+let serverRawSocket;
|
||||
+let serverH2Session;
|
||||
+
|
||||
+const netServer = net.createServer((socket) => {
|
||||
+ serverRawSocket = socket;
|
||||
+ h2Server.emit('connection', socket);
|
||||
+});
|
||||
+
|
||||
+const h2Server = h2.createSecureServer(tlsOptions, (req, res) => {
|
||||
+ res.writeHead(200);
|
||||
+ res.end();
|
||||
+});
|
||||
+
|
||||
+h2Server.on('session', (session) => {
|
||||
+ serverH2Session = session;
|
||||
+});
|
||||
+
|
||||
+netServer.listen(0, common.mustCall(() => {
|
||||
+ const proxyClient = h2.connect(`https://localhost:${netServer.address().port}`, {
|
||||
+ rejectUnauthorized: false
|
||||
+ });
|
||||
+
|
||||
+ proxyClient.on('close', common.mustCall(() => {
|
||||
+ netServer.close();
|
||||
+ }));
|
||||
+
|
||||
+ const req = proxyClient.request({
|
||||
+ ':method': 'GET',
|
||||
+ ':path': '/'
|
||||
+ });
|
||||
+
|
||||
+ req.on('response', common.mustCall((response) => {
|
||||
+ assert.strictEqual(response[':status'], 200);
|
||||
+
|
||||
+ // Asynchronously shut down the server's connections after the response,
|
||||
+ // but not in the order it typically expects:
|
||||
+ setTimeout(() => {
|
||||
+ serverRawSocket.destroy();
|
||||
+
|
||||
+ setTimeout(() => {
|
||||
+ serverH2Session.close();
|
||||
+ }, 10);
|
||||
+ }, 10);
|
||||
+ }));
|
||||
+}));
|
||||
diff --git a/test/parallel/test-tls-socket-close.js b/test/parallel/test-tls-socket-close.js
|
||||
index 87355cf8d7bd2d07bb0fab59491b68f3963f8809..667b291309a4c5636a2c658fa8204b32c2e4df46 100644
|
||||
--- a/test/parallel/test-tls-socket-close.js
|
||||
+++ b/test/parallel/test-tls-socket-close.js
|
||||
@@ -8,37 +8,18 @@ const tls = require('tls');
|
||||
const net = require('net');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
-// Regression test for https://github.com/nodejs/node/issues/8074
|
||||
-//
|
||||
-// This test has a dependency on the order in which the TCP connection is made,
|
||||
-// and TLS server handshake completes. It assumes those server side events occur
|
||||
-// before the client side write callback, which is not guaranteed by the TLS
|
||||
-// API. It usually passes with TLS1.3, but TLS1.3 didn't exist at the time the
|
||||
-// bug existed.
|
||||
-//
|
||||
-// Pin the test to TLS1.2, since the test shouldn't be changed in a way that
|
||||
-// doesn't trigger a segfault in Node.js 7.7.3:
|
||||
-// https://github.com/nodejs/node/issues/13184#issuecomment-303700377
|
||||
-tls.DEFAULT_MAX_VERSION = 'TLSv1.2';
|
||||
-
|
||||
const key = fixtures.readKey('agent2-key.pem');
|
||||
const cert = fixtures.readKey('agent2-cert.pem');
|
||||
|
||||
-let tlsSocket;
|
||||
-// tls server
|
||||
+let serverTlsSocket;
|
||||
const tlsServer = tls.createServer({ cert, key }, (socket) => {
|
||||
- tlsSocket = socket;
|
||||
- socket.on('error', common.mustCall((error) => {
|
||||
- assert.strictEqual(error.code, 'EINVAL');
|
||||
- tlsServer.close();
|
||||
- netServer.close();
|
||||
- }));
|
||||
+ serverTlsSocket = socket;
|
||||
});
|
||||
|
||||
+// A plain net server, that manually passes connections to the TLS
|
||||
+// server to be upgraded
|
||||
let netSocket;
|
||||
-// plain tcp server
|
||||
const netServer = net.createServer((socket) => {
|
||||
- // If client wants to use tls
|
||||
tlsServer.emit('connection', socket);
|
||||
|
||||
netSocket = socket;
|
||||
@@ -46,35 +27,32 @@ const netServer = net.createServer((socket) => {
|
||||
connectClient(netServer);
|
||||
}));
|
||||
|
||||
+// A client that connects, sends one message, and closes the raw connection:
|
||||
function connectClient(server) {
|
||||
- const tlsConnection = tls.connect({
|
||||
+ const clientTlsSocket = tls.connect({
|
||||
host: 'localhost',
|
||||
port: server.address().port,
|
||||
rejectUnauthorized: false
|
||||
});
|
||||
|
||||
- tlsConnection.write('foo', 'utf8', common.mustCall(() => {
|
||||
+ clientTlsSocket.write('foo', 'utf8', common.mustCall(() => {
|
||||
assert(netSocket);
|
||||
netSocket.setTimeout(common.platformTimeout(10), common.mustCall(() => {
|
||||
- assert(tlsSocket);
|
||||
- // This breaks if TLSSocket is already managing the socket:
|
||||
+ assert(serverTlsSocket);
|
||||
+
|
||||
netSocket.destroy();
|
||||
- const interval = setInterval(() => {
|
||||
- // Checking this way allows us to do the write at a time that causes a
|
||||
- // segmentation fault (not always, but often) in Node.js 7.7.3 and
|
||||
- // earlier. If we instead, for example, wait on the `close` event, then
|
||||
- // it will not segmentation fault, which is what this test is all about.
|
||||
- if (tlsSocket._handle._parent.bytesRead === 0) {
|
||||
- tlsSocket.write('bar');
|
||||
- clearInterval(interval);
|
||||
- }
|
||||
- }, 1);
|
||||
+
|
||||
+ setImmediate(() => {
|
||||
+ assert.strictEqual(netSocket.destroyed, true);
|
||||
+ assert.strictEqual(clientTlsSocket.destroyed, true);
|
||||
+
|
||||
+ setImmediate(() => {
|
||||
+ assert.strictEqual(serverTlsSocket.destroyed, true);
|
||||
+
|
||||
+ tlsServer.close();
|
||||
+ netServer.close();
|
||||
+ });
|
||||
+ });
|
||||
}));
|
||||
}));
|
||||
- tlsConnection.on('error', (e) => {
|
||||
- // Tolerate the occasional ECONNRESET.
|
||||
- // Ref: https://github.com/nodejs/node/issues/13184
|
||||
- if (e.code !== 'ECONNRESET')
|
||||
- throw e;
|
||||
- });
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user