Compare commits

...

26 Commits

Author SHA1 Message Date
Piotr Płaczek
5b60698dea docs: fix lint command (#42028) 2024-05-04 15:48:08 +02:00
Charles Kerr
05631ec445 chore: disable tests that require nut.js (#42006)
* chore: disable tests that require nut.js

* fixup! chore: disable tests that require nut.js
2024-04-30 21:13:38 -04:00
John Kleinschmidt
36310b8729 chore: fixup gn check when enable_pdf_viewer is false (#41990) 2024-04-30 20:32:11 -04:00
Shelley Vohr
f5fb44eaf8 fix: requestFullscreen from WebContentsView (#41966)
fix: requestFullscreen from WebContentsView
2024-04-29 19:09:29 -04:00
Shelley Vohr
441dbda833 fix: recentDocuments on macOS not working (#41978) 2024-04-29 19:07:14 -04:00
Michaela Laurencin
ef097b77ad chore: fix notes stack updates (#41600)
* chore: fix removeSupercededStackUpdates for generating notes

* add early stop for less than

* Update script/release/notes/notes.js

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

* clean up comparison functionality

* add tests

---------

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2024-04-29 11:41:54 -04:00
Shelley Vohr
5310b79ffb fix: setTitleBarOverlay should be implemented on BaseWindow (#41960)
fix: setTitleBarOverlay should be implemented on BaseWindow
2024-04-29 11:28:24 -04:00
Shelley Vohr
b95d0f7623 build: use env var for build-tools pinning (#41969) 2024-04-29 10:07:42 -04:00
Shelley Vohr
b41da150ca build: add GitHub Actions testing pipeline for macOS (#41812)
* build: test the Mac runner space

* build: baby steps, super basic checkout

* chore: simplify depot-tools

* build: try a sync

* build: fix path

* build: pass different URL for sync

* build: gclient sync with --verbose

* debug: add logging for mtime cache

* build: add psuedocode for Azure workflow, add workflow_dispatch

* build: enable ssh access to runners

* build: test azure upload without full sync

* build: full sync and cache upload test

* build (WIP): mock out download logic

* build: remove sync, try disk space prune

* build: lets try it again, lads

* ci: add cache downloading wip

* fix: correct json parsing

* chore: use depshash and fix output syntax

* chore: rework depshash state and delete more

* refactor: split checkout to Linux runner

* fix: depot_tools get on Linux

* fix: add infra/3pp/tools/swift-format handling

* chore: move to patch file in build as well

* chore: misc cleanup of env steps

* chore: add fix sync step

* build: use tar file, strip .git dirs

* build: set GIT_CACHE_PATH outside of src

* ci: fix cache prefix, add check for ssh debug

* fix: fix tar pack/unpack

* build: add reclient support & ninja build step

* chore: clean up reclient round 1

* fix: grab ELECTRON_RBE_JWT from secrets

* chore: run tmate if debug logging enabled

* chore: move ulimit setting

* fix: missing GN gen env vars

* fix: workaround packed-refs issue

* chore: fixup PATH usage

* chore: remove GIT_CACHE env var

* fix: call pack refs manually

* fix: add RBE_experimental_credentials_helper_args

* chore: whoops we need electron_node/deps/v8 actually

* fix: we need electron_node/deps/openssl too

* build: load build-tools & xcode

* build: add dist, chromedriver & mksnapshot

* build: add test job, download artifacts

* Cache non-generated build artifacts

* chore: set download path explicitly

* chore: load-xcode is called by e build

* Add codesigning certificate step

* Add Test Step

* Try without codesigning just to get tests running

* Add depot_tools to PATH in test

* Persist src/buildtools/mac

* chore: use script/yarn test directly

* Build Node.js Headers for caching

* Add initial matrix for mas build

* Fix GN_EXTRA_ARGS generation syntax

* Fix BUILD_TYPE interpolation

* Use matrix in test correctly

* feat: add publish config, alter release-build script

* build: force trigger the first workflow

* build: oops

* Ensure env vars escaped

* Move GN_EXTRA_ARGS to gn gen step

* chore: rename yml to match convention

* ci: fix helperPath calls in action configs

* chore: try setting directly

* fix: switch to mas config

* chore: Testing -> Default

* Re-enable darwin build

* Use mas JSON config

* refactor: extract artifact logic to bash scripts

* refactor: build MAS after darwin

* chore: move to script/actions

* chore: use Node.js 20.11.x

* Don't fail-fast in tests

* build: tweak release script

* build: remove macos-publish.yml

* build: change action to trigger on publish workflow dispatch

* chore: remove SSH debugging using action-tmate

* build: do not disable CircleCI config

* chore: switch away from cURL for AzureCLI

* chore: move evm.mas.json to .github/workflows/config

* chore: remove publish logic from initial build flow

* build: add patchup check for non-release builds

* build: pin build-tools to sha 2bb63e2

---------

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2024-04-24 10:29:19 -07:00
Charles Kerr
b684a98267 refactor: replace base::EndsWith() with std::ends_with() (#41937) 2024-04-23 21:13:59 -05:00
South Drifted
7621e7cff7 docs: Windows typo in Tutorial document (#41896)
Update tutorial-6-publishing-updating.md
2024-04-23 13:14:26 -04:00
Shelley Vohr
d8f8560b1c refactor: address changes and fix errors in chrome://accessibility (#41911)
refactor: address changes and fix errors in chrome://accessibility
2024-04-23 11:30:47 -04:00
Kilian Valkhof
1cf194faae docs: correct the return value for canceled showSaveDialog (#41926) 2024-04-23 11:29:14 -04:00
Shelley Vohr
a0fee8f47a build: fixup codespaces on-create (#41428) 2024-04-22 20:26:11 -04:00
Jeremy Rose
4e8c28fdf0 fix: data corruption in protocol.handle (#41894) 2024-04-22 13:40:01 -07:00
tuanzijiang
46adb0a3a9 fix: offscreen rendering does not paint after gpu process crashed (#41904)
Co-authored-by: zhangqi.67 <zhangqi.67@bytedance.com>
2024-04-22 09:50:55 -04:00
Shelley Vohr
a8db7fe2ef build: use latest devcontainer buildimage with codespaces (#41916) 2024-04-22 09:48:30 -04:00
Charles Kerr
0346e0a8bf refactor: use std::erase() (#41881)
* refactor: use std::erase() in WebContentsPreferences::~WebContentsPreferences()

* refactor: use std::erase() in WindowList::RemoveWindow()

* refactor: use std::erase() in ElectronBindings::EnvironmentDestroyed()

* refactor: use std::erase() in CleanedUpAtExit::~CleanedUpAtExit()

* refactor: use std::erase_if() in ElectronBrowserContext::RevokeDevicePermission()

* refactor: use std::erase_if() in UsbChooserController::GotUsbDeviceList()

* refactor: move DoesDeviceMatch() out of class into anonymous namespace
2024-04-19 10:55:59 -05:00
Shelley Vohr
39bf441b3b build: enable Perfetto in Chromium (#41880)
* build: enable perfetto in Chromium

* refactor: delete TracingControllerImpl

* fix: TraceObject isn't present when v8_use_perfetto is true

* fix: update lib/internal/http for perfetto

* chore: remove stray log
2024-04-19 11:07:36 -04:00
Samuel Attard
46ef7ef8fb build: update typescript-definitions to 8.15.6 (#41900) 2024-04-19 10:29:45 -04:00
JakobDev
07a68c2bf8 fix: don't check for Desktop Environment in unity_service.cc (#41211)
Don't check for Desktop Environment in unity_service.cc
2024-04-19 09:58:32 -04:00
Jeremy Rose
ed9fec7da4 fix: nativeImage.createThumbnailFromPath and shell.openExternal in renderer (#41875)
* fix: nativeImage.createThumbnailFromPath in renderer

* also fix shell.openExternal
2024-04-19 09:43:01 -04:00
Shelley Vohr
c4aeb17245 fix: EINVAL when spawning cmd files on Windows (#41893)
fix: EINVAL when spawning on Windows
2024-04-19 09:27:58 -04:00
Jeremy Rose
67ba30402b refactor: JSify BrowserWindow unresponsive handling (#37902) 2024-04-18 13:14:07 -07:00
Charles Kerr
b683754c16 chore: remove unused hash function (#41876)
Unused since e1e73fa #24115
2024-04-17 19:04:06 -05:00
nashaofu
0222686e9a docs: update build docs,support Powershell on Windows (#41567)
* docs: update build docs,support Powershell on Windows

* chore: fix capitalization
2024-04-17 18:46:52 -04:00
67 changed files with 1856 additions and 1462 deletions

View File

@@ -27,7 +27,8 @@
]
},
"vscode": {
"extensions": ["joeleinbinder.mojom-language",
"extensions": [
"joeleinbinder.mojom-language",
"rafaelmaiolla.diff",
"surajbarkale.ninja",
"ms-vscode.cpptools",

View File

@@ -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

View File

@@ -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
View 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
View 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,

584
.github/workflows/macos-build.yml vendored Normal file
View File

@@ -0,0 +1,584 @@
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: |
export BUILD_TOOLS_SHA=2bb63e2e7877491b52f972532b52adc979a6ec2f
npm i -g @electron/build-tools
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

View File

@@ -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 = ""

View 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.

View File

@@ -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`.

View File

@@ -41,7 +41,7 @@ etc.
* Write [remark](https://github.com/remarkjs/remark) markdown style.
You can run `npm run lint-docs` to ensure that your documentation changes are
You can run `npm run lint:docs` to ensure that your documentation changes are
formatted correctly.
## JavaScript

View File

@@ -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

View File

@@ -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 = () => {

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View 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

View 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

View 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
View 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

View File

@@ -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]+/)) {

View File

@@ -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');

View File

@@ -485,6 +485,24 @@ const getNotes = async (fromRef, toRef, newVersion) => {
return notes;
};
const compareVersions = (v1, v2) => {
const [split1, split2] = [v1.split('.'), v2.split('.')];
if (split1.length !== split2.length) {
throw new Error(`Expected version strings to have same number of sections: ${split1} and ${split2}`);
}
for (let i = 0; i < split1.length; i++) {
const p1 = parseInt(split1[i], 10);
const p2 = parseInt(split2[i], 10);
if (p1 > p2) return 1;
else if (p1 < p2) return -1;
// Continue checking the value if this portion is equal
}
return 0;
};
const removeSupercededStackUpdates = (commits) => {
const updateRegex = /^Updated ([a-zA-Z.]+) to v?([\d.]+)/;
const notupdates = [];
@@ -496,8 +514,9 @@ const removeSupercededStackUpdates = (commits) => {
notupdates.push(commit);
continue;
}
const [, dep, version] = match;
if (!newest[dep] || newest[dep].version < version) {
if (!newest[dep] || compareVersions(version, newest[dep].version) > 0) {
newest[dep] = { commit, version };
}
}

View File

@@ -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));

View File

@@ -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}'`);

View File

@@ -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));

View File

@@ -39,8 +39,8 @@
#endif // BUILDFLAG(ENABLE_WIDEVINE)
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "components/pdf/common/constants.h"
#include "pdf/pdf.h" // nogncheck
#include "components/pdf/common/constants.h" // nogncheck
#include "pdf/pdf.h" // nogncheck
#include "shell/common/electron_constants.h"
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)

View File

@@ -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;
}

View File

@@ -11,6 +11,7 @@
#include "base/containers/contains.h"
#include "base/task/single_thread_task_runner.h"
#include "content/public/common/color_parser.h"
#include "electron/buildflags/buildflags.h"
#include "gin/dictionary.h"
#include "shell/browser/api/electron_api_menu.h"
@@ -36,6 +37,7 @@
#endif
#if BUILDFLAG(IS_WIN)
#include "shell/browser/ui/views/win_frame_view.h"
#include "shell/browser/ui/win/taskbar_host.h"
#include "ui/base/win/shell.h"
#endif
@@ -1039,6 +1041,63 @@ void BaseWindow::SetAppDetails(const gin_helper::Dictionary& options) {
relaunch_command, relaunch_display_name,
window_->GetAcceleratedWidget());
}
void BaseWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args) {
// Ensure WCO is already enabled on this window
if (!window_->titlebar_overlay_enabled()) {
args->ThrowError("Titlebar overlay is not enabled");
return;
}
auto* window = static_cast<NativeWindowViews*>(window_.get());
bool updated = false;
// Check and update the button color
std::string btn_color;
if (options.Get(options::kOverlayButtonColor, &btn_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(btn_color, &color)) {
args->ThrowError("Could not parse color as CSS color");
return;
}
// Update the view
window->set_overlay_button_color(color);
updated = true;
}
// Check and update the symbol color
std::string symbol_color;
if (options.Get(options::kOverlaySymbolColor, &symbol_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(symbol_color, &color)) {
args->ThrowError("Could not parse symbol color as CSS color");
return;
}
// Update the view
window->set_overlay_symbol_color(color);
updated = true;
}
// Check and update the height
int height = 0;
if (options.Get(options::kOverlayHeight, &height)) {
window->set_titlebar_overlay_height(height);
updated = true;
}
// If anything was updated, invalidate the layout and schedule a paint of the
// window's frame view
if (updated) {
auto* frame_view = static_cast<WinFrameView*>(
window->widget()->non_client_view()->frame_view());
frame_view->InvalidateCaptionButtons();
}
}
#endif
int32_t BaseWindow::GetID() const {
@@ -1227,6 +1286,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setThumbnailClip", &BaseWindow::SetThumbnailClip)
.SetMethod("setThumbnailToolTip", &BaseWindow::SetThumbnailToolTip)
.SetMethod("setAppDetails", &BaseWindow::SetAppDetails)
.SetMethod("setTitleBarOverlay", &BaseWindow::SetTitleBarOverlay)
#endif
.SetProperty("id", &BaseWindow::GetID);
}

View File

@@ -241,6 +241,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
bool SetThumbnailClip(const gfx::Rect& region);
bool SetThumbnailToolTip(const std::string& tooltip);
void SetAppDetails(const gin_helper::Dictionary& options);
void SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args);
#endif
int32_t GetID() const;

View File

@@ -10,7 +10,6 @@
#include "content/browser/web_contents/web_contents_impl.h" // nogncheck
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/color_parser.h"
#include "shell/browser/api/electron_api_web_contents_view.h"
#include "shell/browser/browser.h"
#include "shell/browser/web_contents_preferences.h"
@@ -27,10 +26,6 @@
#include "shell/browser/native_window_views.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "shell/browser/ui/views/win_frame_view.h"
#endif
namespace electron::api {
BrowserWindow::BrowserWindow(gin::Arguments* args,
@@ -117,19 +112,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 +119,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 +154,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 +220,6 @@ void BrowserWindow::CloseImmediately() {
}
BaseWindow::CloseImmediately();
// Do not sent "unresponsive" event after window is closed.
window_unresponsive_closure_.Cancel();
}
void BrowserWindow::Focus() {
@@ -303,83 +270,6 @@ v8::Local<v8::Value> BrowserWindow::GetWebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, web_contents_);
}
#if BUILDFLAG(IS_WIN)
void BrowserWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args) {
// Ensure WCO is already enabled on this window
if (!window_->titlebar_overlay_enabled()) {
args->ThrowError("Titlebar overlay is not enabled");
return;
}
auto* window = static_cast<NativeWindowViews*>(window_.get());
bool updated = false;
// Check and update the button color
std::string btn_color;
if (options.Get(options::kOverlayButtonColor, &btn_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(btn_color, &color)) {
args->ThrowError("Could not parse color as CSS color");
return;
}
// Update the view
window->set_overlay_button_color(color);
updated = true;
}
// Check and update the symbol color
std::string symbol_color;
if (options.Get(options::kOverlaySymbolColor, &symbol_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(symbol_color, &color)) {
args->ThrowError("Could not parse symbol color as CSS color");
return;
}
// Update the view
window->set_overlay_symbol_color(color);
updated = true;
}
// Check and update the height
int height = 0;
if (options.Get(options::kOverlayHeight, &height)) {
window->set_titlebar_overlay_height(height);
updated = true;
}
// If anything was updated, invalidate the layout and schedule a paint of the
// window's frame view
if (updated) {
auto* frame_view = static_cast<WinFrameView*>(
window->widget()->non_client_view()->frame_view());
frame_view->InvalidateCaptionButtons();
}
}
#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();
@@ -419,9 +309,6 @@ void BrowserWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("focusOnWebView", &BrowserWindow::FocusOnWebView)
.SetMethod("blurWebView", &BrowserWindow::BlurWebView)
.SetMethod("isWebViewFocused", &BrowserWindow::IsWebViewFocused)
#if BUILDFLAG(IS_WIN)
.SetMethod("setTitleBarOverlay", &BrowserWindow::SetTitleBarOverlay)
#endif
.SetProperty("webContents", &BrowserWindow::GetWebContents);
}

View File

@@ -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:
@@ -76,24 +73,10 @@ class BrowserWindow : public BaseWindow,
void BlurWebView();
bool IsWebViewFocused();
v8::Local<v8::Value> GetWebContents(v8::Isolate* isolate);
#if BUILDFLAG(IS_WIN)
void SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args);
#endif
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_;

View File

@@ -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));

View File

@@ -89,6 +89,9 @@ void WebContentsView::OnViewAddedToWidget(views::View* observed_view) {
widget->GetNativeWindowProperty(electron::kElectronNativeWindowKey));
if (!native_window)
return;
// We don't need to call SetOwnerWindow(nullptr) in OnViewRemovedFromWidget
// because that's handled in the WebContents dtor called prior.
api_web_contents_->SetOwnerWindow(native_window);
native_window->AddDraggableRegionProvider(this);
}

View File

@@ -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

View File

@@ -214,7 +214,7 @@
#include "components/pdf/browser/pdf_document_helper.h" // nogncheck
#include "components/pdf/browser/pdf_navigation_throttle.h"
#include "components/pdf/browser/pdf_url_loader_request_interceptor.h"
#include "components/pdf/common/constants.h"
#include "components/pdf/common/constants.h" // nogncheck
#include "shell/browser/electron_pdf_document_helper_client.h"
#endif

View File

@@ -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;
}

View File

@@ -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_;

View File

@@ -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),

View File

@@ -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)

View File

@@ -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_)

View File

@@ -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(

View File

@@ -26,8 +26,6 @@ class ElectronMenuModel;
@protected
base::WeakPtr<electron::ElectronMenuModel> model_;
NSMenu* __strong menu_;
NSMenuItem* __strong recentDocumentsMenuItem_;
NSMenu* __strong recentDocumentsMenuSwap_;
BOOL isMenuOpen_;
BOOL useDefaultAccelerator_;
base::OnceClosure closeCallback;

View File

@@ -31,10 +31,14 @@ using SharingItem = electron::ElectronMenuModel::SharingItem;
namespace {
static NSMenuItem* __strong recentDocumentsMenuItem_;
static NSMenu* __strong recentDocumentsMenuSwap_;
struct Role {
SEL selector;
const char* role;
};
Role kRolesMap[] = {
{@selector(orderFrontStandardAboutPanel:), "about"},
{@selector(hide:), "hide"},

View File

@@ -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));
}

View File

@@ -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);
};

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -69,8 +69,8 @@
#endif
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "components/pdf/common/constants.h"
#include "components/pdf/common/pdf_util.h"
#include "components/pdf/common/constants.h" // nogncheck
#include "components/pdf/common/pdf_util.h" // nogncheck
#include "components/pdf/renderer/pdf_internal_plugin_delegate.h"
#include "shell/common/electron_constants.h"
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)

View File

@@ -6596,6 +6596,7 @@ describe('BrowserWindow module', () => {
afterEach(closeAllWindows);
ifit(hasCapturableScreen())('should allow the window to be dragged when enabled', async () => {
// FIXME: nut-js has been removed from npm; we need to find a replacement
// WOA fails to load libnut so we're using require to defer loading only
// on supported platforms.
// "@nut-tree\libnut-win32\build\Release\libnut.node is not a valid Win32 application."
@@ -6640,6 +6641,7 @@ describe('BrowserWindow module', () => {
});
ifit(hasCapturableScreen())('should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled', async () => {
// FIXME: nut-js has been removed from npm; we need to find a replacement
// @ts-ignore: nut-js is an optional dependency so it may not be installed
const { mouse, straightTo, centerOf, Region, Button } = require('@nut-tree/nut-js') as typeof import('@nut-tree/nut-js');

View File

@@ -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()', () => {

View File

@@ -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'); });

View File

@@ -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()', () => {

View File

@@ -60,6 +60,18 @@ describe('WebContentsView', () => {
});
});
it('can be fullscreened', async () => {
const w = new BaseWindow();
const v = new WebContentsView();
w.setContentView(v);
await v.webContents.loadURL('data:text/html,<div id="div">This is a simple div.</div>');
const enterFullScreen = once(w, 'enter-full-screen');
await v.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
await enterFullScreen;
expect(w.isFullScreen()).to.be.true('isFullScreen');
});
describe('visibilityState', () => {
it('is initially hidden', async () => {
const v = new WebContentsView();

View File

@@ -7,5 +7,7 @@
"session module ses.cookies should set cookie for standard scheme",
"webFrameMain module WebFrame.visibilityState should match window state",
"reporting api sends a report for a deprecation",
"chromium features SpeechSynthesis should emit lifecycle events"
]
"chromium features SpeechSynthesis should emit lifecycle events",
"BrowserWindow module draggable regions should allow the window to be dragged when enabled",
"BrowserWindow module draggable regions should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled"
]

View File

@@ -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 } },

View File

@@ -38,9 +38,6 @@
"ws": "^7.4.6",
"yargs": "^16.0.3"
},
"optionalDependencies": {
"@nut-tree/nut-js": "^3.1.2"
},
"resolutions": {
"nan": "file:../../third_party/nan",
"dbus-native/optimist/minimist": "1.2.7",

View File

@@ -211,4 +211,51 @@ describe('release notes', () => {
expect(results.breaking[0].hash).to.equal(testCommit.sha1);
});
});
// test that when you have multiple stack updates only the
// latest will be kept
describe('superseding stack updates', () => {
const oldBranch = '27-x-y';
const newBranch = '28-x-y';
const version = 'v28.0.0';
it('with different major versions', async function () {
const mostRecentCommit = new Commit('9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa', 'chore: bump chromium to 119.0.6043.0');
const sharedChromiumHistory = [
new Commit('029127a8b6f7c511fca4612748ad5b50e43aadaa', 'chore: bump chromium to 118.0.5993.0') // merge-base
];
const chromiumPatchUpdates = [
new Commit('d9ba26273ad3e7a34c905eccbd5dabda4eb7b402', 'chore: bump chromium to 118.0.5991.0'),
mostRecentCommit,
new Commit('d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2', 'chore: bump chromium to 119.0.6029.0')
];
gitFake.setBranch(oldBranch, sharedChromiumHistory);
gitFake.setBranch(newBranch, [...sharedChromiumHistory, ...chromiumPatchUpdates]);
const results: any = await notes.get(oldBranch, newBranch, version);
expect(results.other).to.have.lengthOf(1);
expect(results.other[0].hash).to.equal(mostRecentCommit.sha1);
});
it('with different build versions', async function () {
const mostRecentCommit = new Commit('8f7a48879ef8633a76279803637cdee7f7c6cd4f', 'chore: bump chromium to 119.0.6045.0');
const sharedChromiumHistory = [
new Commit('029127a8b6f7c511fca4612748ad5b50e43aadaa', 'chore: bump chromium to 118.0.5993.0') // merge-base
];
const chromiumPatchUpdates = [
mostRecentCommit,
new Commit('9d0e6d09f0be0abbeae46dd3d66afd96d2daacaa', 'chore: bump chromium to 119.0.6043.0'),
new Commit('d6c8ff2e7050f30dffd784915bcbd2a9f993cdb2', 'chore: bump chromium to 119.0.6029.0')
];
gitFake.setBranch(oldBranch, sharedChromiumHistory);
gitFake.setBranch(newBranch, [...sharedChromiumHistory, ...chromiumPatchUpdates]);
const results: any = await notes.get(oldBranch, newBranch, version);
expect(results.other).to.have.lengthOf(1);
expect(results.other[0].hash).to.equal(mostRecentCommit.sha1);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -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"