mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
543f7c3fdb | ||
|
|
e51dee4e81 | ||
|
|
384f44d042 | ||
|
|
edb117a239 | ||
|
|
3f864b28a0 | ||
|
|
97bf8c8325 | ||
|
|
4a9b36703b | ||
|
|
0508e25549 | ||
|
|
0641412e98 | ||
|
|
c574fedc84 | ||
|
|
3cb87f49ad | ||
|
|
94586037cd | ||
|
|
d6cea5fc0c | ||
|
|
0284dfb2a9 | ||
|
|
2c07dab03a | ||
|
|
b3912c65ff | ||
|
|
0641a85498 | ||
|
|
cec0e9c871 | ||
|
|
63883adbe0 | ||
|
|
f22a5b80eb | ||
|
|
6e36eba667 | ||
|
|
693c9d7484 | ||
|
|
f08d5f1e02 | ||
|
|
ec4c609e4f | ||
|
|
89d57368d8 | ||
|
|
e0b1723dd1 | ||
|
|
7698575651 | ||
|
|
baf3081e1d | ||
|
|
d49364fa53 | ||
|
|
04af0337bc | ||
|
|
08dd28204b | ||
|
|
09bb5eef2a | ||
|
|
faae88d0fe | ||
|
|
3484a5606e | ||
|
|
0cc1893c8c | ||
|
|
88604f2fb8 | ||
|
|
144a70b1d1 | ||
|
|
e2d17db85b | ||
|
|
ae9593d0e4 | ||
|
|
e239cf9ac5 | ||
|
|
ccca1cf5ab | ||
|
|
348243e7e5 | ||
|
|
bcffbb1c7e | ||
|
|
a5fc0c139d | ||
|
|
491358e18e | ||
|
|
115e4976da | ||
|
|
be3a3d554d | ||
|
|
549221d0f1 | ||
|
|
34e961a6dd | ||
|
|
92ac9267f0 | ||
|
|
6a20f61102 | ||
|
|
2136769836 | ||
|
|
c998d2fb41 | ||
|
|
fa768aa749 | ||
|
|
f7e22ed743 | ||
|
|
437bf7d1fd | ||
|
|
d0b2a4e48f | ||
|
|
192295697e | ||
|
|
e47bdb67f8 | ||
|
|
25dee92c57 | ||
|
|
053031e96c | ||
|
|
1e64527ec3 | ||
|
|
1645aece38 | ||
|
|
1f66b20392 |
@@ -65,6 +65,9 @@ jobs:
|
||||
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/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 >>
|
||||
@@ -247,19 +259,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
|
||||
@@ -347,7 +359,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
|
||||
@@ -730,8 +742,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
|
||||
$GOMA_DIR/goma_ctl.py stat
|
||||
$GOMA_DIR/diagnose_goma_log.py
|
||||
true
|
||||
when: always
|
||||
background: true
|
||||
@@ -883,14 +895,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
|
||||
@@ -903,6 +927,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
|
||||
@@ -920,6 +950,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
|
||||
@@ -957,7 +993,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:
|
||||
@@ -967,7 +1003,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:
|
||||
@@ -993,15 +1039,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
|
||||
@@ -1013,11 +1050,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
|
||||
@@ -1027,23 +1145,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:
|
||||
@@ -1158,12 +1297,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: |
|
||||
@@ -1301,6 +1444,8 @@ commands:
|
||||
after-persist:
|
||||
type: steps
|
||||
default: []
|
||||
could-be-aks:
|
||||
type: boolean
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.attach >>
|
||||
@@ -1318,7 +1463,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:
|
||||
@@ -1334,8 +1480,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:
|
||||
@@ -1351,7 +1504,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
|
||||
@@ -1401,9 +1559,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 >>
|
||||
@@ -1455,6 +1623,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:
|
||||
@@ -1592,6 +1772,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
|
||||
@@ -1650,7 +1831,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'
|
||||
@@ -1663,6 +1844,7 @@ jobs:
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: true
|
||||
|
||||
mac-checkout:
|
||||
executor:
|
||||
@@ -1682,6 +1864,7 @@ jobs:
|
||||
restore-src-cache: false
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: false
|
||||
|
||||
mac-make-src-cache:
|
||||
executor:
|
||||
@@ -1701,12 +1884,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
|
||||
@@ -1719,11 +1903,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
|
||||
@@ -1734,15 +1919,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
|
||||
@@ -1755,21 +1942,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
|
||||
@@ -1792,7 +1982,7 @@ jobs:
|
||||
linux-arm-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-arm
|
||||
@@ -1808,11 +1998,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
|
||||
@@ -1837,7 +2028,7 @@ jobs:
|
||||
linux-arm64-testing:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: 2xlarge
|
||||
size: << pipeline.parameters.large-linux-executor >>
|
||||
environment:
|
||||
<<: *env-global
|
||||
<<: *env-arm64
|
||||
@@ -1853,22 +2044,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
|
||||
@@ -1923,6 +2117,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- generated_artifacts_mas-x64
|
||||
could-be-aks: false
|
||||
|
||||
osx-testing-x64-gn-check:
|
||||
executor:
|
||||
@@ -1932,7 +2127,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:
|
||||
@@ -2015,6 +2212,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
|
||||
|
||||
@@ -16,6 +16,8 @@ ln -s $buildtools_configs $buildtools/configs
|
||||
|
||||
# Write the gclient config if it does not already exist
|
||||
if [ ! -f $gclient_root/.gclient ]; then
|
||||
echo "Creating gclient config"
|
||||
|
||||
echo "solutions = [
|
||||
{ \"name\" : \"src/electron\",
|
||||
\"url\" : \"https://github.com/electron/electron\",
|
||||
@@ -32,6 +34,8 @@ fi
|
||||
# Write the default buildtools config file if it does
|
||||
# not already exist
|
||||
if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
echo "Creating build-tools testing config"
|
||||
|
||||
write_config() {
|
||||
echo "
|
||||
{
|
||||
@@ -53,7 +57,7 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
\"CHROMIUM_BUILDTOOLS_PATH\": \"/workspaces/gclient/src/buildtools\",
|
||||
\"GIT_CACHE_PATH\": \"/workspaces/gclient/.git-cache\"
|
||||
},
|
||||
\"$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\"
|
||||
\"\$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\"
|
||||
}
|
||||
" >$buildtools/configs/evm.testing.json
|
||||
}
|
||||
@@ -67,10 +71,12 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
# if it works we can use the goma cluster
|
||||
export NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN
|
||||
if e d goma_auth login; then
|
||||
echo "$GITHUB_USER has GOMA access - switching to cluster mode"
|
||||
write_config cluster
|
||||
fi
|
||||
else
|
||||
# Even if the config file existed we still need to re-auth with the goma
|
||||
# cluster
|
||||
echo "build-tools testing config already exists"
|
||||
|
||||
# Re-auth with the goma cluster regardless.
|
||||
NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN e d goma_auth login || true
|
||||
fi
|
||||
|
||||
@@ -49,6 +49,11 @@ environment:
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: base-woa
|
||||
APPVEYOR_BUILD_WORKER_CLOUD: electronhq-woa
|
||||
|
||||
clone_script:
|
||||
- ps: git clone -q $("--branch=" + $Env:APPVEYOR_REPO_BRANCH) $("https://github.com/" + $Env:APPVEYOR_REPO_NAME + ".git") $Env:APPVEYOR_BUILD_FOLDER
|
||||
- ps: if (!$Env:APPVEYOR_PULL_REQUEST_NUMBER) {$("git checkout -qf " + $Env:APPVEYOR_REPO_COMMIT)}
|
||||
- ps: if ($Env:APPVEYOR_PULL_REQUEST_NUMBER) {git fetch -q origin +refs/pull/$($Env:APPVEYOR_PULL_REQUEST_NUMBER)/head; git checkout -qf FETCH_HEAD}
|
||||
|
||||
clone_folder: C:\projects\src\electron
|
||||
|
||||
skip_branch_with_pr: true
|
||||
@@ -67,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
|
||||
@@ -85,6 +92,8 @@ for:
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- ps: New-Item -Name depot_tools\.disable_auto_update -ItemType File
|
||||
- depot_tools\bootstrap\win_tools.bat
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
@@ -107,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 {
|
||||
@@ -157,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
|
||||
@@ -178,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
|
||||
@@ -203,7 +236,7 @@ for:
|
||||
- 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)
|
||||
- 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
|
||||
@@ -236,7 +269,7 @@ for:
|
||||
# Download build artifacts
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID"
|
||||
$artifacts_to_download = @('dist.zip','ffmpeg.zip','node_headers.zip','pdb.zip','electron.lib')
|
||||
$artifacts_to_download = @('dist.zip','ffmpeg.zip','node_headers.zip','electron.lib')
|
||||
foreach ($job in $build_info.build.jobs) {
|
||||
if ($job.name -eq "Build Arm on X64 Windows") {
|
||||
$jobId = $job.jobId
|
||||
@@ -248,10 +281,13 @@ for:
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
|
||||
}
|
||||
# Uncomment the following lines to download the pdb.zip to show real stacktraces when crashes happen during testing
|
||||
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/pdb.zip" -OutFile pdb.zip
|
||||
# 7z x -y -osrc pdb.zip
|
||||
}
|
||||
}
|
||||
- ps: |
|
||||
$out_default_zips = @('dist.zip','pdb.zip')
|
||||
$out_default_zips = @('dist.zip')
|
||||
foreach($zip_name in $out_default_zips) {
|
||||
7z x -y -osrc\out\Default $zip_name
|
||||
}
|
||||
|
||||
44
appveyor.yml
44
appveyor.yml
@@ -47,6 +47,11 @@ environment:
|
||||
- job_name: Test
|
||||
job_depends_on: Build
|
||||
|
||||
clone_script:
|
||||
- ps: git clone -q $("--branch=" + $Env:APPVEYOR_REPO_BRANCH) $("https://github.com/" + $Env:APPVEYOR_REPO_NAME + ".git") $Env:APPVEYOR_BUILD_FOLDER
|
||||
- ps: if (!$Env:APPVEYOR_PULL_REQUEST_NUMBER) {$("git checkout -qf " + $Env:APPVEYOR_REPO_COMMIT)}
|
||||
- ps: if ($Env:APPVEYOR_PULL_REQUEST_NUMBER) {git fetch -q origin +refs/pull/$($Env:APPVEYOR_PULL_REQUEST_NUMBER)/head; git checkout -qf FETCH_HEAD}
|
||||
|
||||
clone_folder: C:\projects\src\electron
|
||||
|
||||
skip_branch_with_pr: true
|
||||
@@ -65,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
|
||||
@@ -83,6 +90,8 @@ for:
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- ps: New-Item -Name depot_tools\.disable_auto_update -ItemType File
|
||||
- depot_tools\bootstrap\win_tools.bat
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
@@ -105,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 {
|
||||
@@ -155,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
|
||||
@@ -176,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
|
||||
@@ -201,7 +234,7 @@ for:
|
||||
- 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)
|
||||
- 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
|
||||
@@ -244,6 +277,9 @@ for:
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
|
||||
}
|
||||
# Uncomment the following lines to download the pdb.zip to show real stacktraces when crashes happen during testing
|
||||
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/pdb.zip" -OutFile pdb.zip
|
||||
# 7z x -y -osrc pdb.zip
|
||||
}
|
||||
}
|
||||
- ps: |
|
||||
|
||||
@@ -402,18 +402,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `details` Object
|
||||
* `reason` string - The reason the render process is gone. Possible values:
|
||||
* `clean-exit` - Process exited with an exit code of zero
|
||||
* `abnormal-exit` - Process exited with a non-zero exit code
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failed` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
* `exitCode` Integer - The exit code of the process, unless `reason` is
|
||||
`launch-failed`, in which case `exitCode` will be a platform-specific
|
||||
launch failure error code.
|
||||
* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md)
|
||||
|
||||
Emitted when the renderer process unexpectedly disappears. This is normally
|
||||
because it was crashed or killed.
|
||||
|
||||
@@ -1110,10 +1110,14 @@ win.setBounds({ width: 100 })
|
||||
console.log(win.getBounds())
|
||||
```
|
||||
|
||||
**Note:** On macOS, the y-coordinate value cannot be smaller than the [Tray](tray.md) height. The tray height has changed over time and depends on the operating system, but is between 20-40px. Passing a value lower than the tray height will result in a window that is flush to the tray.
|
||||
|
||||
#### `win.getBounds()`
|
||||
|
||||
Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`.
|
||||
|
||||
**Note:** On macOS, the y-coordinate value returned will be at minimum the [Tray](tray.md) height. For example, calling `win.setBounds({ x: 25, y: 20, width: 800, height: 600 })` with a tray height of 38 means that `win.getBounds()` will return `{ x: 25, y: 38, width: 800, height: 600 }`.
|
||||
|
||||
#### `win.getBackgroundColor()`
|
||||
|
||||
Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format.
|
||||
|
||||
@@ -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,28 @@ 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).
|
||||
|
||||
[app]: app.md
|
||||
[append-switch]: command-line.md#commandlineappendswitchswitch-value
|
||||
[debugging-main-process]: ../tutorial/debugging-main-process.md
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -822,18 +822,19 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `permission` string - The type of requested permission.
|
||||
* `clipboard-read` - Request access to read from the clipboard.
|
||||
* `clipboard-sanitized-write` - Request access to write to the clipboard.
|
||||
* `display-capture` - Request access to capture the screen via the [Screen Capture API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Capture_API).
|
||||
* `fullscreen` - Request control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API).
|
||||
* `geolocation` - Request access to the user's location via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
|
||||
* `idle-detection` - Request access to the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector).
|
||||
* `media` - Request access to media devices such as camera, microphone and speakers.
|
||||
* `display-capture` - Request access to capture the screen.
|
||||
* `mediaKeySystem` - Request access to DRM protected content.
|
||||
* `geolocation` - Request access to user's current location.
|
||||
* `notifications` - Request notification creation and the ability to display them in the user's system tray.
|
||||
* `midi` - Request MIDI access in the `webmidi` API.
|
||||
* `midiSysex` - Request the use of system exclusive messages in the `webmidi` API.
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. These requests always appear to originate from the main frame.
|
||||
* `fullscreen` - Request for the app to enter fullscreen mode.
|
||||
* `midi` - Request MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
|
||||
* `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
|
||||
* `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification)
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
|
||||
* `unknown` - An unrecognized permission request
|
||||
* `unknown` - An unrecognized permission request.
|
||||
* `callback` Function
|
||||
* `permissionGranted` boolean - Allow or deny the permission.
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
@@ -865,7 +866,22 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
|
||||
* `handler` Function\<boolean> | null
|
||||
* `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
|
||||
* `permission` string - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, `hid`, `serial`, or `usb`.
|
||||
* `permission` string - Type of permission check.
|
||||
* `clipboard-read` - Request access to read from the clipboard.
|
||||
* `clipboard-sanitized-write` - Request access to write to the clipboard.
|
||||
* `geolocation` - Access the user's geolocation data via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
|
||||
* `fullscreen` - Control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API).
|
||||
* `hid` - Access the HID protocol to manipulate HID devices via the [WebHID API](https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API).
|
||||
* `idle-detection` - Access the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector).
|
||||
* `media` - Access to media devices such as camera, microphone and speakers.
|
||||
* `mediaKeySystem` - Access to DRM protected content.
|
||||
* `midi` - Enable MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
|
||||
* `midiSysex` - Use system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
|
||||
* `notifications` - Configure and display desktop notifications to the user with the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification).
|
||||
* `openExternal` - Open links in external applications.
|
||||
* `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API).
|
||||
* `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
|
||||
* `requestingOrigin` string - The origin URL of the permission check
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
* `embeddingOrigin` string (optional) - The origin of the frame embedding the frame that made the permission check. Only set for cross-origin sub frames making permission checks.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
* `sender` [IpcRenderer](../ipc-renderer.md) - The `IpcRenderer` instance that emitted the event originally
|
||||
* `senderId` Integer - The `webContents.id` that sent the message, you can call `event.sender.sendTo(event.senderId, ...)` to reply to the message, see [ipcRenderer.sendTo][ipc-renderer-sendto] for more information. This only applies to messages sent from a different renderer. Messages sent directly from the main process set `event.senderId` to `0`.
|
||||
* `senderIsMainFrame` boolean (optional) - Whether the message sent via [ipcRenderer.sendTo][ipc-renderer-sendto] was sent by the main frame. This is relevant when `nodeIntegrationInSubFrames` is enabled in the originating `webContents`.
|
||||
* `ports` [MessagePort][][] - A list of MessagePorts that were transferred with this message
|
||||
|
||||
[ipc-renderer-sendto]: ../ipc-renderer.md#ipcrenderersendtowebcontentsid-channel-args
|
||||
|
||||
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`.
|
||||
|
||||
@@ -373,18 +373,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.
|
||||
|
||||
@@ -938,9 +938,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'
|
||||
|
||||
|
||||
@@ -51,6 +51,12 @@ but can only import a subset of Electron and Node's built-in modules:
|
||||
* [`timers`](https://nodejs.org/api/timers.html)
|
||||
* [`url`](https://nodejs.org/api/url.html)
|
||||
|
||||
[node: imports](https://nodejs.org/api/esm.html#node-imports) are supported as well:
|
||||
|
||||
* [`node:events`](https://nodejs.org/api/events.html)
|
||||
* [`node:timers`](https://nodejs.org/api/timers.html)
|
||||
* [`node:url`](https://nodejs.org/api/url.html)
|
||||
|
||||
In addition, the preload script also polyfills certain Node.js primitives as globals:
|
||||
|
||||
* [`Buffer`](https://nodejs.org/api/buffer.html)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -27,7 +27,7 @@ const cachedArchives = new Map<string, NodeJS.AsarArchive>();
|
||||
const getOrCreateArchive = (archivePath: string) => {
|
||||
const isCached = cachedArchives.has(archivePath);
|
||||
if (isCached) {
|
||||
return cachedArchives.get(archivePath);
|
||||
return cachedArchives.get(archivePath)!;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -39,6 +39,8 @@ const getOrCreateArchive = (archivePath: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
process._getOrCreateArchive = getOrCreateArchive;
|
||||
|
||||
const asarRe = /\.asar/i;
|
||||
|
||||
// Separate asar package's path from full path.
|
||||
@@ -839,7 +841,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
const originalModuleLoad = Module._load;
|
||||
Module._load = (request: string, ...args: any[]) => {
|
||||
const loadResult = originalModuleLoad(request, ...args);
|
||||
if (request === 'child_process') {
|
||||
if (request === 'child_process' || request === 'node:child_process') {
|
||||
if (!asarReady.has(loadResult)) {
|
||||
asarReady.add(loadResult);
|
||||
// Just to make it obvious what we are dealing with here
|
||||
|
||||
@@ -317,7 +317,7 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
|
||||
if (options.preferCSSPageSize !== undefined) {
|
||||
if (typeof options.preferCSSPageSize !== 'boolean') {
|
||||
return Promise.reject(new Error('footerTemplate must be a String'));
|
||||
return Promise.reject(new Error('preferCSSPageSize must be a Boolean'));
|
||||
}
|
||||
printSettings.preferCSSPageSize = options.preferCSSPageSize;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -17,13 +17,13 @@ const isWebView = mainFrame.getWebPreference('isWebView');
|
||||
// ElectronApiServiceImpl will look for the "ipcNative" hidden object when
|
||||
// invoking the 'onMessage' callback.
|
||||
v8Util.setHiddenValue(global, 'ipcNative', {
|
||||
onMessage (internal: boolean, channel: string, ports: MessagePort[], args: any[], senderId: number) {
|
||||
onMessage (internal: boolean, channel: string, ports: MessagePort[], args: any[], senderId: number, senderIsMainFrame: boolean) {
|
||||
if (internal && senderId !== 0) {
|
||||
console.error(`Message ${channel} sent by unexpected WebContents (${senderId})`);
|
||||
return;
|
||||
}
|
||||
const sender = internal ? ipcRendererInternal : ipcRenderer;
|
||||
sender.emit(channel, { sender, senderId, ports }, ...args);
|
||||
sender.emit(channel, { sender, senderId, ...(senderId ? { senderIsMainFrame } : {}), ports }, ...args);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -33,12 +33,15 @@ const loadedModules = new Map<string, any>([
|
||||
['electron', electron],
|
||||
['electron/common', electron],
|
||||
['electron/renderer', electron],
|
||||
['events', events]
|
||||
['events', events],
|
||||
['node:events', events]
|
||||
]);
|
||||
|
||||
const loadableModules = new Map<string, Function>([
|
||||
['timers', () => require('timers')],
|
||||
['url', () => require('url')]
|
||||
['node:timers', () => require('timers')],
|
||||
['url', () => require('url')],
|
||||
['node:url', () => require('url')]
|
||||
]);
|
||||
|
||||
// Pass different process object to the preload script.
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
fix_rename_webswapcgllayer_to_webswapcgllayerchromium.patch
|
||||
cherry-pick-5486190be556.patch
|
||||
cherry-pick-e4669a74888d.patch
|
||||
|
||||
41
patches/angle/cherry-pick-5486190be556.patch
Normal file
41
patches/angle/cherry-pick-5486190be556.patch
Normal file
@@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Geoff Lang <geofflang@chromium.org>
|
||||
Date: Fri, 21 Jul 2023 13:45:52 -0400
|
||||
Subject: Fix read size validation for RGBX formats.
|
||||
|
||||
GL_RGBX8_ANGLE is the only format where the upload format is 3-channel
|
||||
RGB, whilethe download format is 4-channel RGBX. As such, the internal
|
||||
format corresponding to format+type expects 3-byte input/output. The
|
||||
format is fixed here for readPixels to output 4 bytes per pixel.
|
||||
|
||||
Bug: chromium:1458046
|
||||
Change-Id: Iec737ed64bade003cfab50dc5f595eb4875e81e4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4706957
|
||||
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
(cherry picked from commit 430a4f559cbc2bcd5d026e8b36ee46ddd80e9651)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4765136
|
||||
Commit-Queue: Daniel Yip <danielyip@google.com>
|
||||
Auto-Submit: Daniel Yip <danielyip@google.com>
|
||||
(cherry picked from commit 4a372ad49ceddea6c13f79adb212a777ec770a66)
|
||||
|
||||
diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp
|
||||
index 0b8d4eeb537690da830a0d7162e86ea1379c42b4..9e3007fa12189aa8a1bebb33e869cf5f597e04a9 100644
|
||||
--- a/src/libANGLE/formatutils.cpp
|
||||
+++ b/src/libANGLE/formatutils.cpp
|
||||
@@ -1715,7 +1715,15 @@ const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type)
|
||||
GLuint InternalFormat::computePixelBytes(GLenum formatType) const
|
||||
{
|
||||
const auto &typeInfo = GetTypeInfo(formatType);
|
||||
- GLuint components = typeInfo.specialInterpretation ? 1u : componentCount;
|
||||
+ GLuint components = componentCount;
|
||||
+ if (sizedInternalFormat == GL_RGBX8_ANGLE)
|
||||
+ {
|
||||
+ components = 4;
|
||||
+ }
|
||||
+ else if (typeInfo.specialInterpretation)
|
||||
+ {
|
||||
+ components = 1;
|
||||
+ }
|
||||
return components * typeInfo.bytes;
|
||||
}
|
||||
|
||||
395
patches/angle/cherry-pick-e4669a74888d.patch
Normal file
395
patches/angle/cherry-pick-e4669a74888d.patch
Normal file
@@ -0,0 +1,395 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Charlie Lao <cclao@google.com>
|
||||
Date: Tue, 8 Aug 2023 10:14:47 -0700
|
||||
Subject: M116: Vulkan: Fix data race with DynamicDescriptorPool
|
||||
|
||||
Right now DynamicDescriptorPool::destroyCachedDescriptorSet can be
|
||||
called from garbage clean up thread, while simultaneously accessed from
|
||||
context main thread, and data race will happen and cause bugs. This can
|
||||
only happen when the buffer is not being suballocated. In this case,
|
||||
suballocation owns the bufferBlock and bufferBlock gets destroyed when
|
||||
suballocation is destroyed from garbage collection thread. If buffer is
|
||||
suballocated, the shared group owns pool which owns bufferBlocks and
|
||||
they gets destroyed from shared group with the share group lock. This CL
|
||||
avoids this race problem by release the shared cacheKey when the buffer
|
||||
is released, while we still had the shared group lock.
|
||||
|
||||
Bug: chromium:1469542
|
||||
Change-Id: Ie6235fcfb77dee2a12b2ebde44042c3845fc0aca
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4790523
|
||||
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp
|
||||
index 0898e7d67f47b0d87476a70b9bede290d22ca87a..2957ddf5dede7ffcf7a918ba2f6c8235feb7357b 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/BufferVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp
|
||||
@@ -285,7 +285,7 @@ void BufferVk::release(ContextVk *contextVk)
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
if (mBuffer.valid())
|
||||
{
|
||||
- mBuffer.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ mBuffer.releaseBufferAndDescriptorSetCache(renderer);
|
||||
}
|
||||
if (mStagingBuffer.valid())
|
||||
{
|
||||
@@ -628,7 +628,7 @@ angle::Result BufferVk::ghostMappedBuffer(ContextVk *contextVk,
|
||||
memcpy(dstMapPtr, srcMapPtr, static_cast<size_t>(mState.getSize()));
|
||||
}
|
||||
|
||||
- src.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ src.releaseBufferAndDescriptorSetCache(contextVk->getRenderer());
|
||||
|
||||
// Return the already mapped pointer with the offset adjustment to avoid the call to unmap().
|
||||
*mapPtr = dstMapPtr + offset;
|
||||
@@ -966,7 +966,7 @@ angle::Result BufferVk::acquireAndUpdate(ContextVk *contextVk,
|
||||
|
||||
if (src.valid())
|
||||
{
|
||||
- src.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ src.releaseBufferAndDescriptorSetCache(contextVk->getRenderer());
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
@@ -1073,7 +1073,7 @@ angle::Result BufferVk::acquireBufferHelper(ContextVk *contextVk, size_t sizeInB
|
||||
|
||||
if (mBuffer.valid())
|
||||
{
|
||||
- mBuffer.releaseBufferAndDescriptorSetCache(contextVk);
|
||||
+ mBuffer.releaseBufferAndDescriptorSetCache(renderer);
|
||||
}
|
||||
|
||||
// Allocate the buffer directly
|
||||
diff --git a/src/libANGLE/renderer/vulkan/Suballocation.h b/src/libANGLE/renderer/vulkan/Suballocation.h
|
||||
index d25481bdbbb12d9377eb8ae540a8603a16e453b1..276f6b4c854df2a2a4a353f2893c4bc2df9e8502 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/Suballocation.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/Suballocation.h
|
||||
@@ -86,6 +86,13 @@ class BufferBlock final : angle::NonCopyable
|
||||
{
|
||||
mDescriptorSetCacheManager.addKey(sharedCacheKey);
|
||||
}
|
||||
+ void releaseAllCachedDescriptorSetCacheKeys(RendererVk *renderer)
|
||||
+ {
|
||||
+ if (!mDescriptorSetCacheManager.empty())
|
||||
+ {
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
private:
|
||||
mutable std::mutex mVirtualBlockMutex;
|
||||
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
index 1375e39971faff88db94c09b50b8c0db761eaba2..903def6e88e8d0f3a16f1f891429b9e088191f32 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
||||
@@ -1617,7 +1617,7 @@ void TextureVk::releaseAndDeleteImageAndViews(ContextVk *contextVk)
|
||||
|
||||
mBufferViews.release(contextVk);
|
||||
mRedefinedLevels.reset();
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(contextVk->getRenderer());
|
||||
}
|
||||
|
||||
void TextureVk::initImageUsageFlags(ContextVk *contextVk, angle::FormatID actualFormatID)
|
||||
@@ -2845,7 +2845,7 @@ angle::Result TextureVk::syncState(const gl::Context *context,
|
||||
|
||||
mBufferViews.release(contextVk);
|
||||
mBufferViews.init(renderer, offset, size);
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -3285,7 +3285,7 @@ void TextureVk::releaseImageViews(ContextVk *contextVk)
|
||||
{
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
|
||||
if (mImage == nullptr)
|
||||
{
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
|
||||
index abab85dcfb5da21630b9e8987543a09e7fb9e6c4..965e6ee4e1f8349c057e7fdbca7ebaa4593823ac 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
|
||||
@@ -2588,11 +2588,19 @@ void ReleaseCachedObject(ContextVk *contextVk, const FramebufferDesc &desc)
|
||||
{
|
||||
contextVk->getShareGroup()->getFramebufferCache().erase(contextVk, desc);
|
||||
}
|
||||
+void ReleaseCachedObject(RendererVk *renderer, const FramebufferDesc &desc)
|
||||
+{
|
||||
+ UNREACHABLE();
|
||||
+}
|
||||
|
||||
void ReleaseCachedObject(ContextVk *contextVk, const DescriptorSetDescAndPool &descAndPool)
|
||||
+{
|
||||
+ UNREACHABLE();
|
||||
+}
|
||||
+void ReleaseCachedObject(RendererVk *renderer, const DescriptorSetDescAndPool &descAndPool)
|
||||
{
|
||||
ASSERT(descAndPool.mPool != nullptr);
|
||||
- descAndPool.mPool->releaseCachedDescriptorSet(contextVk, descAndPool.mDesc);
|
||||
+ descAndPool.mPool->releaseCachedDescriptorSet(renderer, descAndPool.mDesc);
|
||||
}
|
||||
|
||||
void DestroyCachedObject(RendererVk *renderer, const FramebufferDesc &desc)
|
||||
@@ -6255,6 +6263,22 @@ void SharedCacheKeyManager<SharedCacheKeyT>::releaseKeys(ContextVk *contextVk)
|
||||
mSharedCacheKeys.clear();
|
||||
}
|
||||
|
||||
+template <class SharedCacheKeyT>
|
||||
+void SharedCacheKeyManager<SharedCacheKeyT>::releaseKeys(RendererVk *renderer)
|
||||
+{
|
||||
+ for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
|
||||
+ {
|
||||
+ if (*sharedCacheKey.get() != nullptr)
|
||||
+ {
|
||||
+ // Immediate destroy the cached object and the key itself when first releaseKeys call is
|
||||
+ // made
|
||||
+ ReleaseCachedObject(renderer, *(*sharedCacheKey.get()));
|
||||
+ *sharedCacheKey.get() = nullptr;
|
||||
+ }
|
||||
+ }
|
||||
+ mSharedCacheKeys.clear();
|
||||
+}
|
||||
+
|
||||
template <class SharedCacheKeyT>
|
||||
void SharedCacheKeyManager<SharedCacheKeyT>::destroyKeys(RendererVk *renderer)
|
||||
{
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.h b/src/libANGLE/renderer/vulkan/vk_cache_utils.h
|
||||
index 2d9784c1e0db828a5aacefa19168795da85fc5a5..c7213a1193fee21595737047e2379231039b66e9 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_cache_utils.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.h
|
||||
@@ -1937,6 +1937,7 @@ class SharedCacheKeyManager
|
||||
void addKey(const SharedCacheKeyT &key);
|
||||
// Iterate over the descriptor array and release the descriptor and cache.
|
||||
void releaseKeys(ContextVk *contextVk);
|
||||
+ void releaseKeys(RendererVk *rendererVk);
|
||||
// Iterate over the descriptor array and destroy the descriptor and cache.
|
||||
void destroyKeys(RendererVk *renderer);
|
||||
void clear();
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
index b6efd6855a819d28f60a79848dd811a347704d44..b56e78f8f5335e14826c58bfc521bd7d8e55caeb 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
|
||||
@@ -3598,7 +3598,7 @@ angle::Result DynamicDescriptorPool::allocateNewPool(Context *context)
|
||||
return mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool);
|
||||
}
|
||||
|
||||
-void DynamicDescriptorPool::releaseCachedDescriptorSet(ContextVk *contextVk,
|
||||
+void DynamicDescriptorPool::releaseCachedDescriptorSet(RendererVk *renderer,
|
||||
const DescriptorSetDesc &desc)
|
||||
{
|
||||
VkDescriptorSet descriptorSet;
|
||||
@@ -3612,7 +3612,7 @@ void DynamicDescriptorPool::releaseCachedDescriptorSet(ContextVk *contextVk,
|
||||
// Wrap it with helper object so that it can be GPU tracked and add it to resource list.
|
||||
DescriptorSetHelper descriptorSetHelper(poolOut->get().getResourceUse(), descriptorSet);
|
||||
poolOut->get().addGarbage(std::move(descriptorSetHelper));
|
||||
- checkAndReleaseUnusedPool(contextVk->getRenderer(), poolOut);
|
||||
+ checkAndReleaseUnusedPool(renderer, poolOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4807,6 +4807,12 @@ void BufferHelper::release(RendererVk *renderer)
|
||||
|
||||
if (mSuballocation.valid())
|
||||
{
|
||||
+ if (!mSuballocation.isSuballocated())
|
||||
+ {
|
||||
+ // Destroy cacheKeys now to avoid getting into situation that having to destroy
|
||||
+ // descriptorSet from garbage collection thread.
|
||||
+ mSuballocation.getBufferBlock()->releaseAllCachedDescriptorSetCacheKeys(renderer);
|
||||
+ }
|
||||
renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
|
||||
std::move(mBufferForVertexArray));
|
||||
}
|
||||
@@ -4815,17 +4821,15 @@ void BufferHelper::release(RendererVk *renderer)
|
||||
ASSERT(!mBufferForVertexArray.valid());
|
||||
}
|
||||
|
||||
-void BufferHelper::releaseBufferAndDescriptorSetCache(ContextVk *contextVk)
|
||||
+void BufferHelper::releaseBufferAndDescriptorSetCache(RendererVk *renderer)
|
||||
{
|
||||
- RendererVk *renderer = contextVk->getRenderer();
|
||||
-
|
||||
if (renderer->hasResourceUseFinished(getResourceUse()))
|
||||
{
|
||||
mDescriptorSetCacheManager.destroyKeys(renderer);
|
||||
}
|
||||
else
|
||||
{
|
||||
- mDescriptorSetCacheManager.releaseKeys(contextVk);
|
||||
+ mDescriptorSetCacheManager.releaseKeys(renderer);
|
||||
}
|
||||
|
||||
release(renderer);
|
||||
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
|
||||
index 29f7d2141fab70e0f542b05004b21701883a39c9..d81f9a4b9b07c6e34094d6d275a04c74c2652d3a 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
|
||||
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
|
||||
@@ -247,7 +247,7 @@ class DynamicDescriptorPool final : angle::NonCopyable
|
||||
VkDescriptorSet *descriptorSetOut,
|
||||
SharedDescriptorSetCacheKey *sharedCacheKeyOut);
|
||||
|
||||
- void releaseCachedDescriptorSet(ContextVk *contextVk, const DescriptorSetDesc &desc);
|
||||
+ void releaseCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc);
|
||||
void destroyCachedDescriptorSet(RendererVk *renderer, const DescriptorSetDesc &desc);
|
||||
|
||||
template <typename Accumulator>
|
||||
@@ -771,7 +771,7 @@ class BufferHelper : public ReadWriteResource
|
||||
|
||||
void destroy(RendererVk *renderer);
|
||||
void release(RendererVk *renderer);
|
||||
- void releaseBufferAndDescriptorSetCache(ContextVk *contextVk);
|
||||
+ void releaseBufferAndDescriptorSetCache(RendererVk *renderer);
|
||||
|
||||
BufferSerial getBufferSerial() const { return mSerial; }
|
||||
BufferSerial getBlockSerial() const
|
||||
diff --git a/src/tests/gl_tests/TransformFeedbackTest.cpp b/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
index ea3eeea4015dcb56f710c873b22c95d168bb287c..226eb1f049bb708e0221c81e9b836a67594eb7b0 100644
|
||||
--- a/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
+++ b/src/tests/gl_tests/TransformFeedbackTest.cpp
|
||||
@@ -507,8 +507,8 @@ TEST_P(TransformFeedbackTest, UseAsUBOThenUpdateThenCapture)
|
||||
|
||||
const std::array<uint32_t, 12> kInitialData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
const std::array<uint32_t, 12> kUpdateData = {
|
||||
- 0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u, 0x23456781u, 0xABCDEF09u,
|
||||
- 0x3579BDF1u, 0x468ACE02u, 0x34567812u, 0xBCDEF09Au, 0x579BDF13u, 0x68ACE024u,
|
||||
+ 0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u, 0x23456781u, 0xABCDEF09u,
|
||||
+ 0x3579BDF1u, 0x468ACE02u, 0x34567812u, 0xBCDEF09Au, 0x579BDF13u, 0x68ACE024u,
|
||||
};
|
||||
|
||||
GLBuffer buffer;
|
||||
@@ -3749,9 +3749,9 @@ void main()
|
||||
constexpr size_t kCapturedVaryingsCount = 3;
|
||||
constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {8, 9, 4};
|
||||
const std::vector<float> kExpected[kCapturedVaryingsCount] = {
|
||||
- {0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48},
|
||||
- {0.63, 0.66, 0.69, 0.72, 0.75, 0.78, 0.81, 0.84, 0.87},
|
||||
- {0.25, 0.5, 0.75, 1.0},
|
||||
+ {0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48},
|
||||
+ {0.63, 0.66, 0.69, 0.72, 0.75, 0.78, 0.81, 0.84, 0.87},
|
||||
+ {0.25, 0.5, 0.75, 1.0},
|
||||
};
|
||||
|
||||
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
|
||||
@@ -3848,9 +3848,9 @@ void main()
|
||||
constexpr size_t kCapturedVaryingsCount = 3;
|
||||
constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {1, 2, 1};
|
||||
const std::vector<float> kExpected[kCapturedVaryingsCount] = {
|
||||
- {0.25},
|
||||
- {0.5, 0.75},
|
||||
- {1.0},
|
||||
+ {0.25},
|
||||
+ {0.5, 0.75},
|
||||
+ {1.0},
|
||||
};
|
||||
|
||||
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_SEPARATE_ATTRIBS);
|
||||
@@ -4392,6 +4392,51 @@ TEST_P(TransformFeedbackTest, RenderOnceChangeXfbBufferRenderAgain)
|
||||
glEndTransformFeedback();
|
||||
}
|
||||
|
||||
+// Test bufferData call and transform feedback.
|
||||
+TEST_P(TransformFeedbackTest, BufferDataAndTransformFeedback)
|
||||
+{
|
||||
+ const char kVS[] = R"(#version 300 es
|
||||
+flat out highp int var;
|
||||
+void main() {
|
||||
+var = 1;
|
||||
+})";
|
||||
+
|
||||
+ const char kFS[] = R"(#version 300 es
|
||||
+flat in highp int var;
|
||||
+out highp int color;
|
||||
+void main() {
|
||||
+color = var;
|
||||
+})";
|
||||
+
|
||||
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
|
||||
+
|
||||
+ GLTexture texture;
|
||||
+ glBindTexture(GL_TEXTURE_2D, texture);
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, 1, 1);
|
||||
+
|
||||
+ GLFramebuffer fbo;
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
+ EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+
|
||||
+ constexpr int kClearColor[] = {123, 0, 0, 0};
|
||||
+ glClearBufferiv(GL_COLOR, 0, kClearColor);
|
||||
+ glDrawArrays(GL_POINTS, 0, 1);
|
||||
+
|
||||
+ const char *kVarying = "var";
|
||||
+ glTransformFeedbackVaryings(program, 1, &kVarying, GL_INTERLEAVED_ATTRIBS);
|
||||
+ glLinkProgram(program);
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+
|
||||
+ GLBuffer buffer;
|
||||
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer);
|
||||
+ glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 0x7ffc * 10000, nullptr, GL_DYNAMIC_READ);
|
||||
+ glBeginTransformFeedback(GL_POINTS);
|
||||
+ glDrawArrays(GL_POINTS, 0, 1);
|
||||
+ glEndTransformFeedback();
|
||||
+ glFlush();
|
||||
+}
|
||||
+
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTest);
|
||||
ANGLE_INSTANTIATE_TEST_ES3_AND(TransformFeedbackTest,
|
||||
ES3_VULKAN()
|
||||
diff --git a/src/tests/gl_tests/UniformBufferTest.cpp b/src/tests/gl_tests/UniformBufferTest.cpp
|
||||
index 4d005c0740d5ff918af103236aa18e8249e00acc..71b85043bd9ca49018e9ed79fa36f24f8499757e 100644
|
||||
--- a/src/tests/gl_tests/UniformBufferTest.cpp
|
||||
+++ b/src/tests/gl_tests/UniformBufferTest.cpp
|
||||
@@ -3422,6 +3422,50 @@ void main() {
|
||||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
|
||||
}
|
||||
|
||||
+// Calling BufferData and use it in a loop to force descriptorSet creation and destroy.
|
||||
+TEST_P(UniformBufferTest, BufferDataInLoop)
|
||||
+{
|
||||
+ glClear(GL_COLOR_BUFFER_BIT);
|
||||
+
|
||||
+ // Use large buffer size to get around suballocation, so that we will gets a new buffer with
|
||||
+ // bufferData call.
|
||||
+ static constexpr size_t kBufferSize = 4 * 1024 * 1024;
|
||||
+ std::vector<float> floatData;
|
||||
+ floatData.resize(kBufferSize / (sizeof(float)), 0.0f);
|
||||
+ floatData[0] = 0.5f;
|
||||
+ floatData[1] = 0.75f;
|
||||
+ floatData[2] = 0.25f;
|
||||
+ floatData[3] = 1.0f;
|
||||
+
|
||||
+ GLTexture textures[2];
|
||||
+ GLFramebuffer fbos[2];
|
||||
+ for (int i = 0; i < 2; i++)
|
||||
+ {
|
||||
+ glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
|
||||
+
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
|
||||
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[i], 0);
|
||||
+ EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
+ }
|
||||
+
|
||||
+ for (int loop = 0; loop < 10; loop++)
|
||||
+ {
|
||||
+ int i = loop & 0x1;
|
||||
+ // Switch FBO to get around deferred flush
|
||||
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
|
||||
+ glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
|
||||
+ glBufferData(GL_UNIFORM_BUFFER, kBufferSize, floatData.data(), GL_STATIC_DRAW);
|
||||
+
|
||||
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
|
||||
+ glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
|
||||
+ drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
|
||||
+ glFlush();
|
||||
+ }
|
||||
+ ASSERT_GL_NO_ERROR();
|
||||
+ EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
|
||||
+}
|
||||
+
|
||||
class WebGL2UniformBufferTest : public UniformBufferTest
|
||||
{
|
||||
protected:
|
||||
@@ -132,3 +132,16 @@ cherry-pick-94af9d13a14b.patch
|
||||
cherry-pick-ea1cd76358e0.patch
|
||||
m114_merge_fix_a_crash_caused_by_calling_trace_event.patch
|
||||
mojoipcz_copy_incoming_messages_early.patch
|
||||
base_do_not_use_va_args_twice_in_asprintf.patch
|
||||
cherry-pick-85beff6fd302.patch
|
||||
cherry-pick-60b93798c991.patch
|
||||
cherry-pick-933b9fad3a53.patch
|
||||
cherry-pick-b03973561862.patch
|
||||
cherry-pick-c60a1ab717c7.patch
|
||||
cherry-pick-aa23556ff213.patch
|
||||
networkcontext_don_t_access_url_loader_factories_during_destruction.patch
|
||||
cherry-pick-1939f7b78eda.patch
|
||||
cherry-pick-35c06406a658.patch
|
||||
cherry-pick-74a2eb9c8cb2.patch
|
||||
cherry-pick-26175b0903d8.patch
|
||||
fix_use_delegated_generic_capturer_when_available.patch
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benoit Lize <lizeb@chromium.org>
|
||||
Date: Fri, 9 Jun 2023 17:59:08 +0000
|
||||
Subject: Do not use va_args twice in asprintf()
|
||||
|
||||
(cherry picked from commit 3cff0cb19a6d01cbdd9932f43dabaaeda9c0330a)
|
||||
|
||||
Bug: 1450536
|
||||
Change-Id: Ib34d96935278869a63897f9a1c66afc98865d90f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4579347
|
||||
Reviewed-by: Egor Pasko <pasko@chromium.org>
|
||||
Commit-Queue: Benoit Lize <lizeb@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1151796}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4604070
|
||||
Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1224}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
index 621873126602463a09efca1bf1548ed10910d323..de2af6d7d54e254b9e7b8264b53d30a338fb13e8 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
@@ -123,13 +123,21 @@ SHIM_ALWAYS_EXPORT char* __wrap_getcwd(char* buffer, size_t size) {
|
||||
SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
const char* fmt,
|
||||
va_list va_args) {
|
||||
+ // There are cases where we need to use the list of arguments twice, namely
|
||||
+ // when the original buffer is too small. It is not allowed to walk the list
|
||||
+ // twice, so make a copy for the second invocation of vsnprintf().
|
||||
+ va_list va_args_copy;
|
||||
+ va_copy(va_args_copy, va_args);
|
||||
+
|
||||
constexpr int kInitialSize = 128;
|
||||
*strp = static_cast<char*>(
|
||||
malloc(kInitialSize)); // Our malloc() doesn't return nullptr.
|
||||
|
||||
int actual_size = vsnprintf(*strp, kInitialSize, fmt, va_args);
|
||||
- if (actual_size < 0)
|
||||
+ if (actual_size < 0) {
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
+ }
|
||||
*strp =
|
||||
static_cast<char*>(realloc(*strp, static_cast<size_t>(actual_size + 1)));
|
||||
|
||||
@@ -139,9 +147,14 @@ SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
//
|
||||
// This is very lightly used in Chromium in practice, see crbug.com/116558 for
|
||||
// details.
|
||||
- if (actual_size >= kInitialSize)
|
||||
- return vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt, va_args);
|
||||
-
|
||||
+ if (actual_size >= kInitialSize) {
|
||||
+ int ret = vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt,
|
||||
+ va_args_copy);
|
||||
+ va_end(va_args_copy);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
index dcf26fa5fc6d51de6276aa6fdcc4691f781c4bfd..fd46a15799864acaf58ef57315606bf515b48b15 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
@@ -734,6 +734,28 @@ TEST_F(AllocatorShimTest, InterceptVasprintf) {
|
||||
// Should not crash.
|
||||
}
|
||||
|
||||
+TEST_F(AllocatorShimTest, InterceptLongVasprintf) {
|
||||
+ char* str = nullptr;
|
||||
+ const char* lorem_ipsum =
|
||||
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. "
|
||||
+ "Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, "
|
||||
+ "ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula "
|
||||
+ "massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci "
|
||||
+ "nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit "
|
||||
+ "amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat "
|
||||
+ "in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero "
|
||||
+ "pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo "
|
||||
+ "in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue "
|
||||
+ "blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus "
|
||||
+ "et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed "
|
||||
+ "pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales "
|
||||
+ "hendrerit.";
|
||||
+ int err = asprintf(&str, "%s", lorem_ipsum);
|
||||
+ EXPECT_EQ(err, static_cast<int>(strlen(lorem_ipsum)));
|
||||
+ EXPECT_TRUE(str);
|
||||
+ free(str);
|
||||
+}
|
||||
+
|
||||
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
|
||||
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
84
patches/chromium/cherry-pick-1939f7b78eda.patch
Normal file
84
patches/chromium/cherry-pick-1939f7b78eda.patch
Normal file
@@ -0,0 +1,84 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Rune Lillesveen <futhark@chromium.org>
|
||||
Date: Thu, 24 Aug 2023 10:53:36 +0000
|
||||
Subject: Don't keep pointer to popped stack memory for :has()
|
||||
|
||||
The sibling_features pass into UpdateFeaturesFromCombinator may be
|
||||
initialized to last_compound_in_adjacent_chain_features if null. The
|
||||
outer while loop in
|
||||
AddFeaturesToInvalidationSetsForLogicalCombinationInHas() could then
|
||||
reference to the last_compound_in_adjacent_chain_features which is
|
||||
popped from the stack on every outer iteration. That caused an ASAN
|
||||
failure for reading stack memory that had been popped.
|
||||
|
||||
Instead make sure each inner iteration restarts with the same
|
||||
sibling_features pointer, which seems to have been the intent here.
|
||||
|
||||
(cherry picked from commit 5e213507a2f0d6e3c96904a710407b01493670bd)
|
||||
|
||||
Bug: 1470477
|
||||
Change-Id: I260c93016f8ab0d165e4b29ca1aea810bede5b97
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4759326
|
||||
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1181365}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4777251
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#1482}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
(cherry picked from commit 34e544e4dedf299211f104a2822d98ce1db80f61)
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/css/rule_feature_set.cc b/third_party/blink/renderer/core/css/rule_feature_set.cc
|
||||
index 35483b54816197b3244cac4bb32759a88de57664..c6a93968829a8dc6d14247e8882a9a3fdcfb6f84 100644
|
||||
--- a/third_party/blink/renderer/core/css/rule_feature_set.cc
|
||||
+++ b/third_party/blink/renderer/core/css/rule_feature_set.cc
|
||||
@@ -1322,6 +1322,7 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForLogicalCombinationInHas(
|
||||
descendant_features);
|
||||
|
||||
const CSSSelector* compound_in_logical_combination = complex;
|
||||
+ InvalidationSetFeatures* inner_sibling_features = sibling_features;
|
||||
InvalidationSetFeatures last_compound_in_adjacent_chain_features;
|
||||
while (compound_in_logical_combination) {
|
||||
AddFeaturesToInvalidationSetsForLogicalCombinationInHasContext context(
|
||||
@@ -1333,14 +1334,14 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForLogicalCombinationInHas(
|
||||
last_in_compound =
|
||||
SkipAddingAndGetLastInCompoundForLogicalCombinationInHas(
|
||||
compound_in_logical_combination, compound_containing_has,
|
||||
- sibling_features, descendant_features, previous_combinator,
|
||||
- add_features_method);
|
||||
+ inner_sibling_features, descendant_features,
|
||||
+ previous_combinator, add_features_method);
|
||||
} else {
|
||||
last_in_compound =
|
||||
AddFeaturesAndGetLastInCompoundForLogicalCombinationInHas(
|
||||
compound_in_logical_combination, compound_containing_has,
|
||||
- sibling_features, descendant_features, previous_combinator,
|
||||
- add_features_method);
|
||||
+ inner_sibling_features, descendant_features,
|
||||
+ previous_combinator, add_features_method);
|
||||
}
|
||||
|
||||
if (!last_in_compound) {
|
||||
@@ -1355,7 +1356,7 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForLogicalCombinationInHas(
|
||||
? CSSSelector::kIndirectAdjacent
|
||||
: previous_combinator,
|
||||
context.last_compound_in_adjacent_chain,
|
||||
- last_compound_in_adjacent_chain_features, sibling_features,
|
||||
+ last_compound_in_adjacent_chain_features, inner_sibling_features,
|
||||
descendant_features);
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/has-sibling-chrome-crash.html b/third_party/blink/web_tests/external/wpt/css/selectors/has-sibling-chrome-crash.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0306e3e39272c321fc3539aa582b4e239ffe2fa1
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/has-sibling-chrome-crash.html
|
||||
@@ -0,0 +1,10 @@
|
||||
+<!DOCTYPE html>
|
||||
+<title>CSS Selectors Test: Chrome crash issue 1470477</title>
|
||||
+<link rel="help" href="https://crbug.com/1470477">
|
||||
+<style>
|
||||
+ :has(> :where(label:first-child + [a="a"]:only-of-type,
|
||||
+ [a="a"]:only-of-type + label:last-child)) label:last-child {
|
||||
+ margin-inline: 1em;
|
||||
+ }
|
||||
+</style>
|
||||
+<p>PASS if this tests does not crash</p>
|
||||
61
patches/chromium/cherry-pick-26175b0903d8.patch
Normal file
61
patches/chromium/cherry-pick-26175b0903d8.patch
Normal file
@@ -0,0 +1,61 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yi Gu <yigu@chromium.org>
|
||||
Date: Thu, 31 Aug 2023 20:12:41 +0000
|
||||
Subject: ReportBadMessage when the provider list is empty
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The provider list should not be empty unless the API is called from a
|
||||
compromised renderer.
|
||||
|
||||
(cherry picked from commit 3b19acb01dcea93b423aa0da56c4a9811a067353)
|
||||
|
||||
Change-Id: I3e497fae2343342b3ec6b17bd663f2ec1bf12d54
|
||||
Bug: 1476403
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4822925
|
||||
Reviewed-by: Nicolás Peña <npm@chromium.org>
|
||||
Commit-Queue: Yi Gu <yigu@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1189841}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4833411
|
||||
Commit-Queue: Nicolás Peña <npm@chromium.org>
|
||||
Auto-Submit: Yi Gu <yigu@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#1698}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
|
||||
index cbae35e588c2db4ac83a23d62fa7c5b0aec09324..194e4d937562ce73fb6e1e095dc16d13f74f002b 100644
|
||||
--- a/content/browser/webid/federated_auth_request_impl.cc
|
||||
+++ b/content/browser/webid/federated_auth_request_impl.cc
|
||||
@@ -415,6 +415,16 @@ void FederatedAuthRequestImpl::RequestToken(
|
||||
mojo::ReportBadMessage("idp_get_params_ptrs is empty.");
|
||||
return;
|
||||
}
|
||||
+ // This could only happen with a compromised renderer process. We ensure that
|
||||
+ // the provider list size is > 0 on the renderer side at the beginning of
|
||||
+ // parsing |IdentityCredentialRequestOptions|.
|
||||
+ for (auto& idp_get_params_ptr : idp_get_params_ptrs) {
|
||||
+ if (idp_get_params_ptr->providers.size() == 0) {
|
||||
+ mojo::ReportBadMessage("The provider list should not be empty.");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
// It should not be possible to receive multiple IDPs when the
|
||||
// `kFedCmMultipleIdentityProviders` flag is disabled. But such a message
|
||||
// could be received from a compromised renderer.
|
||||
@@ -425,14 +435,6 @@ void FederatedAuthRequestImpl::RequestToken(
|
||||
return;
|
||||
}
|
||||
|
||||
- // Check that providers are non-empty.
|
||||
- for (auto& idp_get_params_ptr : idp_get_params_ptrs) {
|
||||
- if (idp_get_params_ptr->providers.size() == 0) {
|
||||
- std::move(callback).Run(RequestTokenStatus::kError, absl::nullopt, "");
|
||||
- return;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
if (!fedcm_metrics_) {
|
||||
// TODO(crbug.com/1307709): Handle FedCmMetrics for multiple IDPs.
|
||||
fedcm_metrics_ =
|
||||
162
patches/chromium/cherry-pick-35c06406a658.patch
Normal file
162
patches/chromium/cherry-pick-35c06406a658.patch
Normal file
@@ -0,0 +1,162 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Thu, 24 Aug 2023 11:12:43 +0000
|
||||
Subject: Handle object destruction in MediaStreamDeviceObserver
|
||||
|
||||
MSDO executes some callbacks that can result in the destruction of
|
||||
MSDO upon an external event such as removing a media device or the
|
||||
user revoking permission.
|
||||
This CL adds code to detect this condition and prevent further
|
||||
processing that would result in UAF. It also removes some invalid
|
||||
DCHECKs.
|
||||
|
||||
Drive-by: minor style fixes
|
||||
|
||||
(cherry picked from commit 7337133682ab0404b753c563dde2ae2b1dc13171)
|
||||
|
||||
Bug: 1472492, b/296997707
|
||||
Change-Id: I76f019bb110e7d9cca276444bc23a7e43114d2cc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4798398
|
||||
Reviewed-by: Palak Agarwal <agpalak@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1186452}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4810035
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#1586}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
|
||||
index 0715b727f7e2b319243f5ec47ead48c8b1b1f644..7bf375055637d67fa409ce977e103baf4aecdf6b 100644
|
||||
--- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
|
||||
@@ -37,11 +37,11 @@ MediaStreamDeviceObserver::MediaStreamDeviceObserver(LocalFrame* frame) {
|
||||
if (frame) {
|
||||
frame->GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
|
||||
&MediaStreamDeviceObserver::BindMediaStreamDeviceObserverReceiver,
|
||||
- WTF::Unretained(this)));
|
||||
+ weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
}
|
||||
|
||||
-MediaStreamDeviceObserver::~MediaStreamDeviceObserver() {}
|
||||
+MediaStreamDeviceObserver::~MediaStreamDeviceObserver() = default;
|
||||
|
||||
MediaStreamDevices MediaStreamDeviceObserver::GetNonScreenCaptureDevices() {
|
||||
MediaStreamDevices video_devices;
|
||||
@@ -70,13 +70,21 @@ void MediaStreamDeviceObserver::OnDeviceStopped(
|
||||
}
|
||||
|
||||
for (Stream& stream : it->value) {
|
||||
- if (IsAudioInputMediaType(device.type))
|
||||
+ if (IsAudioInputMediaType(device.type)) {
|
||||
RemoveStreamDeviceFromArray(device, &stream.audio_devices);
|
||||
- else
|
||||
+ } else {
|
||||
RemoveStreamDeviceFromArray(device, &stream.video_devices);
|
||||
-
|
||||
- if (stream.on_device_stopped_cb)
|
||||
+ }
|
||||
+ if (stream.on_device_stopped_cb) {
|
||||
+ // Running `stream.on_device_stopped_cb` can destroy `this`. Use a weak
|
||||
+ // pointer to detect that condition, and stop processing if it happens.
|
||||
+ base::WeakPtr<MediaStreamDeviceObserver> weak_this =
|
||||
+ weak_factory_.GetWeakPtr();
|
||||
stream.on_device_stopped_cb.Run(device);
|
||||
+ if (!weak_this) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
// |it| could have already been invalidated in the function call above. So we
|
||||
@@ -85,8 +93,9 @@ void MediaStreamDeviceObserver::OnDeviceStopped(
|
||||
// iterator from |label_stream_map_| (https://crbug.com/616884). Future work
|
||||
// needs to be done to resolve this re-entrancy issue.
|
||||
it = label_stream_map_.find(label);
|
||||
- if (it == label_stream_map_.end())
|
||||
+ if (it == label_stream_map_.end()) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
Vector<Stream>& streams = it->value;
|
||||
auto* stream_it = streams.begin();
|
||||
@@ -122,8 +131,16 @@ void MediaStreamDeviceObserver::OnDeviceChanged(
|
||||
DCHECK_EQ(1u, it->value.size());
|
||||
|
||||
Stream* stream = &it->value[0];
|
||||
- if (stream->on_device_changed_cb)
|
||||
+ if (stream->on_device_changed_cb) {
|
||||
+ // Running `stream->on_device_changed_cb` can destroy `this`. Use a weak
|
||||
+ // pointer to detect that condition, and stop processing if it happens.
|
||||
+ base::WeakPtr<MediaStreamDeviceObserver> weak_this =
|
||||
+ weak_factory_.GetWeakPtr();
|
||||
stream->on_device_changed_cb.Run(old_device, new_device);
|
||||
+ if (!weak_this) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
// Update device list only for device changing. Removing device will be
|
||||
// handled in its own callback.
|
||||
@@ -304,9 +321,9 @@ void MediaStreamDeviceObserver::RemoveStreamDevice(
|
||||
streams_to_remove.push_back(entry.key);
|
||||
}
|
||||
}
|
||||
- DCHECK(device_found);
|
||||
- for (const String& label : streams_to_remove)
|
||||
+ for (const String& label : streams_to_remove) {
|
||||
label_stream_map_.erase(label);
|
||||
+ }
|
||||
}
|
||||
|
||||
base::UnguessableToken MediaStreamDeviceObserver::GetAudioSessionId(
|
||||
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h
|
||||
index e14c74b7c4ba270efeb433eb0e5d876f6224e60b..a97e39274caa75a321d08afc8703bd9b2c29351d 100644
|
||||
--- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h
|
||||
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h
|
||||
@@ -123,6 +123,7 @@ class MODULES_EXPORT MediaStreamDeviceObserver
|
||||
|
||||
using LabelStreamMap = HashMap<String, Vector<Stream>>;
|
||||
LabelStreamMap label_stream_map_;
|
||||
+ base::WeakPtrFactory<MediaStreamDeviceObserver> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc b/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc
|
||||
index 2cc3a9a7f072dec1aaf44b3e13d4ef6dacf3e943..e3eddc9d5ed12bf9947af12c1054f217c90d40b8 100644
|
||||
--- a/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc
|
||||
+++ b/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc
|
||||
@@ -32,10 +32,12 @@ void WebPlatformMediaStreamSource::StopSource() {
|
||||
|
||||
void WebPlatformMediaStreamSource::FinalizeStopSource() {
|
||||
DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
- if (!stop_callback_.is_null())
|
||||
+ if (!stop_callback_.is_null()) {
|
||||
std::move(stop_callback_).Run(Owner());
|
||||
- if (Owner())
|
||||
+ }
|
||||
+ if (Owner()) {
|
||||
Owner().SetReadyState(WebMediaStreamSource::kReadyStateEnded);
|
||||
+ }
|
||||
}
|
||||
|
||||
void WebPlatformMediaStreamSource::SetSourceMuted(bool is_muted) {
|
||||
@@ -43,8 +45,9 @@ void WebPlatformMediaStreamSource::SetSourceMuted(bool is_muted) {
|
||||
// Although this change is valid only if the ready state isn't already Ended,
|
||||
// there's code further along (like in MediaStreamTrack) which filters
|
||||
// that out already.
|
||||
- if (!Owner())
|
||||
+ if (!Owner()) {
|
||||
return;
|
||||
+ }
|
||||
Owner().SetReadyState(is_muted ? WebMediaStreamSource::kReadyStateMuted
|
||||
: WebMediaStreamSource::kReadyStateLive);
|
||||
}
|
||||
@@ -73,7 +76,6 @@ void WebPlatformMediaStreamSource::SetStopCallback(
|
||||
|
||||
void WebPlatformMediaStreamSource::ResetSourceStoppedCallback() {
|
||||
DCHECK(task_runner_->BelongsToCurrentThread());
|
||||
- DCHECK(!stop_callback_.is_null());
|
||||
stop_callback_.Reset();
|
||||
}
|
||||
|
||||
99
patches/chromium/cherry-pick-60b93798c991.patch
Normal file
99
patches/chromium/cherry-pick-60b93798c991.patch
Normal file
@@ -0,0 +1,99 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eugene Zemtsov <eugene@chromium.org>
|
||||
Date: Wed, 21 Jun 2023 17:57:52 +0000
|
||||
Subject: webcodecs: Fix crash when changing temporal layer count in AV1
|
||||
encoder
|
||||
|
||||
(cherry picked from commit f312efac1b90117729e8961b58c643fc0eae1fbd)
|
||||
|
||||
Bug: 1447568
|
||||
Change-Id: I4ecb02ed956707571573a65ade17fdffe676b502
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4554300
|
||||
Auto-Submit: Eugene Zemtsov <eugene@chromium.org>
|
||||
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
|
||||
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1148041}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4610718
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1360}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/media/video/av1_video_encoder.cc b/media/video/av1_video_encoder.cc
|
||||
index 19796f667564412391abdb9d28f900f0364e37e3..72e4184861b6eb837a5d4830140d720b28c90f0f 100644
|
||||
--- a/media/video/av1_video_encoder.cc
|
||||
+++ b/media/video/av1_video_encoder.cc
|
||||
@@ -119,6 +119,7 @@ EncoderStatus SetUpAomConfig(const VideoEncoder::Options& opts,
|
||||
svc_params = {};
|
||||
svc_params.framerate_factor[0] = 1;
|
||||
svc_params.number_spatial_layers = 1;
|
||||
+ svc_params.number_temporal_layers = 1;
|
||||
if (opts.scalability_mode.has_value()) {
|
||||
switch (opts.scalability_mode.value()) {
|
||||
case SVCScalabilityMode::kL1T1:
|
||||
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc
|
||||
index c05337f87ff4b8e3a8baf4a417a7dcfc3a2074cc..7954254f7ebf21d7375fb7661cbeb3276a5a4e7f 100644
|
||||
--- a/media/video/software_video_encoder_test.cc
|
||||
+++ b/media/video/software_video_encoder_test.cc
|
||||
@@ -612,6 +612,63 @@ TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) {
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_P(SVCVideoEncoderTest, ChangeLayers) {
|
||||
+ VideoEncoder::Options options;
|
||||
+ options.frame_size = gfx::Size(640, 480);
|
||||
+ options.bitrate = Bitrate::ConstantBitrate(1000000u); // 1Mbps
|
||||
+ options.framerate = 25;
|
||||
+ options.scalability_mode = GetParam().scalability_mode;
|
||||
+ std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
|
||||
+
|
||||
+ std::vector<VideoEncoderOutput> chunks;
|
||||
+ size_t total_frames_count = 80;
|
||||
+
|
||||
+ // Encoder all frames with 3 temporal layers and put all outputs in |chunks|
|
||||
+ auto frame_duration = base::Seconds(1.0 / options.framerate.value());
|
||||
+
|
||||
+ VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
|
||||
+ [&](VideoEncoderOutput output,
|
||||
+ absl::optional<VideoEncoder::CodecDescription> desc) {
|
||||
+ chunks.push_back(std::move(output));
|
||||
+ });
|
||||
+
|
||||
+ encoder_->Initialize(profile_, options, /*info_cb=*/base::DoNothing(),
|
||||
+ std::move(encoder_output_cb),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+
|
||||
+ uint32_t color = 0x964050;
|
||||
+ for (auto frame_index = 0u; frame_index < total_frames_count; frame_index++) {
|
||||
+ auto timestamp = frame_index * frame_duration;
|
||||
+
|
||||
+ const bool reconfigure = (frame_index == total_frames_count / 2);
|
||||
+ if (reconfigure) {
|
||||
+ encoder_->Flush(ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+
|
||||
+ // Ask encoder to change SVC mode, empty output callback
|
||||
+ // means the encoder should keep the old one.
|
||||
+ options.scalability_mode = SVCScalabilityMode::kL1T1;
|
||||
+ encoder_->ChangeOptions(
|
||||
+ options, VideoEncoder::OutputCB(),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ }
|
||||
+
|
||||
+ auto frame =
|
||||
+ CreateFrame(options.frame_size, pixel_format_, timestamp, color);
|
||||
+ color = (color << 1) + frame_index;
|
||||
+ frames_to_encode.push_back(frame);
|
||||
+ encoder_->Encode(frame, VideoEncoder::EncodeOptions(false),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ }
|
||||
+
|
||||
+ encoder_->Flush(ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ EXPECT_EQ(chunks.size(), total_frames_count);
|
||||
+}
|
||||
+
|
||||
TEST_P(H264VideoEncoderTest, ReconfigureWithResize) {
|
||||
VideoEncoder::Options options;
|
||||
gfx::Size size1(320, 200), size2(400, 240);
|
||||
37
patches/chromium/cherry-pick-74a2eb9c8cb2.patch
Normal file
37
patches/chromium/cherry-pick-74a2eb9c8cb2.patch
Normal file
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yoichi Osato <yoichio@chromium.org>
|
||||
Date: Tue, 29 Aug 2023 02:37:46 +0000
|
||||
Subject: Readd lock when ObserverListMap::erase()
|
||||
|
||||
We should lock when remove an item from the map.
|
||||
This lock was accidentally removed in:
|
||||
https://chromium-review.googlesource.com/c/chromium/src/+/4280021
|
||||
|
||||
(cherry picked from commit a41479ba6efb5e48b82edad972c7dded6f385b79)
|
||||
|
||||
Bug: 1469928
|
||||
Change-Id: I2512e14d4ad9b246cadae947023dbccb5158da51
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4790983
|
||||
Auto-Submit: Yoichi Osato <yoichio@chromium.org>
|
||||
Reviewed-by: Yoichi Osato <yoichio@chromium.org>
|
||||
Reviewed-by: Koji Ishii <kojii@chromium.org>
|
||||
Commit-Queue: Koji Ishii <kojii@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1187668}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4820108
|
||||
Reviewed-by: Kent Tamura <tkent@chromium.org>
|
||||
Commit-Queue: Kent Tamura <tkent@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#1666}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/network/network_state_notifier.cc b/third_party/blink/renderer/platform/network/network_state_notifier.cc
|
||||
index 39c417e0f8ec672d413bb69a3b98f06442183295..e74b4ea41b2b30037890f36dd9ff81d6ef3c4e88 100644
|
||||
--- a/third_party/blink/renderer/platform/network/network_state_notifier.cc
|
||||
+++ b/third_party/blink/renderer/platform/network/network_state_notifier.cc
|
||||
@@ -350,6 +350,7 @@ void NetworkStateNotifier::RemoveObserver(
|
||||
DCHECK(task_runner->RunsTasksInCurrentSequence());
|
||||
DCHECK(observer);
|
||||
|
||||
+ base::AutoLock locker(lock_);
|
||||
ObserverListMap& map = GetObserverMapFor(type);
|
||||
DCHECK_NE(map.end(), map.find(observer));
|
||||
map.erase(observer);
|
||||
215
patches/chromium/cherry-pick-85beff6fd302.patch
Normal file
215
patches/chromium/cherry-pick-85beff6fd302.patch
Normal file
@@ -0,0 +1,215 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin McNee <mcnee@chromium.org>
|
||||
Date: Wed, 14 Jun 2023 01:10:19 +0000
|
||||
Subject: M114: Don't recursively destroy guests when clearing unattached
|
||||
guests
|
||||
|
||||
Don't recursively destroy guests when clearing unattached guests
|
||||
|
||||
When an embedder process is destroyed, we also destroy any unattached
|
||||
guests associated with that process. This is currently done with a
|
||||
single call to `owned_guests_.erase`. However, it's possible that two
|
||||
unattached guests could have an opener relationship, which causes the
|
||||
destruction of the opener guest to also destroy the other guest, during
|
||||
the call to `erase`, which is unsafe.
|
||||
|
||||
We now separate the steps of erasing `owned_guests_` and destroying the
|
||||
guests, to avoid this recursive guest destruction.
|
||||
|
||||
This also fixes the WaitForNumGuestsCreated test method to not
|
||||
return prematurely.
|
||||
|
||||
(cherry picked from commit 6345e7871e8197af92f9c6158b06c6e197f87945)
|
||||
|
||||
Bug: 1450397
|
||||
Change-Id: Ifef5ec9ff3a1e6952ff56ec279e29e8522625ac0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4589949
|
||||
Commit-Queue: Kevin McNee <mcnee@chromium.org>
|
||||
Auto-Submit: Kevin McNee <mcnee@chromium.org>
|
||||
Reviewed-by: James Maclean <wjmaclean@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1153396}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4611152
|
||||
Commit-Queue: James Maclean <wjmaclean@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1292}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
index c5167c135a7e41705ac018d3aec568c65fdcb0dc..bdfbf5c75a4275d4a395ff182cbfeda3cb2cc699 100644
|
||||
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
@@ -2884,6 +2884,22 @@ IN_PROC_BROWSER_TEST_P(WebViewNewWindowTest,
|
||||
EXPECT_TRUE(content::NavigateToURLFromRenderer(guest2, coop_url));
|
||||
}
|
||||
|
||||
+// This test creates a situation where we have two unattached webviews which
|
||||
+// have an opener relationship, and ensures that we can shutdown safely. See
|
||||
+// https://crbug.com/1450397.
|
||||
+IN_PROC_BROWSER_TEST_P(WebViewNewWindowTest, DestroyOpenerBeforeAttachment) {
|
||||
+ TestHelper("testDestroyOpenerBeforeAttachment", "web_view/newwindow",
|
||||
+ NEEDS_TEST_SERVER);
|
||||
+ GetGuestViewManager()->WaitForNumGuestsCreated(2);
|
||||
+
|
||||
+ content::RenderProcessHost* embedder_rph =
|
||||
+ GetEmbedderWebContents()->GetPrimaryMainFrame()->GetProcess();
|
||||
+ content::RenderProcessHostWatcher kill_observer(
|
||||
+ embedder_rph, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
|
||||
+ EXPECT_TRUE(embedder_rph->Shutdown(content::RESULT_CODE_KILLED));
|
||||
+ kill_observer.Wait();
|
||||
+}
|
||||
+
|
||||
IN_PROC_BROWSER_TEST_P(WebViewTest, ContextMenuInspectElement) {
|
||||
LoadAppWithGuest("web_view/context_menus/basic");
|
||||
content::RenderFrameHost* guest_rfh = GetGuestRenderFrameHost();
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
index 900911f4963d23d74225868dce01326ba533f63a..4dd25d8849b0b13957ab7fa2912c0a158d3cd244 100644
|
||||
--- a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
@@ -34,6 +34,9 @@ embedder.setUp_ = function(config) {
|
||||
embedder.guestWithLinkURL = embedder.baseGuestURL +
|
||||
'/extensions/platform_apps/web_view/newwindow' +
|
||||
'/guest_with_link.html';
|
||||
+ embedder.guestOpenOnLoadURL = embedder.baseGuestURL +
|
||||
+ '/extensions/platform_apps/web_view/newwindow' +
|
||||
+ '/guest_opener_open_on_load.html';
|
||||
};
|
||||
|
||||
/** @private */
|
||||
@@ -652,6 +655,24 @@ function testNewWindowDeferredAttachmentIndefinitely() {
|
||||
embedder.setUpNewWindowRequest_(webview, 'guest.html', '', testName);
|
||||
}
|
||||
|
||||
+// This is not a test in and of itself, but a means of creating a webview that
|
||||
+// is left in an unattached state while its opener webview is also in an
|
||||
+// unattached state, so that the C++ side can test it in that state.
|
||||
+function testDestroyOpenerBeforeAttachment() {
|
||||
+ embedder.test.succeed();
|
||||
+
|
||||
+ let webview = new WebView();
|
||||
+ webview.src = embedder.guestOpenOnLoadURL;
|
||||
+ document.body.appendChild(webview);
|
||||
+
|
||||
+ // By spinning forever here, we prevent `webview` from completing the
|
||||
+ // attachment process. But since the guest is still created and it calls
|
||||
+ // window.open, we have a situation where two unattached webviews have an
|
||||
+ // opener relationship. The C++ side will test that we can shutdown safely in
|
||||
+ // this case.
|
||||
+ while (true) {}
|
||||
+}
|
||||
+
|
||||
embedder.test.testList = {
|
||||
'testNewWindowAttachAfterOpenerDestroyed':
|
||||
testNewWindowAttachAfterOpenerDestroyed,
|
||||
@@ -675,7 +696,9 @@ embedder.test.testList = {
|
||||
testNewWindowWebViewNameTakesPrecedence,
|
||||
'testNewWindowAndUpdateOpener': testNewWindowAndUpdateOpener,
|
||||
'testNewWindowDeferredAttachmentIndefinitely':
|
||||
- testNewWindowDeferredAttachmentIndefinitely
|
||||
+ testNewWindowDeferredAttachmentIndefinitely,
|
||||
+ 'testDestroyOpenerBeforeAttachment':
|
||||
+ testDestroyOpenerBeforeAttachment
|
||||
};
|
||||
|
||||
onload = function() {
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html b/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e961feb3c6487066801adf414bf4a2746c50a3f6
|
||||
--- /dev/null
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html
|
||||
@@ -0,0 +1,13 @@
|
||||
+<!--
|
||||
+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.
|
||||
+-->
|
||||
+<html>
|
||||
+<body>
|
||||
+<script>
|
||||
+ // A guest that opens a new window on load.
|
||||
+ window.open('guest.html');
|
||||
+</script>
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/components/guest_view/browser/guest_view_manager.cc b/components/guest_view/browser/guest_view_manager.cc
|
||||
index 6b18dc43962386c11c9b656a0f74ae6867b50cd4..eecc03787430cfdbbf1804ebb5245fd6abf731db 100644
|
||||
--- a/components/guest_view/browser/guest_view_manager.cc
|
||||
+++ b/components/guest_view/browser/guest_view_manager.cc
|
||||
@@ -332,7 +332,20 @@ void GuestViewManager::RemoveGuest(int guest_instance_id, bool invalidate_id) {
|
||||
|
||||
void GuestViewManager::EmbedderProcessDestroyed(int embedder_process_id) {
|
||||
embedders_observed_.erase(embedder_process_id);
|
||||
+
|
||||
+ // We can't just call std::multimap::erase here because destroying a guest
|
||||
+ // could trigger the destruction of another guest which is also owned by
|
||||
+ // `owned_guests_`. Recursively calling std::multimap::erase is unsafe (see
|
||||
+ // https://crbug.com/1450397). So we take ownership of all of the guests that
|
||||
+ // will be destroyed before erasing the entries from the map.
|
||||
+ std::vector<std::unique_ptr<GuestViewBase>> guests_to_destroy;
|
||||
+ const auto destroy_range = owned_guests_.equal_range(embedder_process_id);
|
||||
+ for (auto it = destroy_range.first; it != destroy_range.second; ++it) {
|
||||
+ guests_to_destroy.push_back(std::move(it->second));
|
||||
+ }
|
||||
owned_guests_.erase(embedder_process_id);
|
||||
+ guests_to_destroy.clear();
|
||||
+
|
||||
CallViewDestructionCallbacks(embedder_process_id);
|
||||
}
|
||||
|
||||
diff --git a/components/guest_view/browser/test_guest_view_manager.cc b/components/guest_view/browser/test_guest_view_manager.cc
|
||||
index a0fb5885084cb04688770323c940825ca8e0b6d5..44e264730e2a21d613f4515e8552ad81703f062b 100644
|
||||
--- a/components/guest_view/browser/test_guest_view_manager.cc
|
||||
+++ b/components/guest_view/browser/test_guest_view_manager.cc
|
||||
@@ -37,7 +37,6 @@ TestGuestViewManager::TestGuestViewManager(
|
||||
num_guests_created_(0),
|
||||
expected_num_guests_created_(0),
|
||||
num_views_garbage_collected_(0),
|
||||
- waiting_for_guests_created_(false),
|
||||
waiting_for_attach_(nullptr) {}
|
||||
|
||||
TestGuestViewManager::~TestGuestViewManager() = default;
|
||||
@@ -128,14 +127,15 @@ GuestViewBase* TestGuestViewManager::WaitForNextGuestViewCreated() {
|
||||
}
|
||||
|
||||
void TestGuestViewManager::WaitForNumGuestsCreated(size_t count) {
|
||||
- if (count == num_guests_created_)
|
||||
+ if (count == num_guests_created_) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
- waiting_for_guests_created_ = true;
|
||||
expected_num_guests_created_ = count;
|
||||
|
||||
num_created_run_loop_ = std::make_unique<base::RunLoop>();
|
||||
num_created_run_loop_->Run();
|
||||
+ num_created_run_loop_ = nullptr;
|
||||
}
|
||||
|
||||
void TestGuestViewManager::WaitUntilAttached(GuestViewBase* guest_view) {
|
||||
@@ -180,13 +180,11 @@ void TestGuestViewManager::AddGuest(int guest_instance_id,
|
||||
created_run_loop_->Quit();
|
||||
|
||||
++num_guests_created_;
|
||||
- if (!waiting_for_guests_created_ &&
|
||||
- num_guests_created_ != expected_num_guests_created_) {
|
||||
- return;
|
||||
- }
|
||||
|
||||
- if (num_created_run_loop_)
|
||||
+ if (num_created_run_loop_ &&
|
||||
+ num_guests_created_ == expected_num_guests_created_) {
|
||||
num_created_run_loop_->Quit();
|
||||
+ }
|
||||
}
|
||||
|
||||
void TestGuestViewManager::AttachGuest(int embedder_process_id,
|
||||
diff --git a/components/guest_view/browser/test_guest_view_manager.h b/components/guest_view/browser/test_guest_view_manager.h
|
||||
index 094524fad8b5d46cc938e8ac8559bac019b25c09..0c0b718be474335bf95767308f400e40379775d1 100644
|
||||
--- a/components/guest_view/browser/test_guest_view_manager.h
|
||||
+++ b/components/guest_view/browser/test_guest_view_manager.h
|
||||
@@ -120,7 +120,6 @@ class TestGuestViewManager : public GuestViewManager {
|
||||
size_t num_guests_created_;
|
||||
size_t expected_num_guests_created_;
|
||||
int num_views_garbage_collected_;
|
||||
- bool waiting_for_guests_created_;
|
||||
|
||||
// Tracks the life time of the GuestView's main FrameTreeNode. The main FTN
|
||||
// has the same lifesspan as the GuestView.
|
||||
404
patches/chromium/cherry-pick-933b9fad3a53.patch
Normal file
404
patches/chromium/cherry-pick-933b9fad3a53.patch
Normal file
@@ -0,0 +1,404 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Rockot <rockot@google.com>
|
||||
Date: Fri, 9 Jun 2023 07:49:02 +0000
|
||||
Subject: Reland "ipcz: Refactor FragmentDescriptor decode"
|
||||
|
||||
This is a reland of commit 17dd18d1f2194089b8433e0ca334c81343b591e2
|
||||
|
||||
Original change's description:
|
||||
> ipcz: Refactor FragmentDescriptor decode
|
||||
>
|
||||
> Funnels untrusted FragmentDescriptor mapping through a new
|
||||
> Fragment::MappedFromDescriptor helper. See the linked bug
|
||||
> for more details.
|
||||
>
|
||||
> Fixed: 1450899
|
||||
> Change-Id: I4c7751b9f4299da4a13c0becc1b889160a0c6e66
|
||||
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4599218
|
||||
> Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
> Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
> Cr-Commit-Position: refs/heads/main@{#1155133}
|
||||
|
||||
Change-Id: I86ee9118a30dea59d837c377a1f751b20a85a3c3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4602794
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#1155397}
|
||||
|
||||
diff --git a/third_party/ipcz/src/BUILD.gn b/third_party/ipcz/src/BUILD.gn
|
||||
index 4b3bbaf262815573249648b56c03442757c098ae..3c1cd26c65e5be543e24f51ad0d89b482d177a79 100644
|
||||
--- a/third_party/ipcz/src/BUILD.gn
|
||||
+++ b/third_party/ipcz/src/BUILD.gn
|
||||
@@ -212,6 +212,7 @@ ipcz_source_set("impl") {
|
||||
"ipcz/application_object.h",
|
||||
"ipcz/block_allocator.h",
|
||||
"ipcz/box.h",
|
||||
+ "ipcz/buffer_id.h",
|
||||
"ipcz/buffer_pool.h",
|
||||
"ipcz/driver_memory.h",
|
||||
"ipcz/driver_memory_mapping.h",
|
||||
@@ -254,7 +255,6 @@ ipcz_source_set("impl") {
|
||||
"ipcz/block_allocator_pool.cc",
|
||||
"ipcz/block_allocator_pool.h",
|
||||
"ipcz/box.cc",
|
||||
- "ipcz/buffer_id.h",
|
||||
"ipcz/buffer_pool.cc",
|
||||
"ipcz/driver_memory.cc",
|
||||
"ipcz/driver_memory_mapping.cc",
|
||||
@@ -378,6 +378,7 @@ ipcz_source_set("ipcz_tests_sources") {
|
||||
"ipcz/driver_memory_test.cc",
|
||||
"ipcz/driver_object_test.cc",
|
||||
"ipcz/driver_transport_test.cc",
|
||||
+ "ipcz/fragment_test.cc",
|
||||
"ipcz/message_test.cc",
|
||||
"ipcz/node_connector_test.cc",
|
||||
"ipcz/node_link_memory_test.cc",
|
||||
diff --git a/third_party/ipcz/src/ipcz/block_allocator_pool.cc b/third_party/ipcz/src/ipcz/block_allocator_pool.cc
|
||||
index bd464f897d1fcbde03941ee334d0e1706bf59868..1b9d50b2c77c046d815a94d7760328c8b379ecab 100644
|
||||
--- a/third_party/ipcz/src/ipcz/block_allocator_pool.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/block_allocator_pool.cc
|
||||
@@ -86,7 +86,7 @@ Fragment BlockAllocatorPool::Allocate() {
|
||||
FragmentDescriptor descriptor(
|
||||
entry->buffer_id, checked_cast<uint32_t>(offset),
|
||||
checked_cast<uint32_t>(allocator.block_size()));
|
||||
- return Fragment(descriptor, block);
|
||||
+ return Fragment::FromDescriptorUnsafe(descriptor, block);
|
||||
}
|
||||
|
||||
// Allocation from the active allocator failed. Try another if available.
|
||||
diff --git a/third_party/ipcz/src/ipcz/buffer_pool.cc b/third_party/ipcz/src/ipcz/buffer_pool.cc
|
||||
index 6881346d8f8532f070e5121da16f064ae4a9bdaf..27b23049848967f29f81b10ba4f8fa4ead14d2e2 100644
|
||||
--- a/third_party/ipcz/src/ipcz/buffer_pool.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/buffer_pool.cc
|
||||
@@ -26,15 +26,11 @@ Fragment BufferPool::GetFragment(const FragmentDescriptor& descriptor) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
auto it = mappings_.find(descriptor.buffer_id());
|
||||
if (it == mappings_.end()) {
|
||||
- return Fragment(descriptor, nullptr);
|
||||
+ return Fragment::PendingFromDescriptor(descriptor);
|
||||
}
|
||||
|
||||
auto& [id, mapping] = *it;
|
||||
- if (descriptor.end() > mapping.bytes().size()) {
|
||||
- return {};
|
||||
- }
|
||||
-
|
||||
- return Fragment(descriptor, mapping.address_at(descriptor.offset()));
|
||||
+ return Fragment::MappedFromDescriptor(descriptor, mapping);
|
||||
}
|
||||
|
||||
bool BufferPool::AddBlockBuffer(
|
||||
diff --git a/third_party/ipcz/src/ipcz/buffer_pool_test.cc b/third_party/ipcz/src/ipcz/buffer_pool_test.cc
|
||||
index a009ffe1c20ade013a19b51eceee4faf334eb591..bff66c452a3e2c38b0f208cca1fa1a082f1ee871 100644
|
||||
--- a/third_party/ipcz/src/ipcz/buffer_pool_test.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/buffer_pool_test.cc
|
||||
@@ -194,9 +194,11 @@ TEST_F(BufferPoolTest, BasicBlockAllocation) {
|
||||
pool.GetTotalBlockCapacity(kBlockSize));
|
||||
|
||||
// We can't free something that isn't a valid allocation.
|
||||
- EXPECT_FALSE(pool.FreeBlock(Fragment{{}, nullptr}));
|
||||
- EXPECT_FALSE(pool.FreeBlock(Fragment{{BufferId{1000}, 0, 1}, nullptr}));
|
||||
- EXPECT_FALSE(pool.FreeBlock(Fragment{{BufferId{0}, 0, 1}, bytes0.data()}));
|
||||
+ EXPECT_FALSE(pool.FreeBlock(Fragment::FromDescriptorUnsafe({}, nullptr)));
|
||||
+ EXPECT_FALSE(pool.FreeBlock(
|
||||
+ Fragment::FromDescriptorUnsafe({BufferId{1000}, 0, 1}, nullptr)));
|
||||
+ EXPECT_FALSE(pool.FreeBlock(
|
||||
+ Fragment::FromDescriptorUnsafe({BufferId{0}, 0, 1}, bytes0.data())));
|
||||
|
||||
// Allocate all available capacity.
|
||||
std::vector<Fragment> fragments;
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment.cc b/third_party/ipcz/src/ipcz/fragment.cc
|
||||
index 651d1c2fca5fe4fb69cdf61c6062bd8804ebf704..2ef4ed8dcfa0a56a73975a0b7dcc3f86bf5a83a0 100644
|
||||
--- a/third_party/ipcz/src/ipcz/fragment.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment.cc
|
||||
@@ -6,10 +6,38 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
+#include "ipcz/driver_memory_mapping.h"
|
||||
+#include "ipcz/fragment_descriptor.h"
|
||||
#include "third_party/abseil-cpp/absl/base/macros.h"
|
||||
+#include "util/safe_math.h"
|
||||
|
||||
namespace ipcz {
|
||||
|
||||
+// static
|
||||
+Fragment Fragment::MappedFromDescriptor(const FragmentDescriptor& descriptor,
|
||||
+ DriverMemoryMapping& mapping) {
|
||||
+ if (descriptor.is_null()) {
|
||||
+ return {};
|
||||
+ }
|
||||
+
|
||||
+ const uint32_t end = SaturatedAdd(descriptor.offset(), descriptor.size());
|
||||
+ if (end > mapping.bytes().size()) {
|
||||
+ return {};
|
||||
+ }
|
||||
+ return Fragment{descriptor, mapping.address_at(descriptor.offset())};
|
||||
+}
|
||||
+
|
||||
+// static
|
||||
+Fragment Fragment::PendingFromDescriptor(const FragmentDescriptor& descriptor) {
|
||||
+ return Fragment{descriptor, nullptr};
|
||||
+}
|
||||
+
|
||||
+// static
|
||||
+Fragment Fragment::FromDescriptorUnsafe(const FragmentDescriptor& descriptor,
|
||||
+ void* base_address) {
|
||||
+ return Fragment{descriptor, base_address};
|
||||
+}
|
||||
+
|
||||
Fragment::Fragment(const FragmentDescriptor& descriptor, void* address)
|
||||
: descriptor_(descriptor), address_(address) {
|
||||
// If `address` is non-null, the descriptor must also be. Note that the
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment.h b/third_party/ipcz/src/ipcz/fragment.h
|
||||
index c0151fdcf4b418680172a29d1c0d28b58a5807cd..de65f087b0bc27fd59ab88e23130d5ce0d345a8a 100644
|
||||
--- a/third_party/ipcz/src/ipcz/fragment.h
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment.h
|
||||
@@ -14,21 +14,32 @@
|
||||
|
||||
namespace ipcz {
|
||||
|
||||
+class DriverMemoryMapping;
|
||||
+
|
||||
// Represents a span of memory located within the shared memory regions owned by
|
||||
// a NodeLinkMemory, via BufferPool. This is essentially a FragmentDescriptor
|
||||
// plus the actual mapped address of the given buffer and offset.
|
||||
struct Fragment {
|
||||
constexpr Fragment() = default;
|
||||
|
||||
- // Constructs a new Fragment over `descriptor`, mapped to `address`. If
|
||||
- // `address` is null, the Fragment is considered "pending" -- it has a
|
||||
- // potentially valid descriptor, but could not be resolved to a mapped address
|
||||
- // yet (e.g. because the relevant BufferPool doesn't have the identified
|
||||
- // buffer mapped yet.)
|
||||
- Fragment(const FragmentDescriptor& descriptor, void* address);
|
||||
Fragment(const Fragment&);
|
||||
Fragment& operator=(const Fragment&);
|
||||
|
||||
+ // Returns a new concrete Fragment corresponding to `descriptor` within the
|
||||
+ // context of `mapping`. This validates that the fragment's bounds fall within
|
||||
+ // the bounds of `mapping`. If `descriptor` was null or validation fails, this
|
||||
+ // returns a null Fragment.
|
||||
+ static Fragment MappedFromDescriptor(const FragmentDescriptor& descriptor,
|
||||
+ DriverMemoryMapping& mapping);
|
||||
+
|
||||
+ // Returns a pending Fragment corresponding to `descriptor`.
|
||||
+ static Fragment PendingFromDescriptor(const FragmentDescriptor& descriptor);
|
||||
+
|
||||
+ // Returns a Fragment corresponding to `descriptor`, with the starting address
|
||||
+ // already mapped to `address`.
|
||||
+ static Fragment FromDescriptorUnsafe(const FragmentDescriptor& descriptor,
|
||||
+ void* address);
|
||||
+
|
||||
// A null fragment is a fragment with a null descriptor, meaning it does not
|
||||
// reference a valid buffer ID.
|
||||
bool is_null() const { return descriptor_.is_null(); }
|
||||
@@ -66,6 +77,13 @@ struct Fragment {
|
||||
}
|
||||
|
||||
private:
|
||||
+ // Constructs a new Fragment over `descriptor`, mapped to `address`. If
|
||||
+ // `address` is null, the Fragment is considered "pending" -- it has a
|
||||
+ // potentially valid descriptor, but could not be resolved to a mapped address
|
||||
+ // yet (e.g. because the relevant BufferPool doesn't have the identified
|
||||
+ // buffer mapped yet.)
|
||||
+ Fragment(const FragmentDescriptor& descriptor, void* address);
|
||||
+
|
||||
FragmentDescriptor descriptor_;
|
||||
|
||||
// The actual mapped address corresponding to `descriptor_`.
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment_descriptor.h b/third_party/ipcz/src/ipcz/fragment_descriptor.h
|
||||
index ed5229a392ca8f20ef092fec78c878a53babfa95..d8dbec5333b52f977d56571965ffbee79dff288c 100644
|
||||
--- a/third_party/ipcz/src/ipcz/fragment_descriptor.h
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment_descriptor.h
|
||||
@@ -36,7 +36,6 @@ struct IPCZ_ALIGN(8) FragmentDescriptor {
|
||||
BufferId buffer_id() const { return buffer_id_; }
|
||||
uint32_t offset() const { return offset_; }
|
||||
uint32_t size() const { return size_; }
|
||||
- uint32_t end() const { return offset_ + size_; }
|
||||
|
||||
private:
|
||||
// Identifies the shared memory buffer in which the memory resides. This ID is
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment_test.cc b/third_party/ipcz/src/ipcz/fragment_test.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e6b6baa6cb2f1fbdfb89d87d644f63681c797c01
|
||||
--- /dev/null
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment_test.cc
|
||||
@@ -0,0 +1,102 @@
|
||||
+// 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 "ipcz/fragment.h"
|
||||
+
|
||||
+#include <algorithm>
|
||||
+#include <cstring>
|
||||
+#include <limits>
|
||||
+#include <string>
|
||||
+#include <utility>
|
||||
+
|
||||
+#include "ipcz/buffer_id.h"
|
||||
+#include "ipcz/driver_memory.h"
|
||||
+#include "ipcz/driver_memory_mapping.h"
|
||||
+#include "reference_drivers/sync_reference_driver.h"
|
||||
+#include "testing/gtest/include/gtest/gtest.h"
|
||||
+
|
||||
+namespace ipcz {
|
||||
+namespace {
|
||||
+
|
||||
+const IpczDriver& kTestDriver = reference_drivers::kSyncReferenceDriver;
|
||||
+
|
||||
+using FragmentTest = testing::Test;
|
||||
+
|
||||
+TEST_F(FragmentTest, FromDescriptorUnsafe) {
|
||||
+ char kBuffer[] = "Hello, world!";
|
||||
+
|
||||
+ Fragment f = Fragment::FromDescriptorUnsafe({BufferId{0}, 1, 4}, kBuffer + 1);
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+ EXPECT_EQ(1u, f.offset());
|
||||
+ EXPECT_EQ(4u, f.size());
|
||||
+ EXPECT_EQ("ello", std::string(f.bytes().begin(), f.bytes().end()));
|
||||
+
|
||||
+ f = Fragment::FromDescriptorUnsafe({BufferId{0}, 7, 6}, kBuffer + 7);
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+ EXPECT_EQ(7u, f.offset());
|
||||
+ EXPECT_EQ(6u, f.size());
|
||||
+ EXPECT_EQ("world!", std::string(f.bytes().begin(), f.bytes().end()));
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, PendingFromDescriptor) {
|
||||
+ Fragment f = Fragment::PendingFromDescriptor({BufferId{0}, 5, 42});
|
||||
+ EXPECT_TRUE(f.is_pending());
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_EQ(5u, f.offset());
|
||||
+ EXPECT_EQ(42u, f.size());
|
||||
+
|
||||
+ f = Fragment::PendingFromDescriptor({kInvalidBufferId, 0, 0});
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, NullMappedFromDescriptor) {
|
||||
+ constexpr size_t kDataSize = 32;
|
||||
+ DriverMemory memory(kTestDriver, kDataSize);
|
||||
+ auto mapping = memory.Map();
|
||||
+
|
||||
+ Fragment f =
|
||||
+ Fragment::MappedFromDescriptor({kInvalidBufferId, 0, 0}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, InvalidMappedFromDescriptor) {
|
||||
+ constexpr size_t kDataSize = 32;
|
||||
+ DriverMemory memory(kTestDriver, kDataSize);
|
||||
+ auto mapping = memory.Map();
|
||||
+
|
||||
+ Fragment f;
|
||||
+
|
||||
+ // Offset out of bounds
|
||||
+ f = Fragment::MappedFromDescriptor({BufferId{0}, kDataSize, 1}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+
|
||||
+ // Tail out of bounds
|
||||
+ f = Fragment::MappedFromDescriptor({BufferId{0}, 0, kDataSize + 5}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+
|
||||
+ // Tail overflow
|
||||
+ f = Fragment::MappedFromDescriptor(
|
||||
+ {BufferId{0}, std::numeric_limits<uint32_t>::max(), 2}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, ValidMappedFromDescriptor) {
|
||||
+ const char kData[] = "0123456789abcdef";
|
||||
+ DriverMemory memory(kTestDriver, std::size(kData));
|
||||
+ auto mapping = memory.Map();
|
||||
+ memcpy(mapping.bytes().data(), kData, std::size(kData));
|
||||
+
|
||||
+ Fragment f = Fragment::MappedFromDescriptor({BufferId{0}, 2, 11}, mapping);
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+ EXPECT_EQ(2u, f.offset());
|
||||
+ EXPECT_EQ(11u, f.size());
|
||||
+ EXPECT_EQ("23456789abc", std::string(f.bytes().begin(), f.bytes().end()));
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+} // namespace ipcz
|
||||
diff --git a/third_party/ipcz/src/ipcz/node_link_memory.cc b/third_party/ipcz/src/ipcz/node_link_memory.cc
|
||||
index 480c756f48f8367d8adacdda4867e8d5766fa760..e424192e77f2bc51215320a9ca7489931dcaf8ba 100644
|
||||
--- a/third_party/ipcz/src/ipcz/node_link_memory.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/node_link_memory.cc
|
||||
@@ -260,8 +260,9 @@ FragmentRef<RouterLinkState> NodeLinkMemory::GetInitialRouterLinkState(
|
||||
FragmentDescriptor descriptor(kPrimaryBufferId,
|
||||
ToOffset(state, primary_buffer_memory_.data()),
|
||||
sizeof(RouterLinkState));
|
||||
- return FragmentRef<RouterLinkState>(RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(descriptor, state));
|
||||
+ return FragmentRef<RouterLinkState>(
|
||||
+ RefCountedFragment::kUnmanagedRef,
|
||||
+ Fragment::FromDescriptorUnsafe(descriptor, state));
|
||||
}
|
||||
|
||||
Fragment NodeLinkMemory::GetFragment(const FragmentDescriptor& descriptor) {
|
||||
diff --git a/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc b/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
|
||||
index d5a2243a693597e43f87f116f80599fde383cb59..220c3556a261c5caab7194114af4cf375d9af683 100644
|
||||
--- a/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
|
||||
@@ -64,7 +64,8 @@ TEST_F(RefCountedFragmentTest, SimpleRef) {
|
||||
|
||||
FragmentRef<TestObject> ref(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object)), &object));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object)), &object));
|
||||
EXPECT_EQ(1, object.ref_count_for_testing());
|
||||
ref.reset();
|
||||
EXPECT_EQ(0, object.ref_count_for_testing());
|
||||
@@ -75,7 +76,8 @@ TEST_F(RefCountedFragmentTest, Copy) {
|
||||
|
||||
FragmentRef<TestObject> ref1(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
EXPECT_EQ(1, object1.ref_count_for_testing());
|
||||
|
||||
FragmentRef<TestObject> other1 = ref1;
|
||||
@@ -88,7 +90,8 @@ TEST_F(RefCountedFragmentTest, Copy) {
|
||||
TestObject object2;
|
||||
auto ref2 = FragmentRef<TestObject>(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
EXPECT_EQ(1, object1.ref_count_for_testing());
|
||||
EXPECT_EQ(1, object2.ref_count_for_testing());
|
||||
ref2 = ref1;
|
||||
@@ -115,7 +118,8 @@ TEST_F(RefCountedFragmentTest, Move) {
|
||||
|
||||
FragmentRef<TestObject> ref1(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
EXPECT_EQ(1, ref1.ref_count_for_testing());
|
||||
|
||||
FragmentRef<TestObject> other1 = std::move(ref1);
|
||||
@@ -133,10 +137,12 @@ TEST_F(RefCountedFragmentTest, Move) {
|
||||
TestObject object3;
|
||||
FragmentRef<TestObject> ref2(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
FragmentRef<TestObject> ref3(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object3)), &object3));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object3)), &object3));
|
||||
|
||||
EXPECT_FALSE(ref2.is_null());
|
||||
EXPECT_TRUE(ref2.is_addressable());
|
||||
266
patches/chromium/cherry-pick-aa23556ff213.patch
Normal file
266
patches/chromium/cherry-pick-aa23556ff213.patch
Normal file
@@ -0,0 +1,266 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Alex Moshchuk <alexmos@chromium.org>
|
||||
Date: Tue, 13 Jun 2023 20:27:29 +0000
|
||||
Subject: Remove SiteInstanceDeleting from content/public API.
|
||||
|
||||
Currently, two unit tests are relying on
|
||||
ContentBrowserClient::SiteInstanceDeleting() to ensure that
|
||||
SiteInstance lifetimes are managed properly. However, it is
|
||||
undesirable to allow //content embedders to run arbitrary code during
|
||||
SiteInstance destruction, per the linked bug. Hence, this CL converts
|
||||
SiteInstanceDeleting() usage to a test-specific callback instead and
|
||||
removes it from ContentBrowserClient.
|
||||
|
||||
(cherry picked from commit f149f77b2a4f3416f8f7ea54a8fd972763c4b383)
|
||||
|
||||
Bug: 1444438
|
||||
Change-Id: I2affcb4a40ccfbf3bd715d7b225976a687405616
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4564316
|
||||
Commit-Queue: Alex Moshchuk <alexmos@chromium.org>
|
||||
Reviewed-by: Charlie Reis <creis@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1149171}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4610071
|
||||
Cr-Commit-Position: refs/branch-heads/5790@{#710}
|
||||
Cr-Branched-From: 1d71a337b1f6e707a13ae074dca1e2c34905eb9f-refs/heads/main@{#1148114}
|
||||
|
||||
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
|
||||
index 3fd0545c6a9a49e064d54d3292187e78a4900040..8ba13311bdd825d6b07b941769af94f6e9002091 100644
|
||||
--- a/content/browser/site_instance_impl.cc
|
||||
+++ b/content/browser/site_instance_impl.cc
|
||||
@@ -105,7 +105,9 @@ SiteInstanceImpl::SiteInstanceImpl(BrowsingInstance* browsing_instance)
|
||||
}
|
||||
|
||||
SiteInstanceImpl::~SiteInstanceImpl() {
|
||||
- GetContentClient()->browser()->SiteInstanceDeleting(this);
|
||||
+ if (destruction_callback_for_testing_) {
|
||||
+ std::move(destruction_callback_for_testing_).Run();
|
||||
+ }
|
||||
|
||||
// Now that no one is referencing us, we can safely remove ourselves from
|
||||
// the BrowsingInstance. Any future visits to a page from this site
|
||||
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
|
||||
index bea6b211ead2190960a3bf5a52ca888daa7c5797..28d03536c16aad7d4021e6a9efddd1bc06324ace 100644
|
||||
--- a/content/browser/site_instance_impl.h
|
||||
+++ b/content/browser/site_instance_impl.h
|
||||
@@ -446,6 +446,12 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance {
|
||||
// BrowsingInstance.
|
||||
RenderProcessHost* GetDefaultProcessForBrowsingInstance();
|
||||
|
||||
+ // Set a callback to be run from this SiteInstance's destructor. Used only in
|
||||
+ // tests.
|
||||
+ void set_destruction_callback_for_testing(base::OnceClosure callback) {
|
||||
+ destruction_callback_for_testing_ = std::move(callback);
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
friend class BrowsingInstance;
|
||||
friend class SiteInstanceTestBrowserClient;
|
||||
@@ -585,6 +591,12 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance {
|
||||
// Keeps track of whether we need to verify that the StoragePartition
|
||||
// information does not change when `site_info_` is set.
|
||||
bool verify_storage_partition_info_ = false;
|
||||
+
|
||||
+ // Tracks the number of active documents currently in this SiteInstance.
|
||||
+ size_t active_document_count_ = 0;
|
||||
+
|
||||
+ // Test-only callback to run when this SiteInstance is destroyed.
|
||||
+ base::OnceClosure destruction_callback_for_testing_;
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
|
||||
index 73a689bb2680bd7d76cf580c1a085923c0e1e464..e89c0866d23d8a6353eed4a5d424113112f3cad7 100644
|
||||
--- a/content/browser/site_instance_impl_unittest.cc
|
||||
+++ b/content/browser/site_instance_impl_unittest.cc
|
||||
@@ -91,32 +91,8 @@ class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
|
||||
privileged_process_id_ = process_id;
|
||||
}
|
||||
|
||||
- void SiteInstanceDeleting(content::SiteInstance* site_instance) override {
|
||||
- site_instance_delete_count_++;
|
||||
- // Infer deletion of the browsing instance.
|
||||
- if (static_cast<SiteInstanceImpl*>(site_instance)
|
||||
- ->browsing_instance_->HasOneRef()) {
|
||||
- browsing_instance_delete_count_++;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- int GetAndClearSiteInstanceDeleteCount() {
|
||||
- int result = site_instance_delete_count_;
|
||||
- site_instance_delete_count_ = 0;
|
||||
- return result;
|
||||
- }
|
||||
-
|
||||
- int GetAndClearBrowsingInstanceDeleteCount() {
|
||||
- int result = browsing_instance_delete_count_;
|
||||
- browsing_instance_delete_count_ = 0;
|
||||
- return result;
|
||||
- }
|
||||
-
|
||||
private:
|
||||
int privileged_process_id_ = -1;
|
||||
-
|
||||
- int site_instance_delete_count_ = 0;
|
||||
- int browsing_instance_delete_count_ = 0;
|
||||
};
|
||||
|
||||
class SiteInstanceTest : public testing::Test {
|
||||
@@ -193,6 +169,45 @@ class SiteInstanceTest : public testing::Test {
|
||||
/*should_compare_effective_urls=*/true);
|
||||
}
|
||||
|
||||
+ // Helper class to watch whether a particular SiteInstance has been
|
||||
+ // destroyed.
|
||||
+ class SiteInstanceDestructionObserver {
|
||||
+ public:
|
||||
+ SiteInstanceDestructionObserver() = default;
|
||||
+
|
||||
+ explicit SiteInstanceDestructionObserver(SiteInstanceImpl* site_instance) {
|
||||
+ SetSiteInstance(site_instance);
|
||||
+ }
|
||||
+
|
||||
+ void SetSiteInstance(SiteInstanceImpl* site_instance) {
|
||||
+ site_instance_ = site_instance;
|
||||
+ site_instance_->set_destruction_callback_for_testing(
|
||||
+ base::BindOnce(&SiteInstanceDestructionObserver::SiteInstanceDeleting,
|
||||
+ weak_factory_.GetWeakPtr()));
|
||||
+ }
|
||||
+
|
||||
+ void SiteInstanceDeleting() {
|
||||
+ ASSERT_FALSE(site_instance_deleted_);
|
||||
+ ASSERT_FALSE(browsing_instance_deleted_);
|
||||
+
|
||||
+ site_instance_deleted_ = true;
|
||||
+ // Infer deletion of the BrowsingInstance.
|
||||
+ if (site_instance_->browsing_instance_->HasOneRef()) {
|
||||
+ browsing_instance_deleted_ = true;
|
||||
+ }
|
||||
+ site_instance_ = nullptr;
|
||||
+ }
|
||||
+
|
||||
+ bool site_instance_deleted() { return site_instance_deleted_; }
|
||||
+ bool browsing_instance_deleted() { return browsing_instance_deleted_; }
|
||||
+
|
||||
+ private:
|
||||
+ raw_ptr<SiteInstanceImpl> site_instance_ = nullptr;
|
||||
+ bool site_instance_deleted_ = false;
|
||||
+ bool browsing_instance_deleted_ = false;
|
||||
+ base::WeakPtrFactory<SiteInstanceDestructionObserver> weak_factory_{this};
|
||||
+ };
|
||||
+
|
||||
private:
|
||||
BrowserTaskEnvironment task_environment_;
|
||||
TestBrowserContext context_;
|
||||
@@ -440,7 +455,8 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
|
||||
|
||||
// Ensure that instances are deleted when their NavigationEntries are gone.
|
||||
scoped_refptr<SiteInstanceImpl> instance = SiteInstanceImpl::Create(&context);
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
+ SiteInstanceDestructionObserver observer(instance.get());
|
||||
+ EXPECT_FALSE(observer.site_instance_deleted());
|
||||
|
||||
NavigationEntryImpl* e1 = new NavigationEntryImpl(
|
||||
instance, url, Referrer(), /* initiator_origin= */ absl::nullopt,
|
||||
@@ -450,8 +466,8 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
|
||||
|
||||
// Redundantly setting e1's SiteInstance shouldn't affect the ref count.
|
||||
e1->set_site_instance(instance);
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+ EXPECT_FALSE(observer.site_instance_deleted());
|
||||
+ EXPECT_FALSE(observer.browsing_instance_deleted());
|
||||
|
||||
// Add a second reference
|
||||
NavigationEntryImpl* e2 = new NavigationEntryImpl(
|
||||
@@ -461,36 +477,40 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
|
||||
false /* is_initial_entry */);
|
||||
|
||||
instance = nullptr;
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+
|
||||
+ EXPECT_FALSE(observer.site_instance_deleted());
|
||||
+ EXPECT_FALSE(observer.browsing_instance_deleted());
|
||||
|
||||
// Now delete both entries and be sure the SiteInstance goes away.
|
||||
delete e1;
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+ EXPECT_FALSE(observer.site_instance_deleted());
|
||||
+ EXPECT_FALSE(observer.browsing_instance_deleted());
|
||||
delete e2;
|
||||
// instance is now deleted
|
||||
- EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+ EXPECT_TRUE(observer.site_instance_deleted());
|
||||
+ EXPECT_TRUE(observer.browsing_instance_deleted());
|
||||
// browsing_instance is now deleted
|
||||
|
||||
- // Ensure that instances are deleted when their RenderViewHosts are gone.
|
||||
+ // Ensure that instances are deleted when their RenderFrameHosts are gone.
|
||||
std::unique_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
|
||||
+ SiteInstanceDestructionObserver observer2;
|
||||
{
|
||||
std::unique_ptr<WebContents> web_contents(
|
||||
WebContents::Create(WebContents::CreateParams(
|
||||
browser_context.get(),
|
||||
SiteInstance::Create(browser_context.get()))));
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+ observer2.SetSiteInstance(static_cast<SiteInstanceImpl*>(
|
||||
+ web_contents->GetPrimaryMainFrame()->GetSiteInstance()));
|
||||
+ EXPECT_FALSE(observer2.site_instance_deleted());
|
||||
+ EXPECT_FALSE(observer2.browsing_instance_deleted());
|
||||
}
|
||||
|
||||
// Make sure that we flush any messages related to the above WebContentsImpl
|
||||
// destruction.
|
||||
DrainMessageLoop();
|
||||
|
||||
- EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+ EXPECT_TRUE(observer2.site_instance_deleted());
|
||||
+ EXPECT_TRUE(observer2.browsing_instance_deleted());
|
||||
// contents is now deleted, along with instance and browsing_instance
|
||||
}
|
||||
|
||||
@@ -521,7 +541,6 @@ TEST_F(SiteInstanceTest, DefaultSiteInstanceProperties) {
|
||||
|
||||
auto site_instance = SiteInstanceImpl::CreateForTesting(
|
||||
&browser_context, GURL("http://foo.com"));
|
||||
-
|
||||
EXPECT_TRUE(site_instance->IsDefaultSiteInstance());
|
||||
EXPECT_TRUE(site_instance->HasSite());
|
||||
EXPECT_EQ(site_instance->GetSiteInfo(),
|
||||
@@ -547,14 +566,15 @@ TEST_F(SiteInstanceTest, DefaultSiteInstanceDestruction) {
|
||||
// are gone.
|
||||
auto site_instance = SiteInstanceImpl::CreateForTesting(
|
||||
&browser_context, GURL("http://foo.com"));
|
||||
+ SiteInstanceDestructionObserver observer(site_instance.get());
|
||||
|
||||
EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
|
||||
site_instance->IsDefaultSiteInstance());
|
||||
|
||||
site_instance.reset();
|
||||
|
||||
- EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
|
||||
- EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
|
||||
+ EXPECT_TRUE(observer.site_instance_deleted());
|
||||
+ EXPECT_TRUE(observer.browsing_instance_deleted());
|
||||
}
|
||||
|
||||
// Test to ensure GetProcess returns and creates processes correctly.
|
||||
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
||||
index 543b1712a9b744598ec6d851bc658e5b7e86d39e..757b20c73826e291c8958cc2bfaded2a8f8cd576 100644
|
||||
--- a/content/public/browser/content_browser_client.h
|
||||
+++ b/content/public/browser/content_browser_client.h
|
||||
@@ -582,9 +582,6 @@ class CONTENT_EXPORT ContentBrowserClient {
|
||||
// Called when a site instance is first associated with a process.
|
||||
virtual void SiteInstanceGotProcess(SiteInstance* site_instance) {}
|
||||
|
||||
- // Called from a site instance's destructor.
|
||||
- virtual void SiteInstanceDeleting(SiteInstance* site_instance) {}
|
||||
-
|
||||
// Returns true if for the navigation from |current_effective_url| to
|
||||
// |destination_effective_url| in |site_instance|, a new SiteInstance and
|
||||
// BrowsingInstance should be created (even if we are in a process model that
|
||||
119
patches/chromium/cherry-pick-b03973561862.patch
Normal file
119
patches/chromium/cherry-pick-b03973561862.patch
Normal file
@@ -0,0 +1,119 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tommi <tommi@chromium.org>
|
||||
Date: Wed, 5 Jul 2023 10:55:53 +0000
|
||||
Subject: Make RTCDataChannel's channel and observer pointers const.
|
||||
|
||||
This allows channel properties to be queried while the RTCDataChannel
|
||||
instance exists and avoids potential null deref after entering the
|
||||
kClosed state.
|
||||
|
||||
(cherry picked from commit 08d5ad011f53a1995bfccef6728bfa62541f7608)
|
||||
|
||||
Bug: 1456567, 1457421
|
||||
Change-Id: I4747f9c00804b35711667d7320ec6188f20910c4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4663082
|
||||
Commit-Queue: Tomas Gunnarsson <tommi@chromium.org>
|
||||
Reviewed-by: Elad Alon <eladalon@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1165406}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4665530
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#300}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
|
||||
index 26879ee20a09044bf1ea914e872599b4a2e65ec8..317023c42431319b20d1cc72bc40f52fffc7708a 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
|
||||
@@ -229,11 +229,12 @@ RTCDataChannel::Observer::Observer(
|
||||
scoped_refptr<webrtc::DataChannelInterface> channel)
|
||||
: main_thread_(main_thread),
|
||||
blink_channel_(blink_channel),
|
||||
- webrtc_channel_(channel) {}
|
||||
+ webrtc_channel_(std::move(channel)) {
|
||||
+ CHECK(webrtc_channel_.get());
|
||||
+}
|
||||
|
||||
RTCDataChannel::Observer::~Observer() {
|
||||
DCHECK(!blink_channel_) << "Reference to blink channel hasn't been released.";
|
||||
- DCHECK(!webrtc_channel_.get()) << "Unregister hasn't been called.";
|
||||
}
|
||||
|
||||
const scoped_refptr<webrtc::DataChannelInterface>&
|
||||
@@ -243,13 +244,8 @@ RTCDataChannel::Observer::channel() const {
|
||||
|
||||
void RTCDataChannel::Observer::Unregister() {
|
||||
DCHECK(main_thread_->BelongsToCurrentThread());
|
||||
+ webrtc_channel_->UnregisterObserver();
|
||||
blink_channel_ = nullptr;
|
||||
- if (webrtc_channel_.get()) {
|
||||
- webrtc_channel_->UnregisterObserver();
|
||||
- // Now that we're guaranteed to not get further OnStateChange callbacks,
|
||||
- // it's safe to release our reference to the channel.
|
||||
- webrtc_channel_ = nullptr;
|
||||
- }
|
||||
}
|
||||
|
||||
void RTCDataChannel::Observer::OnStateChange() {
|
||||
@@ -303,7 +299,7 @@ void RTCDataChannel::Observer::OnMessageImpl(
|
||||
|
||||
RTCDataChannel::RTCDataChannel(
|
||||
ExecutionContext* context,
|
||||
- scoped_refptr<webrtc::DataChannelInterface> channel,
|
||||
+ scoped_refptr<webrtc::DataChannelInterface> data_channel,
|
||||
RTCPeerConnectionHandler* peer_connection_handler)
|
||||
: ExecutionContextLifecycleObserver(context),
|
||||
state_(webrtc::DataChannelInterface::kConnecting),
|
||||
@@ -318,7 +314,7 @@ RTCDataChannel::RTCDataChannel(
|
||||
observer_(base::MakeRefCounted<Observer>(
|
||||
context->GetTaskRunner(TaskType::kNetworking),
|
||||
this,
|
||||
- channel)),
|
||||
+ std::move(data_channel))),
|
||||
signaling_thread_(peer_connection_handler->signaling_thread()) {
|
||||
DCHECK(peer_connection_handler);
|
||||
|
||||
@@ -341,7 +337,7 @@ RTCDataChannel::RTCDataChannel(
|
||||
observer_, state_),
|
||||
"RegisterObserverAndGetStateUpdate");
|
||||
|
||||
- IncrementCounters(*channel.get());
|
||||
+ IncrementCounters(*(observer_->channel()).get());
|
||||
}
|
||||
|
||||
RTCDataChannel::~RTCDataChannel() = default;
|
||||
@@ -690,9 +686,8 @@ void RTCDataChannel::Dispose() {
|
||||
if (stopped_)
|
||||
return;
|
||||
|
||||
- // Clears the weak persistent reference to this on-heap object.
|
||||
+ // Clear the weak persistent reference to this on-heap object.
|
||||
observer_->Unregister();
|
||||
- observer_ = nullptr;
|
||||
}
|
||||
|
||||
void RTCDataChannel::ScheduleDispatchEvent(Event* event) {
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
|
||||
index 21bb39382ac0c6acbf984ffbda5f6a4e6c863432..6959b8b1e3a0b586be68cb4a8d0389b7926b98fe 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
|
||||
@@ -152,7 +152,7 @@ class MODULES_EXPORT RTCDataChannel final
|
||||
|
||||
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
|
||||
WeakPersistent<RTCDataChannel> blink_channel_;
|
||||
- scoped_refptr<webrtc::DataChannelInterface> webrtc_channel_;
|
||||
+ const scoped_refptr<webrtc::DataChannelInterface> webrtc_channel_;
|
||||
};
|
||||
|
||||
void OnStateChange(webrtc::DataChannelInterface::DataState state);
|
||||
@@ -195,7 +195,11 @@ class MODULES_EXPORT RTCDataChannel final
|
||||
unsigned buffered_amount_;
|
||||
bool stopped_;
|
||||
bool closed_from_owner_;
|
||||
- scoped_refptr<Observer> observer_;
|
||||
+ // Keep the `observer_` reference const to make it clear that we don't want
|
||||
+ // to free the underlying channel (or callback observer) until the
|
||||
+ // `RTCDataChannel` instance goes away. This allows properties to be queried
|
||||
+ // after the state reaches `kClosed`.
|
||||
+ const scoped_refptr<Observer> observer_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
|
||||
THREAD_CHECKER(thread_checker_);
|
||||
};
|
||||
187
patches/chromium/cherry-pick-c60a1ab717c7.patch
Normal file
187
patches/chromium/cherry-pick-c60a1ab717c7.patch
Normal file
@@ -0,0 +1,187 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taylor Bergquist <tbergquist@chromium.org>
|
||||
Date: Tue, 11 Jul 2023 01:32:22 +0000
|
||||
Subject: Fix UAF when exiting a nested run loop in
|
||||
TabDragContextImpl::OnGestureEvent.
|
||||
|
||||
OnGestureEvent may call ContinueDrag, which may run a nested run loop. After the nested run loop returns, multiple seconds of time may have passed, and the world may be in a very different state; in particular, the window that contains this TabDragContext may have closed.
|
||||
|
||||
This CL checks if this has happened, and returns early in that case.
|
||||
|
||||
(cherry picked from commit 63d6b8ba8126b16215d33670df8c67dcbc6c9bef)
|
||||
|
||||
Bug: 1453465
|
||||
Change-Id: I6095c0afeb5aa5f422717f1bbd93b96175e52afa
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4657527
|
||||
Reviewed-by: Darryl James <dljames@chromium.org>
|
||||
Commit-Queue: Taylor Bergquist <tbergquist@chromium.org>
|
||||
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1164449}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4676126
|
||||
Reviewed-by: Shibalik Mohapatra <shibalik@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#410}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
|
||||
index d1f5a96ed729fde1224f596212f49e386fc6f170..c80536b0d4601c68ce279dfa122f38b39b13fb72 100644
|
||||
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
|
||||
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
|
||||
@@ -43,6 +43,12 @@ bool FakeTabSlotController::IsFocusInTabs() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
+TabSlotController::Liveness FakeTabSlotController::ContinueDrag(
|
||||
+ views::View* view,
|
||||
+ const ui::LocatedEvent& event) {
|
||||
+ return Liveness::kAlive;
|
||||
+}
|
||||
+
|
||||
bool FakeTabSlotController::EndDrag(EndDragReason reason) {
|
||||
return false;
|
||||
}
|
||||
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
|
||||
index 25f1c66d131189ebec2711b49f7f0c141f2c06d2..98dab21cfe2e3ecb88f70cac3868fb30828658be 100644
|
||||
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
|
||||
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
|
||||
@@ -60,8 +60,8 @@ class FakeTabSlotController : public TabSlotController {
|
||||
TabSlotView* source,
|
||||
const ui::LocatedEvent& event,
|
||||
const ui::ListSelectionModel& original_selection) override {}
|
||||
- void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override {
|
||||
- }
|
||||
+ Liveness ContinueDrag(views::View* view,
|
||||
+ const ui::LocatedEvent& event) override;
|
||||
bool EndDrag(EndDragReason reason) override;
|
||||
Tab* GetTabAt(const gfx::Point& point) override;
|
||||
const Tab* GetAdjacentTab(const Tab* tab, int offset) override;
|
||||
diff --git a/chrome/browser/ui/views/tabs/tab_slot_controller.h b/chrome/browser/ui/views/tabs/tab_slot_controller.h
|
||||
index f729425995ffd1ee6926ef953417d2e81a1b527b..c57760f30ae515cf5ee7a021e07c8d049082e371 100644
|
||||
--- a/chrome/browser/ui/views/tabs/tab_slot_controller.h
|
||||
+++ b/chrome/browser/ui/views/tabs/tab_slot_controller.h
|
||||
@@ -49,6 +49,8 @@ class TabSlotController {
|
||||
kEvent
|
||||
};
|
||||
|
||||
+ enum class Liveness { kAlive, kDeleted };
|
||||
+
|
||||
virtual const ui::ListSelectionModel& GetSelectionModel() const = 0;
|
||||
|
||||
// Returns the tab at |index|.
|
||||
@@ -126,9 +128,10 @@ class TabSlotController {
|
||||
const ui::LocatedEvent& event,
|
||||
const ui::ListSelectionModel& original_selection) = 0;
|
||||
|
||||
- // Continues dragging a Tab.
|
||||
- virtual void ContinueDrag(views::View* view,
|
||||
- const ui::LocatedEvent& event) = 0;
|
||||
+ // Continues dragging a Tab. May enter a nested event loop - returns
|
||||
+ // Liveness::kDeleted if `this` was destroyed during this nested event loop,
|
||||
+ // and Liveness::kAlive if `this` is still alive.
|
||||
+ virtual Liveness ContinueDrag(views::View* view, const ui::LocatedEvent& event) = 0;
|
||||
|
||||
// Ends dragging a Tab. Returns whether the tab has been destroyed.
|
||||
virtual bool EndDrag(EndDragReason reason) = 0;
|
||||
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
|
||||
index c847ab83eaf94af83b0253747e6d15018d4eb5cf..8e5f40ca5a20f6010c573a51c816c0709322906c 100644
|
||||
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
|
||||
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
|
||||
@@ -179,7 +179,7 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
}
|
||||
|
||||
bool OnMouseDragged(const ui::MouseEvent& event) override {
|
||||
- ContinueDrag(this, event);
|
||||
+ (void)ContinueDrag(this, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
void OnMouseCaptureLost() override { EndDrag(END_DRAG_CAPTURE_LOST); }
|
||||
|
||||
void OnGestureEvent(ui::GestureEvent* event) override {
|
||||
+ Liveness tabstrip_alive = Liveness::kAlive;
|
||||
switch (event->type()) {
|
||||
case ui::ET_GESTURE_SCROLL_END:
|
||||
case ui::ET_SCROLL_FLING_START:
|
||||
@@ -203,7 +204,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
}
|
||||
|
||||
case ui::ET_GESTURE_SCROLL_UPDATE:
|
||||
- ContinueDrag(this, *event);
|
||||
+ // N.B. !! ContinueDrag may enter a nested run loop !!
|
||||
+ tabstrip_alive = ContinueDrag(this, *event);
|
||||
break;
|
||||
|
||||
case ui::ET_GESTURE_TAP_DOWN:
|
||||
@@ -215,6 +217,12 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
}
|
||||
event->SetHandled();
|
||||
|
||||
+ // If tabstrip was destroyed (during ContinueDrag above), return early to
|
||||
+ // avoid UAF below.
|
||||
+ if (tabstrip_alive == Liveness::kDeleted) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// TabDragContext gets event capture as soon as a drag session begins, which
|
||||
// precludes TabStrip from ever getting events like tap or long tap. Forward
|
||||
// this on to TabStrip so it can respond to those events.
|
||||
@@ -303,20 +311,20 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
std::move(drag_controller_set_callback_).Run(drag_controller_.get());
|
||||
}
|
||||
|
||||
- void ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
|
||||
- if (drag_controller_.get() &&
|
||||
- drag_controller_->event_source() == EventSourceFromEvent(event)) {
|
||||
- gfx::Point screen_location(event.location());
|
||||
- views::View::ConvertPointToScreen(view, &screen_location);
|
||||
+ Liveness ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
|
||||
+ if (!drag_controller_.get() ||
|
||||
+ drag_controller_->event_source() != EventSourceFromEvent(event)) {
|
||||
+ return Liveness::kAlive;
|
||||
+ }
|
||||
|
||||
- // Note: |tab_strip_| can be destroyed during drag, also destroying
|
||||
- // |this|.
|
||||
- base::WeakPtr<TabDragContext> weak_ptr(weak_factory_.GetWeakPtr());
|
||||
- drag_controller_->Drag(screen_location);
|
||||
+ gfx::Point screen_location(event.location());
|
||||
+ views::View::ConvertPointToScreen(view, &screen_location);
|
||||
|
||||
- if (!weak_ptr)
|
||||
- return;
|
||||
- }
|
||||
+ // Note: `tab_strip_` can be destroyed during drag, also destroying `this`.
|
||||
+ base::WeakPtr<TabDragContext> weak_ptr(weak_factory_.GetWeakPtr());
|
||||
+ drag_controller_->Drag(screen_location);
|
||||
+
|
||||
+ return weak_ptr ? Liveness::kAlive : Liveness::kDeleted;
|
||||
}
|
||||
|
||||
bool EndDrag(EndDragReason reason) {
|
||||
@@ -1601,8 +1609,10 @@ void TabStrip::MaybeStartDrag(
|
||||
drag_context_->MaybeStartDrag(source, event, original_selection);
|
||||
}
|
||||
|
||||
-void TabStrip::ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
|
||||
- drag_context_->ContinueDrag(view, event);
|
||||
+TabSlotController::Liveness TabStrip::ContinueDrag(
|
||||
+ views::View* view,
|
||||
+ const ui::LocatedEvent& event) {
|
||||
+ return drag_context_->ContinueDrag(view, event);
|
||||
}
|
||||
|
||||
bool TabStrip::EndDrag(EndDragReason reason) {
|
||||
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
|
||||
index bae5dee16134a343173c3fd3f6005aef76ac1e25..ea3397c7da33ac5933caf7a8e9816a931ee064e7 100644
|
||||
--- a/chrome/browser/ui/views/tabs/tab_strip.h
|
||||
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
|
||||
@@ -277,7 +277,8 @@ class TabStrip : public views::View,
|
||||
TabSlotView* source,
|
||||
const ui::LocatedEvent& event,
|
||||
const ui::ListSelectionModel& original_selection) override;
|
||||
- void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override;
|
||||
+ Liveness ContinueDrag(views::View* view,
|
||||
+ const ui::LocatedEvent& event) override;
|
||||
bool EndDrag(EndDragReason reason) override;
|
||||
Tab* GetTabAt(const gfx::Point& point) override;
|
||||
const Tab* GetAdjacentTab(const Tab* tab, int offset) override;
|
||||
@@ -82,7 +82,7 @@ index 33ca7a53dfb6d2c9e3a33f0065a3acd806e82e01..9fdf2e8ff0056ff407015b914c6b03eb
|
||||
const Source& GetSource(int index) const override;
|
||||
DesktopMediaList::Type GetMediaListType() const override;
|
||||
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
index b548c9fbd3c0bf425447b29dcd866cd27e96b14c..f994ac6086c7b4cd3e8534f34691189d78a21601 100644
|
||||
index b548c9fbd3c0bf425447b29dcd866cd27e96b14c..4de719510eaeaaf77cdbd46560f3b4ab1869877a 100644
|
||||
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
@@ -147,7 +147,7 @@ BOOL CALLBACK AllHwndCollector(HWND hwnd, LPARAM param) {
|
||||
@@ -94,17 +94,20 @@ index b548c9fbd3c0bf425447b29dcd866cd27e96b14c..f994ac6086c7b4cd3e8534f34691189d
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
@@ -457,6 +457,9 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() {
|
||||
@@ -457,6 +457,12 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() {
|
||||
FROM_HERE,
|
||||
base::BindOnce(&NativeDesktopMediaList::UpdateNativeThumbnailsFinished,
|
||||
media_list_));
|
||||
+
|
||||
+ // This call is necessary to release underlying OS screen capture mechanisms.
|
||||
+ capturer_.reset();
|
||||
+ // Skip if the source list is delegated, as the source list window will be active.
|
||||
+ if (!capturer_->GetDelegatedSourceListController()) {
|
||||
+ capturer_.reset();
|
||||
+ }
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::Worker::OnCaptureResult(
|
||||
@@ -829,6 +832,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows(
|
||||
@@ -829,6 +835,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows(
|
||||
FROM_HERE, base::BindOnce(&Worker::RefreshThumbnails,
|
||||
base::Unretained(worker_.get()),
|
||||
std::move(native_ids), thumbnail_size_));
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Athul Iddya <athul@iddya.com>
|
||||
Date: Fri, 14 Jul 2023 08:03:37 -0700
|
||||
Subject: fix: use delegated generic capturer when available
|
||||
|
||||
When the generic capturer is used to fetch capture sources, the returned
|
||||
ID will be arbitrarily prefixed with "screen" or "window" regardless of
|
||||
the source type. If the window capturer is used to stream video when the
|
||||
source was a screen or vice-versa, the stream fails to restart in
|
||||
delegated capturers like PipeWire.
|
||||
|
||||
To fix this, use the generic capturer to fetch the media stream if it's
|
||||
delegated and available. This does not cause any issues if the original
|
||||
capturer was window or screen-specific, as the IDs remain valid for
|
||||
generic capturer as well.
|
||||
|
||||
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
|
||||
index 18b03b2f3cc6a36df1241decef190114eeacfb1f..a65989fcab06caea2cb955f7da050d8328cbcae4 100644
|
||||
--- a/content/browser/media/capture/desktop_capture_device.cc
|
||||
+++ b/content/browser/media/capture/desktop_capture_device.cc
|
||||
@@ -622,8 +622,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
|
||||
DesktopCapturerLacros::CaptureType::kScreen,
|
||||
webrtc::DesktopCaptureOptions());
|
||||
#else
|
||||
- std::unique_ptr<webrtc::DesktopCapturer> screen_capturer(
|
||||
- webrtc::DesktopCapturer::CreateScreenCapturer(options));
|
||||
+ std::unique_ptr<webrtc::DesktopCapturer> screen_capturer;
|
||||
+ if (auto generic_capturer =
|
||||
+ webrtc::DesktopCapturer::CreateGenericCapturer(options);
|
||||
+ generic_capturer && generic_capturer->GetDelegatedSourceListController()) {
|
||||
+ screen_capturer = std::move(generic_capturer);
|
||||
+ } else {
|
||||
+ screen_capturer = webrtc::DesktopCapturer::CreateScreenCapturer(options);
|
||||
+ }
|
||||
#endif
|
||||
if (screen_capturer && screen_capturer->SelectSource(source.id)) {
|
||||
capturer = std::make_unique<webrtc::DesktopAndCursorComposer>(
|
||||
@@ -642,8 +648,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
|
||||
new DesktopCapturerLacros(DesktopCapturerLacros::CaptureType::kWindow,
|
||||
webrtc::DesktopCaptureOptions()));
|
||||
#else
|
||||
- std::unique_ptr<webrtc::DesktopCapturer> window_capturer =
|
||||
- webrtc::DesktopCapturer::CreateWindowCapturer(options);
|
||||
+ std::unique_ptr<webrtc::DesktopCapturer> window_capturer;
|
||||
+ if (auto generic_capturer =
|
||||
+ webrtc::DesktopCapturer::CreateGenericCapturer(options);
|
||||
+ generic_capturer && generic_capturer->GetDelegatedSourceListController()) {
|
||||
+ window_capturer = std::move(generic_capturer);
|
||||
+ } else {
|
||||
+ window_capturer = webrtc::DesktopCapturer::CreateWindowCapturer(options);
|
||||
+ }
|
||||
#endif
|
||||
if (window_capturer && window_capturer->SelectSource(source.id)) {
|
||||
capturer = std::make_unique<webrtc::DesktopAndCursorComposer>(
|
||||
@@ -0,0 +1,93 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Adam Rice <ricea@chromium.org>
|
||||
Date: Tue, 8 Aug 2023 08:48:51 +0000
|
||||
Subject: NetworkContext: Don't access url_loader_factories_ during destruction
|
||||
|
||||
Move the contents of `url_loader_factories_` to a temporary variable in
|
||||
the destructor of network::NetworkContext so that re-entrant calls to
|
||||
DestroyURLLoaderFactory() don't happen after it has started being
|
||||
destroyed.
|
||||
|
||||
BUG=1465833
|
||||
|
||||
(cherry picked from commit e579b20308290df03f045c5d0ccb852d96b24ce3)
|
||||
|
||||
Change-Id: I476f0865256bdcba4ec934688597e69991968f84
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4733351
|
||||
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
|
||||
Commit-Queue: Adam Rice <ricea@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1177648}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4756334
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Auto-Submit: Adam Rice <ricea@chromium.org>
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#1252}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
|
||||
index 97fa9e6e96fde894feb7da28afca6f65a310199d..d3cda420386ce946568fdc2656308d9c3cf3b610 100644
|
||||
--- a/services/network/network_context.cc
|
||||
+++ b/services/network/network_context.cc
|
||||
@@ -692,6 +692,8 @@ NetworkContext::NetworkContext(
|
||||
}
|
||||
|
||||
NetworkContext::~NetworkContext() {
|
||||
+ is_destructing_ = true;
|
||||
+
|
||||
// May be nullptr in tests.
|
||||
if (network_service_)
|
||||
network_service_->DeregisterNetworkContext(this);
|
||||
@@ -749,6 +751,12 @@ NetworkContext::~NetworkContext() {
|
||||
}
|
||||
}
|
||||
#endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
|
||||
+
|
||||
+ // Clear `url_loader_factories_` before deleting the contents, as it can
|
||||
+ // result in re-entrant calls to DestroyURLLoaderFactory().
|
||||
+ std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
|
||||
+ base::UniquePtrComparator>
|
||||
+ url_loader_factories = std::move(url_loader_factories_);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -974,6 +982,9 @@ void NetworkContext::DisableQuic() {
|
||||
|
||||
void NetworkContext::DestroyURLLoaderFactory(
|
||||
cors::CorsURLLoaderFactory* url_loader_factory) {
|
||||
+ if (is_destructing_) {
|
||||
+ return;
|
||||
+ }
|
||||
auto it = url_loader_factories_.find(url_loader_factory);
|
||||
DCHECK(it != url_loader_factories_.end());
|
||||
url_loader_factories_.erase(it);
|
||||
diff --git a/services/network/network_context.h b/services/network/network_context.h
|
||||
index 06cd75b4aa3ee7a582fe9a2b2cd288cb61b3c19e..fd3655943b1b1caf8a6db35219f437113163276a 100644
|
||||
--- a/services/network/network_context.h
|
||||
+++ b/services/network/network_context.h
|
||||
@@ -915,6 +915,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
|
||||
// according to the spec.
|
||||
bool acam_preflight_spec_conformant_ = true;
|
||||
|
||||
+ // True once the destructor has been called. Used to guard against re-entrant
|
||||
+ // calls to DestroyURLLoaderFactory().
|
||||
+ bool is_destructing_ = false;
|
||||
+
|
||||
// Indicating whether
|
||||
// https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name is
|
||||
// supported.
|
||||
@@ -923,13 +927,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
|
||||
|
||||
// CorsURLLoaderFactory assumes that fields owned by the NetworkContext always
|
||||
// live longer than the factory. Therefore we want the factories to be
|
||||
- // destroyed before other fields above. In particular:
|
||||
- // - This must be below |url_request_context_| so that the URLRequestContext
|
||||
- // outlives all the URLLoaderFactories and URLLoaders that depend on it;
|
||||
- // for the same reason, it must also be below |network_context_|.
|
||||
- // - This must be below |loader_count_per_process_| that is touched by
|
||||
- // CorsURLLoaderFactory::DestroyURLLoader (see also
|
||||
- // https://crbug.com/1174943).
|
||||
+ // destroyed before other fields above. This is accomplished by explicitly
|
||||
+ // clearing `url_loader_factories_` in the destructor.
|
||||
std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
|
||||
base::UniquePtrComparator>
|
||||
url_loader_factories_;
|
||||
@@ -25,5 +25,11 @@
|
||||
|
||||
"src/electron/patches/webrtc": "src/third_party/webrtc",
|
||||
|
||||
"src/electron/patches/pdfium": "src/third_party/pdfium"
|
||||
"src/electron/patches/pdfium": "src/third_party/pdfium",
|
||||
|
||||
"src/electron/patches/skia": "src/third_party/skia",
|
||||
|
||||
"src/electron/patches/libwebp": "src/third_party/libwebp/src",
|
||||
|
||||
"src/electron/patches/libvpx": "src/third_party/libvpx/source/libvpx"
|
||||
}
|
||||
|
||||
1
patches/libvpx/.patches
Normal file
1
patches/libvpx/.patches
Normal file
@@ -0,0 +1 @@
|
||||
cherry-pick-3fbd1dca6a4d.patch
|
||||
27
patches/libvpx/cherry-pick-3fbd1dca6a4d.patch
Normal file
27
patches/libvpx/cherry-pick-3fbd1dca6a4d.patch
Normal file
@@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: James Zern <jzern@google.com>
|
||||
Date: Mon, 25 Sep 2023 18:55:59 -0700
|
||||
Subject: VP8: disallow thread count changes
|
||||
|
||||
Currently allocations are done at encoder creation time. Going from
|
||||
threaded to non-threaded would cause a crash.
|
||||
|
||||
Bug: chromium:1486441
|
||||
Change-Id: Ie301c2a70847dff2f0daae408fbef1e4d42e73d4
|
||||
|
||||
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
|
||||
index 4bbeadef013c8e0a1ae8d9241b90489e37ab36d7..148a16cc493d109fee859a9628f58e7361b02e0d 100644
|
||||
--- a/vp8/encoder/onyx_if.c
|
||||
+++ b/vp8/encoder/onyx_if.c
|
||||
@@ -1443,6 +1443,11 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) {
|
||||
last_h = cpi->oxcf.Height;
|
||||
prev_number_of_layers = cpi->oxcf.number_of_layers;
|
||||
|
||||
+ if (cpi->initial_width) {
|
||||
+ // TODO(https://crbug.com/1486441): Allow changing thread counts; the
|
||||
+ // allocation is done once in vp8_create_compressor().
|
||||
+ oxcf->multi_threaded = cpi->oxcf.multi_threaded;
|
||||
+ }
|
||||
cpi->oxcf = *oxcf;
|
||||
|
||||
switch (cpi->oxcf.Mode) {
|
||||
1
patches/libwebp/.patches
Normal file
1
patches/libwebp/.patches
Normal file
@@ -0,0 +1 @@
|
||||
fix_oob_write_in_buildhuffmantable.patch
|
||||
354
patches/libwebp/fix_oob_write_in_buildhuffmantable.patch
Normal file
354
patches/libwebp/fix_oob_write_in_buildhuffmantable.patch
Normal file
@@ -0,0 +1,354 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Vincent Rabaud <vrabaud@google.com>
|
||||
Date: Thu, 7 Sep 2023 21:16:03 +0200
|
||||
Subject: Fix OOB write in BuildHuffmanTable.
|
||||
|
||||
First, BuildHuffmanTable is called to check if the data is valid.
|
||||
If it is and the table is not big enough, more memory is allocated.
|
||||
|
||||
This will make sure that valid (but unoptimized because of unbalanced
|
||||
codes) streams are still decodable.
|
||||
|
||||
Bug: chromium:1479274
|
||||
Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
|
||||
(cherry picked from commit 902bc9190331343b2017211debcec8d2ab87e17a)
|
||||
(cherry picked from commit 2af26267cdfcb63a88e5c74a85927a12d6ca1d76)
|
||||
(cherry picked from commit 904941b437ccc2f14de7cd791994f655c3583050)
|
||||
|
||||
diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c
|
||||
index c0ea0181e52e31e8c03d6abe5597f3c50b8e4c09..7995313fa19cafe3b48bb6e3ad6160c8cac407e6 100644
|
||||
--- a/src/dec/vp8l_dec.c
|
||||
+++ b/src/dec/vp8l_dec.c
|
||||
@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
|
||||
int symbol;
|
||||
int max_symbol;
|
||||
int prev_code_len = DEFAULT_CODE_LENGTH;
|
||||
- HuffmanCode table[1 << LENGTHS_TABLE_BITS];
|
||||
+ HuffmanTables tables;
|
||||
|
||||
- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
|
||||
- code_length_code_lengths,
|
||||
- NUM_CODE_LENGTH_CODES)) {
|
||||
+ if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
|
||||
+ !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
|
||||
+ code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
|
||||
goto End;
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
|
||||
int code_len;
|
||||
if (max_symbol-- == 0) break;
|
||||
VP8LFillBitWindow(br);
|
||||
- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
|
||||
+ p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
|
||||
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
|
||||
code_len = p->value;
|
||||
if (code_len < kCodeLengthLiterals) {
|
||||
@@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
|
||||
ok = 1;
|
||||
|
||||
End:
|
||||
+ VP8LHuffmanTablesDeallocate(&tables);
|
||||
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
|
||||
return ok;
|
||||
}
|
||||
@@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
|
||||
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
|
||||
// tree.
|
||||
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
||||
- int* const code_lengths, HuffmanCode* const table) {
|
||||
+ int* const code_lengths,
|
||||
+ HuffmanTables* const table) {
|
||||
int ok = 0;
|
||||
int size = 0;
|
||||
VP8LBitReader* const br = &dec->br_;
|
||||
@@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
VP8LMetadata* const hdr = &dec->hdr_;
|
||||
uint32_t* huffman_image = NULL;
|
||||
HTreeGroup* htree_groups = NULL;
|
||||
- HuffmanCode* huffman_tables = NULL;
|
||||
- HuffmanCode* huffman_table = NULL;
|
||||
+ HuffmanTables* huffman_tables = &hdr->huffman_tables_;
|
||||
int num_htree_groups = 1;
|
||||
int num_htree_groups_max = 1;
|
||||
int max_alphabet_size = 0;
|
||||
@@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
int* mapping = NULL;
|
||||
int ok = 0;
|
||||
|
||||
+ // Check the table has been 0 initialized (through InitMetadata).
|
||||
+ assert(huffman_tables->root.start == NULL);
|
||||
+ assert(huffman_tables->curr_segment == NULL);
|
||||
+
|
||||
if (allow_recursion && VP8LReadBits(br, 1)) {
|
||||
// use meta Huffman codes.
|
||||
const int huffman_precision = VP8LReadBits(br, 3) + 2;
|
||||
@@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
|
||||
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
|
||||
sizeof(*code_lengths));
|
||||
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
|
||||
- sizeof(*huffman_tables));
|
||||
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
|
||||
|
||||
- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
|
||||
+ if (htree_groups == NULL || code_lengths == NULL ||
|
||||
+ !VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
|
||||
+ huffman_tables)) {
|
||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
- huffman_table = huffman_tables;
|
||||
for (i = 0; i < num_htree_groups_max; ++i) {
|
||||
// If the index "i" is unused in the Huffman image, just make sure the
|
||||
// coefficients are valid but do not store them.
|
||||
@@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
int max_bits = 0;
|
||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||
int alphabet_size = kAlphabetSize[j];
|
||||
- htrees[j] = huffman_table;
|
||||
if (j == 0 && color_cache_bits > 0) {
|
||||
alphabet_size += (1 << color_cache_bits);
|
||||
}
|
||||
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
|
||||
+ size =
|
||||
+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
|
||||
+ htrees[j] = huffman_tables->curr_segment->curr_table;
|
||||
if (size == 0) {
|
||||
goto Error;
|
||||
}
|
||||
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
||||
- is_trivial_literal = (huffman_table->bits == 0);
|
||||
+ is_trivial_literal = (htrees[j]->bits == 0);
|
||||
}
|
||||
- total_size += huffman_table->bits;
|
||||
- huffman_table += size;
|
||||
+ total_size += htrees[j]->bits;
|
||||
+ huffman_tables->curr_segment->curr_table += size;
|
||||
if (j <= ALPHA) {
|
||||
int local_max_bits = code_lengths[0];
|
||||
int k;
|
||||
@@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
hdr->huffman_image_ = huffman_image;
|
||||
hdr->num_htree_groups_ = num_htree_groups;
|
||||
hdr->htree_groups_ = htree_groups;
|
||||
- hdr->huffman_tables_ = huffman_tables;
|
||||
|
||||
Error:
|
||||
WebPSafeFree(code_lengths);
|
||||
WebPSafeFree(mapping);
|
||||
if (!ok) {
|
||||
WebPSafeFree(huffman_image);
|
||||
- WebPSafeFree(huffman_tables);
|
||||
+ VP8LHuffmanTablesDeallocate(huffman_tables);
|
||||
VP8LHtreeGroupsFree(htree_groups);
|
||||
}
|
||||
return ok;
|
||||
@@ -1358,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
|
||||
assert(hdr != NULL);
|
||||
|
||||
WebPSafeFree(hdr->huffman_image_);
|
||||
- WebPSafeFree(hdr->huffman_tables_);
|
||||
+ VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
|
||||
VP8LHtreeGroupsFree(hdr->htree_groups_);
|
||||
VP8LColorCacheClear(&hdr->color_cache_);
|
||||
VP8LColorCacheClear(&hdr->saved_color_cache_);
|
||||
@@ -1673,7 +1677,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
|
||||
|
||||
if (dec == NULL) return 0;
|
||||
|
||||
- assert(dec->hdr_.huffman_tables_ != NULL);
|
||||
+ assert(dec->hdr_.huffman_tables_.root.start != NULL);
|
||||
assert(dec->hdr_.htree_groups_ != NULL);
|
||||
assert(dec->hdr_.num_htree_groups_ > 0);
|
||||
|
||||
diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h
|
||||
index 72b2e861208447f45e5ee12eac57b9c36ff2cd31..32540a4b88a05cc74b88f11da3f143e83be81c9c 100644
|
||||
--- a/src/dec/vp8li_dec.h
|
||||
+++ b/src/dec/vp8li_dec.h
|
||||
@@ -51,7 +51,7 @@ typedef struct {
|
||||
uint32_t* huffman_image_;
|
||||
int num_htree_groups_;
|
||||
HTreeGroup* htree_groups_;
|
||||
- HuffmanCode* huffman_tables_;
|
||||
+ HuffmanTables huffman_tables_;
|
||||
} VP8LMetadata;
|
||||
|
||||
typedef struct VP8LDecoder VP8LDecoder;
|
||||
diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c
|
||||
index 90c2fbf7c18c79ccb3597fe7cbbc332dbd1b2548..cf73abd437d02173f43c61c8877a5f467997774a 100644
|
||||
--- a/src/utils/huffman_utils.c
|
||||
+++ b/src/utils/huffman_utils.c
|
||||
@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
if (num_open < 0) {
|
||||
return 0;
|
||||
}
|
||||
- if (root_table == NULL) continue;
|
||||
for (; count[len] > 0; --count[len]) {
|
||||
HuffmanCode code;
|
||||
if ((key & mask) != low) {
|
||||
- table += table_size;
|
||||
+ if (root_table != NULL) table += table_size;
|
||||
table_bits = NextTableBitSize(count, len, root_bits);
|
||||
table_size = 1 << table_bits;
|
||||
total_size += table_size;
|
||||
low = key & mask;
|
||||
- root_table[low].bits = (uint8_t)(table_bits + root_bits);
|
||||
- root_table[low].value = (uint16_t)((table - root_table) - low);
|
||||
+ if (root_table != NULL) {
|
||||
+ root_table[low].bits = (uint8_t)(table_bits + root_bits);
|
||||
+ root_table[low].value = (uint16_t)((table - root_table) - low);
|
||||
+ }
|
||||
+ }
|
||||
+ if (root_table != NULL) {
|
||||
+ code.bits = (uint8_t)(len - root_bits);
|
||||
+ code.value = (uint16_t)sorted[symbol++];
|
||||
+ ReplicateValue(&table[key >> root_bits], step, table_size, code);
|
||||
}
|
||||
- code.bits = (uint8_t)(len - root_bits);
|
||||
- code.value = (uint16_t)sorted[symbol++];
|
||||
- ReplicateValue(&table[key >> root_bits], step, table_size, code);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
@@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
|
||||
// Cut-off value for switching between heap and stack allocation.
|
||||
#define SORTED_SIZE_CUTOFF 512
|
||||
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
|
||||
const int code_lengths[], int code_lengths_size) {
|
||||
- int total_size;
|
||||
+ const int total_size =
|
||||
+ BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
|
||||
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
|
||||
- if (root_table == NULL) {
|
||||
- total_size = BuildHuffmanTable(NULL, root_bits,
|
||||
- code_lengths, code_lengths_size, NULL);
|
||||
- } else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||
+ if (total_size == 0 || root_table == NULL) return total_size;
|
||||
+
|
||||
+ if (root_table->curr_segment->curr_table + total_size >=
|
||||
+ root_table->curr_segment->start + root_table->curr_segment->size) {
|
||||
+ // If 'root_table' does not have enough memory, allocate a new segment.
|
||||
+ // The available part of root_table->curr_segment is left unused because we
|
||||
+ // need a contiguous buffer.
|
||||
+ const int segment_size = root_table->curr_segment->size;
|
||||
+ struct HuffmanTablesSegment* next =
|
||||
+ (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
|
||||
+ if (next == NULL) return 0;
|
||||
+ // Fill the new segment.
|
||||
+ // We need at least 'total_size' but if that value is small, it is better to
|
||||
+ // allocate a big chunk to prevent more allocations later. 'segment_size' is
|
||||
+ // therefore chosen (any other arbitrary value could be chosen).
|
||||
+ next->size = total_size > segment_size ? total_size : segment_size;
|
||||
+ next->start =
|
||||
+ (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
|
||||
+ if (next->start == NULL) {
|
||||
+ WebPSafeFree(next);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ next->curr_table = next->start;
|
||||
+ next->next = NULL;
|
||||
+ // Point to the new segment.
|
||||
+ root_table->curr_segment->next = next;
|
||||
+ root_table->curr_segment = next;
|
||||
+ }
|
||||
+ if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||
// use local stack-allocated array.
|
||||
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
||||
- total_size = BuildHuffmanTable(root_table, root_bits,
|
||||
- code_lengths, code_lengths_size, sorted);
|
||||
- } else { // rare case. Use heap allocation.
|
||||
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
|
||||
+ code_lengths, code_lengths_size, sorted);
|
||||
+ } else { // rare case. Use heap allocation.
|
||||
uint16_t* const sorted =
|
||||
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
|
||||
if (sorted == NULL) return 0;
|
||||
- total_size = BuildHuffmanTable(root_table, root_bits,
|
||||
- code_lengths, code_lengths_size, sorted);
|
||||
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
|
||||
+ code_lengths, code_lengths_size, sorted);
|
||||
WebPSafeFree(sorted);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
+
|
||||
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
|
||||
+ // Have 'segment' point to the first segment for now, 'root'.
|
||||
+ HuffmanTablesSegment* const root = &huffman_tables->root;
|
||||
+ huffman_tables->curr_segment = root;
|
||||
+ // Allocate root.
|
||||
+ root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
|
||||
+ if (root->start == NULL) return 0;
|
||||
+ root->curr_table = root->start;
|
||||
+ root->next = NULL;
|
||||
+ root->size = size;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
|
||||
+ HuffmanTablesSegment *current, *next;
|
||||
+ if (huffman_tables == NULL) return;
|
||||
+ // Free the root node.
|
||||
+ current = &huffman_tables->root;
|
||||
+ next = current->next;
|
||||
+ WebPSafeFree(current->start);
|
||||
+ current->start = NULL;
|
||||
+ current->next = NULL;
|
||||
+ current = next;
|
||||
+ // Free the following nodes.
|
||||
+ while (current != NULL) {
|
||||
+ next = current->next;
|
||||
+ WebPSafeFree(current->start);
|
||||
+ WebPSafeFree(current);
|
||||
+ current = next;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h
|
||||
index 13b7ad1ac40c5316f5506d9b4cbf5039c9fd5600..98415c532895374ea28fc1dc5c9a15c751ea9ba0 100644
|
||||
--- a/src/utils/huffman_utils.h
|
||||
+++ b/src/utils/huffman_utils.h
|
||||
@@ -43,6 +43,29 @@ typedef struct {
|
||||
// or non-literal symbol otherwise
|
||||
} HuffmanCode32;
|
||||
|
||||
+// Contiguous memory segment of HuffmanCodes.
|
||||
+typedef struct HuffmanTablesSegment {
|
||||
+ HuffmanCode* start;
|
||||
+ // Pointer to where we are writing into the segment. Starts at 'start' and
|
||||
+ // cannot go beyond 'start' + 'size'.
|
||||
+ HuffmanCode* curr_table;
|
||||
+ // Pointer to the next segment in the chain.
|
||||
+ struct HuffmanTablesSegment* next;
|
||||
+ int size;
|
||||
+} HuffmanTablesSegment;
|
||||
+
|
||||
+// Chained memory segments of HuffmanCodes.
|
||||
+typedef struct HuffmanTables {
|
||||
+ HuffmanTablesSegment root;
|
||||
+ // Currently processed segment. At first, this is 'root'.
|
||||
+ HuffmanTablesSegment* curr_segment;
|
||||
+} HuffmanTables;
|
||||
+
|
||||
+// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
|
||||
+// memory allocation error, 1 otherwise.
|
||||
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
|
||||
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
|
||||
+
|
||||
#define HUFFMAN_PACKED_BITS 6
|
||||
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
|
||||
|
||||
@@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
|
||||
// the huffman table.
|
||||
// Returns built table size or 0 in case of error (invalid tree or
|
||||
// memory error).
|
||||
-// If root_table is NULL, it returns 0 if a lookup cannot be built, something
|
||||
-// > 0 otherwise (but not the table size).
|
||||
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
|
||||
const int code_lengths[], int code_lengths_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -36,3 +36,5 @@ src_allow_optional_isolation_termination_in_node.patch
|
||||
test_mark_cpu_prof_tests_as_flaky_in_electron.patch
|
||||
lib_fix_broadcastchannel_initialization_location.patch
|
||||
intl_revert_date_formatting_behavior_change_from_icu_72.patch
|
||||
fix_do_not_resolve_electron_entrypoints.patch
|
||||
fix_assert_module_in_the_renderer_process.patch
|
||||
|
||||
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 82c3a285f51abd1d517e7930887492652628e8c6..f68f22a4737ce395d3ee8a375513cb24ed1e8d2d 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();
|
||||
@@ -289,8 +290,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 c718b9919bb30627e5da2b92a8de58c494bf4b93..64f8bef214fa4d55114aa9d04c111fcc3033ad10 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 99f5274aec7512956a5e13a5ca9c0b593a57cc7a..2094efecfb83e80a01d582fde7566f3eed79cd55 100644
|
||||
--- a/src/node_options.cc
|
||||
+++ b/src/node_options.cc
|
||||
@@ -1186,6 +1186,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()))
|
||||
47
patches/node/fix_do_not_resolve_electron_entrypoints.patch
Normal file
47
patches/node/fix_do_not_resolve_electron_entrypoints.patch
Normal file
@@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <marshallofsound@electronjs.org>
|
||||
Date: Wed, 26 Jul 2023 17:03:15 -0700
|
||||
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..ebc9999358ccf16689dc02322eb1aeb86355f39b 100644
|
||||
--- a/lib/internal/modules/run_main.js
|
||||
+++ b/lib/internal/modules/run_main.js
|
||||
@@ -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' && 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).
|
||||
1
patches/skia/.patches
Normal file
1
patches/skia/.patches
Normal file
@@ -0,0 +1 @@
|
||||
enforce_an_upper_limit_of_715_million_path_verbs_in_skpath.patch
|
||||
@@ -0,0 +1,118 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: John Stiles <johnstiles@google.com>
|
||||
Date: Thu, 3 Aug 2023 13:33:52 -0400
|
||||
Subject: Enforce an upper limit of 715 million path verbs in SkPath.
|
||||
|
||||
Bug: chromium:1464215
|
||||
Change-Id: Iedb7d73fc80de5ffb881b664dd77314cc2c6b108
|
||||
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/735316
|
||||
Reviewed-by: Brian Osman <brianosman@google.com>
|
||||
Commit-Queue: John Stiles <johnstiles@google.com>
|
||||
|
||||
diff --git a/relnotes/path_715M.md b/relnotes/path_715M.md
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7be9a40f1fc5b4f6432c490725b05d536d497fb1
|
||||
--- /dev/null
|
||||
+++ b/relnotes/path_715M.md
|
||||
@@ -0,0 +1 @@
|
||||
+SkPath now enforces an upper limit of 715 million path verbs.
|
||||
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
|
||||
index 6cc1e2ef1b49b18aa6692dba655ef5ca83610b0d..976edee87e763a1f44396902d4f641ed3da8e452 100644
|
||||
--- a/src/core/SkPath.cpp
|
||||
+++ b/src/core/SkPath.cpp
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
+#include <limits.h>
|
||||
#include <utility>
|
||||
|
||||
struct SkPath_Storage_Equivalent {
|
||||
@@ -3421,43 +3422,52 @@ bool SkPath::IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
|
||||
|
||||
SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t vbs[], int verbCount) {
|
||||
SkPathVerbAnalysis info = {false, 0, 0, 0};
|
||||
-
|
||||
bool needMove = true;
|
||||
bool invalid = false;
|
||||
- for (int i = 0; i < verbCount; ++i) {
|
||||
- switch ((SkPathVerb)vbs[i]) {
|
||||
- case SkPathVerb::kMove:
|
||||
- needMove = false;
|
||||
- info.points += 1;
|
||||
- break;
|
||||
- case SkPathVerb::kLine:
|
||||
- invalid |= needMove;
|
||||
- info.segmentMask |= kLine_SkPathSegmentMask;
|
||||
- info.points += 1;
|
||||
- break;
|
||||
- case SkPathVerb::kQuad:
|
||||
- invalid |= needMove;
|
||||
- info.segmentMask |= kQuad_SkPathSegmentMask;
|
||||
- info.points += 2;
|
||||
- break;
|
||||
- case SkPathVerb::kConic:
|
||||
- invalid |= needMove;
|
||||
- info.segmentMask |= kConic_SkPathSegmentMask;
|
||||
- info.points += 2;
|
||||
- info.weights += 1;
|
||||
- break;
|
||||
- case SkPathVerb::kCubic:
|
||||
- invalid |= needMove;
|
||||
- info.segmentMask |= kCubic_SkPathSegmentMask;
|
||||
- info.points += 3;
|
||||
- break;
|
||||
- case SkPathVerb::kClose:
|
||||
- invalid |= needMove;
|
||||
- needMove = true;
|
||||
- break;
|
||||
- default:
|
||||
- invalid = true;
|
||||
- break;
|
||||
+
|
||||
+ if (verbCount >= (INT_MAX / 3)) {
|
||||
+ // A path with an extremely high number of quad, conic or cubic verbs could cause
|
||||
+ // `info.points` to overflow. To prevent against this, we reject extremely large paths. This
|
||||
+ // check is conservative and assumes the worst case (in particular, it assumes that every
|
||||
+ // verb consumes 3 points, which would only happen for a path composed entirely of cubics).
|
||||
+ // This limits us to 700 million verbs, which is large enough for any reasonable use case.
|
||||
+ invalid = true;
|
||||
+ } else {
|
||||
+ for (int i = 0; i < verbCount; ++i) {
|
||||
+ switch ((SkPathVerb)vbs[i]) {
|
||||
+ case SkPathVerb::kMove:
|
||||
+ needMove = false;
|
||||
+ info.points += 1;
|
||||
+ break;
|
||||
+ case SkPathVerb::kLine:
|
||||
+ invalid |= needMove;
|
||||
+ info.segmentMask |= kLine_SkPathSegmentMask;
|
||||
+ info.points += 1;
|
||||
+ break;
|
||||
+ case SkPathVerb::kQuad:
|
||||
+ invalid |= needMove;
|
||||
+ info.segmentMask |= kQuad_SkPathSegmentMask;
|
||||
+ info.points += 2;
|
||||
+ break;
|
||||
+ case SkPathVerb::kConic:
|
||||
+ invalid |= needMove;
|
||||
+ info.segmentMask |= kConic_SkPathSegmentMask;
|
||||
+ info.points += 2;
|
||||
+ info.weights += 1;
|
||||
+ break;
|
||||
+ case SkPathVerb::kCubic:
|
||||
+ invalid |= needMove;
|
||||
+ info.segmentMask |= kCubic_SkPathSegmentMask;
|
||||
+ info.points += 3;
|
||||
+ break;
|
||||
+ case SkPathVerb::kClose:
|
||||
+ invalid |= needMove;
|
||||
+ needMove = true;
|
||||
+ break;
|
||||
+ default:
|
||||
+ invalid = true;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
info.valid = !invalid;
|
||||
@@ -13,3 +13,10 @@ cherry-pick-3b0607d14060.patch
|
||||
cherry-pick-9c6dfc733fce.patch
|
||||
cherry-pick-73af1a19a901.patch
|
||||
cherry-pick-0035a4a8dac2.patch
|
||||
cherry-pick-2e76270cf65e.patch
|
||||
merged_runtime_set_instance_prototypes_directly_on_maps.patch
|
||||
merged_compiler_stackcheck_can_have_side_effects.patch
|
||||
cherry-pick-8ff63d378f2c.patch
|
||||
cherry-pick-d671b099a57d.patch
|
||||
merged_squashed_multiple_commits.patch
|
||||
cherry-pick-038530c94a06.patch
|
||||
|
||||
49
patches/v8/cherry-pick-038530c94a06.patch
Normal file
49
patches/v8/cherry-pick-038530c94a06.patch
Normal file
@@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Tebbi <tebbi@chromium.org>
|
||||
Date: Wed, 30 Aug 2023 10:59:48 +0200
|
||||
Subject: Merged: [turbofan] Growing a non-JSArray packed elements kind makes
|
||||
it holey
|
||||
|
||||
Bug: chromium:1473247
|
||||
(cherry picked from commit ae7dc61652805bc8e2b060d53b2b6da7cf846b6f)
|
||||
|
||||
Change-Id: I5268513bc91ca0cc18e3e2115244c0b090afa0da
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4831892
|
||||
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
|
||||
Owners-Override: Leszek Swirski <leszeks@chromium.org>
|
||||
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
|
||||
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
|
||||
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.6@{#34}
|
||||
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
|
||||
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
|
||||
|
||||
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
|
||||
index b6336828e564902923acefb789dc852aa56b8419..c2f9a4e0d1d2f8f1421ca17ee2c120e16fd09da5 100644
|
||||
--- a/src/compiler/js-native-context-specialization.cc
|
||||
+++ b/src/compiler/js-native-context-specialization.cc
|
||||
@@ -3423,15 +3423,21 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
// the (potential) backing store growth would normalize and thus
|
||||
// the elements kind of the {receiver} would change to slow mode.
|
||||
//
|
||||
- // For PACKED_*_ELEMENTS the {index} must be within the range
|
||||
+ // For JSArray PACKED_*_ELEMENTS the {index} must be within the range
|
||||
// [0,length+1[ to be valid. In case {index} equals {length},
|
||||
// the {receiver} will be extended, but kept packed.
|
||||
+ //
|
||||
+ // Non-JSArray PACKED_*_ELEMENTS always grow by adding holes because they
|
||||
+ // lack the magical length property, which requires a map transition.
|
||||
+ // So we can assume that this did not happen if we did not see this map.
|
||||
Node* limit =
|
||||
IsHoleyElementsKind(elements_kind)
|
||||
? graph()->NewNode(simplified()->NumberAdd(), elements_length,
|
||||
jsgraph()->Constant(JSObject::kMaxGap))
|
||||
- : graph()->NewNode(simplified()->NumberAdd(), length,
|
||||
- jsgraph()->OneConstant());
|
||||
+ : receiver_is_jsarray
|
||||
+ ? graph()->NewNode(simplified()->NumberAdd(), length,
|
||||
+ jsgraph()->OneConstant())
|
||||
+ : elements_length;
|
||||
index = effect = graph()->NewNode(
|
||||
simplified()->CheckBounds(
|
||||
FeedbackSource(), CheckBoundsFlag::kConvertStringAndMinusZero),
|
||||
45
patches/v8/cherry-pick-2e76270cf65e.patch
Normal file
45
patches/v8/cherry-pick-2e76270cf65e.patch
Normal file
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Mon, 5 Jun 2023 16:05:52 -0700
|
||||
Subject: Merged: Check for encoding when appending in string builder
|
||||
|
||||
Fixed: chromium:1450114
|
||||
(cherry picked from commit a7e2bef27b72f187a7dcdf95714df686f56d9e0b)
|
||||
|
||||
Change-Id: I5838383b6b12d137e84c8a36863ef88000e85c76
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4604652
|
||||
Reviewed-by: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#41}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/strings/string-builder.cc b/src/strings/string-builder.cc
|
||||
index f6871d9e6aa33942ec595e3076f689c2008989d7..30540b6a32a006fa4417d612a1243f18f59d3c2e 100644
|
||||
--- a/src/strings/string-builder.cc
|
||||
+++ b/src/strings/string-builder.cc
|
||||
@@ -317,12 +317,21 @@ bool IncrementalStringBuilder::CanAppendByCopy(Handle<String> string) {
|
||||
void IncrementalStringBuilder::AppendStringByCopy(Handle<String> string) {
|
||||
DCHECK(CanAppendByCopy(string));
|
||||
|
||||
- Handle<SeqOneByteString> part =
|
||||
- Handle<SeqOneByteString>::cast(current_part());
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
- String::WriteToFlat(*string, part->GetChars(no_gc) + current_index_, 0,
|
||||
- string->length());
|
||||
+ if (encoding_ == String::ONE_BYTE_ENCODING) {
|
||||
+ String::WriteToFlat(
|
||||
+ *string,
|
||||
+ Handle<SeqOneByteString>::cast(current_part())->GetChars(no_gc) +
|
||||
+ current_index_,
|
||||
+ 0, string->length());
|
||||
+ } else {
|
||||
+ String::WriteToFlat(
|
||||
+ *string,
|
||||
+ Handle<SeqTwoByteString>::cast(current_part())->GetChars(no_gc) +
|
||||
+ current_index_,
|
||||
+ 0, string->length());
|
||||
+ }
|
||||
}
|
||||
current_index_ += string->length();
|
||||
DCHECK(current_index_ <= part_length_);
|
||||
126
patches/v8/cherry-pick-8ff63d378f2c.patch
Normal file
126
patches/v8/cherry-pick-8ff63d378f2c.patch
Normal file
@@ -0,0 +1,126 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Wed, 2 Aug 2023 17:41:03 -0700
|
||||
Subject: Merged: [builtins] Clear FixedArray slot in Promise builtins
|
||||
|
||||
Fixed: chromium:1468943
|
||||
(cherry picked from commit a84849ed718932b94dc877bb44a2d38eb8a0aef9)
|
||||
|
||||
Change-Id: Ia2b181c373c15bd1840e2a1572c0e930cddcd788
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4753495
|
||||
Commit-Queue: Adam Klein <adamk@chromium.org>
|
||||
Reviewed-by: Adam Klein <adamk@chromium.org>
|
||||
Auto-Submit: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.6@{#28}
|
||||
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
|
||||
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
|
||||
|
||||
diff --git a/src/builtins/promise-all-element-closure.tq b/src/builtins/promise-all-element-closure.tq
|
||||
index db3fb0134cf5bf0065174153171ef44a726a6fff..036e3c7b7473eae98f39a6da4472e826420086c8 100644
|
||||
--- a/src/builtins/promise-all-element-closure.tq
|
||||
+++ b/src/builtins/promise-all-element-closure.tq
|
||||
@@ -175,11 +175,22 @@ transitioning macro PromiseAllResolveElementClosure<F: type>(
|
||||
*NativeContextSlot(
|
||||
nativeContext, ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
|
||||
|
||||
- // If resolve and reject handlers close over values to keep track of whether
|
||||
- // an input promise is already settled, mark the values array as COW before
|
||||
- // letting it escape to user code.
|
||||
- if (hasResolveAndRejectClosures) MakeFixedArrayCOW(values);
|
||||
-
|
||||
+ // After this point, values escapes to user code.
|
||||
+ //
|
||||
+ // If resolve and reject handlers close over values to keep track of
|
||||
+ // whether an input promise is already settled, mark the values array as
|
||||
+ // COW. The original values array is still needed to guard against resolve
|
||||
+ // or reject being called multiple times for an element.
|
||||
+ //
|
||||
+ // Otherwise, clear the slot.
|
||||
+ if (hasResolveAndRejectClosures) {
|
||||
+ MakeFixedArrayCOW(values);
|
||||
+ } else {
|
||||
+ *ContextSlot(
|
||||
+ promiseContext,
|
||||
+ PromiseAllResolveElementContextSlots::
|
||||
+ kPromiseAllResolveElementValuesSlot) = kEmptyFixedArray;
|
||||
+ }
|
||||
const valuesArray = NewJSArray(arrayMap, values);
|
||||
Call(promiseContext, resolve, Undefined, valuesArray);
|
||||
}
|
||||
diff --git a/src/builtins/promise-all.tq b/src/builtins/promise-all.tq
|
||||
index 4d131abb44b7593d3e361d1d2f971380ee91850c..7205279526fa9edd93f154feb9694c22cae68606 100644
|
||||
--- a/src/builtins/promise-all.tq
|
||||
+++ b/src/builtins/promise-all.tq
|
||||
@@ -278,15 +278,16 @@ Reject(JSAny) {
|
||||
|
||||
check(remainingElementsCount >= 0);
|
||||
|
||||
+ const valuesRef:&FixedArray = ContextSlot(
|
||||
+ resolveElementContext,
|
||||
+ PromiseAllResolveElementContextSlots::
|
||||
+ kPromiseAllResolveElementValuesSlot);
|
||||
+ const values = *valuesRef;
|
||||
+
|
||||
if (remainingElementsCount > 0) {
|
||||
// Pre-allocate the backing store for the {values} to the desired
|
||||
// capacity. We may already have elements in "values" - this happens
|
||||
// when the Thenable calls the resolve callback immediately.
|
||||
- const valuesRef:&FixedArray = ContextSlot(
|
||||
- resolveElementContext,
|
||||
- PromiseAllResolveElementContextSlots::
|
||||
- kPromiseAllResolveElementValuesSlot);
|
||||
- const values = *valuesRef;
|
||||
// 'index' is a 1-based index and incremented after every Promise. Later we
|
||||
// use 'values' as a 0-based array, so capacity 'index - 1' is enough.
|
||||
const newCapacity = SmiUntag(index) - 1;
|
||||
@@ -301,19 +302,23 @@ Reject(JSAny) {
|
||||
// Let valuesArray be CreateArrayFromList(values).
|
||||
// Perform ? Call(resultCapability.[[Resolve]], undefined,
|
||||
// « valuesArray »).
|
||||
-
|
||||
- const values: FixedArray = *ContextSlot(
|
||||
- resolveElementContext,
|
||||
- PromiseAllResolveElementContextSlots::
|
||||
- kPromiseAllResolveElementValuesSlot);
|
||||
const arrayMap =
|
||||
*NativeContextSlot(
|
||||
nativeContext, ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
|
||||
|
||||
+ // After this point, values escapes to user code.
|
||||
+ //
|
||||
// If resolve and reject handlers close over values to keep track of
|
||||
// whether an input promise is already settled, mark the values array as
|
||||
- // COW before letting it escape to user code.
|
||||
- if (hasResolveAndRejectClosures) MakeFixedArrayCOW(values);
|
||||
+ // COW. The original values array is still needed to guard against resolve
|
||||
+ // or reject being called multiple times for an element.
|
||||
+ //
|
||||
+ // Otherwise, clear the slot.
|
||||
+ if (hasResolveAndRejectClosures) {
|
||||
+ MakeFixedArrayCOW(values);
|
||||
+ } else {
|
||||
+ *valuesRef = kEmptyFixedArray;
|
||||
+ }
|
||||
|
||||
const valuesArray = NewJSArray(arrayMap, values);
|
||||
Call(nativeContext, UnsafeCast<JSAny>(resolve), Undefined, valuesArray);
|
||||
diff --git a/src/builtins/promise-any.tq b/src/builtins/promise-any.tq
|
||||
index 7e707e649f11bc946a6d1173180d7293fe94d8ce..45bafac0e6b09143b69b21a7292f9ed6b9c46239 100644
|
||||
--- a/src/builtins/promise-any.tq
|
||||
+++ b/src/builtins/promise-any.tq
|
||||
@@ -313,10 +313,14 @@ Reject(JSAny) {
|
||||
|
||||
// We may already have elements in "errors" - this happens when the
|
||||
// Thenable calls the reject callback immediately.
|
||||
- const errors: FixedArray = *ContextSlot(
|
||||
+ const errorsRef:&FixedArray = ContextSlot(
|
||||
rejectElementContext,
|
||||
PromiseAnyRejectElementContextSlots::
|
||||
kPromiseAnyRejectElementErrorsSlot);
|
||||
+ const errors: FixedArray = *errorsRef;
|
||||
+
|
||||
+ // After this point, errors escapes to user code. Clear the slot.
|
||||
+ *errorsRef = kEmptyFixedArray;
|
||||
|
||||
check(errors.length == index - 1);
|
||||
const error = ConstructAggregateError(errors);
|
||||
31
patches/v8/cherry-pick-d671b099a57d.patch
Normal file
31
patches/v8/cherry-pick-d671b099a57d.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Tebbi <tebbi@chromium.org>
|
||||
Date: Tue, 13 Jun 2023 11:50:11 +0200
|
||||
Subject: Merged: [compiler] check for read-only property on
|
||||
AccessMode::kDefine
|
||||
|
||||
(cherry picked from commit 95eda07ddbc1839e39b3d1ff5db329c0ceb6dfaa)
|
||||
|
||||
Change-Id: Ic5799a32e7c312e41cd0a7e1e6073a235414d56f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4665588
|
||||
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
|
||||
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
|
||||
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#53}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
|
||||
index 3120077a7710264926b9f9cce348cc3f7c0ac858..fc1bfcf2cd6c24ca9ddf8a95ef6a48b087ed3fde 100644
|
||||
--- a/src/compiler/access-info.cc
|
||||
+++ b/src/compiler/access-info.cc
|
||||
@@ -749,8 +749,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
}
|
||||
|
||||
if (index.is_found()) {
|
||||
- if (access_mode == AccessMode::kStore ||
|
||||
- access_mode == AccessMode::kStoreInLiteral) {
|
||||
+ if (IsAnyStore(access_mode)) {
|
||||
DCHECK(!map.is_dictionary_map());
|
||||
|
||||
// Don't bother optimizing stores to read-only properties.
|
||||
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Tebbi <tebbi@chromium.org>
|
||||
Date: Tue, 13 Jun 2023 17:08:59 +0200
|
||||
Subject: Merged: [compiler] StackCheck can have side effects
|
||||
|
||||
Bug: chromium:1452137
|
||||
(cherry picked from commit e548943e473b020fdc1de6e5543ca31b24d8b7f9)
|
||||
|
||||
Change-Id: Ibd7c9b02efd12341b452e4c34a635a58a817649f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4637129
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
|
||||
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
|
||||
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#49}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc
|
||||
index 1728f91280bf9e6a3cf173fe399a8b68bd64cad3..abdd45a16e9f207c8d9012cfb434e816218bbf7c 100644
|
||||
--- a/src/compiler/js-operator.cc
|
||||
+++ b/src/compiler/js-operator.cc
|
||||
@@ -1400,7 +1400,7 @@ const Operator* JSOperatorBuilder::CloneObject(FeedbackSource const& feedback,
|
||||
const Operator* JSOperatorBuilder::StackCheck(StackCheckKind kind) {
|
||||
return zone()->New<Operator1<StackCheckKind>>( // --
|
||||
IrOpcode::kJSStackCheck, // opcode
|
||||
- Operator::kNoWrite, // properties
|
||||
+ Operator::kNoProperties, // properties
|
||||
"JSStackCheck", // name
|
||||
0, 1, 1, 0, 1, 2, // counts
|
||||
kind); // parameter
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Toon Verwaest <verwaest@chromium.org>
|
||||
Date: Fri, 16 Jun 2023 17:13:52 +0200
|
||||
Subject: Merged: [runtime] Set instance prototypes directly on maps
|
||||
|
||||
Bug: chromium:1452137
|
||||
(cherry picked from commit c7c447735f762f6d6d0878e229371797845ef4ab)
|
||||
|
||||
Change-Id: I611c41f942e2e51f3c4b4f1d119c18410617188e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4637888
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Auto-Submit: Igor Sheludko <ishell@chromium.org>
|
||||
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#47}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/js-function.cc b/src/objects/js-function.cc
|
||||
index 6f9b2f676ac5d3f91589a78344b27765dc8bef06..d50743b1c73ad3304c5c5c22a4e0589cca302502 100644
|
||||
--- a/src/objects/js-function.cc
|
||||
+++ b/src/objects/js-function.cc
|
||||
@@ -676,6 +676,10 @@ void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
|
||||
// At that point, a new initial map is created and the prototype is put
|
||||
// into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value, kReleaseStore);
|
||||
+ if (value->IsJSObjectThatCanBeTrackedAsPrototype()) {
|
||||
+ // Optimize as prototype to detach it from its transition tree.
|
||||
+ JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
|
||||
+ }
|
||||
} else {
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, initial_map, "SetInstancePrototype");
|
||||
@@ -801,8 +805,10 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
||||
Handle<HeapObject> prototype;
|
||||
if (function->has_instance_prototype()) {
|
||||
prototype = handle(function->instance_prototype(), isolate);
|
||||
+ map->set_prototype(*prototype);
|
||||
} else {
|
||||
prototype = isolate->factory()->NewFunctionPrototype(function);
|
||||
+ Map::SetPrototype(isolate, map, prototype);
|
||||
}
|
||||
DCHECK(map->has_fast_object_elements());
|
||||
|
||||
51
patches/v8/merged_squashed_multiple_commits.patch
Normal file
51
patches/v8/merged_squashed_multiple_commits.patch
Normal file
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Samuel=20Gro=C3=9F?= <saelo@chromium.org>
|
||||
Date: Thu, 17 Aug 2023 09:10:19 +0000
|
||||
Subject: Merged: Squashed multiple commits.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Merged: [runtime] Recreate enum cache on map update
|
||||
Revision: 1c623f9ff6e077be1c66f155485ea4005ddb6574
|
||||
|
||||
Merged: [runtime] Don't try to create empty enum cache.
|
||||
Revision: 5516e06237c9f0013121f47319e8c253c896d52d
|
||||
|
||||
BUG=chromium:1470668,chromium:1472317
|
||||
R=tebbi@chromium.org
|
||||
|
||||
Change-Id: I31d5491aba663661ba68bb55631747a195ed084e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4788990
|
||||
Commit-Queue: Samuel Groß <saelo@chromium.org>
|
||||
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.6@{#32}
|
||||
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
|
||||
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
|
||||
|
||||
diff --git a/src/objects/map-updater.cc b/src/objects/map-updater.cc
|
||||
index be6568aac4730d08601e883b80092bbd6ee8081a..2ebfc84d3e326abf2602a1af8309024a46cb9c9d 100644
|
||||
--- a/src/objects/map-updater.cc
|
||||
+++ b/src/objects/map-updater.cc
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "src/execution/isolate.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/objects/field-type.h"
|
||||
+#include "src/objects/keys.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/objects.h"
|
||||
#include "src/objects/property-details.h"
|
||||
@@ -1035,6 +1036,13 @@ MapUpdater::State MapUpdater::ConstructNewMap() {
|
||||
// the new descriptors to maintain descriptors sharing invariant.
|
||||
split_map->ReplaceDescriptors(isolate_, *new_descriptors);
|
||||
|
||||
+ // If the old descriptors had an enum cache, make sure the new ones do too.
|
||||
+ if (old_descriptors_->enum_cache().keys().length() > 0 &&
|
||||
+ new_map->NumberOfEnumerableProperties() > 0) {
|
||||
+ FastKeyAccumulator::InitializeFastPropertyEnumCache(
|
||||
+ isolate_, new_map, new_map->NumberOfEnumerableProperties());
|
||||
+ }
|
||||
+
|
||||
if (has_integrity_level_transition_) {
|
||||
target_map_ = new_map;
|
||||
state_ = kAtIntegrityLevelSource;
|
||||
@@ -1 +1,6 @@
|
||||
fix_fallback_to_x11_capturer_on_wayland.patch
|
||||
m114_move_transceiver_iteration_loop_over_to_the_signaling_thread.patch
|
||||
m114_sdp_reject_duplicate_ssrcs_in_ssrc-groups.patch
|
||||
pipewire_capturer_fix_fcntl_call_when_duplicating_a_file_descriptor.patch
|
||||
pipewire_capturer_increase_buffer_size_to_avoid_buffer_overflow.patch
|
||||
desktop_capture_introduce_capturer_requesting_both_screen_and.patch
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <grulja@gmail.com>
|
||||
Date: Wed, 12 Jul 2023 13:15:40 +0200
|
||||
Subject: Desktop capture: introduce capturer requesting both screen and
|
||||
windows
|
||||
|
||||
When PipeWire and xdg-desktop-portals are used, we can actually combine
|
||||
both source types into one request. Make this part of the API for those
|
||||
who want to use it this way, e.g. Firefox or Electron, otherwise they
|
||||
will end up making two simultaneous requests, resulting into two dialogs
|
||||
at the same time asking, while they can be combined into just one.
|
||||
|
||||
Bug: webrtc:15363
|
||||
Change-Id: Ib6e1e47f66cb01d5c65096aec378b44c3af5f387
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311549
|
||||
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
|
||||
Commit-Queue: Jan Grulich <grulja@gmail.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#40425}
|
||||
|
||||
diff --git a/modules/desktop_capture/desktop_capture_types.h b/modules/desktop_capture/desktop_capture_types.h
|
||||
index 9627076eea3d1272f87b773ada86be6051f1e224..a4e3e897fde1d3c7bb470449448f30ff6e50caea 100644
|
||||
--- a/modules/desktop_capture/desktop_capture_types.h
|
||||
+++ b/modules/desktop_capture/desktop_capture_types.h
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
-enum class CaptureType { kWindow, kScreen };
|
||||
+enum class CaptureType { kWindow, kScreen, kAnyScreenContent };
|
||||
|
||||
// Type used to identify windows on the desktop. Values are platform-specific:
|
||||
// - On Windows: HWND cast to intptr_t.
|
||||
diff --git a/modules/desktop_capture/desktop_capturer.cc b/modules/desktop_capture/desktop_capturer.cc
|
||||
index 5211f1acecaba963e1436c1d04aa953853c79eb7..b99f5ecb803ac0ac0e26fbdb3411c77605f33011 100644
|
||||
--- a/modules/desktop_capture/desktop_capturer.cc
|
||||
+++ b/modules/desktop_capture/desktop_capturer.cc
|
||||
@@ -26,6 +26,10 @@
|
||||
#include "rtc_base/win/windows_version.h"
|
||||
#endif // defined(RTC_ENABLE_WIN_WGC)
|
||||
|
||||
+#if defined(WEBRTC_USE_PIPEWIRE)
|
||||
+#include "modules/desktop_capture/linux/wayland/base_capturer_pipewire.h"
|
||||
+#endif
|
||||
+
|
||||
namespace webrtc {
|
||||
|
||||
void LogDesktopCapturerFullscreenDetectorUsage() {
|
||||
@@ -101,6 +105,25 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
|
||||
return capturer;
|
||||
}
|
||||
|
||||
+// static
|
||||
+std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateGenericCapturer(
|
||||
+ const DesktopCaptureOptions& options) {
|
||||
+ std::unique_ptr<DesktopCapturer> capturer;
|
||||
+
|
||||
+#if defined(WEBRTC_USE_PIPEWIRE)
|
||||
+ if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
|
||||
+ capturer = std::make_unique<BaseCapturerPipeWire>(
|
||||
+ options, CaptureType::kAnyScreenContent);
|
||||
+ }
|
||||
+
|
||||
+ if (capturer && options.detect_updated_region()) {
|
||||
+ capturer.reset(new DesktopCapturerDifferWrapper(std::move(capturer)));
|
||||
+ }
|
||||
+#endif // defined(WEBRTC_USE_PIPEWIRE)
|
||||
+
|
||||
+ return capturer;
|
||||
+}
|
||||
+
|
||||
#if defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11)
|
||||
bool DesktopCapturer::IsRunningUnderWayland() {
|
||||
const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
|
||||
diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h
|
||||
index fd884f13ff771de2d5ea8b79ba530e9d3b03e913..9c7ecc78f46ea2e2c173416132318f0526714265 100644
|
||||
--- a/modules/desktop_capture/desktop_capturer.h
|
||||
+++ b/modules/desktop_capture/desktop_capturer.h
|
||||
@@ -186,6 +186,11 @@ class RTC_EXPORT DesktopCapturer {
|
||||
static std::unique_ptr<DesktopCapturer> CreateScreenCapturer(
|
||||
const DesktopCaptureOptions& options);
|
||||
|
||||
+ // Creates a DesktopCapturer instance which targets to capture windows and
|
||||
+ // screens.
|
||||
+ static std::unique_ptr<DesktopCapturer> CreateGenericCapturer(
|
||||
+ const DesktopCaptureOptions& options);
|
||||
+
|
||||
#if defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11)
|
||||
static bool IsRunningUnderWayland();
|
||||
|
||||
diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.cc b/modules/desktop_capture/linux/wayland/screencast_portal.cc
|
||||
index 52788524c88f8699afda54dcf5d3972618d595a3..8d9e956779e0d9826652c6c97485c8107cb4ad3b 100644
|
||||
--- a/modules/desktop_capture/linux/wayland/screencast_portal.cc
|
||||
+++ b/modules/desktop_capture/linux/wayland/screencast_portal.cc
|
||||
@@ -41,6 +41,8 @@ ScreenCastPortal::CaptureSourceType ScreenCastPortal::ToCaptureSourceType(
|
||||
return ScreenCastPortal::CaptureSourceType::kScreen;
|
||||
case CaptureType::kWindow:
|
||||
return ScreenCastPortal::CaptureSourceType::kWindow;
|
||||
+ case CaptureType::kAnyScreenContent:
|
||||
+ return ScreenCastPortal::CaptureSourceType::kAnyScreenContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tommi <tommi@webrtc.org>
|
||||
Date: Thu, 1 Jun 2023 16:08:52 +0200
|
||||
Subject: Move transceiver iteration loop over to the signaling thread.
|
||||
|
||||
This is required for ReportTransportStats since iterating over the
|
||||
transceiver list from the network thread is not safe.
|
||||
|
||||
(cherry picked from commit dba22d31909298161318e00d43a80cdb0abc940f)
|
||||
|
||||
No-Try: true
|
||||
Bug: chromium:1446274, webrtc:12692
|
||||
Change-Id: I7c514df9f029112c4b1da85826af91217850fb26
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/307340
|
||||
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
|
||||
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#40197}
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/308001
|
||||
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#3}
|
||||
Cr-Branched-From: df7df199abd619e75b9f1d9a7e12fc3f3f748775-refs/heads/main@{#39949}
|
||||
|
||||
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
|
||||
index 88b99bb515325b9c616b7d06495c7a9c924133b2..5701504e7a6ebd96bd5cafdbe37de4a510f6a436 100644
|
||||
--- a/pc/peer_connection.cc
|
||||
+++ b/pc/peer_connection.cc
|
||||
@@ -728,9 +728,6 @@ JsepTransportController* PeerConnection::InitializeTransportController_n(
|
||||
transport_controller_->SubscribeIceConnectionState(
|
||||
[this](cricket::IceConnectionState s) {
|
||||
RTC_DCHECK_RUN_ON(network_thread());
|
||||
- if (s == cricket::kIceConnectionConnected) {
|
||||
- ReportTransportStats();
|
||||
- }
|
||||
signaling_thread()->PostTask(
|
||||
SafeTask(signaling_thread_safety_.flag(), [this, s]() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
@@ -2415,6 +2412,20 @@ void PeerConnection::OnTransportControllerConnectionState(
|
||||
case cricket::kIceConnectionConnected:
|
||||
RTC_LOG(LS_INFO) << "Changing to ICE connected state because "
|
||||
"all transports are writable.";
|
||||
+ {
|
||||
+ std::vector<RtpTransceiverProxyRefPtr> transceivers;
|
||||
+ if (ConfiguredForMedia()) {
|
||||
+ transceivers = rtp_manager()->transceivers()->List();
|
||||
+ }
|
||||
+
|
||||
+ network_thread()->PostTask(
|
||||
+ SafeTask(network_thread_safety_,
|
||||
+ [this, transceivers = std::move(transceivers)] {
|
||||
+ RTC_DCHECK_RUN_ON(network_thread());
|
||||
+ ReportTransportStats(std::move(transceivers));
|
||||
+ }));
|
||||
+ }
|
||||
+
|
||||
SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
|
||||
NoteUsageEvent(UsageEvent::ICE_STATE_CONNECTED);
|
||||
break;
|
||||
@@ -2762,20 +2773,18 @@ void PeerConnection::OnTransportControllerGatheringState(
|
||||
}
|
||||
|
||||
// Runs on network_thread().
|
||||
-void PeerConnection::ReportTransportStats() {
|
||||
+void PeerConnection::ReportTransportStats(
|
||||
+ std::vector<RtpTransceiverProxyRefPtr> transceivers) {
|
||||
TRACE_EVENT0("webrtc", "PeerConnection::ReportTransportStats");
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
std::map<std::string, std::set<cricket::MediaType>>
|
||||
media_types_by_transport_name;
|
||||
- if (ConfiguredForMedia()) {
|
||||
- for (const auto& transceiver :
|
||||
- rtp_manager()->transceivers()->UnsafeList()) {
|
||||
- if (transceiver->internal()->channel()) {
|
||||
- std::string transport_name(
|
||||
- transceiver->internal()->channel()->transport_name());
|
||||
- media_types_by_transport_name[transport_name].insert(
|
||||
- transceiver->media_type());
|
||||
- }
|
||||
+ for (const auto& transceiver : transceivers) {
|
||||
+ if (transceiver->internal()->channel()) {
|
||||
+ std::string transport_name(
|
||||
+ transceiver->internal()->channel()->transport_name());
|
||||
+ media_types_by_transport_name[transport_name].insert(
|
||||
+ transceiver->media_type());
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
|
||||
index 850142b9584a9f2e5b29b337b2bcd433d4b0224d..69b2ca7925eceb636aa4d22b9397cb25a7637051 100644
|
||||
--- a/pc/peer_connection.h
|
||||
+++ b/pc/peer_connection.h
|
||||
@@ -569,7 +569,8 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
|
||||
// Invoked when TransportController connection completion is signaled.
|
||||
// Reports stats for all transports in use.
|
||||
- void ReportTransportStats() RTC_RUN_ON(network_thread());
|
||||
+ void ReportTransportStats(std::vector<RtpTransceiverProxyRefPtr> transceivers)
|
||||
+ RTC_RUN_ON(network_thread());
|
||||
|
||||
// Gather the usage of IPv4/IPv6 as best connection.
|
||||
static void ReportBestConnectionState(const cricket::TransportStats& stats);
|
||||
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
|
||||
index 1d1bec3e93e0e87bb0b1da13c13ed11712ad0480..c373e2f643b33dea4e619e38dfc8d1007f2cedad 100644
|
||||
--- a/pc/peer_connection_integrationtest.cc
|
||||
+++ b/pc/peer_connection_integrationtest.cc
|
||||
@@ -1831,6 +1831,10 @@ TEST_P(PeerConnectionIntegrationTest,
|
||||
EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected,
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
|
||||
+ // Part of reporting the stats will occur on the network thread, so flush it
|
||||
+ // before checking NumEvents.
|
||||
+ SendTask(network_thread(), [] {});
|
||||
+
|
||||
EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(
|
||||
"WebRTC.PeerConnection.CandidatePairType_UDP",
|
||||
webrtc::kIceCandidatePairHostNameHostName));
|
||||
@@ -1959,6 +1963,10 @@ TEST_P(PeerConnectionIntegrationIceStatesTest, MAYBE_VerifyBestConnection) {
|
||||
EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected,
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
|
||||
+ // Part of reporting the stats will occur on the network thread, so flush it
|
||||
+ // before checking NumEvents.
|
||||
+ SendTask(network_thread(), [] {});
|
||||
+
|
||||
// TODO(bugs.webrtc.org/9456): Fix it.
|
||||
const int num_best_ipv4 = webrtc::metrics::NumEvents(
|
||||
"WebRTC.PeerConnection.IPMetrics", webrtc::kBestConnections_IPv4);
|
||||
@@ -0,0 +1,79 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Philipp Hancke <phancke@microsoft.com>
|
||||
Date: Thu, 15 Jun 2023 07:21:56 +0200
|
||||
Subject: sdp: reject duplicate ssrcs in ssrc-groups
|
||||
|
||||
while not really covered by
|
||||
https://www.rfc-editor.org/rfc/rfc5576.html#section-4.2
|
||||
and using the same SSRC for RTX and primary payload may work
|
||||
since payload type demuxing *could* be used is not a good idea.
|
||||
This also applies to flexfec's FEC-FR.
|
||||
|
||||
For the nonstandard SIM ssrc-group duplicates make no sense.
|
||||
This rejects duplicates for unknown ssrc-groups as well.
|
||||
|
||||
BUG=chromium:1454860
|
||||
|
||||
(cherry picked from commit 6a38a3eb38f732b89ca0d8e36c43a434670c4ef5)
|
||||
|
||||
No-Try: true
|
||||
Change-Id: I3e86101dbd5d6c4099f2fdb7b4a52d5cd0809c5f
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/308820
|
||||
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
|
||||
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
|
||||
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#40292}
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/309601
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#4}
|
||||
Cr-Branched-From: df7df199abd619e75b9f1d9a7e12fc3f3f748775-refs/heads/main@{#39949}
|
||||
|
||||
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
|
||||
index 6d041ff0a1c8ce731a0e4fc20731129663924374..4beb6b0faa0eb78a794cd91507fb476821e94b7c 100644
|
||||
--- a/pc/webrtc_sdp.cc
|
||||
+++ b/pc/webrtc_sdp.cc
|
||||
@@ -3542,6 +3542,11 @@ bool ParseSsrcGroupAttribute(absl::string_view line,
|
||||
if (!GetValueFromString(line, fields[i], &ssrc, error)) {
|
||||
return false;
|
||||
}
|
||||
+ // Reject duplicates. While not forbidden by RFC 5576,
|
||||
+ // they don't make sense.
|
||||
+ if (absl::c_linear_search(ssrcs, ssrc)) {
|
||||
+ return ParseFailed(line, "Duplicate SSRC in ssrc-group", error);
|
||||
+ }
|
||||
ssrcs.push_back(ssrc);
|
||||
}
|
||||
ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
|
||||
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
|
||||
index 37464425c6d88a097140d04fa0a44af5410a64b5..d6a851a2974c348200bf8347aaa16b585f4b9fab 100644
|
||||
--- a/pc/webrtc_sdp_unittest.cc
|
||||
+++ b/pc/webrtc_sdp_unittest.cc
|
||||
@@ -5058,3 +5058,29 @@ TEST_F(WebRtcSdpTest, RejectSessionLevelMediaLevelExtmapMixedUsage) {
|
||||
JsepSessionDescription jdesc(kDummyType);
|
||||
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
|
||||
}
|
||||
+
|
||||
+TEST_F(WebRtcSdpTest, RejectDuplicateSsrcInSsrcGroup) {
|
||||
+ std::string sdp =
|
||||
+ "v=0\r\n"
|
||||
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
|
||||
+ "s=-\r\n"
|
||||
+ "t=0 0\r\n"
|
||||
+ "a=group:BUNDLE 0\r\n"
|
||||
+ "a=fingerprint:sha-1 "
|
||||
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
|
||||
+ "a=setup:actpass\r\n"
|
||||
+ "a=ice-ufrag:ETEn\r\n"
|
||||
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
|
||||
+ "m=video 9 UDP/TLS/RTP/SAVPF 96 97\r\n"
|
||||
+ "c=IN IP4 0.0.0.0\r\n"
|
||||
+ "a=rtcp-mux\r\n"
|
||||
+ "a=sendonly\r\n"
|
||||
+ "a=mid:0\r\n"
|
||||
+ "a=rtpmap:96 VP8/90000\r\n"
|
||||
+ "a=rtpmap:97 rtx/90000\r\n"
|
||||
+ "a=fmtp:97 apt=96\r\n"
|
||||
+ "a=ssrc-group:FID 1234 1234\r\n"
|
||||
+ "a=ssrc:1234 cname:test\r\n";
|
||||
+ JsepSessionDescription jdesc(kDummyType);
|
||||
+ EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
|
||||
+}
|
||||
@@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <grulja@gmail.com>
|
||||
Date: Fri, 12 May 2023 20:59:06 +0200
|
||||
Subject: PipeWire capturer: fix fcntl call when duplicating a file descriptor
|
||||
|
||||
The fcntl() call has variable arguments, therefore we need to pass 0 to
|
||||
specify there are no other arguments for this call, otherwise we might
|
||||
end up with an argument that is random garbage.
|
||||
|
||||
Bug: webrtc:15174
|
||||
Change-Id: I34f16a942d80913b667d8ade7eed557b0233be01
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/305120
|
||||
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
|
||||
Commit-Queue: Jan Grulich <grulja@gmail.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#40060}
|
||||
|
||||
diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
index d31f86772e348b7b6c103289180bdca3bf182a94..0aab2dd22466bc6b6d4e8e43fab8eb716512df5b 100644
|
||||
--- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
+++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
@@ -447,7 +447,7 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream(
|
||||
|
||||
if (fd >= 0) {
|
||||
pw_core_ = pw_context_connect_fd(
|
||||
- pw_context_, fcntl(fd, F_DUPFD_CLOEXEC), nullptr, 0);
|
||||
+ pw_context_, fcntl(fd, F_DUPFD_CLOEXEC, 0), nullptr, 0);
|
||||
} else {
|
||||
pw_core_ = pw_context_connect(pw_context_, nullptr, 0);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <grulja@gmail.com>
|
||||
Date: Mon, 10 Jul 2023 10:07:38 +0200
|
||||
Subject: PipeWire capturer: increase buffer size to avoid buffer overflow
|
||||
|
||||
Recently added framerate option can cause a buffer overflow and make
|
||||
PipeWire to fail on negotiation, which effectively makes screen sharing
|
||||
not to work.
|
||||
|
||||
Bug: webrtc:15346
|
||||
Change-Id: I4a68e26c8f85ca287b06a25da500b6a7009e075f
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311541
|
||||
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
|
||||
Commit-Queue: Jan Grulich <grulja@gmail.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#40413}
|
||||
|
||||
diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
index 0aab2dd22466bc6b6d4e8e43fab8eb716512df5b..5b1cd10e9d903bcebf0389ec5c985fbc7ddff6a8 100644
|
||||
--- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
+++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
@@ -276,7 +276,7 @@ void SharedScreenCastStreamPrivate::OnStreamParamChanged(
|
||||
|
||||
that->stream_size_ = DesktopSize(width, height);
|
||||
|
||||
- uint8_t buffer[1024] = {};
|
||||
+ uint8_t buffer[2048] = {};
|
||||
auto builder = spa_pod_builder{buffer, sizeof(buffer)};
|
||||
|
||||
// Setup buffers and meta header for new format.
|
||||
@@ -361,7 +361,7 @@ void SharedScreenCastStreamPrivate::OnRenegotiateFormat(void* data, uint64_t) {
|
||||
{
|
||||
PipeWireThreadLoopLock thread_loop_lock(that->pw_main_loop_);
|
||||
|
||||
- uint8_t buffer[2048] = {};
|
||||
+ uint8_t buffer[4096] = {};
|
||||
|
||||
spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
|
||||
|
||||
@@ -479,7 +479,7 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream(
|
||||
|
||||
pw_stream_add_listener(pw_stream_, &spa_stream_listener_,
|
||||
&pw_stream_events_, this);
|
||||
- uint8_t buffer[2048] = {};
|
||||
+ uint8_t buffer[4096] = {};
|
||||
|
||||
spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
param([string]$gomaDir=$PWD)
|
||||
$cmdPath = Join-Path -Path $gomaDir -ChildPath "goma_ctl.py"
|
||||
Start-Process -FilePath cmd -ArgumentList "/C", "python", "$cmdPath", "ensure_start"
|
||||
Start-Process -FilePath cmd -ArgumentList "/C", "python3", "$cmdPath", "ensure_start"
|
||||
$timedOut = $false; $waitTime = 0; $waitIncrement = 5; $timeout=120;
|
||||
Do { sleep $waitIncrement; $timedOut = (($waitTime+=$waitIncrement) -gt $timeout); iex "$gomaDir\gomacc.exe port 2" > $null; } Until(($LASTEXITCODE -eq 0) -or $timedOut)
|
||||
if ($timedOut) {
|
||||
|
||||
@@ -50,10 +50,10 @@
|
||||
|
||||
namespace {
|
||||
|
||||
// Initialize Node.js cli options to pass to Node.js
|
||||
// Preparse Node.js cli options to pass to Node.js
|
||||
// See https://nodejs.org/api/cli.html#cli_options
|
||||
int SetNodeCliFlags() {
|
||||
// Options that are unilaterally disallowed
|
||||
void ExitIfContainsDisallowedFlags(const std::vector<std::string>& argv) {
|
||||
// Options that are unilaterally disallowed.
|
||||
static constexpr auto disallowed = base::MakeFixedFlatSet<base::StringPiece>({
|
||||
"--enable-fips",
|
||||
"--force-fips",
|
||||
@@ -62,40 +62,18 @@ int SetNodeCliFlags() {
|
||||
"--use-openssl-ca",
|
||||
});
|
||||
|
||||
const auto argv = base::CommandLine::ForCurrentProcess()->argv();
|
||||
std::vector<std::string> args;
|
||||
|
||||
// TODO(codebytere): We need to set the first entry in args to the
|
||||
// process name owing to src/node_options-inl.h#L286-L290 but this is
|
||||
// redundant and so should be refactored upstream.
|
||||
args.reserve(argv.size() + 1);
|
||||
args.emplace_back("electron");
|
||||
|
||||
for (const auto& arg : argv) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
const auto& option = base::WideToUTF8(arg);
|
||||
#else
|
||||
const auto& option = arg;
|
||||
#endif
|
||||
const auto stripped = base::StringPiece(option).substr(0, option.find('='));
|
||||
if (disallowed.contains(stripped)) {
|
||||
LOG(ERROR) << "The Node.js cli flag " << stripped
|
||||
const auto key = base::StringPiece(arg).substr(0, arg.find('='));
|
||||
if (disallowed.contains(key)) {
|
||||
LOG(ERROR) << "The Node.js cli flag " << key
|
||||
<< " is not supported in Electron";
|
||||
// Node.js returns 9 from ProcessGlobalArgs for any errors encountered
|
||||
// when setting up cli flags and env vars. Since we're outlawing these
|
||||
// flags (making them errors) return 9 here for consistency.
|
||||
return 9;
|
||||
} else {
|
||||
args.push_back(option);
|
||||
// flags (making them errors) exit with the same error code for
|
||||
// consistency.
|
||||
exit(9);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> errors;
|
||||
|
||||
// Node.js itself will output parsing errors to
|
||||
// console so we don't need to handle that ourselves
|
||||
return ProcessGlobalArgs(&args, nullptr, &errors,
|
||||
node::kDisallowedInEnvironment);
|
||||
}
|
||||
|
||||
#if IS_MAS_BUILD()
|
||||
@@ -116,7 +94,11 @@ v8::Local<v8::Value> GetParameters(v8::Isolate* isolate) {
|
||||
}
|
||||
|
||||
int NodeMain(int argc, char* argv[]) {
|
||||
base::CommandLine::Init(argc, argv);
|
||||
bool initialized = base::CommandLine::Init(argc, argv);
|
||||
if (!initialized) {
|
||||
LOG(ERROR) << "Failed to initialize CommandLine";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
v8_crashpad_support::SetUp();
|
||||
@@ -153,15 +135,13 @@ int NodeMain(int argc, char* argv[]) {
|
||||
// Explicitly register electron's builtin bindings.
|
||||
NodeBindings::RegisterBuiltinBindings();
|
||||
|
||||
// Parse and set Node.js cli flags.
|
||||
int flags_exit_code = SetNodeCliFlags();
|
||||
if (flags_exit_code != 0)
|
||||
exit(flags_exit_code);
|
||||
|
||||
// Hack around with the argv pointer. Used for process.title = "blah".
|
||||
argv = uv_setup_args(argc, argv);
|
||||
|
||||
// Parse Node.js cli flags and strip out disallowed options.
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
ExitIfContainsDisallowedFlags(args);
|
||||
|
||||
std::unique_ptr<node::InitializationResult> result =
|
||||
node::InitializeOncePerProcess(
|
||||
args,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -473,51 +474,38 @@ IconLoader::IconSize GetIconSizeByString(const std::string& size) {
|
||||
}
|
||||
|
||||
// Return the path constant from string.
|
||||
int GetPathConstant(const std::string& name) {
|
||||
if (name == "appData")
|
||||
return DIR_APP_DATA;
|
||||
else if (name == "sessionData")
|
||||
return DIR_SESSION_DATA;
|
||||
else if (name == "userData")
|
||||
return chrome::DIR_USER_DATA;
|
||||
else if (name == "cache")
|
||||
constexpr int GetPathConstant(base::StringPiece name) {
|
||||
// clang-format off
|
||||
constexpr auto Lookup = base::MakeFixedFlatMap<base::StringPiece, int>({
|
||||
{"appData", DIR_APP_DATA},
|
||||
#if BUILDFLAG(IS_POSIX)
|
||||
return base::DIR_CACHE;
|
||||
{"cache", base::DIR_CACHE},
|
||||
#else
|
||||
return base::DIR_ROAMING_APP_DATA;
|
||||
{"cache", base::DIR_ROAMING_APP_DATA},
|
||||
#endif
|
||||
else if (name == "userCache")
|
||||
return DIR_USER_CACHE;
|
||||
else if (name == "logs")
|
||||
return DIR_APP_LOGS;
|
||||
else if (name == "crashDumps")
|
||||
return DIR_CRASH_DUMPS;
|
||||
else if (name == "home")
|
||||
return base::DIR_HOME;
|
||||
else if (name == "temp")
|
||||
return base::DIR_TEMP;
|
||||
else if (name == "userDesktop" || name == "desktop")
|
||||
return base::DIR_USER_DESKTOP;
|
||||
else if (name == "exe")
|
||||
return base::FILE_EXE;
|
||||
else if (name == "module")
|
||||
return base::FILE_MODULE;
|
||||
else if (name == "documents")
|
||||
return chrome::DIR_USER_DOCUMENTS;
|
||||
else if (name == "downloads")
|
||||
return chrome::DIR_DEFAULT_DOWNLOADS;
|
||||
else if (name == "music")
|
||||
return chrome::DIR_USER_MUSIC;
|
||||
else if (name == "pictures")
|
||||
return chrome::DIR_USER_PICTURES;
|
||||
else if (name == "videos")
|
||||
return chrome::DIR_USER_VIDEOS;
|
||||
{"crashDumps", DIR_CRASH_DUMPS},
|
||||
{"desktop", base::DIR_USER_DESKTOP},
|
||||
{"documents", chrome::DIR_USER_DOCUMENTS},
|
||||
{"downloads", chrome::DIR_DEFAULT_DOWNLOADS},
|
||||
{"exe", base::FILE_EXE},
|
||||
{"home", base::DIR_HOME},
|
||||
{"logs", DIR_APP_LOGS},
|
||||
{"module", base::FILE_MODULE},
|
||||
{"music", chrome::DIR_USER_MUSIC},
|
||||
{"pictures", chrome::DIR_USER_PICTURES},
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
else if (name == "recent")
|
||||
return electron::DIR_RECENT;
|
||||
{"recent", electron::DIR_RECENT},
|
||||
#endif
|
||||
else
|
||||
return -1;
|
||||
{"sessionData", DIR_SESSION_DATA},
|
||||
{"temp", base::DIR_TEMP},
|
||||
{"userCache", DIR_USER_CACHE},
|
||||
{"userData", chrome::DIR_USER_DATA},
|
||||
{"userDesktop", base::DIR_USER_DESKTOP},
|
||||
{"videos", chrome::DIR_USER_VIDEOS},
|
||||
});
|
||||
// clang-format on
|
||||
const auto* iter = Lookup.find(name);
|
||||
return iter != Lookup.end() ? iter->second : -1;
|
||||
}
|
||||
|
||||
bool NotificationCallbackWrapper(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "gin/dictionary.h"
|
||||
@@ -760,8 +761,7 @@ void BaseWindow::SetBrowserView(
|
||||
}
|
||||
|
||||
void BaseWindow::AddBrowserView(gin::Handle<BrowserView> browser_view) {
|
||||
auto iter = browser_views_.find(browser_view->ID());
|
||||
if (iter == browser_views_.end()) {
|
||||
if (!base::Contains(browser_views_, browser_view->ID())) {
|
||||
// If we're reparenting a BrowserView, ensure that it's detached from
|
||||
// its previous owner window.
|
||||
BaseWindow* owner_window = browser_view->owner_window();
|
||||
@@ -782,8 +782,8 @@ void BaseWindow::AddBrowserView(gin::Handle<BrowserView> browser_view) {
|
||||
void BaseWindow::RemoveBrowserView(gin::Handle<BrowserView> browser_view) {
|
||||
auto iter = browser_views_.find(browser_view->ID());
|
||||
if (iter != browser_views_.end()) {
|
||||
window_->RemoveBrowserView(browser_view->view());
|
||||
window_->RemoveDraggableRegionProvider(browser_view.get());
|
||||
window_->RemoveBrowserView(browser_view->view());
|
||||
browser_view->SetOwnerWindow(nullptr);
|
||||
iter->second.Reset();
|
||||
browser_views_.erase(iter);
|
||||
|
||||
@@ -134,6 +134,10 @@ void BrowserView::WebContentsDestroyed() {
|
||||
Unpin();
|
||||
}
|
||||
|
||||
void BrowserView::OnCloseContents() {
|
||||
api_web_contents_ = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<BrowserView> BrowserView::New(gin_helper::ErrorThrower thrower,
|
||||
gin::Arguments* args) {
|
||||
|
||||
@@ -71,6 +71,9 @@ class BrowserView : public gin::Wrappable<BrowserView>,
|
||||
// content::WebContentsObserver:
|
||||
void WebContentsDestroyed() override;
|
||||
|
||||
// ExtendedWebContentsObserver:
|
||||
void OnCloseContents() override;
|
||||
|
||||
private:
|
||||
void SetAutoResize(AutoResizeFlags flags);
|
||||
void SetBounds(const gfx::Rect& bounds);
|
||||
|
||||
@@ -181,6 +181,41 @@ DesktopCapturer::DesktopCapturer(v8::Isolate* isolate) {}
|
||||
|
||||
DesktopCapturer::~DesktopCapturer() = default;
|
||||
|
||||
DesktopCapturer::DesktopListListener::DesktopListListener(
|
||||
OnceCallback update_callback,
|
||||
OnceCallback failure_callback,
|
||||
bool skip_thumbnails)
|
||||
: update_callback_(std::move(update_callback)),
|
||||
failure_callback_(std::move(failure_callback)),
|
||||
have_thumbnail_(skip_thumbnails) {}
|
||||
|
||||
DesktopCapturer::DesktopListListener::~DesktopListListener() = default;
|
||||
|
||||
void DesktopCapturer::DesktopListListener::OnDelegatedSourceListSelection() {
|
||||
if (have_thumbnail_) {
|
||||
std::move(update_callback_).Run();
|
||||
} else {
|
||||
have_selection_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::DesktopListListener::OnSourceThumbnailChanged(int index) {
|
||||
if (have_selection_) {
|
||||
// This is called every time a thumbnail is refreshed. Reset variable to
|
||||
// ensure that the callback is not run again.
|
||||
have_selection_ = false;
|
||||
|
||||
// PipeWire returns a single source, so index is not relevant.
|
||||
std::move(update_callback_).Run();
|
||||
} else {
|
||||
have_thumbnail_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::DesktopListListener::OnDelegatedSourceListDismissed() {
|
||||
std::move(failure_callback_).Run();
|
||||
}
|
||||
|
||||
void DesktopCapturer::StartHandling(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size,
|
||||
@@ -199,6 +234,33 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
// clear any existing captured sources.
|
||||
captured_sources_.clear();
|
||||
|
||||
if (capture_window && capture_screen) {
|
||||
// Some capturers like PipeWire suppport a single capturer for both screens
|
||||
// and windows. Use it if possible, treating both as window capture
|
||||
if (auto capturer = webrtc::DesktopCapturer::CreateGenericCapturer(
|
||||
content::desktop_capture::CreateDesktopCaptureOptions());
|
||||
capturer && capturer->GetDelegatedSourceListController()) {
|
||||
capture_screen_ = false;
|
||||
capture_window_ = capture_window;
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer));
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get());
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
|
||||
window_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
window_capturer_->StartUpdating(window_listener_.get());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Start listening for captured sources.
|
||||
capture_window_ = capture_window;
|
||||
capture_screen_ = capture_screen;
|
||||
@@ -212,11 +274,22 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer));
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
window_capturer_->Update(
|
||||
base::BindOnce(&DesktopCapturer::UpdateSourcesList,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get()),
|
||||
/* refresh_thumbnails = */ true);
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get());
|
||||
|
||||
if (window_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
window_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
window_capturer_->StartUpdating(window_listener_.get());
|
||||
} else {
|
||||
window_capturer_->Update(std::move(update_callback),
|
||||
/* refresh_thumbnails = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +299,22 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
screen_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kScreen, std::move(capturer));
|
||||
screen_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
screen_capturer_->Update(
|
||||
base::BindOnce(&DesktopCapturer::UpdateSourcesList,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get()),
|
||||
/* refresh_thumbnails = */ true);
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get());
|
||||
|
||||
if (screen_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
screen_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
screen_capturer_->StartUpdating(screen_listener_.get());
|
||||
} else {
|
||||
screen_capturer_->Update(std::move(update_callback),
|
||||
/* refresh_thumbnails = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,12 +354,7 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
// |media_list_sources|.
|
||||
if (!webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames(
|
||||
&device_names)) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
|
||||
|
||||
Unpin();
|
||||
|
||||
HandleFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -325,6 +404,14 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::HandleFailure() {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
|
||||
|
||||
Unpin();
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<DesktopCapturer> DesktopCapturer::Create(v8::Isolate* isolate) {
|
||||
auto handle = gin::CreateHandle(isolate, new DesktopCapturer(isolate));
|
||||
|
||||
@@ -62,8 +62,37 @@ class DesktopCapturer : public gin::Wrappable<DesktopCapturer>,
|
||||
void OnDelegatedSourceListDismissed() override {}
|
||||
|
||||
private:
|
||||
void UpdateSourcesList(DesktopMediaList* list);
|
||||
using OnceCallback = base::OnceClosure;
|
||||
|
||||
class DesktopListListener : public DesktopMediaListObserver {
|
||||
public:
|
||||
DesktopListListener(OnceCallback update_callback,
|
||||
OnceCallback failure_callback,
|
||||
bool skip_thumbnails);
|
||||
~DesktopListListener() override;
|
||||
|
||||
protected:
|
||||
void OnSourceAdded(int index) override {}
|
||||
void OnSourceRemoved(int index) override {}
|
||||
void OnSourceMoved(int old_index, int new_index) override {}
|
||||
void OnSourceNameChanged(int index) override {}
|
||||
void OnSourceThumbnailChanged(int index) override;
|
||||
void OnSourcePreviewChanged(size_t index) override {}
|
||||
void OnDelegatedSourceListSelection() override;
|
||||
void OnDelegatedSourceListDismissed() override;
|
||||
|
||||
private:
|
||||
OnceCallback update_callback_;
|
||||
OnceCallback failure_callback_;
|
||||
bool have_selection_ = false;
|
||||
bool have_thumbnail_ = false;
|
||||
};
|
||||
|
||||
void UpdateSourcesList(DesktopMediaList* list);
|
||||
void HandleFailure();
|
||||
|
||||
std::unique_ptr<DesktopListListener> window_listener_;
|
||||
std::unique_ptr<DesktopListListener> screen_listener_;
|
||||
std::unique_ptr<DesktopMediaList> window_capturer_;
|
||||
std::unique_ptr<DesktopMediaList> screen_capturer_;
|
||||
std::vector<DesktopCapturer::Source> captured_sources_;
|
||||
|
||||
@@ -62,8 +62,7 @@ GlobalShortcut::~GlobalShortcut() {
|
||||
}
|
||||
|
||||
void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
|
||||
if (accelerator_callback_map_.find(accelerator) ==
|
||||
accelerator_callback_map_.end()) {
|
||||
if (!base::Contains(accelerator_callback_map_, accelerator)) {
|
||||
// This should never occur, because if it does, GlobalShortcutListener
|
||||
// notifies us with wrong accelerator.
|
||||
NOTREACHED();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/functional/callback_helpers.h"
|
||||
#include "content/public/browser/device_service.h"
|
||||
#include "gin/dictionary.h"
|
||||
@@ -106,8 +107,8 @@ bool PowerSaveBlocker::Stop(int id) {
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PowerSaveBlocker::IsStarted(int id) {
|
||||
return wake_lock_types_.find(id) != wake_lock_types_.end();
|
||||
bool PowerSaveBlocker::IsStarted(int id) const {
|
||||
return base::Contains(wake_lock_types_, id);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -37,7 +37,7 @@ class PowerSaveBlocker : public gin::Wrappable<PowerSaveBlocker> {
|
||||
void UpdatePowerSaveBlocker();
|
||||
int Start(device::mojom::WakeLockType type);
|
||||
bool Stop(int id);
|
||||
bool IsStarted(int id);
|
||||
bool IsStarted(int id) const;
|
||||
|
||||
device::mojom::WakeLock* GetWakeLock();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "shell/browser/api/electron_api_system_preferences.h"
|
||||
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/win/core_winrt_util.h"
|
||||
#include "base/win/windows_types.h"
|
||||
#include "base/win/wrapped_window_proc.h"
|
||||
@@ -97,73 +98,45 @@ std::string SystemPreferences::GetAccentColor() {
|
||||
|
||||
std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
|
||||
const std::string& color) {
|
||||
int id;
|
||||
if (color == "3d-dark-shadow") {
|
||||
id = COLOR_3DDKSHADOW;
|
||||
} else if (color == "3d-face") {
|
||||
id = COLOR_3DFACE;
|
||||
} else if (color == "3d-highlight") {
|
||||
id = COLOR_3DHIGHLIGHT;
|
||||
} else if (color == "3d-light") {
|
||||
id = COLOR_3DLIGHT;
|
||||
} else if (color == "3d-shadow") {
|
||||
id = COLOR_3DSHADOW;
|
||||
} else if (color == "active-border") {
|
||||
id = COLOR_ACTIVEBORDER;
|
||||
} else if (color == "active-caption") {
|
||||
id = COLOR_ACTIVECAPTION;
|
||||
} else if (color == "active-caption-gradient") {
|
||||
id = COLOR_GRADIENTACTIVECAPTION;
|
||||
} else if (color == "app-workspace") {
|
||||
id = COLOR_APPWORKSPACE;
|
||||
} else if (color == "button-text") {
|
||||
id = COLOR_BTNTEXT;
|
||||
} else if (color == "caption-text") {
|
||||
id = COLOR_CAPTIONTEXT;
|
||||
} else if (color == "desktop") {
|
||||
id = COLOR_DESKTOP;
|
||||
} else if (color == "disabled-text") {
|
||||
id = COLOR_GRAYTEXT;
|
||||
} else if (color == "highlight") {
|
||||
id = COLOR_HIGHLIGHT;
|
||||
} else if (color == "highlight-text") {
|
||||
id = COLOR_HIGHLIGHTTEXT;
|
||||
} else if (color == "hotlight") {
|
||||
id = COLOR_HOTLIGHT;
|
||||
} else if (color == "inactive-border") {
|
||||
id = COLOR_INACTIVEBORDER;
|
||||
} else if (color == "inactive-caption") {
|
||||
id = COLOR_INACTIVECAPTION;
|
||||
} else if (color == "inactive-caption-gradient") {
|
||||
id = COLOR_GRADIENTINACTIVECAPTION;
|
||||
} else if (color == "inactive-caption-text") {
|
||||
id = COLOR_INACTIVECAPTIONTEXT;
|
||||
} else if (color == "info-background") {
|
||||
id = COLOR_INFOBK;
|
||||
} else if (color == "info-text") {
|
||||
id = COLOR_INFOTEXT;
|
||||
} else if (color == "menu") {
|
||||
id = COLOR_MENU;
|
||||
} else if (color == "menu-highlight") {
|
||||
id = COLOR_MENUHILIGHT;
|
||||
} else if (color == "menubar") {
|
||||
id = COLOR_MENUBAR;
|
||||
} else if (color == "menu-text") {
|
||||
id = COLOR_MENUTEXT;
|
||||
} else if (color == "scrollbar") {
|
||||
id = COLOR_SCROLLBAR;
|
||||
} else if (color == "window") {
|
||||
id = COLOR_WINDOW;
|
||||
} else if (color == "window-frame") {
|
||||
id = COLOR_WINDOWFRAME;
|
||||
} else if (color == "window-text") {
|
||||
id = COLOR_WINDOWTEXT;
|
||||
} else {
|
||||
thrower.ThrowError("Unknown color: " + color);
|
||||
return "";
|
||||
}
|
||||
static constexpr auto Lookup =
|
||||
base::MakeFixedFlatMap<base::StringPiece, int>({
|
||||
{"3d-dark-shadow", COLOR_3DDKSHADOW},
|
||||
{"3d-face", COLOR_3DFACE},
|
||||
{"3d-highlight", COLOR_3DHIGHLIGHT},
|
||||
{"3d-light", COLOR_3DLIGHT},
|
||||
{"3d-shadow", COLOR_3DSHADOW},
|
||||
{"active-border", COLOR_ACTIVEBORDER},
|
||||
{"active-caption", COLOR_ACTIVECAPTION},
|
||||
{"active-caption-gradient", COLOR_GRADIENTACTIVECAPTION},
|
||||
{"app-workspace", COLOR_APPWORKSPACE},
|
||||
{"button-text", COLOR_BTNTEXT},
|
||||
{"caption-text", COLOR_CAPTIONTEXT},
|
||||
{"desktop", COLOR_DESKTOP},
|
||||
{"disabled-text", COLOR_GRAYTEXT},
|
||||
{"highlight", COLOR_HIGHLIGHT},
|
||||
{"highlight-text", COLOR_HIGHLIGHTTEXT},
|
||||
{"hotlight", COLOR_HOTLIGHT},
|
||||
{"inactive-border", COLOR_INACTIVEBORDER},
|
||||
{"inactive-caption", COLOR_INACTIVECAPTION},
|
||||
{"inactive-caption-gradient", COLOR_GRADIENTINACTIVECAPTION},
|
||||
{"inactive-caption-text", COLOR_INACTIVECAPTIONTEXT},
|
||||
{"info-background", COLOR_INFOBK},
|
||||
{"info-text", COLOR_INFOTEXT},
|
||||
{"menu", COLOR_MENU},
|
||||
{"menu-highlight", COLOR_MENUHILIGHT},
|
||||
{"menu-text", COLOR_MENUTEXT},
|
||||
{"menubar", COLOR_MENUBAR},
|
||||
{"scrollbar", COLOR_SCROLLBAR},
|
||||
{"window", COLOR_WINDOW},
|
||||
{"window-frame", COLOR_WINDOWFRAME},
|
||||
{"window-text", COLOR_WINDOWTEXT},
|
||||
});
|
||||
|
||||
return ToRGBHex(color_utils::GetSysSkColor(id));
|
||||
if (const auto* iter = Lookup.find(color); iter != Lookup.end())
|
||||
return ToRGBHex(color_utils::GetSysSkColor(iter->second));
|
||||
|
||||
thrower.ThrowError("Unknown color: " + color);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string SystemPreferences::GetMediaAccessStatus(
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "gin/handle.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
@@ -412,62 +413,46 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
|
||||
request->trusted_params->has_user_activation = has_user_activation;
|
||||
}
|
||||
|
||||
std::string mode;
|
||||
if (opts.Get("mode", &mode) && !mode.empty()) {
|
||||
if (mode == "navigate") {
|
||||
request->mode = network::mojom::RequestMode::kNavigate;
|
||||
} else if (mode == "cors") {
|
||||
request->mode = network::mojom::RequestMode::kCors;
|
||||
} else if (mode == "no-cors") {
|
||||
request->mode = network::mojom::RequestMode::kNoCors;
|
||||
} else if (mode == "same-origin") {
|
||||
request->mode = network::mojom::RequestMode::kSameOrigin;
|
||||
}
|
||||
if (std::string mode; opts.Get("mode", &mode)) {
|
||||
using Val = network::mojom::RequestMode;
|
||||
static constexpr auto Lookup =
|
||||
base::MakeFixedFlatMap<base::StringPiece, Val>({
|
||||
{"cors", Val::kCors},
|
||||
{"navigate", Val::kNavigate},
|
||||
{"no-cors", Val::kNoCors},
|
||||
{"same-origin", Val::kSameOrigin},
|
||||
});
|
||||
if (auto* iter = Lookup.find(mode); iter != Lookup.end())
|
||||
request->mode = iter->second;
|
||||
}
|
||||
|
||||
std::string destination;
|
||||
if (opts.Get("destination", &destination) && !destination.empty()) {
|
||||
if (destination == "empty") {
|
||||
request->destination = network::mojom::RequestDestination::kEmpty;
|
||||
} else if (destination == "audio") {
|
||||
request->destination = network::mojom::RequestDestination::kAudio;
|
||||
} else if (destination == "audioworklet") {
|
||||
request->destination = network::mojom::RequestDestination::kAudioWorklet;
|
||||
} else if (destination == "document") {
|
||||
request->destination = network::mojom::RequestDestination::kDocument;
|
||||
} else if (destination == "embed") {
|
||||
request->destination = network::mojom::RequestDestination::kEmbed;
|
||||
} else if (destination == "font") {
|
||||
request->destination = network::mojom::RequestDestination::kFont;
|
||||
} else if (destination == "frame") {
|
||||
request->destination = network::mojom::RequestDestination::kFrame;
|
||||
} else if (destination == "iframe") {
|
||||
request->destination = network::mojom::RequestDestination::kIframe;
|
||||
} else if (destination == "image") {
|
||||
request->destination = network::mojom::RequestDestination::kImage;
|
||||
} else if (destination == "manifest") {
|
||||
request->destination = network::mojom::RequestDestination::kManifest;
|
||||
} else if (destination == "object") {
|
||||
request->destination = network::mojom::RequestDestination::kObject;
|
||||
} else if (destination == "paintworklet") {
|
||||
request->destination = network::mojom::RequestDestination::kPaintWorklet;
|
||||
} else if (destination == "report") {
|
||||
request->destination = network::mojom::RequestDestination::kReport;
|
||||
} else if (destination == "script") {
|
||||
request->destination = network::mojom::RequestDestination::kScript;
|
||||
} else if (destination == "serviceworker") {
|
||||
request->destination = network::mojom::RequestDestination::kServiceWorker;
|
||||
} else if (destination == "style") {
|
||||
request->destination = network::mojom::RequestDestination::kStyle;
|
||||
} else if (destination == "track") {
|
||||
request->destination = network::mojom::RequestDestination::kTrack;
|
||||
} else if (destination == "video") {
|
||||
request->destination = network::mojom::RequestDestination::kVideo;
|
||||
} else if (destination == "worker") {
|
||||
request->destination = network::mojom::RequestDestination::kWorker;
|
||||
} else if (destination == "xslt") {
|
||||
request->destination = network::mojom::RequestDestination::kXslt;
|
||||
}
|
||||
if (std::string destination; opts.Get("destination", &destination)) {
|
||||
using Val = network::mojom::RequestDestination;
|
||||
static constexpr auto Lookup =
|
||||
base::MakeFixedFlatMap<base::StringPiece, Val>({
|
||||
{"audio", Val::kAudio},
|
||||
{"audioworklet", Val::kAudioWorklet},
|
||||
{"document", Val::kDocument},
|
||||
{"embed", Val::kEmbed},
|
||||
{"empty", Val::kEmpty},
|
||||
{"font", Val::kFont},
|
||||
{"frame", Val::kFrame},
|
||||
{"iframe", Val::kIframe},
|
||||
{"image", Val::kImage},
|
||||
{"manifest", Val::kManifest},
|
||||
{"object", Val::kObject},
|
||||
{"paintworklet", Val::kPaintWorklet},
|
||||
{"report", Val::kReport},
|
||||
{"script", Val::kScript},
|
||||
{"serviceworker", Val::kServiceWorker},
|
||||
{"style", Val::kStyle},
|
||||
{"track", Val::kTrack},
|
||||
{"video", Val::kVideo},
|
||||
{"worker", Val::kWorker},
|
||||
{"xslt", Val::kXslt},
|
||||
});
|
||||
if (auto* iter = Lookup.find(destination); iter != Lookup.end())
|
||||
request->destination = iter->second;
|
||||
}
|
||||
|
||||
bool credentials_specified =
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/containers/id_map.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/json/json_reader.h"
|
||||
@@ -729,8 +730,8 @@ std::map<std::string, std::string> GetAddedFileSystemPaths(
|
||||
|
||||
bool IsDevToolsFileSystemAdded(content::WebContents* web_contents,
|
||||
const std::string& file_system_path) {
|
||||
auto file_system_paths = GetAddedFileSystemPaths(web_contents);
|
||||
return file_system_paths.find(file_system_path) != file_system_paths.end();
|
||||
return base::Contains(GetAddedFileSystemPaths(web_contents),
|
||||
file_system_path);
|
||||
}
|
||||
|
||||
void SetBackgroundColor(content::RenderWidgetHostView* rwhv, SkColor color) {
|
||||
@@ -768,12 +769,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
content::WebContents* web_contents)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
type_(Type::kRemote),
|
||||
id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
id_(GetAllWebContents().Add(this))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
,
|
||||
print_task_runner_(CreatePrinterHandlerTaskRunner())
|
||||
@@ -806,12 +802,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
Type type)
|
||||
: content::WebContentsObserver(web_contents.get()),
|
||||
type_(type),
|
||||
id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
id_(GetAllWebContents().Add(this))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
,
|
||||
print_task_runner_(CreatePrinterHandlerTaskRunner())
|
||||
@@ -827,12 +818,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
|
||||
WebContents::WebContents(v8::Isolate* isolate,
|
||||
const gin_helper::Dictionary& options)
|
||||
: id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
: id_(GetAllWebContents().Add(this))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
,
|
||||
print_task_runner_(CreatePrinterHandlerTaskRunner())
|
||||
@@ -1339,7 +1325,9 @@ void WebContents::CloseContents(content::WebContents* source) {
|
||||
for (ExtendedWebContentsObserver& observer : observers_)
|
||||
observer.OnCloseContents();
|
||||
|
||||
Destroy();
|
||||
// This is handled by the embedder frame.
|
||||
if (!IsGuest())
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void WebContents::ActivateContents(content::WebContents* source) {
|
||||
@@ -1394,7 +1382,7 @@ bool WebContents::PlatformHandleKeyboardEvent(
|
||||
content::KeyboardEventProcessingResult WebContents::PreHandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (exclusive_access_manager_->HandleUserKeyEvent(event))
|
||||
if (exclusive_access_manager_.HandleUserKeyEvent(event))
|
||||
return content::KeyboardEventProcessingResult::HANDLED;
|
||||
|
||||
if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown ||
|
||||
@@ -1482,7 +1470,7 @@ void WebContents::OnEnterFullscreenModeForTab(
|
||||
|
||||
owner_window()->set_fullscreen_transition_type(
|
||||
NativeWindow::FullScreenTransitionType::HTML);
|
||||
exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab(
|
||||
exclusive_access_manager_.fullscreen_controller()->EnterFullscreenModeForTab(
|
||||
requesting_frame, options.display_id);
|
||||
|
||||
SetHtmlApiFullscreen(true);
|
||||
@@ -1500,7 +1488,7 @@ void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
|
||||
// This needs to be called before we exit fullscreen on the native window,
|
||||
// or the controller will incorrectly think we weren't fullscreen and bail.
|
||||
exclusive_access_manager_->fullscreen_controller()->ExitFullscreenModeForTab(
|
||||
exclusive_access_manager_.fullscreen_controller()->ExitFullscreenModeForTab(
|
||||
source);
|
||||
|
||||
SetHtmlApiFullscreen(false);
|
||||
@@ -1559,7 +1547,7 @@ void WebContents::RequestExclusivePointerAccess(
|
||||
bool last_unlocked_by_target,
|
||||
bool allowed) {
|
||||
if (allowed) {
|
||||
exclusive_access_manager_->mouse_lock_controller()->RequestToLockMouse(
|
||||
exclusive_access_manager_.mouse_lock_controller()->RequestToLockMouse(
|
||||
web_contents, user_gesture, last_unlocked_by_target);
|
||||
} else {
|
||||
web_contents->GotResponseToLockMouseRequest(
|
||||
@@ -1579,18 +1567,18 @@ void WebContents::RequestToLockMouse(content::WebContents* web_contents,
|
||||
}
|
||||
|
||||
void WebContents::LostMouseLock() {
|
||||
exclusive_access_manager_->mouse_lock_controller()->LostMouseLock();
|
||||
exclusive_access_manager_.mouse_lock_controller()->LostMouseLock();
|
||||
}
|
||||
|
||||
void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
|
||||
bool esc_key_locked) {
|
||||
exclusive_access_manager_->keyboard_lock_controller()->RequestKeyboardLock(
|
||||
exclusive_access_manager_.keyboard_lock_controller()->RequestKeyboardLock(
|
||||
web_contents, esc_key_locked);
|
||||
}
|
||||
|
||||
void WebContents::CancelKeyboardLockRequest(
|
||||
content::WebContents* web_contents) {
|
||||
exclusive_access_manager_->keyboard_lock_controller()
|
||||
exclusive_access_manager_.keyboard_lock_controller()
|
||||
->CancelKeyboardLockRequest(web_contents);
|
||||
}
|
||||
|
||||
@@ -1961,7 +1949,8 @@ void WebContents::MessageSync(
|
||||
|
||||
void WebContents::MessageTo(int32_t web_contents_id,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments) {
|
||||
blink::CloneableMessage arguments,
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
TRACE_EVENT1("electron", "WebContents::MessageTo", "channel", channel);
|
||||
auto* target_web_contents = FromID(web_contents_id);
|
||||
|
||||
@@ -1977,8 +1966,10 @@ void WebContents::MessageTo(int32_t web_contents_id,
|
||||
return;
|
||||
|
||||
int32_t sender_id = ID();
|
||||
bool sender_is_main_frame = render_frame_host->GetParent() == nullptr;
|
||||
web_frame_main->GetRendererApi()->Message(false /* internal */, channel,
|
||||
std::move(arguments), sender_id);
|
||||
std::move(arguments), sender_id,
|
||||
sender_is_main_frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/observer_list_types.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "chrome/browser/devtools/devtools_eye_dropper.h"
|
||||
#include "chrome/browser/devtools/devtools_file_system_indexer.h"
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" // nogncheck
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
|
||||
#include "content/common/frame.mojom.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/keyboard_event_processing_result.h"
|
||||
@@ -75,8 +77,6 @@ namespace gin {
|
||||
class Arguments;
|
||||
}
|
||||
|
||||
class ExclusiveAccessManager;
|
||||
|
||||
class SkRegion;
|
||||
|
||||
namespace electron {
|
||||
@@ -418,7 +418,8 @@ class WebContents : public ExclusiveAccessContext,
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
void MessageTo(int32_t web_contents_id,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments);
|
||||
blink::CloneableMessage arguments,
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
void MessageHost(const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
@@ -790,9 +791,10 @@ class WebContents : public ExclusiveAccessContext,
|
||||
// Whether window is fullscreened by window api.
|
||||
bool native_fullscreen_ = false;
|
||||
|
||||
scoped_refptr<DevToolsFileSystemIndexer> devtools_file_system_indexer_;
|
||||
const scoped_refptr<DevToolsFileSystemIndexer> devtools_file_system_indexer_ =
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>();
|
||||
|
||||
std::unique_ptr<ExclusiveAccessManager> exclusive_access_manager_;
|
||||
ExclusiveAccessManager exclusive_access_manager_{this};
|
||||
|
||||
std::unique_ptr<DevToolsEyeDropper> eye_dropper_;
|
||||
|
||||
@@ -814,10 +816,11 @@ class WebContents : public ExclusiveAccessContext,
|
||||
DevToolsIndexingJobsMap;
|
||||
DevToolsIndexingJobsMap devtools_indexing_jobs_;
|
||||
|
||||
scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
|
||||
const scoped_refptr<base::SequencedTaskRunner> file_task_runner_ =
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
scoped_refptr<base::TaskRunner> print_task_runner_;
|
||||
const scoped_refptr<base::TaskRunner> print_task_runner_;
|
||||
#endif
|
||||
|
||||
// Stores the frame thats currently in fullscreen, nullptr if there is none.
|
||||
|
||||
@@ -185,7 +185,8 @@ void WebFrameMain::Send(v8::Isolate* isolate,
|
||||
return;
|
||||
|
||||
GetRendererApi()->Message(internal, channel, std::move(message),
|
||||
0 /* sender_id */);
|
||||
0 /* sender_id */,
|
||||
false /* sender_is_main_frame */);
|
||||
}
|
||||
|
||||
const mojo::Remote<mojom::ElectronRenderer>& WebFrameMain::GetRendererApi() {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/values.h"
|
||||
@@ -294,7 +295,7 @@ bool WebRequest::RequestFilter::MatchesURL(const GURL& url) const {
|
||||
|
||||
bool WebRequest::RequestFilter::MatchesType(
|
||||
extensions::WebRequestResourceType type) const {
|
||||
return types_.empty() || types_.find(type) != types_.end();
|
||||
return types_.empty() || base::Contains(types_, type);
|
||||
}
|
||||
|
||||
bool WebRequest::RequestFilter::MatchesRequest(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "gin/arguments.h"
|
||||
@@ -221,7 +222,7 @@ std::vector<blink::MessagePortChannel> MessagePort::DisentanglePorts(
|
||||
// or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec).
|
||||
for (unsigned i = 0; i < ports.size(); ++i) {
|
||||
auto* port = ports[i].get();
|
||||
if (!port || port->IsNeutered() || visited.find(port) != visited.end()) {
|
||||
if (!port || port->IsNeutered() || base::Contains(visited, port)) {
|
||||
std::string type;
|
||||
if (!port)
|
||||
type = "null";
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "components/proxy_config/proxy_config_dictionary.h"
|
||||
#include "components/proxy_config/proxy_config_pref_names.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/browser/network_quality_observer_factory.h"
|
||||
#include "content/public/browser/network_service_instance.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "electron/fuses.h"
|
||||
#include "extensions/common/constants.h"
|
||||
@@ -130,6 +132,10 @@ void BrowserProcessImpl::PreCreateThreads() {
|
||||
SystemNetworkContextManager::CreateInstance(local_state_.get());
|
||||
}
|
||||
|
||||
void BrowserProcessImpl::PreMainMessageLoopRun() {
|
||||
CreateNetworkQualityObserver();
|
||||
}
|
||||
|
||||
void BrowserProcessImpl::PostMainMessageLoopRun() {
|
||||
if (local_state_)
|
||||
local_state_->CommitPendingWrite();
|
||||
@@ -324,3 +330,18 @@ printing::PrintJobManager* BrowserProcessImpl::print_job_manager() {
|
||||
StartupData* BrowserProcessImpl::startup_data() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
network::NetworkQualityTracker* BrowserProcessImpl::GetNetworkQualityTracker() {
|
||||
if (!network_quality_tracker_) {
|
||||
network_quality_tracker_ = std::make_unique<network::NetworkQualityTracker>(
|
||||
base::BindRepeating(&content::GetNetworkService));
|
||||
}
|
||||
return network_quality_tracker_.get();
|
||||
}
|
||||
|
||||
void BrowserProcessImpl::CreateNetworkQualityObserver() {
|
||||
DCHECK(!network_quality_observer_);
|
||||
network_quality_observer_ =
|
||||
content::CreateNetworkQualityObserver(GetNetworkQualityTracker());
|
||||
DCHECK(network_quality_observer_);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/prefs/value_map_pref_store.h"
|
||||
#include "printing/buildflags/buildflags.h"
|
||||
#include "services/network/public/cpp/network_quality_tracker.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "shell/browser/net/system_network_context_manager.h"
|
||||
|
||||
@@ -46,6 +47,7 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
GetBreadcrumbPersistentStorageManager() override;
|
||||
void PostEarlyInitialization();
|
||||
void PreCreateThreads();
|
||||
void PreMainMessageLoopRun();
|
||||
void PostDestroyThreads() {}
|
||||
void PostMainMessageLoopRun();
|
||||
|
||||
@@ -109,12 +111,19 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
StartupData* startup_data() override;
|
||||
|
||||
private:
|
||||
void CreateNetworkQualityObserver();
|
||||
network::NetworkQualityTracker* GetNetworkQualityTracker();
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
std::unique_ptr<printing::PrintJobManager> print_job_manager_;
|
||||
#endif
|
||||
std::unique_ptr<PrefService> local_state_;
|
||||
std::string locale_;
|
||||
std::string system_locale_;
|
||||
|
||||
std::unique_ptr<network::NetworkQualityTracker> network_quality_tracker_;
|
||||
std::unique_ptr<
|
||||
network::NetworkQualityTracker::RTTAndThroughputEstimatesObserver>
|
||||
network_quality_observer_;
|
||||
};
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_BROWSER_PROCESS_IMPL_H_
|
||||
|
||||
@@ -82,7 +82,8 @@ void ElectronApiIPCHandlerImpl::MessageTo(int32_t web_contents_id,
|
||||
blink::CloneableMessage arguments) {
|
||||
api::WebContents* api_web_contents = api::WebContents::From(web_contents());
|
||||
if (api_web_contents) {
|
||||
api_web_contents->MessageTo(web_contents_id, channel, std::move(arguments));
|
||||
api_web_contents->MessageTo(web_contents_id, channel, std::move(arguments),
|
||||
GetRenderFrameHost());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -778,32 +778,6 @@ base::FilePath ElectronBrowserClient::GetLoggingFileName(
|
||||
return logging::GetLogFileName(cmd_line);
|
||||
}
|
||||
|
||||
void ElectronBrowserClient::SiteInstanceDeleting(
|
||||
content::SiteInstance* site_instance) {
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
// Don't do anything if we're shutting down.
|
||||
if (content::BrowserMainRunner::ExitedMainMessageLoop())
|
||||
return;
|
||||
|
||||
auto* browser_context =
|
||||
static_cast<ElectronBrowserContext*>(site_instance->GetBrowserContext());
|
||||
if (!browser_context->IsOffTheRecord()) {
|
||||
// If this isn't an extension renderer there's nothing to do.
|
||||
extensions::ExtensionRegistry* registry =
|
||||
extensions::ExtensionRegistry::Get(browser_context);
|
||||
const extensions::Extension* extension =
|
||||
registry->enabled_extensions().GetExtensionOrAppByURL(
|
||||
site_instance->GetSiteURL());
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
extensions::ProcessMap::Get(browser_context)
|
||||
->Remove(extension->id(), site_instance->GetProcess()->GetID(),
|
||||
site_instance->GetId());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<net::ClientCertStore>
|
||||
ElectronBrowserClient::CreateClientCertStore(
|
||||
content::BrowserContext* browser_context) {
|
||||
|
||||
@@ -166,7 +166,6 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
||||
std::vector<std::string>* additional_schemes) override;
|
||||
void GetAdditionalWebUISchemes(
|
||||
std::vector<std::string>* additional_schemes) override;
|
||||
void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
|
||||
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
|
||||
content::BrowserContext* browser_context) override;
|
||||
std::unique_ptr<device::LocationProvider> OverrideSystemLocationProvider()
|
||||
|
||||
@@ -210,11 +210,11 @@ ElectronBrowserMainParts* ElectronBrowserMainParts::self_ = nullptr;
|
||||
|
||||
ElectronBrowserMainParts::ElectronBrowserMainParts()
|
||||
: fake_browser_process_(std::make_unique<BrowserProcessImpl>()),
|
||||
browser_(std::make_unique<Browser>()),
|
||||
node_bindings_(
|
||||
NodeBindings::Create(NodeBindings::BrowserEnvironment::kBrowser)),
|
||||
electron_bindings_(
|
||||
std::make_unique<ElectronBindings>(node_bindings_->uv_loop())) {
|
||||
node_bindings_{
|
||||
NodeBindings::Create(NodeBindings::BrowserEnvironment::kBrowser)},
|
||||
electron_bindings_{
|
||||
std::make_unique<ElectronBindings>(node_bindings_->uv_loop())},
|
||||
browser_{std::make_unique<Browser>()} {
|
||||
DCHECK(!self_) << "Cannot have two ElectronBrowserMainParts";
|
||||
self_ = this;
|
||||
}
|
||||
@@ -525,6 +525,8 @@ int ElectronBrowserMainParts::PreMainMessageLoopRun() {
|
||||
// Notify observers that main thread message loop was initialized.
|
||||
Browser::Get()->PreMainMessageLoopRun();
|
||||
|
||||
fake_browser_process_->PreMainMessageLoopRun();
|
||||
|
||||
return GetExitCode();
|
||||
}
|
||||
|
||||
|
||||
@@ -165,11 +165,20 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
|
||||
// Before then, we just exit() without any intermediate steps.
|
||||
absl::optional<int> exit_code_;
|
||||
|
||||
std::unique_ptr<JavascriptEnvironment> js_env_;
|
||||
std::unique_ptr<Browser> browser_;
|
||||
std::unique_ptr<NodeBindings> node_bindings_;
|
||||
|
||||
// depends-on: node_bindings_
|
||||
std::unique_ptr<ElectronBindings> electron_bindings_;
|
||||
|
||||
// depends-on: node_bindings_
|
||||
std::unique_ptr<JavascriptEnvironment> js_env_;
|
||||
|
||||
// depends-on: js_env_'s isolate
|
||||
std::unique_ptr<NodeEnvironment> node_env_;
|
||||
|
||||
// depends-on: js_env_'s isolate
|
||||
std::unique_ptr<Browser> browser_;
|
||||
|
||||
std::unique_ptr<IconManager> icon_manager_;
|
||||
std::unique_ptr<base::FieldTrialList> field_trial_list_;
|
||||
|
||||
|
||||
@@ -149,8 +149,7 @@ void HidChooserController::OnDeviceAdded(
|
||||
void HidChooserController::OnDeviceRemoved(
|
||||
const device::mojom::HidDeviceInfo& device) {
|
||||
auto id = PhysicalDeviceIdFromDeviceInfo(device);
|
||||
auto items_it = std::find(items_.begin(), items_.end(), id);
|
||||
if (items_it == items_.end())
|
||||
if (!base::Contains(items_, id))
|
||||
return;
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
@@ -197,10 +198,6 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) {
|
||||
SetSizeConstraints(size_constraints);
|
||||
}
|
||||
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
|
||||
bool resizable;
|
||||
if (options.Get(options::kResizable, &resizable)) {
|
||||
SetResizable(resizable);
|
||||
}
|
||||
bool closable;
|
||||
if (options.Get(options::kClosable, &closable)) {
|
||||
SetClosable(closable);
|
||||
@@ -222,6 +219,7 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) {
|
||||
if (options.Get(options::kAlwaysOnTop, &top) && top) {
|
||||
SetAlwaysOnTop(ui::ZOrderLevel::kFloatingWindow);
|
||||
}
|
||||
|
||||
bool fullscreenable = true;
|
||||
bool fullscreen = false;
|
||||
if (options.Get(options::kFullscreen, &fullscreen) && !fullscreen) {
|
||||
@@ -230,12 +228,18 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) {
|
||||
fullscreenable = false;
|
||||
#endif
|
||||
}
|
||||
// Overridden by 'fullscreenable'.
|
||||
|
||||
options.Get(options::kFullScreenable, &fullscreenable);
|
||||
SetFullScreenable(fullscreenable);
|
||||
if (fullscreen) {
|
||||
|
||||
if (fullscreen)
|
||||
SetFullScreen(true);
|
||||
|
||||
bool resizable;
|
||||
if (options.Get(options::kResizable, &resizable)) {
|
||||
SetResizable(resizable);
|
||||
}
|
||||
|
||||
bool skip;
|
||||
if (options.Get(options::kSkipTaskbar, &skip)) {
|
||||
SetSkipTaskbar(skip);
|
||||
@@ -725,9 +729,7 @@ int NativeWindow::NonClientHitTest(const gfx::Point& point) {
|
||||
|
||||
void NativeWindow::AddDraggableRegionProvider(
|
||||
DraggableRegionProvider* provider) {
|
||||
if (std::find(draggable_region_providers_.begin(),
|
||||
draggable_region_providers_.end(),
|
||||
provider) == draggable_region_providers_.end()) {
|
||||
if (!base::Contains(draggable_region_providers_, provider)) {
|
||||
draggable_region_providers_.push_back(provider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual std::string GetAlwaysOnTopLevel() = 0;
|
||||
virtual void SetActive(bool is_key) = 0;
|
||||
virtual bool IsActive() const = 0;
|
||||
virtual void RemoveChildFromParentWindow() = 0;
|
||||
virtual void RemoveChildWindow(NativeWindow* child) = 0;
|
||||
virtual void AttachChildren() = 0;
|
||||
virtual void DetachChildren() = 0;
|
||||
|
||||
@@ -157,7 +157,7 @@ class NativeWindowMac : public NativeWindow,
|
||||
bool IsActive() const override;
|
||||
// Remove the specified child window without closing it.
|
||||
void RemoveChildWindow(NativeWindow* child) override;
|
||||
void RemoveChildFromParentWindow(NativeWindow* child);
|
||||
void RemoveChildFromParentWindow() override;
|
||||
// Attach child windows, if the window is visible.
|
||||
void AttachChildren() override;
|
||||
// Detach window from parent without destroying it.
|
||||
|
||||
@@ -163,6 +163,47 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
|
||||
[self setFrame:[[self superview] bounds]];
|
||||
}
|
||||
|
||||
// -[NSWindow orderWindow] does not handle reordering for children
|
||||
// windows. Their order is fixed to the attachment order (the last attached
|
||||
// window is on the top). Therefore, work around it by re-parenting in our
|
||||
// desired order.
|
||||
void ReorderChildWindowAbove(NSWindow* child_window, NSWindow* other_window) {
|
||||
NSWindow* parent = [child_window parentWindow];
|
||||
DCHECK(parent);
|
||||
|
||||
// `ordered_children` sorts children windows back to front.
|
||||
NSArray<NSWindow*>* children = [[child_window parentWindow] childWindows];
|
||||
std::vector<std::pair<NSInteger, NSWindow*>> ordered_children;
|
||||
for (NSWindow* child in children)
|
||||
ordered_children.push_back({[child orderedIndex], child});
|
||||
std::sort(ordered_children.begin(), ordered_children.end(), std::greater<>());
|
||||
|
||||
// If `other_window` is nullptr, place `child_window` in front of
|
||||
// all other children windows.
|
||||
if (other_window == nullptr)
|
||||
other_window = ordered_children.back().second;
|
||||
|
||||
if (child_window == other_window)
|
||||
return;
|
||||
|
||||
for (NSWindow* child in children)
|
||||
[parent removeChildWindow:child];
|
||||
|
||||
const bool relative_to_parent = parent == other_window;
|
||||
if (relative_to_parent)
|
||||
[parent addChildWindow:child_window ordered:NSWindowAbove];
|
||||
|
||||
// Re-parent children windows in the desired order.
|
||||
for (auto [ordered_index, child] : ordered_children) {
|
||||
if (child != child_window && child != other_window) {
|
||||
[parent addChildWindow:child ordered:NSWindowAbove];
|
||||
} else if (child == other_window && !relative_to_parent) {
|
||||
[parent addChildWindow:other_window ordered:NSWindowAbove];
|
||||
[parent addChildWindow:child_window ordered:NSWindowAbove];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
||||
@@ -390,7 +431,12 @@ void NativeWindowMac::Close() {
|
||||
}
|
||||
|
||||
// Ensure we're detached from the parent window before closing.
|
||||
RemoveChildFromParentWindow(this);
|
||||
RemoveChildFromParentWindow();
|
||||
|
||||
while (!child_windows_.empty()) {
|
||||
auto* child = child_windows_.back();
|
||||
child->RemoveChildFromParentWindow();
|
||||
}
|
||||
|
||||
// If a sheet is attached to the window when we call
|
||||
// [window_ performClose:nil], the window won't close properly
|
||||
@@ -409,13 +455,20 @@ void NativeWindowMac::Close() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::CloseImmediately() {
|
||||
RemoveChildFromParentWindow(this);
|
||||
// Ensure we're detached from the parent window before closing.
|
||||
RemoveChildFromParentWindow();
|
||||
|
||||
// Retain the child window before closing it. If the last reference to the
|
||||
// NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
|
||||
// See e.g. http://crbug.com/616701.
|
||||
base::scoped_nsobject<NSWindow> child_window(window_,
|
||||
base::scoped_policy::RETAIN);
|
||||
|
||||
while (!child_windows_.empty()) {
|
||||
auto* child = child_windows_.back();
|
||||
child->RemoveChildFromParentWindow();
|
||||
}
|
||||
|
||||
[window_ close];
|
||||
}
|
||||
|
||||
@@ -604,9 +657,11 @@ void NativeWindowMac::RemoveChildWindow(NativeWindow* child) {
|
||||
[window_ removeChildWindow:child->GetNativeWindow().GetNativeNSWindow()];
|
||||
}
|
||||
|
||||
void NativeWindowMac::RemoveChildFromParentWindow(NativeWindow* child) {
|
||||
if (parent())
|
||||
parent()->RemoveChildWindow(child);
|
||||
void NativeWindowMac::RemoveChildFromParentWindow() {
|
||||
if (parent() && !is_modal()) {
|
||||
parent()->RemoveChildWindow(this);
|
||||
NativeWindow::SetParentWindow(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::AttachChildren() {
|
||||
@@ -760,19 +815,41 @@ bool NativeWindowMac::MoveAbove(const std::string& sourceId) {
|
||||
if (!webrtc::GetWindowOwnerPid(window_id))
|
||||
return false;
|
||||
|
||||
[window_ orderWindow:NSWindowAbove relativeTo:id.id];
|
||||
if (!parent() || is_modal()) {
|
||||
[window_ orderWindow:NSWindowAbove relativeTo:window_id];
|
||||
} else {
|
||||
NSWindow* other_window = [NSApp windowWithWindowNumber:window_id];
|
||||
ReorderChildWindowAbove(window_, other_window);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeWindowMac::MoveTop() {
|
||||
[window_ orderWindow:NSWindowAbove relativeTo:0];
|
||||
if (!parent() || is_modal()) {
|
||||
[window_ orderWindow:NSWindowAbove relativeTo:0];
|
||||
} else {
|
||||
ReorderChildWindowAbove(window_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetResizable(bool resizable) {
|
||||
ScopedDisableResize disable_resize;
|
||||
SetStyleMask(resizable, NSWindowStyleMaskResizable);
|
||||
|
||||
bool was_fullscreenable = IsFullScreenable();
|
||||
|
||||
// Right now, resizable and fullscreenable are decoupled in
|
||||
// documentation and on Windows/Linux. Chromium disables
|
||||
// fullscreen collection behavior as well as the maximize traffic
|
||||
// light in SetCanResize if resizability is false on macOS unless
|
||||
// the window is both resizable and maximizable. We want consistent
|
||||
// cross-platform behavior, so if resizability is disabled we disable
|
||||
// the maximize button and ensure fullscreenability matches user setting.
|
||||
SetCanResize(resizable);
|
||||
SetFullScreenable(was_fullscreenable);
|
||||
[[window_ standardWindowButton:NSWindowZoomButton]
|
||||
setEnabled:resizable ? was_fullscreenable : false];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsResizable() {
|
||||
@@ -1801,12 +1878,13 @@ void NativeWindowMac::InternalSetParentWindow(NativeWindow* new_parent,
|
||||
return;
|
||||
|
||||
// Remove current parent window.
|
||||
RemoveChildFromParentWindow(this);
|
||||
RemoveChildFromParentWindow();
|
||||
|
||||
// Set new parent window.
|
||||
if (new_parent && attach) {
|
||||
if (new_parent) {
|
||||
new_parent->add_child_window(this);
|
||||
new_parent->AttachChildren();
|
||||
if (attach)
|
||||
new_parent->AttachChildren();
|
||||
}
|
||||
|
||||
NativeWindow::SetParentWindow(new_parent);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/cxx17_backports.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@@ -233,6 +234,10 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
||||
|
||||
if (title_bar_style_ != TitleBarStyle::kNormal)
|
||||
set_has_frame(false);
|
||||
|
||||
// If the taskbar is re-created after we start up, we have to rebuild all of
|
||||
// our buttons.
|
||||
taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||||
#endif
|
||||
|
||||
if (enable_larger_than_screen())
|
||||
@@ -1439,8 +1444,7 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
|
||||
std::vector<x11::Atom> wm_states;
|
||||
GetArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
|
||||
x11::GetAtom("_NET_WM_STATE"), &wm_states);
|
||||
return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
|
||||
wm_states.end();
|
||||
return base::Contains(wm_states, sticky_atom);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
|
||||
@@ -315,6 +315,10 @@ class NativeWindowViews : public NativeWindow,
|
||||
// Controls Overlay if enabled on Windows.
|
||||
SkColor overlay_button_color_;
|
||||
SkColor overlay_symbol_color_;
|
||||
|
||||
// The message ID of the "TaskbarCreated" message, sent to us when we need to
|
||||
// reset our thumbar buttons.
|
||||
UINT taskbar_created_message_ = 0;
|
||||
#endif
|
||||
|
||||
// Handles unhandled keyboard messages coming back from the renderer process.
|
||||
|
||||
@@ -221,6 +221,12 @@ bool NativeWindowViews::PreHandleMSG(UINT message,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (message == taskbar_created_message_) {
|
||||
// We need to reset all of our buttons because the taskbar went away.
|
||||
taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget());
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
// Screen readers send WM_GETOBJECT in order to get the accessibility
|
||||
// object, so take this opportunity to push Chromium into accessible
|
||||
|
||||
@@ -64,6 +64,11 @@ void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
options.reply_placeholder)];
|
||||
}
|
||||
|
||||
// We need to explicitly set this to false if there are no
|
||||
// actions, otherwise a Show button will appear by default.
|
||||
if (options.actions.size() == 0)
|
||||
[notification_ setHasActionButton:false];
|
||||
|
||||
int i = 0;
|
||||
action_index_ = UINT_MAX;
|
||||
NSMutableArray* additionalActions =
|
||||
@@ -75,7 +80,6 @@ void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
// become additional actions.
|
||||
if (!options.has_reply && action_index_ == UINT_MAX) {
|
||||
// First button observed is the displayed action
|
||||
[notification_ setHasActionButton:true];
|
||||
[notification_
|
||||
setActionButtonTitle:base::SysUTF16ToNSString(action.text)];
|
||||
action_index_ = i;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user