mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
18 Commits
v31.0.0
...
v32.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b41da150ca | ||
|
|
b684a98267 | ||
|
|
7621e7cff7 | ||
|
|
d8f8560b1c | ||
|
|
1cf194faae | ||
|
|
a0fee8f47a | ||
|
|
4e8c28fdf0 | ||
|
|
46adb0a3a9 | ||
|
|
a8db7fe2ef | ||
|
|
0346e0a8bf | ||
|
|
39bf441b3b | ||
|
|
46ef7ef8fb | ||
|
|
07a68c2bf8 | ||
|
|
ed9fec7da4 | ||
|
|
c4aeb17245 | ||
|
|
67ba30402b | ||
|
|
b683754c16 | ||
|
|
0222686e9a |
@@ -27,7 +27,8 @@
|
||||
]
|
||||
},
|
||||
"vscode": {
|
||||
"extensions": ["joeleinbinder.mojom-language",
|
||||
"extensions": [
|
||||
"joeleinbinder.mojom-language",
|
||||
"rafaelmaiolla.diff",
|
||||
"surajbarkale.ninja",
|
||||
"ms-vscode.cpptools",
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
buildtools:
|
||||
image: ghcr.io/electron/devcontainer:3d8d44d0f15b05bef6149e448f9cc522111847e9
|
||||
image: ghcr.io/electron/devcontainer:9a43c14f5c19be0359843299f79e736521373adc
|
||||
|
||||
volumes:
|
||||
- ..:/workspaces/gclient/src/electron:cached
|
||||
|
||||
@@ -39,7 +39,6 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
write_config() {
|
||||
echo "
|
||||
{
|
||||
\"goma\": \"$1\",
|
||||
\"root\": \"/workspaces/gclient\",
|
||||
\"remotes\": {
|
||||
\"electron\": {
|
||||
@@ -49,7 +48,7 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
\"gen\": {
|
||||
\"args\": [
|
||||
\"import(\\\"//electron/build/args/testing.gn\\\")\",
|
||||
\"import(\\\"/home/builduser/.electron_build_tools/third_party/goma.gn\\\")\"
|
||||
\"use_remoteexec = true\"
|
||||
],
|
||||
\"out\": \"Testing\"
|
||||
},
|
||||
@@ -57,26 +56,18 @@ 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\",
|
||||
\"configValidationLevel\": \"strict\",
|
||||
\"reclient\": \"$1\",
|
||||
\"goma\": \"none\",
|
||||
\"preserveXcode\": 5
|
||||
}
|
||||
" >$buildtools/configs/evm.testing.json
|
||||
}
|
||||
|
||||
# Start out as cache only
|
||||
write_config cache-only
|
||||
write_config remote_exec
|
||||
|
||||
e use testing
|
||||
|
||||
# Attempt to auth to the goma service via codespaces tokens
|
||||
# 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
|
||||
e use testing
|
||||
else
|
||||
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
|
||||
|
||||
26
.github/workflows/config/evm.mas.json
vendored
Normal file
26
.github/workflows/config/evm.mas.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"root": "/Users/runner/work/electron/electron/",
|
||||
"remotes": {
|
||||
"electron": {
|
||||
"origin": "https://github.com/electron/electron.git"
|
||||
}
|
||||
},
|
||||
"gen": {
|
||||
"args": [
|
||||
"import(\"//electron/build/args/testing.gn\")",
|
||||
"use_remoteexec = true",
|
||||
"target_cpu = \"arm64\"",
|
||||
"is_mas_build = true"
|
||||
],
|
||||
"out": "Default"
|
||||
},
|
||||
"env": {
|
||||
"CHROMIUM_BUILDTOOLS_PATH": "/Users/runner/work/electron/electron/src/buildtools",
|
||||
"GIT_CACHE_PATH": "/Users/runner/work/electron/electron/.git-cache"
|
||||
},
|
||||
"$schema": "file:///home/builduser/.electron_build_tools/evm-config.schema.json",
|
||||
"configValidationLevel": "strict",
|
||||
"reclient": "remote_exec",
|
||||
"goma": "none",
|
||||
"preserveXcode": 5
|
||||
}
|
||||
14
.github/workflows/config/gclient.diff
vendored
Normal file
14
.github/workflows/config/gclient.diff
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
diff --git a/gclient.py b/gclient.py
|
||||
index 59e2b4c5197928bdba1ef69bdbe637d7dfe471c1..b4bae5e48c83c84bd867187afaf40eed16e69851 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -739,7 +739,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,
|
||||
583
.github/workflows/macos-build.yml
vendored
Normal file
583
.github/workflows/macos-build.yml
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
name: Build MacOS
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac --custom-var=host_cpu=arm64'
|
||||
IS_RELEASE: false
|
||||
# GENERATE_SYMBOLS: true only on release builds
|
||||
GENERATE_SYMBOLS: false
|
||||
AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
|
||||
AZURE_STORAGE_KEY: ${{ secrets.AZURE_STORAGE_KEY }}
|
||||
AZURE_STORAGE_CONTAINER_NAME: ${{ secrets.AZURE_STORAGE_CONTAINER_NAME }}
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
# TODO: this should be set to the correct GN_CONFIG for the build type.
|
||||
GN_CONFIG: //electron/build/args/testing.gn
|
||||
# Disable pre-compiled headers to reduce out size - only useful for rebuilds
|
||||
GN_BUILDFLAG_ARGS: 'enable_precompiled_headers = false'
|
||||
|
||||
jobs:
|
||||
checkout:
|
||||
runs-on: LargeLinuxRunner
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: src/electron
|
||||
- name: Install Azure CLI
|
||||
run: ./script/azure_cli_deb_install.sh
|
||||
- name: Set GIT_CACHE_PATH to make gclient to use the cache
|
||||
run: |
|
||||
echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV
|
||||
- name: Setup Node.js/npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20.11.x
|
||||
cache: yarn
|
||||
cache-dependency-path: src/electron/yarn.lock
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
else
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
fi
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
|
||||
- name: Check If Cache Exists
|
||||
id: check-cache
|
||||
run: |
|
||||
exists_json=$(az storage blob exists \
|
||||
--account-name $AZURE_STORAGE_ACCOUNT \
|
||||
--account-key $AZURE_STORAGE_KEY \
|
||||
--container-name $AZURE_STORAGE_CONTAINER_NAME \
|
||||
--name $DEPSHASH)
|
||||
|
||||
cache_exists=$(echo $exists_json | jq -r '.exists')
|
||||
echo "cache_exists=$cache_exists" >> $GITHUB_OUTPUT
|
||||
|
||||
if (test "$cache_exists" = "true"); then
|
||||
echo "Cache Exists for $DEPSHASH"
|
||||
else
|
||||
echo "Cache Does Not Exist for $DEPSHASH"
|
||||
fi
|
||||
- name: Gclient Sync
|
||||
# If there is no existing src cache, we need to do a full gclient sync.
|
||||
# TODO(codebytere): Add stale patch handling for non-release builds.
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
run: |
|
||||
gclient config \
|
||||
--name "src/electron" \
|
||||
--unmanaged \
|
||||
${GCLIENT_EXTRA_ARGS} \
|
||||
"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
|
||||
|
||||
ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags -vvvvv
|
||||
if [ "$IS_RELEASE" != "true" ]; then
|
||||
# Re-export all the patches to check if there were changes.
|
||||
python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
cd src/electron
|
||||
git update-index --refresh || true
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
# There are changes to the patches. Make a git commit with the updated patches
|
||||
git add patches
|
||||
GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>"
|
||||
# Export it
|
||||
mkdir -p ../../patches
|
||||
git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
|
||||
if (node ./script/push-patch.js 2> /dev/null > /dev/null); then
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch"
|
||||
echo "A new CI job will kick off shortly"
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
else
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "There were changes to the patches when applying."
|
||||
echo "Check the CI artifacts for a patch you can apply to fix it."
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# delete all .git directories under src/ except for
|
||||
# third_party/angle/ and third_party/dawn/ because of build time generation of files
|
||||
# gen/angle/commit.h depends on third_party/angle/.git/HEAD
|
||||
# https://chromium-review.googlesource.com/c/angle/angle/+/2074924
|
||||
# and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD
|
||||
# https://dawn-review.googlesource.com/c/dawn/+/83901
|
||||
# TODO: maybe better to always leave out */.git/HEAD file for all targets ?
|
||||
- name: Delete .git directories under src to free space
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
run: |
|
||||
cd src
|
||||
( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf
|
||||
- name: Minimize Cache Size for Upload
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
run: |
|
||||
rm -rf src/android_webview
|
||||
rm -rf src/ios/chrome
|
||||
rm -rf src/third_party/blink/web_tests
|
||||
rm -rf src/third_party/blink/perf_tests
|
||||
rm -rf src/chrome/test/data/xr/webvr_info
|
||||
rm -rf src/third_party/angle/third_party/VK-GL-CTS/src
|
||||
rm -rf src/third_party/swift-toolchain
|
||||
rm -rf src/third_party/swiftshader/tests/regres/testlists
|
||||
rm -rf src/electron
|
||||
- name: Compress Src Directory
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
run: |
|
||||
echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')"
|
||||
tar -cvf $DEPSHASH.tar src
|
||||
echo "Compressed src to $(du -sh $DEPSHASH.tar | cut -f1 -d' ')"
|
||||
- name: Upload Compressed Src Cache to Azure
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
run: |
|
||||
az storage blob upload \
|
||||
--account-name $AZURE_STORAGE_ACCOUNT \
|
||||
--account-key $AZURE_STORAGE_KEY \
|
||||
--container-name $AZURE_STORAGE_CONTAINER_NAME \
|
||||
--file $DEPSHASH.tar \
|
||||
--name $DEPSHASH \
|
||||
--debug
|
||||
build:
|
||||
runs-on: macos-13-xlarge
|
||||
needs: checkout
|
||||
steps:
|
||||
- name: Load Build Tools
|
||||
run: |
|
||||
yarn add git://github.com/electron/build-tools.git#2bb63e2e7877491b52f972532b52adc979a6ec2f
|
||||
e init --root=$(pwd) --out=Default testing
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: src/electron
|
||||
- name: Install Azure CLI
|
||||
run: |
|
||||
brew update && brew install azure-cli
|
||||
- name: Setup Node.js/npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20.11.x
|
||||
cache: yarn
|
||||
cache-dependency-path: src/electron/yarn.lock
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
else
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
fi
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
|
||||
- name: Download Src Cache
|
||||
# The cache will always exist here as a result of the checkout job
|
||||
# Either it was uploaded to Azure in the checkout job for this commit
|
||||
# or it was uploaded in the checkout job for a previous commit.
|
||||
run: |
|
||||
az storage blob download \
|
||||
--account-name $AZURE_STORAGE_ACCOUNT \
|
||||
--account-key $AZURE_STORAGE_KEY \
|
||||
--container-name $AZURE_STORAGE_CONTAINER_NAME \
|
||||
--name $DEPSHASH \
|
||||
--file $DEPSHASH.tar \
|
||||
- name: Unzip and Ensure Src Cache
|
||||
run: |
|
||||
echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)"
|
||||
mkdir temp-cache
|
||||
tar -xvf $DEPSHASH.tar -C temp-cache
|
||||
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
|
||||
|
||||
if [ -d "temp-cache/src" ]; then
|
||||
echo "Relocating Cache"
|
||||
rm -rf src
|
||||
mv temp-cache/src src
|
||||
|
||||
echo "Deleting zip file"
|
||||
rm -rf $DEPSHASH.tar
|
||||
fi
|
||||
|
||||
if [ ! -d "src/third_party/blink" ]; then
|
||||
echo "Cache was not correctly restored - exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Wiping Electron Directory"
|
||||
rm -rf src/electron
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: src/electron
|
||||
- name: Run Electron Only Hooks
|
||||
run: |
|
||||
echo "Running Electron Only Hooks"
|
||||
gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
|
||||
- name: Regenerate DEPS Hash
|
||||
run: |
|
||||
(cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
|
||||
- name: Add CHROMIUM_BUILDTOOLS_PATH to env
|
||||
run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
|
||||
- name: Fix Sync
|
||||
# This step is required to correct for differences between "gclient sync"
|
||||
# on Linux and the expected state on macOS. This requires:
|
||||
# 1. Fixing Clang Install (wrong binary)
|
||||
# 2. Fixing esbuild (wrong binary)
|
||||
# 3. Fixing rustc (wrong binary)
|
||||
# 4. Fixing gn (wrong binary)
|
||||
# 5. Fix reclient (wrong binary)
|
||||
# 6. Fixing dsymutil (wrong binary)
|
||||
# 7. Ensuring we are using the correct ninja and adding it to PATH
|
||||
# 8. Fixing angle (wrong remote)
|
||||
run : |
|
||||
SEDOPTION="-i ''"
|
||||
rm -rf src/third_party/llvm-build
|
||||
python3 src/tools/clang/scripts/update.py
|
||||
|
||||
echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file
|
||||
# Remove extra output from calling gclient getdep which always calls update_depot_tools
|
||||
sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file
|
||||
cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file
|
||||
|
||||
rm -rf src/third_party/rust-toolchain
|
||||
python3 src/tools/rust/update_rust.py
|
||||
|
||||
# Prevent calling gclient getdep which always calls update_depot_tools
|
||||
echo 'gn/gn/mac-${arch}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/mac:gn/gn/mac-${arch}'` > gn_ensure_file
|
||||
sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
|
||||
cipd ensure --root src/buildtools/mac -ensure-file gn_ensure_file
|
||||
|
||||
# Prevent calling gclient getdep which always calls update_depot_tools
|
||||
echo 'infra/rbe/client/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/reclient:infra/rbe/client/${platform}'` > gn_ensure_file
|
||||
sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
|
||||
cipd ensure --root src/buildtools/reclient -ensure-file gn_ensure_file
|
||||
python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch
|
||||
|
||||
DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1
|
||||
python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil
|
||||
|
||||
echo 'infra/3pp/tools/ninja/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/third_party/ninja:infra/3pp/tools/ninja/${platform}'` > ninja_ensure_file
|
||||
sed $SEDOPTION "s/Updating depot_tools... //g" ninja_ensure_file
|
||||
cipd ensure --root src/third_party/ninja -ensure-file ninja_ensure_file
|
||||
|
||||
echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH
|
||||
|
||||
cd src/third_party/angle
|
||||
rm -f .git/objects/info/alternates
|
||||
git remote set-url origin https://chromium.googlesource.com/angle/angle.git
|
||||
cp .git/config .git/config.backup
|
||||
git remote remove origin
|
||||
mv .git/config.backup .git/config
|
||||
git fetch
|
||||
- name: Install build-tools & Setup RBE
|
||||
run: |
|
||||
echo "NUMBER_OF_NINJA_PROCESSES=200" >> $GITHUB_ENV
|
||||
cd ~/.electron_build_tools
|
||||
npx yarn --ignore-engines
|
||||
# Pull down credential helper and print status
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
|
||||
$HELPER login
|
||||
echo 'RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $GITHUB_ENV
|
||||
echo 'RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $GITHUB_ENV
|
||||
echo 'RBE_experimental_credentials_helper_args=print' >> $GITHUB_ENV
|
||||
- name: Build Electron (darwin)
|
||||
run: |
|
||||
cd src/electron
|
||||
# TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
|
||||
git pack-refs
|
||||
cd ..
|
||||
|
||||
ulimit -n 10000
|
||||
sudo launchctl limit maxfiles 65536 200000
|
||||
NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
|
||||
cp out/Default/.ninja_log out/electron_ninja_log
|
||||
node electron/script/check-symlinks.js
|
||||
- name: Build Electron dist.zip (darwin)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_dist_zip $ADDITIONAL_TARGETS -j $NUMBER_OF_NINJA_PROCESSES
|
||||
if [ "$CHECK_DIST_MANIFEST" == "1" ]; then
|
||||
target_os=mac
|
||||
target_cpu=arm64
|
||||
electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.$target_cpu.manifest
|
||||
fi
|
||||
- name: Build Mksnapshot (darwin)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
|
||||
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
# Remove unused args from mksnapshot_args
|
||||
SEDOPTION="-i ''"
|
||||
sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
|
||||
if [ "$SKIP_DIST_ZIP" != "1" ]; then
|
||||
e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
(cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
|
||||
fi
|
||||
- name: Build Chromedriver (darwin)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
|
||||
e build electron:electron_chromedriver_zip
|
||||
- name: Build Node Headers (darwin)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:node_headers
|
||||
- name: Generate & Zip Symbols (darwin)
|
||||
run: |
|
||||
if [ "$GENERATE_SYMBOLS" == "true" ]; then
|
||||
e build electron:electron_symbols
|
||||
fi
|
||||
cd src
|
||||
export BUILD_PATH="$(pwd)/out/Default"
|
||||
e build electron:licenses
|
||||
e build electron:electron_version_file
|
||||
electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
# TODO(vertedinde): handle creating ffmpeg and hunspell for release builds
|
||||
# The current generated_artifacts_<< artifact.key >> name was taken from CircleCI
|
||||
# tp ensure we don't break anything, but we may be able to improve that.
|
||||
- name: Move all Generated Artifacts to Upload Folder
|
||||
run: ./src/electron/script/actions/move-artifacts.sh
|
||||
- name: Upload Generated Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: generated_artifacts_darwin
|
||||
path: ./generated_artifacts_darwin
|
||||
- name: Persist Build Artifacts
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
src/out/Default/gen/node_headers
|
||||
src/out/Default/overlapped-checker
|
||||
src/electron
|
||||
src/third_party/electron_node
|
||||
src/third_party/nan
|
||||
src/cross-arch-snapshots
|
||||
src/third_party/llvm-build
|
||||
src/build/linux
|
||||
src/buildtools/mac
|
||||
src/buildtools/third_party/libc++
|
||||
src/buildtools/third_party/libc++abi
|
||||
src/third_party/libc++
|
||||
src/third_party/libc++abi
|
||||
src/out/Default/obj/buildtools/third_party
|
||||
src/v8/tools/builtins-pgo
|
||||
key: ${{ runner.os }}-build-artifacts-darwin-${{ github.sha }}
|
||||
- name: Create MAS Config
|
||||
run: |
|
||||
mv src/electron/.github/workflows/config/evm.mas.json $HOME/.electron_build_tools/configs/evm.mas.json
|
||||
echo "MAS_BUILD=true" >> $GITHUB_ENV
|
||||
e use mas
|
||||
- name: Build Electron (mas)
|
||||
run: |
|
||||
rm -rf "src/out/Default/Electron Framework.framework"
|
||||
rm -rf src/out/Default/Electron*.app
|
||||
|
||||
cd src/electron
|
||||
# TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
|
||||
git pack-refs
|
||||
cd ..
|
||||
|
||||
ulimit -n 10000
|
||||
sudo launchctl limit maxfiles 65536 200000
|
||||
NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
|
||||
cp out/Default/.ninja_log out/electron_ninja_log
|
||||
node electron/script/check-symlinks.js
|
||||
- name: Build Electron dist.zip (mas)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_dist_zip $ADDITIONAL_TARGETS -j $NUMBER_OF_NINJA_PROCESSES
|
||||
if [ "$CHECK_DIST_MANIFEST" == "1" ]; then
|
||||
target_os=mac_mas
|
||||
target_cpu=arm64
|
||||
electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.$target_cpu.manifest
|
||||
fi
|
||||
- name: Build Mksnapshot (mas)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
|
||||
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
# Remove unused args from mksnapshot_args
|
||||
SEDOPTION="-i ''"
|
||||
sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
|
||||
if [ "$SKIP_DIST_ZIP" != "1" ]; then
|
||||
e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
(cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
|
||||
fi
|
||||
- name: Build Chromedriver (mas)
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
|
||||
e build electron:electron_chromedriver_zip
|
||||
- name: Build Node Headers
|
||||
run: |
|
||||
cd src
|
||||
e build electron:node_headers
|
||||
- name: Generate & Zip Symbols (mas)
|
||||
run: |
|
||||
if [ "$GENERATE_SYMBOLS" == "true" ]; then
|
||||
e build electron:electron_symbols
|
||||
fi
|
||||
cd src
|
||||
export BUILD_PATH="$(pwd)/out/Default"
|
||||
e build electron:licenses
|
||||
e build electron:electron_version_file
|
||||
electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
- name: Move all Generated Artifacts to Upload Folder (mas)
|
||||
run: ./src/electron/script/actions/move-artifacts.sh
|
||||
- name: Upload Generated Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: generated_artifacts_mas
|
||||
path: ./generated_artifacts_mas
|
||||
- name: Persist Build Artifacts
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
src/out/Default/gen/node_headers
|
||||
src/out/Default/overlapped-checker
|
||||
src/electron
|
||||
src/third_party/electron_node
|
||||
src/third_party/nan
|
||||
src/cross-arch-snapshots
|
||||
src/third_party/llvm-build
|
||||
src/build/linux
|
||||
src/buildtools/mac
|
||||
src/buildtools/third_party/libc++
|
||||
src/buildtools/third_party/libc++abi
|
||||
src/third_party/libc++
|
||||
src/third_party/libc++abi
|
||||
src/out/Default/obj/buildtools/third_party
|
||||
src/v8/tools/builtins-pgo
|
||||
key: ${{ runner.os }}-build-artifacts-mas-${{ github.sha }}
|
||||
test:
|
||||
runs-on: macos-13-xlarge
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build-type: [darwin, mas]
|
||||
env:
|
||||
BUILD_TYPE: ${{ matrix.build-type }}
|
||||
steps:
|
||||
- name: Load Build Tools
|
||||
run: |
|
||||
yarn add git://github.com/electron/build-tools.git#2bb63e2e7877491b52f972532b52adc979a6ec2f
|
||||
e init --root=$(pwd) --out=Default testing
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: src/electron
|
||||
- name: Setup Node.js/npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20.11.x
|
||||
cache: yarn
|
||||
cache-dependency-path: src/electron/yarn.lock
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
else
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
fi
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: generated_artifacts_${{ matrix.build-type }}
|
||||
path: ./generated_artifacts_${{ matrix.build-type }}
|
||||
- name: Restore Persisted Build Artifacts
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
src/out/Default/gen/node_headers
|
||||
src/out/Default/overlapped-checker
|
||||
src/electron
|
||||
src/third_party/electron_node
|
||||
src/third_party/nan
|
||||
src/cross-arch-snapshots
|
||||
src/third_party/llvm-build
|
||||
src/build/linux
|
||||
src/buildtools/mac
|
||||
src/buildtools/third_party/libc++
|
||||
src/buildtools/third_party/libc++abi
|
||||
src/third_party/libc++
|
||||
src/third_party/libc++abi
|
||||
src/out/Default/obj/buildtools/third_party
|
||||
src/v8/tools/builtins-pgo
|
||||
key: ${{ runner.os }}-build-artifacts-${{ matrix.build-type }}-${{ github.sha }}
|
||||
- name: Restore Generated Artifacts
|
||||
run: ./src/electron/script/actions/restore-artifacts.sh
|
||||
- name: Unzip Dist, Mksnapshot & Chromedriver
|
||||
run: |
|
||||
cd src/out/Default
|
||||
unzip -:o dist.zip
|
||||
unzip -:o chromedriver.zip
|
||||
unzip -:o mksnapshot.zip
|
||||
- name: Run Electron Tests
|
||||
env:
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn test --runners=main --trace-uncaught --enable-logging
|
||||
@@ -50,10 +50,6 @@ is_cfi = false
|
||||
# TODO: fix this once sysroots have been updated.
|
||||
use_qt = false
|
||||
|
||||
# https://chromium-review.googlesource.com/c/chromium/src/+/4365718
|
||||
# TODO(codebytere): fix perfetto incompatibility with Node.js.
|
||||
use_perfetto_client_library = false
|
||||
|
||||
# Disables the builtins PGO for V8
|
||||
v8_builtins_profiling_log_file = ""
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ dialog.showOpenDialog(mainWindow, {
|
||||
* `dontAddToRecent` _Windows_ - Do not add the item being saved to the recent documents list.
|
||||
* `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path.
|
||||
|
||||
Returns `string | undefined`, the path of the file chosen by the user; if the dialog is cancelled it returns `undefined`.
|
||||
Returns `string`, the path of the file chosen by the user; if the dialog is cancelled it returns an empty string.
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
@@ -207,7 +207,7 @@ The `filters` specifies an array of file types that can be displayed, see
|
||||
Returns `Promise<Object>` - Resolve with an object containing the following:
|
||||
|
||||
* `canceled` boolean - whether or not the dialog was canceled.
|
||||
* `filePath` string (optional) - If the dialog is canceled, this will be `undefined`.
|
||||
* `filePath` string - If the dialog is canceled, this will be an empty string.
|
||||
* `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).)
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
@@ -110,22 +110,51 @@ $ export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools
|
||||
On Windows:
|
||||
|
||||
```sh
|
||||
# cmd
|
||||
$ cd src
|
||||
$ set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools
|
||||
|
||||
# PowerShell
|
||||
$ cd src
|
||||
$ $env:CHROMIUM_BUILDTOOLS_PATH = "$(Get-Location)\buildtools"
|
||||
```
|
||||
|
||||
**To generate Testing build config of Electron:**
|
||||
|
||||
On Linux & MacOS
|
||||
|
||||
```sh
|
||||
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")"
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```sh
|
||||
# cmd
|
||||
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")"
|
||||
|
||||
# PowerShell
|
||||
gn gen out/Testing --args="import(\`"//electron/build/args/testing.gn\`")"
|
||||
```
|
||||
|
||||
**To generate Release build config of Electron:**
|
||||
|
||||
On Linux & MacOS
|
||||
|
||||
```sh
|
||||
$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")"
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```sh
|
||||
# cmd
|
||||
$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")"
|
||||
|
||||
# PowerShell
|
||||
$ gn gen out/Release --args="import(\`"//electron/build/args/release.gn\`")"
|
||||
```
|
||||
|
||||
**Note:** This will generate a `out/Testing` or `out/Release` build directory under `src/` with the testing or release build depending upon the configuration passed above. You can replace `Testing|Release` with another names, but it should be a subdirectory of `out`.
|
||||
|
||||
Also you shouldn't have to run `gn gen` again—if you want to change the build arguments, you can run `gn args out/Testing` to bring up an editor. To see the list of available build configuration options, run `gn args out/Testing --list`.
|
||||
|
||||
@@ -152,7 +152,7 @@ command that can handle the version bumping and tagging for you.
|
||||
#### Bonus: Publishing in GitHub Actions
|
||||
|
||||
Publishing locally can be painful, especially because you can only create distributables
|
||||
for your host operating system (i.e. you can't publish a Window `.exe` file from macOS).
|
||||
for your host operating system (i.e. you can't publish a Windows `.exe` file from macOS).
|
||||
|
||||
A solution for this would be to publish your app via automation workflows
|
||||
such as [GitHub Actions][], which can run tasks in the
|
||||
|
||||
@@ -36,6 +36,29 @@ BrowserWindow.prototype._init = function (this: BWT) {
|
||||
app.emit('browser-window-focus', event, this);
|
||||
});
|
||||
|
||||
let unresponsiveEvent: NodeJS.Timeout | null = null;
|
||||
const emitUnresponsiveEvent = () => {
|
||||
unresponsiveEvent = null;
|
||||
if (!this.isDestroyed() && this.isEnabled()) { this.emit('unresponsive'); }
|
||||
};
|
||||
this.webContents.on('unresponsive', () => {
|
||||
if (!unresponsiveEvent) { unresponsiveEvent = setTimeout(emitUnresponsiveEvent, 50); }
|
||||
});
|
||||
this.webContents.on('responsive', () => {
|
||||
if (unresponsiveEvent) {
|
||||
clearTimeout(unresponsiveEvent);
|
||||
unresponsiveEvent = null;
|
||||
}
|
||||
this.emit('responsive');
|
||||
});
|
||||
this.on('close', () => {
|
||||
if (!unresponsiveEvent) { unresponsiveEvent = setTimeout(emitUnresponsiveEvent, 5000); }
|
||||
});
|
||||
this.webContents.on('destroyed', () => {
|
||||
if (unresponsiveEvent) clearTimeout(unresponsiveEvent);
|
||||
unresponsiveEvent = null;
|
||||
});
|
||||
|
||||
// Subscribe to visibilityState changes and pass to renderer process.
|
||||
let isVisible = this.isVisible() && !this.isMinimized();
|
||||
const visibilityChanged = () => {
|
||||
|
||||
@@ -18,7 +18,7 @@ function makeStreamFromPipe (pipe: any): ReadableStream {
|
||||
try {
|
||||
const rv = await pipe.read(buf);
|
||||
if (rv > 0) {
|
||||
controller.enqueue(buf.subarray(0, rv));
|
||||
controller.enqueue(buf.slice(0, rv));
|
||||
} else {
|
||||
controller.close();
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ crash_allow_setting_more_options.patch
|
||||
upload_list_add_loadsync_method.patch
|
||||
allow_setting_secondary_label_via_simplemenumodel.patch
|
||||
feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch
|
||||
fix_patch_out_profile_refs_in_accessibility_ui.patch
|
||||
adjust_accessibility_ui_for_electron.patch
|
||||
skip_atk_toolchain_check.patch
|
||||
worker_feat_add_hook_to_notify_script_ready.patch
|
||||
chore_provide_iswebcontentscreationoverridden_with_full_params.patch
|
||||
|
||||
@@ -1,47 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 6 Jul 2020 13:46:06 -0700
|
||||
Subject: fix: patch out Profile refs in accessibility_ui
|
||||
Subject: Adjust accessibility_ui for Electron
|
||||
|
||||
This tweaks Chrome's Accessibility support at chrome://accessibility
|
||||
to make it usable from Electron by removing Profile references.
|
||||
to make it usable from Electron by replacing use of the Profile PrefService
|
||||
with Electron's own PrefService in ElectronBrowserContext. It also removes
|
||||
usage of BrowserList and Browser as we subclass related methods and use our
|
||||
WindowList.
|
||||
|
||||
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
|
||||
index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3086e8794 100644
|
||||
index 45b085ebb5096b2cdd083337371539a249c7a0a8..9a0a6cb8b37c60641c2c51aa489fbf22cdb123cb 100644
|
||||
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
|
||||
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
|
||||
@@ -23,7 +23,10 @@
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#if 0
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
+#endif
|
||||
+#include "chrome/common/chrome_features.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "chrome/grit/accessibility_resources.h"
|
||||
@@ -33,6 +36,7 @@
|
||||
#include "content/public/browser/ax_event_notification_details.h"
|
||||
#include "content/public/browser/ax_inspect_factory.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
+#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/favicon_status.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
@@ -52,9 +56,11 @@
|
||||
#include "ui/views/accessibility/view_accessibility.h"
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
+#if 0
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_list.h"
|
||||
#include "chrome/browser/ui/browser_window.h"
|
||||
+#endif
|
||||
#include "ui/views/accessibility/widget_ax_tree_id_map.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
@@ -169,7 +175,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) {
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_ui_data_source.h"
|
||||
+#include "electron/shell/browser/electron_browser_context.h"
|
||||
#include "ui/accessibility/accessibility_features.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
|
||||
@@ -169,7 +170,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) {
|
||||
accessibility_mode);
|
||||
}
|
||||
|
||||
@@ -50,27 +30,25 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
base::Value::Dict BuildTargetDescriptor(Browser* browser) {
|
||||
base::Value::Dict target_data;
|
||||
target_data.Set(kSessionIdField, browser->session_id().id());
|
||||
@@ -203,7 +209,9 @@ void HandleAccessibilityRequestCallback(
|
||||
@@ -203,7 +204,7 @@ void HandleAccessibilityRequestCallback(
|
||||
DCHECK(ShouldHandleAccessibilityRequestCallback(path));
|
||||
|
||||
base::Value::Dict data;
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromBrowserContext(current_context)->GetPrefs();
|
||||
+#endif
|
||||
- PrefService* pref = Profile::FromBrowserContext(current_context)->GetPrefs();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(current_context)->prefs();
|
||||
ui::AXMode mode =
|
||||
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
|
||||
bool is_native_enabled = content::BrowserAccessibilityState::GetInstance()
|
||||
@@ -235,8 +243,7 @@ void HandleAccessibilityRequestCallback(
|
||||
// enabled.
|
||||
@@ -236,7 +237,7 @@ void HandleAccessibilityRequestCallback(
|
||||
data.Set(kViewsAccessibility, features::IsAccessibilityTreeForViewsEnabled());
|
||||
|
||||
- std::string pref_api_type =
|
||||
std::string pref_api_type =
|
||||
- pref->GetString(prefs::kShownAccessibilityApiType);
|
||||
+ std::string pref_api_type = "blink";
|
||||
+ std::string(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
bool pref_api_type_supported = false;
|
||||
|
||||
std::vector<ui::AXApiType::Type> supported_api_types =
|
||||
@@ -303,11 +310,11 @@ void HandleAccessibilityRequestCallback(
|
||||
@@ -303,11 +304,11 @@ void HandleAccessibilityRequestCallback(
|
||||
data.Set(kPagesField, std::move(page_list));
|
||||
|
||||
base::Value::List browser_list;
|
||||
@@ -80,36 +58,31 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
browser_list.Append(BuildTargetDescriptor(browser));
|
||||
}
|
||||
-#endif // !BUILDFLAG(IS_ANDROID)
|
||||
+#endif // !BUILDFLAG(IS_ANDROID)
|
||||
+#endif
|
||||
data.Set(kBrowsersField, std::move(browser_list));
|
||||
|
||||
base::Value::List widgets_list;
|
||||
@@ -647,8 +654,10 @@ void AccessibilityUIMessageHandler::SetGlobalString(
|
||||
@@ -647,7 +648,8 @@ void AccessibilityUIMessageHandler::SetGlobalString(
|
||||
const std::string value = CheckJSValue(data.FindString(kValueField));
|
||||
|
||||
if (string_name == kApiTypeField) {
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(
|
||||
+ web_ui()->GetWebContents()->GetBrowserContext())->prefs();
|
||||
pref->SetString(prefs::kShownAccessibilityApiType, value);
|
||||
+#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,9 +709,13 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree(
|
||||
@@ -700,7 +702,8 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree(
|
||||
AXPropertyFilter::ALLOW_EMPTY);
|
||||
AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY);
|
||||
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(
|
||||
+ web_contents->GetBrowserContext())->prefs();
|
||||
ui::AXApiType::Type api_type =
|
||||
ui::AXApiType::From(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
+#else
|
||||
+ ui::AXApiType::Type api_type = ui::AXApiType::kBlink;
|
||||
+#endif
|
||||
std::string accessibility_contents =
|
||||
web_contents->DumpAccessibilityTree(api_type, property_filters);
|
||||
result.Set(kTreeField, accessibility_contents);
|
||||
@@ -727,6 +740,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
@@ -727,6 +730,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
AXPropertyFilter::ALLOW_EMPTY);
|
||||
AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY);
|
||||
|
||||
@@ -117,7 +90,7 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
for (Browser* browser : *BrowserList::GetInstance()) {
|
||||
if (browser->session_id().id() == session_id) {
|
||||
base::Value::Dict result = BuildTargetDescriptor(browser);
|
||||
@@ -739,6 +753,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
@@ -739,6 +743,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -125,25 +98,24 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
// No browser with the specified |session_id| was found.
|
||||
base::Value::Dict result;
|
||||
@@ -807,11 +822,15 @@ void AccessibilityUIMessageHandler::StopRecording(
|
||||
@@ -807,11 +812,13 @@ void AccessibilityUIMessageHandler::StopRecording(
|
||||
}
|
||||
|
||||
ui::AXApiType::Type AccessibilityUIMessageHandler::GetRecordingApiType() {
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- const std::vector<ui::AXApiType::Type> supported_types =
|
||||
- content::AXInspectFactory::SupportedApis();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(
|
||||
+ web_ui()->GetWebContents()->GetBrowserContext())->prefs();
|
||||
ui::AXApiType::Type api_type =
|
||||
ui::AXApiType::From(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
+#else
|
||||
+ ui::AXApiType::Type api_type = ui::AXApiType::kBlink;
|
||||
+#endif
|
||||
+
|
||||
+ const std::vector<ui::AXApiType::Type> supported_types =
|
||||
+ content::AXInspectFactory::SupportedApis();
|
||||
// Check to see if it is in the supported types list.
|
||||
if (std::find(supported_types.begin(), supported_types.end(), api_type) ==
|
||||
supported_types.end()) {
|
||||
@@ -881,8 +900,11 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
|
||||
@@ -881,8 +888,11 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
|
||||
// static
|
||||
void AccessibilityUIMessageHandler::RegisterProfilePrefs(
|
||||
user_prefs::PrefRegistrySyncable* registry) {
|
||||
@@ -45,3 +45,4 @@ fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
|
||||
src_preload_function_for_environment.patch
|
||||
deprecate_vector_v8_local_in_v8.patch
|
||||
fix_remove_deprecated_errno_constants.patch
|
||||
build_enable_perfetto.patch
|
||||
|
||||
370
patches/node/build_enable_perfetto.patch
Normal file
370
patches/node/build_enable_perfetto.patch
Normal file
@@ -0,0 +1,370 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Wed, 17 Apr 2024 08:17:49 -0400
|
||||
Subject: build: enable perfetto
|
||||
|
||||
Enable perfetto by default in Node.js. Node.js disables perfetto by
|
||||
default but is broken on build - they don't currently add guards for
|
||||
`V8_USE_PERFETTO` and upstream only defines certain functions
|
||||
on `v8::TracingController` if perfetto is disabled. Electron already
|
||||
had minimal to no support for Node.js trace events, so the impact of
|
||||
adding associated guards there should be relatively small.
|
||||
|
||||
We should upstream this as it will eventually impact Node.js as well.
|
||||
|
||||
diff --git a/lib/internal/constants.js b/lib/internal/constants.js
|
||||
index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b564ef600 100644
|
||||
--- a/lib/internal/constants.js
|
||||
+++ b/lib/internal/constants.js
|
||||
@@ -5,12 +5,15 @@ const isWindows = process.platform === 'win32';
|
||||
module.exports = {
|
||||
// Alphabet chars.
|
||||
CHAR_UPPERCASE_A: 65, /* A */
|
||||
+ CHAR_UPPERCASE_B: 66, /* B */
|
||||
CHAR_LOWERCASE_A: 97, /* a */
|
||||
CHAR_UPPERCASE_Z: 90, /* Z */
|
||||
CHAR_LOWERCASE_Z: 122, /* z */
|
||||
CHAR_UPPERCASE_C: 67, /* C */
|
||||
CHAR_LOWERCASE_B: 98, /* b */
|
||||
+ CHAR_UPPERCASE_E: 69, /* E */
|
||||
CHAR_LOWERCASE_E: 101, /* e */
|
||||
+
|
||||
CHAR_LOWERCASE_N: 110, /* n */
|
||||
|
||||
// Non-alphabetic chars.
|
||||
diff --git a/lib/internal/http.js b/lib/internal/http.js
|
||||
index b20b3cd229efcd9701791309361b7d106f315900..6b2820c9dcce5e658b694f53e75d93707c4320d7 100644
|
||||
--- a/lib/internal/http.js
|
||||
+++ b/lib/internal/http.js
|
||||
@@ -10,8 +10,8 @@ const {
|
||||
const { setUnrefTimeout } = require('internal/timers');
|
||||
const { trace, isTraceCategoryEnabled } = internalBinding('trace_events');
|
||||
const {
|
||||
- CHAR_LOWERCASE_B,
|
||||
- CHAR_LOWERCASE_E,
|
||||
+ CHAR_UPPERCASE_B,
|
||||
+ CHAR_UPPERCASE_E,
|
||||
} = require('internal/constants');
|
||||
|
||||
let utcCache;
|
||||
@@ -44,11 +44,13 @@ function isTraceHTTPEnabled() {
|
||||
const traceEventCategory = 'node,node.http';
|
||||
|
||||
function traceBegin(...args) {
|
||||
- trace(CHAR_LOWERCASE_B, traceEventCategory, ...args);
|
||||
+ // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
|
||||
+ trace(CHAR_UPPERCASE_B, traceEventCategory, ...args);
|
||||
}
|
||||
|
||||
function traceEnd(...args) {
|
||||
- trace(CHAR_LOWERCASE_E, traceEventCategory, ...args);
|
||||
+ // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
|
||||
+ trace(CHAR_UPPERCASE_E, traceEventCategory, ...args);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc
|
||||
index 7ce59674356f9743438350949be42fa7ead2afbe..c5fedc3be86a77730c57321b9c73cc8e94a001d7 100644
|
||||
--- a/src/tracing/agent.cc
|
||||
+++ b/src/tracing/agent.cc
|
||||
@@ -50,7 +50,9 @@ using v8::platform::tracing::TraceWriter;
|
||||
using std::string;
|
||||
|
||||
Agent::Agent() : tracing_controller_(new TracingController()) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
tracing_controller_->Initialize(nullptr);
|
||||
+#endif
|
||||
|
||||
CHECK_EQ(uv_loop_init(&tracing_loop_), 0);
|
||||
CHECK_EQ(uv_async_init(&tracing_loop_,
|
||||
@@ -86,10 +88,14 @@ Agent::~Agent() {
|
||||
void Agent::Start() {
|
||||
if (started_)
|
||||
return;
|
||||
-
|
||||
+#ifdef V8_USE_PERFETTO
|
||||
+ std::ostringstream perfetto_output;
|
||||
+ tracing_controller_->InitializeForPerfetto(&perfetto_output);
|
||||
+#else
|
||||
NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer(
|
||||
NodeTraceBuffer::kBufferChunks, this, &tracing_loop_);
|
||||
tracing_controller_->Initialize(trace_buffer_);
|
||||
+#endif
|
||||
|
||||
// This thread should be created *after* async handles are created
|
||||
// (within NodeTraceWriter and NodeTraceBuffer constructors).
|
||||
@@ -143,8 +149,10 @@ void Agent::StopTracing() {
|
||||
return;
|
||||
// Perform final Flush on TraceBuffer. We don't want the tracing controller
|
||||
// to flush the buffer again on destruction of the V8::Platform.
|
||||
- tracing_controller_->StopTracing();
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
tracing_controller_->Initialize(nullptr);
|
||||
+#endif
|
||||
+ tracing_controller_->StopTracing();
|
||||
started_ = false;
|
||||
|
||||
// Thread should finish when the tracing loop is stopped.
|
||||
@@ -202,6 +210,7 @@ std::string Agent::GetEnabledCategories() const {
|
||||
return categories;
|
||||
}
|
||||
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void Agent::AppendTraceEvent(TraceObject* trace_event) {
|
||||
for (const auto& id_writer : writers_)
|
||||
id_writer.second->AppendTraceEvent(trace_event);
|
||||
@@ -211,18 +220,21 @@ void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) {
|
||||
Mutex::ScopedLock lock(metadata_events_mutex_);
|
||||
metadata_events_.push_back(std::move(event));
|
||||
}
|
||||
+#endif
|
||||
|
||||
void Agent::Flush(bool blocking) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
{
|
||||
Mutex::ScopedLock lock(metadata_events_mutex_);
|
||||
for (const auto& event : metadata_events_)
|
||||
AppendTraceEvent(event.get());
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
for (const auto& id_writer : writers_)
|
||||
id_writer.second->Flush(blocking);
|
||||
}
|
||||
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void TracingController::AddMetadataEvent(
|
||||
const unsigned char* category_group_enabled,
|
||||
const char* name,
|
||||
@@ -246,6 +258,6 @@ void TracingController::AddMetadataEvent(
|
||||
if (node_agent != nullptr)
|
||||
node_agent->AddMetadataEvent(std::move(trace_event));
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
} // namespace tracing
|
||||
} // namespace node
|
||||
diff --git a/src/tracing/agent.h b/src/tracing/agent.h
|
||||
index b542a849fe8da7e8bbbcca7067b73dc32b18d6d3..059ce6f6ea17199ead09c6c13bcc680f18f8c4d0 100644
|
||||
--- a/src/tracing/agent.h
|
||||
+++ b/src/tracing/agent.h
|
||||
@@ -27,7 +27,9 @@ class Agent;
|
||||
class AsyncTraceWriter {
|
||||
public:
|
||||
virtual ~AsyncTraceWriter() = default;
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
|
||||
+#endif
|
||||
virtual void Flush(bool blocking) = 0;
|
||||
virtual void InitializeOnThread(uv_loop_t* loop) {}
|
||||
};
|
||||
@@ -36,6 +38,7 @@ class TracingController : public v8::platform::tracing::TracingController {
|
||||
public:
|
||||
TracingController() : v8::platform::tracing::TracingController() {}
|
||||
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
int64_t CurrentTimestampMicroseconds() override {
|
||||
return uv_hrtime() / 1000;
|
||||
}
|
||||
@@ -48,6 +51,7 @@ class TracingController : public v8::platform::tracing::TracingController {
|
||||
const uint64_t* arg_values,
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values,
|
||||
unsigned int flags);
|
||||
+#endif
|
||||
};
|
||||
|
||||
class AgentWriterHandle {
|
||||
@@ -108,11 +112,12 @@ class Agent {
|
||||
|
||||
// Returns a comma-separated list of enabled categories.
|
||||
std::string GetEnabledCategories() const;
|
||||
-
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
// Writes to all writers registered through AddClient().
|
||||
void AppendTraceEvent(TraceObject* trace_event);
|
||||
|
||||
void AddMetadataEvent(std::unique_ptr<TraceObject> event);
|
||||
+#endif
|
||||
// Flushes all writers registered through AddClient().
|
||||
void Flush(bool blocking);
|
||||
|
||||
@@ -152,7 +157,9 @@ class Agent {
|
||||
std::set<AsyncTraceWriter*> to_be_initialized_;
|
||||
|
||||
Mutex metadata_events_mutex_;
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::list<std::unique_ptr<TraceObject>> metadata_events_;
|
||||
+#endif
|
||||
};
|
||||
|
||||
void AgentWriterHandle::reset() {
|
||||
diff --git a/src/tracing/node_trace_buffer.cc b/src/tracing/node_trace_buffer.cc
|
||||
index e187a1d78c81972b69cd4e03f7079cdb727956ad..3256c6326a08c6cafd83f1e49e3350193e813b51 100644
|
||||
--- a/src/tracing/node_trace_buffer.cc
|
||||
+++ b/src/tracing/node_trace_buffer.cc
|
||||
@@ -55,6 +55,7 @@ TraceObject* InternalTraceBuffer::GetEventByHandle(uint64_t handle) {
|
||||
}
|
||||
|
||||
void InternalTraceBuffer::Flush(bool blocking) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
{
|
||||
Mutex::ScopedLock scoped_lock(mutex_);
|
||||
if (total_chunks_ > 0) {
|
||||
@@ -75,6 +76,7 @@ void InternalTraceBuffer::Flush(bool blocking) {
|
||||
flushing_ = false;
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
agent_->Flush(blocking);
|
||||
}
|
||||
|
||||
diff --git a/src/tracing/node_trace_writer.cc b/src/tracing/node_trace_writer.cc
|
||||
index 8f053efe93324b9acbb4e85f7b974b4f7712e200..e331ed5567caa39ade90ce28cea69f1d10533812 100644
|
||||
--- a/src/tracing/node_trace_writer.cc
|
||||
+++ b/src/tracing/node_trace_writer.cc
|
||||
@@ -95,7 +95,7 @@ void NodeTraceWriter::OpenNewFileForStreaming() {
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
-
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
|
||||
Mutex::ScopedLock scoped_lock(stream_mutex_);
|
||||
// If this is the first trace event, open a new file for streaming.
|
||||
@@ -112,7 +112,7 @@ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
|
||||
++total_traces_;
|
||||
json_trace_writer_->AppendTraceEvent(trace_event);
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
void NodeTraceWriter::FlushPrivate() {
|
||||
std::string str;
|
||||
int highest_request_id;
|
||||
diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h
|
||||
index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196ddfd15c26 100644
|
||||
--- a/src/tracing/node_trace_writer.h
|
||||
+++ b/src/tracing/node_trace_writer.h
|
||||
@@ -20,7 +20,9 @@ class NodeTraceWriter : public AsyncTraceWriter {
|
||||
~NodeTraceWriter() override;
|
||||
|
||||
void InitializeOnThread(uv_loop_t* loop) override;
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void AppendTraceEvent(TraceObject* trace_event) override;
|
||||
+#endif
|
||||
void Flush(bool blocking) override;
|
||||
|
||||
static const int kTracesPerFile = 1 << 19;
|
||||
diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h
|
||||
index be0f55a409a71bf9c1763c36fdc252857228742e..827b5330b2f8c545338a46c548f8abf4aab7f50c 100644
|
||||
--- a/src/tracing/trace_event.h
|
||||
+++ b/src/tracing/trace_event.h
|
||||
@@ -69,8 +69,16 @@ enum CategoryGroupEnabledFlags {
|
||||
// for best performance when tracing is disabled.
|
||||
// const uint8_t*
|
||||
// TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
|
||||
node::tracing::TraceEventHelper::GetCategoryGroupEnabled
|
||||
+#else
|
||||
+#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group) \
|
||||
+ ([](const char*) -> const uint8_t* { \
|
||||
+ static uint8_t no = 0; \
|
||||
+ return &no; \
|
||||
+ })(category_group)
|
||||
+#endif
|
||||
|
||||
// Get the number of times traces have been recorded. This is used to implement
|
||||
// the TRACE_EVENT_IS_NEW_TRACE facility.
|
||||
@@ -114,10 +122,15 @@ enum CategoryGroupEnabledFlags {
|
||||
// const uint8_t* category_group_enabled,
|
||||
// const char* name,
|
||||
// uint64_t id)
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
|
||||
if (auto controller = \
|
||||
node::tracing::TraceEventHelper::GetTracingController()) \
|
||||
controller->UpdateTraceEventDuration
|
||||
+#else
|
||||
+#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled, name, event_handle) \
|
||||
+ (void)(category_group_enabled), (void)(name), (void)(event_handle)
|
||||
+#endif
|
||||
|
||||
// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
|
||||
// on the convertable value will be called at flush time.
|
||||
@@ -319,10 +332,13 @@ class TraceEventHelper {
|
||||
static void SetAgent(Agent* agent);
|
||||
|
||||
static inline const uint8_t* GetCategoryGroupEnabled(const char* group) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
v8::TracingController* controller = GetTracingController();
|
||||
static const uint8_t disabled = 0;
|
||||
if (UNLIKELY(controller == nullptr)) return &disabled;
|
||||
return controller->GetCategoryGroupEnabled(group);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -460,6 +476,7 @@ static inline uint64_t AddTraceEventImpl(
|
||||
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
|
||||
const char** arg_names, const uint8_t* arg_types,
|
||||
const uint64_t* arg_values, unsigned int flags) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -469,13 +486,14 @@ static inline uint64_t AddTraceEventImpl(
|
||||
arg_convertibles[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
static_cast<intptr_t>(arg_values[1])));
|
||||
}
|
||||
- // DCHECK(num_args, 2);
|
||||
v8::TracingController* controller =
|
||||
node::tracing::TraceEventHelper::GetTracingController();
|
||||
if (controller == nullptr) return 0;
|
||||
return controller->AddTraceEvent(phase, category_group_enabled, name, scope, id,
|
||||
bind_id, num_args, arg_names, arg_types,
|
||||
arg_values, arg_convertibles, flags);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
@@ -483,6 +501,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
|
||||
const char** arg_names, const uint8_t* arg_types,
|
||||
const uint64_t* arg_values, unsigned int flags, int64_t timestamp) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertables[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertables[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -492,19 +511,21 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
arg_convertables[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
static_cast<intptr_t>(arg_values[1])));
|
||||
}
|
||||
- // DCHECK_LE(num_args, 2);
|
||||
v8::TracingController* controller =
|
||||
node::tracing::TraceEventHelper::GetTracingController();
|
||||
if (controller == nullptr) return 0;
|
||||
return controller->AddTraceEventWithTimestamp(
|
||||
phase, category_group_enabled, name, scope, id, bind_id, num_args,
|
||||
arg_names, arg_types, arg_values, arg_convertables, flags, timestamp);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static V8_INLINE void AddMetadataEventImpl(
|
||||
const uint8_t* category_group_enabled, const char* name, int32_t num_args,
|
||||
const char** arg_names, const uint8_t* arg_types,
|
||||
const uint64_t* arg_values, unsigned int flags) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -520,6 +541,7 @@ static V8_INLINE void AddMetadataEventImpl(
|
||||
return agent->GetTracingController()->AddMetadataEvent(
|
||||
category_group_enabled, name, num_args, arg_names, arg_types, arg_values,
|
||||
arg_convertibles, flags);
|
||||
+#endif
|
||||
}
|
||||
|
||||
// Define SetTraceValue for each allowed type. It stores the type and
|
||||
40
script/actions/move-artifacts.sh
Executable file
40
script/actions/move-artifacts.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if [ -z "$MAS_BUILD" ]; then
|
||||
BUILD_TYPE="darwin"
|
||||
else
|
||||
BUILD_TYPE="mas"
|
||||
fi
|
||||
|
||||
rm -rf generated_artifacts_${BUILD_TYPE}
|
||||
mkdir generated_artifacts_${BUILD_TYPE}
|
||||
|
||||
mv_if_exist() {
|
||||
if [ -f "$1" ] || [ -d "$1" ]; then
|
||||
echo Storing $1
|
||||
mv $1 generated_artifacts_${BUILD_TYPE}
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
cp_if_exist() {
|
||||
if [ -f "$1" ] || [ -d "$1" ]; then
|
||||
echo Storing $1
|
||||
cp $1 generated_artifacts_${BUILD_TYPE}
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
|
||||
mv_if_exist src/out/Default/dist.zip
|
||||
mv_if_exist src/out/Default/gen/node_headers.tar.gz
|
||||
mv_if_exist src/out/Default/symbols.zip
|
||||
mv_if_exist src/out/Default/mksnapshot.zip
|
||||
mv_if_exist src/out/Default/chromedriver.zip
|
||||
mv_if_exist src/out/ffmpeg/ffmpeg.zip
|
||||
mv_if_exist src/out/Default/hunspell_dictionaries.zip
|
||||
mv_if_exist src/cross-arch-snapshots
|
||||
cp_if_exist src/out/electron_ninja_log
|
||||
cp_if_exist src/out/Default/.ninja_log
|
||||
22
script/actions/restore-artifacts.sh
Executable file
22
script/actions/restore-artifacts.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
mv_if_exist() {
|
||||
if [ -f "generated_artifacts_${BUILD_TYPE}/$1" ] || [ -d "generated_artifacts_${BUILD_TYPE}/$1" ]; then
|
||||
echo Restoring $1 to $2
|
||||
mkdir -p $2
|
||||
mv generated_artifacts_${BUILD_TYPE}/$1 $2
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
|
||||
mv_if_exist dist.zip src/out/Default
|
||||
mv_if_exist node_headers.tar.gz src/out/Default/gen
|
||||
mv_if_exist symbols.zip src/out/Default
|
||||
mv_if_exist mksnapshot.zip src/out/Default
|
||||
mv_if_exist chromedriver.zip src/out/Default
|
||||
mv_if_exist ffmpeg.zip src/out/ffmpeg
|
||||
mv_if_exist hunspell_dictionaries.zip src/out/Default
|
||||
mv_if_exist cross-arch-snapshots src
|
||||
91
script/azure_cli_deb_install.sh
Executable file
91
script/azure_cli_deb_install.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#######################################################################################################################
|
||||
# This script does three fundamental things: #
|
||||
# 1. Add Microsoft's GPG Key has a trusted source of apt packages. #
|
||||
# 2. Add Microsoft's repositories as a source for apt packages. #
|
||||
# 3. Installs the Azure CLI from those repositories. #
|
||||
# Given the nature of this script, it must be executed with elevated privileges, i.e. with `sudo`. #
|
||||
# #
|
||||
# Copied from https://azurecliprod.blob.core.windows.net/$root/deb_install.sh #
|
||||
#######################################################################################################################
|
||||
|
||||
set -e
|
||||
|
||||
if [[ $# -ge 1 && $1 == "-y" ]]; then
|
||||
global_consent=0
|
||||
else
|
||||
global_consent=1
|
||||
fi
|
||||
|
||||
function assert_consent {
|
||||
if [[ $2 -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -n "$1 [Y/n] "
|
||||
read consent
|
||||
if [[ ! "${consent}" == "y" && ! "${consent}" == "Y" && ! "${consent}" == "" ]]; then
|
||||
echo "'${consent}'"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
global_consent=0 # Artificially giving global consent after review-feedback. Remove this line to enable interactive mode
|
||||
|
||||
setup() {
|
||||
|
||||
assert_consent "Add packages necessary to modify your apt-package sources?" ${global_consent}
|
||||
set -v
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y apt-transport-https lsb-release gnupg curl
|
||||
set +v
|
||||
|
||||
assert_consent "Add Microsoft as a trusted package signer?" ${global_consent}
|
||||
set -v
|
||||
curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg
|
||||
set +v
|
||||
|
||||
assert_consent "Add the Azure CLI Repository to your apt sources?" ${global_consent}
|
||||
set -v
|
||||
# Use env var DIST_CODE for the package dist name if provided
|
||||
if [[ -z $DIST_CODE ]]; then
|
||||
CLI_REPO=$(lsb_release -cs)
|
||||
shopt -s nocasematch
|
||||
ERROR_MSG="Unable to find a package for your system. Please check if an existing package in https://packages.microsoft.com/repos/azure-cli/dists/ can be used in your system and install with the dist name: 'curl -sL https://aka.ms/InstallAzureCLIDeb | sudo DIST_CODE=<dist_code_name> bash'"
|
||||
if [[ ! $(curl -sL https://packages.microsoft.com/repos/azure-cli/dists/) =~ $CLI_REPO ]]; then
|
||||
DIST=$(lsb_release -is)
|
||||
if [[ $DIST =~ "Ubuntu" ]]; then
|
||||
CLI_REPO="jammy"
|
||||
elif [[ $DIST =~ "Debian" ]]; then
|
||||
CLI_REPO="bookworm"
|
||||
elif [[ $DIST =~ "LinuxMint" ]]; then
|
||||
CLI_REPO=$(cat /etc/os-release | grep -Po 'UBUNTU_CODENAME=\K.*') || true
|
||||
if [[ -z $CLI_REPO ]]; then
|
||||
echo $ERROR_MSG
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo $ERROR_MSG
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
CLI_REPO=$DIST_CODE
|
||||
if [[ ! $(curl -sL https://packages.microsoft.com/repos/azure-cli/dists/) =~ $CLI_REPO ]]; then
|
||||
echo "Unable to find an azure-cli package with DIST_CODE=$CLI_REPO in https://packages.microsoft.com/repos/azure-cli/dists/."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "deb [arch=$(dpkg --print-architecture)] https://packages.microsoft.com/repos/azure-cli/ ${CLI_REPO} main" \
|
||||
> /etc/apt/sources.list.d/azure-cli.list
|
||||
apt-get update
|
||||
set +v
|
||||
|
||||
assert_consent "Install the Azure CLI?" ${global_consent}
|
||||
apt-get install -y azure-cli
|
||||
|
||||
}
|
||||
|
||||
setup # ensure the whole file is downloaded before executing
|
||||
@@ -75,7 +75,8 @@ function spawnAndCheckExitCode (cmd, args, opts) {
|
||||
|
||||
function cpplint (args) {
|
||||
args.unshift(`--root=${SOURCE_ROOT}`);
|
||||
const result = childProcess.spawnSync(IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py', args, { encoding: 'utf8', shell: true });
|
||||
const cmd = IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py';
|
||||
const result = childProcess.spawnSync(cmd, args, { encoding: 'utf8', shell: true });
|
||||
// cpplint.py writes EVERYTHING to stderr, including status messages
|
||||
if (result.stderr) {
|
||||
for (const line of result.stderr.split(/[\r\n]+/)) {
|
||||
|
||||
@@ -93,7 +93,8 @@ async function main () {
|
||||
const { status: buildStatus } = cp.spawnSync(NPX_CMD, ['node-gyp', 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
|
||||
env,
|
||||
cwd: NAN_DIR,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
|
||||
if (buildStatus !== 0) {
|
||||
@@ -104,7 +105,8 @@ async function main () {
|
||||
const { status: installStatus } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], {
|
||||
env,
|
||||
cwd: NAN_DIR,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
if (installStatus !== 0) {
|
||||
console.error('Failed to install nan node_modules');
|
||||
|
||||
@@ -10,7 +10,8 @@ if (fs.existsSync(checkPath)) {
|
||||
command.slice(1),
|
||||
{
|
||||
stdio: 'inherit',
|
||||
cwd: checkPath
|
||||
cwd: checkPath,
|
||||
shell: process.platform === 'win32'
|
||||
}
|
||||
);
|
||||
child.on('exit', code => process.exit(code));
|
||||
|
||||
@@ -221,7 +221,8 @@ async function installSpecModules (dir) {
|
||||
const { status } = childProcess.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install', '--frozen-lockfile'], {
|
||||
env,
|
||||
cwd: dir,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
if (status !== 0 && !process.env.IGNORE_YARN_INSTALL_ERROR) {
|
||||
console.log(`${fail} Failed to yarn install in '${dir}'`);
|
||||
|
||||
@@ -11,7 +11,8 @@ if (require.main === module) {
|
||||
env: {
|
||||
...process.env,
|
||||
npm_config_yes: 'true'
|
||||
}
|
||||
},
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
|
||||
child.on('exit', code => process.exit(code));
|
||||
|
||||
@@ -33,14 +33,12 @@ base::FilePath GetHelperAppPath(const base::FilePath& frameworks_path,
|
||||
base::PathService::Get(base::FILE_EXE, &path);
|
||||
|
||||
std::string helper_name = "Helper";
|
||||
if (base::EndsWith(path.value(), content::kMacHelperSuffix_renderer,
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
if (const auto& val = path.value();
|
||||
val.ends_with(content::kMacHelperSuffix_renderer)) {
|
||||
helper_name += content::kMacHelperSuffix_renderer;
|
||||
} else if (base::EndsWith(path.value(), content::kMacHelperSuffix_gpu,
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
} else if (val.ends_with(content::kMacHelperSuffix_gpu)) {
|
||||
helper_name += content::kMacHelperSuffix_gpu;
|
||||
} else if (base::EndsWith(path.value(), content::kMacHelperSuffix_plugin,
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
} else if (val.ends_with(content::kMacHelperSuffix_plugin)) {
|
||||
helper_name += content::kMacHelperSuffix_plugin;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,19 +117,6 @@ BrowserWindow::~BrowserWindow() {
|
||||
|
||||
void BrowserWindow::BeforeUnloadDialogCancelled() {
|
||||
WindowList::WindowCloseCancelled(window());
|
||||
// Cancel unresponsive event when window close is cancelled.
|
||||
window_unresponsive_closure_.Cancel();
|
||||
}
|
||||
|
||||
void BrowserWindow::OnRendererUnresponsive(content::RenderProcessHost*) {
|
||||
// Schedule the unresponsive shortly later, since we may receive the
|
||||
// responsive event soon. This could happen after the whole application had
|
||||
// blocked for a while.
|
||||
// Also notice that when closing this event would be ignored because we have
|
||||
// explicitly started a close timeout counter. This is on purpose because we
|
||||
// don't want the unresponsive event to be sent too early when user is closing
|
||||
// the window.
|
||||
ScheduleUnresponsiveEvent(50);
|
||||
}
|
||||
|
||||
void BrowserWindow::WebContentsDestroyed() {
|
||||
@@ -137,11 +124,6 @@ void BrowserWindow::WebContentsDestroyed() {
|
||||
CloseImmediately();
|
||||
}
|
||||
|
||||
void BrowserWindow::OnRendererResponsive(content::RenderProcessHost*) {
|
||||
window_unresponsive_closure_.Cancel();
|
||||
Emit("responsive");
|
||||
}
|
||||
|
||||
void BrowserWindow::OnSetContentBounds(const gfx::Rect& rect) {
|
||||
// window.resizeTo(...)
|
||||
// window.moveTo(...)
|
||||
@@ -177,13 +159,6 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
||||
// first, and when the web page is closed the window will also be closed.
|
||||
*prevent_default = true;
|
||||
|
||||
// Assume the window is not responding if it doesn't cancel the close and is
|
||||
// not closed in 5s, in this way we can quickly show the unresponsive
|
||||
// dialog when the window is busy executing some script without waiting for
|
||||
// the unresponsive timeout.
|
||||
if (window_unresponsive_closure_.IsCancelled())
|
||||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
// Already closed by renderer.
|
||||
if (!web_contents() || !api_web_contents_)
|
||||
return;
|
||||
@@ -250,9 +225,6 @@ void BrowserWindow::CloseImmediately() {
|
||||
}
|
||||
|
||||
BaseWindow::CloseImmediately();
|
||||
|
||||
// Do not sent "unresponsive" event after window is closed.
|
||||
window_unresponsive_closure_.Cancel();
|
||||
}
|
||||
|
||||
void BrowserWindow::Focus() {
|
||||
@@ -362,24 +334,6 @@ void BrowserWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
|
||||
}
|
||||
#endif
|
||||
|
||||
void BrowserWindow::ScheduleUnresponsiveEvent(int ms) {
|
||||
if (!window_unresponsive_closure_.IsCancelled())
|
||||
return;
|
||||
|
||||
window_unresponsive_closure_.Reset(base::BindRepeating(
|
||||
&BrowserWindow::NotifyWindowUnresponsive, GetWeakPtr()));
|
||||
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
|
||||
FROM_HERE, window_unresponsive_closure_.callback(),
|
||||
base::Milliseconds(ms));
|
||||
}
|
||||
|
||||
void BrowserWindow::NotifyWindowUnresponsive() {
|
||||
window_unresponsive_closure_.Cancel();
|
||||
if (!window_->IsClosed() && window_->IsEnabled()) {
|
||||
Emit("unresponsive");
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserWindow::OnWindowShow() {
|
||||
web_contents()->WasShown();
|
||||
BaseWindow::OnWindowShow();
|
||||
|
||||
@@ -43,9 +43,6 @@ class BrowserWindow : public BaseWindow,
|
||||
|
||||
// content::WebContentsObserver:
|
||||
void BeforeUnloadDialogCancelled() override;
|
||||
void OnRendererUnresponsive(content::RenderProcessHost*) override;
|
||||
void OnRendererResponsive(
|
||||
content::RenderProcessHost* render_process_host) override;
|
||||
void WebContentsDestroyed() override;
|
||||
|
||||
// ExtendedWebContentsObserver:
|
||||
@@ -84,16 +81,6 @@ class BrowserWindow : public BaseWindow,
|
||||
private:
|
||||
// Helpers.
|
||||
|
||||
// Schedule a notification unresponsive event.
|
||||
void ScheduleUnresponsiveEvent(int ms);
|
||||
|
||||
// Dispatch unresponsive event to observers.
|
||||
void NotifyWindowUnresponsive();
|
||||
|
||||
// Closure that would be called when window is unresponsive when closing,
|
||||
// it should be cancelled when we can prove that the window is responsive.
|
||||
base::CancelableRepeatingClosure window_unresponsive_closure_;
|
||||
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
v8::Global<v8::Value> web_contents_view_;
|
||||
base::WeakPtr<api::WebContents> api_web_contents_;
|
||||
|
||||
@@ -1545,8 +1545,7 @@ gin::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
|
||||
if (partition.empty()) {
|
||||
browser_context =
|
||||
ElectronBrowserContext::From("", false, std::move(options));
|
||||
} else if (base::StartsWith(partition, kPersistPrefix,
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
} else if (partition.starts_with(kPersistPrefix)) {
|
||||
std::string name = partition.substr(8);
|
||||
browser_context =
|
||||
ElectronBrowserContext::From(name, false, std::move(options));
|
||||
|
||||
@@ -106,12 +106,9 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol,
|
||||
const std::vector<std::string> argv = {kXdgSettings, "check",
|
||||
kXdgSettingsDefaultSchemeHandler,
|
||||
protocol, desktop_name};
|
||||
const auto output = GetXdgAppOutput(argv);
|
||||
if (!output)
|
||||
return false;
|
||||
|
||||
// Allow any reply that starts with "yes".
|
||||
return base::StartsWith(output.value(), "yes", base::CompareCase::SENSITIVE);
|
||||
const std::optional<std::string> output = GetXdgAppOutput(argv);
|
||||
return output && output->starts_with("yes");
|
||||
}
|
||||
|
||||
// Todo implement
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "shell/browser/protocol_registry.h"
|
||||
#include "shell/browser/special_storage_policy.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||
#include "shell/browser/ui/webui/accessibility_ui.h"
|
||||
#include "shell/browser/web_contents_permission_helper.h"
|
||||
#include "shell/browser/web_view_manager.h"
|
||||
#include "shell/browser/zoom_level_delegate.h"
|
||||
@@ -241,6 +242,67 @@ std::string MakePartitionName(const std::string& input) {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool DoesDeviceMatch(const base::Value& device,
|
||||
const base::Value& device_to_compare,
|
||||
const blink::PermissionType permission_type) {
|
||||
if (permission_type ==
|
||||
static_cast<blink::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::HID) ||
|
||||
permission_type ==
|
||||
static_cast<blink::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::USB)) {
|
||||
if (device.GetDict().FindInt(kDeviceVendorIdKey) !=
|
||||
device_to_compare.GetDict().FindInt(kDeviceVendorIdKey) ||
|
||||
device.GetDict().FindInt(kDeviceProductIdKey) !=
|
||||
device_to_compare.GetDict().FindInt(kDeviceProductIdKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* serial_number =
|
||||
device_to_compare.GetDict().FindString(kDeviceSerialNumberKey);
|
||||
const auto* device_serial_number =
|
||||
device.GetDict().FindString(kDeviceSerialNumberKey);
|
||||
|
||||
if (serial_number && device_serial_number &&
|
||||
*device_serial_number == *serial_number)
|
||||
return true;
|
||||
} else if (permission_type ==
|
||||
static_cast<blink::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::SERIAL)) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
const auto* instance_id = device.GetDict().FindString(kDeviceInstanceIdKey);
|
||||
const auto* port_instance_id =
|
||||
device_to_compare.GetDict().FindString(kDeviceInstanceIdKey);
|
||||
if (instance_id && port_instance_id && *instance_id == *port_instance_id)
|
||||
return true;
|
||||
#else
|
||||
const auto* serial_number = device.GetDict().FindString(kSerialNumberKey);
|
||||
const auto* port_serial_number =
|
||||
device_to_compare.GetDict().FindString(kSerialNumberKey);
|
||||
if (device.GetDict().FindInt(kVendorIdKey) !=
|
||||
device_to_compare.GetDict().FindInt(kVendorIdKey) ||
|
||||
device.GetDict().FindInt(kProductIdKey) !=
|
||||
device_to_compare.GetDict().FindInt(kProductIdKey) ||
|
||||
(serial_number && port_serial_number &&
|
||||
*port_serial_number != *serial_number)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
const auto* usb_driver_key = device.GetDict().FindString(kUsbDriverKey);
|
||||
const auto* port_usb_driver_key =
|
||||
device_to_compare.GetDict().FindString(kUsbDriverKey);
|
||||
if (usb_driver_key && port_usb_driver_key &&
|
||||
*usb_driver_key != *port_usb_driver_key) {
|
||||
return false;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
return true;
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@@ -352,6 +414,7 @@ void ElectronBrowserContext::InitPrefs() {
|
||||
MediaDeviceIDSalt::RegisterPrefs(registry.get());
|
||||
ZoomLevelDelegate::RegisterPrefs(registry.get());
|
||||
PrefProxyConfigTrackerImpl::RegisterPrefs(registry.get());
|
||||
ElectronAccessibilityUIMessageHandler::RegisterPrefs(registry.get());
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (!in_memory_)
|
||||
extensions::ExtensionPrefs::RegisterProfilePrefs(registry.get());
|
||||
@@ -721,7 +784,7 @@ void ElectronBrowserContext::GrantDevicePermission(
|
||||
void ElectronBrowserContext::RevokeDevicePermission(
|
||||
const url::Origin& origin,
|
||||
const base::Value& device,
|
||||
blink::PermissionType permission_type) {
|
||||
const blink::PermissionType permission_type) {
|
||||
const auto& current_devices_it = granted_devices_.find(permission_type);
|
||||
if (current_devices_it == granted_devices_.end())
|
||||
return;
|
||||
@@ -730,76 +793,10 @@ void ElectronBrowserContext::RevokeDevicePermission(
|
||||
if (origin_devices_it == current_devices_it->second.end())
|
||||
return;
|
||||
|
||||
for (auto it = origin_devices_it->second.begin();
|
||||
it != origin_devices_it->second.end();) {
|
||||
if (DoesDeviceMatch(device, it->get(), permission_type)) {
|
||||
it = origin_devices_it->second.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ElectronBrowserContext::DoesDeviceMatch(
|
||||
const base::Value& device,
|
||||
const base::Value* device_to_compare,
|
||||
blink::PermissionType permission_type) {
|
||||
if (permission_type ==
|
||||
static_cast<blink::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::HID) ||
|
||||
permission_type ==
|
||||
static_cast<blink::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::USB)) {
|
||||
if (device.GetDict().FindInt(kDeviceVendorIdKey) !=
|
||||
device_to_compare->GetDict().FindInt(kDeviceVendorIdKey) ||
|
||||
device.GetDict().FindInt(kDeviceProductIdKey) !=
|
||||
device_to_compare->GetDict().FindInt(kDeviceProductIdKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* serial_number =
|
||||
device_to_compare->GetDict().FindString(kDeviceSerialNumberKey);
|
||||
const auto* device_serial_number =
|
||||
device.GetDict().FindString(kDeviceSerialNumberKey);
|
||||
|
||||
if (serial_number && device_serial_number &&
|
||||
*device_serial_number == *serial_number)
|
||||
return true;
|
||||
} else if (permission_type ==
|
||||
static_cast<blink::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::SERIAL)) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
const auto* instance_id = device.GetDict().FindString(kDeviceInstanceIdKey);
|
||||
const auto* port_instance_id =
|
||||
device_to_compare->GetDict().FindString(kDeviceInstanceIdKey);
|
||||
if (instance_id && port_instance_id && *instance_id == *port_instance_id)
|
||||
return true;
|
||||
#else
|
||||
const auto* serial_number = device.GetDict().FindString(kSerialNumberKey);
|
||||
const auto* port_serial_number =
|
||||
device_to_compare->GetDict().FindString(kSerialNumberKey);
|
||||
if (device.GetDict().FindInt(kVendorIdKey) !=
|
||||
device_to_compare->GetDict().FindInt(kVendorIdKey) ||
|
||||
device.GetDict().FindInt(kProductIdKey) !=
|
||||
device_to_compare->GetDict().FindInt(kProductIdKey) ||
|
||||
(serial_number && port_serial_number &&
|
||||
*port_serial_number != *serial_number)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
const auto* usb_driver_key = device.GetDict().FindString(kUsbDriverKey);
|
||||
const auto* port_usb_driver_key =
|
||||
device_to_compare->GetDict().FindString(kUsbDriverKey);
|
||||
if (usb_driver_key && port_usb_driver_key &&
|
||||
*usb_driver_key != *port_usb_driver_key) {
|
||||
return false;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
return true;
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
}
|
||||
return false;
|
||||
std::erase_if(origin_devices_it->second,
|
||||
[&device, &permission_type](auto const& val) {
|
||||
return DoesDeviceMatch(device, *val, permission_type);
|
||||
});
|
||||
}
|
||||
|
||||
bool ElectronBrowserContext::CheckDevicePermission(
|
||||
@@ -815,7 +812,7 @@ bool ElectronBrowserContext::CheckDevicePermission(
|
||||
return false;
|
||||
|
||||
for (const auto& device_to_compare : origin_devices_it->second) {
|
||||
if (DoesDeviceMatch(device, device_to_compare.get(), permission_type))
|
||||
if (DoesDeviceMatch(device, *device_to_compare, permission_type))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#include "content/public/browser/media_stream_request.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "electron/shell/browser/media/media_device_id_salt.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "services/network/public/mojom/url_loader_factory.mojom.h"
|
||||
#include "shell/browser/media/media_device_id_salt.h"
|
||||
#include "third_party/blink/public/common/permissions/permission_utils.h"
|
||||
|
||||
class PrefService;
|
||||
@@ -221,10 +221,6 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||
// Initialize pref registry.
|
||||
void InitPrefs();
|
||||
|
||||
bool DoesDeviceMatch(const base::Value& device,
|
||||
const base::Value* device_to_compare,
|
||||
blink::PermissionType permission_type);
|
||||
|
||||
scoped_refptr<ValueMapPrefStore> in_memory_pref_store_;
|
||||
std::unique_ptr<CookieChangeNotifier> cookie_change_notifier_;
|
||||
std::unique_ptr<PrefService> prefs_;
|
||||
|
||||
@@ -131,153 +131,6 @@ JavascriptEnvironment::~JavascriptEnvironment() {
|
||||
platform_->UnregisterIsolate(isolate_);
|
||||
}
|
||||
|
||||
class EnabledStateObserverImpl final
|
||||
: public base::trace_event::TraceLog::EnabledStateObserver {
|
||||
public:
|
||||
EnabledStateObserverImpl() {
|
||||
base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
|
||||
}
|
||||
|
||||
~EnabledStateObserverImpl() override {
|
||||
base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(
|
||||
this);
|
||||
}
|
||||
|
||||
// disable copy
|
||||
EnabledStateObserverImpl(const EnabledStateObserverImpl&) = delete;
|
||||
EnabledStateObserverImpl& operator=(const EnabledStateObserverImpl&) = delete;
|
||||
|
||||
void OnTraceLogEnabled() final {
|
||||
base::AutoLock lock(mutex_);
|
||||
for (auto* o : observers_) {
|
||||
o->OnTraceEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
void OnTraceLogDisabled() final {
|
||||
base::AutoLock lock(mutex_);
|
||||
for (auto* o : observers_) {
|
||||
o->OnTraceDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
void AddObserver(v8::TracingController::TraceStateObserver* observer) {
|
||||
{
|
||||
base::AutoLock lock(mutex_);
|
||||
DCHECK(!observers_.count(observer));
|
||||
observers_.insert(observer);
|
||||
}
|
||||
|
||||
// Fire the observer if recording is already in progress.
|
||||
if (base::trace_event::TraceLog::GetInstance()->IsEnabled())
|
||||
observer->OnTraceEnabled();
|
||||
}
|
||||
|
||||
void RemoveObserver(v8::TracingController::TraceStateObserver* observer) {
|
||||
base::AutoLock lock(mutex_);
|
||||
DCHECK_EQ(observers_.count(observer), 1lu);
|
||||
observers_.erase(observer);
|
||||
}
|
||||
|
||||
private:
|
||||
base::Lock mutex_;
|
||||
std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
|
||||
};
|
||||
|
||||
class TracingControllerImpl : public node::tracing::TracingController {
|
||||
public:
|
||||
TracingControllerImpl() = default;
|
||||
~TracingControllerImpl() override = default;
|
||||
|
||||
// disable copy
|
||||
TracingControllerImpl(const TracingControllerImpl&) = delete;
|
||||
TracingControllerImpl& operator=(const TracingControllerImpl&) = delete;
|
||||
|
||||
// TracingController implementation.
|
||||
const uint8_t* GetCategoryGroupEnabled(const char* name) override {
|
||||
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
|
||||
}
|
||||
uint64_t AddTraceEvent(
|
||||
char phase,
|
||||
const uint8_t* category_enabled_flag,
|
||||
const char* name,
|
||||
const char* scope,
|
||||
uint64_t id,
|
||||
uint64_t bind_id,
|
||||
int32_t num_args,
|
||||
const char** arg_names,
|
||||
const uint8_t* arg_types,
|
||||
const uint64_t* arg_values,
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
|
||||
unsigned int flags) override {
|
||||
base::trace_event::TraceArguments args(
|
||||
num_args, arg_names, arg_types,
|
||||
reinterpret_cast<const unsigned long long*>( // NOLINT(runtime/int)
|
||||
arg_values),
|
||||
arg_convertables);
|
||||
DCHECK_LE(num_args, 2);
|
||||
base::trace_event::TraceEventHandle handle =
|
||||
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID(
|
||||
phase, category_enabled_flag, name, scope, id, bind_id, &args,
|
||||
flags);
|
||||
uint64_t result;
|
||||
memcpy(&result, &handle, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
uint64_t AddTraceEventWithTimestamp(
|
||||
char phase,
|
||||
const uint8_t* category_enabled_flag,
|
||||
const char* name,
|
||||
const char* scope,
|
||||
uint64_t id,
|
||||
uint64_t bind_id,
|
||||
int32_t num_args,
|
||||
const char** arg_names,
|
||||
const uint8_t* arg_types,
|
||||
const uint64_t* arg_values,
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
|
||||
unsigned int flags,
|
||||
int64_t timestampMicroseconds) override {
|
||||
base::trace_event::TraceArguments args(
|
||||
num_args, arg_names, arg_types,
|
||||
reinterpret_cast<const unsigned long long*>( // NOLINT(runtime/int)
|
||||
arg_values),
|
||||
arg_convertables);
|
||||
DCHECK_LE(num_args, 2);
|
||||
base::TimeTicks timestamp =
|
||||
base::TimeTicks() + base::Microseconds(timestampMicroseconds);
|
||||
base::trace_event::TraceEventHandle handle =
|
||||
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
|
||||
phase, category_enabled_flag, name, scope, id, bind_id,
|
||||
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, &args, flags);
|
||||
uint64_t result;
|
||||
memcpy(&result, &handle, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
|
||||
const char* name,
|
||||
uint64_t handle) override {
|
||||
base::trace_event::TraceEventHandle traceEventHandle;
|
||||
memcpy(&traceEventHandle, &handle, sizeof(handle));
|
||||
TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name,
|
||||
traceEventHandle);
|
||||
}
|
||||
|
||||
void AddTraceStateObserver(TraceStateObserver* observer) override {
|
||||
GetObserverDelegate().AddObserver(observer);
|
||||
}
|
||||
|
||||
void RemoveTraceStateObserver(TraceStateObserver* observer) override {
|
||||
GetObserverDelegate().RemoveObserver(observer);
|
||||
}
|
||||
|
||||
private:
|
||||
static EnabledStateObserverImpl& GetObserverDelegate() {
|
||||
static base::NoDestructor<EnabledStateObserverImpl> instance;
|
||||
return *instance;
|
||||
}
|
||||
};
|
||||
|
||||
v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
|
||||
bool setup_wasm_streaming) {
|
||||
auto* cmd = base::CommandLine::ForCurrentProcess();
|
||||
@@ -292,7 +145,7 @@ v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
|
||||
// The V8Platform of gin relies on Chromium's task schedule, which has not
|
||||
// been started at this point, so we have to rely on Node's V8Platform.
|
||||
auto* tracing_agent = node::CreateAgent();
|
||||
auto* tracing_controller = new TracingControllerImpl();
|
||||
auto* tracing_controller = tracing_agent->GetTracingController();
|
||||
node::tracing::TraceEventHelper::SetAgent(tracing_agent);
|
||||
platform_ = node::MultiIsolatePlatform::Create(
|
||||
base::RecommendedMaxNumberOfThreadsInThreadGroup(3, 8, 0.1, 0),
|
||||
|
||||
@@ -51,21 +51,10 @@ unity_launcher_entry_set_progress_visible_func entry_set_progress_visible =
|
||||
nullptr;
|
||||
|
||||
void EnsureLibUnityLoaded() {
|
||||
using base::nix::GetDesktopEnvironment;
|
||||
|
||||
if (attempted_load)
|
||||
return;
|
||||
attempted_load = true;
|
||||
|
||||
auto env = base::Environment::Create();
|
||||
base::nix::DesktopEnvironment desktop_env = GetDesktopEnvironment(env.get());
|
||||
|
||||
// The "icon-tasks" KDE task manager also honors Unity Launcher API.
|
||||
if (desktop_env != base::nix::DESKTOP_ENVIRONMENT_UNITY &&
|
||||
desktop_env != base::nix::DESKTOP_ENVIRONMENT_KDE4 &&
|
||||
desktop_env != base::nix::DESKTOP_ENVIRONMENT_KDE5)
|
||||
return;
|
||||
|
||||
// Ubuntu still hasn't given us a nice libunity.so symlink.
|
||||
void* unity_lib = dlopen("libunity.so.4", RTLD_LAZY);
|
||||
if (!unity_lib)
|
||||
|
||||
@@ -230,6 +230,7 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
|
||||
ResizeRootLayer(false);
|
||||
render_widget_host_->SetView(this);
|
||||
render_widget_host_->render_frame_metadata_provider()->AddObserver(this);
|
||||
|
||||
if (content::GpuDataManager::GetInstance()->HardwareAccelerationEnabled()) {
|
||||
video_consumer_ = std::make_unique<OffScreenVideoConsumer>(
|
||||
@@ -240,7 +241,21 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
}
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnLocalSurfaceIdChanged(
|
||||
const cc::RenderFrameMetadata& metadata) {
|
||||
if (metadata.local_surface_id) {
|
||||
bool changed = delegated_frame_host_allocator_.UpdateFromChild(
|
||||
*metadata.local_surface_id);
|
||||
|
||||
if (changed) {
|
||||
ResizeRootLayer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() {
|
||||
render_widget_host_->render_frame_metadata_provider()->RemoveObserver(this);
|
||||
|
||||
// Marking the DelegatedFrameHost as removed from the window hierarchy is
|
||||
// necessary to remove all connections to its old ui::Compositor.
|
||||
if (is_showing_)
|
||||
|
||||
@@ -59,9 +59,11 @@ typedef base::RepeatingCallback<void(const gfx::Rect&, const SkBitmap&)>
|
||||
OnPaintCallback;
|
||||
typedef base::RepeatingCallback<void(const gfx::Rect&)> OnPopupPaintCallback;
|
||||
|
||||
class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
public ui::CompositorDelegate,
|
||||
public OffscreenViewProxyObserver {
|
||||
class OffScreenRenderWidgetHostView
|
||||
: public content::RenderWidgetHostViewBase,
|
||||
public content::RenderFrameMetadataProvider::Observer,
|
||||
public ui::CompositorDelegate,
|
||||
public OffscreenViewProxyObserver {
|
||||
public:
|
||||
OffScreenRenderWidgetHostView(bool transparent,
|
||||
bool painting,
|
||||
@@ -175,6 +177,15 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
RenderWidgetHostViewBase* target_view,
|
||||
gfx::PointF* transformed_point) override;
|
||||
|
||||
// RenderFrameMetadataProvider::Observer:
|
||||
void OnRenderFrameMetadataChangedBeforeActivation(
|
||||
const cc::RenderFrameMetadata& metadata) override {}
|
||||
void OnRenderFrameMetadataChangedAfterActivation(
|
||||
base::TimeTicks activation_time) override {}
|
||||
void OnRenderFrameSubmission() override {}
|
||||
void OnLocalSurfaceIdChanged(
|
||||
const cc::RenderFrameMetadata& metadata) override;
|
||||
|
||||
// ui::CompositorDelegate:
|
||||
bool IsOffscreen() const override;
|
||||
std::unique_ptr<viz::HostDisplayClient> CreateHostDisplayClient(
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/common/chrome_features.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "chrome/grit/accessibility_resources.h" // nogncheck
|
||||
@@ -40,11 +39,17 @@
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_ui_data_source.h"
|
||||
#include "shell/browser/electron_browser_context.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "ui/accessibility/accessibility_features.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
|
||||
#include "ui/base/webui/web_ui_util.h"
|
||||
#include "ui/views/accessibility/view_accessibility.h"
|
||||
#include "ui/views/accessibility/widget_ax_tree_id_map.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -57,26 +62,34 @@ static const char kFaviconUrlField[] = "faviconUrl";
|
||||
static const char kNameField[] = "name";
|
||||
static const char kPagesField[] = "pages";
|
||||
static const char kPidField[] = "pid";
|
||||
static const char kSessionIdField[] = "sessionId";
|
||||
static const char kProcessIdField[] = "processId";
|
||||
static const char kRequestTypeField[] = "requestType";
|
||||
static const char kRoutingIdField[] = "routingId";
|
||||
static const char kSessionIdField[] = "sessionId";
|
||||
static const char kSupportedApiTypesField[] = "supportedApiTypes";
|
||||
static const char kTreeField[] = "tree";
|
||||
static const char kTypeField[] = "type";
|
||||
static const char kUrlField[] = "url";
|
||||
static const char kTreeField[] = "tree";
|
||||
static const char kWidgetsField[] = "widgets";
|
||||
static const char kApiTypeField[] = "apiType";
|
||||
|
||||
#if defined(USE_AURA)
|
||||
static const char kWidgetIdField[] = "widgetId";
|
||||
static const char kWidget[] = "widget";
|
||||
#endif
|
||||
|
||||
// Global flags
|
||||
static const char kBrowser[] = "browser";
|
||||
static const char kCopyTree[] = "copyTree";
|
||||
static const char kHTML[] = "html";
|
||||
static const char kInternal[] = "internal";
|
||||
static const char kLabelImages[] = "labelImages";
|
||||
static const char kLocked[] = "locked";
|
||||
static const char kNative[] = "native";
|
||||
static const char kPage[] = "page";
|
||||
static const char kPDF[] = "pdf";
|
||||
static const char kPDFPrinting[] = "pdfPrinting";
|
||||
static const char kScreenReader[] = "screenreader";
|
||||
static const char kShowOrRefreshTree[] = "showOrRefreshTree";
|
||||
static const char kText[] = "text";
|
||||
static const char kViewsAccessibility[] = "viewsAccessibility";
|
||||
static const char kWeb[] = "web";
|
||||
|
||||
// Possible global flag values
|
||||
@@ -141,75 +154,23 @@ base::Value::Dict BuildTargetDescriptor(electron::NativeWindow* window) {
|
||||
return target_data;
|
||||
}
|
||||
|
||||
#if defined(USE_AURA)
|
||||
base::Value::Dict BuildTargetDescriptor(views::Widget* widget) {
|
||||
base::Value::Dict widget_data;
|
||||
widget_data.Set(kNameField, widget->widget_delegate()->GetWindowTitle());
|
||||
widget_data.Set(kTypeField, kWidget);
|
||||
|
||||
// Use the Widget's root view ViewAccessibility's unique ID for lookup.
|
||||
int id = widget->GetRootView()->GetViewAccessibility().GetUniqueId().Get();
|
||||
widget_data.Set(kWidgetIdField, id);
|
||||
return widget_data;
|
||||
}
|
||||
#endif // defined(USE_AURA)
|
||||
|
||||
bool ShouldHandleAccessibilityRequestCallback(const std::string& path) {
|
||||
return path == kTargetsDataFile;
|
||||
}
|
||||
|
||||
// Add property filters to the property_filters vector for the given property
|
||||
// filter type. The attributes are passed in as a string with each attribute
|
||||
// separated by a space.
|
||||
void AddPropertyFilters(std::vector<ui::AXPropertyFilter>* property_filters,
|
||||
const std::string& attributes,
|
||||
ui::AXPropertyFilter::Type type) {
|
||||
for (const std::string& attribute : base::SplitString(
|
||||
attributes, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
|
||||
property_filters->emplace_back(attribute, type);
|
||||
}
|
||||
}
|
||||
|
||||
bool MatchesPropertyFilters(
|
||||
const std::vector<ui::AXPropertyFilter>& property_filters,
|
||||
const std::string& text) {
|
||||
bool allow = false;
|
||||
for (const auto& filter : property_filters) {
|
||||
if (base::MatchPattern(text, filter.match_str)) {
|
||||
switch (filter.type) {
|
||||
case ui::AXPropertyFilter::ALLOW_EMPTY:
|
||||
case ui::AXPropertyFilter::SCRIPT:
|
||||
allow = true;
|
||||
break;
|
||||
case ui::AXPropertyFilter::ALLOW:
|
||||
allow = (!base::MatchPattern(text, "*=''"));
|
||||
break;
|
||||
case ui::AXPropertyFilter::DENY:
|
||||
allow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return allow;
|
||||
}
|
||||
|
||||
std::string RecursiveDumpAXPlatformNodeAsString(
|
||||
const ui::AXPlatformNode* node,
|
||||
int indent,
|
||||
const std::vector<ui::AXPropertyFilter>& property_filters) {
|
||||
if (!node)
|
||||
return "";
|
||||
std::string str(2 * indent, '+');
|
||||
const std::string line = node->GetDelegate()->GetData().ToString();
|
||||
const std::vector<std::string> attributes = base::SplitString(
|
||||
line, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
for (const std::string& attribute : attributes) {
|
||||
if (MatchesPropertyFilters(property_filters, attribute)) {
|
||||
str += attribute + " ";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
for (size_t i = 0; i < node->GetDelegate()->GetChildCount(); i++) {
|
||||
gfx::NativeViewAccessible child = node->GetDelegate()->ChildAtIndex(i);
|
||||
const ui::AXPlatformNode* child_node =
|
||||
ui::AXPlatformNode::FromNativeViewAccessible(child);
|
||||
str += RecursiveDumpAXPlatformNodeAsString(child_node, indent + 1,
|
||||
property_filters);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool IsValidJSValue(const std::string* str) {
|
||||
return str && str->length() < 5000U;
|
||||
}
|
||||
|
||||
void HandleAccessibilityRequestCallback(
|
||||
content::BrowserContext* current_context,
|
||||
const std::string& path,
|
||||
@@ -217,6 +178,8 @@ void HandleAccessibilityRequestCallback(
|
||||
DCHECK(ShouldHandleAccessibilityRequestCallback(path));
|
||||
|
||||
base::Value::Dict data;
|
||||
PrefService* pref =
|
||||
static_cast<electron::ElectronBrowserContext*>(current_context)->prefs();
|
||||
ui::AXMode mode =
|
||||
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
|
||||
bool is_native_enabled = content::BrowserAccessibilityState::GetInstance()
|
||||
@@ -226,7 +189,7 @@ void HandleAccessibilityRequestCallback(
|
||||
bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
|
||||
bool screenreader = mode.has_mode(ui::AXMode::kScreenReader);
|
||||
bool html = mode.has_mode(ui::AXMode::kHTML);
|
||||
bool pdf = mode.has_mode(ui::AXMode::kPDFPrinting);
|
||||
bool pdf_printing = mode.has_mode(ui::AXMode::kPDFPrinting);
|
||||
|
||||
// The "native" and "web" flags are disabled if
|
||||
// --disable-renderer-accessibility is set.
|
||||
@@ -241,73 +204,161 @@ void HandleAccessibilityRequestCallback(
|
||||
is_web_enabled ? (screenreader ? kOn : kOff) : kDisabled);
|
||||
data.Set(kHTML, is_web_enabled ? (html ? kOn : kOff) : kDisabled);
|
||||
|
||||
// TODO(codebytere): enable use of this flag.
|
||||
//
|
||||
// The "labelImages" flag works only if "web" is enabled, the current profile
|
||||
// has the kAccessibilityImageLabelsEnabled preference set and the appropriate
|
||||
// command line switch has been used. Since this is so closely tied into user
|
||||
// prefs and causes bugs, we're disabling it for now.
|
||||
bool are_accessibility_image_labels_enabled = is_web_enabled;
|
||||
data.Set(kLabelImages, kDisabled);
|
||||
// The "pdfPrinting" flag is independent of the others.
|
||||
data.Set(kPDFPrinting, pdf_printing ? kOn : kOff);
|
||||
|
||||
// The "pdf" flag is independent of the others.
|
||||
data.Set(kPDF, pdf ? kOn : kOff);
|
||||
// The "Top Level Widgets" section is only relevant if views accessibility is
|
||||
// enabled.
|
||||
data.Set(kViewsAccessibility, features::IsAccessibilityTreeForViewsEnabled());
|
||||
|
||||
// Always dump the Accessibility tree.
|
||||
data.Set(kInternal, kOn);
|
||||
std::string pref_api_type =
|
||||
std::string(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
bool pref_api_type_supported = false;
|
||||
|
||||
base::Value::List rvh_list;
|
||||
std::unique_ptr<content::RenderWidgetHostIterator> widgets(
|
||||
std::vector<ui::AXApiType::Type> supported_api_types =
|
||||
content::AXInspectFactory::SupportedApis();
|
||||
base::Value::List supported_api_list;
|
||||
supported_api_list.reserve(supported_api_types.size());
|
||||
for (ui::AXApiType::Type type : supported_api_types) {
|
||||
supported_api_list.Append(std::string_view(type));
|
||||
if (type == ui::AXApiType::From(pref_api_type)) {
|
||||
pref_api_type_supported = true;
|
||||
}
|
||||
}
|
||||
data.Set(kSupportedApiTypesField, std::move(supported_api_list));
|
||||
|
||||
// If the saved API type is not supported, use the default platform formatter
|
||||
// API type.
|
||||
if (!pref_api_type_supported) {
|
||||
pref_api_type = std::string_view(
|
||||
content::AXInspectFactory::DefaultPlatformFormatterType());
|
||||
}
|
||||
data.Set(kApiTypeField, pref_api_type);
|
||||
|
||||
bool is_mode_locked = !content::BrowserAccessibilityState::GetInstance()
|
||||
->IsAXModeChangeAllowed();
|
||||
data.Set(kLocked, is_mode_locked ? kOn : kOff);
|
||||
|
||||
base::Value::List page_list;
|
||||
std::unique_ptr<content::RenderWidgetHostIterator> widget_iter(
|
||||
content::RenderWidgetHost::GetRenderWidgetHosts());
|
||||
|
||||
while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
|
||||
while (content::RenderWidgetHost* widget = widget_iter->GetNextHost()) {
|
||||
// Ignore processes that don't have a connection, such as crashed tabs.
|
||||
if (!widget->GetProcess()->IsInitializedAndNotDead())
|
||||
if (!widget->GetProcess()->IsInitializedAndNotDead()) {
|
||||
continue;
|
||||
}
|
||||
content::RenderViewHost* rvh = content::RenderViewHost::From(widget);
|
||||
if (!rvh)
|
||||
if (!rvh) {
|
||||
continue;
|
||||
}
|
||||
content::WebContents* web_contents =
|
||||
content::WebContents::FromRenderViewHost(rvh);
|
||||
content::WebContentsDelegate* delegate = web_contents->GetDelegate();
|
||||
if (!delegate)
|
||||
if (!delegate) {
|
||||
continue;
|
||||
}
|
||||
if (web_contents->GetPrimaryMainFrame()->GetRenderViewHost() != rvh) {
|
||||
continue;
|
||||
}
|
||||
// Ignore views that are never user-visible, like background pages.
|
||||
if (delegate->IsNeverComposited(web_contents))
|
||||
if (delegate->IsNeverComposited(web_contents)) {
|
||||
continue;
|
||||
}
|
||||
content::BrowserContext* context = rvh->GetProcess()->GetBrowserContext();
|
||||
if (context != current_context)
|
||||
if (context != current_context) {
|
||||
continue;
|
||||
}
|
||||
|
||||
base::Value::Dict descriptor = BuildTargetDescriptor(rvh);
|
||||
descriptor.Set(kNative, is_native_enabled);
|
||||
descriptor.Set(kScreenReader, is_web_enabled && screenreader);
|
||||
descriptor.Set(kWeb, is_web_enabled);
|
||||
descriptor.Set(kLabelImages, are_accessibility_image_labels_enabled);
|
||||
rvh_list.Append(std::move(descriptor));
|
||||
page_list.Append(std::move(descriptor));
|
||||
}
|
||||
|
||||
data.Set(kPagesField, std::move(rvh_list));
|
||||
data.Set(kPagesField, std::move(page_list));
|
||||
|
||||
base::Value::List window_list;
|
||||
for (auto* window : electron::WindowList::GetWindows()) {
|
||||
window_list.Append(BuildTargetDescriptor(window));
|
||||
}
|
||||
|
||||
data.Set(kBrowsersField, std::move(window_list));
|
||||
|
||||
base::Value::List widgets_list;
|
||||
#if defined(USE_AURA)
|
||||
if (features::IsAccessibilityTreeForViewsEnabled()) {
|
||||
views::WidgetAXTreeIDMap& manager_map =
|
||||
views::WidgetAXTreeIDMap::GetInstance();
|
||||
const std::vector<views::Widget*> widgets = manager_map.GetWidgets();
|
||||
for (views::Widget* widget : widgets) {
|
||||
widgets_list.Append(BuildTargetDescriptor(widget));
|
||||
}
|
||||
}
|
||||
#endif // defined(USE_AURA)
|
||||
data.Set(kWidgetsField, std::move(widgets_list));
|
||||
|
||||
std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
|
||||
base::WriteJson(data).value_or("")));
|
||||
}
|
||||
|
||||
std::string RecursiveDumpAXPlatformNodeAsString(
|
||||
ui::AXPlatformNode* node,
|
||||
int indent,
|
||||
const std::vector<ui::AXPropertyFilter>& property_filters) {
|
||||
if (!node) {
|
||||
return "";
|
||||
}
|
||||
std::string str(2 * indent, '+');
|
||||
std::string line = node->GetDelegate()->GetData().ToString();
|
||||
std::vector<std::string> attributes = base::SplitString(
|
||||
line, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
for (std::string attribute : attributes) {
|
||||
if (ui::AXTreeFormatter::MatchesPropertyFilters(property_filters, attribute,
|
||||
false)) {
|
||||
str += attribute + " ";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
for (size_t i = 0; i < node->GetDelegate()->GetChildCount(); i++) {
|
||||
gfx::NativeViewAccessible child = node->GetDelegate()->ChildAtIndex(i);
|
||||
ui::AXPlatformNode* child_node =
|
||||
ui::AXPlatformNode::FromNativeViewAccessible(child);
|
||||
str += RecursiveDumpAXPlatformNodeAsString(child_node, indent + 1,
|
||||
property_filters);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Add property filters to the property_filters vector for the given property
|
||||
// filter type. The attributes are passed in as a string with each attribute
|
||||
// separated by a space.
|
||||
void AddPropertyFilters(std::vector<ui::AXPropertyFilter>& property_filters,
|
||||
const std::string& attributes,
|
||||
ui::AXPropertyFilter::Type type) {
|
||||
for (const std::string& attribute : base::SplitString(
|
||||
attributes, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
|
||||
property_filters.emplace_back(attribute, type);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidJSValue(const std::string* str) {
|
||||
return str && str->length() < 5000U;
|
||||
}
|
||||
|
||||
const std::string& CheckJSValue(const std::string* str) {
|
||||
CHECK(IsValidJSValue(str));
|
||||
return *str;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ElectronAccessibilityUI::ElectronAccessibilityUI(content::WebUI* web_ui)
|
||||
: content::WebUIController(web_ui) {
|
||||
auto* const browser_context = web_ui->GetWebContents()->GetBrowserContext();
|
||||
// Set up the chrome://accessibility source.
|
||||
content::WebUIDataSource* html_source =
|
||||
content::WebUIDataSource::CreateAndAdd(
|
||||
web_ui->GetWebContents()->GetBrowserContext(),
|
||||
chrome::kChromeUIAccessibilityHost);
|
||||
browser_context, chrome::kChromeUIAccessibilityHost);
|
||||
|
||||
// Add required resources.
|
||||
html_source->UseStringsJs();
|
||||
@@ -317,8 +368,7 @@ ElectronAccessibilityUI::ElectronAccessibilityUI(content::WebUI* web_ui)
|
||||
html_source->SetRequestFilter(
|
||||
base::BindRepeating(&ShouldHandleAccessibilityRequestCallback),
|
||||
base::BindRepeating(&HandleAccessibilityRequestCallback,
|
||||
web_ui->GetWebContents()->GetBrowserContext()));
|
||||
|
||||
browser_context));
|
||||
html_source->OverrideContentSecurityPolicy(
|
||||
network::mojom::CSPDirectiveName::TrustedTypes,
|
||||
"trusted-types parse-html-subset sanitize-inner-html;");
|
||||
@@ -332,33 +382,35 @@ ElectronAccessibilityUI::~ElectronAccessibilityUI() = default;
|
||||
ElectronAccessibilityUIMessageHandler::ElectronAccessibilityUIMessageHandler() =
|
||||
default;
|
||||
|
||||
void ElectronAccessibilityUIMessageHandler::GetRequestTypeAndFilters(
|
||||
const base::Value::Dict& data,
|
||||
std::string& request_type,
|
||||
std::string& allow,
|
||||
std::string& allow_empty,
|
||||
std::string& deny) {
|
||||
request_type = CheckJSValue(data.FindString(kRequestTypeField));
|
||||
CHECK(request_type == kShowOrRefreshTree || request_type == kCopyTree);
|
||||
allow = CheckJSValue(data.FindStringByDottedPath("filters.allow"));
|
||||
allow_empty = CheckJSValue(data.FindStringByDottedPath("filters.allowEmpty"));
|
||||
deny = CheckJSValue(data.FindStringByDottedPath("filters.deny"));
|
||||
}
|
||||
|
||||
void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
const base::Value::List& args) {
|
||||
const base::Value::Dict& data = args.front().GetDict();
|
||||
|
||||
const int window_id = *data.FindInt(kSessionIdField);
|
||||
const std::string* const request_type_p = data.FindString(kRequestTypeField);
|
||||
CHECK(IsValidJSValue(request_type_p));
|
||||
std::string request_type = *request_type_p;
|
||||
CHECK(request_type == kShowOrRefreshTree || request_type == kCopyTree);
|
||||
request_type = "accessibility." + request_type;
|
||||
std::string request_type, allow, allow_empty, deny;
|
||||
GetRequestTypeAndFilters(data, request_type, allow, allow_empty, deny);
|
||||
|
||||
const std::string* const allow_p =
|
||||
data.FindStringByDottedPath("filters.allow");
|
||||
CHECK(IsValidJSValue(allow_p));
|
||||
const std::string* const allow_empty_p =
|
||||
data.FindStringByDottedPath("filters.allowEmpty");
|
||||
CHECK(IsValidJSValue(allow_empty_p));
|
||||
const std::string* const deny_p = data.FindStringByDottedPath("filters.deny");
|
||||
CHECK(IsValidJSValue(deny_p));
|
||||
int window_id = *data.FindInt(kSessionIdField);
|
||||
|
||||
AllowJavascript();
|
||||
|
||||
std::vector<ui::AXPropertyFilter> property_filters;
|
||||
AddPropertyFilters(&property_filters, *allow_p, ui::AXPropertyFilter::ALLOW);
|
||||
AddPropertyFilters(&property_filters, *allow_empty_p,
|
||||
AddPropertyFilters(property_filters, allow, ui::AXPropertyFilter::ALLOW);
|
||||
AddPropertyFilters(property_filters, allow_empty,
|
||||
ui::AXPropertyFilter::ALLOW_EMPTY);
|
||||
AddPropertyFilters(&property_filters, *deny_p, ui::AXPropertyFilter::DENY);
|
||||
AddPropertyFilters(property_filters, deny, ui::AXPropertyFilter::DENY);
|
||||
|
||||
for (auto* window : electron::WindowList::GetWindows()) {
|
||||
if (window->window_id() == window_id) {
|
||||
@@ -366,9 +418,9 @@ void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
gfx::NativeWindow native_window = window->GetNativeWindow();
|
||||
ui::AXPlatformNode* node =
|
||||
ui::AXPlatformNode::FromNativeWindow(native_window);
|
||||
result.Set(kTreeField, base::Value(RecursiveDumpAXPlatformNodeAsString(
|
||||
node, 0, property_filters)));
|
||||
CallJavascriptFunction(request_type, base::Value(std::move(result)));
|
||||
result.Set(kTreeField, RecursiveDumpAXPlatformNodeAsString(
|
||||
node, 0, property_filters));
|
||||
FireWebUIListener(request_type, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -378,7 +430,7 @@ void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
result.Set(kSessionIdField, window_id);
|
||||
result.Set(kTypeField, kBrowser);
|
||||
result.Set(kErrorField, "Window no longer exists.");
|
||||
CallJavascriptFunction(request_type, base::Value(std::move(result)));
|
||||
FireWebUIListener(request_type, result);
|
||||
}
|
||||
|
||||
void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
|
||||
@@ -393,6 +445,10 @@ void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
|
||||
"setGlobalFlag",
|
||||
base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalFlag,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"setGlobalString",
|
||||
base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalString,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"requestWebContentsTree",
|
||||
base::BindRepeating(
|
||||
@@ -403,9 +459,24 @@ void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
|
||||
base::BindRepeating(
|
||||
&ElectronAccessibilityUIMessageHandler::RequestNativeUITree,
|
||||
base::Unretained(this)));
|
||||
#if defined(USE_AURA)
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"requestWidgetsTree",
|
||||
base::BindRepeating(&AccessibilityUIMessageHandler::RequestWidgetsTree,
|
||||
base::Unretained(this)));
|
||||
#endif
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"requestAccessibilityEvents",
|
||||
base::BindRepeating(
|
||||
&AccessibilityUIMessageHandler::RequestAccessibilityEvents,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
// static
|
||||
void ElectronAccessibilityUIMessageHandler::RegisterPrefs(
|
||||
user_prefs::PrefRegistrySyncable* registry) {
|
||||
const std::string_view default_api_type =
|
||||
std::string_view(ui::AXApiType::Type(ui::AXApiType::kBlink));
|
||||
registry->RegisterStringPref(prefs::kShownAccessibilityApiType,
|
||||
std::string(default_api_type));
|
||||
}
|
||||
|
||||
@@ -31,7 +31,14 @@ class ElectronAccessibilityUIMessageHandler
|
||||
|
||||
void RegisterMessages() final;
|
||||
|
||||
static void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry);
|
||||
|
||||
private:
|
||||
void GetRequestTypeAndFilters(const base::Value::Dict& data,
|
||||
std::string& request_type,
|
||||
std::string& allow,
|
||||
std::string& allow_empty,
|
||||
std::string& deny);
|
||||
void RequestNativeUITree(const base::Value::List& args);
|
||||
};
|
||||
|
||||
|
||||
@@ -122,11 +122,9 @@ void UsbChooserController::GotUsbDeviceList(
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
// "select-usb-device" should respect |filters|.
|
||||
devices.erase(std::remove_if(devices.begin(), devices.end(),
|
||||
[this](const auto& device_info) {
|
||||
return !DisplayDevice(*device_info);
|
||||
}),
|
||||
devices.end());
|
||||
std::erase_if(devices, [this](const auto& device_info) {
|
||||
return !DisplayDevice(*device_info);
|
||||
});
|
||||
|
||||
v8::Local<v8::Object> details = gin::DataObjectBuilder(isolate)
|
||||
.Set("deviceList", devices)
|
||||
|
||||
@@ -107,8 +107,7 @@ WebContentsPreferences::WebContentsPreferences(
|
||||
}
|
||||
|
||||
WebContentsPreferences::~WebContentsPreferences() {
|
||||
Instances().erase(std::remove(Instances().begin(), Instances().end(), this),
|
||||
Instances().end());
|
||||
std::erase(Instances(), this);
|
||||
}
|
||||
|
||||
void WebContentsPreferences::Clear() {
|
||||
|
||||
@@ -59,8 +59,7 @@ void WindowList::AddWindow(NativeWindow* window) {
|
||||
// static
|
||||
void WindowList::RemoveWindow(NativeWindow* window) {
|
||||
WindowVector& windows = GetInstance()->windows_;
|
||||
windows.erase(std::remove(windows.begin(), windows.end(), window),
|
||||
windows.end());
|
||||
std::erase(windows, window);
|
||||
|
||||
for (WindowListObserver& observer : GetObservers())
|
||||
observer.OnWindowRemoved(window);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "base/apple/foundation_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/task/bind_post_task.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
@@ -38,6 +39,23 @@ double safeShift(double in, double def) {
|
||||
return def;
|
||||
}
|
||||
|
||||
void ReceivedThumbnailResult(CGSize size,
|
||||
gin_helper::Promise<gfx::Image> p,
|
||||
QLThumbnailRepresentation* thumbnail,
|
||||
NSError* error) {
|
||||
if (error || !thumbnail) {
|
||||
std::string err_msg([error.localizedDescription UTF8String]);
|
||||
p.RejectWithErrorMessage("unable to retrieve thumbnail preview "
|
||||
"image for the given path: " +
|
||||
err_msg);
|
||||
} else {
|
||||
NSImage* result = [[NSImage alloc] initWithCGImage:[thumbnail CGImage]
|
||||
size:size];
|
||||
gfx::Image image(result);
|
||||
p.Resolve(image);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath(
|
||||
v8::Isolate* isolate,
|
||||
@@ -70,31 +88,15 @@ v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath(
|
||||
size:cg_size
|
||||
scale:[screen backingScaleFactor]
|
||||
representationTypes:QLThumbnailGenerationRequestRepresentationTypeAll]);
|
||||
__block gin_helper::Promise<gfx::Image> p = std::move(promise);
|
||||
__block auto block_callback = base::BindPostTaskToCurrentDefault(
|
||||
base::BindOnce(&ReceivedThumbnailResult, cg_size, std::move(promise)));
|
||||
auto completionHandler =
|
||||
^(QLThumbnailRepresentation* thumbnail, NSError* error) {
|
||||
std::move(block_callback).Run(thumbnail, error);
|
||||
};
|
||||
[[QLThumbnailGenerator sharedGenerator]
|
||||
generateBestRepresentationForRequest:request
|
||||
completionHandler:^(
|
||||
QLThumbnailRepresentation* thumbnail,
|
||||
NSError* error) {
|
||||
if (error || !thumbnail) {
|
||||
std::string err_msg(
|
||||
[error.localizedDescription UTF8String]);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
p.RejectWithErrorMessage(
|
||||
"unable to retrieve thumbnail preview "
|
||||
"image for the given path: " +
|
||||
err_msg);
|
||||
});
|
||||
} else {
|
||||
NSImage* result = [[NSImage alloc]
|
||||
initWithCGImage:[thumbnail CGImage]
|
||||
size:cg_size];
|
||||
gfx::Image image(result);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
p.Resolve(image);
|
||||
});
|
||||
}
|
||||
}];
|
||||
completionHandler:completionHandler];
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#include "base/hash/hash.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "shell/common/api/electron_api_key_weak_map.h"
|
||||
@@ -17,18 +16,6 @@
|
||||
#include "url/origin.h"
|
||||
#include "v8/include/v8-profiler.h"
|
||||
|
||||
namespace std {
|
||||
|
||||
// The hash function used by DoubleIDWeakMap.
|
||||
template <typename Type1, typename Type2>
|
||||
struct hash<std::pair<Type1, Type2>> {
|
||||
std::size_t operator()(std::pair<Type1, Type2> value) const {
|
||||
return base::HashInts(base::Hash(value.first), value.second);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <typename Type1, typename Type2>
|
||||
|
||||
@@ -83,10 +83,7 @@ void ElectronBindings::BindTo(v8::Isolate* isolate,
|
||||
}
|
||||
|
||||
void ElectronBindings::EnvironmentDestroyed(node::Environment* env) {
|
||||
auto it =
|
||||
std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env);
|
||||
if (it != pending_next_ticks_.end())
|
||||
pending_next_ticks_.erase(it);
|
||||
std::erase(pending_next_ticks_, env);
|
||||
}
|
||||
|
||||
void ElectronBindings::ActivateUVLoop(v8::Isolate* isolate) {
|
||||
|
||||
@@ -19,8 +19,7 @@ CleanedUpAtExit::CleanedUpAtExit() {
|
||||
GetDoomed().emplace_back(this);
|
||||
}
|
||||
CleanedUpAtExit::~CleanedUpAtExit() {
|
||||
auto& doomed = GetDoomed();
|
||||
doomed.erase(std::remove(doomed.begin(), doomed.end(), this), doomed.end());
|
||||
std::erase(GetDoomed(), this);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -31,13 +31,10 @@ base::FilePath MainApplicationBundlePath() {
|
||||
|
||||
// Up to Contents.
|
||||
if (!HasMainProcessKey() &&
|
||||
(base::EndsWith(path.value(), " Helper", base::CompareCase::SENSITIVE) ||
|
||||
base::EndsWith(path.value(), content::kMacHelperSuffix_plugin,
|
||||
base::CompareCase::SENSITIVE) ||
|
||||
base::EndsWith(path.value(), content::kMacHelperSuffix_renderer,
|
||||
base::CompareCase::SENSITIVE) ||
|
||||
base::EndsWith(path.value(), content::kMacHelperSuffix_gpu,
|
||||
base::CompareCase::SENSITIVE))) {
|
||||
(path.value().ends_with(" Helper") ||
|
||||
path.value().ends_with(content::kMacHelperSuffix_plugin) ||
|
||||
path.value().ends_with(content::kMacHelperSuffix_renderer) ||
|
||||
path.value().ends_with(content::kMacHelperSuffix_gpu))) {
|
||||
// The running executable is the helper. Go up five steps:
|
||||
// Contents/Frameworks/Helper.app/Contents/MacOS/Helper
|
||||
// ^ to here ^ from here
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
#include "base/apple/osstatus_logging.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/scoped_aedesc.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/apple/url_conversions.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "url/gurl.h"
|
||||
@@ -183,15 +187,12 @@ void OpenExternal(const GURL& url,
|
||||
return;
|
||||
}
|
||||
|
||||
bool activate = options.activate;
|
||||
__block OpenCallback c = std::move(callback);
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
||||
^{
|
||||
__block std::string error = OpenURL(ns_url, activate);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
std::move(c).Run(error);
|
||||
});
|
||||
});
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE,
|
||||
{base::MayBlock(), base::WithBaseSyncPrimitives(),
|
||||
base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
|
||||
base::BindOnce(&OpenURL, ns_url, options.activate), std::move(callback));
|
||||
}
|
||||
|
||||
bool MoveItemToTrashWithError(const base::FilePath& full_path,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect } from 'chai';
|
||||
import { nativeImage } from 'electron/common';
|
||||
import { ifdescribe, ifit } from './lib/spec-helpers';
|
||||
import { ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers';
|
||||
import * as path from 'node:path';
|
||||
|
||||
describe('nativeImage module', () => {
|
||||
@@ -426,6 +426,8 @@ describe('nativeImage module', () => {
|
||||
});
|
||||
|
||||
ifdescribe(process.platform !== 'linux')('createThumbnailFromPath(path, size)', () => {
|
||||
useRemoteContext({ webPreferences: { contextIsolation: false, nodeIntegration: true } });
|
||||
|
||||
it('throws when invalid size is passed', async () => {
|
||||
const badSize = { width: -1, height: -1 };
|
||||
|
||||
@@ -473,6 +475,13 @@ describe('nativeImage module', () => {
|
||||
const result = await nativeImage.createThumbnailFromPath(imgPath, maxSize);
|
||||
expect(result.getSize()).to.deep.equal(maxSize);
|
||||
});
|
||||
|
||||
itremote('works in the renderer', async (path: string) => {
|
||||
const { nativeImage } = require('electron');
|
||||
const goodSize = { width: 100, height: 100 };
|
||||
const result = await nativeImage.createThumbnailFromPath(path, goodSize);
|
||||
expect(result.isEmpty()).to.equal(false);
|
||||
}, [path.join(fixturesPath, 'assets', 'logo.png')]);
|
||||
});
|
||||
|
||||
describe('addRepresentation()', () => {
|
||||
|
||||
@@ -1381,6 +1381,49 @@ describe('protocol module', () => {
|
||||
expect(body).to.equal(text);
|
||||
});
|
||||
|
||||
it('can receive stream request body asynchronously', async () => {
|
||||
let done: any;
|
||||
const requestReceived: Promise<Buffer[]> = new Promise(resolve => { done = resolve; });
|
||||
protocol.handle('http-like', async (req) => {
|
||||
const chunks = [];
|
||||
for await (const chunk of (req.body as any)) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
done(chunks);
|
||||
return new Response('ok');
|
||||
});
|
||||
defer(() => { protocol.unhandle('http-like'); });
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.loadURL('about:blank');
|
||||
const expectedHashChunks = await w.webContents.executeJavaScript(`
|
||||
const dataStream = () =>
|
||||
new ReadableStream({
|
||||
async start(controller) {
|
||||
for (let i = 0; i < 10; i++) { controller.enqueue(Array(1024 * 128).fill(+i).join("\\n")); }
|
||||
controller.close();
|
||||
},
|
||||
}).pipeThrough(new TextEncoderStream());
|
||||
fetch(
|
||||
new Request("http-like://host", {
|
||||
method: "POST",
|
||||
body: dataStream(),
|
||||
duplex: "half",
|
||||
})
|
||||
);
|
||||
(async () => {
|
||||
const chunks = []
|
||||
for await (const chunk of dataStream()) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
return chunks;
|
||||
})()
|
||||
`);
|
||||
const expectedHash = Buffer.from(await crypto.subtle.digest('SHA-256', Buffer.concat(expectedHashChunks))).toString('hex');
|
||||
const body = Buffer.concat(await requestReceived);
|
||||
const actualHash = Buffer.from(await crypto.subtle.digest('SHA-256', Buffer.from(body))).toString('hex');
|
||||
expect(actualHash).to.equal(expectedHash);
|
||||
});
|
||||
|
||||
it('can receive multi-part postData from loadURL', async () => {
|
||||
protocol.handle('test-scheme', (req) => new Response(req.body));
|
||||
defer(() => { protocol.unhandle('test-scheme'); });
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('shell module', () => {
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('opens an external link', async () => {
|
||||
async function urlOpened () {
|
||||
let url = 'http://127.0.0.1';
|
||||
let requestReceived: Promise<any>;
|
||||
if (process.platform === 'linux') {
|
||||
@@ -53,12 +53,26 @@ describe('shell module', () => {
|
||||
url = (await listen(server)).url;
|
||||
requestReceived = new Promise<void>(resolve => server.on('connection', () => resolve()));
|
||||
}
|
||||
return { url, requestReceived };
|
||||
}
|
||||
|
||||
it('opens an external link', async () => {
|
||||
const { url, requestReceived } = await urlOpened();
|
||||
await Promise.all<void>([
|
||||
shell.openExternal(url),
|
||||
requestReceived
|
||||
]);
|
||||
});
|
||||
|
||||
it('opens an external link in the renderer', async () => {
|
||||
const { url, requestReceived } = await urlOpened();
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: false, contextIsolation: false, nodeIntegration: true } });
|
||||
await w.loadURL('about:blank');
|
||||
await Promise.all<void>([
|
||||
w.webContents.executeJavaScript(`require("electron").shell.openExternal(${JSON.stringify(url)})`),
|
||||
requestReceived
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shell.trashItem()', () => {
|
||||
|
||||
@@ -40,6 +40,7 @@ protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: global.standardScheme, privileges: { standard: true, secure: true, stream: false } },
|
||||
{ scheme: global.zoomScheme, privileges: { standard: true, secure: true } },
|
||||
{ scheme: global.serviceWorkerScheme, privileges: { allowServiceWorkers: true, standard: true, secure: true } },
|
||||
{ scheme: 'http-like', privileges: { standard: true, secure: true, corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'cors-blob', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'cors', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'no-cors', privileges: { supportFetchAPI: true } },
|
||||
|
||||
@@ -220,9 +220,9 @@
|
||||
vscode-uri "^3.0.7"
|
||||
|
||||
"@electron/typescript-definitions@^8.15.2":
|
||||
version "8.15.2"
|
||||
resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.15.2.tgz#1152e3d3731d236b50a3dee5a108176ce43fd703"
|
||||
integrity sha512-6vlWnnNfZrg9QFOGgoLaQZ/nTCg+Y1laz02pUsRRmCJIpJZOY3HnWnIuav7e8g5IIwHMVc8JSohR+YRgiRk/eA==
|
||||
version "8.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.15.6.tgz#a578ee3de6e6dcfdb5765da58f303900a34b2d06"
|
||||
integrity sha512-9YR2jG7AdRLvZMhQLgTljZzkoaKNP1wbQq+/qjBCCCCCbUpECvMRk1/UeuZErZEmddhSYanQZgXiftF1T072uQ==
|
||||
dependencies:
|
||||
"@types/node" "^11.13.7"
|
||||
chalk "^2.4.2"
|
||||
|
||||
Reference in New Issue
Block a user