diff --git a/.github/actions/build-electron/action.yml b/.github/actions/build-electron/action.yml index 38e514a553403..07ceccab1e912 100644 --- a/.github/actions/build-electron/action.yml +++ b/.github/actions/build-electron/action.yml @@ -60,14 +60,28 @@ runs: sudo launchctl limit maxfiles 65536 200000 fi - NINJA_SUMMARIZE_BUILD=1 e build + if [ "${{ inputs.is-release }}" = "true" ]; then + NINJA_SUMMARIZE_BUILD=1 e build --target electron:release_build + else + NINJA_SUMMARIZE_BUILD=1 e build --target electron:testing_build + fi cp out/Default/.ninja_log out/electron_ninja_log node electron/script/check-symlinks.js - - name: Build Electron dist.zip ${{ inputs.step-suffix }} + + # Upload build stats to Datadog + if ! [ -z $DD_API_KEY ]; then + if [ "$TARGET_PLATFORM" = "win" ]; then + npx node electron/script/build-stats.mjs out/Default/siso.exe.INFO --upload-stats || true + else + npx node electron/script/build-stats.mjs out/Default/siso.INFO --upload-stats || true + fi + else + echo "Skipping build-stats.mjs upload because DD_API_KEY is not set" + fi + - name: Verify dist.zip ${{ inputs.step-suffix }} shell: bash run: | - cd src - e build --target electron:electron_dist_zip + cd src if [ "${{ inputs.is-asan }}" != "true" ]; then target_os=${{ inputs.target-platform == 'macos' && 'mac' || inputs.target-platform }} if [ "${{ inputs.artifact-platform }}" = "mas" ]; then @@ -75,11 +89,10 @@ runs: fi electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ inputs.target-arch }}.manifest fi - - name: Build Mksnapshot ${{ inputs.step-suffix }} + - name: Fixup Mksnapshot ${{ inputs.step-suffix }} shell: bash run: | cd src - e build --target electron:electron_mksnapshot ELECTRON_DEPOT_TOOLS_DISABLE_LOG=1 e d gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args # Remove unused args from mksnapshot_args SEDOPTION="-i" @@ -89,7 +102,6 @@ runs: sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args - e build --target electron:electron_mksnapshot_zip if [ "${{ inputs.target-platform }}" = "win" ]; then cd out/Default powershell Compress-Archive -update mksnapshot_args mksnapshot.zip @@ -123,7 +135,6 @@ runs: shell: bash run: | cd src - e build --target electron:electron_chromedriver e build --target electron:electron_chromedriver_zip if [ "${{ inputs.is-asan }}" != "true" ]; then @@ -133,11 +144,6 @@ runs: fi electron/script/zip_manifests/check-zip-manifest.py out/Default/chromedriver.zip electron/script/zip_manifests/chromedriver_zip.$target_os.${{ inputs.target-arch }}.manifest fi - - name: Build Node.js headers ${{ inputs.step-suffix }} - shell: bash - run: | - cd src - e build --target electron:node_headers - name: Create installed_software.json ${{ inputs.step-suffix }} shell: powershell if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'win' }} @@ -157,17 +163,11 @@ runs: # Needed for msdia140.dll on 64-bit windows cd src export PATH="$PATH:$(pwd)/third_party/llvm-build/Release+Asserts/bin" - - name: Generate & Zip Symbols ${{ inputs.step-suffix }} + - name: Zip Symbols ${{ inputs.step-suffix }} shell: bash run: | - # Generate breakpad symbols on release builds - if [ "${{ inputs.generate-symbols }}" = "true" ]; then - e build --target electron:electron_symbols - fi cd src export BUILD_PATH="$(pwd)/out/Default" - e build --target electron:licenses - e build --target electron:electron_version_file if [ "${{ inputs.is-release }}" = "true" ]; then DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH else @@ -180,18 +180,6 @@ runs: cd src gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true use_siso=true $GN_EXTRA_ARGS" e build --target electron:electron_ffmpeg_zip -C ../../out/ffmpeg - - name: Generate Hunspell Dictionaries ${{ inputs.step-suffix }} - shell: bash - if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }} - run: | - e build --target electron:hunspell_dictionaries_zip - - name: Generate Libcxx ${{ inputs.step-suffix }} - shell: bash - if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }} - run: | - e build --target electron:libcxx_headers_zip - e build --target electron:libcxxabi_headers_zip - e build --target electron:libcxx_objects_zip - name: Remove Clang problem matcher shell: bash run: echo "::remove-matcher owner=clang::" diff --git a/.github/actions/checkout/action.yml b/.github/actions/checkout/action.yml index e7d41c566c67a..aa0baa6fac808 100644 --- a/.github/actions/checkout/action.yml +++ b/.github/actions/checkout/action.yml @@ -172,7 +172,6 @@ runs: 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 diff --git a/.github/actions/fix-sync/action.yml b/.github/actions/fix-sync/action.yml index b72d0ab18b9db..b7442702ba292 100644 --- a/.github/actions/fix-sync/action.yml +++ b/.github/actions/fix-sync/action.yml @@ -109,7 +109,7 @@ runs: deps-file: src/DEPS installation-dir: src/third_party/siso/cipd target-platform: ${{ inputs.target-platform }} - package: infra/build/siso/${platform} + package: build/siso/${platform} - name: Fixup angle git if: ${{ inputs.target-platform != 'linux' }} shell: bash diff --git a/.github/actions/free-space-macos/action.yml b/.github/actions/free-space-macos/action.yml index efdea79f1ed5b..d0251e6802bdd 100644 --- a/.github/actions/free-space-macos/action.yml +++ b/.github/actions/free-space-macos/action.yml @@ -17,28 +17,30 @@ runs: } strip_universal_deep() { - opwd=$(pwd) - cd $1 - f=$(find . -perm +111 -type f) - for fp in $f - do - if [[ $(file "$fp") == *"universal binary"* ]]; then - if [ "`arch`" == "arm64" ]; then - if [[ $(file "$fp") == *"x86_64"* ]]; then - sudo lipo -remove x86_64 "$fp" -o "$fp" || true - fi - else - if [[ $(file "$fp") == *"arm64e)"* ]]; then - sudo lipo -remove arm64e "$fp" -o "$fp" || true - fi - if [[ $(file "$fp") == *"arm64)"* ]]; then - sudo lipo -remove arm64 "$fp" -o "$fp" || true + if [ -d "$1" ]; then + opwd=$(pwd) + cd $1 + f=$(find . -perm +111 -type f) + for fp in $f + do + if [[ $(file "$fp") == *"universal binary"* ]]; then + if [ "`arch`" == "arm64" ]; then + if [[ $(file "$fp") == *"x86_64"* ]]; then + sudo lipo -remove x86_64 "$fp" -o "$fp" || true + fi + else + if [[ $(file "$fp") == *"arm64e)"* ]]; then + sudo lipo -remove arm64e "$fp" -o "$fp" || true + fi + if [[ $(file "$fp") == *"arm64)"* ]]; then + sudo lipo -remove arm64 "$fp" -o "$fp" || true + fi fi fi - fi - done + done - cd $opwd + cd $opwd + fi } tmpify /Library/Developer/CoreSimulator @@ -60,10 +62,9 @@ runs: sudo rm -rf /Applications/Safari.app sudo rm -rf /Applications/Xcode_16.1.app - sudo rm -rf /Applications/Xcode_16.3.app sudo rm -rf /Applications/Xcode_16.2.app + sudo rm -rf /Applications/Xcode_16.3.app sudo rm -rf /Applications/Google Chrome.app - sudo rm -rf /Applications/Xcode_16.4.app sudo rm -rf /Applications/Google Chrome for Testing.app sudo rm -rf /Applications/Firefox.app sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data diff --git a/.github/actions/install-build-tools/action.yml b/.github/actions/install-build-tools/action.yml index e3ebdd3e81bd7..2dc60d1f0ba5b 100644 --- a/.github/actions/install-build-tools/action.yml +++ b/.github/actions/install-build-tools/action.yml @@ -15,7 +15,7 @@ runs: git config --global core.preloadindex true git config --global core.longpaths true fi - export BUILD_TOOLS_SHA=fb34fbad068586d9a6e2bb4e4950bdcf9aaee862 + export BUILD_TOOLS_SHA=a5d9f9052dcc36ee88bef5c8b13acbefd87b7d8d npm i -g @electron/build-tools # Update depot_tools to ensure python e d update_depot_tools diff --git a/.github/workflows/archaeologist-dig.yml b/.github/workflows/archaeologist-dig.yml index 4be9246226ce8..14180fdc90ea3 100644 --- a/.github/workflows/archaeologist-dig.yml +++ b/.github/workflows/archaeologist-dig.yml @@ -3,19 +3,23 @@ name: Archaeologist on: pull_request: +permissions: {} + jobs: archaeologist-dig: name: Archaeologist Dig runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.0.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: fetch-depth: 0 - name: Setup Node.js/npm - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 with: - node-version: 20.19.x + node-version: 22.21.x - name: Setting Up Dig Site run: | echo "remote: ${{ github.event.pull_request.head.repo.clone_url }}" @@ -41,7 +45,7 @@ jobs: sha-file: .dig-old filename: electron.old.d.ts - name: Upload artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 #v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 #v5.0.0 with: name: artifacts path: electron/artifacts diff --git a/.github/workflows/audit-branch-ci.yml b/.github/workflows/audit-branch-ci.yml index 05c37badd1fd8..47af2dafcc991 100644 --- a/.github/workflows/audit-branch-ci.yml +++ b/.github/workflows/audit-branch-ci.yml @@ -16,11 +16,11 @@ jobs: contents: read steps: - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: 22.17.x - run: npm install @actions/cache@4.0.3 @electron/fiddle-core@2.0.1 - - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 id: audit-errors with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -73,6 +73,7 @@ jobs: annotation_level === "failure" && !message.startsWith("Process completed with exit code") && !message.startsWith("Response status code does not indicate success") && + !message.startsWith("The hosted runner lost communication with the server") && !/Unable to make request/.test(message) && !/The requested URL returned error/.test(message), ) diff --git a/.github/workflows/branch-created.yml b/.github/workflows/branch-created.yml index 87c4aa933b49f..8416afccfff06 100644 --- a/.github/workflows/branch-created.yml +++ b/.github/workflows/branch-created.yml @@ -75,7 +75,7 @@ jobs: org: electron - name: Generate Release Project Board Metadata if: ${{ steps.check-major-version.outputs.MAJOR }} - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 id: generate-project-metadata with: script: | diff --git a/.github/workflows/build-git-cache.yml b/.github/workflows/build-git-cache.yml index 43daf56e5aa36..6e081176cb5d0 100644 --- a/.github/workflows/build-git-cache.yml +++ b/.github/workflows/build-git-cache.yml @@ -6,9 +6,13 @@ on: schedule: - cron: "0 0 * * *" +permissions: {} + jobs: build-git-cache-linux: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1 options: --user root @@ -19,7 +23,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -30,6 +34,8 @@ jobs: build-git-cache-windows: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1 options: --user root --device /dev/fuse --cap-add SYS_ADMIN @@ -41,7 +47,7 @@ jobs: TARGET_OS: 'win' steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -52,6 +58,8 @@ jobs: build-git-cache-macos: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read # This job updates the same git cache as linux, so it needs to run after the linux one. needs: build-git-cache-linux container: @@ -64,7 +72,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7dec7e0a490c9..8418d0b9e1a58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,10 +43,13 @@ defaults: run: shell: bash +permissions: {} + jobs: setup: runs-on: ubuntu-latest permissions: + contents: read pull-requests: read outputs: docs: ${{ steps.filter.outputs.docs }} @@ -54,7 +57,7 @@ jobs: build-image-sha: ${{ steps.set-output.outputs.build-image-sha }} docs-only: ${{ steps.set-output.outputs.docs-only }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.0.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: ref: ${{ github.event.pull_request.head.sha }} - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 @@ -63,6 +66,10 @@ jobs: filters: | docs: - 'docs/**' + - README.md + - SECURITY.md + - CONTRIBUTING.md + - CODE_OF_CONDUCT.md src: - '!docs/**' - name: Set Outputs for Build Image SHA & Docs Only @@ -80,6 +87,8 @@ jobs: needs: setup if: ${{ !inputs.skip-lint }} uses: ./.github/workflows/pipeline-electron-lint.yml + permissions: + contents: read with: container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}' secrets: inherit @@ -89,6 +98,8 @@ jobs: needs: [setup, checkout-linux] if: ${{ needs.setup.outputs.docs-only == 'true' }} uses: ./.github/workflows/pipeline-electron-docs-only.yml + permissions: + contents: read with: container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' secrets: inherit @@ -98,6 +109,8 @@ jobs: needs: setup if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}} runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root @@ -111,7 +124,7 @@ jobs: build-image-sha: ${{ needs.setup.outputs.build-image-sha }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -126,6 +139,8 @@ jobs: needs: setup if: ${{ !inputs.skip-linux}} runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root @@ -141,7 +156,7 @@ jobs: build-image-sha: ${{ needs.setup.outputs.build-image-sha}} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -155,6 +170,8 @@ jobs: needs: setup if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }} runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root --device /dev/fuse --cap-add SYS_ADMIN @@ -171,7 +188,7 @@ jobs: build-image-sha: ${{ needs.setup.outputs.build-image-sha}} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -185,16 +202,20 @@ jobs: # GN Check Jobs macos-gn-check: uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + permissions: + contents: read needs: checkout-macos with: target-platform: macos target-archs: x64 arm64 - check-runs-on: macos-14 + check-runs-on: macos-15 gn-build-type: testing secrets: inherit linux-gn-check: uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + permissions: + contents: read needs: checkout-linux if: ${{ needs.setup.outputs.src == 'true' }} with: @@ -207,6 +228,8 @@ jobs: windows-gn-check: uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml + permissions: + contents: read needs: checkout-windows with: target-platform: win @@ -225,7 +248,7 @@ jobs: uses: ./.github/workflows/pipeline-electron-build-and-test.yml needs: checkout-macos with: - build-runs-on: macos-14-xlarge + build-runs-on: macos-15-xlarge test-runs-on: macos-15-large target-platform: macos target-arch: x64 @@ -244,7 +267,7 @@ jobs: uses: ./.github/workflows/pipeline-electron-build-and-test.yml needs: checkout-macos with: - build-runs-on: macos-14-xlarge + build-runs-on: macos-15-xlarge test-runs-on: macos-15 target-platform: macos target-arch: arm64 @@ -400,6 +423,8 @@ jobs: gha-done: name: GitHub Actions Completed runs-on: ubuntu-latest + permissions: + contents: read needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, windows-x64, windows-x86, windows-arm64] if: always() && !contains(needs.*.result, 'failure') steps: diff --git a/.github/workflows/clean-src-cache.yml b/.github/workflows/clean-src-cache.yml index 9a1bfddccc888..d632ba2d5fa3f 100644 --- a/.github/workflows/clean-src-cache.yml +++ b/.github/workflows/clean-src-cache.yml @@ -1,16 +1,20 @@ name: Clean Source Cache -description: | - This workflow cleans up the source cache on the cross-instance cache volume - to free up space. It runs daily at midnight and clears files older than 15 days. +# Description: +# This workflow cleans up the source cache on the cross-instance cache volume +# to free up space. It runs daily at midnight and clears files older than 15 days. on: schedule: - cron: "0 0 * * *" +permissions: {} + jobs: clean-src-cache: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1 options: --user root diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml index 80066a103a359..3fe344f3c7f33 100644 --- a/.github/workflows/issue-labeled.yml +++ b/.github/workflows/issue-labeled.yml @@ -4,14 +4,15 @@ on: issues: types: [labeled] -permissions: # added using https://github.com/step-security/secure-workflows - contents: read +permissions: {} jobs: issue-labeled-with-status: name: status/{confirmed,reviewed} label added if: github.event.label.name == 'status/confirmed' || github.event.label.name == 'status/reviewed' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 @@ -31,6 +32,8 @@ jobs: name: blocked/* label added if: startsWith(github.event.label.name, 'blocked/') runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 @@ -72,7 +75,7 @@ jobs: creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} - name: Create comment if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }} - uses: actions-cool/issues-helper@50068f49b7b2b3857270ead65e2d02e4459b022c # v3.6.2 + uses: actions-cool/issues-helper@9861779a695cf1898bd984c727f685f351cfc372 # v3.7.2 with: actions: 'create-comment' token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml index 32048864809a4..ae6800d09ace9 100644 --- a/.github/workflows/issue-opened.yml +++ b/.github/workflows/issue-opened.yml @@ -11,6 +11,7 @@ jobs: add-to-issue-triage: if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }} runs-on: ubuntu-latest + permissions: {} steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 @@ -28,6 +29,7 @@ jobs: set-labels: if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }} runs-on: ubuntu-latest + permissions: {} steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 @@ -37,7 +39,7 @@ jobs: org: electron - run: npm install @electron/fiddle-core@1.3.3 mdast-util-from-markdown@2.0.0 unist-util-select@5.1.0 semver@7.6.0 - name: Add labels - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 id: add-labels env: ISSUE_BODY: ${{ github.event.issue.body }} @@ -134,7 +136,7 @@ jobs: } - name: Create unsupported major comment if: ${{ steps.add-labels.outputs.unsupportedMajor }} - uses: actions-cool/issues-helper@50068f49b7b2b3857270ead65e2d02e4459b022c # v3.6.2 + uses: actions-cool/issues-helper@9861779a695cf1898bd984c727f685f351cfc372 # v3.7.2 with: actions: 'create-comment' token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/issue-transferred.yml b/.github/workflows/issue-transferred.yml index 2e5543ae9ec5a..29a9c846a963d 100644 --- a/.github/workflows/issue-transferred.yml +++ b/.github/workflows/issue-transferred.yml @@ -10,6 +10,7 @@ jobs: issue-transferred: name: Issue Transferred runs-on: ubuntu-latest + permissions: {} if: ${{ !github.event.changes.new_repository.private }} steps: - name: Generate GitHub App token diff --git a/.github/workflows/issue-unlabeled.yml b/.github/workflows/issue-unlabeled.yml index a7080a896713d..04067970525fe 100644 --- a/.github/workflows/issue-unlabeled.yml +++ b/.github/workflows/issue-unlabeled.yml @@ -4,14 +4,15 @@ on: issues: types: [unlabeled] -permissions: - contents: read +permissions: {} jobs: issue-unlabeled-blocked: name: All blocked/* labels removed if: startsWith(github.event.label.name, 'blocked/') && github.event.issue.state == 'open' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Check for any blocked labels id: check-for-blocked-labels diff --git a/.github/workflows/linux-publish.yml b/.github/workflows/linux-publish.yml index 5903fc925c4b0..a2dfaa9ee99e2 100644 --- a/.github/workflows/linux-publish.yml +++ b/.github/workflows/linux-publish.yml @@ -17,9 +17,13 @@ on: type: boolean default: false +permissions: {} + jobs: checkout-linux: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:${{ inputs.build-image-sha }} options: --user root @@ -31,7 +35,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -40,6 +44,8 @@ jobs: publish-x64: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-linux with: environment: production-release @@ -55,6 +61,8 @@ jobs: publish-arm: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-linux with: environment: production-release @@ -70,6 +78,8 @@ jobs: publish-arm64: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-linux with: environment: production-release diff --git a/.github/workflows/macos-publish.yml b/.github/workflows/macos-publish.yml index faf1aae291aa1..0a068d98482b9 100644 --- a/.github/workflows/macos-publish.yml +++ b/.github/workflows/macos-publish.yml @@ -18,9 +18,13 @@ on: type: boolean default: false +permissions: {} + jobs: checkout-macos: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:${{ inputs.build-image-sha }} options: --user root @@ -32,7 +36,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -44,10 +48,12 @@ jobs: publish-x64-darwin: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-macos with: environment: production-release - build-runs-on: macos-14-xlarge + build-runs-on: macos-15-xlarge target-platform: macos target-arch: x64 target-variant: darwin @@ -59,10 +65,12 @@ jobs: publish-x64-mas: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-macos with: environment: production-release - build-runs-on: macos-14-xlarge + build-runs-on: macos-15-xlarge target-platform: macos target-arch: x64 target-variant: mas @@ -74,10 +82,12 @@ jobs: publish-arm64-darwin: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-macos with: environment: production-release - build-runs-on: macos-14-xlarge + build-runs-on: macos-15-xlarge target-platform: macos target-arch: arm64 target-variant: darwin @@ -89,10 +99,12 @@ jobs: publish-arm64-mas: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-macos with: environment: production-release - build-runs-on: macos-14-xlarge + build-runs-on: macos-15-xlarge target-platform: macos target-arch: arm64 target-variant: mas diff --git a/.github/workflows/pipeline-electron-build-and-test-and-nan.yml b/.github/workflows/pipeline-electron-build-and-test-and-nan.yml index f4a7ec5243566..8ba78ac23fb3b 100644 --- a/.github/workflows/pipeline-electron-build-and-test-and-nan.yml +++ b/.github/workflows/pipeline-electron-build-and-test-and-nan.yml @@ -55,6 +55,8 @@ on: type: boolean default: false +permissions: {} + concurrency: group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} cancel-in-progress: ${{ github.ref_protected != true }} @@ -62,6 +64,8 @@ concurrency: jobs: build: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read with: build-runs-on: ${{ inputs.build-runs-on }} build-container: ${{ inputs.build-container }} @@ -74,6 +78,10 @@ jobs: secrets: inherit test: uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read needs: build with: target-arch: ${{ inputs.target-arch }} @@ -83,6 +91,8 @@ jobs: secrets: inherit nn-test: uses: ./.github/workflows/pipeline-segment-node-nan-test.yml + permissions: + contents: read needs: build with: target-arch: ${{ inputs.target-arch }} diff --git a/.github/workflows/pipeline-electron-build-and-test.yml b/.github/workflows/pipeline-electron-build-and-test.yml index ee043fb31795f..258bd969d767a 100644 --- a/.github/workflows/pipeline-electron-build-and-test.yml +++ b/.github/workflows/pipeline-electron-build-and-test.yml @@ -64,14 +64,13 @@ concurrency: group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} cancel-in-progress: ${{ github.ref_protected != true }} -permissions: - contents: read - issues: read - pull-requests: read +permissions: {} jobs: build: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read with: build-runs-on: ${{ inputs.build-runs-on }} build-container: ${{ inputs.build-container }} @@ -86,6 +85,10 @@ jobs: secrets: inherit test: uses: ./.github/workflows/pipeline-segment-electron-test.yml + permissions: + contents: read + issues: read + pull-requests: read needs: build with: target-arch: ${{ inputs.target-arch }} diff --git a/.github/workflows/pipeline-electron-docs-only.yml b/.github/workflows/pipeline-electron-docs-only.yml index a1d2dc5256163..548950a63eea4 100644 --- a/.github/workflows/pipeline-electron-docs-only.yml +++ b/.github/workflows/pipeline-electron-docs-only.yml @@ -8,6 +8,8 @@ on: description: 'Container to run the docs-only ts compile in' type: string +permissions: {} + concurrency: group: electron-docs-only-${{ github.ref }} cancel-in-progress: true @@ -19,11 +21,13 @@ jobs: docs-only: name: Docs Only Compile runs-on: electron-arc-centralus-linux-amd64-4core + permissions: + contents: read timeout-minutes: 20 container: ${{ fromJSON(inputs.container) }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -39,7 +43,7 @@ jobs: with: target-platform: linux - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 diff --git a/.github/workflows/pipeline-electron-lint.yml b/.github/workflows/pipeline-electron-lint.yml index 7c1b27d0a33b8..e8d570da0737d 100644 --- a/.github/workflows/pipeline-electron-lint.yml +++ b/.github/workflows/pipeline-electron-lint.yml @@ -8,6 +8,8 @@ on: description: 'Container to run lint in' type: string +permissions: {} + concurrency: group: electron-lint-${{ github.ref_protected == true && github.run_id || github.ref }} cancel-in-progress: ${{ github.ref_protected != true }} @@ -19,11 +21,13 @@ jobs: lint: name: Lint runs-on: electron-arc-centralus-linux-amd64-4core + permissions: + contents: read timeout-minutes: 20 container: ${{ fromJSON(inputs.container) }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 diff --git a/.github/workflows/pipeline-segment-electron-build.yml b/.github/workflows/pipeline-segment-electron-build.yml index b634e2b675700..e48e24892e979 100644 --- a/.github/workflows/pipeline-segment-electron-build.yml +++ b/.github/workflows/pipeline-segment-electron-build.yml @@ -59,6 +59,8 @@ on: type: boolean default: false +permissions: {} + concurrency: group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }} cancel-in-progress: ${{ github.ref_protected != true }} @@ -66,6 +68,7 @@ concurrency: env: CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }} ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }} SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }} @@ -80,16 +83,19 @@ jobs: run: shell: bash runs-on: ${{ inputs.build-runs-on }} + permissions: + contents: read container: ${{ fromJSON(inputs.build-container) }} environment: ${{ inputs.environment }} env: TARGET_ARCH: ${{ inputs.target-arch }} + TARGET_PLATFORM: ${{ inputs.target-platform }} steps: - name: Create src dir run: | mkdir src - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -113,9 +119,9 @@ jobs: run: df -h - name: Setup Node.js/npm if: ${{ inputs.target-platform == 'macos' }} - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 with: - node-version: 20.19.x + node-version: 22.21.x cache: yarn cache-dependency-path: src/electron/yarn.lock - name: Install Dependencies @@ -157,7 +163,7 @@ jobs: if: ${{ inputs.target-platform == 'linux' }} uses: ./src/electron/.github/actions/restore-cache-aks - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 diff --git a/.github/workflows/pipeline-segment-electron-gn-check.yml b/.github/workflows/pipeline-segment-electron-gn-check.yml index 48fe703078145..cb78b735ec24d 100644 --- a/.github/workflows/pipeline-segment-electron-gn-check.yml +++ b/.github/workflows/pipeline-segment-electron-gn-check.yml @@ -26,6 +26,8 @@ on: type: string default: testing +permissions: {} + concurrency: group: electron-gn-check-${{ inputs.target-platform }}-${{ github.ref }} cancel-in-progress: true @@ -41,10 +43,12 @@ jobs: run: shell: bash runs-on: ${{ inputs.check-runs-on }} + permissions: + contents: read container: ${{ fromJSON(inputs.check-container) }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -111,7 +115,7 @@ jobs: - name: Add CHROMIUM_BUILDTOOLS_PATH to env run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 diff --git a/.github/workflows/pipeline-segment-electron-test.yml b/.github/workflows/pipeline-segment-electron-test.yml index 7f4417f3bd433..3b26f807291c5 100644 --- a/.github/workflows/pipeline-segment-electron-test.yml +++ b/.github/workflows/pipeline-segment-electron-test.yml @@ -35,10 +35,7 @@ concurrency: group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }} cancel-in-progress: ${{ github.ref_protected != true }} -permissions: - contents: read - issues: read - pull-requests: read +permissions: {} env: CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }} @@ -53,6 +50,10 @@ jobs: run: shell: bash runs-on: ${{ inputs.test-runs-on }} + permissions: + contents: read + issues: read + pull-requests: read container: ${{ fromJSON(inputs.test-container) }} strategy: fail-fast: false @@ -68,11 +69,12 @@ jobs: if: ${{ inputs.target-arch == 'arm' && inputs.target-platform == 'linux' }} run: | cp $(which node) /mnt/runner-externals/node20/bin/ + cp $(which node) /mnt/runner-externals/node24/bin/ - name: Setup Node.js/npm if: ${{ inputs.target-platform == 'win' }} - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 with: - node-version: 20.19.x + node-version: 22.21.x - name: Add TCC permissions on macOS if: ${{ inputs.target-platform == 'macos' }} run: | @@ -110,11 +112,6 @@ jobs: configure_sys_tccdb "$values" fi done - - # Ref: https://github.com/getsentry/sentry-cocoa/blob/main/scripts/ci-enable-permissions.sh - if [ "$OSTYPE" = "darwin24" ]; then - defaults write ~/Library/Group\ Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist "/bin/bash" -date "3024-09-23 12:00:00 +0000" - fi - name: Turn off the unexpectedly quit dialog on macOS if: ${{ inputs.target-platform == 'macos' }} run: defaults write com.apple.CrashReporter DialogType server @@ -122,11 +119,17 @@ jobs: if: ${{ inputs.target-platform == 'macos' }} run: sudo xcode-select --switch /Applications/Xcode_16.4.app - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} + - name: Turn off screenshot nag on macOS + if: ${{ inputs.target-platform == 'macos' }} + run: | + defaults write ~/Library/Group\ Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist "/bin/bash" -date "3024-09-23 12:00:00 +0000" + src/electron/script/actions/screencapture-nag-remover.sh -a $(which bash) + src/electron/script/actions/screencapture-nag-remover.sh -a /opt/hca/hosted-compute-agent - name: Setup SSH Debugging if: ${{ inputs.target-platform == 'macos' && (inputs.enable-ssh || env.ACTIONS_STEP_DEBUG == 'true') }} uses: ./src/electron/.github/actions/ssh-debug @@ -165,33 +168,29 @@ jobs: echo "DISABLE_CRASH_REPORTER_TESTS=true" >> $GITHUB_ENV echo "IS_ASAN=true" >> $GITHUB_ENV - name: Download Generated Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: generated_artifacts_${{ env.ARTIFACT_KEY }} path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }} - name: Download Src Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: src_artifacts_${{ env.ARTIFACT_KEY }} path: ./src_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }} - name: Restore Generated Artifacts run: ./src/electron/script/actions/restore-artifacts.sh - - name: Unzip Dist, Mksnapshot & Chromedriver (win) + - name: Unzip Dist (win) if: ${{ inputs.target-platform == 'win' }} shell: powershell run: | Set-ExecutionPolicy Bypass -Scope Process -Force cd src/out/Default Expand-Archive -Force dist.zip -DestinationPath ./ - Expand-Archive -Force chromedriver.zip -DestinationPath ./ - Expand-Archive -Force mksnapshot.zip -DestinationPath ./ - - name: Unzip Dist, Mksnapshot & Chromedriver (unix) + - name: Unzip Dist (unix) if: ${{ inputs.target-platform != 'win' }} run: | cd src/out/Default unzip -:o dist.zip - unzip -:o chromedriver.zip - unzip -:o mksnapshot.zip #- name: Import & Trust Self-Signed Codesigning Cert on MacOS # if: ${{ inputs.target-platform == 'macos' && inputs.target-arch == 'x64' }} # run: | @@ -227,7 +226,7 @@ jobs: export ELECTRON_FORCE_TEST_SUITE_EXIT="true" fi fi - node script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files + node script/yarn test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files else chown :builduser .. && chmod g+w .. chown -R :builduser . && chmod -R g+w . @@ -264,7 +263,7 @@ jobs: if: always() && !cancelled() - name: Upload Test Artifacts if: always() && !cancelled() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 with: name: test_artifacts_${{ env.ARTIFACT_KEY }}_${{ matrix.shard }} path: src/electron/spec/artifacts diff --git a/.github/workflows/pipeline-segment-node-nan-test.yml b/.github/workflows/pipeline-segment-node-nan-test.yml index 568754a862001..a79cb452c7396 100644 --- a/.github/workflows/pipeline-segment-node-nan-test.yml +++ b/.github/workflows/pipeline-segment-node-nan-test.yml @@ -26,6 +26,8 @@ on: type: string default: testing +permissions: {} + concurrency: group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }} cancel-in-progress: ${{ github.ref_protected != true }} @@ -39,6 +41,8 @@ jobs: node-tests: name: Run Node.js Tests runs-on: electron-arc-centralus-linux-amd64-8core + permissions: + contents: read timeout-minutes: 30 env: TARGET_ARCH: ${{ inputs.target-arch }} @@ -46,7 +50,7 @@ jobs: container: ${{ fromJSON(inputs.test-container) }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -61,12 +65,12 @@ jobs: - name: Install Dependencies uses: ./src/electron/.github/actions/install-dependencies - name: Download Generated Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} - name: Download Src Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: src_artifacts_linux_${{ env.TARGET_ARCH }} path: ./src_artifacts_linux_${{ env.TARGET_ARCH }} @@ -93,6 +97,8 @@ jobs: nan-tests: name: Run Nan Tests runs-on: electron-arc-centralus-linux-amd64-4core + permissions: + contents: read timeout-minutes: 30 env: TARGET_ARCH: ${{ inputs.target-arch }} @@ -100,7 +106,7 @@ jobs: container: ${{ fromJSON(inputs.test-container) }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -115,12 +121,12 @@ jobs: - name: Install Dependencies uses: ./src/electron/.github/actions/install-dependencies - name: Download Generated Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }} - name: Download Src Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: src_artifacts_linux_${{ env.TARGET_ARCH }} path: ./src_artifacts_linux_${{ env.TARGET_ARCH }} diff --git a/.github/workflows/pull-request-labeled.yml b/.github/workflows/pull-request-labeled.yml index 51bfcb86705f5..129280ba2364f 100644 --- a/.github/workflows/pull-request-labeled.yml +++ b/.github/workflows/pull-request-labeled.yml @@ -11,6 +11,7 @@ jobs: name: backport/requested label added if: github.event.label.name == 'backport/requested 🗳' runs-on: ubuntu-latest + permissions: {} steps: - name: Trigger Slack workflow uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 @@ -19,12 +20,16 @@ jobs: webhook-type: webhook-trigger payload: | { - "url": "${{ github.event.pull_request.html_url }}" + "base_ref": ${{ toJSON(github.event.pull_request.base.ref) }}, + "title": ${{ toJSON(github.event.pull_request.title) }}, + "url": ${{ toJSON(github.event.pull_request.html_url) }}, + "user": ${{ toJSON(github.event.pull_request.user.login) }} } pull-request-labeled-deprecation-review-complete: name: deprecation-review/complete label added if: github.event.label.name == 'deprecation-review/complete ✅' runs-on: ubuntu-latest + permissions: {} steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index bf2c12e61e3ec..e24c43fdcf4fc 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -22,13 +22,13 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false # This is a pre-submit / pre-release. - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif @@ -42,7 +42,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 with: sarif_file: results.sarif diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml index 56e07e2f0aa97..92abda9930c34 100644 --- a/.github/workflows/semantic.yml +++ b/.github/workflows/semantic.yml @@ -7,8 +7,7 @@ on: - edited - synchronize -permissions: - contents: read +permissions: {} jobs: main: diff --git a/.github/workflows/stable-prep-items.yml b/.github/workflows/stable-prep-items.yml index 576ddbc16c8b9..963a69ad17a12 100644 --- a/.github/workflows/stable-prep-items.yml +++ b/.github/workflows/stable-prep-items.yml @@ -11,6 +11,7 @@ jobs: check-stable-prep-items: name: Check Stable Prep Items runs-on: ubuntu-latest + permissions: {} steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 7fd2e20fa5e5c..498489c0db33a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,13 +10,14 @@ permissions: {} jobs: stale: runs-on: ubuntu-latest + permissions: {} steps: - name: Generate GitHub App token uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1 id: generate-token with: creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} - - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # tag: v9.1.0 + - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # tag: v10.1.0 with: repo-token: ${{ steps.generate-token.outputs.token }} days-before-stale: 90 @@ -27,10 +28,11 @@ jobs: This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment! close-issue-message: > This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue. - exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:,status/confirmed,stale-exempt,upgrade-follow-up" + exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:,status/confirmed,stale-exempt,upgrade-follow-up,tracking-upstream" only-pr-labels: not-a-real-label pending-repro: runs-on: ubuntu-latest + permissions: {} if: ${{ always() }} needs: stale steps: @@ -39,7 +41,7 @@ jobs: id: generate-token with: creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} - - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # tag: v9.1.0 + - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # tag: v10.1.0 with: repo-token: ${{ steps.generate-token.outputs.token }} days-before-stale: -1 diff --git a/.github/workflows/windows-publish.yml b/.github/workflows/windows-publish.yml index b72e045d7679d..5fe757a4b6b28 100644 --- a/.github/workflows/windows-publish.yml +++ b/.github/workflows/windows-publish.yml @@ -18,9 +18,13 @@ on: type: boolean default: false +permissions: {} + jobs: checkout-windows: runs-on: electron-arc-centralus-linux-amd64-32core + permissions: + contents: read container: image: ghcr.io/electron/build:${{ inputs.build-image-sha }} options: --user root --device /dev/fuse --cap-add SYS_ADMIN @@ -36,7 +40,7 @@ jobs: build-image-sha: ${{ inputs.build-image-sha }} steps: - name: Checkout Electron - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: path: src/electron fetch-depth: 0 @@ -48,6 +52,8 @@ jobs: publish-x64-win: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-windows with: environment: production-release @@ -62,6 +68,8 @@ jobs: publish-arm64-win: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-windows with: environment: production-release @@ -76,6 +84,8 @@ jobs: publish-x86-win: uses: ./.github/workflows/pipeline-segment-electron-build.yml + permissions: + contents: read needs: checkout-windows with: environment: production-release diff --git a/.nvmrc b/.nvmrc index 209e3ef4b6247..2bd5a0a98a36c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20 +22 diff --git a/BUILD.gn b/BUILD.gn index 1d274958b48f2..da572f0924478 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -480,6 +480,7 @@ source_set("electron_lib") { "//device/bluetooth", "//device/bluetooth/public/cpp", "//gin", + "//gpu/ipc/client", "//media/capture/mojom:video_capture", "//media/mojo/mojom", "//media/mojo/mojom:web_speech_recognition", @@ -586,7 +587,13 @@ source_set("electron_lib") { } if (is_mac) { + # Disable C++ modules to resolve linking error when including MacOS SDK + # headers from third_party/electron_node/deps/uv/include/uv/darwin.h + # TODO(samuelmaddock): consider revisiting this in the future + use_libcxx_modules = false + deps += [ + "//components/os_crypt/common:keychain_password_mac", "//components/remote_cocoa/app_shim", "//components/remote_cocoa/browser", "//content/browser:mac_helpers", @@ -655,6 +662,7 @@ source_set("electron_lib") { "//ui/events/devices/x11", "//ui/events/platform/x11", "//ui/gtk:gtk_config", + "//ui/linux:display_server_utils", "//ui/linux:linux_ui", "//ui/linux:linux_ui_factory", "//ui/wm", @@ -688,7 +696,6 @@ source_set("electron_lib") { "//components/app_launch_prefetch", "//components/crash/core/app:crash_export_thunks", "//third_party/libxml:xml_writer", - "//ui/native_theme:native_theme_browser", "//ui/wm", "//ui/wm/public", ] @@ -755,11 +762,13 @@ source_set("electron_lib") { if (enable_pdf_viewer) { deps += [ "//chrome/browser/resources/pdf:resources", + "//chrome/browser/ui:browser_element_identifiers", "//components/pdf/browser", "//components/pdf/browser:interceptors", "//components/pdf/common:constants", "//components/pdf/common:util", "//components/pdf/renderer", + "//components/user_education/webui", "//pdf", "//pdf:content_restriction", ] @@ -1619,6 +1628,29 @@ group("node_headers") { public_deps = [ ":tar_node_headers" ] } +group("testing_build") { + public_deps = [ + ":electron_dist_zip", + ":electron_mksnapshot_zip", + ":node_headers", + ] +} + +group("release_build") { + public_deps = [ ":testing_build" ] + if (is_official_build) { + public_deps += [ ":electron_symbols" ] + } + if (is_linux) { + public_deps += [ + ":hunspell_dictionaries_zip", + ":libcxx_headers_zip", + ":libcxx_objects_zip", + ":libcxxabi_headers_zip", + ] + } +} + if (is_linux && is_official_build) { strip_binary("strip_electron_binary") { binary_input = "$root_out_dir/$electron_project_name" diff --git a/DEPS b/DEPS index dc72d1a147352..32f76a74fe45b 100644 --- a/DEPS +++ b/DEPS @@ -2,17 +2,17 @@ gclient_gn_args_from = 'src' vars = { 'chromium_version': - '141.0.7361.0', + '144.0.7526.0', 'node_version': - 'v22.18.0', + 'v24.11.0', 'nan_version': - 'e14bdcd1f72d62bca1d541b66da43130384ec213', + '675cefebca42410733da8a454c8d9391fcebfbc2', 'squirrel.mac_version': '0e5d146ba13101a1302d59ea6e6e0b3cace4ae38', 'reactiveobjc_version': '74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76', 'mantle_version': - '78d3966b3c331292ea29ec38661b25df0a245948', + '2a8e2123a3931038179ee06105c9e6ec336b12ea', 'engflow_reclient_configs_version': '955335c30a752e9ef7bff375baab5e0819b6c00d', diff --git a/README.md b/README.md index 2ab98ce41009b..cf69aaa75182d 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,9 @@ For more installation options and troubleshooting tips, see Each Electron release provides binaries for macOS, Windows, and Linux. -* macOS (Big Sur and up): Electron provides 64-bit Intel and Apple Silicon / ARM binaries for macOS. +* macOS (Monterey and up): Electron provides 64-bit Intel and Apple Silicon / ARM binaries for macOS. * Windows (Windows 10 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. Support for Windows 7, 8 and 8.1 was [removed in Electron 23, in line with Chromium's Windows deprecation policy](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice). -* Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on: +* Linux: The prebuilt binaries of Electron are built on Ubuntu 22.04. They have also been verified to work on: * Ubuntu 18.04 and newer * Fedora 32 and newer * Debian 10 and newer diff --git a/SECURITY.md b/SECURITY.md index ebf5d628d18ee..7b1e3dd46a025 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,6 +8,12 @@ The Electron team will send a response indicating the next steps in handling you Report security bugs in third-party modules to the person or team maintaining the module. You can also report a vulnerability through the [npm contact form](https://www.npmjs.com/support) by selecting "I'm reporting a security vulnerability". +## Escalation + +If you do not receive an acknowledgement of your report within 6 business days, or if you cannot find a private security contact for the project, you may escalate to the OpenJS Foundation CNA at `security@lists.openjsf.org`. + +If the project acknowledges your report but does not provide any further response or engagement within 14 days, escalation is also appropriate. + ## The Electron Security Notification Process For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md) Governance document. diff --git a/build/args/all.gn b/build/args/all.gn index 80c3e44e9d6a1..b62e24774ded3 100644 --- a/build/args/all.gn +++ b/build/args/all.gn @@ -2,7 +2,7 @@ is_electron_build = true root_extra_deps = [ "//electron" ] # Registry of NMVs --> https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json -node_module_version = 140 +node_module_version = 143 v8_promise_internal_field_count = 1 v8_embedder_string = "-electron.0" @@ -19,15 +19,15 @@ proprietary_codecs = true enable_printing = true +# Refs https://chromium-review.googlesource.com/c/chromium/src/+/6986517 +# CI is using MacOS 15.5 which doesn't have the required modulemaps. +use_clang_modules = false + # Removes DLLs from the build, which are only meant to be used for Chromium development. # See https://github.com/electron/electron/pull/17985 angle_enable_vulkan_validation_layers = false dawn_enable_vulkan_validation_layers = false -# Removes dxc dll's that are only used experimentally. -# See https://bugs.chromium.org/p/chromium/issues/detail?id=1474897 -dawn_use_built_dxc = false - # These are disabled because they cause the zip manifest to differ between # testing and release builds. # See https://chromium-review.googlesource.com/c/chromium/src/+/2774898. @@ -72,3 +72,6 @@ enterprise_cloud_content_analysis = false # We don't use anything from here, and it causes target collisions enable_linux_installer = false + +# Disable "Save to Drive" feature in PDF viewer +enable_pdf_save_to_drive = false diff --git a/build/checksum_header.py b/build/checksum_header.py index 9f98c510ee8ef..86237e8885557 100644 --- a/build/checksum_header.py +++ b/build/checksum_header.py @@ -12,7 +12,7 @@ namespace electron::snapshot_checksum { -const std::string kChecksum = "{checksum}"; +inline constexpr std::string_view kChecksum = "{checksum}"; } // namespace electron::snapshot_checksum diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index 2acef923561bf..36dd0ea29d705 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -23,6 +23,8 @@ static_library("chrome") { "//chrome/browser/browser_process.h", "//chrome/browser/devtools/devtools_contents_resizing_strategy.cc", "//chrome/browser/devtools/devtools_contents_resizing_strategy.h", + "//chrome/browser/devtools/devtools_dispatch_http_request_params.cc", + "//chrome/browser/devtools/devtools_dispatch_http_request_params.h", "//chrome/browser/devtools/devtools_embedder_message_dispatcher.cc", "//chrome/browser/devtools/devtools_embedder_message_dispatcher.h", "//chrome/browser/devtools/devtools_eye_dropper.cc", @@ -381,6 +383,8 @@ static_library("chrome") { "//chrome/browser/pdf/chrome_pdf_stream_delegate.h", "//chrome/browser/pdf/pdf_extension_util.cc", "//chrome/browser/pdf/pdf_extension_util.h", + "//chrome/browser/pdf/pdf_help_bubble_handler_factory.cc", + "//chrome/browser/pdf/pdf_help_bubble_handler_factory.h", "//chrome/browser/pdf/pdf_viewer_stream_manager.cc", "//chrome/browser/pdf/pdf_viewer_stream_manager.h", "//chrome/browser/plugins/pdf_iframe_navigation_throttle.cc", @@ -389,6 +393,8 @@ static_library("chrome") { deps += [ "//components/pdf/browser", "//components/pdf/renderer", + "//ui/base/interaction", + "//ui/webui/resources/cr_components/help_bubble:mojo_bindings", ] } } else { diff --git a/docs/README.md b/docs/README.md index 02d5d1331ca29..3af381dc56347 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,10 +37,11 @@ an issue: * [Represented File for macOS BrowserWindows](tutorial/represented-file.md) * [Native File Drag & Drop](tutorial/native-file-drag-drop.md) * [Navigation History](tutorial/navigation-history.md) + * [Window State Persistence](tutorial/window-state-persistence.md) * [Offscreen Rendering](tutorial/offscreen-rendering.md) * [Dark Mode](tutorial/dark-mode.md) * [Web embeds in Electron](tutorial/web-embeds.md) -* [Boilerplates and CLIs](tutorial/boilerplates-and-clis.md) + * [Boilerplates and CLIs](tutorial/boilerplates-and-clis.md) * [Boilerplate vs CLI](tutorial/boilerplates-and-clis.md#boilerplate-vs-cli) * [Electron Forge](tutorial/boilerplates-and-clis.md#electron-forge) * [electron-builder](tutorial/boilerplates-and-clis.md#electron-builder) diff --git a/docs/api/app.md b/docs/api/app.md index 9dcb4835aaded..d27cc46ad194e 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -421,6 +421,7 @@ Returns: * `oom` - Process ran out of memory * `launch-failed` - Process never successfully launched * `integrity-failure` - Windows code integrity checks failed + * `memory-eviction` - Process proactively terminated to prevent a future out-of-memory (OOM) situation * `exitCode` number - The exit code for the process (e.g. status from waitpid if on POSIX, from GetExitCodeProcess on Windows). * `serviceName` string (optional) - The non-localized name of the process. @@ -564,8 +565,9 @@ and subscribing to the `ready` event if the app is not ready yet. * `steal` boolean _macOS_ - Make the receiver the active app even if another app is currently active. -On Linux, focuses on the first visible window. On macOS, makes the application -the active app. On Windows, focuses on the application's first window. +On macOS, makes the application the active app. On Windows, focuses on the application's +first window. On Linux, either focuses on the first visible window (X11) or requests +focus but may instead show a notification or flash the app icon (Wayland). You should seek to use the `steal` option as sparingly as possible. @@ -1214,6 +1216,13 @@ Disables hardware acceleration for current app. This method can only be called before app is ready. +### `app.isHardwareAccelerationEnabled()` + +Returns `boolean` - whether hardware acceleration is currently enabled. + + > [!NOTE] + > This information is only usable after the `gpu-info-update` event is emitted. + ### `app.disableDomainBlockingFor3DAPIs()` By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per @@ -1397,7 +1406,75 @@ details. Disabled by default. This API must be called after the `ready` event is emitted. > [!NOTE] -> Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. +> Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. Calling this method will enable the following accessibility support features: `nativeAPIs`, `webContents`, `inlineTextBoxes`, and `extendedProperties`. + +### `app.getAccessibilitySupportFeatures()` _macOS_ _Windows_ + +Returns `string[]` - Array of strings naming currently enabled accessibility support components. Possible values: + +* `nativeAPIs` - Native OS accessibility APIs integration enabled. +* `webContents` - Web contents accessibility tree exposure enabled. +* `inlineTextBoxes` - Inline text boxes (character bounding boxes) enabled. +* `extendedProperties` - Extended accessibility properties enabled. +* `screenReader` - Screen reader specific mode enabled. +* `html` - HTML accessibility tree construction enabled. +* `labelImages` - Accessibility support for automatic image annotations. +* `pdfPrinting` - Accessibility support for PDF printing enabled. + +Notes: + +* The array may be empty if no accessibility modes are active. +* Use `app.isAccessibilitySupportEnabled()` for the legacy boolean check; + prefer this method for granular diagnostics or telemetry. + +Example: + +```js +const { app } = require('electron') + +app.whenReady().then(() => { + if (app.getAccessibilitySupportFeatures().includes('screenReader')) { + // Change some app UI to better work with Screen Readers. + } +}) +``` + +### `app.setAccessibilitySupportFeatures(features)` _macOS_ _Windows_ + +* `features` string[] - An array of the accessibility features to enable. + +Possible values are: + +* `nativeAPIs` - Native OS accessibility APIs integration enabled. +* `webContents` - Web contents accessibility tree exposure enabled. +* `inlineTextBoxes` - Inline text boxes (character bounding boxes) enabled. +* `extendedProperties` - Extended accessibility properties enabled. +* `screenReader` - Screen reader specific mode enabled. +* `html` - HTML accessibility tree construction enabled. +* `labelImages` - Accessibility support for automatic image annotations. +* `pdfPrinting` - Accessibility support for PDF printing enabled. + +To disable all supported features, pass an empty array `[]`. + +Example: + +```js +const { app } = require('electron') + +app.whenReady().then(() => { + // Enable a subset of features: + app.setAccessibilitySupportFeatures([ + 'screenReader', + 'pdfPrinting', + 'webContents' + ]) + + // Other logic + + // Some time later, disable all features: + app.setAccessibilitySupportFeatures([]) +}) +``` ### `app.showAboutPanel()` diff --git a/docs/api/base-window.md b/docs/api/base-window.md index a4520c1c57482..9bcbfdc48a03d 100644 --- a/docs/api/base-window.md +++ b/docs/api/base-window.md @@ -369,6 +369,15 @@ Calling `event.preventDefault()` will prevent the menu from being displayed. To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows-linux). +#### Event: 'restored-persisted-state' + +Emitted after the persisted window state has been restored. + +Window state includes the window bounds (x, y, height, width) and display mode (maximized, fullscreen, kiosk). + +> [!NOTE] +> This event is only emitted when [windowStatePersistence](structures/window-state-persistence.md) is enabled in [BaseWindowConstructorOptions](structures/base-window-options.md) or in [BrowserWindowConstructorOptions](structures/browser-window-options.md). + ### Static Methods The `BaseWindow` class has the following static methods: @@ -387,6 +396,14 @@ Returns `BaseWindow | null` - The window that is focused in this application, ot Returns `BaseWindow | null` - The window with the given `id`. +#### `BaseWindow.clearPersistedState(name)` + +* `name` string - The window `name` to clear state for (see [BaseWindowConstructorOptions](structures/base-window-options.md)). + +Clears the saved state for a window with the given name. This removes all persisted window bounds, display mode, and work area information that was previously saved when `windowStatePersistence` was enabled. + +If the window `name` is empty or the window state doesn't exist, the method will log a warning. + ### Instance Properties Objects created with `new BaseWindow` have the following properties: @@ -1262,15 +1279,16 @@ Sets the properties for the window's taskbar button. #### `win.setAccentColor(accentColor)` _Windows_ -* `accentColor` boolean | string - The accent color for the window. By default, follows user preference in System Settings. +* `accentColor` boolean | string | null - The accent color for the window. By default, follows user preference in System Settings. To reset to system default, pass `null`. Sets the system accent color and highlighting of active window border. The `accentColor` parameter accepts the following values: -* **Color string** - Sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque. -* **`true`** - Uses the system's default accent color from user preferences in System Settings. -* **`false`** - Explicitly disables accent color highlighting for the window. +* **Color string** - Like `true`, but sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque. +* **`true`** - Enable accent color highlighting for the window with the system accent color regardless of whether accent colors are enabled for windows in System `Settings.` +* **`false`** - Disable accent color highlighting for the window regardless of whether accent colors are currently enabled for windows in System Settings. +* **`null`** - Reset window accent color behavior to follow behavior set in System Settings. Examples: @@ -1283,11 +1301,14 @@ win.setAccentColor('#ff0000') // RGB format (alpha ignored if present). win.setAccentColor('rgba(255,0,0,0.5)') -// Use system accent color. +// Enable accent color, using the color specified in System Settings. win.setAccentColor(true) // Disable accent color. win.setAccentColor(false) + +// Reset window accent color behavior to follow behavior set in System Settings. +win.setAccentColor(null) ``` #### `win.getAccentColor()` _Windows_ diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 4578ca0713851..598c9e428d4fa 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -140,6 +140,10 @@ state is `hidden` in order to minimize power consumption. move. * On Linux the type of modal windows will be changed to `dialog`. * On Linux many desktop environments do not support hiding a modal window. +* On Wayland (Linux) it is generally not possible to programmatically resize windows + after creation, or to position, move, focus, or blur windows without user input. + If your app needs these capabilities, run it in Xwayland by appending the flag + `--ozone-platform=x11`. ## Class: BrowserWindow extends `BaseWindow` @@ -656,10 +660,15 @@ the [close event](#event-close). Focuses on the window. +On Wayland (Linux), the desktop environment may show a notification or flash +the app icon if the window or app is not already focused. + #### `win.blur()` Removes focus from the window. +Not supported on Wayland (Linux). + #### `win.isFocused()` Returns `boolean` - Whether the window is focused. @@ -676,6 +685,8 @@ Shows and gives focus to the window. Shows the window but doesn't focus on it. +Not supported on Wayland (Linux). + #### `win.hide()` Hides the window. @@ -824,6 +835,8 @@ Closes the currently open [Quick Look][quick-look] panel. Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values. +On Wayland (Linux), has the same limitations as `setSize` and `setPosition`. + ```js const { BrowserWindow } = require('electron') @@ -866,6 +879,8 @@ See [Setting `backgroundColor`](#setting-the-backgroundcolor-property). Resizes and moves the window's client area (e.g. the web page) to the supplied bounds. +On Wayland (Linux), has the same limitations as `setContentSize` and `setPosition`. + #### `win.getContentBounds()` Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window's client area as `Object`. @@ -895,6 +910,8 @@ Returns `boolean` - whether the window is enabled. Resizes the window to `width` and `height`. If `width` or `height` are below any set minimum size constraints the window will snap to its minimum size. +On Wayland (Linux), may not work as some window managers restrict programmatic window resizing. + #### `win.getSize()` Returns `Integer[]` - Contains the window's width and height. @@ -907,6 +924,8 @@ Returns `Integer[]` - Contains the window's width and height. Resizes the window's client area (e.g. the web page) to `width` and `height`. +On Wayland (Linux), may not work as some window managers restrict programmatic window resizing. + #### `win.getContentSize()` Returns `Integer[]` - Contains the window's client area's width and height. @@ -1044,12 +1063,16 @@ this method throws an error. #### `win.moveTop()` -Moves window to top(z-order) regardless of focus +Moves window to top(z-order) regardless of focus. + +Not supported on Wayland (Linux). #### `win.center()` Moves window to the center of the screen. +Not supported on Wayland (Linux). + #### `win.setPosition(x, y[, animate])` * `x` Integer @@ -1058,6 +1081,8 @@ Moves window to the center of the screen. Moves window to `x` and `y`. +Not supported on Wayland (Linux). + #### `win.getPosition()` Returns `Integer[]` - Contains the window's current position. @@ -1442,15 +1467,16 @@ Sets the properties for the window's taskbar button. #### `win.setAccentColor(accentColor)` _Windows_ -* `accentColor` boolean | string - The accent color for the window. By default, follows user preference in System Settings. +* `accentColor` boolean | string | null - The accent color for the window. By default, follows user preference in System Settings. To reset to system default, pass `null`. Sets the system accent color and highlighting of active window border. The `accentColor` parameter accepts the following values: -* **Color string** - Sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque. -* **`true`** - Uses the system's default accent color from user preferences in System Settings. -* **`false`** - Explicitly disables accent color highlighting for the window. +* **Color string** - Like `true`, but sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque. +* **`true`** - Enable accent color highlighting for the window with the system accent color regardless of whether accent colors are enabled for windows in System `Settings.` +* **`false`** - Disable accent color highlighting for the window regardless of whether accent colors are currently enabled for windows in System Settings. +* **`null`** - Reset window accent color behavior to follow behavior set in System Settings. Examples: @@ -1463,11 +1489,14 @@ win.setAccentColor('#ff0000') // RGB format (alpha ignored if present). win.setAccentColor('rgba(255,0,0,0.5)') -// Use system accent color. +// Enable accent color, using the color specified in System Settings. win.setAccentColor(true) // Disable accent color. win.setAccentColor(false) + +// Reset window accent color behavior to follow behavior set in System Settings. +win.setAccentColor(null) ``` #### `win.getAccentColor()` _Windows_ @@ -1570,11 +1599,18 @@ events. Prevents the window contents from being captured by other apps. -On macOS it sets the NSWindow's [`sharingType`](https://developer.apple.com/documentation/appkit/nswindow/sharingtype-swift.property?language=objc) to [`NSWindowSharingNone`](https://developer.apple.com/documentation/appkit/nswindow/sharingtype-swift.enum/none?language=objc). -On Windows it calls [`SetWindowDisplayAffinity`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity) with `WDA_EXCLUDEFROMCAPTURE`. +On Windows, it calls [`SetWindowDisplayAffinity`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity) with `WDA_EXCLUDEFROMCAPTURE`. For Windows 10 version 2004 and up the window will be removed from capture entirely, older Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. +On macOS, it sets the `NSWindow`'s +[`sharingType`](https://developer.apple.com/documentation/appkit/nswindow/sharingtype-swift.property?language=objc) +to +[`NSWindowSharingNone`](https://developer.apple.com/documentation/appkit/nswindow/sharingtype-swift.enum/none?language=objc). +Unfortunately, due to an intentional change in macOS, newer Mac applications that use +`ScreenCaptureKit` will capture your window despite `win.setContentProtection(true)`. +See [here](https://github.com/electron/electron/issues/48258#issuecomment-3269893618). + #### `win.isContentProtected()` _macOS_ _Windows_ Returns `boolean` - whether or not content protection is currently enabled. diff --git a/docs/api/client-request.md b/docs/api/client-request.md index d6e27d6deb951..398290f1eef90 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -25,6 +25,11 @@ following properties: with which the request is associated. Defaults to the empty string. The `session` option supersedes `partition`. Thus if a `session` is explicitly specified, `partition` is ignored. + * `bypassCustomProtocolHandlers` boolean (optional) - When set to `true`, + custom protocol handlers registered for the request's URL scheme will not be + called. This allows forwarding an intercepted request to the built-in + handler. [webRequest](web-request.md) handlers will still be triggered + when bypassing custom protocols. Defaults to `false`. * `credentials` string (optional) - Can be `include`, `omit` or `same-origin`. Whether to send [credentials](https://fetch.spec.whatwg.org/#credentials) with this diff --git a/docs/api/clipboard.md b/docs/api/clipboard.md index 275a7afe62108..64001c8d25c09 100644 --- a/docs/api/clipboard.md +++ b/docs/api/clipboard.md @@ -2,7 +2,16 @@ > Perform copy and paste operations on the system clipboard. -Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) (non-sandboxed only) +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) _Deprecated_ (non-sandboxed only) + +> [!NOTE] +> Using the `clipoard` API from the renderer process is deprecated. + +> [!IMPORTANT] +> If you want to call this API from a renderer process, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. On Linux, there is also a `selection` clipboard. To manipulate it you need to pass `selection` to each method: diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index 314b39a8e7c29..5695b40d3f84f 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -49,6 +49,10 @@ Disables the disk cache for HTTP requests. Disable HTTP/2 and SPDY/3.1 protocols. +### --disable-geolocation _macOS_ + +Disables the Geolocation API. Permission requests for geolocation will be denied internally regardless of the decision made by a handler set via `session.setPermissionRequestHandler`. This functionality is currently implemented only for macOS. Has no effect on other platforms. + ### --disable-renderer-backgrounding Prevents Chromium from lowering the priority of invisible pages' renderer @@ -193,6 +197,11 @@ Disables the Chromium [sandbox](https://www.chromium.org/developers/design-docum Forces renderer process and Chromium helper processes to run un-sandboxed. Should only be used for testing. +### --no-stdio-init + +Disable stdio initialization during node initialization. +Used to avoid node initialization crash when the nul device is disabled on Windows platform. + ### --proxy-bypass-list=`hosts` Instructs Electron to bypass the proxy server for the given semi-colon-separated diff --git a/docs/api/crash-reporter.md b/docs/api/crash-reporter.md index d00dad544f7b8..a269750e70498 100644 --- a/docs/api/crash-reporter.md +++ b/docs/api/crash-reporter.md @@ -4,6 +4,12 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + The following is an example of setting up Electron to automatically submit crash reports to a remote server: diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 822eabeac8751..63f647c474784 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -102,6 +102,10 @@ Returns `Promise` - Resolves with an array of [`Desktop ## Caveats +`desktopCapturer.getSources(options)` only returns a single source on Linux when using Pipewire. + +PipeWire supports a single capture for both screens and windows. If you request the window and screen type, the selected source will be returned as a window capture. + `navigator.mediaDevices.getUserMedia` does not work on macOS for audio capture due to a fundamental limitation whereby apps that want to access the system's audio require a [signed kernel extension](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html). Chromium, and by extension Electron, does not provide this. It is possible to circumvent this limitation by capturing system audio with another macOS app like Soundflower and passing it through a virtual audio input device. This virtual device can then be queried with `navigator.mediaDevices.getUserMedia`. diff --git a/docs/api/environment-variables.md b/docs/api/environment-variables.md index f6b05c4cf85c7..c033676a5915e 100644 --- a/docs/api/environment-variables.md +++ b/docs/api/environment-variables.md @@ -186,14 +186,3 @@ the one downloaded by `npm install`. Usage: ```sh export ELECTRON_OVERRIDE_DIST_PATH=/Users/username/projects/electron/out/Testing ``` - -## Set By Electron - -Electron sets some variables in your environment at runtime. - -### `ORIGINAL_XDG_CURRENT_DESKTOP` - -This variable is set to the value of `XDG_CURRENT_DESKTOP` that your application -originally launched with. Electron sometimes modifies the value of `XDG_CURRENT_DESKTOP` -to affect other logic within Chromium so if you want access to the _original_ value -you should look up this environment variable instead. diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index 53722a414bbea..307ac8bf01263 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -20,6 +20,12 @@ changes: Process: [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + The `ipcRenderer` module is an [EventEmitter][event-emitter]. It provides a few methods so you can send synchronous and asynchronous messages from the render process (web page) to the main process. You can also receive replies from the diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 90c72fb578f15..aa3d6ce6ee216 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -34,7 +34,8 @@ See [`Menu`](menu.md) for examples. * `sublabel` string (optional) _macOS_ - Available in macOS >= 14.4 * `toolTip` string (optional) _macOS_ - Hover text for this menu item. * `accelerator` string (optional) - An [Accelerator](../tutorial/keyboard-shortcuts.md#accelerators) string. - * `icon` ([NativeImage](native-image.md) | string) (optional) + * `icon` ([NativeImage](native-image.md) | string) (optional) - Can be a + [NativeImage](native-image.md) or the file path of an icon. * `enabled` boolean (optional) - If false, the menu item will be greyed out and unclickable. * `acceleratorWorksWhenHidden` boolean (optional) _macOS_ - default is `true`, and when `false` will prevent the accelerator from triggering the item if the item is not visible. diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 68ecbbe1ad1d7..f851606ec9040 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -4,6 +4,12 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + The `nativeImage` module provides a unified interface for manipulating system images. These can be handy if you want to provide multiple scaled versions of the same icon or take advantage of macOS [template images][template-image]. @@ -196,8 +202,7 @@ Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL Returns `NativeImage` Creates a new `NativeImage` instance from the `NSImage` that maps to the -given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388) -documentation for a list of possible values. +given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388) documentation and [SF Symbols](https://developer.apple.com/sf-symbols/) for a list of possible values. The `hslShift` is applied to the image with the following rules: @@ -225,6 +230,15 @@ echo -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc). +For SF Symbols, usage looks as follows: + +```js +const image = nativeImage.createFromNamedImage('square.and.pencil') +``` + +where `'square.and.pencil'` is the symbol name from the +[SF Symbols app](https://developer.apple.com/sf-symbols/). + ## Class: NativeImage > Natively wrap images such as tray, dock, and application icons. diff --git a/docs/api/session.md b/docs/api/session.md index 1d13094426a8c..2e6e61b71845b 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -66,7 +66,7 @@ The `session` module has the following properties: ### `session.defaultSession` -A `Session` object, the default session object of the app. +A `Session` object, the default session object of the app, available after `app.whenReady` is called. ## Class: Session @@ -939,14 +939,18 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents * `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API). * `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API). * `deprecated-sync-clipboard-read` _Deprecated_ - Request access to run `document.execCommand("paste")` + * `fileSystem` - Access to read, write, and file management capabilities using the [File System API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API). * `requestingOrigin` string - The origin URL of the permission check * `details` Object - Some properties are only available on certain permission types. * `embeddingOrigin` string (optional) - The origin of the frame embedding the frame that made the permission check. Only set for cross-origin sub frames making permission checks. * `securityOrigin` string (optional) - The security origin of the `media` check. * `mediaType` string (optional) - The type of media access being requested, can be `video`, - `audio` or `unknown` + `audio` or `unknown`. * `requestingUrl` string (optional) - The last URL the requesting frame loaded. This is not provided for cross-origin sub frames making permission checks. - * `isMainFrame` boolean - Whether the frame making the request is the main frame + * `isMainFrame` boolean - Whether the frame making the request is the main frame. + * `filePath` string (optional) - The path of a `fileSystem` request. + * `isDirectory` boolean (optional) - Whether a `fileSystem` request is a directory. + * `fileAccessType` string (optional) - The access type of a `fileSystem` request. Can be `writable` or `readable`. Sets the handler which can be used to respond to permission checks for the `session`. Returning `true` will allow the permission and `false` will reject it. Please note that @@ -968,6 +972,9 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents, }) ``` +> [!NOTE] +> `isMainFrame` will always be `false` for a `fileSystem` request as a result of Chromium limitations. + #### `ses.setDisplayMediaRequestHandler(handler[, opts])` * `handler` Function | null diff --git a/docs/api/shared-texture.md b/docs/api/shared-texture.md new file mode 100644 index 0000000000000..6aecb71d6aa4b --- /dev/null +++ b/docs/api/shared-texture.md @@ -0,0 +1,58 @@ +# sharedTexture + +> Import shared textures into Electron and converts platform specific handles into [`VideoFrame`](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame). Supports all Web rendering systems, and can be transferred across Electron processes. Read [here](https://github.com/electron/electron/blob/main/shell/common/api/shared_texture/README.md) for more information. + +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) + +## Methods + +The `sharedTexture` module has the following methods: + +**Note:** Experimental APIs are marked as such and could be removed in the future. + +### `sharedTexture.importSharedTexture(options)` _Experimental_ + +* `options` Object - Options for importing shared textures. + * `textureInfo` [SharedTextureImportTextureInfo](structures/shared-texture-import-texture-info.md) - The information of the shared texture to import. + * `allReferencesReleased` Function (optional) - Called when all references in all processes are released. You should keep the imported texture valid until this callback is called. + +Imports the shared texture from the given options. + +> [!NOTE] +> This method is only available in the main process. + +Returns `SharedTextureImported` - The imported shared texture. + +### `sharedTexture.sendSharedTexture(options, ...args)` _Experimental_ + +* `options` Object - Options for sending shared texture. + * `frame` [WebFrameMain](web-frame-main.md) - The target frame to transfer the shared texture to. For `WebContents`, you can pass `webContents.mainFrame`. If you provide a `webFrameMain` that is not a main frame, you'll need to enable `webPreferences.nodeIntegrationInSubFrames` for this, since this feature requires [IPC](https://www.electronjs.org/docs/latest/api/web-frame-main#frameipc-readonly) between main and the frame. + * `importedSharedTexture` [SharedTextureImported](structures/shared-texture-imported.md) - The imported shared texture. +* `...args` any[] - Additional arguments to pass to the renderer process. + +Send the imported shared texture to a renderer process. You must register a receiver at renderer process before calling this method. This method has a 1000ms timeout. Ensure the receiver is set and the renderer process is alive before calling this method. + +> [!NOTE] +> This method is only available in the main process. + +Returns `Promise` - Resolves when the transfer is complete. + +### `sharedTexture.setSharedTextureReceiver(callback)` _Experimental_ + +* `callback` Function\\> - The function to receive the imported shared texture. + * `receivedSharedTextureData` Object - The data received from the main process. + * `importedSharedTexture` [SharedTextureImported](structures/shared-texture-imported.md) - The imported shared texture. + * `...args` any[] - Additional arguments passed from the main process. + +Set a callback to receive imported shared textures from the main process. + +> [!NOTE] +> This method is only available in the renderer process. + +## Properties + +The `sharedTexture` module has the following properties: + +### `sharedTexture.subtle` _Experimental_ + +A [`SharedTextureSubtle`](structures/shared-texture-subtle.md) property, provides subtle APIs for interacting with shared texture for advanced users. diff --git a/docs/api/structures/base-window-options.md b/docs/api/structures/base-window-options.md index 375c6adc3b59b..c056044e7c599 100644 --- a/docs/api/structures/base-window-options.md +++ b/docs/api/structures/base-window-options.md @@ -42,6 +42,8 @@ Default is `false`. * `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control. * `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`. +* `name` string (optional) - A unique identifier for the window, used internally by Electron to enable features such as state persistence. Each window must have a distinct name. It can only be reused after the corresponding window has been destroyed. An error is thrown if the name is already in use. This is not the visible title shown to users on the title bar. +* `windowStatePersistence` ([WindowStatePersistence](window-state-persistence.md) | boolean) (optional) - Configures or enables the persistence of window state (position, size, maximized state, etc.) across application restarts. Has no effect if window `name` is not provided. Automatically disabled when there is no available display. _Experimental_ * `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `` is defined in the HTML file loaded by `loadURL()`, this property will be ignored. * `icon` ([NativeImage](../native-image.md) | string) (optional) - The window icon. On Windows it is recommended to use `ICO` icons to get best visual effects, you can also @@ -91,7 +93,7 @@ title bar and a full size content window, the traffic light buttons will display when being hovered over in the top left of the window. **Note:** This option is currently experimental. -* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjunction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. +* `titleBarOverlay` Object | boolean (optional) - When using a frameless window in conjunction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. * `color` String (optional) _Windows_ _Linux_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color. * `symbolColor` String (optional) _Windows_ _Linux_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color. * `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. Default is system height. @@ -102,9 +104,10 @@ should have rounded corners. Default is `true`. Setting this property to `false` will prevent the window from being fullscreenable on macOS. On Windows versions older than Windows 11 Build 22000 this property has no effect, and frameless windows will not have rounded corners. -* `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on - Windows, which adds standard window frame. Setting it to `false` will remove - window shadow and window animations. Default is `true`. +* `thickFrame` boolean (optional) _Windows_ - Use `WS_THICKFRAME` style for + frameless windows on Windows, which adds the standard window frame. Setting it + to `false` will remove window shadow and window animations, and disable window + resizing via dragging the window edges. Default is `true`. * `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to the window, only on macOS. Can be `appearance-based`, `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, diff --git a/docs/api/structures/offscreen-shared-texture.md b/docs/api/structures/offscreen-shared-texture.md index b930bc5daf254..e434287747409 100644 --- a/docs/api/structures/offscreen-shared-texture.md +++ b/docs/api/structures/offscreen-shared-texture.md @@ -2,7 +2,10 @@ * `textureInfo` Object - The shared texture info. * `widgetType` string - The widget type of the texture. Can be `popup` or `frame`. - * `pixelFormat` string - The pixel format of the texture. Can be `rgba` or `bgra`. + * `pixelFormat` string - The pixel format of the texture. + * `rgba` - The texture format is 8-bit unorm RGBA. + * `bgra` - The texture format is 8-bit unorm BGRA. + * `rgbaf16` - The texture format is 16-bit float RGBA. * `codedSize` [Size](size.md) - The full dimensions of the video frame. * `colorSpace` [ColorSpace](color-space.md) - The color space of the video frame. * `visibleRect` [Rectangle](rectangle.md) - A subsection of [0, 0, codedSize.width, codedSize.height]. In OSR case, it is expected to have the full section area. diff --git a/docs/api/structures/render-process-gone-details.md b/docs/api/structures/render-process-gone-details.md index e48800a5b87d7..633d9bbc9ddb6 100644 --- a/docs/api/structures/render-process-gone-details.md +++ b/docs/api/structures/render-process-gone-details.md @@ -8,6 +8,7 @@ * `oom` - Process ran out of memory * `launch-failed` - Process never successfully launched * `integrity-failure` - Windows code integrity checks failed + * `memory-eviction` - Process proactively terminated to prevent a future out-of-memory (OOM) situation * `exitCode` Integer - The exit code of the process, unless `reason` is `launch-failed`, in which case `exitCode` will be a platform-specific launch failure error code. diff --git a/docs/api/structures/shared-texture-import-texture-info.md b/docs/api/structures/shared-texture-import-texture-info.md new file mode 100644 index 0000000000000..47c9338c8fa3e --- /dev/null +++ b/docs/api/structures/shared-texture-import-texture-info.md @@ -0,0 +1,11 @@ +# SharedTextureImportTextureInfo Object + +* `pixelFormat` string - The pixel format of the texture. + * `bgra` - 32bpp BGRA (byte-order), 1 plane. + * `rgba` - 32bpp RGBA (byte-order), 1 plane. + * `rgbaf16` - Half float RGBA, 1 plane. +* `colorSpace` [ColorSpace](color-space.md) (optional) - The color space of the texture. +* `codedSize` [Size](size.md) - The full dimensions of the shared texture. +* `visibleRect` [Rectangle](rectangle.md) (optional) - A subsection of [0, 0, codedSize.width, codedSize.height]. In common cases, it is the full section area. +* `timestamp` number (optional) - A timestamp in microseconds that will be reflected to `VideoFrame`. +* `handle` [SharedTextureHandle](shared-texture-handle.md) - The shared texture handle. diff --git a/docs/api/structures/shared-texture-imported-subtle.md b/docs/api/structures/shared-texture-imported-subtle.md new file mode 100644 index 0000000000000..c0c934ee1a281 --- /dev/null +++ b/docs/api/structures/shared-texture-imported-subtle.md @@ -0,0 +1,9 @@ +# SharedTextureImportedSubtle Object + +* `getVideoFrame` Function\<[VideoFrame](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame)\> - Create a `VideoFrame` that uses the imported shared texture in the current process. You can call `VideoFrame.close()` once you've finished using the object. The underlying resources will wait for GPU finish internally. +* `release` Function - Release the resources. If you transferred and get multiple `SharedTextureImported` objects, you have to `release` every one of them. The resource on the GPU process will be destroyed when the last one is released. + * `callback` Function (optional) - Callback when the GPU command buffer finishes using this shared texture. It provides a precise event to safely release dependent resources. For example, if this object is created by `finishTransferSharedTexture`, you can use this callback to safely release the original one that called `startTransferSharedTexture` in other processes. You can also release the source shared texture that was used to `importSharedTexture` safely. +* `startTransferSharedTexture` Function\<[SharedTextureTransfer](shared-texture-transfer.md)\> - Create a `SharedTextureTransfer` that can be serialized and transferred to other processes. +* `getFrameCreationSyncToken` Function\<[SharedTextureSyncToken](shared-texture-sync-token.md)\> - This method is for advanced users. If used, it is typically called after `finishTransferSharedTexture`, and should be passed to the object which was called `startTransferSharedTexture` to prevent the source object release the underlying resource before the target object actually acquire the reference at gpu process asyncly. +* `setReleaseSyncToken` Function - This method is for advanced users. If used, this object's underlying resource will not be released until the set sync token is fulfilled at gpu process. By using sync tokens, users are not required to use release callbacks for lifetime management. + * `syncToken` [SharedTextureSyncToken](shared-texture-sync-token.md) - The sync token to set. diff --git a/docs/api/structures/shared-texture-imported.md b/docs/api/structures/shared-texture-imported.md new file mode 100644 index 0000000000000..e6fea2f420488 --- /dev/null +++ b/docs/api/structures/shared-texture-imported.md @@ -0,0 +1,6 @@ +# SharedTextureImported Object + +* `textureId` string - The unique identifier of the imported shared texture. +* `getVideoFrame` Function\<[VideoFrame](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame)\> - Create a `VideoFrame` that uses the imported shared texture in the current process. You can call `VideoFrame.close()` once you've finished using the object. The underlying resources will wait for GPU finish internally. +* `release` Function - Release this object's reference of the imported shared texture. The underlying resource will be alive until every reference is released. +* `subtle` [SharedTextureImportedSubtle](shared-texture-imported-subtle.md) - Provides subtle APIs to interact with the imported shared texture for advanced users. diff --git a/docs/api/structures/shared-texture-subtle.md b/docs/api/structures/shared-texture-subtle.md new file mode 100644 index 0000000000000..a20f4ff8928ab --- /dev/null +++ b/docs/api/structures/shared-texture-subtle.md @@ -0,0 +1,6 @@ +# SharedTextureSubtle Object + +* `importSharedTexture` Function\<[SharedTextureImportedSubtle](shared-texture-imported-subtle.md)\> - Imports the shared texture from the given options. Returns the imported shared texture. + * `textureInfo` [SharedTextureImportTextureInfo](shared-texture-import-texture-info.md) - The information of shared texture to import. +* `finishTransferSharedTexture` Function\<[SharedTextureImportedSubtle](shared-texture-imported-subtle.md)\> - Finishes the transfer of the shared texture and gets the transferred shared texture. Returns the imported shared texture from the transfer object. + * `transfer` [SharedTextureTransfer](shared-texture-transfer.md) - The transfer object of the shared texture. diff --git a/docs/api/structures/shared-texture-sync-token.md b/docs/api/structures/shared-texture-sync-token.md new file mode 100644 index 0000000000000..abc3b6e28748a --- /dev/null +++ b/docs/api/structures/shared-texture-sync-token.md @@ -0,0 +1,3 @@ +# SharedTextureSyncToken Object + +* `syncToken` string - The opaque data for sync token. diff --git a/docs/api/structures/shared-texture-transfer.md b/docs/api/structures/shared-texture-transfer.md new file mode 100644 index 0000000000000..3d36ab650bf2a --- /dev/null +++ b/docs/api/structures/shared-texture-transfer.md @@ -0,0 +1,10 @@ +# SharedTextureTransfer Object + +* `transfer` string _Readonly_ - The opaque transfer data of the shared texture. This can be transferred across Electron processes. +* `syncToken` string _Readonly_ - The opaque sync token data for frame creation. +* `pixelFormat` string _Readonly_ - The pixel format of the transferring texture. +* `codedSize` [Size](size.md) _Readonly_ - The full dimensions of the shared texture. +* `visibleRect` [Rectangle](rectangle.md) _Readonly_ - A subsection of [0, 0, codedSize.width(), codedSize.height()]. In common cases, it is the full section area. +* `timestamp` number _Readonly_ - A timestamp in microseconds that will be reflected to `VideoFrame`. + +Use `sharedTexture.subtle.finishTransferSharedTexture` to get [`SharedTextureImportedSubtle`](shared-texture-imported-subtle.md) back. diff --git a/docs/api/structures/web-preferences.md b/docs/api/structures/web-preferences.md index 26ead57c2329f..ceb55730148e2 100644 --- a/docs/api/structures/web-preferences.md +++ b/docs/api/structures/web-preferences.md @@ -21,7 +21,9 @@ associated with the window, making it compatible with the Chromium OS-level sandbox and disabling the Node.js engine. This is not the same as the `nodeIntegration` option and the APIs available to the preload script - are more limited. Read more about the option [here](../../tutorial/sandbox.md). + are more limited. Default is `true` since Electron 20. The sandbox will + automatically be disabled when `nodeIntegration` is set to `true`. + Read more about the option [here](../../tutorial/sandbox.md). * `session` [Session](../session.md#class-session) (optional) - Sets the session used by the page. Instead of passing the Session object directly, you can also choose to use the `partition` option instead, which accepts a partition string. When @@ -87,6 +89,11 @@ paint event. Defaults to `false`. See the [offscreen rendering tutorial](../../tutorial/offscreen-rendering.md) for more details. + * `sharedTexturePixelFormat` string (optional) _Experimental_ - The requested output format of the shared texture. Defaults to `argb`. + The name is originated from Chromium [`media::VideoPixelFormat`](https://source.chromium.org/chromium/chromium/src/+/main:media/base/video_types.h) enum suffix and only subset of them are supported. + The actual output pixel format and color space of the texture should refer to [`OffscreenSharedTexture`](../structures/offscreen-shared-texture.md) object in the `paint` event. + * `argb` - The requested output texture format is 8-bit unorm RGBA, with SRGB SDR color space. + * `rgbaf16` - The requested output texture format is 16-bit float RGBA, with scRGB HDR color space. * `contextIsolation` boolean (optional) - Whether to run Electron APIs and the specified `preload` script in a separate JavaScript context. Defaults to `true`. The context that the `preload` script runs in will only have diff --git a/docs/api/structures/window-state-persistence.md b/docs/api/structures/window-state-persistence.md new file mode 100644 index 0000000000000..efb02bb56d09f --- /dev/null +++ b/docs/api/structures/window-state-persistence.md @@ -0,0 +1,4 @@ +# WindowStatePersistence Object + +* `bounds` boolean (optional) - Whether to persist window position and size across application restarts. Defaults to `true` if not specified. +* `displayMode` boolean (optional) - Whether to persist display modes (fullscreen, kiosk, maximized, etc.) across application restarts. Defaults to `true` if not specified. diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index 8af85f757dcf0..ce5f4bf8b5e71 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -14,7 +14,7 @@ console.log(systemPreferences.getEffectiveAppearance()) The `systemPreferences` object emits the following events: -### Event: 'accent-color-changed' _Windows_ +### Event: 'accent-color-changed' _Windows_ _Linux_ Returns: @@ -182,7 +182,7 @@ Some popular `key` and `type`s are: Removes the `key` in `NSUserDefaults`. This can be used to restore the default or global value of a `key` previously set with `setUserDefault`. -### `systemPreferences.getAccentColor()` _Windows_ _macOS_ +### `systemPreferences.getAccentColor()` Returns `string` - The users current system wide accent color preference in RGBA hexadecimal form. diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 4c92a8985e29c..2681df864a507 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -4,6 +4,12 @@ Process: [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + `webFrame` export of the Electron module is an instance of the `WebFrame` class representing the current frame. Sub-frames can be retrieved by certain properties and methods (e.g. `webFrame.firstChild`). @@ -139,7 +145,7 @@ by its key, which is returned from `webFrame.insertCSS(css)`. Inserts `text` to the focused element. -### `webFrame.executeJavaScript(code[, userGesture, callback])` +### `webFrame.executeJavaScript(code[, userGesture][, callback])` * `code` string * `userGesture` boolean (optional) - Default is `false`. @@ -160,7 +166,7 @@ In the browser window some HTML APIs like `requestFullScreen` can only be invoked by a gesture from the user. Setting `userGesture` to `true` will remove this limitation. -### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])` +### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture][, callback])` * `worldId` Integer - The ID of the world to run the javascript in, `0` is the default main world (where content runs), `999` is the diff --git a/docs/api/web-utils.md b/docs/api/web-utils.md index 6ce407260e922..f1d04fcc9887b 100644 --- a/docs/api/web-utils.md +++ b/docs/api/web-utils.md @@ -4,6 +4,12 @@ Process: [Renderer](../glossary.md#renderer-process) +> [!IMPORTANT] +> If you want to call this API from a renderer process with context isolation enabled, +> place the API call in your preload script and +> [expose](../tutorial/context-isolation.md#after-context-isolation-enabled) it using the +> [`contextBridge`](context-bridge.md) API. + ## Methods The `webUtils` module has the following methods: @@ -17,11 +23,27 @@ Returns `string` - The file system path that this `File` object points to. In th This method superseded the previous augmentation to the `File` object with the `path` property. An example is included below. ```js @ts-nocheck -// Before -const oldPath = document.querySelector('input').files[0].path +// Before (renderer) +const oldPath = document.querySelector('input[type=file]').files[0].path +``` +```js @ts-nocheck // After -const { webUtils } = require('electron') -const newPath = webUtils.getPathForFile(document.querySelector('input').files[0]) +// Renderer: + +const file = document.querySelector('input[type=file]').files[0] +electronApi.doSomethingWithFile(file) + +// Preload script: + +const { contextBridge, webUtils } = require('electron') + +contextBridge.exposeInMainWorld('electronApi', { + doSomethingWithFile (file) { + const path = webUtils.getPathForFile(file) + // Do something with the path, e.g., send it over IPC to the main process. + // It's best not to expose the full file path to the web content if possible. + } +}) ``` diff --git a/docs/api/window-open.md b/docs/api/window-open.md index 7285c956bd056..e9c4b80550e59 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -39,8 +39,8 @@ consider using `webContents.setWindowOpenHandler` to customize the BrowserWindow creation. A subset of [`WebPreferences`](structures/web-preferences.md) can be set directly, -unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`, -`javascript`, `contextIsolation`, and `webviewTag`. +unnested, from the features string: `zoomFactor`, `nodeIntegration`, `javascript`, +`contextIsolation`, and `webviewTag`. For example: diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index 689519c62b0bb..31d9a27bbd21f 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -12,6 +12,19 @@ This document uses the following convention to categorize breaking changes: * **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. * **Removed:** An API or feature was removed, and is no longer supported by Electron. +## Planned Breaking API Changes (40.0) + +### Deprecated: `clipboard` API access from renderer processes + +Using the `clipboard` API directly in the renderer process is deprecated. +If you want to call this API from a renderer process, place the API call in +your preload script and expose it using the [contextBridge](https://www.electronjs.org/docs/latest/api/context-bridge) API. + +### Behavior Changed: MacOS dSYM files now compressed with tar.xz + +Debug symbols for MacOS (dSYM) now use xz compression in order to handle larger file sizes. `dsym.zip` files are now +`dsym.tar.xz` files. End users using debug symbols may need to update their zip utilities. + ## Planned Breaking API Changes (39.0) ### Deprecated: `--host-rules` command line switch @@ -20,13 +33,42 @@ Chromium is deprecating the `--host-rules` switch. You should use `--host-resolver-rules` instead. +### Behavior Changed: window.open popups are always resizable + +Per current [WHATWG spec](https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-open-dev), the `window.open` API will now always create a resizable popup window. + +To restore previous behavior: + +```js +webContents.setWindowOpenHandler((details) => { + return { + action: 'allow', + overrideBrowserWindowOptions: { + resizable: details.features.includes('resizable=yes') + } + } +}) +``` + +### Behavior Changed: shared texture OSR `paint` event data structure + +When using shared texture offscreen rendering feature, the `paint` event now emits a more structured object. +It moves the `sharedTextureHandle`, `planes`, `modifier` into a unified `handle` property. +See the [OffscreenSharedTexture](./api/structures/offscreen-shared-texture.md) API structure for more details. + ## Planned Breaking API Changes (38.0) ### Removed: `ELECTRON_OZONE_PLATFORM_HINT` environment variable -The default value of the `--ozone-plaftform` flag [changed to `auto`](https://chromium-review.googlesource.com/c/chromium/src/+/6775426). +The default value of the `--ozone-platform` flag [changed to `auto`](https://chromium-review.googlesource.com/c/chromium/src/+/6775426). + +Electron now defaults to running as a native Wayland app when launched in a Wayland session (when `XDG_SESSION_TYPE=wayland`). +Users can force XWayland by passing `--ozone-platform=x11`. -You should use the `XDG_SESSION_TYPE=wayland` environment variable instead to use Wayland. +### Removed: `ORIGINAL_XDG_CURRENT_DESKTOP` environment variable + +Previously, Electron changed the value of `XDG_CURRENT_DESKTOP` internally to `Unity`, and stored the original name of the desktop session +in a separate variable. `XDG_CURRENT_DESKTOP` is no longer overriden and now reflects the actual desktop environment. ### Removed: macOS 11 support @@ -51,29 +93,6 @@ The `webFrame.findFrameByRoutingId(routingId)` function will be removed. You should use `webFrame.findFrameByToken(frameToken)` instead. -### Behavior Changed: window.open popups are always resizable - -Per current [WHATWG spec](https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-open-dev), the `window.open` API will now always create a resizable popup window. - -To restore previous behavior: - -```js -webContents.setWindowOpenHandler((details) => { - return { - action: 'allow', - overrideBrowserWindowOptions: { - resizable: details.features.includes('resizable=yes') - } - } -}) -``` - -### Behavior Changed: shared texture OSR `paint` event data structure - -When using shared texture offscreen rendering feature, the `paint` event now emits a more structured object. -It moves the `sharedTextureHandle`, `planes`, `modifier` into a unified `handle` property. -See [here](https://www.electronjs.org/docs/latest/api/structures/offscreen-shared-texture) for more details. - ## Planned Breaking API Changes (37.0) ### Utility Process unhandled rejection behavior change diff --git a/docs/development/multi-monitor-testing.md b/docs/development/multi-monitor-testing.md new file mode 100644 index 0000000000000..900c8170d35df --- /dev/null +++ b/docs/development/multi-monitor-testing.md @@ -0,0 +1,111 @@ +# Multi-Monitor Testing + +The `virtualDisplay` addon leverages macOS CoreGraphics APIs to create virtual displays, allowing you to write and run multi-monitor tests without the need for physical monitors. Due to macOS CoreGraphics quirks, reading the entire guide once before writing tests is recommended. + +## Methods + +#### `virtualDisplay.create([options])` + +Creates a virtual display and returns a display ID. + +```js @ts-nocheck +const virtualDisplay = require('@electron-ci/virtual-display') +// Default: 1920×1080 at origin (0, 0) +const displayId = virtualDisplay.create() +``` + +```js @ts-nocheck +const virtualDisplay = require('@electron-ci/virtual-display') +// Custom options (all parameters optional and have default values) +const displayId = virtualDisplay.create({ + width: 2560, // Display width in pixels + height: 1440, // Display height in pixels + x: 1920, // X position (top-left corner) + y: 0 // Y position (top-left corner) +}) +``` + +**Returns:** `number` - Unique display ID used to identify the display. Returns `0` on failure to create display. + +> [!NOTE] +> It is recommended to call [`virtualDisplay.forceCleanup()`](#virtualdisplayforcecleanup) before every test to prevent display creation from failing in that test. macOS CoreGraphics maintains an internal display ID allocation pool that can become corrupted when virtual displays are created and destroyed rapidly during testing. Without proper cleanup, subsequent display creation may fail with inconsistent display IDs, resulting in test flakiness. + +#### `virtualDisplay.forceCleanup()` + +Performs a complete cleanup of all virtual displays and resets the macOS CoreGraphics display system. + +```js @ts-nocheck +beforeEach(() => { + virtualDisplay.forceCleanup() +}) +``` + +#### `virtualDisplay.destroy(displayId)` + +Removes the virtual display. + +```js @ts-nocheck +virtualDisplay.destroy(displayId) +``` + +> [!NOTE] +> Always destroy virtual displays after use to prevent corrupting the macOS CoreGraphics display pool and affecting subsequent tests. + +## Recommended usage pattern + +```js @ts-nocheck +describe('multi-monitor tests', () => { + const virtualDisplay = require('@electron-ci/virtual-display') + beforeEach(() => { + virtualDisplay.forceCleanup() + }) + + it('should handle multiple displays', () => { + const display1 = virtualDisplay.create({ width: 1920, height: 1080, x: 0, y: 0 }) + const display2 = virtualDisplay.create({ width: 2560, height: 1440, x: 1920, y: 0 }) + // Your test logic here + virtualDisplay.destroy(display1) + virtualDisplay.destroy(display2) + }) +}) +``` + +## Display Constraints + +### Size Limits + +Virtual displays are constrained to 720×720 pixels minimum and 8192×8192 pixels maximum. Actual limits may vary depending on your Mac's graphics capabilities, so sizes outside this range (like 9000×6000) may fail on some systems. + +```js @ts-nocheck +// Safe sizes for testing +virtualDisplay.create({ width: 1920, height: 1080 }) // Full HD +virtualDisplay.create({ width: 3840, height: 2160 }) // 4K +``` + +### Positioning Behavior + +macOS maintains a contiguous desktop space by automatically adjusting display positions if there are any overlaps or gaps. In case of either, the placement of the new origin is as close as possible to the requested location, without overlapping or leaving a gap between displays. + +**Overlap:** + +```js @ts-nocheck +// Requested positions +const display1 = virtualDisplay.create({ x: 0, y: 0, width: 1920, height: 1080 }) +const display2 = virtualDisplay.create({ x: 500, y: 0, width: 1920, height: 1080 }) + +// macOS automatically repositions display2 to x: 1920 to prevent overlap +const actualBounds = screen.getAllDisplays().map(d => d.bounds) +// Result: [{ x: 0, y: 0, width: 1920, height: 1080 }, { x: 1920, y: 0, width: 1920, height: 1080 }] +``` + +**Gap:** + +```js @ts-nocheck +// Requested: gap between displays +const display1 = virtualDisplay.create({ width: 1920, height: 1080, x: 0, y: 0 }) +const display2 = virtualDisplay.create({ width: 1920, height: 1080, x: 2000, y: 0 }) +// macOS snaps display2 to x: 1920 (eliminates 80px gap) +``` + +> [!NOTE] +> Always verify actual positions with `screen.getAllDisplays()` after creation, as macOS may adjust coordinates from the set values. diff --git a/docs/development/testing.md b/docs/development/testing.md index cce8ea5eab463..2de3b2e2e8c27 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -95,3 +95,11 @@ To configure display scaling: 1. Push the Windows key and search for _Display settings_. 2. Under _Scale and layout_, make sure that the device is set to 100%. + +## Multi-Monitor Tests + +Some Electron APIs require testing across multiple displays, such as screen detection, window positioning, and display-related events. For contributors working on these features, the `virtualDisplay` native addon enables you to create and position virtual displays programmatically, making it possible to test multi-monitor scenarios without any physical hardware. + +For detailed information on using virtual displays in your tests, see [Multi-Monitor Testing](multi-monitor-testing.md). + +**Platform support:** macOS only diff --git a/docs/faq.md b/docs/faq.md index b7259d1661b39..34aa74b04ab0e 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -12,19 +12,28 @@ network problems. The best resolution is to try switching networks, or wait a bit and try installing again. You can also attempt to download Electron directly from -[electron/electron/releases](https://github.com/electron/electron/releases) +[GitHub Releases](https://github.com/electron/electron/releases) if installing via `npm` is failing. -## When will Electron upgrade to latest Chrome? +If you need to install Electron through a custom mirror or proxy, see +the [Advanced Installation](./tutorial/installation.md) documentation for more details. -The Chrome version of Electron is usually bumped within one or two weeks after -a new stable Chrome version gets released. This estimate is not guaranteed and -depends on the amount of work involved with upgrading. +## How are Electron binaries downloaded? -Only the stable channel of Chrome is used. If an important fix is in beta or dev -channel, we will back-port it. +When you run `npm install electron`, the Electron binary for the corresponding version is downloaded +into your project's `node_modules` folder via npm's `postinstall` lifecycle script. -For more information, please see the [security introduction](tutorial/security.md). +This logic is handled by the [`@electron/get`](https://github.com/electron/get) utility package +under the hood. + +## When will Electron upgrade to latest Chromium? + +Every new major version of Electron releases with a Chromium major version upgrade. By releasing every +8 weeks, Electron is able to pull in every other major Chromium release on the very same day that it +releases upstream. Security fixes will be backported to stable release channels ahead of time. + +See the [Electron Releases](./tutorial/electron-timelines.md) documentation for more details or +[releases.electronjs.org](https://releases.electronjs.org) to see our Release Status dashboard. ## When will Electron upgrade to latest Node.js? diff --git a/docs/glossary.md b/docs/glossary.md index b917ed0d7b609..5ce09d8c5a1eb 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -12,6 +12,15 @@ The ASAR format was created primarily to improve performance on Windows when reading large quantities of small files (e.g. when loading your app's JavaScript dependency tree from `node_modules`). +### ASAR integrity + +ASAR integrity is an security feature that validates the contents of your app's +ASAR archives at runtime. When enabled, your Electron app will verify the +header hash of its ASAR archive on runtime. If no hash is present or if there is a mismatch in the +hashes, the app will forcefully terminate. + +See the [ASAR Integrity](./tutorial/asar-integrity.md) guide for more details. + ### code signing Code signing is a process where an app developer digitally signs their code to diff --git a/docs/tutorial/asar-integrity.md b/docs/tutorial/asar-integrity.md index fd3c8ba25244f..f1067eea9ee42 100644 --- a/docs/tutorial/asar-integrity.md +++ b/docs/tutorial/asar-integrity.md @@ -5,7 +5,7 @@ slug: asar-integrity hide_title: false --- -ASAR integrity is an experimental feature that validates the contents of your app's +ASAR integrity is a security feature that validates the contents of your app's [ASAR archives](./asar-archives.md) at runtime. ## Version support @@ -64,13 +64,10 @@ flipFuses( ) ``` -:::tip Fuses in Electron Forge - -With Electron Forge, you can configure your app's fuses with -[@electron-forge/plugin-fuses](https://www.electronforge.io/config/plugins/fuses) -in your Forge configuration file. - -::: +> [!TIP] +> With Electron Forge, you can configure your app's fuses with +> [@electron-forge/plugin-fuses](https://www.electronforge.io/config/plugins/fuses) +> in your Forge configuration file. ## Providing the header hash @@ -80,7 +77,7 @@ on package time. The process of providing this packaged hash is different for ma ### Using Electron tooling Electron Forge and Electron Packager do this setup automatically for you with no additional -configuration. The minimum required versions for ASAR integrity are: +configuration whenever `asar` is enabled. The minimum required versions for ASAR integrity are: * `@electron/packager@18.3.1` * `@electron/forge@7.4.0` @@ -109,7 +106,7 @@ Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of th The `@electron/asar` package exposes a `getRawHeader` method whose result can then be hashed to generate this value (e.g. using the [`node:crypto`](https://nodejs.org/api/crypto.html) module). -### Windows +#### Windows When packaging for Windows, you must populate a valid [resource](https://learn.microsoft.com/en-us/windows/win32/menurc/resources) entry of type `Integrity` and name `ElectronAsar`. The value of this resource should be a JSON encoded dictionary @@ -125,9 +122,6 @@ in the form included below: ] ``` -:::info - -For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts) -in the Electron Packager code. - -::: +> [!NOTE] +> For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts) +> in the Electron Packager code. diff --git a/docs/tutorial/code-signing.md b/docs/tutorial/code-signing.md index d0eff31e5fe38..a51db39acf243 100644 --- a/docs/tutorial/code-signing.md +++ b/docs/tutorial/code-signing.md @@ -233,10 +233,10 @@ can find [its documentation here](https://www.electron.build/code-signing). [Azure Trusted Signing][] is Microsoft's modern cloud-based alternative to EV certificates. It is the cheapest option for code signing on Windows, and it gets rid of SmartScreen warnings. -As of May 2025, Azure Trusted Signing is [available][trusted-signing-availability] to US and -Canada-based organizations with 3+ years of verifiable business history. Microsoft is looking -to make the program more widely available. If you're reading this at a later point, it could -make sense to check if the eligibility criteria have changed. +As of October 2025, Azure Trusted Signing is available to US and Canada-based organizations +with 3+ years of verifiable business history and to individual developers in the US and Canada. +Microsoft is looking to make the program more widely available. If you're reading this at a +later point, it could make sense to check if the eligibility criteria have changed. #### Using Electron Forge @@ -267,6 +267,5 @@ See the [Windows Store Guide][]. [maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows [maker-msi]: https://www.electronforge.io/config/makers/wix-msi [azure trusted signing]: https://azure.microsoft.com/en-us/products/trusted-signing -[trusted-signing-availability]: https://techcommunity.microsoft.com/blog/microsoft-security-blog/trusted-signing-public-preview-update/4399713 [forge-trusted-signing]: https://www.electronforge.io/guides/code-signing/code-signing-windows#using-azure-trusted-signing [builder-trusted-signing]: https://www.electron.build/code-signing-win#using-azure-trusted-signing-beta diff --git a/docs/tutorial/devtools-extension.md b/docs/tutorial/devtools-extension.md index 679e3e749a77c..27902dfe7dafb 100644 --- a/docs/tutorial/devtools-extension.md +++ b/docs/tutorial/devtools-extension.md @@ -94,7 +94,7 @@ If the extension works on Chrome but not on Electron, file a bug in Electron's [issue tracker][issue-tracker] and describe which part of the extension is not working as expected. -[devtools-extension]: https://developer.chrome.com/extensions/devtools +[devtools-extension]: https://developer.chrome.com/docs/extensions/how-to/devtools/extend-devtools [session]: ../api/session.md [react-devtools]: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi [load-extension]: ../api/extensions-api.md#extensionsloadextensionpath-options diff --git a/docs/tutorial/electron-timelines.md b/docs/tutorial/electron-timelines.md index 259987b33ae0a..deb2e71125e13 100644 --- a/docs/tutorial/electron-timelines.md +++ b/docs/tutorial/electron-timelines.md @@ -9,11 +9,12 @@ check out our [Electron Versioning](./electron-versioning.md) doc. | Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported | | ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- | -| 39.0.0 | 2025-Sep-04 | 2025-Oct-01 | 2025-Oct-28 | 2026-May-05 | M142 | TBD | ✅ | +| 40.0.0 | 2025-Oct-30 | 2025-Dec-03 | 2026-Jan-13 | 2026-Jun-30 | M144 | TBD | ✅ | +| 39.0.0 | 2025-Sep-04 | 2025-Oct-01 | 2025-Oct-28 | 2026-May-05 | M142 | v22.20 | ✅ | | 38.0.0 | 2025-Jun-26 | 2025-Aug-06 | 2025-Sep-02 | 2026-Mar-10 | M140 | v22.18 | ✅ | | 37.0.0 | 2025-May-01 | 2025-May-28 | 2025-Jun-24 | 2026-Jan-13 | M138 | v22.16 | ✅ | -| 36.0.0 | 2025-Mar-06 | 2025-Apr-02 | 2025-Apr-29 | 2025-Oct-28 | M136 | v22.14 | ✅ | -| 35.0.0 | 2025-Jan-16 | 2025-Feb-05 | 2025-Mar-04 | 2025-Sep-02 | M134 | v22.14 | ✅ | +| 36.0.0 | 2025-Mar-06 | 2025-Apr-02 | 2025-Apr-29 | 2025-Oct-28 | M136 | v22.14 | 🚫 | +| 35.0.0 | 2025-Jan-16 | 2025-Feb-05 | 2025-Mar-04 | 2025-Sep-02 | M134 | v22.14 | 🚫 | | 34.0.0 | 2024-Oct-17 | 2024-Nov-13 | 2025-Jan-14 | 2025-Jun-24 | M132 | v20.18 | 🚫 | | 33.0.0 | 2024-Aug-22 | 2024-Sep-18 | 2024-Oct-15 | 2025-Apr-29 | M130 | v20.18 | 🚫 | | 32.0.0 | 2024-Jun-14 | 2024-Jul-24 | 2024-Aug-20 | 2025-Mar-04 | M128 | v20.16 | 🚫 | @@ -121,22 +122,3 @@ and that number is reduced to two in major version 10, the three-argument versio continue to work until, at minimum, major version 12. Past the minimum two-version threshold, we will attempt to support backwards compatibility beyond two versions until the maintainers feel the maintenance burden is too high to continue doing so. - -### End-of-life - -When a release branch reaches the end of its support cycle, the series -will be deprecated in NPM and a final end-of-support release will be -made. This release will add a warning to inform that an unsupported -version of Electron is in use. - -These steps are to help app developers learn when a branch they're -using becomes unsupported, but without being excessively intrusive -to end users. - -If an application has exceptional circumstances and needs to stay -on an unsupported series of Electron, developers can silence the -end-of-support warning by omitting the final release from the app's -`package.json` `devDependencies`. For example, since the 1-6-x series -ended with an end-of-support 1.6.18 release, developers could choose -to stay in the 1-6-x series without warnings with `devDependency` of -`"electron": 1.6.0 - 1.6.17`. diff --git a/docs/tutorial/esm.md b/docs/tutorial/esm.md index ae532fbba5b11..f1500eb5ff2b2 100644 --- a/docs/tutorial/esm.md +++ b/docs/tutorial/esm.md @@ -32,7 +32,7 @@ This table gives a general overview of where ESM is supported and which ESM load | Main | Node.js | N/A | <ul><li> [You must use `await` generously before the app's `ready` event](#you-must-use-await-generously-before-the-apps-ready-event) </li></ul> | | Renderer (Sandboxed) | Chromium | Unsupported | <ul><li> [Sandboxed preload scripts can't use ESM imports](#sandboxed-preload-scripts-cant-use-esm-imports) </li></ul> | | Renderer (Unsandboxed & Context Isolated) | Chromium | Node.js | <ul><li> [Unsandboxed ESM preload scripts will run after page load on pages with no content](#unsandboxed-esm-preload-scripts-will-run-after-page-load-on-pages-with-no-content) </li> <li>[ESM Preload Scripts must have the `.mjs` extension](#esm-preload-scripts-must-have-the-mjs-extension)</li></ul> | -| Renderer (Unsandboxed & Non Context Isolated) | Chromium | Node.js | <ul><li>[Unsandboxed ESM preload scripts will run after page load on pages with no content](#unsandboxed-esm-preload-scripts-will-run-after-page-load-on-pages-with-no-content)</li><li>[ESM Preload Scripts must have the `.mjs` extension](#esm-preload-scripts-must-have-the-mjs-extension)</li><li>[ESM preload scripts must be context isolated to use dynamic Node.js ESM imports](#esm-preload-scripts-must-be-context-isolated-to-use-dynamic-nodejs-esm-imports)</li></ul> | +| Renderer (Unsandboxed & Non Context Isolated) | Chromium | Node.js | <ul><li>[Unsandboxed ESM preload scripts will run after page load on pages with no content](#unsandboxed-esm-preload-scripts-will-run-after-page-load-on-pages-with-no-content)</li><li>[ESM Preload Scripts must have the `.mjs` extension](#esm-preload-scripts-must-have-the-mjs-extension)</li></ul> | ## Main process diff --git a/docs/tutorial/fuses.md b/docs/tutorial/fuses.md index c810d1af2a660..f5dc6a6ee4012 100644 --- a/docs/tutorial/fuses.md +++ b/docs/tutorial/fuses.md @@ -4,11 +4,24 @@ ## What are fuses? -For a subset of Electron functionality it makes sense to disable certain features for an entire application. For example, 99% of apps don't make use of `ELECTRON_RUN_AS_NODE`, these applications want to be able to ship a binary that is incapable of using that feature. We also don't want Electron consumers building Electron from source as that is both a massive technical challenge and has a high cost of both time and money. +From a security perspective, it makes sense to disable certain unused Electron features +that are powerful but may make your app's security posture weaker. For example, any app that doesn't +use the `ELECTRON_RUN_AS_NODE` environment variable would want to disable the feature to prevent a +subset of "living off the land" attacks. -Fuses are the solution to this problem, at a high level they are "magic bits" in the Electron binary that can be flipped when packaging your Electron app to enable / disable certain features / restrictions. Because they are flipped at package time before you code sign your app the OS becomes responsible for ensuring those bits aren't flipped back via OS level code signing validation (Gatekeeper / App Locker). +We also don't want Electron consumers forking to achieve this goal, as building from source and +maintaining a fork is a massive technical challenge and costs a lot of time and money. -## Current Fuses +Fuses are the solution to this problem. At a high level, they are "magic bits" in the Electron binary +that can be flipped when packaging your Electron app to enable or disable certain features/restrictions. + +Because they are flipped at package time before you code sign your app, the OS becomes responsible +for ensuring those bits aren't flipped back via OS-level code signing validation +(e.g. [Gatekeeper](https://support.apple.com/en-ca/guide/security/sec5599b66df/web) on macOS or +[AppLocker](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/applocker-overview) +on Windows). + +## Current fuses ### `runAsNode` @@ -16,7 +29,11 @@ Fuses are the solution to this problem, at a high level they are "magic bits" in **@electron/fuses:** `FuseV1Options.RunAsNode` -The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function. Instead, we recommend that you use [Utility Processes](../api/utility-process.md), which work for many use cases where you need a standalone Node.js process (like a Sqlite server process or similar scenarios). +The `runAsNode` fuse toggles whether the [`ELECTRON_RUN_AS_NODE`](../api/environment-variables.md) +environment variable is respected or not. With this fuse disabled, [`child_process.fork`](https://nodejs.org/api/child_process.html#child_processforkmodulepath-args-options) in the main process will not function +as expected, as it depends on this environment variable to function. Instead, we recommend that you +use [Utility Processes](../api/utility-process.md), which work for many use cases where you need a +standalone Node.js process (e.g. a SQLite server process). ### `cookieEncryption` @@ -24,7 +41,12 @@ The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variab **@electron/fuses:** `FuseV1Options.EnableCookieEncryption` -The cookieEncryption fuse toggles whether the cookie store on disk is encrypted using OS level cryptography keys. By default the sqlite database that Chromium uses to store cookies stores the values in plaintext. If you wish to ensure your apps cookies are encrypted in the same way Chrome does then you should enable this fuse. Please note it is a one-way transition, if you enable this fuse existing unencrypted cookies will be encrypted-on-write but if you then disable the fuse again your cookie store will effectively be corrupt and useless. Most apps can safely enable this fuse. +The `cookieEncryption` fuse toggles whether the cookie store on disk is encrypted using OS level +cryptography keys. By default, the SQLite database that Chromium uses to store cookies stores the +values in plaintext. If you wish to ensure your app's cookies are encrypted in the same way Chrome +does, then you should enable this fuse. Please note it is a one-way transition—if you enable this +fuse, existing unencrypted cookies will be encrypted-on-write, but subsequently disabling the fuse +later will make your cookie store corrupt and useless. Most apps can safely enable this fuse. ### `nodeOptions` @@ -32,7 +54,11 @@ The cookieEncryption fuse toggles whether the cookie store on disk is encrypted **@electron/fuses:** `FuseV1Options.EnableNodeOptionsEnvironmentVariable` -The nodeOptions fuse toggles whether the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions) and [`NODE_EXTRA_CA_CERTS`](https://github.com/nodejs/node/blob/main/doc/api/cli.md#node_extra_ca_certsfile) environment variables are respected. The `NODE_OPTIONS` environment variable can be used to pass all kinds of custom options to the Node.js runtime and isn't typically used by apps in production. Most apps can safely disable this fuse. +The `nodeOptions` fuse toggles whether the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions) +and [`NODE_EXTRA_CA_CERTS`](https://github.com/nodejs/node/blob/main/doc/api/cli.md#node_extra_ca_certsfile) +environment variables are respected. The `NODE_OPTIONS` environment variable can be used to pass all +kinds of custom options to the Node.js runtime and isn't typically used by apps in production. +Most apps can safely disable this fuse. ### `nodeCliInspect` @@ -40,7 +66,9 @@ The nodeOptions fuse toggles whether the [`NODE_OPTIONS`](https://nodejs.org/api **@electron/fuses:** `FuseV1Options.EnableNodeCliInspectArguments` -The nodeCliInspect fuse toggles whether the `--inspect`, `--inspect-brk`, etc. flags are respected or not. When disabled it also ensures that `SIGUSR1` signal does not initialize the main process inspector. Most apps can safely disable this fuse. +The `nodeCliInspect` fuse toggles whether the `--inspect`, `--inspect-brk`, etc. flags are respected +or not. When disabled, it also ensures that `SIGUSR1` signal does not initialize the main process +inspector. Most apps can safely disable this fuse. ### `embeddedAsarIntegrityValidation` @@ -48,9 +76,12 @@ The nodeCliInspect fuse toggles whether the `--inspect`, `--inspect-brk`, etc. f **@electron/fuses:** `FuseV1Options.EnableEmbeddedAsarIntegrityValidation` -The embeddedAsarIntegrityValidation fuse toggles an experimental feature on macOS and Windows that validates the content of the `app.asar` file when it is loaded. This feature is designed to have a minimal performance impact but may marginally slow down file reads from inside the `app.asar` archive. +The `embeddedAsarIntegrityValidation` fuse toggles a feature on macOS and Windows that validates the +content of the `app.asar` file when it is loaded. This feature is designed to have a minimal +performance impact but may marginally slow down file reads from inside the `app.asar` archive. +Most apps can safely enable this fuse. -For more information on how to use asar integrity validation please read the [Asar Integrity](asar-integrity.md) documentation. +For more information on how to use ASAR integrity validation, please read the [Asar Integrity](asar-integrity.md) documentation. ### `onlyLoadAppFromAsar` @@ -58,7 +89,15 @@ For more information on how to use asar integrity validation please read the [As **@electron/fuses:** `FuseV1Options.OnlyLoadAppFromAsar` -The onlyLoadAppFromAsar fuse changes the search system that Electron uses to locate your app code. By default Electron will search in the following order `app.asar` -> `app` -> `default_app.asar`. When this fuse is enabled the search order becomes a single entry `app.asar` thus ensuring that when combined with the `embeddedAsarIntegrityValidation` fuse it is impossible to load non-validated code. +The `onlyLoadAppFromAsar` fuse changes the search system that Electron uses to locate your app code. +By default, Electron will search for this code in the following order: + +1. `app.asar` +1. `app` +1. `default_app.asar` + +When this fuse is enabled, Electron will _only_ search for `app.asar`. When combined with the [`embeddedAsarIntegrityValidation`](#embeddedasarintegrityvalidation) fuse, this fuse ensures that +it is impossible to load non-validated code. ### `loadBrowserProcessSpecificV8Snapshot` @@ -66,11 +105,17 @@ The onlyLoadAppFromAsar fuse changes the search system that Electron uses to loc **@electron/fuses:** `FuseV1Options.LoadBrowserProcessSpecificV8Snapshot` -The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is used for the browser process. By default Electron's processes will all use the same V8 snapshot file. When this fuse is enabled the browser process uses the file called `browser_v8_context_snapshot.bin` for its V8 snapshot. The other processes will use the V8 snapshot file that they normally do. +V8 snapshots can be useful to improve app startup performance. V8 lets you take snapshots of +initialized heaps and then load them back in to avoid the cost of initializing the heap. -V8 snapshots can be useful to improve app startup performance. V8 lets you take snapshots of initialized heaps and then load them back in to avoid the cost of initializing the heap. +The `loadBrowserProcessSpecificV8Snapshot` fuse changes which V8 snapshot file is used for the browser +process. By default, Electron's processes will all use the same V8 snapshot file. When this fuse is +enabled, the main process uses the file called `browser_v8_context_snapshot.bin` for its V8 snapshot. +Other processes will use the V8 snapshot file that they normally do. -Using separate snapshots for renderer processes and the main process can improve security, especially to make sure that the renderer doesn't use a snapshot with `nodeIntegration` enabled. See [#35170](https://github.com/electron/electron/issues/35170) for details. +Using separate snapshots for renderer processes and the main process can improve security, especially +to make sure that the renderer doesn't use a snapshot with `nodeIntegration` enabled. +See [electron/electron#35170](https://github.com/electron/electron/issues/35170) for details. ### `grantFileProtocolExtraPrivileges` @@ -78,19 +123,25 @@ Using separate snapshots for renderer processes and the main process can improve **@electron/fuses:** `FuseV1Options.GrantFileProtocolExtraPrivileges` -The grantFileProtocolExtraPrivileges fuse changes whether pages loaded from the `file://` protocol are given privileges beyond what they would receive in a traditional web browser. This behavior was core to Electron apps in original versions of Electron but is no longer required as apps should be [serving local files from custom protocols](./security.md#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) now instead. If you aren't serving pages from `file://` you should disable this fuse. +The `grantFileProtocolExtraPrivileges` fuse changes whether pages loaded from the `file://` protocol +are given privileges beyond what they would receive in a traditional web browser. This behavior was +core to Electron apps in original versions of Electron, but is no longer required as apps should be +[serving local files from custom protocols](./security.md#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) now instead. + +If you aren't serving pages from `file://`, you should disable this fuse. The extra privileges granted to the `file://` protocol by this fuse are incompletely documented below: * `file://` protocol pages can use `fetch` to load other assets over `file://` * `file://` protocol pages can use service workers -* `file://` protocol pages have universal access granted to child frames also running on `file://` protocols regardless of sandbox settings +* `file://` protocol pages have universal access granted to child frames also running on `file://` + protocols regardless of sandbox settings -## How do I flip the fuses? +## How do I flip fuses? ### The easy way -We've made a handy module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases. +[`@electron/fuses`](https://npmjs.com/package/@electron/fuses) is a JavaScript utility designed to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases. ```js @ts-nocheck const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses') @@ -106,29 +157,37 @@ flipFuses( ) ``` -You can validate the fuses have been flipped or check the fuse status of an arbitrary Electron app using the fuses CLI. +You can validate the fuses that have been flipped or check the fuse status of an arbitrary Electron +app using the `@electron/fuses` CLI. ```bash npx @electron/fuses read --app /Applications/Foo.app ``` -### The hard way +>[!NOTE] +> If you are using Electron Forge to distribute your application, you can flip fuses using +> [`@electron-forge/plugin-fuses`](https://www.electronforge.io/config/plugins/fuses), +> which comes pre-installed with all templates. -#### Quick Glossary +### The hard way -* **Fuse Wire**: A sequence of bytes in the Electron binary used to control the fuses -* **Sentinel**: A static known sequence of bytes you can use to locate the fuse wire -* **Fuse Schema**: The format / allowed values for the fuse wire +> [!IMPORTANT] +> Glossary: +> +> * **Fuse Wire**: A sequence of bytes in the Electron binary used to control the fuses +> * **Sentinel**: A static known sequence of bytes you can use to locate the fuse wire +> * **Fuse Schema**: The format/allowed values for the fuse wire -Manually flipping fuses requires editing the Electron binary and modifying the fuse wire to be the sequence of bytes that represent the state of the fuses you want. +Manually flipping fuses requires editing the Electron binary and modifying the fuse wire to be the +sequence of bytes that represent the state of the fuses you want. -Somewhere in the Electron binary there will be a sequence of bytes that look like this: +Somewhere in the Electron binary, there will be a sequence of bytes that look like this: ```text | ...binary | sentinel_bytes | fuse_version | fuse_wire_length | fuse_wire | ...binary | ``` -* `sentinel_bytes` is always this exact string `dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX` +* `sentinel_bytes` is always this exact string: `dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX` * `fuse_version` is a single byte whose unsigned integer value represents the version of the fuse schema * `fuse_wire_length` is a single byte whose unsigned integer value represents the number of fuses in the following fuse wire * `fuse_wire` is a sequence of N bytes, each byte represents a single fuse and its state. @@ -136,6 +195,6 @@ Somewhere in the Electron binary there will be a sequence of bytes that look lik * "1" (0x31) indicates the fuse is enabled * "r" (0x72) indicates the fuse has been removed and changing the byte to either 1 or 0 will have no effect. -To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like. +To flip a fuse, you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like. You can view the current schema [here](https://github.com/electron/electron/blob/main/build/fuses/fuses.json5). diff --git a/docs/tutorial/installation.md b/docs/tutorial/installation.md index c96de676358da..821611a922505 100644 --- a/docs/tutorial/installation.md +++ b/docs/tutorial/installation.md @@ -26,12 +26,12 @@ any dependencies in your app will not be installed. ## Customization -If you want to change the architecture that is downloaded (e.g., `ia32` on an -`x64` machine), you can use the `--arch` flag with npm install or set the +If you want to change the architecture that is downloaded (e.g., `x64` on an +`arm64` machine), you can use the `--arch` flag with npm install or set the `npm_config_arch` environment variable: ```shell -npm install --arch=ia32 electron +npm install --arch=x64 electron ``` In addition to changing the architecture, you can also specify the platform @@ -60,7 +60,7 @@ where `$VERSION` is the exact version of Electron). If you are unable to access GitHub or you need to provide a custom build, you can do so by either providing a mirror or an existing cache directory. -#### Mirror +### Mirror You can use environment variables to override the base URL, the path at which to look for Electron binaries, and the binary filename. The URL used by `@electron/get` @@ -95,7 +95,7 @@ Electron release you may have to set `electron_use_remote_checksums=1` directly, or configure it in a `.npmrc` file, to force Electron to use the remote `SHASUMS256.txt` file to verify the checksum instead of the embedded checksums. -#### Cache +### Cache Alternatively, you can override the local cache. `@electron/get` will cache downloaded binaries in a local directory to not stress your network. You can use @@ -120,7 +120,7 @@ The cache contains the version's official zip file as well as a checksum, and is │ └── electron-v15.3.1-darwin-x64.zip ``` -## Skip binary download +## Postinstall script Under the hood, Electron's JavaScript API binds to a binary that contains its implementations. Because this binary is crucial to the function of any Electron app, diff --git a/docs/tutorial/native-file-drag-drop.md b/docs/tutorial/native-file-drag-drop.md index bf284cbb6da84..d9fa39c1a0088 100644 --- a/docs/tutorial/native-file-drag-drop.md +++ b/docs/tutorial/native-file-drag-drop.md @@ -110,4 +110,10 @@ the item is a Markdown file located in the root of the project: ![Drag and drop](../images/drag-and-drop.gif) +## Dragging files into your app + +You can use the standard +[Drag and Drop web API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API) +for dragging and dropping files into your app. + [`contextBridge`]: ../api/context-bridge.md diff --git a/docs/tutorial/online-offline-events.md b/docs/tutorial/online-offline-events.md index eb0f6dac25714..a3ff4b9b19f31 100644 --- a/docs/tutorial/online-offline-events.md +++ b/docs/tutorial/online-offline-events.md @@ -2,15 +2,15 @@ ## Overview -[Online and offline event](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) -detection can be implemented in the Renderer process using the -[`navigator.onLine`](http://html5index.org/Offline%20-%20NavigatorOnLine.html) -attribute, part of standard HTML5 API. +Online and offline event detection can be implemented in both the main and renderer processes: + +- **Renderer process**: Use the [`navigator.onLine`](http://html5index.org/Offline%20-%20NavigatorOnLine.html) attribute and [online/offline events](https://developer.mozilla.org/en-US/docs/Online_and_offline_events), part of standard HTML5 API. +- **Main process**: Use the [`net.isOnline()`](../api/net.md#netisonline) method or the [`net.online`](../api/net.md#netonline-readonly) property. The `navigator.onLine` attribute returns: -* `false` if all network requests are guaranteed to fail (e.g. when disconnected from the network). -* `true` in all other cases. +- `false` if all network requests are guaranteed to fail (e.g. when disconnected from the network). +- `true` in all other cases. Since many cases return `true`, you should treat with care situations of getting false positives, as we cannot always assume that `true` value means @@ -19,7 +19,27 @@ is running a virtualization software that has virtual Ethernet adapters in "alwa connected" state. Therefore, if you want to determine the Internet access status of Electron, you should develop additional means for this check. -## Example +## Main Process Detection + +In the main process, you can use the `net` module to detect online/offline status: + +```js +const { net } = require('electron') + +// Method 1: Using net.isOnline() +const isOnline = net.isOnline() +console.log('Online status:', isOnline) + +// Method 2: Using net.online property +console.log('Online status:', net.online) +``` + +Both `net.isOnline()` and `net.online` return the same boolean value with the same reliability characteristics as `navigator.onLine` - they provide a strong indicator when offline (`false`), but a `true` value doesn't guarantee successful internet connectivity. + +> [!NOTE] +> The `net` module is only available after the app emits the `ready` event. + +## Renderer Process Example Starting with an HTML file `index.html`, this example will demonstrate how the `navigator.onLine` API can be used to build a connection status indicator. @@ -84,4 +104,4 @@ After launching the Electron application, you should see the notification: ![Connection status](../images/connection-status.png) > [!NOTE] -> If you need to communicate the connection status to the main process, use the [IPC renderer](../api/ipc-renderer.md) API. +> If you need to check the connection status in the main process, you can use [`net.isOnline()`](../api/net.md#netisonline) directly instead of communicating from the renderer process via [IPC](../api/ipc-renderer.md). diff --git a/docs/tutorial/sandbox.md b/docs/tutorial/sandbox.md index 2580f1d92bc56..cbc0d13ae3ede 100644 --- a/docs/tutorial/sandbox.md +++ b/docs/tutorial/sandbox.md @@ -13,7 +13,13 @@ the GPU service and the network service. See Chromium's [Sandbox design document][sandbox] for more information. Starting from Electron 20, the sandbox is enabled for renderer processes without any -further configuration. If you want to disable the sandbox for a process, see the +further configuration. + +Sandboxing is tied to Node.js integration. _Enabling Node.js integration_ for a +renderer process by setting `nodeIntegration: true` _disables the sandbox_ for the +process. + +If you want to disable the sandbox for a process, see the [Disabling the sandbox for a single process](#disabling-the-sandbox-for-a-single-process) section. @@ -98,7 +104,8 @@ app.whenReady().then(() => { ``` Sandboxing is also disabled whenever Node.js integration is enabled in the renderer. -This can be done through the BrowserWindow constructor with the `nodeIntegration: true` flag. +This can be done through the BrowserWindow constructor with the `nodeIntegration: true` flag +or by providing the respective HTML boolean attribute for a `webview`. ```js title='main.js' app.whenReady().then(() => { @@ -111,6 +118,10 @@ app.whenReady().then(() => { }) ``` +```html title='index.html (Renderer Process)' +<webview nodeIntegration src="page.html"></webview> +``` + ### Enabling the sandbox globally If you want to force sandboxing for all renderers, you can also use the diff --git a/docs/tutorial/security.md b/docs/tutorial/security.md index 3b5c554b88dfa..8cbb262367a7a 100644 --- a/docs/tutorial/security.md +++ b/docs/tutorial/security.md @@ -98,7 +98,7 @@ either `process.env` or the `window` object. You should at least follow these steps to improve the security of your application: 1. [Only load secure content](#1-only-load-secure-content) -2. [Disable the Node.js integration in all renderers that display remote content](#2-do-not-enable-nodejs-integration-for-remote-content) +2. [Do not enable Node.js integration for remote content](#2-do-not-enable-nodejs-integration-for-remote-content) 3. [Enable context isolation in all renderers](#3-enable-context-isolation) 4. [Enable process sandboxing](#4-enable-process-sandboxing) 5. [Use `ses.setPermissionRequestHandler()` in all sessions that load remote content](#5-handle-session-permission-requests-from-remote-content) @@ -118,13 +118,6 @@ You should at least follow these steps to improve the security of your applicati 19. [Check which fuses you can change](#19-check-which-fuses-you-can-change) 20. [Do not expose Electron APIs to untrusted web content](#20-do-not-expose-electron-apis-to-untrusted-web-content) -To automate the detection of misconfigurations and insecure patterns, it is -possible to use -[Electronegativity](https://github.com/doyensec/electronegativity). For -additional details on potential weaknesses and implementation bugs when -developing applications using Electron, please refer to this -[guide for developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf). - ### 1. Only load secure content Any resources not included with your application should be loaded using a @@ -244,6 +237,10 @@ to enable this behavior. Even when `nodeIntegration: false` is used, to truly enforce strong isolation and prevent the use of Node primitives `contextIsolation` **must** also be used. +Beware that _disabling context isolation_ for a renderer process by setting +`nodeIntegration: true` _also disables process sandboxing_ for that process. +See section below. + :::info For more information on what `contextIsolation` is and how to enable it please see our dedicated [Context Isolation](context-isolation.md) document. @@ -251,6 +248,16 @@ see our dedicated [Context Isolation](context-isolation.md) document. ### 4. Enable process sandboxing +:::info +This recommendation is the default behavior in Electron since 20.0.0. + +Additionally, process sandboxing can be enforced for all renderer processes +application wide: [Enabling the sandbox globally](sandbox.md#enabling-the-sandbox-globally) + +_Disabling context isolation_ (see above) _also disables process sandboxing_, +regardless of the default, `sandbox: false` or globally enabled sandboxing! +::: + [Sandboxing](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md) is a Chromium feature that uses the operating system to significantly limit what renderer processes have access to. You should enable @@ -285,7 +292,7 @@ const { session } = require('electron') const { URL } = require('node:url') session - .fromPartition('some-partition') + .defaultSession .setPermissionRequestHandler((webContents, permission, callback) => { const parsedUrl = new URL(webContents.getURL()) @@ -302,6 +309,8 @@ session }) ``` +Note: `session.defaultSession` is only available after `app.whenReady` is called. + ### 6. Do not disable `webSecurity` :::info @@ -392,6 +401,8 @@ session.defaultSession.webRequest.onHeadersReceived((details, callback) => { }) ``` +Note: `session.defaultSession` is only available after `app.whenReady` is called. + #### CSP meta tag CSP's preferred delivery mechanism is an HTTP header. However, it is not possible @@ -804,10 +815,10 @@ that your application might have the rights for. #### How? -We've made a module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make +[`@electron/fuses`](https://npmjs.com/package/@electron/fuses) is a module we made to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases, and refer to -[How do I flip the fuses?](./fuses.md#how-do-i-flip-the-fuses) in our documentation. +[How do I flip fuses?](./fuses.md#how-do-i-flip-fuses) in our documentation. ### 20. Do not expose Electron APIs to untrusted web content diff --git a/docs/tutorial/tutorial-2-first-app.md b/docs/tutorial/tutorial-2-first-app.md index 465c98c0bf26e..ee830d3101ead 100644 --- a/docs/tutorial/tutorial-2-first-app.md +++ b/docs/tutorial/tutorial-2-first-app.md @@ -55,14 +55,27 @@ There are a few rules to follow for the purposes of this tutorial: - _author_, _license_, and _description_ can be any value, but will be necessary for [packaging][packaging] later on. +:::caution Install dependencies with a regular `node_modules` folder + +Electron's packaging toolchain requires the `node_modules` folder to be physically on disk in the +way that npm installs Node dependencies. By default, [Yarn Berry](https://yarnpkg.com/) and +[pnpm](http://pnpm.io/) both use alternative installation strategies. + +Therefore, you must set [`nodeLinker: node-modules`](https://yarnpkg.com/configuration/yarnrc#nodeLinker) +in Yarn or [`nodeLinker: hoisted`](https://pnpm.io/settings#nodelinker) in pnpm if you are using +those package managers. + +::: + Then, install Electron into your app's **devDependencies**, which is the list of external development-only package dependencies not required in production. -:::info Why is Electron a devDependency? +:::info Why is Electron a dev dependency? -This may seem counter-intuitive since your production code is running Electron APIs. -However, packaged apps will come bundled with the Electron binary, eliminating the need to specify -it as a production dependency. +This may seem counter-intuitive since your production code is running Electron APIs. Under the hood, +Electron's JavaScript API binds to a binary that contains its implementations. The packaging step for +Electron handles the bundling of this binary, eliminating the need to specify it as a production +dependency. ::: @@ -70,6 +83,17 @@ it as a production dependency. npm install electron --save-dev ``` +:::warning + +In order to correctly install Electron, you need to ensure that its `postinstall` lifecycle +script is able to run. This means avoiding the `--ignore-scripts` flag on npm and allowlisting +`electron` to run build scripts on other package managers. + +This is likely to change in a future version of Electron. See +[electron/rfcs#22](https://github.com/electron/rfcs/pull/22) for more details. + +::: + Your package.json file should look something like this after initializing your package and installing Electron. You should also now have a `node_modules` folder containing the Electron executable, as well as a `package-lock.json` lockfile that specifies diff --git a/docs/tutorial/window-state-persistence.md b/docs/tutorial/window-state-persistence.md new file mode 100644 index 0000000000000..492c84b2f0fb5 --- /dev/null +++ b/docs/tutorial/window-state-persistence.md @@ -0,0 +1,102 @@ +# Window State Persistence + +## Overview + +Window State Persistence allows your Electron application to automatically save and restore a window's position, size, and display modes (such as maximized or fullscreen states) across application restarts. + +This feature is particularly useful for applications where users frequently resize, move, or maximize windows and expect them to remain in the same state when reopening the app. + +## Usage + +### Basic usage + +To enable Window State Persistence, simply set `windowStatePersistence: true` in your window constructor options and provide a unique `name` for the window. + +```js +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + name: 'main-window', + width: 800, + height: 600, + windowStatePersistence: true + }) + + win.loadFile('index.html') +} + +app.whenReady().then(createWindow) +``` + +With this configuration, Electron will automatically: + +1. Restore the window's position, size, and display mode when created (if a previous state exists) +2. Save the window state whenever it changes (position, size, or display mode). +3. Emit a `restored-persisted-state` event after successfully restoring state. +4. Adapt restored window state to multi-monitor setups and display changes automatically. + +> [!NOTE] +> Window State Persistence requires that the window has a unique `name` property set in its constructor options. This name serves as the identifier for storing and retrieving the window's saved state. + +### Selective persistence + +You can control which aspects of the window state are persisted by passing an object with specific options: + +```js +const { app, BrowserWindow } = require('electron') + +function createWindow () { + const win = new BrowserWindow({ + name: 'main-window', + width: 800, + height: 600, + windowStatePersistence: { + bounds: true, // Save position and size (default: true) + displayMode: false // Don't save maximized/fullscreen/kiosk state (default: true) + } + }) + + win.loadFile('index.html') +} + +app.whenReady().then(createWindow) +``` + +In this example, the window will remember its position and size but will always start in normal mode, even if it was maximized or fullscreened when last closed. + +### Clearing persisted state + +You can programmatically clear the saved state for a specific window using the static `clearPersistedState` method: + +```js +const { BrowserWindow } = require('electron') + +// Clear saved state for a specific window +BrowserWindow.clearPersistedState('main-window') + +// Now when you create a window with this name, +// it will use the default constructor options +const win = new BrowserWindow({ + name: 'main-window', + width: 800, + height: 600, + windowStatePersistence: true +}) +``` + +## API Reference + +The Window State Persistence APIs are available on both `BaseWindow` and `BrowserWindow` (since `BrowserWindow` extends `BaseWindow`) and work identically. + +For complete API documentation, see: + +- [`windowStatePersistence` in BaseWindowConstructorOptions][base-window-options] +- [`WindowStatePersistence` object structure][window-state-persistence-structure] +- [`BaseWindow.clearPersistedState()`][clear-persisted-state] +- [`restored-persisted-state` event][restored-event] + +[base-window-options]: ../api/structures/base-window-options.md +[window-state-persistence-structure]: ../api/structures/window-state-persistence.md +[clear-persisted-state]: ../api/base-window.md#basewindowclearpersistedstatename +[restored-event]: ../api/base-window.md#event-restored-persisted-state diff --git a/filenames.auto.gni b/filenames.auto.gni index 9491b55b149ae..fb53337584f69 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -52,6 +52,7 @@ auto_filenames = { "docs/api/service-workers.md", "docs/api/session.md", "docs/api/share-menu.md", + "docs/api/shared-texture.md", "docs/api/shell.md", "docs/api/structures", "docs/api/system-preferences.md", @@ -145,6 +146,12 @@ auto_filenames = { "docs/api/structures/shared-dictionary-info.md", "docs/api/structures/shared-dictionary-usage-info.md", "docs/api/structures/shared-texture-handle.md", + "docs/api/structures/shared-texture-import-texture-info.md", + "docs/api/structures/shared-texture-imported-subtle.md", + "docs/api/structures/shared-texture-imported.md", + "docs/api/structures/shared-texture-subtle.md", + "docs/api/structures/shared-texture-sync-token.md", + "docs/api/structures/shared-texture-transfer.md", "docs/api/structures/shared-worker-info.md", "docs/api/structures/sharing-item.md", "docs/api/structures/shortcut-details.md", @@ -164,6 +171,7 @@ auto_filenames = { "docs/api/structures/web-source.md", "docs/api/structures/window-open-handler-response.md", "docs/api/structures/window-session-end-event.md", + "docs/api/structures/window-state-persistence.md", ] sandbox_bundle_deps = [ @@ -176,6 +184,7 @@ auto_filenames = { "lib/renderer/api/context-bridge.ts", "lib/renderer/api/crash-reporter.ts", "lib/renderer/api/ipc-renderer.ts", + "lib/renderer/api/shared-texture.ts", "lib/renderer/api/web-frame.ts", "lib/renderer/api/web-utils.ts", "lib/renderer/common-init.ts", @@ -257,6 +266,7 @@ auto_filenames = { "lib/browser/api/service-worker-main.ts", "lib/browser/api/session.ts", "lib/browser/api/share-menu.ts", + "lib/browser/api/shared-texture.ts", "lib/browser/api/system-preferences.ts", "lib/browser/api/touch-bar.ts", "lib/browser/api/tray.ts", @@ -312,6 +322,7 @@ auto_filenames = { "lib/renderer/api/exports/electron.ts", "lib/renderer/api/ipc-renderer.ts", "lib/renderer/api/module-list.ts", + "lib/renderer/api/shared-texture.ts", "lib/renderer/api/web-frame.ts", "lib/renderer/api/web-utils.ts", "lib/renderer/common-init.ts", @@ -352,6 +363,7 @@ auto_filenames = { "lib/renderer/api/exports/electron.ts", "lib/renderer/api/ipc-renderer.ts", "lib/renderer/api/module-list.ts", + "lib/renderer/api/shared-texture.ts", "lib/renderer/api/web-frame.ts", "lib/renderer/api/web-utils.ts", "lib/renderer/ipc-renderer-bindings.ts", diff --git a/filenames.gni b/filenames.gni index 488058008c20e..21b57205fed3b 100644 --- a/filenames.gni +++ b/filenames.gni @@ -194,6 +194,8 @@ filenames = { "shell/common/api/electron_api_clipboard_mac.mm", "shell/common/api/electron_api_native_image_mac.mm", "shell/common/asar/archive_mac.mm", + "shell/common/asar/integrity_digest.h", + "shell/common/asar/integrity_digest.mm", "shell/common/application_info_mac.mm", "shell/common/language_util_mac.mm", "shell/common/mac/main_application_bundle.h", @@ -456,7 +458,6 @@ filenames = { "shell/browser/net/system_network_context_manager.h", "shell/browser/net/url_loader_network_observer.cc", "shell/browser/net/url_loader_network_observer.h", - "shell/browser/net/web_request_api_interface.h", "shell/browser/network_hints_handler_impl.cc", "shell/browser/network_hints_handler_impl.h", "shell/browser/notifications/notification.cc", @@ -564,6 +565,7 @@ filenames = { "shell/common/api/electron_api_native_image.cc", "shell/common/api/electron_api_native_image.h", "shell/common/api/electron_api_net.cc", + "shell/common/api/electron_api_shared_texture.cc", "shell/common/api/electron_api_shell.cc", "shell/common/api/electron_api_testing.cc", "shell/common/api/electron_api_url_loader.cc", @@ -580,6 +582,7 @@ filenames = { "shell/common/asar/asar_util.h", "shell/common/asar/scoped_temporary_file.cc", "shell/common/asar/scoped_temporary_file.h", + "shell/common/callback_util.h", "shell/common/color_util.cc", "shell/common/color_util.h", "shell/common/crash_keys.cc", @@ -629,8 +632,6 @@ filenames = { "shell/common/gin_converters/usb_device_info_converter.h", "shell/common/gin_converters/value_converter.cc", "shell/common/gin_converters/value_converter.h", - "shell/common/gin_helper/arguments.cc", - "shell/common/gin_helper/arguments.h", "shell/common/gin_helper/callback.cc", "shell/common/gin_helper/callback.h", "shell/common/gin_helper/cleaned_up_at_exit.cc", diff --git a/filenames.hunspell.gni b/filenames.hunspell.gni index 64574354e4244..38c2c1fc2b4f6 100644 --- a/filenames.hunspell.gni +++ b/filenames.hunspell.gni @@ -7,21 +7,17 @@ hunspell_dictionaries = [ "//third_party/hunspell_dictionaries/da-DK-3-0.bdic", "//third_party/hunspell_dictionaries/de-DE-3-0.bdic", "//third_party/hunspell_dictionaries/el-GR-3-0.bdic", - "//third_party/hunspell_dictionaries/en-AU-10-0.bdic", "//third_party/hunspell_dictionaries/en-AU-10-1.bdic", - "//third_party/hunspell_dictionaries/en-CA-10-0.bdic", "//third_party/hunspell_dictionaries/en-CA-10-1.bdic", - "//third_party/hunspell_dictionaries/en-GB-10-0.bdic", "//third_party/hunspell_dictionaries/en-GB-10-1.bdic", - "//third_party/hunspell_dictionaries/en-GB-oxendict-10-0.bdic", "//third_party/hunspell_dictionaries/en-GB-oxendict-10-1.bdic", - "//third_party/hunspell_dictionaries/en-US-10-0.bdic", "//third_party/hunspell_dictionaries/en-US-10-1.bdic", "//third_party/hunspell_dictionaries/es-ES-3-0.bdic", "//third_party/hunspell_dictionaries/et-EE-3-0.bdic", "//third_party/hunspell_dictionaries/fa-IR-9-0.bdic", "//third_party/hunspell_dictionaries/fo-FO-3-0.bdic", "//third_party/hunspell_dictionaries/fr-FR-3-0.bdic", + "//third_party/hunspell_dictionaries/gl-1-0.bdic", "//third_party/hunspell_dictionaries/he-IL-3-0.bdic", "//third_party/hunspell_dictionaries/hi-IN-3-0.bdic", "//third_party/hunspell_dictionaries/hr-HR-3-0.bdic", @@ -59,6 +55,7 @@ hunspell_dictionaries = [ hunspell_licenses = [ "//third_party/hunspell_dictionaries/COPYING", "//third_party/hunspell_dictionaries/COPYING.Apache", + "//third_party/hunspell_dictionaries/COPYING.GPL3", "//third_party/hunspell_dictionaries/COPYING.LESSER", "//third_party/hunspell_dictionaries/COPYING.LGPL", "//third_party/hunspell_dictionaries/COPYING.MIT", diff --git a/filenames.libcxx.gni b/filenames.libcxx.gni index 1b32357d69c4a..9b728cc89f8ea 100644 --- a/filenames.libcxx.gni +++ b/filenames.libcxx.gni @@ -217,6 +217,7 @@ libcxx_headers = [ "//third_party/libc++/src/include/__atomic/check_memory_order.h", "//third_party/libc++/src/include/__atomic/contention_t.h", "//third_party/libc++/src/include/__atomic/fence.h", + "//third_party/libc++/src/include/__atomic/floating_point_helper.h", "//third_party/libc++/src/include/__atomic/is_always_lock_free.h", "//third_party/libc++/src/include/__atomic/kill_dependency.h", "//third_party/libc++/src/include/__atomic/memory_order.h", @@ -840,7 +841,6 @@ libcxx_headers = [ "//third_party/libc++/src/include/__cxx03/cmath", "//third_party/libc++/src/include/__cxx03/codecvt", "//third_party/libc++/src/include/__cxx03/complex", - "//third_party/libc++/src/include/__cxx03/complex.h", "//third_party/libc++/src/include/__cxx03/condition_variable", "//third_party/libc++/src/include/__cxx03/csetjmp", "//third_party/libc++/src/include/__cxx03/csignal", @@ -853,25 +853,20 @@ libcxx_headers = [ "//third_party/libc++/src/include/__cxx03/cstring", "//third_party/libc++/src/include/__cxx03/ctgmath", "//third_party/libc++/src/include/__cxx03/ctime", - "//third_party/libc++/src/include/__cxx03/ctype.h", "//third_party/libc++/src/include/__cxx03/cuchar", "//third_party/libc++/src/include/__cxx03/cwchar", "//third_party/libc++/src/include/__cxx03/cwctype", "//third_party/libc++/src/include/__cxx03/deque", - "//third_party/libc++/src/include/__cxx03/errno.h", "//third_party/libc++/src/include/__cxx03/exception", "//third_party/libc++/src/include/__cxx03/experimental/__config", "//third_party/libc++/src/include/__cxx03/experimental/utility", "//third_party/libc++/src/include/__cxx03/ext/__hash", "//third_party/libc++/src/include/__cxx03/ext/hash_map", "//third_party/libc++/src/include/__cxx03/ext/hash_set", - "//third_party/libc++/src/include/__cxx03/fenv.h", - "//third_party/libc++/src/include/__cxx03/float.h", "//third_party/libc++/src/include/__cxx03/forward_list", "//third_party/libc++/src/include/__cxx03/fstream", "//third_party/libc++/src/include/__cxx03/functional", "//third_party/libc++/src/include/__cxx03/future", - "//third_party/libc++/src/include/__cxx03/inttypes.h", "//third_party/libc++/src/include/__cxx03/iomanip", "//third_party/libc++/src/include/__cxx03/ios", "//third_party/libc++/src/include/__cxx03/iosfwd", @@ -898,11 +893,8 @@ libcxx_headers = [ "//third_party/libc++/src/include/__cxx03/sstream", "//third_party/libc++/src/include/__cxx03/stack", "//third_party/libc++/src/include/__cxx03/stdatomic.h", - "//third_party/libc++/src/include/__cxx03/stdbool.h", - "//third_party/libc++/src/include/__cxx03/stddef.h", "//third_party/libc++/src/include/__cxx03/stdexcept", "//third_party/libc++/src/include/__cxx03/stdint.h", - "//third_party/libc++/src/include/__cxx03/stdio.h", "//third_party/libc++/src/include/__cxx03/stdlib.h", "//third_party/libc++/src/include/__cxx03/streambuf", "//third_party/libc++/src/include/__cxx03/string", @@ -910,7 +902,6 @@ libcxx_headers = [ "//third_party/libc++/src/include/__cxx03/string_view", "//third_party/libc++/src/include/__cxx03/strstream", "//third_party/libc++/src/include/__cxx03/system_error", - "//third_party/libc++/src/include/__cxx03/tgmath.h", "//third_party/libc++/src/include/__cxx03/thread", "//third_party/libc++/src/include/__cxx03/type_traits", "//third_party/libc++/src/include/__cxx03/typeindex", @@ -923,7 +914,6 @@ libcxx_headers = [ "//third_party/libc++/src/include/__cxx03/vector", "//third_party/libc++/src/include/__cxx03/version", "//third_party/libc++/src/include/__cxx03/wchar.h", - "//third_party/libc++/src/include/__cxx03/wctype.h", "//third_party/libc++/src/include/__debug_utils/randomize_range.h", "//third_party/libc++/src/include/__debug_utils/sanitizers.h", "//third_party/libc++/src/include/__debug_utils/strict_weak_ordering_check.h", @@ -1034,14 +1024,12 @@ libcxx_headers = [ "//third_party/libc++/src/include/__fwd/get.h", "//third_party/libc++/src/include/__fwd/ios.h", "//third_party/libc++/src/include/__fwd/istream.h", - "//third_party/libc++/src/include/__fwd/map.h", "//third_party/libc++/src/include/__fwd/mdspan.h", "//third_party/libc++/src/include/__fwd/memory.h", "//third_party/libc++/src/include/__fwd/memory_resource.h", "//third_party/libc++/src/include/__fwd/ostream.h", "//third_party/libc++/src/include/__fwd/pair.h", "//third_party/libc++/src/include/__fwd/queue.h", - "//third_party/libc++/src/include/__fwd/set.h", "//third_party/libc++/src/include/__fwd/span.h", "//third_party/libc++/src/include/__fwd/sstream.h", "//third_party/libc++/src/include/__fwd/stack.h", @@ -1117,6 +1105,7 @@ libcxx_headers = [ "//third_party/libc++/src/include/__locale_dir/support/freebsd.h", "//third_party/libc++/src/include/__locale_dir/support/fuchsia.h", "//third_party/libc++/src/include/__locale_dir/support/linux.h", + "//third_party/libc++/src/include/__locale_dir/support/netbsd.h", "//third_party/libc++/src/include/__locale_dir/support/no_locale/characters.h", "//third_party/libc++/src/include/__locale_dir/support/no_locale/strtonum.h", "//third_party/libc++/src/include/__locale_dir/support/windows.h", @@ -1367,11 +1356,9 @@ libcxx_headers = [ "//third_party/libc++/src/include/__tree", "//third_party/libc++/src/include/__tuple/find_index.h", "//third_party/libc++/src/include/__tuple/ignore.h", - "//third_party/libc++/src/include/__tuple/make_tuple_types.h", "//third_party/libc++/src/include/__tuple/sfinae_helpers.h", "//third_party/libc++/src/include/__tuple/tuple_element.h", "//third_party/libc++/src/include/__tuple/tuple_like.h", - "//third_party/libc++/src/include/__tuple/tuple_like_ext.h", "//third_party/libc++/src/include/__tuple/tuple_like_no_subrange.h", "//third_party/libc++/src/include/__tuple/tuple_size.h", "//third_party/libc++/src/include/__tuple/tuple_types.h", @@ -1381,7 +1368,6 @@ libcxx_headers = [ "//third_party/libc++/src/include/__type_traits/aligned_storage.h", "//third_party/libc++/src/include/__type_traits/aligned_union.h", "//third_party/libc++/src/include/__type_traits/alignment_of.h", - "//third_party/libc++/src/include/__type_traits/can_extract_key.h", "//third_party/libc++/src/include/__type_traits/common_reference.h", "//third_party/libc++/src/include/__type_traits/common_type.h", "//third_party/libc++/src/include/__type_traits/conditional.h", @@ -1429,6 +1415,7 @@ libcxx_headers = [ "//third_party/libc++/src/include/__type_traits/is_floating_point.h", "//third_party/libc++/src/include/__type_traits/is_function.h", "//third_party/libc++/src/include/__type_traits/is_fundamental.h", + "//third_party/libc++/src/include/__type_traits/is_generic_transparent_comparator.h", "//third_party/libc++/src/include/__type_traits/is_implicit_lifetime.h", "//third_party/libc++/src/include/__type_traits/is_implicitly_default_constructible.h", "//third_party/libc++/src/include/__type_traits/is_integral.h", @@ -1462,14 +1449,17 @@ libcxx_headers = [ "//third_party/libc++/src/include/__type_traits/is_trivially_relocatable.h", "//third_party/libc++/src/include/__type_traits/is_unbounded_array.h", "//third_party/libc++/src/include/__type_traits/is_union.h", + "//third_party/libc++/src/include/__type_traits/is_unqualified.h", "//third_party/libc++/src/include/__type_traits/is_unsigned.h", "//third_party/libc++/src/include/__type_traits/is_valid_expansion.h", "//third_party/libc++/src/include/__type_traits/is_void.h", "//third_party/libc++/src/include/__type_traits/is_volatile.h", + "//third_party/libc++/src/include/__type_traits/is_within_lifetime.h", "//third_party/libc++/src/include/__type_traits/lazy.h", "//third_party/libc++/src/include/__type_traits/make_32_64_or_128_bit.h", "//third_party/libc++/src/include/__type_traits/make_const_lvalue_ref.h", "//third_party/libc++/src/include/__type_traits/make_signed.h", + "//third_party/libc++/src/include/__type_traits/make_transparent.h", "//third_party/libc++/src/include/__type_traits/make_unsigned.h", "//third_party/libc++/src/include/__type_traits/maybe_const.h", "//third_party/libc++/src/include/__type_traits/nat.h", @@ -1501,6 +1491,7 @@ libcxx_headers = [ "//third_party/libc++/src/include/__utility/cmp.h", "//third_party/libc++/src/include/__utility/convert_to_integral.h", "//third_party/libc++/src/include/__utility/declval.h", + "//third_party/libc++/src/include/__utility/default_three_way_comparator.h", "//third_party/libc++/src/include/__utility/element_count.h", "//third_party/libc++/src/include/__utility/empty.h", "//third_party/libc++/src/include/__utility/exception_guard.h", @@ -1511,6 +1502,7 @@ libcxx_headers = [ "//third_party/libc++/src/include/__utility/integer_sequence.h", "//third_party/libc++/src/include/__utility/is_pointer_in_range.h", "//third_party/libc++/src/include/__utility/is_valid_range.h", + "//third_party/libc++/src/include/__utility/lazy_synth_three_way_comparator.h", "//third_party/libc++/src/include/__utility/move.h", "//third_party/libc++/src/include/__utility/no_destroy.h", "//third_party/libc++/src/include/__utility/pair.h", @@ -1522,6 +1514,7 @@ libcxx_headers = [ "//third_party/libc++/src/include/__utility/small_buffer.h", "//third_party/libc++/src/include/__utility/swap.h", "//third_party/libc++/src/include/__utility/to_underlying.h", + "//third_party/libc++/src/include/__utility/try_key_extraction.h", "//third_party/libc++/src/include/__utility/unreachable.h", "//third_party/libc++/src/include/__variant/monostate.h", "//third_party/libc++/src/include/__vector/comparison.h", diff --git a/lib/browser/api/browser-window.ts b/lib/browser/api/browser-window.ts index c8938a580fc1f..842a36fb75395 100644 --- a/lib/browser/api/browser-window.ts +++ b/lib/browser/api/browser-window.ts @@ -111,6 +111,8 @@ BrowserWindow.getAllWindows = () => { return BaseWindow.getAllWindows().filter(isBrowserWindow) as any[] as BWT[]; }; +BrowserWindow.clearPersistedState = BaseWindow.clearPersistedState; + BrowserWindow.getFocusedWindow = () => { for (const window of BrowserWindow.getAllWindows()) { if (!window.isDestroyed() && window.webContents && !window.webContents.isDestroyed()) { diff --git a/lib/browser/api/menu.ts b/lib/browser/api/menu.ts index 10cad67f10c43..5f607b4ed3980 100644 --- a/lib/browser/api/menu.ts +++ b/lib/browser/api/menu.ts @@ -25,13 +25,32 @@ Menu.prototype._isCommandIdChecked = function (id) { }; Menu.prototype._isCommandIdEnabled = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].enabled : false; + const item = this.commandsMap[id]; + if (!item) return false; + + const focusedWindow = BaseWindow.getFocusedWindow(); + + if (item.role === 'minimize' && focusedWindow) { + return focusedWindow.isMinimizable(); + } + + if (item.role === 'togglefullscreen' && focusedWindow) { + return focusedWindow.isFullScreenable(); + } + + if (item.role === 'close' && focusedWindow) { + return focusedWindow.isClosable(); + } + + return item.enabled; }; + Menu.prototype._shouldCommandIdWorkWhenHidden = function (id) { - return this.commandsMap[id] ? !!this.commandsMap[id].acceleratorWorksWhenHidden : false; + return this.commandsMap[id]?.acceleratorWorksWhenHidden ?? false; }; + Menu.prototype._isCommandIdVisible = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].visible : false; + return this.commandsMap[id]?.visible ?? false; }; Menu.prototype._getAcceleratorForCommandId = function (id, useDefaultAccelerator) { @@ -42,12 +61,12 @@ Menu.prototype._getAcceleratorForCommandId = function (id, useDefaultAccelerator }; Menu.prototype._shouldRegisterAcceleratorForCommandId = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : false; + return this.commandsMap[id]?.registerAccelerator ?? false; }; if (process.platform === 'darwin') { Menu.prototype._getSharingItemForCommandId = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].sharingItem : null; + return this.commandsMap[id]?.sharingItem ?? null; }; } diff --git a/lib/browser/api/module-list.ts b/lib/browser/api/module-list.ts index 81547d159a60c..8463e7027eb17 100644 --- a/lib/browser/api/module-list.ts +++ b/lib/browser/api/module-list.ts @@ -31,6 +31,7 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [ { name: 'screen', loader: () => require('./screen') }, { name: 'ServiceWorkerMain', loader: () => require('./service-worker-main') }, { name: 'session', loader: () => require('./session') }, + { name: 'sharedTexture', loader: () => require('./shared-texture') }, { name: 'ShareMenu', loader: () => require('./share-menu') }, { name: 'systemPreferences', loader: () => require('./system-preferences') }, { name: 'TouchBar', loader: () => require('./touch-bar') }, diff --git a/lib/browser/api/net-fetch.ts b/lib/browser/api/net-fetch.ts index 54fdc788d6c6d..40e1a635fd362 100644 --- a/lib/browser/api/net-fetch.ts +++ b/lib/browser/api/net-fetch.ts @@ -119,7 +119,10 @@ export function fetchWithSession (input: RequestInfo, init: (RequestInit & {bypa p.reject(err); }); - if (!req.body?.pipeTo(Writable.toWeb(r as unknown as Writable)).then(() => r.end())) { r.end(); } + // pipeTo expects a WritableStream<Uint8Array>. Node.js' Writable.toWeb returns WritableStream<any>, + // which causes a TS structural mismatch. + const writable = Writable.toWeb(r as unknown as Writable) as unknown as WritableStream<Uint8Array>; + if (!req.body?.pipeTo(writable).then(() => r.end())) { r.end(); } return p.promise; } diff --git a/lib/browser/api/protocol.ts b/lib/browser/api/protocol.ts index cb6a1492eb227..9fd579b98681e 100644 --- a/lib/browser/api/protocol.ts +++ b/lib/browser/api/protocol.ts @@ -4,6 +4,8 @@ import { createReadStream } from 'fs'; import { Readable } from 'stream'; import { ReadableStream } from 'stream/web'; +import type { ReadableStreamDefaultReader } from 'stream/web'; + // Global protocol APIs. const { registerSchemesAsPrivileged, getStandardSchemes, Protocol } = process._linkedBinding('electron_browser_protocol'); @@ -12,7 +14,7 @@ const ERR_UNEXPECTED = -9; const isBuiltInScheme = (scheme: string) => ['http', 'https', 'file'].includes(scheme); -function makeStreamFromPipe (pipe: any): ReadableStream { +function makeStreamFromPipe (pipe: any): ReadableStream<Uint8Array> { const buf = new Uint8Array(1024 * 1024 /* 1 MB */); return new ReadableStream({ async pull (controller) { @@ -38,21 +40,26 @@ function makeStreamFromFileInfo ({ filePath: string; offset?: number; length?: number; -}): ReadableStream { +}): ReadableStream<Uint8Array> { + // Node's Readable.toWeb produces a WHATWG ReadableStream whose chunks are Uint8Array. return Readable.toWeb(createReadStream(filePath, { start: offset, end: length >= 0 ? offset + length : undefined - })); + })) as ReadableStream<Uint8Array>; } function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] { if (!uploadData) return null; // Optimization: skip creating a stream if the request is just a single buffer. - if (uploadData.length === 1 && (uploadData[0] as any).type === 'rawData') return uploadData[0].bytes; + if (uploadData.length === 1 && (uploadData[0] as any).type === 'rawData') { + return uploadData[0].bytes as any; + } - const chunks = [...uploadData] as any[]; // TODO: types are wrong - let current: ReadableStreamDefaultReader | null = null; - return new ReadableStream({ + const chunks = [...uploadData] as any[]; // TODO: refine ProtocolRequest types + // Use Node's web stream types explicitly to avoid DOM lib vs Node lib structural mismatches. + // Generic <Uint8Array> ensures reader.read() returns value?: Uint8Array consistent with enqueue. + let current: ReadableStreamDefaultReader<Uint8Array> | null = null; + return new ReadableStream<Uint8Array>({ async pull (controller) { if (current) { const { done, value } = await current.read(); @@ -67,7 +74,7 @@ function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): Reque if (!chunks.length) { return controller.close(); } const chunk = chunks.shift()!; if (chunk.type === 'rawData') { - controller.enqueue(chunk.bytes); + controller.enqueue(chunk.bytes as Uint8Array); } else if (chunk.type === 'file') { current = makeStreamFromFileInfo(chunk).getReader(); return this.pull!(controller); diff --git a/lib/browser/api/shared-texture.ts b/lib/browser/api/shared-texture.ts new file mode 100644 index 0000000000000..85fcd49001168 --- /dev/null +++ b/lib/browser/api/shared-texture.ts @@ -0,0 +1,191 @@ +import ipcMain from '@electron/internal/browser/api/ipc-main'; +import * as ipcMainInternalUtils from '@electron/internal/browser/ipc-main-internal-utils'; +import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; + +import { randomUUID } from 'crypto'; + +const transferTimeout = 1000; +const sharedTextureNative = process._linkedBinding('electron_common_shared_texture'); +const managedSharedTextures = new Map<string, SharedTextureImportedWrapper>(); + +type AllReleasedCallback = (imported: Electron.SharedTextureImported) => void; + +type SharedTextureImportedWrapper = { + texture: Electron.SharedTextureImported; + allReferencesReleased: AllReleasedCallback | undefined; + mainReference: boolean; + rendererFrameReferences: Map<number, { count: number, reference: Electron.WebFrameMain }>; +} + +ipcMain.handle(IPC_MESSAGES.IMPORT_SHARED_TEXTURE_RELEASE_RENDERER_TO_MAIN, (event: Electron.IpcMainInvokeEvent, textureId: string) => { + const frameTreeNodeId = event.frameTreeNodeId ?? event.sender.mainFrame.frameTreeNodeId; + wrapperReleaseFromRenderer(textureId, frameTreeNodeId); +}); + +let checkManagedSharedTexturesInterval: NodeJS.Timeout | null = null; + +function scheduleCheckManagedSharedTextures () { + if (checkManagedSharedTexturesInterval === null) { + checkManagedSharedTexturesInterval = setInterval(checkManagedSharedTextures, 1000); + } +} + +function unscheduleCheckManagedSharedTextures () { + if (checkManagedSharedTexturesInterval !== null) { + clearInterval(checkManagedSharedTexturesInterval); + checkManagedSharedTexturesInterval = null; + } +} + +function checkManagedSharedTextures () { + const texturesToRemoveTracking = new Set<string>(); + for (const [, wrapper] of managedSharedTextures) { + for (const [frameTreeNodeId, entry] of wrapper.rendererFrameReferences) { + const frame = entry.reference; + if (!frame || frame.isDestroyed()) { + console.error(`The imported shared texture ${wrapper.texture.textureId} is referenced by a destroyed webContent/webFrameMain, this means a imported shared texture in renderer process is not released before the process is exited. Releasing that dangling reference now.`); + wrapper.rendererFrameReferences.delete(frameTreeNodeId); + } + } + + if (wrapper.rendererFrameReferences.size === 0 && !wrapper.mainReference) { + texturesToRemoveTracking.add(wrapper.texture.textureId); + wrapper.texture.subtle.release(() => { + wrapper.allReferencesReleased?.(wrapper.texture); + }); + } + } + + for (const id of texturesToRemoveTracking) { + managedSharedTextures.delete(id); + } + + if (managedSharedTextures.size === 0) { + unscheduleCheckManagedSharedTextures(); + } +} + +function wrapperReleaseFromRenderer (id: string, frameTreeNodeId: number) { + const wrapper = managedSharedTextures.get(id); + if (!wrapper) { + throw new Error(`Shared texture with id ${id} not found`); + } + + const entry = wrapper.rendererFrameReferences.get(frameTreeNodeId); + if (!entry) { + throw new Error(`Shared texture ${id} is not referenced by renderer frame ${frameTreeNodeId}`); + } + + entry.count -= 1; + if (entry.count === 0) { + wrapper.rendererFrameReferences.delete(frameTreeNodeId); + } else { + wrapper.rendererFrameReferences.set(frameTreeNodeId, entry); + } + + // Actually release the texture if no one is referencing it + if (wrapper.rendererFrameReferences.size === 0 && !wrapper.mainReference) { + managedSharedTextures.delete(id); + wrapper.texture.subtle.release(() => { + wrapper.allReferencesReleased?.(wrapper.texture); + }); + } +} + +function wrapperReleaseFromMain (id: string) { + const wrapper = managedSharedTextures.get(id); + if (!wrapper) { + throw new Error(`Shared texture with id ${id} not found`); + } + + // Actually release the texture if no one is referencing it + wrapper.mainReference = false; + if (wrapper.rendererFrameReferences.size === 0) { + managedSharedTextures.delete(id); + wrapper.texture.subtle.release(() => { + wrapper.allReferencesReleased?.(wrapper.texture); + }); + } +} + +async function sendSharedTexture (options: Electron.SendSharedTextureOptions, ...args: any[]) { + const imported = options.importedSharedTexture; + const transfer = imported.subtle.startTransferSharedTexture(); + + let timeoutHandle: NodeJS.Timeout | null = null; + const timeoutPromise = new Promise<never>((resolve, reject) => { + timeoutHandle = setTimeout(() => { + reject(new Error(`transfer shared texture timed out after ${transferTimeout}ms, ensure you have registered receiver at renderer process.`)); + }, transferTimeout); + }); + + const targetFrame: Electron.WebFrameMain | undefined = options.frame; + if (!targetFrame) { + throw new Error('`frame` should be provided'); + } + + const invokePromise: Promise<Electron.SharedTextureSyncToken> = ipcMainInternalUtils.invokeInWebFrameMain<Electron.SharedTextureSyncToken>( + targetFrame, + IPC_MESSAGES.IMPORT_SHARED_TEXTURE_TRANSFER_MAIN_TO_RENDERER, + transfer, + imported.textureId, + ...args + ); + + try { + const syncToken = await Promise.race([invokePromise, timeoutPromise]); + imported.subtle.setReleaseSyncToken(syncToken); + + const wrapper = managedSharedTextures.get(imported.textureId); + if (!wrapper) { + throw new Error(`Shared texture with id ${imported.textureId} not found`); + } + + const key = targetFrame.frameTreeNodeId; + const existing = wrapper.rendererFrameReferences.get(key); + if (existing) { + existing.count += 1; + wrapper.rendererFrameReferences.set(key, existing); + } else { + wrapper.rendererFrameReferences.set(key, { count: 1, reference: targetFrame }); + } + } finally { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + } + } + + // Schedule a check to see if any texture is referenced by any dangling renderer + scheduleCheckManagedSharedTextures(); +} + +function importSharedTexture (options: Electron.ImportSharedTextureOptions) { + const id = randomUUID(); + const imported = sharedTextureNative.importSharedTexture(Object.assign(options.textureInfo, { id })); + const ret: Electron.SharedTextureImported = { + textureId: id, + subtle: imported, + getVideoFrame: imported.getVideoFrame, + release: () => { + wrapperReleaseFromMain(id); + } + }; + + const wrapper: SharedTextureImportedWrapper = { + texture: ret, + allReferencesReleased: options.allReferencesReleased, + mainReference: true, + rendererFrameReferences: new Map() + }; + managedSharedTextures.set(id, wrapper); + + return ret; +} + +const sharedTexture = { + subtle: sharedTextureNative, + importSharedTexture, + sendSharedTexture +}; + +export default sharedTexture; diff --git a/lib/browser/init.ts b/lib/browser/init.ts index 0b9b225884f01..4a52cd0283157 100644 --- a/lib/browser/init.ts +++ b/lib/browser/init.ts @@ -40,7 +40,7 @@ process.on('uncaughtException', function (error) { // Emit 'exit' event on quit. const { app } = require('electron'); -app.on('quit', (_event, exitCode) => { +app.on('quit', (_event: any, exitCode: number) => { process.emit('exit', exitCode); }); @@ -162,27 +162,6 @@ require('@electron/internal/browser/api/web-contents-view'); // Set main startup script of the app. const mainStartupScript = packageJson.main || 'index.js'; -const KNOWN_XDG_DESKTOP_VALUES = new Set(['Pantheon', 'Unity:Unity7', 'pop:GNOME']); - -function currentPlatformSupportsAppIndicator () { - if (process.platform !== 'linux') return false; - const currentDesktop = process.env.XDG_CURRENT_DESKTOP; - - if (!currentDesktop) return false; - if (KNOWN_XDG_DESKTOP_VALUES.has(currentDesktop)) return true; - // ubuntu based or derived session (default ubuntu one, communitheme…) supports - // indicator too. - if (/ubuntu/ig.test(currentDesktop)) return true; - - return false; -} - -// Workaround for electron/electron#5050 and electron/electron#9046 -process.env.ORIGINAL_XDG_CURRENT_DESKTOP = process.env.XDG_CURRENT_DESKTOP; -if (currentPlatformSupportsAppIndicator()) { - process.env.XDG_CURRENT_DESKTOP = 'Unity'; -} - // Quit when all windows are closed and no other one is listening to this. app.on('window-all-closed', () => { if (app.listenerCount('window-all-closed') === 1) { diff --git a/lib/browser/ipc-main-internal-utils.ts b/lib/browser/ipc-main-internal-utils.ts index d763cd6807374..602aa000cc06e 100644 --- a/lib/browser/ipc-main-internal-utils.ts +++ b/lib/browser/ipc-main-internal-utils.ts @@ -36,3 +36,27 @@ export function invokeInWebContents<T> (sender: Electron.WebContents, command: s sender._sendInternal(command, requestId, ...args); }); } + +export function invokeInWebFrameMain<T> (sender: Electron.WebFrameMain, command: string, ...args: any[]) { + return new Promise<T>((resolve, reject) => { + const requestId = ++nextId; + const channel = `${command}_RESPONSE_${requestId}`; + const frameTreeNodeId = sender.frameTreeNodeId; + ipcMainInternal.on(channel, function handler (event, error: Error, result: any) { + if (event.type === 'frame' && event.frameTreeNodeId !== frameTreeNodeId) { + console.error(`Reply to ${command} sent by unexpected WebFrameMain (${event.frameTreeNodeId})`); + return; + } + + ipcMainInternal.removeListener(channel, handler); + + if (error) { + reject(error); + } else { + resolve(result); + } + }); + + sender._sendInternal(command, requestId, ...args); + }); +} diff --git a/lib/common/api/net-client-request.ts b/lib/common/api/net-client-request.ts index a2682da670d22..08533c81e6c21 100644 --- a/lib/common/api/net-client-request.ts +++ b/lib/common/api/net-client-request.ts @@ -289,7 +289,8 @@ function parseOptions (optionsIn: ClientRequestConstructorOptions | string): Nod referrerPolicy: options.referrerPolicy, cache: options.cache, allowNonHttpProtocols: Object.hasOwn(options, kAllowNonHttpProtocols), - priority: options.priority + priority: options.priority, + bypassCustomProtocolHandlers: options.bypassCustomProtocolHandlers }; if ('priorityIncremental' in options) { urlLoaderOptions.priorityIncremental = options.priorityIncremental; @@ -427,9 +428,8 @@ export class ClientRequest extends Writable implements Electron.ClientRequest { this._started = true; const stringifyValues = (obj: Record<string, { name: string, value: string | string[] }>) => { const ret: Record<string, string> = {}; - for (const k of Object.keys(obj)) { - const kv = obj[k]; - ret[kv.name] = kv.value.toString(); + for (const { name, value } of Object.values(obj)) { + ret[name] = value.toString(); } return ret; }; diff --git a/lib/common/ipc-messages.ts b/lib/common/ipc-messages.ts index a980924f121db..4988eb08008fe 100644 --- a/lib/common/ipc-messages.ts +++ b/lib/common/ipc-messages.ts @@ -25,4 +25,7 @@ export const enum IPC_MESSAGES { INSPECTOR_CONFIRM = 'INSPECTOR_CONFIRM', INSPECTOR_CONTEXT_MENU = 'INSPECTOR_CONTEXT_MENU', INSPECTOR_SELECT_FILE = 'INSPECTOR_SELECT_FILE', + + IMPORT_SHARED_TEXTURE_TRANSFER_MAIN_TO_RENDERER = 'IMPORT_SHARED_TEXTURE_TRANSFER_MAIN_TO_RENDERER', + IMPORT_SHARED_TEXTURE_RELEASE_RENDERER_TO_MAIN = 'IMPORT_SHARED_TEXTURE_RELEASE_RENDERER_TO_MAIN', } diff --git a/lib/node/asar-fs-wrapper.ts b/lib/node/asar-fs-wrapper.ts index bee5e33025940..25eaf3a4a08f6 100644 --- a/lib/node/asar-fs-wrapper.ts +++ b/lib/node/asar-fs-wrapper.ts @@ -746,7 +746,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => { context.readdirResults.push(dirent); if (dirent!.isDirectory() || stat === 1) { - context.pathsQueue.push(path.join(dirent!.path, dirent!.name)); + context.pathsQueue.push(path.join(dirent!.parentPath, dirent!.name)); } } } diff --git a/lib/renderer/api/clipboard.ts b/lib/renderer/api/clipboard.ts index 96e77b2871e15..3b53f410da9d1 100644 --- a/lib/renderer/api/clipboard.ts +++ b/lib/renderer/api/clipboard.ts @@ -1,21 +1,45 @@ +import * as deprecate from '@electron/internal/common/deprecate'; import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; -const clipboard = process._linkedBinding('electron_common_clipboard'); +const clipboard = {} as Electron.Clipboard; +const originalClipboard = process._linkedBinding('electron_common_clipboard'); + +const warnDeprecatedAccess = function (method: keyof Electron.Clipboard) { + return deprecate.warnOnceMessage(`Accessing 'clipboard.${method}' from the renderer process is + deprecated and will be removed. Please use the 'contextBridge' API to access + the clipboard API from the renderer.`); +}; + +const makeDeprecatedMethod = function (method: keyof Electron.Clipboard): any { + const warnDeprecated = warnDeprecatedAccess(method); + return (...args: any[]) => { + warnDeprecated(); + return (originalClipboard[method] as any)(...args); + }; +}; const makeRemoteMethod = function (method: keyof Electron.Clipboard): any { - return (...args: any[]) => ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, method, ...args); + const warnDeprecated = warnDeprecatedAccess(method); + return (...args: any[]) => { + warnDeprecated(); + return ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, method, ...args); + }; }; if (process.platform === 'linux') { // On Linux we could not access clipboard in renderer process. - for (const method of Object.keys(clipboard) as (keyof Electron.Clipboard)[]) { + for (const method of Object.keys(originalClipboard) as (keyof Electron.Clipboard)[]) { clipboard[method] = makeRemoteMethod(method); } -} else if (process.platform === 'darwin') { - // Read/write to find pasteboard over IPC since only main process is notified of changes - clipboard.readFindText = makeRemoteMethod('readFindText'); - clipboard.writeFindText = makeRemoteMethod('writeFindText'); +} else { + for (const method of Object.keys(originalClipboard) as (keyof Electron.Clipboard)[]) { + if (process.platform === 'darwin' && (method === 'readFindText' || method === 'writeFindText')) { + clipboard[method] = makeRemoteMethod(method); + } else { + clipboard[method] = makeDeprecatedMethod(method); + } + } } export default clipboard; diff --git a/lib/renderer/api/module-list.ts b/lib/renderer/api/module-list.ts index 7ac9ea67a64cc..46d3fcf3df457 100644 --- a/lib/renderer/api/module-list.ts +++ b/lib/renderer/api/module-list.ts @@ -4,6 +4,7 @@ export const rendererModuleList: ElectronInternal.ModuleEntry[] = [ { name: 'contextBridge', loader: () => require('./context-bridge') }, { name: 'crashReporter', loader: () => require('./crash-reporter') }, { name: 'ipcRenderer', loader: () => require('./ipc-renderer') }, + { name: 'sharedTexture', loader: () => require('./shared-texture') }, { name: 'webFrame', loader: () => require('./web-frame') }, { name: 'webUtils', loader: () => require('./web-utils') } ]; diff --git a/lib/renderer/api/shared-texture.ts b/lib/renderer/api/shared-texture.ts new file mode 100644 index 0000000000000..5448edb46efef --- /dev/null +++ b/lib/renderer/api/shared-texture.ts @@ -0,0 +1,45 @@ +import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; +import ipcRenderer from '@electron/internal/renderer/api/ipc-renderer'; +import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; + +const sharedTextureNative = process._linkedBinding('electron_common_shared_texture'); +const transferChannelName = IPC_MESSAGES.IMPORT_SHARED_TEXTURE_TRANSFER_MAIN_TO_RENDERER; + +type SharedTextureReceiverCallback = (data: Electron.ReceivedSharedTextureData, ...args: any[]) => Promise<void>; +let sharedTextureReceiverCallback: SharedTextureReceiverCallback | null = null; + +ipcRendererInternal.on(transferChannelName, async (event, requestId, ...args) => { + const replyChannel = `${transferChannelName}_RESPONSE_${requestId}`; + try { + const transfer = args[0] as Electron.SharedTextureTransfer; + const textureId = args[1] as string; + const imported = sharedTextureNative.finishTransferSharedTexture(Object.assign(transfer, { id: textureId })); + const syncToken = imported.getFrameCreationSyncToken(); + event.sender.send(replyChannel, null, syncToken); + + const wrapper: Electron.SharedTextureImported = { + textureId, + subtle: imported, + getVideoFrame: imported.getVideoFrame, + release: () => { + imported.release(async () => { + await ipcRenderer.invoke(IPC_MESSAGES.IMPORT_SHARED_TEXTURE_RELEASE_RENDERER_TO_MAIN, textureId); + }); + } + }; + + const data: Electron.ReceivedSharedTextureData = { importedSharedTexture: wrapper }; + await sharedTextureReceiverCallback?.(data, ...args.slice(2)); + } catch (error) { + event.sender.send(replyChannel, error); + } +}); + +const sharedTexture = { + subtle: sharedTextureNative, + setSharedTextureReceiver: (callback: SharedTextureReceiverCallback) => { + sharedTextureReceiverCallback = callback; + } +}; + +export default sharedTexture; diff --git a/lib/sandboxed_renderer/api/module-list.ts b/lib/sandboxed_renderer/api/module-list.ts index 36454319e1f63..72aa778e6556a 100644 --- a/lib/sandboxed_renderer/api/module-list.ts +++ b/lib/sandboxed_renderer/api/module-list.ts @@ -15,6 +15,10 @@ export const moduleList: ElectronInternal.ModuleEntry[] = [ name: 'nativeImage', loader: () => require('@electron/internal/common/api/native-image') }, + { + name: 'sharedTexture', + loader: () => require('@electron/internal/renderer/api/shared-texture') + }, { name: 'webFrame', loader: () => require('@electron/internal/renderer/api/web-frame') diff --git a/npm/cli.js b/npm/cli.js index 7dbb3d5a3c0cf..026f0f2b46f21 100755 --- a/npm/cli.js +++ b/npm/cli.js @@ -5,7 +5,9 @@ const proc = require('child_process'); const electron = require('./'); const child = proc.spawn(electron, process.argv.slice(2), { stdio: 'inherit', windowsHide: false }); +let childClosed = false; child.on('close', function (code, signal) { + childClosed = true; if (code === null) { console.error(electron, 'exited with signal', signal); process.exit(1); @@ -15,7 +17,7 @@ child.on('close', function (code, signal) { const handleTerminationSignal = function (signal) { process.on(signal, function signalHandler () { - if (!child.killed) { + if (!childClosed) { child.kill(signal); } }); @@ -23,3 +25,4 @@ const handleTerminationSignal = function (signal) { handleTerminationSignal('SIGINT'); handleTerminationSignal('SIGTERM'); +handleTerminationSignal('SIGUSR2'); diff --git a/npm/install.js b/npm/install.js index a0c177dea4160..9d7ecaf55d29b 100755 --- a/npm/install.js +++ b/npm/install.js @@ -44,7 +44,7 @@ downloadArtifact({ artifactName: 'electron', force: process.env.force_no_cache === 'true', cacheRoot: process.env.electron_config_cache, - checksums: process.env.electron_use_remote_checksums ?? process.env.npm_config_electron_use_remote_checksums ? undefined : require('./checksums.json'), + checksums: (process.env.electron_use_remote_checksums || process.env.npm_config_electron_use_remote_checksums) ? undefined : require('./checksums.json'), platform, arch }).then(extractFile).catch(err => { diff --git a/npm/package.json b/npm/package.json index 96fd3c3ad0769..5f029ee4c7c0e 100644 --- a/npm/package.json +++ b/npm/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@electron/get": "^2.0.0", - "@types/node": "^22.7.7", + "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "engines": { diff --git a/package.json b/package.json index d45a2e60e4131..edc94129d2685 100644 --- a/package.json +++ b/package.json @@ -5,21 +5,22 @@ "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { "@azure/storage-blob": "^12.28.0", - "@electron/asar": "^3.2.13", + "@electron/asar": "^4.0.1", "@electron/docs-parser": "^2.0.0", "@electron/fiddle-core": "^1.3.4", "@electron/github-app-auth": "^2.2.1", "@electron/lint-roller": "^3.1.2", - "@electron/typescript-definitions": "^9.1.2", + "@electron/typescript-definitions": "^9.1.5", "@octokit/rest": "^20.1.2", "@primer/octicons": "^10.0.0", "@types/minimist": "^1.2.5", - "@types/node": "^22.7.7", + "@types/node": "^24.9.0", "@types/semver": "^7.5.8", "@types/stream-json": "^1.7.8", "@types/temp": "^0.9.4", "@typescript-eslint/eslint-plugin": "^8.32.1", "@typescript-eslint/parser": "^8.7.0", + "@xmldom/xmldom": "^0.8.11", "buffer": "^6.0.3", "chalk": "^4.1.0", "check-for-leaks": "^1.2.1", @@ -51,10 +52,10 @@ "timers-browserify": "1.4.2", "ts-loader": "^8.0.2", "ts-node": "6.2.0", - "typescript": "^5.6.2", + "typescript": "^5.8.3", "url": "^0.11.4", "webpack": "^5.95.0", - "webpack-cli": "^5.1.4", + "webpack-cli": "^6.0.1", "wrapper-webpack-plugin": "^2.2.0" }, "private": true, diff --git a/patches/Mantle/.patches b/patches/Mantle/.patches deleted file mode 100644 index 35715fd569153..0000000000000 --- a/patches/Mantle/.patches +++ /dev/null @@ -1 +0,0 @@ -remove_mtlmanagedobjectadapter_h.patch diff --git a/patches/Mantle/remove_mtlmanagedobjectadapter_h.patch b/patches/Mantle/remove_mtlmanagedobjectadapter_h.patch deleted file mode 100644 index 70c6dded28220..0000000000000 --- a/patches/Mantle/remove_mtlmanagedobjectadapter_h.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr <shelley.vohr@gmail.com> -Date: Mon, 7 Dec 2020 17:34:08 -0800 -Subject: Remove MTLManagedObjectAdapter.h - -We are using an outdated version of Mantle which leverages NSConfinementConcurrencyType, -an enum which has been deprecated with no replacement as of macOS 10.11. -The actual solution to this problem is to upgrade Mantle, but for now -we just stop building the offending adapter. - -diff --git a/Mantle/Mantle.h b/Mantle/Mantle.h -index ebd74e7e435ef008ef29e94d406246c1f7b07a12..81abff872bd597ce6d21bb43be4d19ddc7253088 100644 ---- a/Mantle/Mantle.h -+++ b/Mantle/Mantle.h -@@ -15,7 +15,6 @@ FOUNDATION_EXPORT double MantleVersionNumber; - FOUNDATION_EXPORT const unsigned char MantleVersionString[]; - - #import <Mantle/MTLJSONAdapter.h> --#import <Mantle/MTLManagedObjectAdapter.h> - #import <Mantle/MTLModel.h> - #import <Mantle/MTLModel+NSCoding.h> - #import <Mantle/MTLValueTransformer.h> diff --git a/patches/boringssl/.patches b/patches/boringssl/.patches index 9dffabe3d9651..74b9c25484433 100644 --- a/patches/boringssl/.patches +++ b/patches/boringssl/.patches @@ -1,3 +1,2 @@ expose_ripemd160.patch -revert_track_ssl_error_zero_return_explicitly.patch feat_expose_several_extra_cipher_functions.patch diff --git a/patches/boringssl/expose_ripemd160.patch b/patches/boringssl/expose_ripemd160.patch index e9a3f74d62403..1553f657d3961 100644 --- a/patches/boringssl/expose_ripemd160.patch +++ b/patches/boringssl/expose_ripemd160.patch @@ -10,10 +10,10 @@ this patch is required to provide ripemd160 support in the nodejs crypto module. diff --git a/crypto/digest/digest_extra.cc b/crypto/digest/digest_extra.cc -index 431214277314941c5ec031f03ad09e7f22800983..4cc48bbc3f8434876f35767c1a9f01d27388be99 100644 +index ea1709ae6b50faedc786c0eaeb5f9002fd0db7d8..5b0ed4dc6aaf3fafad034e9ecc62cd47b9e3034f 100644 --- a/crypto/digest/digest_extra.cc +++ b/crypto/digest/digest_extra.cc -@@ -46,6 +46,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = { +@@ -47,6 +47,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = { {NID_sha512, EVP_sha512, SN_sha512, LN_sha512}, {NID_sha512_256, EVP_sha512_256, SN_sha512_256, LN_sha512_256}, {NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1}, @@ -22,7 +22,7 @@ index 431214277314941c5ec031f03ad09e7f22800983..4cc48bbc3f8434876f35767c1a9f01d2 // hash function when given a signature OID. To avoid unintended lax parsing // of hash OIDs, this is no longer supported for lookup by OID or NID. diff --git a/crypto/fipsmodule/digest/digests.cc.inc b/crypto/fipsmodule/digest/digests.cc.inc -index 99e3a66c0a47818ccb039f8ccc41ea50e529a16d..dc50fd05bed6cb40bffe1c0f6f3019d25d351ba2 100644 +index 3a3bfd3f0560fcd7b5fdbdf4cc29a56e0346b90a..a7335ca03b5b3b918c4321d890b45649679d772b 100644 --- a/crypto/fipsmodule/digest/digests.cc.inc +++ b/crypto/fipsmodule/digest/digests.cc.inc @@ -18,6 +18,7 @@ @@ -62,27 +62,27 @@ index 99e3a66c0a47818ccb039f8ccc41ea50e529a16d..dc50fd05bed6cb40bffe1c0f6f3019d2 + #undef CHECK diff --git a/decrepit/evp/evp_do_all.cc b/decrepit/evp/evp_do_all.cc -index e04b80cd6a1a215fc87f8fd8d750c3d258c3974f..8fdf1c624794f568bfc77b7b6b0c510b23905a4d 100644 +index feaf17c72cecb8099bc11ac10747fbad719ddca9..891a73f229e3f0838cb2fa99b8fb24fdeac1962b 100644 --- a/decrepit/evp/evp_do_all.cc +++ b/decrepit/evp/evp_do_all.cc @@ -79,6 +79,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher, - callback(EVP_sha384(), "SHA384", NULL, arg); - callback(EVP_sha512(), "SHA512", NULL, arg); - callback(EVP_sha512_256(), "SHA512-256", NULL, arg); -+ callback(EVP_ripemd160(), "ripemd160", NULL, arg); + callback(EVP_sha384(), "SHA384", nullptr, arg); + callback(EVP_sha512(), "SHA512", nullptr, arg); + callback(EVP_sha512_256(), "SHA512-256", nullptr, arg); ++ callback(EVP_ripemd160(), "ripemd160", nullptr, arg); - callback(EVP_md4(), "md4", NULL, arg); - callback(EVP_md5(), "md5", NULL, arg); + callback(EVP_md4(), "md4", nullptr, arg); + callback(EVP_md5(), "md5", nullptr, arg); @@ -88,6 +89,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher, - callback(EVP_sha384(), "sha384", NULL, arg); - callback(EVP_sha512(), "sha512", NULL, arg); - callback(EVP_sha512_256(), "sha512-256", NULL, arg); -+ callback(EVP_ripemd160(), "ripemd160", NULL, arg); + callback(EVP_sha384(), "sha384", nullptr, arg); + callback(EVP_sha512(), "sha512", nullptr, arg); + callback(EVP_sha512_256(), "sha512-256", nullptr, arg); ++ callback(EVP_ripemd160(), "ripemd160", nullptr, arg); } void EVP_MD_do_all(void (*callback)(const EVP_MD *cipher, const char *name, diff --git a/include/openssl/digest.h b/include/openssl/digest.h -index 710c6e6d110378d1db10d8c2ae57b2d844c603b9..dbb1e0cd5e9480d1ac7a86cbca6fae29d6a8dca4 100644 +index a86c18926e7798a3b0aae70c53870e03b5acd0ab..f4f27f9e803533d8db50d89e7a0125384a025a46 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -48,6 +48,9 @@ OPENSSL_EXPORT const EVP_MD *EVP_blake2b256(void); diff --git a/patches/boringssl/feat_expose_several_extra_cipher_functions.patch b/patches/boringssl/feat_expose_several_extra_cipher_functions.patch index b4fdeb6d33b59..4d60a5e2e75f4 100644 --- a/patches/boringssl/feat_expose_several_extra_cipher_functions.patch +++ b/patches/boringssl/feat_expose_several_extra_cipher_functions.patch @@ -28,7 +28,7 @@ RC2 Ciphers: rc2-40-cbc It's unclear whether this would be accepted upstream. We should try regardless. diff --git a/crypto/cipher/get_cipher.cc b/crypto/cipher/get_cipher.cc -index 2622dc78d1da236862312f55bc0a40f26116486e..ac7aff6518ad5c2a0e48bd91d60a1f825851b634 100644 +index 6513df01c4b3e4d33fc6b521d9aae78ec5499e73..52eb7fea420e3d81d274fd5c1e21e4da0229687f 100644 --- a/crypto/cipher/get_cipher.cc +++ b/crypto/cipher/get_cipher.cc @@ -31,6 +31,7 @@ static const struct { @@ -64,64 +64,64 @@ index 2622dc78d1da236862312f55bc0a40f26116486e..ac7aff6518ad5c2a0e48bd91d60a1f82 const EVP_CIPHER *EVP_get_cipherbynid(int nid) { diff --git a/decrepit/evp/evp_do_all.cc b/decrepit/evp/evp_do_all.cc -index 8fdf1c624794f568bfc77b7b6b0c510b23905a4d..2e40c031e8c681fe921331b26dbf63f4df2fcf71 100644 +index 891a73f229e3f0838cb2fa99b8fb24fdeac1962b..f7d0c5dc66f016eb9338c15e7f5ef59e6de2969d 100644 --- a/decrepit/evp/evp_do_all.cc +++ b/decrepit/evp/evp_do_all.cc @@ -20,8 +20,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher, const char *unused, void *arg), void *arg) { - callback(EVP_aes_128_cbc(), "AES-128-CBC", NULL, arg); -+ callback(EVP_aes_128_cfb128(), "AES-128-CFB", NULL, arg); - callback(EVP_aes_192_cbc(), "AES-192-CBC", NULL, arg); - callback(EVP_aes_256_cbc(), "AES-256-CBC", NULL, arg); -+ callback(EVP_aes_256_cfb128(), "AES-256-CFB", NULL, arg); - callback(EVP_aes_128_ctr(), "AES-128-CTR", NULL, arg); - callback(EVP_aes_192_ctr(), "AES-192-CTR", NULL, arg); - callback(EVP_aes_256_ctr(), "AES-256-CTR", NULL, arg); + callback(EVP_aes_128_cbc(), "AES-128-CBC", nullptr, arg); ++ callback(EVP_aes_128_cfb128(), "AES-128-CFB", nullptr, arg); + callback(EVP_aes_192_cbc(), "AES-192-CBC", nullptr, arg); + callback(EVP_aes_256_cbc(), "AES-256-CBC", nullptr, arg); ++ callback(EVP_aes_256_cfb128(), "AES-256-CFB", nullptr, arg); + callback(EVP_aes_128_ctr(), "AES-128-CTR", nullptr, arg); + callback(EVP_aes_192_ctr(), "AES-192-CTR", nullptr, arg); + callback(EVP_aes_256_ctr(), "AES-256-CTR", nullptr, arg); @@ -34,9 +36,13 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher, - callback(EVP_aes_128_gcm(), "AES-128-GCM", NULL, arg); - callback(EVP_aes_192_gcm(), "AES-192-GCM", NULL, arg); - callback(EVP_aes_256_gcm(), "AES-256-GCM", NULL, arg); -+ callback(EVP_bf_cbc(), "BF-CBC", NULL, arg); -+ callback(EVP_bf_cfb(), "BF-CFB", NULL, arg); -+ callback(EVP_bf_ecb(), "BF-ECB", NULL, arg); - callback(EVP_des_cbc(), "DES-CBC", NULL, arg); - callback(EVP_des_ecb(), "DES-ECB", NULL, arg); - callback(EVP_des_ede(), "DES-EDE", NULL, arg); -+ callback(EVP_des_ede3(), "DES-EDE3", NULL, arg); - callback(EVP_des_ede_cbc(), "DES-EDE-CBC", NULL, arg); - callback(EVP_des_ede3_cbc(), "DES-EDE3-CBC", NULL, arg); - callback(EVP_rc2_cbc(), "RC2-CBC", NULL, arg); + callback(EVP_aes_128_gcm(), "AES-128-GCM", nullptr, arg); + callback(EVP_aes_192_gcm(), "AES-192-GCM", nullptr, arg); + callback(EVP_aes_256_gcm(), "AES-256-GCM", nullptr, arg); ++ callback(EVP_bf_cbc(), "BF-CBC", nullptr, arg); ++ callback(EVP_bf_cfb(), "BF-CFB", nullptr, arg); ++ callback(EVP_bf_ecb(), "BF-ECB", nullptr, arg); + callback(EVP_des_cbc(), "DES-CBC", nullptr, arg); + callback(EVP_des_ecb(), "DES-ECB", nullptr, arg); + callback(EVP_des_ede(), "DES-EDE", nullptr, arg); ++ callback(EVP_des_ede3(), "DES-EDE3", nullptr, arg); + callback(EVP_des_ede_cbc(), "DES-EDE-CBC", nullptr, arg); + callback(EVP_des_ede3_cbc(), "DES-EDE3-CBC", nullptr, arg); + callback(EVP_rc2_cbc(), "RC2-CBC", nullptr, arg); @@ -44,8 +50,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher, // OpenSSL returns everything twice, the second time in lower case. - callback(EVP_aes_128_cbc(), "aes-128-cbc", NULL, arg); -+ callback(EVP_aes_128_cfb128(), "aes-128-cfb", NULL, arg); - callback(EVP_aes_192_cbc(), "aes-192-cbc", NULL, arg); - callback(EVP_aes_256_cbc(), "aes-256-cbc", NULL, arg); -+ callback(EVP_aes_256_cfb128(), "aes-256-cfb", NULL, arg); - callback(EVP_aes_128_ctr(), "aes-128-ctr", NULL, arg); - callback(EVP_aes_192_ctr(), "aes-192-ctr", NULL, arg); - callback(EVP_aes_256_ctr(), "aes-256-ctr", NULL, arg); + callback(EVP_aes_128_cbc(), "aes-128-cbc", nullptr, arg); ++ callback(EVP_aes_128_cfb128(), "aes-128-cfb", nullptr, arg); + callback(EVP_aes_192_cbc(), "aes-192-cbc", nullptr, arg); + callback(EVP_aes_256_cbc(), "aes-256-cbc", nullptr, arg); ++ callback(EVP_aes_256_cfb128(), "aes-256-cfb", nullptr, arg); + callback(EVP_aes_128_ctr(), "aes-128-ctr", nullptr, arg); + callback(EVP_aes_192_ctr(), "aes-192-ctr", nullptr, arg); + callback(EVP_aes_256_ctr(), "aes-256-ctr", nullptr, arg); @@ -58,9 +66,13 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher, - callback(EVP_aes_128_gcm(), "aes-128-gcm", NULL, arg); - callback(EVP_aes_192_gcm(), "aes-192-gcm", NULL, arg); - callback(EVP_aes_256_gcm(), "aes-256-gcm", NULL, arg); -+ callback(EVP_bf_cbc(), "bf-cbc", NULL, arg); -+ callback(EVP_bf_cfb(), "bf-cfb", NULL, arg); -+ callback(EVP_bf_ecb(), "bf-ecb", NULL, arg); - callback(EVP_des_cbc(), "des-cbc", NULL, arg); - callback(EVP_des_ecb(), "des-ecb", NULL, arg); - callback(EVP_des_ede(), "des-ede", NULL, arg); -+ callback(EVP_des_ede3(), "des-ede3", NULL, arg); - callback(EVP_des_ede_cbc(), "des-ede-cbc", NULL, arg); - callback(EVP_des_ede3_cbc(), "des-ede3-cbc", NULL, arg); - callback(EVP_rc2_cbc(), "rc2-cbc", NULL, arg); + callback(EVP_aes_128_gcm(), "aes-128-gcm", nullptr, arg); + callback(EVP_aes_192_gcm(), "aes-192-gcm", nullptr, arg); + callback(EVP_aes_256_gcm(), "aes-256-gcm", nullptr, arg); ++ callback(EVP_bf_cbc(), "bf-cbc", nullptr, arg); ++ callback(EVP_bf_cfb(), "bf-cfb", nullptr, arg); ++ callback(EVP_bf_ecb(), "bf-ecb", nullptr, arg); + callback(EVP_des_cbc(), "des-cbc", nullptr, arg); + callback(EVP_des_ecb(), "des-ecb", nullptr, arg); + callback(EVP_des_ede(), "des-ede", nullptr, arg); ++ callback(EVP_des_ede3(), "des-ede3", nullptr, arg); + callback(EVP_des_ede_cbc(), "des-ede-cbc", nullptr, arg); + callback(EVP_des_ede3_cbc(), "des-ede3-cbc", nullptr, arg); + callback(EVP_rc2_cbc(), "rc2-cbc", nullptr, arg); diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h -index 13e68ad20ac08a462bb577d7f99e2c6f167579fa..4960d0eeb8f31bec4347ed2a1b63beba530de700 100644 +index ed2eeab57779d827eb19edcd435b4664d4079859..74bb77e03b562698cb887b25cc8a779631a809fb 100644 --- a/include/openssl/cipher.h +++ b/include/openssl/cipher.h -@@ -448,6 +448,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void); +@@ -552,6 +552,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void); // EVP_aes_128_cfb128 is only available in decrepit. OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cfb128(void); diff --git a/patches/boringssl/revert_track_ssl_error_zero_return_explicitly.patch b/patches/boringssl/revert_track_ssl_error_zero_return_explicitly.patch deleted file mode 100644 index 814a889349dbe..0000000000000 --- a/patches/boringssl/revert_track_ssl_error_zero_return_explicitly.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr <shelley.vohr@gmail.com> -Date: Tue, 6 Sep 2022 09:42:52 +0200 -Subject: revert: track SSL_ERROR_ZERO_RETURN explicitly. - -This reverts commit ebd8b8965c74ab06bb91f7a00b23822e1f1f26ca. - -It is causing significant TLS failures in Node.js. - -diff --git a/ssl/ssl_buffer.cc b/ssl/ssl_buffer.cc -index 2cdcbc346175eeee69402ecee7f169e61c655199..f7226fe711e4214b216ea2c5173a02124b80f9ef 100644 ---- a/ssl/ssl_buffer.cc -+++ b/ssl/ssl_buffer.cc -@@ -230,7 +230,6 @@ int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret, - return 1; - - case ssl_open_record_close_notify: -- ssl->s3->rwstate = SSL_ERROR_ZERO_RETURN; - return 0; - - case ssl_open_record_error: -diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc -index aa8ef8a0c53978021b675e1d909c3f78045dbb7b..61794458f7a7a849d48a225533ef4f8431434e42 100644 ---- a/ssl/ssl_lib.cc -+++ b/ssl/ssl_lib.cc -@@ -1206,7 +1206,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) { - } - - if (ret_code == 0) { -- if (ssl->s3->rwstate == SSL_ERROR_ZERO_RETURN) { -+ if (ssl->s3->read_shutdown == ssl_shutdown_close_notify) { - return SSL_ERROR_ZERO_RETURN; - } - // An EOF was observed which violates the protocol, and the underlying -@@ -2567,13 +2567,7 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) { - return CRYPTO_get_ex_data(&ctx->ex_data, idx); - } - --int SSL_want(const SSL *ssl) { -- // Historically, OpenSSL did not track |SSL_ERROR_ZERO_RETURN| as an |rwstate| -- // value. We do, but map it back to |SSL_ERROR_NONE| to preserve the original -- // behavior. -- return ssl->s3->rwstate == SSL_ERROR_ZERO_RETURN ? SSL_ERROR_NONE -- : ssl->s3->rwstate; --} -+int SSL_want(const SSL *ssl) { return ssl->s3->rwstate; } - - void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, - RSA *(*cb)(SSL *ssl, int is_export, diff --git a/patches/chromium/.patches b/patches/chromium/.patches index cc097efab4644..5881ab1840bd4 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -59,7 +59,6 @@ webview_fullscreen.patch extend_apply_webpreferences.patch build_libc_as_static_library.patch build_do_not_depend_on_packed_resource_integrity.patch -refactor_restore_base_adaptcallbackforrepeating.patch logging_win32_only_create_a_console_if_logging_to_stderr.patch fix_media_key_usage_with_globalshortcuts.patch feat_expose_raw_response_headers_from_urlloader.patch @@ -110,7 +109,6 @@ fix_getcursorscreenpoint_wrongly_returns_0_0.patch fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch refactor_expose_file_system_access_blocklist.patch feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch -fix_font_face_resolution_when_renderer_is_blocked.patch feat_enable_passing_exit_code_on_service_process_crash.patch chore_remove_reference_to_chrome_browser_themes.patch feat_enable_customizing_symbol_color_in_framecaptionbutton.patch @@ -132,9 +130,15 @@ chore_grandfather_in_electron_views_and_delegates.patch refactor_patch_electron_permissiontypes_into_blink.patch revert_views_remove_desktopwindowtreehostwin_window_enlargement.patch build_partial_revert_mac_fullscreen_top_chrome_mouse_events.patch -build_set_mac_sdk_minimum_to_10.patch fix_add_macos_memory_query_fallback_to_avoid_crash.patch fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch feat_add_support_for_embedder_snapshot_validation.patch chore_restore_some_deprecated_wrapper_utility_in_gin.patch chore_add_electron_objects_to_wrappablepointertag.patch +chore_expose_isolate_parameter_in_script_lifecycle_observers.patch +revert_partial_remove_unused_prehandlemouseevent.patch +allow_electron_to_depend_on_components_os_crypt_sync.patch +expose_referrerscriptinfo_hostdefinedoptionsindex.patch +chore_disable_protocol_handler_dcheck.patch +fix_check_for_file_existence_before_setting_mtime.patch +fix_linux_tray_id.patch diff --git a/patches/chromium/accelerator.patch b/patches/chromium/accelerator.patch index 65aea0d48e53f..662c361566d94 100644 --- a/patches/chromium/accelerator.patch +++ b/patches/chromium/accelerator.patch @@ -53,19 +53,19 @@ index 5ad9332dd27ceda7d67cd3f571b12218a4415a40..ffe083836c39fb60b4bff1f9fbdd6ceb } diff --git a/ui/base/accelerators/accelerator.h b/ui/base/accelerators/accelerator.h -index e7d5adfac920c97df8bab9bf4ed69a835ee314a9..9aeea7cb4c48d1ccc27304fa99238151b2811c87 100644 +index 666ecbc118bec6d51465644ae4e573846c33610b..5f578ea153477379bac69e48fbd4f41a9a24885e 100644 --- a/ui/base/accelerators/accelerator.h +++ b/ui/base/accelerators/accelerator.h -@@ -18,6 +18,7 @@ - #include <vector> - - #include "base/component_export.h" -+#include "third_party/abseil-cpp/absl/types/optional.h" +@@ -21,6 +21,7 @@ #include "base/time/time.h" #include "build/blink_buildflags.h" #include "build/build_config.h" -@@ -189,6 +190,8 @@ class COMPONENT_EXPORT(UI_BASE) Accelerator { - return interrupted_by_mouse_event_; ++#include "third_party/abseil-cpp/absl/types/optional.h" + #include "ui/events/event_constants.h" + #include "ui/events/keycodes/keyboard_codes.h" + +@@ -199,6 +200,8 @@ class COMPONENT_EXPORT(UI_BASE) Accelerator { + << 18); // masked to 6 bits } + absl::optional<char16_t> shifted_char; diff --git a/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch b/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch index d1d794b1424b7..cc67817d07f80 100644 --- a/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch +++ b/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch @@ -10,10 +10,10 @@ Allows Electron to restore WER when ELECTRON_DEFAULT_ERROR_MODE is set. This should be upstreamed. diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc -index 6f8e8dd8e7ddb9e3d4c142493f249f616520d613..f89b2e5b846b3b96c99dea2a3b49bc9823ab51e5 100644 +index 30cc1d4a179f9da59824cb98415baed8493fc843..2272eaa7e0e3306201e5e32226a0115f6f6636e5 100644 --- a/content/gpu/gpu_main.cc +++ b/content/gpu/gpu_main.cc -@@ -271,6 +271,10 @@ int GpuMain(MainFunctionParams parameters) { +@@ -272,6 +272,10 @@ int GpuMain(MainFunctionParams parameters) { // to the GpuProcessHost once the GpuServiceImpl has started. viz::GpuLogMessageManager::GetInstance()->InstallPreInitializeLogHandler(); @@ -24,7 +24,7 @@ index 6f8e8dd8e7ddb9e3d4c142493f249f616520d613..f89b2e5b846b3b96c99dea2a3b49bc98 // We are experiencing what appear to be memory-stomp issues in the GPU // process. These issues seem to be impacting the task executor and listeners // registered to it. Create the task executor on the heap to guard against -@@ -380,7 +384,6 @@ int GpuMain(MainFunctionParams parameters) { +@@ -381,7 +385,6 @@ int GpuMain(MainFunctionParams parameters) { #endif const bool dead_on_arrival = !init_success; diff --git a/patches/chromium/add_didinstallconditionalfeatures.patch b/patches/chromium/add_didinstallconditionalfeatures.patch index 87eae933a9233..0b5b7de5be949 100644 --- a/patches/chromium/add_didinstallconditionalfeatures.patch +++ b/patches/chromium/add_didinstallconditionalfeatures.patch @@ -10,10 +10,10 @@ DidCreateScriptContext is called, not all JS APIs are available in the context, which can cause some preload scripts to trip. diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h -index c26cff0adef977617b10bbaa7c0c13cf5e6e91d3..f9c7af85af33572a88956bf1bc9765e90be3d39b 100644 +index 5196f155cdc641b66c4faa77d8b00097145a1290..bbfac47a74f989482343c222b78f187b70297e4e 100644 --- a/content/public/renderer/render_frame_observer.h +++ b/content/public/renderer/render_frame_observer.h -@@ -138,6 +138,8 @@ class CONTENT_EXPORT RenderFrameObserver { +@@ -141,6 +141,8 @@ class CONTENT_EXPORT RenderFrameObserver { virtual void DidHandleOnloadEvents() {} virtual void DidCreateScriptContext(v8::Local<v8::Context> context, int32_t world_id) {} @@ -23,10 +23,10 @@ index c26cff0adef977617b10bbaa7c0c13cf5e6e91d3..f9c7af85af33572a88956bf1bc9765e9 int32_t world_id) {} virtual void DidClearWindowObject() {} diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc -index 859113ed13e77dcdd72b2ab327b94e94492f5d24..51948d7fcae02bd85133a859989f93a07dd0e236 100644 +index d4755acfd0ba3016da545de87d64046a6f5ee387..7070884305eb648c9aa0020f8161202671e1f671 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc -@@ -4677,6 +4677,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context, +@@ -4662,6 +4662,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context, observer.DidCreateScriptContext(context, world_id); } @@ -40,7 +40,7 @@ index 859113ed13e77dcdd72b2ab327b94e94492f5d24..51948d7fcae02bd85133a859989f93a0 int world_id) { for (auto& observer : observers_) diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h -index 5456a50df5f75509c22afa47034afbb624303a75..bbd1edd567aee984001288901581dfa56dbfa2dc 100644 +index 19c5dab00dd9355736c6040868b320483b780afb..621cd9ae7f43470ed4414a48d62330b36c7058e9 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h @@ -603,6 +603,8 @@ class CONTENT_EXPORT RenderFrameImpl @@ -53,10 +53,10 @@ index 5456a50df5f75509c22afa47034afbb624303a75..bbd1edd567aee984001288901581dfa5 int world_id) override; void DidChangeScrollOffset() override; diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h -index 5c1c325d1e4037b0b413c3519e963c5f0210086a..994dd3118dfa43816db60e5dfb61c00bf366e92d 100644 +index 5c1d0c1581b7ef6214f3dde6a4053a23c8673b74..4520c9edccf63bdb9e35bf3a99a8ddb39170da24 100644 --- a/third_party/blink/public/web/web_local_frame_client.h +++ b/third_party/blink/public/web/web_local_frame_client.h -@@ -662,6 +662,9 @@ class BLINK_EXPORT WebLocalFrameClient { +@@ -667,6 +667,9 @@ class BLINK_EXPORT WebLocalFrameClient { virtual void DidCreateScriptContext(v8::Local<v8::Context>, int32_t world_id) {} @@ -67,10 +67,10 @@ index 5c1c325d1e4037b0b413c3519e963c5f0210086a..994dd3118dfa43816db60e5dfb61c00b virtual void WillReleaseScriptContext(v8::Local<v8::Context>, int32_t world_id) {} diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc -index b963abd8c4bf6ffaea1930a8d1f647a8a8c266bc..2e8653654686f4fc775288f059ff27daa38e02d5 100644 +index 3ce1ef340780075951fb8c1b65f2ec90569f34ef..898d7caac98727210ac5780b576526a71ec5a5aa 100644 --- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc +++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc -@@ -216,6 +216,7 @@ void LocalWindowProxy::Initialize() { +@@ -217,6 +217,7 @@ void LocalWindowProxy::Initialize() { } InstallConditionalFeatures(); @@ -92,11 +92,11 @@ index 36baf908d3be8aed44ff60b8de2cffe2eee15efe..8d73ddb12013ce195026b9f63050cf33 int32_t world_id) = 0; virtual bool AllowScriptExtensions() = 0; diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc -index 114cbd9c806572b664b9d9af75955231fa68cc50..03a0b2f762a2d9677212c89e63bb2d2691fac2b7 100644 +index 019445e625257f909875adffdc5e967fb65a3728..11475d1a22054a884f2f1e7e5c933e9ae8d3379f 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc -@@ -295,6 +295,13 @@ void LocalFrameClientImpl::DidCreateScriptContext( - web_frame_->Client()->DidCreateScriptContext(context, world_id); +@@ -300,6 +300,13 @@ void LocalFrameClientImpl::DidCreateScriptContext( + } } +void LocalFrameClientImpl::DidInstallConditionalFeatures( @@ -110,7 +110,7 @@ index 114cbd9c806572b664b9d9af75955231fa68cc50..03a0b2f762a2d9677212c89e63bb2d26 v8::Local<v8::Context> context, int32_t world_id) { diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h -index 081c8fabbcc514e47ff33d7e07a5eac3d112a518..e3fab574523a4b63069587b2fcaf30267fddf7c4 100644 +index fcc0928abbc454281b022e0451d993651ecba42f..16066fe34ee0335a0dabe00b6890e5844349c0b5 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h @@ -81,6 +81,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient { @@ -123,10 +123,10 @@ index 081c8fabbcc514e47ff33d7e07a5eac3d112a518..e3fab574523a4b63069587b2fcaf3026 int32_t world_id) override; diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h -index 769b08ca081fe83c50babb2743fde6e8961b65ff..d8f3b11c98fd58baa9995762a29847b9fd760c84 100644 +index b1677488cb64d2ad83f231b4cbe74bc4f56149b4..80ee0065d1b16520389b6809402438f087430fa3 100644 --- a/third_party/blink/renderer/core/loader/empty_clients.h +++ b/third_party/blink/renderer/core/loader/empty_clients.h -@@ -420,6 +420,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient { +@@ -426,6 +426,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient { void DidCreateScriptContext(v8::Local<v8::Context>, int32_t world_id) override {} diff --git a/patches/chromium/add_electron_deps_to_license_credits_file.patch b/patches/chromium/add_electron_deps_to_license_credits_file.patch index 68f3913a888be..b6bcbd01e8724 100644 --- a/patches/chromium/add_electron_deps_to_license_credits_file.patch +++ b/patches/chromium/add_electron_deps_to_license_credits_file.patch @@ -7,12 +7,12 @@ Ensure that licenses for the dependencies introduced by Electron are included in `LICENSES.chromium.html` diff --git a/tools/licenses/licenses.py b/tools/licenses/licenses.py -index b0807ee3d8ebcf34f0d740362aa46c8631562d38..118d200b74953c0068ad59300ccc0e3041d77a10 100755 +index 514be069768cc1bbd39f2b261cefb1a9f267f89f..0a1ab64914cfaa087e4000fb81bfafd18aa1b98b 100755 --- a/tools/licenses/licenses.py +++ b/tools/licenses/licenses.py -@@ -337,6 +337,31 @@ SPECIAL_CASES = { +@@ -357,6 +357,31 @@ SPECIAL_CASES = { "License": "Apache 2.0", - "License File": ["//third_party/dawn/third_party/khronos/LICENSE"], + "License File": ["//third_party/sample3/the_license"], }, + os.path.join('third_party', 'electron_node'): { + "Name": "Node.js", diff --git a/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch b/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch index 68a06fe5092c5..a7f762497c0c6 100644 --- a/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch +++ b/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch @@ -8,10 +8,10 @@ was removed as part of the Raw Clipboard API scrubbing. https://bugs.chromium.org/p/chromium/issues/detail?id=1217643 diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc -index 0b457d0742b24381718092d6af11f396fda30436..e1619eeeb8f29e6745da282a33a3464ec97aefb0 100644 +index e104f4d7814b6f6a0e1f5cf49ae24d5571e30fb1..cc7e9064b21f8f2c45690454805901c0c56e2aa1 100644 --- a/ui/base/clipboard/scoped_clipboard_writer.cc +++ b/ui/base/clipboard/scoped_clipboard_writer.cc -@@ -236,6 +236,16 @@ void ScopedClipboardWriter::WriteData(std::u16string_view format, +@@ -244,6 +244,16 @@ void ScopedClipboardWriter::WriteData(std::u16string_view format, } } @@ -29,10 +29,10 @@ index 0b457d0742b24381718092d6af11f396fda30436..e1619eeeb8f29e6745da282a33a3464e objects_.clear(); raw_objects_.clear(); diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h -index 939a99b2a086d5373f82fe96da73dabe02f6f9d8..fccc200b1b11076c8fcffde071a53598ffba9a12 100644 +index 8c2be540757856a3e704764fe56003205b24812f..e31fbc01f68c0e92284a72298cac878d7247e7fb 100644 --- a/ui/base/clipboard/scoped_clipboard_writer.h +++ b/ui/base/clipboard/scoped_clipboard_writer.h -@@ -87,6 +87,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter { +@@ -91,6 +91,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter { // This is only used to write custom format data. void WriteData(std::u16string_view format, mojo_base::BigBuffer data); diff --git a/patches/chromium/add_webmessageportconverter_entangleandinjectmessageportchannel.patch b/patches/chromium/add_webmessageportconverter_entangleandinjectmessageportchannel.patch index 19c0f09bb77de..0b622370ca739 100644 --- a/patches/chromium/add_webmessageportconverter_entangleandinjectmessageportchannel.patch +++ b/patches/chromium/add_webmessageportconverter_entangleandinjectmessageportchannel.patch @@ -8,7 +8,7 @@ accessing Blink internals. Its inverse, which already exists, is used in Android WebView. diff --git a/third_party/blink/public/web/web_message_port_converter.h b/third_party/blink/public/web/web_message_port_converter.h -index e7c4464f1b5aa19cbe441d94d88c949798ccb1e3..bd804d509ad5f3581154c6ede8653e7521cb71b8 100644 +index e7c4464f1b5aa19cbe441d94d88c949798ccb1e3..cdf9bca3df292531831b6df0077ba211a29548aa 100644 --- a/third_party/blink/public/web/web_message_port_converter.h +++ b/third_party/blink/public/web/web_message_port_converter.h @@ -13,6 +13,7 @@ @@ -19,18 +19,20 @@ index e7c4464f1b5aa19cbe441d94d88c949798ccb1e3..bd804d509ad5f3581154c6ede8653e75 } // namespace v8 namespace blink { -@@ -25,6 +26,9 @@ class BLINK_EXPORT WebMessagePortConverter { +@@ -25,6 +26,11 @@ class BLINK_EXPORT WebMessagePortConverter { // neutered, it will return nullopt. static std::optional<MessagePortChannel> DisentangleAndExtractMessagePortChannel(v8::Isolate*, v8::Local<v8::Value>); + + BLINK_EXPORT static v8::Local<v8::Value> -+ EntangleAndInjectMessagePortChannel(v8::Local<v8::Context>, MessagePortChannel); ++ EntangleAndInjectMessagePortChannel(v8::Isolate*, ++ v8::Local<v8::Context>, ++ MessagePortChannel); }; } // namespace blink diff --git a/third_party/blink/renderer/core/exported/web_message_port_converter.cc b/third_party/blink/renderer/core/exported/web_message_port_converter.cc -index 3270da19f73077b1fab7522144b9f3d52d9f6a5a..e6c5764c54a18b31223ac8c5b8f2d6ef732225d6 100644 +index 3270da19f73077b1fab7522144b9f3d52d9f6a5a..bbd3c968027549b89087d9a4394f575d84213eba 100644 --- a/third_party/blink/renderer/core/exported/web_message_port_converter.cc +++ b/third_party/blink/renderer/core/exported/web_message_port_converter.cc @@ -6,6 +6,7 @@ @@ -41,19 +43,20 @@ index 3270da19f73077b1fab7522144b9f3d52d9f6a5a..e6c5764c54a18b31223ac8c5b8f2d6ef #include "third_party/blink/renderer/bindings/core/v8/v8_message_port.h" #include "third_party/blink/renderer/core/messaging/message_port.h" -@@ -21,4 +22,15 @@ WebMessagePortConverter::DisentangleAndExtractMessagePortChannel( +@@ -21,4 +22,16 @@ WebMessagePortConverter::DisentangleAndExtractMessagePortChannel( return port->Disentangle(); } +v8::Local<v8::Value> +WebMessagePortConverter::EntangleAndInjectMessagePortChannel( ++ v8::Isolate* isolate, + v8::Local<v8::Context> context, + MessagePortChannel port_channel) { + auto* execution_context = ToExecutionContext(context); + CHECK(execution_context); + auto* port = MakeGarbageCollected<MessagePort>(*execution_context); + port->Entangle(std::move(port_channel)); -+ return port->ToV8(context->GetIsolate(), context->Global()); ++ return port->ToV8(isolate, context->Global()); +} + } // namespace blink diff --git a/patches/chromium/adjust_accessibility_ui_for_electron.patch b/patches/chromium/adjust_accessibility_ui_for_electron.patch index f9d42ad06d4f4..5a517f6b5446b 100644 --- a/patches/chromium/adjust_accessibility_ui_for_electron.patch +++ b/patches/chromium/adjust_accessibility_ui_for_electron.patch @@ -10,7 +10,7 @@ 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 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aabbba621cb 100644 +index 3a9f87d82212bfeab23b312a593fb855df344780..83b4a7fe7149f2b195e53fcb05f77da3b33c3777 100644 --- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc +++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc @@ -48,6 +48,7 @@ @@ -19,18 +19,18 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab #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/ax_mode.h" #include "ui/accessibility/ax_updates_and_events.h" - #include "ui/accessibility/platform/ax_platform.h" -@@ -173,7 +174,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) { +@@ -179,7 +180,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) { rvh->GetRoutingID(), accessibility_mode); } -#if !BUILDFLAG(IS_ANDROID) +#if 0 - base::Value::Dict BuildTargetDescriptor(Browser* browser) { + base::Value::Dict BuildTargetDescriptor(BrowserWindowInterface* browser) { base::Value::Dict target_data; - target_data.Set(kSessionIdField, browser->session_id().id()); -@@ -197,7 +198,7 @@ void HandleAccessibilityRequestCallback( + target_data.Set(kSessionIdField, browser->GetSessionID().id()); +@@ -226,7 +227,7 @@ void HandleAccessibilityRequestCallback( auto& browser_accessibility_state = *content::BrowserAccessibilityState::GetInstance(); base::Value::Dict data; @@ -39,7 +39,7 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab ui::AXMode mode = browser_accessibility_state.GetAccessibilityMode(); bool native = mode.has_mode(ui::AXMode::kNativeAPIs); bool web = mode.has_mode(ui::AXMode::kWebContents); -@@ -258,7 +259,7 @@ void HandleAccessibilityRequestCallback( +@@ -287,7 +288,7 @@ void HandleAccessibilityRequestCallback( data.Set(kIsScreenReaderActive, is_screen_reader_active); std::string pref_api_type = @@ -48,21 +48,23 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab bool pref_api_type_supported = false; std::vector<ui::AXApiType::Type> supported_api_types = -@@ -326,11 +327,11 @@ void HandleAccessibilityRequestCallback( +@@ -355,13 +356,13 @@ void HandleAccessibilityRequestCallback( data.Set(kPagesField, std::move(page_list)); base::Value::List browser_list; -#if !BUILDFLAG(IS_ANDROID) +#if 0 - for (Browser* browser : *BrowserList::GetInstance()) { - browser_list.Append(BuildTargetDescriptor(browser)); - } + ForEachCurrentBrowserWindowInterfaceOrderedByActivation( + [&browser_list](BrowserWindowInterface* browser) { + browser_list.Append(BuildTargetDescriptor(browser)); + return true; + }); -#endif // !BUILDFLAG(IS_ANDROID) +#endif data.Set(kBrowsersField, std::move(browser_list)); - std::string json_string; -@@ -804,7 +805,8 @@ void AccessibilityUIMessageHandler::SetGlobalString( + #if BUILDFLAG(IS_WIN) +@@ -848,7 +849,8 @@ void AccessibilityUIMessageHandler::SetGlobalString( const std::string value = CheckJSValue(data.FindString(kValueField)); if (string_name == kApiTypeField) { @@ -72,7 +74,7 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab pref->SetString(prefs::kShownAccessibilityApiType, value); } } -@@ -858,7 +860,8 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree( +@@ -902,7 +904,8 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree( AXPropertyFilter::ALLOW_EMPTY); AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY); @@ -82,23 +84,25 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab ui::AXApiType::Type api_type = ui::AXApiType::From(pref->GetString(prefs::kShownAccessibilityApiType)); std::string accessibility_contents = -@@ -885,6 +888,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( - AXPropertyFilter::ALLOW_EMPTY); - AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY); +@@ -922,7 +925,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( + + AllowJavascript(); +-#if !BUILDFLAG(IS_ANDROID) +#if 0 - for (Browser* browser : *BrowserList::GetInstance()) { - if (browser->session_id().id() == session_id) { - base::Value::Dict result = BuildTargetDescriptor(browser); -@@ -897,6 +901,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( - return; - } + std::vector<AXPropertyFilter> property_filters; + AddPropertyFilters(property_filters, allow, AXPropertyFilter::ALLOW); + AddPropertyFilters(property_filters, allow_empty, +@@ -949,7 +952,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( + if (found) { + return; } +-#endif // !BUILDFLAG(IS_ANDROID) +#endif - #endif // !BUILDFLAG(IS_ANDROID) // No browser with the specified |session_id| was found. base::Value::Dict result; -@@ -940,11 +945,13 @@ void AccessibilityUIMessageHandler::StopRecording( + result.Set(kSessionIdField, session_id); +@@ -992,11 +995,13 @@ void AccessibilityUIMessageHandler::StopRecording( } ui::AXApiType::Type AccessibilityUIMessageHandler::GetRecordingApiType() { @@ -115,7 +119,7 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab // 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()) { -@@ -1014,8 +1021,11 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents( +@@ -1066,10 +1071,13 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents( // static void AccessibilityUIMessageHandler::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { @@ -127,11 +131,13 @@ index 20ba6b8fa6a7d5edf8ebab80ec15ece93d750000..6c42d825e520982c7fcac52cf3aa8aab + registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false); +#endif } + + void AccessibilityUIMessageHandler::OnVisibilityChanged( diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.h b/chrome/browser/ui/webui/accessibility/accessibility_ui.h -index b171afc941b2b3ef4aeba04a2b1c6eef2774d442..8f431aae69365bc8756e515c603332a7f1648148 100644 +index 4b9d7df73c901c57c14693e9f24a51694ecd375f..93e1c9a79d88c8b4c57b244c9eec1e83c1d1fa0a 100644 --- a/chrome/browser/ui/webui/accessibility/accessibility_ui.h +++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.h -@@ -27,6 +27,8 @@ namespace content { +@@ -28,6 +28,8 @@ namespace content { class WebContents; } // namespace content @@ -140,7 +146,7 @@ index b171afc941b2b3ef4aeba04a2b1c6eef2774d442..8f431aae69365bc8756e515c603332a7 namespace user_prefs { class PrefRegistrySyncable; } // namespace user_prefs -@@ -77,6 +79,8 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler { +@@ -79,6 +81,8 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler, static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); private: diff --git a/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch b/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch index b0dd83c2ce2cc..e64378b32e982 100644 --- a/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch +++ b/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch @@ -6,11 +6,11 @@ Subject: allow disabling blink scheduler throttling per RenderView This allows us to disable throttling for hidden windows. diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc -index 1d002528ba2b90d9c361c77ab00aeb1ccd000177..77f3b011f9c3710ac93ad20a92eafea0d35bb9a7 100644 +index ab916b56116e911af3cf6655cdd68ce139e260b9..f148ce57ae6c75f6635fca487d9493199b79a9f3 100644 --- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc +++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc -@@ -168,6 +168,12 @@ class MockPageBroadcast : public blink::mojom::PageBroadcast { - (const std::optional<uint64_t> canvas_noise_token), +@@ -167,6 +167,12 @@ class MockPageBroadcast : public blink::mojom::PageBroadcast { + (bool supports_draggable_regions), (override)); + MOCK_METHOD( @@ -23,10 +23,10 @@ index 1d002528ba2b90d9c361c77ab00aeb1ccd000177..77f3b011f9c3710ac93ad20a92eafea0 return receiver_.BindNewEndpointAndPassDedicatedRemote(); } diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc -index ac7638da0c0b360d21b88e4e458d3687949884fa..45d2fe002330cb4aa7c81defaa5004d5e62e369a 100644 +index 44fc40e608097797e4c2f5675bf10e5cdeb54d27..aa1d092cfc389fe81052160dc435981069a8a600 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc -@@ -786,6 +786,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) { +@@ -756,6 +756,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) { GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque); } @@ -51,25 +51,25 @@ index 7944fe64e0da112fc670358b75506bb199bb5e4a..0e3c16c6af2a078943e9f39808134ab2 void SendRendererPreferencesToRenderer( const blink::RendererPreferences& preferences); diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc -index b14f5bc3f023c512a066ce9ec9f681c96b1fafc4..b930145db575eb8c4e84297ddd610bd90fb5d3a8 100644 +index 84899b5208f036bd58ba51513820404b6c5a24b9..87fd5aa4fab7ddd0b444a3c8473ae35066c87054 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc -@@ -580,8 +580,8 @@ void RenderWidgetHostViewAura::ShowImpl(PageVisibilityState page_visibility) { +@@ -632,8 +632,8 @@ void RenderWidgetHostViewAura::ShowImpl(PageVisibilityState page_visibility) { // OnShowWithPageVisibility will not call NotifyHostAndDelegateOnWasShown, // which updates `visibility_`, unless the host is hidden. Make sure no update // is needed. -- CHECK(host_->is_hidden() || visibility_ == Visibility::VISIBLE); +- CHECK(host_->IsHidden() || visibility_ == Visibility::VISIBLE); - OnShowWithPageVisibility(page_visibility); -+ if (host_->is_hidden() || visibility_ == Visibility::VISIBLE) ++ if (host_->IsHidden() || visibility_ == Visibility::VISIBLE) + OnShowWithPageVisibility(page_visibility); } void RenderWidgetHostViewAura::EnsurePlatformVisibility( diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h -index 20ca763ff7f55e8176b77349b41917b11e051ae6..a50c122064b5f0092f57e3d508fb19389b72203b 100644 +index 782bed0fdc08d57eceb059f398f253fab9233b1b..f1ab5b981ea68af1b11313e67f2c5060f0a640b1 100644 --- a/content/public/browser/render_view_host.h +++ b/content/public/browser/render_view_host.h -@@ -75,6 +75,9 @@ class CONTENT_EXPORT RenderViewHost { +@@ -73,6 +73,9 @@ class CONTENT_EXPORT RenderViewHost { virtual void WriteIntoTrace( perfetto::TracedProto<TraceProto> context) const = 0; @@ -80,34 +80,34 @@ index 20ca763ff7f55e8176b77349b41917b11e051ae6..a50c122064b5f0092f57e3d508fb1938 // This interface should only be implemented inside content. friend class RenderViewHostImpl; diff --git a/content/test/test_page_broadcast.h b/content/test/test_page_broadcast.h -index 0dc1cd52dec74ede2117eb244e423d7f3ad322ea..352c64b3aec50546451a0033114e3a35dcf32136 100644 +index 4c8d44cdb2fde8e174b78aee7defb980651da18e..f8bf421b5b32af4cd197cbf23f4bd281c3a12514 100644 --- a/content/test/test_page_broadcast.h +++ b/content/test/test_page_broadcast.h -@@ -53,6 +53,7 @@ class TestPageBroadcast : public blink::mojom::PageBroadcast { +@@ -52,6 +52,7 @@ class TestPageBroadcast : public blink::mojom::PageBroadcast { + void UpdateColorProviders( const blink::ColorProviderColorMaps& color_provider_colors) override; - void UpdateCanvasNoiseToken( - std::optional<uint64_t> canvas_noise_token) override; + void SetSupportsDraggableRegions(bool supports_draggable_regions) override; + void SetSchedulerThrottling(bool allowed) override {} mojo::AssociatedReceiver<blink::mojom::PageBroadcast> receiver_; }; diff --git a/third_party/blink/public/mojom/page/page.mojom b/third_party/blink/public/mojom/page/page.mojom -index bcf8559d759e73e4f3f00710d263fe24cc801828..556f990868b862452156cec2354a90ae75352251 100644 +index b00bc8a8a5044fbf46f627f9db56cea7f09d7ef6..114c3a4522d11c1348f681af500c487ccd97eea9 100644 --- a/third_party/blink/public/mojom/page/page.mojom +++ b/third_party/blink/public/mojom/page/page.mojom @@ -180,4 +180,7 @@ interface PageBroadcast { - // the noise token at ReadyToCommit time and update blink::WebViews that - // were made at request time. - UpdateCanvasNoiseToken(uint64? canvas_noise_token); + // Indicates that the page's main frame should collect draggable regions set + // using the app-region CSS property. + SetSupportsDraggableRegions(bool supports_draggable_regions); + + // Whether to enable the Renderer scheduler background throttling. + SetSchedulerThrottling(bool allowed); }; diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h -index b3553c0783a7b00e055f82ef0b72bd866284473d..c91e49807ec0b56d867504831118269116024626 100644 +index 932658273154ef2e022358e493a8e7c00c86e732..57bbfb5cde62c9496c351c861880a18918e22c05 100644 --- a/third_party/blink/public/web/web_view.h +++ b/third_party/blink/public/web/web_view.h -@@ -365,6 +365,7 @@ class BLINK_EXPORT WebView { +@@ -355,6 +355,7 @@ class BLINK_EXPORT WebView { // Scheduling ----------------------------------------------------------- virtual PageScheduler* Scheduler() const = 0; @@ -116,10 +116,10 @@ index b3553c0783a7b00e055f82ef0b72bd866284473d..c91e49807ec0b56d8675048311182691 // Visibility ----------------------------------------------------------- diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc -index 316e686d00b72bf9d2e153221bfc3b97dbad8b61..b9799837c7ce14fc76045700b30e1358d4705251 100644 +index e974581ae0c6b146b92054a56174ba8fdb666574..0d1cd0e4f502f44362fba6552080f31fe5c6b7ea 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc -@@ -2490,6 +2490,10 @@ void WebViewImpl::SetPageLifecycleStateInternal( +@@ -2505,6 +2505,10 @@ void WebViewImpl::SetPageLifecycleStateInternal( TRACE_EVENT2("navigation", "WebViewImpl::SetPageLifecycleStateInternal", "old_state", old_state, "new_state", new_state); @@ -130,7 +130,7 @@ index 316e686d00b72bf9d2e153221bfc3b97dbad8b61..b9799837c7ce14fc76045700b30e1358 bool storing_in_bfcache = new_state->is_in_back_forward_cache && !old_state->is_in_back_forward_cache; bool restoring_from_bfcache = !new_state->is_in_back_forward_cache && -@@ -3999,10 +4003,23 @@ PageScheduler* WebViewImpl::Scheduler() const { +@@ -4013,10 +4017,23 @@ PageScheduler* WebViewImpl::Scheduler() const { return GetPage()->GetPageScheduler(); } @@ -155,10 +155,10 @@ index 316e686d00b72bf9d2e153221bfc3b97dbad8b61..b9799837c7ce14fc76045700b30e1358 // Do not throttle if the page should be painting. bool is_visible = diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h -index efcec3ebab3e60b66c2444e9a5c755c945f052cf..85cd9599cb5169f01c9096d9da89cff59930d1be 100644 +index aecdcea36ed0a502a9da68e871e0ee86040b4350..b2788642a20511f3725d045bc97bc108fba88752 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h -@@ -450,6 +450,7 @@ class CORE_EXPORT WebViewImpl final : public WebView, +@@ -445,6 +445,7 @@ class CORE_EXPORT WebViewImpl final : public WebView, LocalDOMWindow* PagePopupWindow() const; PageScheduler* Scheduler() const override; @@ -166,7 +166,7 @@ index efcec3ebab3e60b66c2444e9a5c755c945f052cf..85cd9599cb5169f01c9096d9da89cff5 void SetVisibilityState(mojom::blink::PageVisibilityState visibility_state, bool is_initial_state) override; mojom::blink::PageVisibilityState GetVisibilityState() override; -@@ -941,6 +942,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, +@@ -938,6 +939,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, // If true, we send IPC messages when |preferred_size_| changes. bool send_preferred_size_changes_ = false; diff --git a/patches/chromium/allow_electron_to_depend_on_components_os_crypt_sync.patch b/patches/chromium/allow_electron_to_depend_on_components_os_crypt_sync.patch new file mode 100644 index 0000000000000..ca5fb38aa2e53 --- /dev/null +++ b/patches/chromium/allow_electron_to_depend_on_components_os_crypt_sync.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt <jkleinsc@electronjs.org> +Date: Mon, 15 Sep 2025 15:52:55 -0400 +Subject: Allow electron to depend on components/os_crypt/sync. + +This is necessary after +https://chromium-review.googlesource.com/c/chromium/src/+/6944749 +landed. That CL notes that "new code should use os_crypt async", +so we can remove this patch once we migrate our code to use +os_crypt async. + +diff --git a/components/os_crypt/sync/BUILD.gn b/components/os_crypt/sync/BUILD.gn +index 23aa391aaf380f87310fb295277809f8b105d6e8..bb308187837371ecfa2482affaf35ac7ed98c1f3 100644 +--- a/components/os_crypt/sync/BUILD.gn ++++ b/components/os_crypt/sync/BUILD.gn +@@ -10,6 +10,7 @@ import("//components/os_crypt/sync/features.gni") + component("sync") { + # New code should use os_crypt async. + visibility = [ ++ "//electron:*", + "//chrome/browser", + "//chrome/test:test_support", + "//components/os_crypt/async/browser:dpapi_key_provider", diff --git a/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch b/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch index 2657586719699..8107e23a707ea 100644 --- a/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch +++ b/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch @@ -8,10 +8,10 @@ WebPreferences of in-process child windows, rather than relying on process-level command line switches, as before. diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc -index e66a1b104fbcb6ac81b745a28588a994533745ff..08abd32cebf89d434bf60b4fd420430e88540adc 100644 +index 11e6b9d984eb95adfeb8675d487002fa1ac851bd..081cf9d03cb9db13113b604af104afbe9030e5c8 100644 --- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc +++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc -@@ -148,6 +148,19 @@ bool StructTraits<blink::mojom::WebPreferencesDataView, +@@ -150,6 +150,19 @@ bool StructTraits<blink::mojom::WebPreferencesDataView, out->v8_cache_options = data.v8_cache_options(); out->record_whole_document = data.record_whole_document(); out->stylus_handwriting_enabled = data.stylus_handwriting_enabled(); @@ -32,7 +32,7 @@ index e66a1b104fbcb6ac81b745a28588a994533745ff..08abd32cebf89d434bf60b4fd420430e out->accelerated_video_decode_enabled = data.accelerated_video_decode_enabled(); diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h -index 39eefd4970a93bef42487d51e9c0bdfd76a001a0..a76da90ca59e07ad57ae85ee765b90875b82819c 100644 +index 1ba0466171963503d412b8aeb37d5953b3bbda9d..34654a186c0dc1715ac217d4c1480e6c36897e93 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences.h +++ b/third_party/blink/public/common/web_preferences/web_preferences.h @@ -9,6 +9,7 @@ @@ -43,8 +43,8 @@ index 39eefd4970a93bef42487d51e9c0bdfd76a001a0..a76da90ca59e07ad57ae85ee765b9087 #include "build/build_config.h" #include "net/nqe/effective_connection_type.h" #include "third_party/blink/public/common/common_export.h" -@@ -462,6 +463,19 @@ struct BLINK_COMMON_EXPORT WebPreferences { - bool increment_local_surface_id_for_mainframe_same_doc_navigation = true; +@@ -466,6 +467,19 @@ struct BLINK_COMMON_EXPORT WebPreferences { + bool should_screenshot_on_mainframe_same_doc_navigation = true; #endif // BUILDFLAG(IS_ANDROID) + // Begin Electron-specific WebPreferences. @@ -64,7 +64,7 @@ index 39eefd4970a93bef42487d51e9c0bdfd76a001a0..a76da90ca59e07ad57ae85ee765b9087 // chrome, except for the cases where it would require lots of extra work for // the embedder to use the same default value. diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h -index 36e04a5f887fd9102b3d74a4230132ecee780c1b..8e53242f1be83920ca64c95c31aa674e04d2bb81 100644 +index 53cfdb6a2739aedef3c72fc2e43709dd5a673c79..045b43f48a619234a8c0c4c76aea1025c10f193d 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h +++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h @@ -8,6 +8,7 @@ @@ -75,7 +75,7 @@ index 36e04a5f887fd9102b3d74a4230132ecee780c1b..8e53242f1be83920ca64c95c31aa674e #include "mojo/public/cpp/bindings/struct_traits.h" #include "net/nqe/effective_connection_type.h" #include "third_party/blink/public/common/common_export.h" -@@ -434,6 +435,52 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView, +@@ -439,6 +440,52 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView, return r.stylus_handwriting_enabled; } @@ -129,22 +129,18 @@ index 36e04a5f887fd9102b3d74a4230132ecee780c1b..8e53242f1be83920ca64c95c31aa674e return r.cookie_enabled; } diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom -index dd6185b0eacf942d902505ac23bf88059bf2786a..f3f1c71f241db0a90144909971412009e5510b6e 100644 +index 58b674f1848a5a70d08323d6f734794218d6ea8e..7011b1b7a754bfc2be30cf4eb07a32134d218359 100644 --- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom +++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom -@@ -8,9 +8,11 @@ import "third_party/blink/public/mojom/css/preferred_color_scheme.mojom"; - import "third_party/blink/public/mojom/css/preferred_contrast.mojom"; - import "third_party/blink/public/mojom/v8_cache_options.mojom"; - import "url/mojom/url.mojom"; +@@ -4,6 +4,7 @@ + + module blink.mojom; + +import "mojo/public/mojom/base/file_path.mojom"; import "mojo/public/mojom/base/string16.mojom"; import "skia/public/mojom/skcolor.mojom"; - -+ - enum PointerType { - kPointerNone = 1, // 1 << 0 - kPointerFirstType = kPointerNone, -@@ -217,6 +219,19 @@ struct WebPreferences { + import "third_party/blink/public/mojom/css/preferred_color_scheme.mojom"; +@@ -224,6 +225,19 @@ struct WebPreferences { // If true, stylus handwriting recognition to text input will be available in // editable input fields which are non-password type. bool stylus_handwriting_enabled; diff --git a/patches/chromium/blink_local_frame.patch b/patches/chromium/blink_local_frame.patch index def5a21d47ee5..ddfe150797fc2 100644 --- a/patches/chromium/blink_local_frame.patch +++ b/patches/chromium/blink_local_frame.patch @@ -15,7 +15,7 @@ Refs changes in: This patch reverts the changes to fix associated crashes in Electron. diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc -index c9f34fa47702504ccdefb8d61c55f5eaae501085..26df03d777c9ea487cae37f3df91d1df233b75e2 100644 +index 2670ea1361ccd8a9e3bac507e94dd25b7205ecf9..c12f78d925e4ccb4ac2fd3851a9c61e87058dc75 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc @@ -134,14 +134,6 @@ bool Frame::Detach(FrameDetachType type) { @@ -49,10 +49,10 @@ index c9f34fa47702504ccdefb8d61c55f5eaae501085..26df03d777c9ea487cae37f3df91d1df // its owning reference back to our owning LocalFrame. client_->Detached(type); diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc -index e57912ad2d06ccd3d5c0f4d958a0735d1fab9997..7aeff27d6005d70f962fcbd90e6902987e3abd09 100644 +index f05c75ec4483f60ccbb4aac3c4bc322d594ab217..b299f0dbfcc23458390d2c7298cc5df33f129b2b 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc -@@ -738,10 +738,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { +@@ -750,10 +750,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { } DCHECK(!view_ || !view_->IsAttached()); @@ -63,7 +63,7 @@ index e57912ad2d06ccd3d5c0f4d958a0735d1fab9997..7aeff27d6005d70f962fcbd90e690298 if (!Client()) return false; -@@ -795,6 +791,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { +@@ -807,6 +803,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { DCHECK(!view_->IsAttached()); Client()->WillBeDetached(); diff --git a/patches/chromium/build_add_electron_tracing_category.patch b/patches/chromium/build_add_electron_tracing_category.patch index d5d2be358809a..5a6cd72ec20cd 100644 --- a/patches/chromium/build_add_electron_tracing_category.patch +++ b/patches/chromium/build_add_electron_tracing_category.patch @@ -8,10 +8,10 @@ categories in use are known / declared. This patch is required for us to introduce a new Electron category for Electron-specific tracing. diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h -index e72bdff1c640ae6f6cbf91727a01985ccf9bd83b..40059b155b5ea9882a2ae4b624c68d3335fdc9f9 100644 +index 404faaae45884e2347fb3a7a2d77c7b95c7f6b43..e63bfce2d65a2015993de91630928029288738f4 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h -@@ -124,6 +124,7 @@ PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE_WITH_ATTRS( +@@ -131,6 +131,7 @@ PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE_WITH_ATTRS( perfetto::Category("drm"), perfetto::Category("drmcursor"), perfetto::Category("dwrite"), diff --git a/patches/chromium/build_add_public_config_simdutf_config.patch b/patches/chromium/build_add_public_config_simdutf_config.patch index 3417d2da5db21..de63ade9774c0 100644 --- a/patches/chromium/build_add_public_config_simdutf_config.patch +++ b/patches/chromium/build_add_public_config_simdutf_config.patch @@ -11,10 +11,10 @@ To accomplish this, we need to make simdutf's config public here for use by third_party/electron_node. diff --git a/third_party/simdutf/BUILD.gn b/third_party/simdutf/BUILD.gn -index 5fbce38841f04dad38f202f529ae84c609c6a8de..9f5ef9bceade8e30bbd2be616b9143e9708fefd8 100644 +index 68f1ed4e012cff5e0abd64a153a329518860689d..eeb846525e58f038733318915a770bafa22cafc5 100644 --- a/third_party/simdutf/BUILD.gn +++ b/third_party/simdutf/BUILD.gn -@@ -6,9 +6,14 @@ source_set("header") { +@@ -8,9 +8,14 @@ source_set("header") { sources = [ "simdutf.h" ] } diff --git a/patches/chromium/build_allow_electron_mojom_interfaces_to_depend_on_blink.patch b/patches/chromium/build_allow_electron_mojom_interfaces_to_depend_on_blink.patch index 5bbfd22399d33..5f9550a820635 100644 --- a/patches/chromium/build_allow_electron_mojom_interfaces_to_depend_on_blink.patch +++ b/patches/chromium/build_allow_electron_mojom_interfaces_to_depend_on_blink.patch @@ -10,10 +10,10 @@ Needed for: 2) //electron/shell/common:web_contents_utility diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn -index 981abc2963aaaa8f4cf283cdc0807907500b65eb..4be2f078f0c9890d0bcca635a82711386abae077 100644 +index 49f3360c3d5ff66ebbc7d6164de3f7ff7244b1fe..ec9018d38520dfca461e9dbb041566b0b3400133 100644 --- a/content/public/common/BUILD.gn +++ b/content/public/common/BUILD.gn -@@ -382,6 +382,8 @@ mojom("interfaces") { +@@ -362,6 +362,8 @@ mojom("interfaces") { "//content/common/*", "//extensions/common:mojom", "//extensions/common:mojom_blink", diff --git a/patches/chromium/build_disable_thin_lto_mac.patch b/patches/chromium/build_disable_thin_lto_mac.patch index 63e03add5f03e..bfd759159ead3 100644 --- a/patches/chromium/build_disable_thin_lto_mac.patch +++ b/patches/chromium/build_disable_thin_lto_mac.patch @@ -11,15 +11,15 @@ This patch can (and should) be removed when we can prevent those symbols from being stripped in the release build. diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni -index 0611cd47ef35d3b137a3278896a9174ae2fc3c31..a076c0f461b50fea86679a148b857739f7ec2c3d 100644 +index 2cf6def300d9d92d476ca4ca792347a49bafc26a..8e54f1d3e50a2c56b0cf35a8e56f97f6622401d5 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni -@@ -88,7 +88,7 @@ declare_args() { - # have the same LLVM revisions as us, making bitcode useless to them. +@@ -85,7 +85,7 @@ declare_args() { + # Chrome's clang. crbug.com/1033839 use_thin_lto = is_cfi || (is_clang && is_official_build && chrome_pgo_phase != 1 && -- (is_linux || is_win || is_mac || -+ (is_linux || is_win || - (is_ios && use_lld && !is_cronet_build) || +- (is_linux || is_win || is_mac || (is_ios && use_lld) || ++ (is_linux || is_win || (is_ios && use_lld) || (is_android && target_os != "chromeos") || (is_chromeos && is_chromeos_device))) + diff --git a/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch b/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch index 1d639a33a7d0b..8352874a725ee 100644 --- a/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch +++ b/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch @@ -11,10 +11,10 @@ if we ever align our .pak file generation with Chrome we can remove this patch. diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn -index e648bb4ed2ff72441faa8773e449e0b6174f5af5..fd2c1d3ac575d10de7d5c09e4418d17217a43b77 100644 +index 606b3bd43179a5b4179a6ec9f58e531d55c1acb5..4d503a53290b4deaea016bb6867f3c07920f4055 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn -@@ -195,11 +195,16 @@ if (!is_android && !is_mac) { +@@ -196,11 +196,16 @@ if (!is_android && !is_mac) { "common/crash_keys.h", ] @@ -33,10 +33,10 @@ index e648bb4ed2ff72441faa8773e449e0b6174f5af5..fd2c1d3ac575d10de7d5c09e4418d172 "//base", "//build:branding_buildflags", diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn -index a8c2f5c562df8974ad02128a363e11ecd489031f..ca1bf94b55f1412599abbbe47063f0ce036c2352 100644 +index c88784479b8d67d8a3f534b555bd6e74c46173fe..cfd9ed1e6a37b3f0034116323320958a1d962f43 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn -@@ -4795,7 +4795,7 @@ static_library("browser") { +@@ -4837,7 +4837,7 @@ static_library("browser") { ] } @@ -46,10 +46,10 @@ index a8c2f5c562df8974ad02128a363e11ecd489031f..ca1bf94b55f1412599abbbe47063f0ce # than here in :chrome_dll. deps += [ "//chrome:packed_resources_integrity_header" ] diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn -index 9fb0b20dd5feb4f4b6ee4d97bcf9fc8e1b43d89c..a55f08cfa09eb2b1afbaab780db2a275ad490d78 100644 +index 23f175d87f95562875af1e7ddd51be4f719e82b8..7488e095e0d32753dff7f5f170a4187ee6b7711e 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn -@@ -7500,9 +7500,12 @@ test("unit_tests") { +@@ -7599,9 +7599,12 @@ test("unit_tests") { "//chrome/notification_helper", ] @@ -63,7 +63,7 @@ index 9fb0b20dd5feb4f4b6ee4d97bcf9fc8e1b43d89c..a55f08cfa09eb2b1afbaab780db2a275 "//chrome//services/util_win:unit_tests", "//chrome/app:chrome_dll_resources", "//chrome/app:win_unit_tests", -@@ -8428,6 +8431,10 @@ test("unit_tests") { +@@ -8544,6 +8547,10 @@ test("unit_tests") { "../browser/performance_manager/policies/background_tab_loading_policy_unittest.cc", ] @@ -74,7 +74,7 @@ index 9fb0b20dd5feb4f4b6ee4d97bcf9fc8e1b43d89c..a55f08cfa09eb2b1afbaab780db2a275 sources += [ # The importer code is not used on Android. "../common/importer/firefox_importer_utils_unittest.cc", -@@ -8484,7 +8491,6 @@ test("unit_tests") { +@@ -8600,7 +8607,6 @@ test("unit_tests") { # TODO(crbug.com/417513088): Maybe merge with the non-android `deps` declaration above? deps += [ "../browser/screen_ai:screen_ai_install_state", diff --git a/patches/chromium/build_gn.patch b/patches/chromium/build_gn.patch index b50bf371f72e0..e13725206cf46 100644 --- a/patches/chromium/build_gn.patch +++ b/patches/chromium/build_gn.patch @@ -7,7 +7,7 @@ These are variables we add to the root BUILDCONFIG so that they're available everywhere, without having to import("//electron/.../flags.gni"). diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn -index b1b5e79b92bea8ea05770d8c48cb4366938d71c5..16664ed3ab4b0ceecd4c74e44e57cca0dc57dc9b 100644 +index 749662ebf2e8f271400f4015f5503378f42ef2b4..f974d8048ca21371865bcae56e8e687529e0be4b 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -123,6 +123,9 @@ if (current_os == "") { diff --git a/patches/chromium/build_libc_as_static_library.patch b/patches/chromium/build_libc_as_static_library.patch index f488d823be8c2..39d96eeb293d0 100644 --- a/patches/chromium/build_libc_as_static_library.patch +++ b/patches/chromium/build_libc_as_static_library.patch @@ -7,10 +7,10 @@ Build libc++ as static library to compile and pass nan tests diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn -index a024e6e435303a67cfd994d28b5a45a1d5343926..34715a1bbd1820c0d78b86cd9155bcf055778d94 100644 +index f1ac049db7df5637c94893009287b53c6127158f..ebf028bdb2934ca2f9f2ab7b7c3e6d3daa544d37 100644 --- a/buildtools/third_party/libc++/BUILD.gn +++ b/buildtools/third_party/libc++/BUILD.gn -@@ -860,6 +860,7 @@ target(libcxx_target_type, "libc++") { +@@ -481,6 +481,7 @@ target(libcxx_target_type, "libc++") { # need to explicitly depend on libc++. visibility = [ "//build/config:common_deps", diff --git a/patches/chromium/build_run_reclient_cfg_generator_after_chrome.patch b/patches/chromium/build_run_reclient_cfg_generator_after_chrome.patch index 58505e6a142e5..fe548a7a9ae1c 100644 --- a/patches/chromium/build_run_reclient_cfg_generator_after_chrome.patch +++ b/patches/chromium/build_run_reclient_cfg_generator_after_chrome.patch @@ -20,10 +20,10 @@ index 17103061c4752e6fcac07413dbf574e0c6fd6d39..848be71fa6dc81a64b7274b31d461f9d /win-cross/ reproxy.cfg diff --git a/buildtools/reclient_cfgs/configure_reclient_cfgs.py b/buildtools/reclient_cfgs/configure_reclient_cfgs.py -index 128bda296c91eac5f0c2fcfeed0c553deb5514dd..f1e33d36810dba80a42608655beb27c6e197a888 100755 +index 8779d4609c9eed155c414a1c97d3598906857b22..731ac034f85c8c5ebee6d29a0395f6e828b41ab0 100755 --- a/buildtools/reclient_cfgs/configure_reclient_cfgs.py +++ b/buildtools/reclient_cfgs/configure_reclient_cfgs.py -@@ -344,4 +344,13 @@ def main(): +@@ -334,4 +334,13 @@ def main(): if __name__ == "__main__": diff --git a/patches/chromium/build_set_mac_sdk_minimum_to_10.patch b/patches/chromium/build_set_mac_sdk_minimum_to_10.patch deleted file mode 100644 index 532be18ac425a..0000000000000 --- a/patches/chromium/build_set_mac_sdk_minimum_to_10.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Keeley Hammond <khammond@slack-corp.com> -Date: Tue, 1 Jul 2025 15:40:02 -0700 -Subject: build: Set MacOS SDK minimum back to 10 - -This commit reverts 6493969: Update mac_sdk_min to -match minimum required SDK version | -https://chromium-review.googlesource.com/c/chromium/src/+/6493969 - -This patch is purely to unblock nightlies while -we merge an upstream fix and allocate additional space -on the Mac runners. If this patch is still in main -anytime after July 30, 2025, find @VerteDinde and yell -at her. - -diff --git a/build/config/mac/mac_sdk_overrides.gni b/build/config/mac/mac_sdk_overrides.gni -index 8f8ac1c218ce15fa5c1aecbbcd0b93281f6c52f2..15ddfd5cffbaba0704b3217e1ae4f2825f399d96 100644 ---- a/build/config/mac/mac_sdk_overrides.gni -+++ b/build/config/mac/mac_sdk_overrides.gni -@@ -7,5 +7,5 @@ - - declare_args() { - # Minimum supported version of the Mac SDK. -- mac_sdk_min = "15" -+ mac_sdk_min = "10.15" - } diff --git a/patches/chromium/can_create_window.patch b/patches/chromium/can_create_window.patch index caf6966630ec1..197b18e80267d 100644 --- a/patches/chromium/can_create_window.patch +++ b/patches/chromium/can_create_window.patch @@ -9,10 +9,10 @@ potentially prevent a window from being created. TODO(loc): this patch is currently broken. diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc -index e812aff087701b5d38fcb0b916335e21f5713040..4f8e3a08890ed7498b29a900ccf4bbda5f9cb494 100644 +index 5025a34f81d255c9c3f8cb8c7ba8e570297f9a06..772cff9b1a9a061645f2220fdc3003627679ac58 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc -@@ -9819,6 +9819,7 @@ void RenderFrameHostImpl::CreateNewWindow( +@@ -9878,6 +9878,7 @@ void RenderFrameHostImpl::CreateNewWindow( last_committed_origin_, params->window_container_type, params->target_url, params->referrer.To<Referrer>(), params->frame_name, params->disposition, *params->features, @@ -21,10 +21,10 @@ index e812aff087701b5d38fcb0b916335e21f5713040..4f8e3a08890ed7498b29a900ccf4bbda &no_javascript_access); diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index a22f9897c47cc0fe0846fd631b0f094c0ded669a..5e35d7af2bcf9078887f4e2658e3f067f3b4f1b7 100644 +index b33145fdbfafd5ea1c23255a4fb8eff2088df915..e003e3a9784e3a9741283128a97f4e3bc255935b 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -5304,6 +5304,10 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -5314,6 +5314,10 @@ FrameTree* WebContentsImpl::CreateNewWindow( create_params.initially_hidden = renderer_started_hidden; create_params.initial_popup_url = params.target_url; @@ -35,7 +35,7 @@ index a22f9897c47cc0fe0846fd631b0f094c0ded669a..5e35d7af2bcf9078887f4e2658e3f067 // Even though all codepaths leading here are in response to a renderer // trying to open a new window, if the new window ends up in a different // browsing instance, then the RenderViewHost, RenderWidgetHost, -@@ -5359,6 +5363,12 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -5366,6 +5370,12 @@ FrameTree* WebContentsImpl::CreateNewWindow( // Sets the newly created WebContents WindowOpenDisposition. new_contents_impl->original_window_open_disposition_ = params.disposition; @@ -48,7 +48,7 @@ index a22f9897c47cc0fe0846fd631b0f094c0ded669a..5e35d7af2bcf9078887f4e2658e3f067 // If the new frame has a name, make sure any SiteInstances that can find // this named frame have proxies for it. Must be called after // SetSessionStorageNamespace, since this calls CreateRenderView, which uses -@@ -5400,12 +5410,6 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -5407,12 +5417,6 @@ FrameTree* WebContentsImpl::CreateNewWindow( AddWebContentsDestructionObserver(new_contents_impl); } @@ -62,10 +62,10 @@ index a22f9897c47cc0fe0846fd631b0f094c0ded669a..5e35d7af2bcf9078887f4e2658e3f067 new_contents_impl, opener, params.target_url, params.referrer.To<Referrer>(), params.disposition, diff --git a/content/common/frame.mojom b/content/common/frame.mojom -index 90cc84198b7f23c6a07ab503f60a577fdfba5baa..722b27b8adaf86624058ace5f9b5871ff0ede627 100644 +index 4c55f0abf8df5a3408f3f90d444ceff3c23ee1bc..72bdb5b5a4c2c21a7192b34bb293bd23bafaf50c 100644 --- a/content/common/frame.mojom +++ b/content/common/frame.mojom -@@ -661,6 +661,10 @@ struct CreateNewWindowParams { +@@ -648,6 +648,10 @@ struct CreateNewWindowParams { pending_associated_remote<blink.mojom.Widget> widget; pending_associated_receiver<blink.mojom.FrameWidgetHost> frame_widget_host; pending_associated_remote<blink.mojom.FrameWidget> frame_widget; @@ -77,10 +77,10 @@ index 90cc84198b7f23c6a07ab503f60a577fdfba5baa..722b27b8adaf86624058ace5f9b5871f // Operation result when the renderer asks the browser to create a new window. diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc -index 51635fb9f5da026fea3d25f0aa0d2d3f05017504..6a6b444270c3fcd084da7a63d8cc491e30b1eb20 100644 +index a0ccc5352495e75e1603fd3f90825eba85276a6a..3cf480086d77bddb3328aa02137e7bb66c2eb511 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc -@@ -872,6 +872,8 @@ bool ContentBrowserClient::CanCreateWindow( +@@ -885,6 +885,8 @@ bool ContentBrowserClient::CanCreateWindow( const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -90,10 +90,10 @@ index 51635fb9f5da026fea3d25f0aa0d2d3f05017504..6a6b444270c3fcd084da7a63d8cc491e bool opener_suppressed, bool* no_javascript_access) { diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h -index f9131c7b44751e3ab51a8db52ca22202138aeada..77addfedac20cf8ecf656321dda53ada149f17ff 100644 +index 3ca58d5630486cd378f3109b1ca59a4563608187..9f8fe55d6c360e3a709f2e5f05baf02c9ca29101 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h -@@ -201,6 +201,7 @@ class NetworkService; +@@ -203,6 +203,7 @@ class NetworkService; class TrustedURLLoaderHeaderClient; } // namespace mojom struct ResourceRequest; @@ -101,7 +101,7 @@ index f9131c7b44751e3ab51a8db52ca22202138aeada..77addfedac20cf8ecf656321dda53ada } // namespace network namespace sandbox { -@@ -1444,6 +1445,8 @@ class CONTENT_EXPORT ContentBrowserClient { +@@ -1462,6 +1463,8 @@ class CONTENT_EXPORT ContentBrowserClient { const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -111,10 +111,10 @@ index f9131c7b44751e3ab51a8db52ca22202138aeada..77addfedac20cf8ecf656321dda53ada bool opener_suppressed, bool* no_javascript_access); diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc -index ca92e2ddf78d8f386b5ab23a09876d3b44e21334..33be50ce93dd998df5244f9ade391943f06978ad 100644 +index 2bac91454385d005d8a6d14c45e63e64923310e0..4f79d90a7d30a6ce2a3720ef94c1ade264d20e16 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc -@@ -32,6 +32,17 @@ namespace content { +@@ -35,6 +35,17 @@ namespace content { WebContentsDelegate::WebContentsDelegate() = default; @@ -133,10 +133,10 @@ index ca92e2ddf78d8f386b5ab23a09876d3b44e21334..33be50ce93dd998df5244f9ade391943 WebContents* source, const OpenURLParams& params, diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h -index a4b8c5f950549e018c0d09522ff8890a1a774966..6c4c6265c26f5304b8f77d7fc5a4fad5dffc831d 100644 +index 2cda4986f3cdef0a01e755b57c307890b62aa4e2..1dab9cf23213d497bb6354d3b909911b014675ba 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h -@@ -18,6 +18,7 @@ +@@ -19,6 +19,7 @@ #include "base/types/expected.h" #include "build/build_config.h" #include "content/common/content_export.h" @@ -144,15 +144,15 @@ index a4b8c5f950549e018c0d09522ff8890a1a774966..6c4c6265c26f5304b8f77d7fc5a4fad5 #include "content/public/browser/eye_dropper.h" #include "content/public/browser/fullscreen_types.h" #include "content/public/browser/invalidate_type.h" -@@ -29,6 +30,7 @@ +@@ -30,6 +31,7 @@ #include "content/public/browser/select_audio_output_request.h" #include "content/public/browser/serial_chooser.h" #include "content/public/browser/storage_partition_config.h" +#include "content/public/browser/web_contents.h" #include "content/public/common/window_container_type.mojom-forward.h" #include "third_party/blink/public/common/input/web_mouse_event.h" - #include "third_party/blink/public/common/mediastream/media_stream_request.h" -@@ -384,6 +386,16 @@ class CONTENT_EXPORT WebContentsDelegate { + #include "third_party/blink/public/common/page/drag_operation.h" +@@ -397,6 +399,16 @@ class CONTENT_EXPORT WebContentsDelegate { const StoragePartitionConfig& partition_config, SessionStorageNamespace* session_storage_namespace); @@ -170,10 +170,10 @@ index a4b8c5f950549e018c0d09522ff8890a1a774966..6c4c6265c26f5304b8f77d7fc5a4fad5 // typically happens when popups are created. virtual void WebContentsCreated(WebContents* source_contents, diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc -index 55ff46bd1c24b2341317102f6308a66c1b5aeb23..859113ed13e77dcdd72b2ab327b94e94492f5d24 100644 +index 403ecc046ee270175a7e7444d9d80ed4456450cc..d4755acfd0ba3016da545de87d64046a6f5ee387 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc -@@ -6770,6 +6770,10 @@ WebView* RenderFrameImpl::CreateNewWindow( +@@ -6727,6 +6727,10 @@ WebView* RenderFrameImpl::CreateNewWindow( request.HasUserGesture(), GetWebFrame()->IsAdFrame(), GetWebFrame()->IsAdScriptInStack()); @@ -185,10 +185,10 @@ index 55ff46bd1c24b2341317102f6308a66c1b5aeb23..859113ed13e77dcdd72b2ab327b94e94 // moved on send. bool is_background_tab = diff --git a/content/web_test/browser/web_test_content_browser_client.cc b/content/web_test/browser/web_test_content_browser_client.cc -index 66a10226b043a490295e518230c20bba0ed71d6c..14b78014d93ce459789fd497dfcfb71e2cc769bd 100644 +index 576fd50ec4c27c6c2da9674e68f65fd0a21d1d68..b44304f128fb97523c9c9046b5edece8c09c5c0f 100644 --- a/content/web_test/browser/web_test_content_browser_client.cc +++ b/content/web_test/browser/web_test_content_browser_client.cc -@@ -537,6 +537,8 @@ bool WebTestContentBrowserClient::CanCreateWindow( +@@ -538,6 +538,8 @@ bool WebTestContentBrowserClient::CanCreateWindow( const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -211,7 +211,7 @@ index 790f004d2a3a9ae5a3588fda097732a5daac0c75..83fcc9418b89b669863e730f2049a1d8 bool opener_suppressed, bool* no_javascript_access) override; diff --git a/third_party/blink/public/web/web_window_features.h b/third_party/blink/public/web/web_window_features.h -index 82e9d3dfb5f7da76d89fe15ae61d379fa46e177d..fd035512099a54dff6cc951a2226c23a252a90e2 100644 +index d92bab531c12c62a5321a23f4a0cb89691668127..c354a79c7c8dd047264df35b873e90c15fa364a2 100644 --- a/third_party/blink/public/web/web_window_features.h +++ b/third_party/blink/public/web/web_window_features.h @@ -35,6 +35,7 @@ @@ -222,7 +222,7 @@ index 82e9d3dfb5f7da76d89fe15ae61d379fa46e177d..fd035512099a54dff6cc951a2226c23a namespace blink { -@@ -74,6 +75,8 @@ struct WebWindowFeatures { +@@ -70,6 +71,8 @@ struct WebWindowFeatures { // TODO(apaseltiner): Investigate moving this field to a non-public struct // since it is only needed within //third_party/blink. std::optional<std::vector<WebString>> attribution_srcs; @@ -232,15 +232,15 @@ index 82e9d3dfb5f7da76d89fe15ae61d379fa46e177d..fd035512099a54dff6cc951a2226c23a } // namespace blink diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc -index 23a95863dc888a9ffb4b09c2b034665ef1186f7c..558f6afcdf8faa91744ac2143a03de88c0965366 100644 +index 438eba715eb4f2a59676491d4d06cd6969c2a107..cfdd94e58cc81ce7b56a1ca64fe7b32cf7bc1f7e 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc -@@ -2354,6 +2354,8 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate, +@@ -2340,6 +2340,8 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate, WebWindowFeatures window_features = GetWindowFeaturesFromString(features, entered_window); + window_features.raw_features = features; + - if (window_features.is_partitioned_popin) { - UseCounter::Count(*entered_window, - WebFeature::kPartitionedPopin_OpenAttempt); + // In fenced frames, we should always use `noopener`. + if (GetFrame()->IsInFencedFrameTree()) { + window_features.noopener = true; diff --git a/patches/chromium/chore_add_electron_deps_to_gitignores.patch b/patches/chromium/chore_add_electron_deps_to_gitignores.patch index 3ed6a1cd0a480..f0e9f46157706 100644 --- a/patches/chromium/chore_add_electron_deps_to_gitignores.patch +++ b/patches/chromium/chore_add_electron_deps_to_gitignores.patch @@ -6,10 +6,10 @@ Subject: chore: add electron deps to gitignores Makes things like "git status" quicker when developing electron locally diff --git a/.gitignore b/.gitignore -index 901485a978b095c44d344c05564b943b5240a4e0..724d42a18a7a093608e665542859eb3c5bb81243 100644 +index e3b01b0a2b878681a861f76cb10f5b40bbc29a3d..277b05e37dadfd32fbcbbe1e596508aafd4313ba 100644 --- a/.gitignore +++ b/.gitignore -@@ -226,6 +226,7 @@ vs-chromium-project.txt +@@ -228,6 +228,7 @@ vs-chromium-project.txt /data /delegate_execute /device/serial/device_serial_mojo.xml @@ -18,10 +18,10 @@ index 901485a978b095c44d344c05564b943b5240a4e0..724d42a18a7a093608e665542859eb3c /google_apis/gcm/gcm.xml /googleurl diff --git a/third_party/.gitignore b/third_party/.gitignore -index a750ba32fa50d4367682bf11b88e6a8a4700dc46..c3188f418a6368b35adfdcb2cd96de1614826d39 100644 +index 6be9e9e6feeedd0d1f566758e8da75870bc1d9c7..a0bacf9e5c4809d76093c449065d7f4f5bb47b02 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore -@@ -46,7 +46,9 @@ +@@ -45,7 +45,9 @@ /directxsdk /dragonbox/src /edk2 diff --git a/patches/chromium/chore_add_electron_objects_to_wrappablepointertag.patch b/patches/chromium/chore_add_electron_objects_to_wrappablepointertag.patch index 4f63db0719663..042769fc0f74e 100644 --- a/patches/chromium/chore_add_electron_objects_to_wrappablepointertag.patch +++ b/patches/chromium/chore_add_electron_objects_to_wrappablepointertag.patch @@ -8,18 +8,22 @@ electron objects that extend gin::Wrappable and gets allocated on the cpp heap diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h -index 80ec409efe1635390887d1324be661643818abff..112a23f81680f5fcc2b016d8f5362e3a03507c8a 100644 +index 573bcb2e56068a2ade6d8ab28964b077487874fd..0321ca6d3c7e1ed541cc1beffb20b1db3d03a0c8 100644 --- a/gin/public/wrappable_pointer_tags.h +++ b/gin/public/wrappable_pointer_tags.h -@@ -66,7 +66,10 @@ enum WrappablePointerTag : uint16_t { - kTextInputControllerBindings, // content::TextInputControllerBindings - kWebAXObjectProxy, // content::WebAXObjectProxy - kWrappedExceptionHandler, // extensions::WrappedExceptionHandler +@@ -74,7 +74,14 @@ enum WrappablePointerTag : uint16_t { + kTextInputControllerBindings, // content::TextInputControllerBindings + kWebAXObjectProxy, // content::WebAXObjectProxy + kWrappedExceptionHandler, // extensions::WrappedExceptionHandler - kLastPointerTag = kWrappedExceptionHandler, + kElectronApp, // electron::api::App -+ kElectronSession, // electron::api::Session ++ kElectronDebugger, // electron::api::Debugger + kElectronEvent, // gin_helper::internal::Event -+ kLastPointerTag = kElectronEvent, ++ kElectronMenu, // electron::api::Menu ++ kElectronNetLog, // electron::api::NetLog ++ kElectronSession, // electron::api::Session ++ kElectronWebRequest, // electron::api::WebRequest ++ kLastPointerTag = kElectronWebRequest, }; static_assert(kLastPointerTag < diff --git a/patches/chromium/chore_disable_protocol_handler_dcheck.patch b/patches/chromium/chore_disable_protocol_handler_dcheck.patch new file mode 100644 index 0000000000000..98a7fa4019475 --- /dev/null +++ b/patches/chromium/chore_disable_protocol_handler_dcheck.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Maddock <smaddock@slack-corp.com> +Date: Thu, 9 Oct 2025 22:07:38 -0400 +Subject: chore: disable protocol handler dcheck + +https://chromium-review.googlesource.com/c/chromium/src/+/6727594 + +The above CL introduces a new extensions API to register custom protocol +handlers. A DCHECK causes Electron to crash until we provide our own +registry. This patch disables the check until we support this. + +diff --git a/extensions/browser/api/protocol_handlers/protocol_handlers_manager.cc b/extensions/browser/api/protocol_handlers/protocol_handlers_manager.cc +index 902cf488c7d84923365c4197a70b06e61e3af038..dce80684853f89a68a2d21997102f48feb3df8f8 100644 +--- a/extensions/browser/api/protocol_handlers/protocol_handlers_manager.cc ++++ b/extensions/browser/api/protocol_handlers/protocol_handlers_manager.cc +@@ -129,7 +129,12 @@ void ProtocolHandlersManager::ProtocolHandlersSanityCheck() { + auto* ph_registry = + ExtensionsBrowserClient::Get()->GetProtocolHandlerRegistry( + browser_context_); +- DCHECK(ph_registry); ++ ++ // TODO(samuelmaddock): Add support for extensions protocol handler. For now, ++ // let's ignore this. ++ if (!ph_registry) ++ return; ++ + for (const auto& handler : ph_registry->GetExtensionProtocolHandlers()) { + DCHECK(handler.extension_id()); + if (!enabled_ids.contains(*handler.extension_id())) { diff --git a/patches/chromium/chore_expose_isolate_parameter_in_script_lifecycle_observers.patch b/patches/chromium/chore_expose_isolate_parameter_in_script_lifecycle_observers.patch new file mode 100644 index 0000000000000..c0d590102e8c8 --- /dev/null +++ b/patches/chromium/chore_expose_isolate_parameter_in_script_lifecycle_observers.patch @@ -0,0 +1,272 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 <hop2deep@gmail.com> +Date: Mon, 1 Sep 2025 18:17:13 +0900 +Subject: chore: expose isolate parameter in script lifecycle observers + +Needed after https://chromium-review.googlesource.com/c/v8/v8/+/6875273 +where callsites that deal with multiple contexts need to distinguish +the current isolate. + +diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h +index 6fa11f89ea212eabd7fdc979d2d99138b1f3c88e..a35372743ce69d7cb04c54fcb75b49c0b6fe87c7 100644 +--- a/content/public/renderer/content_renderer_client.h ++++ b/content/public/renderer/content_renderer_client.h +@@ -389,6 +389,7 @@ class CONTENT_EXPORT ContentRendererClient { + // WillDestroyServiceWorkerContextOnWorkerThread() is called. + virtual void WillEvaluateServiceWorkerOnWorkerThread( + blink::WebServiceWorkerContextProxy* context_proxy, ++ v8::Isolate* const isolate, + v8::Local<v8::Context> v8_context, + int64_t service_worker_version_id, + const GURL& service_worker_scope, +diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h +index bbfac47a74f989482343c222b78f187b70297e4e..3677ca3345fbc775d139684a12fe36241827a729 100644 +--- a/content/public/renderer/render_frame_observer.h ++++ b/content/public/renderer/render_frame_observer.h +@@ -143,7 +143,8 @@ class CONTENT_EXPORT RenderFrameObserver { + int32_t world_id) {} + virtual void DidInstallConditionalFeatures(v8::Local<v8::Context> context, + int32_t world_id) {} +- virtual void WillReleaseScriptContext(v8::Local<v8::Context> context, ++ virtual void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context> context, + int32_t world_id) {} + virtual void DidClearWindowObject() {} + virtual void DidChangeScrollOffset() {} +diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc +index 7070884305eb648c9aa0020f8161202671e1f671..cdb0711205111f8fc76e995e6690fb5fa76ee9cb 100644 +--- a/content/renderer/render_frame_impl.cc ++++ b/content/renderer/render_frame_impl.cc +@@ -4668,10 +4668,11 @@ void RenderFrameImpl::DidInstallConditionalFeatures( + observer.DidInstallConditionalFeatures(context, world_id); + } + +-void RenderFrameImpl::WillReleaseScriptContext(v8::Local<v8::Context> context, ++void RenderFrameImpl::WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context> context, + int world_id) { + for (auto& observer : observers_) +- observer.WillReleaseScriptContext(context, world_id); ++ observer.WillReleaseScriptContext(isolate, context, world_id); + } + + void RenderFrameImpl::DidChangeScrollOffset() { +diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h +index 621cd9ae7f43470ed4414a48d62330b36c7058e9..f0c5f4f55062c85ee1e6b8da74b8f0c6ced75e81 100644 +--- a/content/renderer/render_frame_impl.h ++++ b/content/renderer/render_frame_impl.h +@@ -605,7 +605,8 @@ class CONTENT_EXPORT RenderFrameImpl + int world_id) override; + void DidInstallConditionalFeatures(v8::Local<v8::Context> context, + int world_id) override; +- void WillReleaseScriptContext(v8::Local<v8::Context> context, ++ void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context> context, + int world_id) override; + void DidChangeScrollOffset() override; + blink::WebMediaStreamDeviceObserver* MediaStreamDeviceObserver() override; +diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc +index 37691ecee7a72b2ec47ff575239f628116cf136b..c67e3faf7440514e203e5b15a68fc34525a045a2 100644 +--- a/content/renderer/service_worker/service_worker_context_client.cc ++++ b/content/renderer/service_worker/service_worker_context_client.cc +@@ -318,6 +318,7 @@ void ServiceWorkerContextClient::WorkerContextStarted( + } + + void ServiceWorkerContextClient::WillEvaluateScript( ++ v8::Isolate* const v8_isolate, + v8::Local<v8::Context> v8_context) { + DCHECK(worker_task_runner_->RunsTasksInCurrentSequence()); + start_timing_->script_evaluation_start_time = base::TimeTicks::Now(); +@@ -336,8 +337,8 @@ void ServiceWorkerContextClient::WillEvaluateScript( + + DCHECK(proxy_); + GetContentClient()->renderer()->WillEvaluateServiceWorkerOnWorkerThread( +- proxy_, v8_context, service_worker_version_id_, service_worker_scope_, +- script_url_, service_worker_token_); ++ proxy_, v8_isolate, v8_context, service_worker_version_id_, ++ service_worker_scope_, script_url_, service_worker_token_); + } + + void ServiceWorkerContextClient::DidEvaluateScript(bool success) { +diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h +index 1f5e24bc38d6ced52e4773236522e9520efc6f6d..a22ca5968fce5e6a0c436ec9b40f0e2f7c1482cf 100644 +--- a/content/renderer/service_worker/service_worker_context_client.h ++++ b/content/renderer/service_worker/service_worker_context_client.h +@@ -165,7 +165,8 @@ class ServiceWorkerContextClient + void WorkerContextStarted( + blink::WebServiceWorkerContextProxy* proxy, + scoped_refptr<base::SequencedTaskRunner> worker_task_runner) override; +- void WillEvaluateScript(v8::Local<v8::Context> v8_context) override; ++ void WillEvaluateScript(v8::Isolate* const isolate, ++ v8::Local<v8::Context> v8_context) override; + void DidEvaluateScript(bool success) override; + void WillInitializeWorkerContext() override; + void WillDestroyWorkerContext(v8::Local<v8::Context> context) override; +diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc +index 7b5398b4199ce6df9e1c9624771a5444d7f07eb3..77f896aa6a53bf7d277b963fba54d623eed8068b 100644 +--- a/extensions/renderer/dispatcher.cc ++++ b/extensions/renderer/dispatcher.cc +@@ -615,6 +615,7 @@ void Dispatcher::DidInitializeServiceWorkerContextOnWorkerThread( + + void Dispatcher::WillEvaluateServiceWorkerOnWorkerThread( + blink::WebServiceWorkerContextProxy* context_proxy, ++ v8::Isolate* const isolate, + v8::Local<v8::Context> v8_context, + int64_t service_worker_version_id, + const GURL& service_worker_scope, +diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h +index 9d4c74b7996e2e573079413cd24a99f86dd5b90f..241c012f1a7434944dc5ea6cad8a8c9988b069b2 100644 +--- a/extensions/renderer/dispatcher.h ++++ b/extensions/renderer/dispatcher.h +@@ -151,6 +151,7 @@ class Dispatcher : public content::RenderThreadObserver, + // variables. + void WillEvaluateServiceWorkerOnWorkerThread( + blink::WebServiceWorkerContextProxy* context_proxy, ++ v8::Isolate* const isolate, + v8::Local<v8::Context> v8_context, + int64_t service_worker_version_id, + const GURL& service_worker_scope, +diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc +index c89ea22fcd36a9fef2ce8a83ffc46d3358630e90..6c14424384832b5ed193a08c46a0addb27e54244 100644 +--- a/extensions/renderer/extension_frame_helper.cc ++++ b/extensions/renderer/extension_frame_helper.cc +@@ -439,6 +439,7 @@ void ExtensionFrameHelper::DidCreateScriptContext( + } + + void ExtensionFrameHelper::WillReleaseScriptContext( ++ v8::Isolate* const isolate, + v8::Local<v8::Context> context, + int32_t world_id) { + extension_dispatcher_->WillReleaseScriptContext( +diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h +index e16f370211ba014f778e7b9021b83988a5d27661..a79b20fe95050d6e92615711988384deea3fa1e0 100644 +--- a/extensions/renderer/extension_frame_helper.h ++++ b/extensions/renderer/extension_frame_helper.h +@@ -188,7 +188,8 @@ class ExtensionFrameHelper + blink::WebDocumentLoader* document_loader) override; + void DidCreateScriptContext(v8::Local<v8::Context>, + int32_t world_id) override; +- void WillReleaseScriptContext(v8::Local<v8::Context>, ++ void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context>, + int32_t world_id) override; + void OnDestruct() override; + void DidClearWindowObject() override; +diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h +index f96781a047056876b030581b539be0507acc3a1c..cd9be80be2500a001b1895c81ee597dd16fd295b 100644 +--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h ++++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h +@@ -120,7 +120,8 @@ class WebServiceWorkerContextClient { + // + // |v8_context| is the V8 context of the worker and is used to support + // service workers in Chrome extensions. +- virtual void WillEvaluateScript(v8::Local<v8::Context> v8_context) {} ++ virtual void WillEvaluateScript(v8::Isolate* const isolate, ++ v8::Local<v8::Context> v8_context) {} + + // Called when initial script evaluation finished for the main script. + // |success| is true if the evaluation completed with no uncaught exception. +diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h +index 4520c9edccf63bdb9e35bf3a99a8ddb39170da24..dd2c5bd50075c345262b05952ecf3f2aa300b6ff 100644 +--- a/third_party/blink/public/web/web_local_frame_client.h ++++ b/third_party/blink/public/web/web_local_frame_client.h +@@ -671,7 +671,8 @@ class BLINK_EXPORT WebLocalFrameClient { + int32_t world_id) {} + + // WebKit is about to release its reference to a v8 context for a frame. +- virtual void WillReleaseScriptContext(v8::Local<v8::Context>, ++ virtual void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context>, + int32_t world_id) {} + + // Geometry notifications ---------------------------------------------- +diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc +index 898d7caac98727210ac5780b576526a71ec5a5aa..3fdd5b3c41fd8d5dc920bed710dc10741e7e7423 100644 +--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc ++++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc +@@ -109,11 +109,12 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status, + + ScriptState::Scope scope(script_state_); + v8::Local<v8::Context> context = script_state_->GetContext(); ++ CHECK_EQ(GetIsolate(), script_state_->GetIsolate()); + // The embedder could run arbitrary code in response to the + // willReleaseScriptContext callback, so all disposing should happen after + // it returns. +- GetFrame()->Client()->WillReleaseScriptContext(context, world_->GetWorldId()); +- CHECK_EQ(GetIsolate(), script_state_->GetIsolate()); ++ GetFrame()->Client()->WillReleaseScriptContext( ++ GetIsolate(), context, world_->GetWorldId()); + MainThreadDebugger::Instance(GetIsolate()) + ->ContextWillBeDestroyed(script_state_); + if (next_status == Lifecycle::kV8MemoryIsForciblyPurged || +diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h +index 8d73ddb12013ce195026b9f63050cf33f0bfb0fd..078f0e67e8de6a05178e8e2410f61784fe656dee 100644 +--- a/third_party/blink/renderer/core/frame/local_frame_client.h ++++ b/third_party/blink/renderer/core/frame/local_frame_client.h +@@ -303,7 +303,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient { + int32_t world_id) = 0; + virtual void DidInstallConditionalFeatures(v8::Local<v8::Context>, + int32_t world_id) = 0; +- virtual void WillReleaseScriptContext(v8::Local<v8::Context>, ++ virtual void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context>, + int32_t world_id) = 0; + virtual bool AllowScriptExtensions() = 0; + +diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc +index 11475d1a22054a884f2f1e7e5c933e9ae8d3379f..8d260dead59d366148983a1739b5252fa59b862a 100644 +--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc ++++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc +@@ -308,10 +308,11 @@ void LocalFrameClientImpl::DidInstallConditionalFeatures( + } + + void LocalFrameClientImpl::WillReleaseScriptContext( ++ v8::Isolate* const isolate, + v8::Local<v8::Context> context, + int32_t world_id) { + if (web_frame_->Client()) { +- web_frame_->Client()->WillReleaseScriptContext(context, world_id); ++ web_frame_->Client()->WillReleaseScriptContext(isolate, context, world_id); + } + } + +diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h +index 16066fe34ee0335a0dabe00b6890e5844349c0b5..cc84479f65bdbe56cb4b38bfcef0d752bbe68d35 100644 +--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h ++++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h +@@ -83,7 +83,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient { + int32_t world_id) override; + void DidInstallConditionalFeatures(v8::Local<v8::Context>, + int32_t world_id) override; +- void WillReleaseScriptContext(v8::Local<v8::Context>, ++ void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context>, + int32_t world_id) override; + + // Returns true if we should allow register V8 extensions to be added. +diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h +index 80ee0065d1b16520389b6809402438f087430fa3..3991bc8caee23bb4129eedf7213a770d19439290 100644 +--- a/third_party/blink/renderer/core/loader/empty_clients.h ++++ b/third_party/blink/renderer/core/loader/empty_clients.h +@@ -428,7 +428,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient { + int32_t world_id) override {} + void DidInstallConditionalFeatures(v8::Local<v8::Context>, + int32_t world_id) override {} +- void WillReleaseScriptContext(v8::Local<v8::Context>, ++ void WillReleaseScriptContext(v8::Isolate* const isolate, ++ v8::Local<v8::Context>, + int32_t world_id) override {} + bool AllowScriptExtensions() override { return false; } + +diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +index 17860c80651c526e03fd06e4b644c3332b241be7..741a8587e95789038168eb500d3995724e11b47d 100644 +--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc ++++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +@@ -181,6 +181,7 @@ void ServiceWorkerGlobalScopeProxy::WillEvaluateScript() { + ScriptState::Scope scope( + WorkerGlobalScope()->ScriptController()->GetScriptState()); + Client().WillEvaluateScript( ++ WorkerGlobalScope()->ScriptController()->GetScriptState()->GetIsolate(), + WorkerGlobalScope()->ScriptController()->GetContext()); + top_level_script_evaluation_start_time_ = base::TimeTicks::Now(); + } diff --git a/patches/chromium/chore_grandfather_in_electron_views_and_delegates.patch b/patches/chromium/chore_grandfather_in_electron_views_and_delegates.patch index 34278a2fe5b3d..992ceed10ace0 100644 --- a/patches/chromium/chore_grandfather_in_electron_views_and_delegates.patch +++ b/patches/chromium/chore_grandfather_in_electron_views_and_delegates.patch @@ -10,10 +10,10 @@ Subject: chore: "grandfather in" Electron Views and Delegates 6448510: Lock further access to View::set_owned_by_client(). | https://chromium-review.googlesource.com/c/chromium/src/+/6448510 diff --git a/ui/views/view.h b/ui/views/view.h -index 08ec59edf033052233a105ab13cf00ada8bd4e38..b80d3ab4eb24487de6a8a27d67d23d275513b80e 100644 +index 5d89a7ce81b2df250c02601a45eaec93e3cc171d..709ae884a2d62c6c4df286ae897ef6a4148c1ddd 100644 --- a/ui/views/view.h +++ b/ui/views/view.h -@@ -80,6 +80,19 @@ class ArcNotificationContentView; +@@ -78,6 +78,19 @@ class ArcNotificationContentView; class WideFrameView; } // namespace ash @@ -33,7 +33,7 @@ index 08ec59edf033052233a105ab13cf00ada8bd4e38..b80d3ab4eb24487de6a8a27d67d23d27 namespace exo { class ShellSurfaceBase; } -@@ -324,6 +337,14 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, +@@ -325,6 +338,14 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, public: class OwnedByClientPassKey { private: @@ -49,7 +49,7 @@ index 08ec59edf033052233a105ab13cf00ada8bd4e38..b80d3ab4eb24487de6a8a27d67d23d27 // These existing cases are "grandfathered in", but there shouldn't be more. // See comments atop class. diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h -index 1b23449ceb8e2c257cd40c375154a5fa93d1a26e..3aca30535eb99132a664936bcb19e58e075f4095 100644 +index 7695f926b19cc81dfce9995a4ebac9dd50782ec0..c73616912049615c269be47ef733a6b15546c8c6 100644 --- a/ui/views/widget/widget_delegate.h +++ b/ui/views/widget/widget_delegate.h @@ -168,6 +168,12 @@ namespace crostini { @@ -65,7 +65,7 @@ index 1b23449ceb8e2c257cd40c375154a5fa93d1a26e..3aca30535eb99132a664936bcb19e58e namespace exo { class ShellSurfaceBase; } -@@ -371,6 +377,7 @@ class VIEWS_EXPORT WidgetDelegate { +@@ -372,6 +378,7 @@ class VIEWS_EXPORT WidgetDelegate { class OwnedByWidgetPassKey { private: @@ -81,7 +81,7 @@ index 1b23449ceb8e2c257cd40c375154a5fa93d1a26e..3aca30535eb99132a664936bcb19e58e // DO NOT ADD TO THIS LIST! // These existing cases are "grandfathered in", but there shouldn't be more. // See comments atop `RegisterDeleteDelegateCallback()`. -@@ -922,6 +930,7 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View { +@@ -921,6 +929,7 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View { View* GetContentsView() override; private: diff --git a/patches/chromium/chore_introduce_blocking_api_for_electron.patch b/patches/chromium/chore_introduce_blocking_api_for_electron.patch index 66a7b369fe02c..b363b3985a9d9 100644 --- a/patches/chromium/chore_introduce_blocking_api_for_electron.patch +++ b/patches/chromium/chore_introduce_blocking_api_for_electron.patch @@ -7,7 +7,7 @@ This patch comes after Chromium removed the ScopedAllowIO API in favor of explicitly adding ScopedAllowBlocking calls as friends. diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h -index 5625973d8cb18de3c77fbf001e02fdf2827f60fb..5d50a77051a9d2d906ec547796469d980eb42a35 100644 +index 04f3b585ece1ab90d494dbd15874d793f2429771..c659070d53a1bc20f364fc57e79b8c5038691b4f 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h @@ -133,6 +133,7 @@ class KeyStorageLinux; @@ -28,7 +28,7 @@ index 5625973d8cb18de3c77fbf001e02fdf2827f60fb..5d50a77051a9d2d906ec547796469d98 namespace enterprise_connectors { class LinuxKeyRotationCommand; } // namespace enterprise_connectors -@@ -574,6 +578,7 @@ class BASE_EXPORT ScopedAllowBlocking { +@@ -576,6 +580,7 @@ class BASE_EXPORT ScopedAllowBlocking { friend class ::DesktopNotificationBalloon; friend class ::FirefoxProfileLock; friend class ::GaiaConfig; @@ -36,7 +36,7 @@ index 5625973d8cb18de3c77fbf001e02fdf2827f60fb..5d50a77051a9d2d906ec547796469d98 friend class ::ProfileImpl; friend class ::ScopedAllowBlockingForProfile; friend class ::StartupTabProviderImpl; -@@ -615,6 +620,7 @@ class BASE_EXPORT ScopedAllowBlocking { +@@ -618,6 +623,7 @@ class BASE_EXPORT ScopedAllowBlocking { friend class cronet::CronetPrefsManager; friend class crypto::ScopedAllowBlockingForNSS; // http://crbug.com/59847 friend class drive::FakeDriveService; diff --git a/patches/chromium/chore_modify_chromium_handling_of_mouse_events.patch b/patches/chromium/chore_modify_chromium_handling_of_mouse_events.patch index 21cefe2aee268..043de11892396 100644 --- a/patches/chromium/chore_modify_chromium_handling_of_mouse_events.patch +++ b/patches/chromium/chore_modify_chromium_handling_of_mouse_events.patch @@ -34,10 +34,10 @@ index 2dc44d4787d5198cff7be2cf98ad5acf2d3a9a0b..27a0335aac2bd4239616cf71f5d015c9 class ScrollEvent; diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -index 315356b513e9f2c0ce7658aefeb69d0ac327c4de..54a94e1348fa196eaee8314076c47286c9ab0bcc 100644 +index 3b2fbefaeec2bac725d46bcfeea488122c873d76..fd23b8036c7f2d8bf3ed1bba126f8ee813f688a8 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -@@ -1367,6 +1367,10 @@ HBRUSH DesktopWindowTreeHostWin::GetBackgroundPaintBrush() { +@@ -1375,6 +1375,10 @@ HBRUSH DesktopWindowTreeHostWin::GetBackgroundPaintBrush() { return background_paint_brush_; } @@ -49,7 +49,7 @@ index 315356b513e9f2c0ce7658aefeb69d0ac327c4de..54a94e1348fa196eaee8314076c47286 DesktopWindowTreeHostWin::GetSingletonDesktopNativeCursorManager() { return new DesktopNativeCursorManagerWin(); diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h -index dcda976f4c3cc0ba6bcf015d5bf7435df009ae30..13cfa18bf406f244ec361a1230ccce440ad9785a 100644 +index b65ced55f997d5064b9d9338190567f8c264fce8..e8acd2828ed05deefa335ce2bb461f0c3be8d7b7 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h @@ -273,6 +273,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin @@ -61,10 +61,10 @@ index dcda976f4c3cc0ba6bcf015d5bf7435df009ae30..13cfa18bf406f244ec361a1230ccce44 Widget* GetWidget(); const Widget* GetWidget() const; diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index 3637176c05a7074cb9042b74f7c9ea2e29af5ee5..3ed583cf09dec0ae83c3c9449e6ef7e1fa92aa8d 100644 +index a71630354ee345224371980675d09dc16fdcff16..a834cc49a3a02acdcd127f3f0fb084fa806435e5 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -3239,15 +3239,19 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, +@@ -3250,15 +3250,19 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, } // We must let Windows handle the caption buttons if it's drawing them, or // they won't work. @@ -86,7 +86,7 @@ index 3637176c05a7074cb9042b74f7c9ea2e29af5ee5..3ed583cf09dec0ae83c3c9449e6ef7e1 return 0; } } -@@ -3270,6 +3274,7 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, +@@ -3281,6 +3285,7 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, // handle alt-space, or in the frame itself. is_right_mouse_pressed_on_caption_ = false; ReleaseCapture(); @@ -94,7 +94,7 @@ index 3637176c05a7074cb9042b74f7c9ea2e29af5ee5..3ed583cf09dec0ae83c3c9449e6ef7e1 // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu() // expect screen coordinates. POINT screen_point = CR_POINT_INITIALIZER_FROM_LPARAM(l_param); -@@ -3277,7 +3282,17 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, +@@ -3288,7 +3293,17 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, w_param = static_cast<WPARAM>(SendMessage( hwnd(), WM_NCHITTEST, 0, MAKELPARAM(screen_point.x, screen_point.y))); if (w_param == HTCAPTION || w_param == HTSYSMENU) { @@ -114,10 +114,10 @@ index 3637176c05a7074cb9042b74f7c9ea2e29af5ee5..3ed583cf09dec0ae83c3c9449e6ef7e1 } } else if (message == WM_NCLBUTTONDOWN && diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h -index 2aa7ca1f713da54d12c7ac78103a260a4744d040..7449d7642022145fc1be76b299fa1db2d724122b 100644 +index 20cfb50af8d5131ca87d1fafce6f2ab43771f67b..eee40a56bebe52187a35daacfc788bf2f1f27e29 100644 --- a/ui/views/win/hwnd_message_handler_delegate.h +++ b/ui/views/win/hwnd_message_handler_delegate.h -@@ -256,6 +256,10 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate { +@@ -260,6 +260,10 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate { // if the default should be used. virtual HBRUSH GetBackgroundPaintBrush() = 0; diff --git a/patches/chromium/chore_partial_revert_of.patch b/patches/chromium/chore_partial_revert_of.patch index 14ba7ac150480..f24d4d8ab86bb 100644 --- a/patches/chromium/chore_partial_revert_of.patch +++ b/patches/chromium/chore_partial_revert_of.patch @@ -14,10 +14,10 @@ track down the source of this problem & figure out if we can fix it by changing something in Electron. diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index 3a9264493f90fb8e82e34e13328d74c00d156966..dd274924f1c26efbc9fc3683f69647a0933a9855 100644 +index 6b58df7202c19bda334f711d91af09839f461911..93c078a29e7142e54a20470f7c18f8aa8abf63bf 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -5275,7 +5275,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -5285,7 +5285,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( : IsGuest(); // While some guest types do not have a guest SiteInstance, the ones that // don't all override WebContents creation above. diff --git a/patches/chromium/chore_patch_out_partition_attribute_dcheck_for_webviews.patch b/patches/chromium/chore_patch_out_partition_attribute_dcheck_for_webviews.patch index 67a7197a5356c..1938a00f54184 100644 --- a/patches/chromium/chore_patch_out_partition_attribute_dcheck_for_webviews.patch +++ b/patches/chromium/chore_patch_out_partition_attribute_dcheck_for_webviews.patch @@ -14,10 +14,10 @@ This change patches it out to prevent the DCHECK. It can be removed once/if we see a better solution to the problem. diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc -index 8221d7b96395b06ee177be302dd476c83f569eaf..4c4500421f9cd164ab49b85457e6e37e0b4a703c 100644 +index ff8cd27f46f49ff3b445becf7cb0c628af147899..8702ca4da61aa296c957a9c50b26e921c5e5b19f 100644 --- a/content/browser/site_instance_impl.cc +++ b/content/browser/site_instance_impl.cc -@@ -226,7 +226,7 @@ scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForGuest( +@@ -227,7 +227,7 @@ scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForGuest( BrowserContext* browser_context, const StoragePartitionConfig& partition_config) { DCHECK(browser_context); diff --git a/patches/chromium/chore_patch_out_profile_methods.patch b/patches/chromium/chore_patch_out_profile_methods.patch index abce6f76a96da..dd7a2e7aa1d61 100644 --- a/patches/chromium/chore_patch_out_profile_methods.patch +++ b/patches/chromium/chore_patch_out_profile_methods.patch @@ -7,7 +7,7 @@ Electron does not support Profiles, so we need to patch it out of any code that we use. diff --git a/chrome/browser/pdf/chrome_pdf_stream_delegate.cc b/chrome/browser/pdf/chrome_pdf_stream_delegate.cc -index c390a83277f564f1a67a7dcffa36b9d77a35bc0b..b13273a4b194ad5e8ca2d1639ebca831f9607b1e 100644 +index bd19708922b3d9224cc3a05f515c455ce4fb1e69..7198d9f9b22c8725c7ecdf6931ff36859ffaf506 100644 --- a/chrome/browser/pdf/chrome_pdf_stream_delegate.cc +++ b/chrome/browser/pdf/chrome_pdf_stream_delegate.cc @@ -45,6 +45,7 @@ namespace { @@ -27,12 +27,12 @@ index c390a83277f564f1a67a7dcffa36b9d77a35bc0b..b13273a4b194ad5e8ca2d1639ebca831 // When the enterprise policy is not set, use finch/feature flag choice. return base::FeatureList::IsEnabled( diff --git a/chrome/browser/pdf/pdf_extension_util.cc b/chrome/browser/pdf/pdf_extension_util.cc -index 1362d0c69043ac5d1f7e72cf7ac72c272193844c..08efd98ca16555f6a7bbfb4ae3165130e843c981 100644 +index 328abdd79d287225d0e6ec6becc455e169d6e5d0..10e5e702a43dbb70e13d00b48000e0b4cc974e7a 100644 --- a/chrome/browser/pdf/pdf_extension_util.cc +++ b/chrome/browser/pdf/pdf_extension_util.cc -@@ -271,10 +271,13 @@ bool IsPrintingEnabled(content::BrowserContext* context) { +@@ -248,10 +248,13 @@ bool IsPrintingEnabled(content::BrowserContext* context) { - #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(ENABLE_PDF_INK2) + #if BUILDFLAG(ENABLE_PDF_INK2) bool IsPdfAnnotationsEnabledByPolicy(content::BrowserContext* context) { +# if 0 PrefService* prefs = @@ -42,7 +42,7 @@ index 1362d0c69043ac5d1f7e72cf7ac72c272193844c..08efd98ca16555f6a7bbfb4ae3165130 +#endif + return true; } - #endif // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(ENABLE_PDF_INK2) + #endif // BUILDFLAG(ENABLE_PDF_INK2) diff --git a/chrome/browser/profiles/profile_selections.cc b/chrome/browser/profiles/profile_selections.cc index bc0bad82ebcdceadc505e912ff27202b452fefab..6b77c57fccc4619a1df3b4ed661d2bdd60960228 100644 @@ -84,7 +84,7 @@ index bc0bad82ebcdceadc505e912ff27202b452fefab..6b77c57fccc4619a1df3b4ed661d2bdd ProfileSelection ProfileSelections::GetProfileSelection( diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc -index 4c52386f9ddf13f1453903cda3954b6c596028f2..8fbb2025d157e58c90c701f9e3478f6c99b88aa1 100644 +index f8a36ced14288698849cd5730309e29d47d3d1d4..97b8fc0f38650e816bcae00e074543766f71e0d0 100644 --- a/chrome/browser/spellchecker/spellcheck_service.cc +++ b/chrome/browser/spellchecker/spellcheck_service.cc @@ -21,8 +21,10 @@ diff --git a/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch b/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch index ea88ca2f2c41b..01837337a15cf 100644 --- a/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch +++ b/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch @@ -7,10 +7,10 @@ Pending upstream patch, this gives us fuller access to the window.open params so that we will be able to decide whether to cancel it or not. diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc -index 7a9effeec99682ef063ebe71f209e6ed9fc4cad4..71ef44be47a8665ee36449a38333ddf9cff33ad4 100644 +index 047f1258f951f763df2ca0ba355b19d19337826b..9fc7114312212fbe38ddec740b4aebbcd72cb0f8 100644 --- a/chrome/browser/media/offscreen_tab.cc +++ b/chrome/browser/media/offscreen_tab.cc -@@ -287,8 +287,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden( +@@ -285,8 +285,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -35,7 +35,7 @@ index 231e3595f218aeebe28d0b13ce6182e7a4d6f4e1..609bd205d1cd0404cab3471765bef8b0 content::RenderFrameHost* requesting_frame, const blink::mojom::FullscreenOptions& options) final; diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc -index a17c406b59530a8f57f6cb48905a697dd208a41f..0e22e90c1d570eb4c86ac1f24c5a6e9159be8ea1 100644 +index 7f99bf8c0c79de2cb8a812a7bfe8b4255697444a..d39aee929900cca756a6293b782a44228725f6fc 100644 --- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc +++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc @@ -80,8 +80,7 @@ class ChromeKeyboardContentsDelegate : public content::WebContentsDelegate, @@ -49,7 +49,7 @@ index a17c406b59530a8f57f6cb48905a697dd208a41f..0e22e90c1d570eb4c86ac1f24c5a6e91 } diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc b/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc -index 08c84ca91f7e477e4e8d6370513d90d2fb9801f1..41e04444274f40fdedbf8d97bfd149f2ac682e53 100644 +index e4e42249c476ccae58f0ba42e7dbae299f1e36bd..670c30ed4b7f1a07eb4b8abaa95e5a8a9d94bd8d 100644 --- a/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc +++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl.cc @@ -121,10 +121,9 @@ bool AshWebViewImpl::IsWebContentsCreationOverridden( @@ -66,7 +66,7 @@ index 08c84ca91f7e477e4e8d6370513d90d2fb9801f1..41e04444274f40fdedbf8d97bfd149f2 /*from_user_gesture=*/true); return true; diff --git a/chrome/browser/ui/ash/web_view/ash_web_view_impl.h b/chrome/browser/ui/ash/web_view/ash_web_view_impl.h -index b6582b4013d9682d32bd524b4053b443a4df00f8..afcbce72e0f247b4d5a637b27c9f25d913cfa14b 100644 +index 39fa45f0a0f9076bd7ac0be6f455dd540a276512..3d0381d463eed73470b28085830f2a23751659a7 100644 --- a/chrome/browser/ui/ash/web_view/ash_web_view_impl.h +++ b/chrome/browser/ui/ash/web_view/ash_web_view_impl.h @@ -60,8 +60,7 @@ class AshWebViewImpl : public ash::AshWebView, @@ -80,20 +80,20 @@ index b6582b4013d9682d32bd524b4053b443a4df00f8..afcbce72e0f247b4d5a637b27c9f25d9 content::WebContents* source, const content::OpenURLParams& params, diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc -index 5cf1070e3f407fdb1748b2171b3974933d4610c1..96960883dd68c511d66414f66cf989d28bd4eb36 100644 +index b3eb633c290c5385a58b66a97b1a57b3fe080ab2..faf64b12913aac5cef8a614a0baabb16771dbb3c 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc -@@ -2390,8 +2390,7 @@ bool Browser::IsWebContentsCreationOverridden( - content::SiteInstance* source_site_instance, +@@ -2373,7 +2373,8 @@ bool Browser::IsWebContentsCreationOverridden( content::mojom::WindowContainerType window_container_type, const GURL& opener_url, -- const std::string& frame_name, + const std::string& frame_name, - const GURL& target_url) { ++ const GURL& target_url, + const content::mojom::CreateNewWindowParams& params) { - if (IsActorOperatingOnWebContents( - profile(), content::WebContents::FromRenderFrameHost(opener))) { - // If an ExecutionEngine is acting on the opener, prevent it from creating -@@ -2403,7 +2402,7 @@ bool Browser::IsWebContentsCreationOverridden( + if (HasActorTask(profile(), opener)) { + // If an ExecutionEngine is acting on the opener, prevent it from creating a + // new WebContents. We'll instead force the navigation to happen in the same +@@ -2386,7 +2387,7 @@ bool Browser::IsWebContentsCreationOverridden( return (window_container_type == content::mojom::WindowContainerType::BACKGROUND && ShouldCreateBackgroundContents(source_site_instance, opener_url, @@ -103,10 +103,10 @@ index 5cf1070e3f407fdb1748b2171b3974933d4610c1..96960883dd68c511d66414f66cf989d2 WebContents* Browser::CreateCustomWebContents( diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h -index e80708919d3122d92f6fe63e5c111c999860762e..fb19037baa4cb95f8d581f4ccf984f0b19b6ca70 100644 +index 0c296e8bf3b055b8e6f07adcc9b088febd489f14..533041e1948726eef266625e541f65735dc81e8f 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h -@@ -951,8 +951,7 @@ class Browser : public TabStripModelObserver, +@@ -942,8 +942,7 @@ class Browser : public TabStripModelObserver, content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -145,10 +145,10 @@ index 3fc06be01f20e8cd314d95d73a3f58c2f0742fe9..c07910ae59a185442f37ea6e7b96fdf3 // The profile used for the presentation. raw_ptr<Profile, DanglingUntriaged> otr_profile_; diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc -index 08b9f7ad8544011ee1cbb9bc9857ea06e2fa2c0b..69f666bdc05662bc40e133022b5364cbbbbbdb39 100644 +index 3bbd4e568ba99245622a96f0801d2b6cd203025f..1e0b7d16b33daed980961dd49c667a3b254c186f 100644 --- a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc +++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc -@@ -103,8 +103,7 @@ class HatsNextWebDialog::HatsWebView : public views::WebView { +@@ -104,8 +104,7 @@ class HatsNextWebDialog::HatsWebView : public views::WebView { content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -159,10 +159,10 @@ index 08b9f7ad8544011ee1cbb9bc9857ea06e2fa2c0b..69f666bdc05662bc40e133022b5364cb } content::WebContents* CreateCustomWebContents( diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc -index c07249241e5265030c1feada568fbd54f4e18efa..f0946d19ce07723be8a3736f523db1951cccbb95 100644 +index 36baad877619ad506e07ff385a250c60e9c3f94a..6b5f5352be13e583f996cc131fbdd36f57f96041 100644 --- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc -@@ -202,14 +202,13 @@ bool WebContentsDelegateAndroid::IsWebContentsCreationOverridden( +@@ -216,15 +216,14 @@ bool WebContentsDelegateAndroid::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -171,8 +171,9 @@ index c07249241e5265030c1feada568fbd54f4e18efa..f0946d19ce07723be8a3736f523db195 + const content::mojom::CreateNewWindowParams& params) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); - if (obj.is_null()) + if (obj.is_null()) { return false; + } ScopedJavaLocalRef<jobject> java_gurl = - url::GURLAndroid::FromNativeGURL(env, target_url); + url::GURLAndroid::FromNativeGURL(env, params.target_url.spec()); @@ -180,10 +181,10 @@ index c07249241e5265030c1feada568fbd54f4e18efa..f0946d19ce07723be8a3736f523db195 java_gurl); } diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h -index 13afd2de87888e927d8baf77f4c3de65179c52f5..06de4a27e625745947d2c119fa8f5eb555d99a1d 100644 +index 1676a7d1e1734d196aeb3d2e27997de1743f034c..9be7c579c08af7b9b0de947a9d9af39b4d510b3c 100644 --- a/components/embedder_support/android/delegate/web_contents_delegate_android.h +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h -@@ -84,8 +84,7 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate { +@@ -78,8 +78,7 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate { content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -222,10 +223,10 @@ index b969f1d97b7e3396119b579cfbe61e19ff7d2dd4..b8d6169652da28266a514938b45b39c5 content::WebContents* AddNewContents( content::WebContents* source, diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index 95ea7eb743ae3e4de52741be7f2969bbf86d8a29..c9472325e55052ead090c55704b590bb6722c429 100644 +index b50aa1890036c762ec0df75d133f7b9fb29df4cd..f2f80c86e7910cf513aa916a80c51502bb186f58 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -5238,8 +5238,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -5250,8 +5250,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( if (delegate_ && delegate_->IsWebContentsCreationOverridden( opener, source_site_instance, params.window_container_type, @@ -236,10 +237,10 @@ index 95ea7eb743ae3e4de52741be7f2969bbf86d8a29..c9472325e55052ead090c55704b590bb static_cast<WebContentsImpl*>(delegate_->CreateCustomWebContents( opener, source_site_instance, is_new_browsing_instance, diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc -index 33be50ce93dd998df5244f9ade391943f06978ad..3bb9baf76d331351d23d59fc2b9eb82d42b36b11 100644 +index 4f79d90a7d30a6ce2a3720ef94c1ade264d20e16..923d8834e231b91e7a692e0178ece122b8d70536 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc -@@ -160,8 +160,7 @@ bool WebContentsDelegate::IsWebContentsCreationOverridden( +@@ -161,8 +161,7 @@ bool WebContentsDelegate::IsWebContentsCreationOverridden( SiteInstance* source_site_instance, mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -250,10 +251,10 @@ index 33be50ce93dd998df5244f9ade391943f06978ad..3bb9baf76d331351d23d59fc2b9eb82d } diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h -index 6c4c6265c26f5304b8f77d7fc5a4fad5dffc831d..d0842904102fee982bc8502478a0a9067bb77904 100644 +index 1dab9cf23213d497bb6354d3b909911b014675ba..30d7c81394df4e0f382d9a67fcd414b2d07903db 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h -@@ -364,8 +364,7 @@ class CONTENT_EXPORT WebContentsDelegate { +@@ -377,8 +377,7 @@ class CONTENT_EXPORT WebContentsDelegate { SiteInstance* source_site_instance, mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -264,7 +265,7 @@ index 6c4c6265c26f5304b8f77d7fc5a4fad5dffc831d..d0842904102fee982bc8502478a0a906 // Allow delegate to creates a custom WebContents when // WebContents::CreateNewWindow() is called. This function is only called diff --git a/extensions/browser/guest_view/app_view/app_view_guest.cc b/extensions/browser/guest_view/app_view/app_view_guest.cc -index 3b1fe9ef59fbcd3684348fb518ce67210a639dc1..dc38462f8e29066bec4970cc820b8d6077106b85 100644 +index af80323215e2cb6ff7bdb802f8da4bdbe0067f71..187816751bde435e9c622921c457873d4b3172cd 100644 --- a/extensions/browser/guest_view/app_view/app_view_guest.cc +++ b/extensions/browser/guest_view/app_view/app_view_guest.cc @@ -153,8 +153,7 @@ bool AppViewGuest::IsWebContentsCreationOverridden( @@ -300,7 +301,7 @@ index 7695578f626f2a0c7fefae2bc1d5c35e5ac154f2..78958bff12ce41ae5ad77f43279a4b35 content::RenderFrameHost* opener, content::SiteInstance* source_site_instance, diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc -index 5bd9d59a961a03f3cd3a806bc1af58c3eaee2b58..40d7ae8d6248163524a8c1350b625e107a8ae64a 100644 +index 0ab40dfd23d1071212c4d30d01fa8e7755458d4a..f032127a94c52beb3f509d6ea84c7e55f21084e2 100644 --- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc +++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc @@ -263,8 +263,7 @@ bool ExtensionOptionsGuest::IsWebContentsCreationOverridden( @@ -328,7 +329,7 @@ index 56d86e3d1179df2d5f34eb6216989aef2687f49f..236f3ccf8354b156737e03929ee538f9 content::RenderFrameHost* opener, content::SiteInstance* source_site_instance, diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc -index 3e689ad6bdb51ccd7419eb87e4ba2cdbf2f1a8e9..c219b456721a43d9dfdf69612909a2d4f82cd33d 100644 +index 23705fa50cf79865b68d8352f6ec72444ca5233e..efa5e78ed92464a6d47319f7b2087555d683bd8c 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc @@ -424,8 +424,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden( @@ -356,10 +357,10 @@ index 7eeffdfbda9611806c6f260f0c68f6d84689cb7e..5d8f6d132068d7fabaa52bc61354c71a content::RenderFrameHost* opener, content::SiteInstance* source_site_instance, diff --git a/fuchsia_web/webengine/browser/frame_impl.cc b/fuchsia_web/webengine/browser/frame_impl.cc -index 570cfeb6c74f04d4748648b86661ccf603c71452..da8b64d70e5b26431a576cc52316210fce36f99a 100644 +index 44fdb7377fc4d09137d0718de0f960b0d190c99f..46bde9f83510116f8723d400d5947f9cc6ba3ab5 100644 --- a/fuchsia_web/webengine/browser/frame_impl.cc +++ b/fuchsia_web/webengine/browser/frame_impl.cc -@@ -582,8 +582,7 @@ bool FrameImpl::IsWebContentsCreationOverridden( +@@ -585,8 +585,7 @@ bool FrameImpl::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -384,7 +385,7 @@ index 756d4192271d6a65cfe8e1511737c565b543cb1f..5688f6f745056565c3c01947f741c4d1 int opener_render_process_id, int opener_render_frame_id, diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc -index 1d95f5b521d7ab586fcecda6d6f822b432480367..b534327a8bd5b2c31522339b30caf123734c5cc3 100644 +index 3af22f9e041996cedebc1d9ffd402e9fcccceaea..e488b8d4d8f81ad2a0b8a6a1cc13fb886fd26e62 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc @@ -208,8 +208,7 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate { @@ -398,10 +399,10 @@ index 1d95f5b521d7ab586fcecda6d6f822b432480367..b534327a8bd5b2c31522339b30caf123 ->options() ->block_new_web_contents(); diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc -index 42e0654da5659ba647529c4b0b97ec5df61d59a1..406e2ca73c182005014b56824e89ddfb25fd28f5 100644 +index f56882565de72fa9ab660b4a8d86f08c7392becd..439586a03288822bab8f5f21d0c38b678ed52fb6 100644 --- a/ui/views/controls/webview/web_dialog_view.cc +++ b/ui/views/controls/webview/web_dialog_view.cc -@@ -490,8 +490,7 @@ bool WebDialogView::IsWebContentsCreationOverridden( +@@ -489,8 +489,7 @@ bool WebDialogView::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -412,10 +413,10 @@ index 42e0654da5659ba647529c4b0b97ec5df61d59a1..406e2ca73c182005014b56824e89ddfb return delegate_->HandleShouldOverrideWebContentsCreation(); } diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h -index 0fa7e807d22f6f04b84f2d949fbdf892b94996bf..b0490ae36c9999a766bbf346e35807740f4f9af6 100644 +index 720611a58300a0252d5dd66e1e7c98282dc82646..eb0abf978651266fe7e4d6a8e9af30024fceb7d1 100644 --- a/ui/views/controls/webview/web_dialog_view.h +++ b/ui/views/controls/webview/web_dialog_view.h -@@ -168,8 +168,7 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView, +@@ -167,8 +167,7 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView, content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, diff --git a/patches/chromium/chore_remove_check_is_test_on_script_injection_tracker.patch b/patches/chromium/chore_remove_check_is_test_on_script_injection_tracker.patch index 1fe8521334a1b..b42a7b6a64853 100644 --- a/patches/chromium/chore_remove_check_is_test_on_script_injection_tracker.patch +++ b/patches/chromium/chore_remove_check_is_test_on_script_injection_tracker.patch @@ -9,7 +9,7 @@ Electron when a session is non persistent we do not initialize the ExtensionSystem, so this check is not relevant for Electron. diff --git a/extensions/browser/script_injection_tracker.cc b/extensions/browser/script_injection_tracker.cc -index 09e5575f67c0a7484663d0ecbee5963be622cb8f..b206eca9426491921e6cacfad3fb764d474e7945 100644 +index 8331e06da9055fddd647dbe54051584b101286b0..6a9ddc0060dc272cd4511fc96f358005ad0ee043 100644 --- a/extensions/browser/script_injection_tracker.cc +++ b/extensions/browser/script_injection_tracker.cc @@ -177,7 +177,6 @@ std::vector<const UserScript*> GetLoadedDynamicScripts( diff --git a/patches/chromium/chore_remove_reference_to_chrome_browser_themes.patch b/patches/chromium/chore_remove_reference_to_chrome_browser_themes.patch index 870942fa3ee50..9442d50485bba 100644 --- a/patches/chromium/chore_remove_reference_to_chrome_browser_themes.patch +++ b/patches/chromium/chore_remove_reference_to_chrome_browser_themes.patch @@ -11,10 +11,10 @@ not need this dependency. refs https://chromium-review.googlesource.com/c/chromium/src/+/5573603 diff --git a/chrome/browser/ui/color/BUILD.gn b/chrome/browser/ui/color/BUILD.gn -index fffee1ca3d0ab493c616e18ecdc0a4fb6525f974..11816e864deb4244c4a2d87ccd89c0a5f632a024 100644 +index db1a2f393af2b561cb7d13861bc37f81ab3227c8..d371808e1e59e2dbb2da8790a2212cc001caa772 100644 --- a/chrome/browser/ui/color/BUILD.gn +++ b/chrome/browser/ui/color/BUILD.gn -@@ -85,9 +85,6 @@ source_set("mixers") { +@@ -87,9 +87,6 @@ source_set("mixers") { ] } @@ -23,4 +23,4 @@ index fffee1ca3d0ab493c616e18ecdc0a4fb6525f974..11816e864deb4244c4a2d87ccd89c0a5 - } } - if (!is_ios && !is_android) { + if (!is_android) { diff --git a/patches/chromium/chore_restore_some_deprecated_wrapper_utility_in_gin.patch b/patches/chromium/chore_restore_some_deprecated_wrapper_utility_in_gin.patch index dea3bb87ee321..de6c0e66761d8 100644 --- a/patches/chromium/chore_restore_some_deprecated_wrapper_utility_in_gin.patch +++ b/patches/chromium/chore_restore_some_deprecated_wrapper_utility_in_gin.patch @@ -9,10 +9,10 @@ Patch can be removed once cppgc migration is complete https://github.com/electron/electron/issues/47922 diff --git a/gin/function_template.h b/gin/function_template.h -index 84ab9585240a49048774811718f7ebd6f988e485..f062163cdd81def12fae7e507d18a9133dd0804d 100644 +index c80020b2bda2af39b38295dad3c6208cb8294b88..873015289db9709c00c32080e5387d9cdfea1f69 100644 --- a/gin/function_template.h +++ b/gin/function_template.h -@@ -77,6 +77,7 @@ class GIN_EXPORT CallbackHolderBase { +@@ -79,6 +79,7 @@ class GIN_EXPORT CallbackHolderBase { CallbackHolderBase* holder); ~DisposeObserver() override; void OnBeforeDispose(v8::Isolate* isolate) override; @@ -21,7 +21,7 @@ index 84ab9585240a49048774811718f7ebd6f988e485..f062163cdd81def12fae7e507d18a913 private: diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc -index 083d59f78c542f4900e1b210a0935276516b894b..e32658e386853e2142c325a60ec385635256b758 100644 +index 1943413560f23c212d98fa1b368204c6e062bab2..bf0053833c782c9bc0187bb093a7ffd81ca9d754 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -225,6 +225,7 @@ void IsolateHolder::WillCreateMicrotasksRunner() { @@ -91,7 +91,7 @@ index 9670f9f904c6c864e82409617ac4c7698c6fc3ef..d1014af4b63da244820ff865a8e824dd for (auto& observer : dispose_observers_) { observer.OnDisposed(); diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h -index 82048c08a14d05e1f9bd6ad6cc16d16f0905f879..e38b0ca134e71a968805a547c1eccbc0cd6f6dda 100644 +index 9146df7ec5e65401771f452ed44c63369be1d31f..5ae71c795cc98a885090553177f57deccb8bc546 100644 --- a/gin/per_isolate_data.h +++ b/gin/per_isolate_data.h @@ -34,6 +34,10 @@ class GIN_EXPORT PerIsolateData { diff --git a/patches/chromium/command-ismediakey.patch b/patches/chromium/command-ismediakey.patch index c8a7504f742ff..cbf51b64bf9de 100644 --- a/patches/chromium/command-ismediakey.patch +++ b/patches/chromium/command-ismediakey.patch @@ -39,10 +39,10 @@ index e87c180342b967756efeb701c73207fcee8754f1..42e37564e585987d367921568f0f1d2b NOTREACHED(); } diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc -index b6985bd63a34c55154fcfae601add6ce6c451704..fb44cc65b1a15c8b69410a2a2cb925a0326bb438 100644 +index ce768e551dd96678c04035503a481d375f5887bd..0cec5e73e4ae4441262461ba3c8446cdd8dc04a0 100644 --- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc +++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc -@@ -147,7 +147,8 @@ bool GlobalAcceleratorListenerOzone::StartListeningForAccelerator( +@@ -153,7 +153,8 @@ bool GlobalAcceleratorListenerOzone::StartListeningForAccelerator( const bool registered = platform_global_shortcut_listener_->RegisterAccelerator( accelerator.key_code(), accelerator.IsAltDown(), @@ -52,7 +52,7 @@ index b6985bd63a34c55154fcfae601add6ce6c451704..fb44cc65b1a15c8b69410a2a2cb925a0 if (registered) { registered_hot_keys_.insert(accelerator); } -@@ -162,14 +163,15 @@ void GlobalAcceleratorListenerOzone::StopListeningForAccelerator( +@@ -168,14 +169,15 @@ void GlobalAcceleratorListenerOzone::StopListeningForAccelerator( platform_global_shortcut_listener_->UnregisterAccelerator( accelerator.key_code(), accelerator.IsAltDown(), accelerator.IsCtrlDown(), @@ -70,7 +70,7 @@ index b6985bd63a34c55154fcfae601add6ce6c451704..fb44cc65b1a15c8b69410a2a2cb925a0 int modifiers = 0; if (is_alt_down) { modifiers |= ui::EF_ALT_DOWN; -@@ -180,6 +182,9 @@ void GlobalAcceleratorListenerOzone::OnKeyPressed(ui::KeyboardCode key_code, +@@ -186,6 +188,9 @@ void GlobalAcceleratorListenerOzone::OnKeyPressed(ui::KeyboardCode key_code, if (is_shift_down) { modifiers |= ui::EF_SHIFT_DOWN; } diff --git a/patches/chromium/crash_allow_setting_more_options.patch b/patches/chromium/crash_allow_setting_more_options.patch index 78b4b39481f6b..127611ad91a4c 100644 --- a/patches/chromium/crash_allow_setting_more_options.patch +++ b/patches/chromium/crash_allow_setting_more_options.patch @@ -63,10 +63,10 @@ index 7c890b331be4aaaf20c7efe8a4bcc2f6e9012b7a..c573524d05c07ec67d35046bc8548cc1 // Used by WebView to sample crashes without generating the unwanted dumps. If // the returned value is less than 100, crash dumping will be sampled to that diff --git a/components/crash/core/app/crashpad_linux.cc b/components/crash/core/app/crashpad_linux.cc -index 5d9b3bd5386ecbdb74cc470dbe65308c3afa0a61..dc29a4bedc0533e27affb26367cfcc2c3f9544f3 100644 +index d4d3555891b19d61676465c856055fb04e0168bc..3228888f5449df723f4385a0f2c9b456caa472f0 100644 --- a/components/crash/core/app/crashpad_linux.cc +++ b/components/crash/core/app/crashpad_linux.cc -@@ -218,6 +218,7 @@ bool PlatformCrashpadInitialization( +@@ -219,6 +219,7 @@ bool PlatformCrashpadInitialization( // where crash_reporter provides it's own values for lsb-release. annotations["lsb-release"] = base::GetLinuxDistro(); #endif @@ -74,7 +74,7 @@ index 5d9b3bd5386ecbdb74cc470dbe65308c3afa0a61..dc29a4bedc0533e27affb26367cfcc2c std::vector<std::string> arguments; if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) { -@@ -239,6 +240,13 @@ bool PlatformCrashpadInitialization( +@@ -240,6 +241,13 @@ bool PlatformCrashpadInitialization( } #endif @@ -86,10 +86,10 @@ index 5d9b3bd5386ecbdb74cc470dbe65308c3afa0a61..dc29a4bedc0533e27affb26367cfcc2c + } + CHECK(client.StartHandler(handler_path, *database_path, metrics_path, url, - annotations, arguments, false, false)); - } else { + annotations, arguments, false, false, + attachments)); diff --git a/components/crash/core/app/crashpad_mac.mm b/components/crash/core/app/crashpad_mac.mm -index 42fe73aefe44f218d6a5e8cb1550ff48859c4b70..a1235f0c7ad44ae9c9fdc805af5b9dc5669f5aad 100644 +index 3b131e1fc804a55c80b3b2704686270211fcf9fb..f14ab66f240a236bd90ff4240089a0036ce7d460 100644 --- a/components/crash/core/app/crashpad_mac.mm +++ b/components/crash/core/app/crashpad_mac.mm @@ -86,6 +86,8 @@ @@ -101,7 +101,7 @@ index 42fe73aefe44f218d6a5e8cb1550ff48859c4b70..a1235f0c7ad44ae9c9fdc805af5b9dc5 return annotations; } -@@ -156,6 +158,13 @@ bool PlatformCrashpadInitialization( +@@ -159,6 +161,13 @@ bool PlatformCrashpadInitialization( std::vector<std::string> arguments; @@ -116,10 +116,10 @@ index 42fe73aefe44f218d6a5e8cb1550ff48859c4b70..a1235f0c7ad44ae9c9fdc805af5b9dc5 arguments.push_back("--monitor-self"); } diff --git a/components/crash/core/app/crashpad_win.cc b/components/crash/core/app/crashpad_win.cc -index 5b811cbbc51544cbff7c2e99c3a7ced824990002..f2376d74fbd2c8196184035fc0fb24a0a8ebfe0e 100644 +index a7af39181e259b4c793fa9a39cb95e4f86ac47d1..6101018813315074a1e06bea318ecf3f91188415 100644 --- a/components/crash/core/app/crashpad_win.cc +++ b/components/crash/core/app/crashpad_win.cc -@@ -93,6 +93,7 @@ bool PlatformCrashpadInitialization( +@@ -94,6 +94,7 @@ bool PlatformCrashpadInitialization( std::map<std::string, std::string> process_annotations; GetPlatformCrashpadAnnotations(&process_annotations); @@ -127,7 +127,7 @@ index 5b811cbbc51544cbff7c2e99c3a7ced824990002..f2376d74fbd2c8196184035fc0fb24a0 std::string url = crash_reporter_client->GetUploadUrl(); -@@ -133,6 +134,13 @@ bool PlatformCrashpadInitialization( +@@ -134,6 +135,13 @@ bool PlatformCrashpadInitialization( std::vector<std::string> arguments(start_arguments); diff --git a/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch b/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch index 4f84a3819f3e4..b462c65f603cf 100644 --- a/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch +++ b/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch @@ -7,10 +7,10 @@ By default, chromium sets up one v8 snapshot to be used in all v8 contexts. This to have a dedicated browser process v8 snapshot defined by the file `browser_v8_context_snapshot.bin`. diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc -index 46c7c57b5ff40b0e40d66bbeb8ec3f2b7f86cea0..46d144563983dee5a793948d9fd11852fb311088 100644 +index 9240e8485a8dc895eb455b1418fc7559e52a5dd5..e9444e765ac8ac595b799be7feeb6a483c6acf9f 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc -@@ -272,8 +272,13 @@ void AsanProcessInfoCB(const char*, bool*) { +@@ -273,8 +273,13 @@ void AsanProcessInfoCB(const char*, bool*) { } #endif // defined(ADDRESS_SANITIZER) @@ -25,7 +25,7 @@ index 46c7c57b5ff40b0e40d66bbeb8ec3f2b7f86cea0..46d144563983dee5a793948d9fd11852 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) base::FileDescriptorStore& file_descriptor_store = base::FileDescriptorStore::GetInstance(); -@@ -302,11 +307,12 @@ bool ShouldLoadV8Snapshot(const base::CommandLine& command_line, +@@ -303,11 +308,12 @@ bool ShouldLoadV8Snapshot(const base::CommandLine& command_line, #endif // V8_USE_EXTERNAL_STARTUP_DATA @@ -40,7 +40,7 @@ index 46c7c57b5ff40b0e40d66bbeb8ec3f2b7f86cea0..46d144563983dee5a793948d9fd11852 #endif // V8_USE_EXTERNAL_STARTUP_DATA } -@@ -950,7 +956,7 @@ int ContentMainRunnerImpl::Initialize(ContentMainParams params) { +@@ -951,7 +957,7 @@ int ContentMainRunnerImpl::Initialize(ContentMainParams params) { return TerminateForFatalInitializationError(); #endif // BUILDFLAG(IS_ANDROID) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) @@ -50,7 +50,7 @@ index 46c7c57b5ff40b0e40d66bbeb8ec3f2b7f86cea0..46d144563983dee5a793948d9fd11852 blink::TrialTokenValidator::SetOriginTrialPolicyGetter( base::BindRepeating([]() -> blink::OriginTrialPolicy* { diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc -index 8b02f553e2fc29da88c3e14c05a7ee82210eab51..14f2e66d5ecda6e860724a3ab946eaaffba33d6d 100644 +index fee2fab8ab33a3829f055b0408e9e763443016cc..678c636c9ca08f8113dc67aafaf9761f33a7f0e5 100644 --- a/content/public/app/content_main_delegate.cc +++ b/content/public/app/content_main_delegate.cc @@ -5,6 +5,7 @@ @@ -73,7 +73,7 @@ index 8b02f553e2fc29da88c3e14c05a7ee82210eab51..14f2e66d5ecda6e860724a3ab946eaaf return new ContentClient(); } diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h -index db611d99a6c0f18f39967b38791822fda7d175b5..cc150475de655d5ef20a107ae3ef80c08af8c7fb 100644 +index 8151396412bf6981f3424526386ad6257b8c895d..ac5041c1666ac968251768f604f92434d92e374d 100644 --- a/content/public/app/content_main_delegate.h +++ b/content/public/app/content_main_delegate.h @@ -9,6 +9,7 @@ @@ -84,8 +84,8 @@ index db611d99a6c0f18f39967b38791822fda7d175b5..cc150475de655d5ef20a107ae3ef80c0 #include <vector> #include "base/notreached.h" -@@ -174,6 +175,8 @@ class CONTENT_EXPORT ContentMainDelegate { - virtual bool ShouldHandleConsoleControlEvents(); +@@ -181,6 +182,8 @@ class CONTENT_EXPORT ContentMainDelegate { + virtual bool ShouldInitializePerfetto(InvokedIn invoked_in); #endif + virtual std::string_view GetBrowserV8SnapshotFilename(); diff --git a/patches/chromium/custom_protocols_plzserviceworker.patch b/patches/chromium/custom_protocols_plzserviceworker.patch index 21d42b32cc0b8..c0f92740ba7b0 100644 --- a/patches/chromium/custom_protocols_plzserviceworker.patch +++ b/patches/chromium/custom_protocols_plzserviceworker.patch @@ -8,10 +8,10 @@ Allow registering custom protocols to handle service worker main script fetching Refs https://bugs.chromium.org/p/chromium/issues/detail?id=996511 diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc -index 6bcf498a08a4600b6fb4892e395d6d20bf771057..5d4b50fbfdb43a3efee99f2e27b7fed1fac42e9e 100644 +index cb60c976d469958b6d7dbd69dddc91866744c429..88f1cbc3bc7f3efaae01c88c17fa467175d4f8ea 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc -@@ -1956,6 +1956,26 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( +@@ -1957,6 +1957,26 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( loader_factory_bundle_info = context()->loader_factory_bundle_for_update_check()->Clone(); @@ -38,9 +38,9 @@ index 6bcf498a08a4600b6fb4892e395d6d20bf771057..5d4b50fbfdb43a3efee99f2e27b7fed1 if (auto* config = content::WebUIConfigMap::GetInstance().GetConfig( browser_context(), scope)) { // If this is a Service Worker for a WebUI, the WebUI's URLDataSource -@@ -1975,9 +1995,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( +@@ -1976,9 +1996,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( features::kEnableServiceWorkersForChromeScheme) && - scope.scheme_piece() == kChromeUIScheme) { + scope.scheme() == kChromeUIScheme) { config->RegisterURLDataSource(browser_context()); - static_cast<blink::PendingURLLoaderFactoryBundle*>( - loader_factory_bundle_info.get()) @@ -49,9 +49,9 @@ index 6bcf498a08a4600b6fb4892e395d6d20bf771057..5d4b50fbfdb43a3efee99f2e27b7fed1 .emplace(kChromeUIScheme, CreateWebUIServiceWorkerLoaderFactory( browser_context(), kChromeUIScheme, base::flat_set<std::string>())); -@@ -1985,9 +2003,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( +@@ -1986,9 +2004,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( features::kEnableServiceWorkersForChromeUntrusted) && - scope.scheme_piece() == kChromeUIUntrustedScheme) { + scope.scheme() == kChromeUIUntrustedScheme) { config->RegisterURLDataSource(browser_context()); - static_cast<blink::PendingURLLoaderFactoryBundle*>( - loader_factory_bundle_info.get()) diff --git a/patches/chromium/desktop_media_list.patch b/patches/chromium/desktop_media_list.patch index c03a58c52825e..cfa9f056410f1 100644 --- a/patches/chromium/desktop_media_list.patch +++ b/patches/chromium/desktop_media_list.patch @@ -82,10 +82,10 @@ index 786c526588d81b8b5b1b5dd3760719a53e005995..f66b7d0b4dfcbb8ed3dde5a9ff463ae2 const Source& GetSource(int index) const override; DesktopMediaList::Type GetMediaListType() const override; diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc -index 4383a2dd4a132e3012c206404399d73ac2d40ad4..912921c2b448e2badac50e8a7ed527aeb8f433a9 100644 +index 3be638f1032815d39634b5725031d7f3124e1ad2..fce3e30bc736ac72a42d24956d4abf9f49c8fc41 100644 --- a/chrome/browser/media/webrtc/native_desktop_media_list.cc +++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc -@@ -214,9 +214,13 @@ content::DesktopMediaID::Id GetUpdatedWindowId( +@@ -216,9 +216,13 @@ content::DesktopMediaID::Id GetUpdatedWindowId( } } #elif BUILDFLAG(IS_MAC) @@ -99,7 +99,7 @@ index 4383a2dd4a132e3012c206404399d73ac2d40ad4..912921c2b448e2badac50e8a7ed527ae #endif return window_id; -@@ -319,7 +323,7 @@ class NativeDesktopMediaList::Worker +@@ -321,7 +325,7 @@ class NativeDesktopMediaList::Worker base::WeakPtr<NativeDesktopMediaList> media_list_; DesktopMediaID::Type source_type_; @@ -108,7 +108,7 @@ index 4383a2dd4a132e3012c206404399d73ac2d40ad4..912921c2b448e2badac50e8a7ed527ae const ThumbnailCapturer::FrameDeliveryMethod frame_delivery_method_; const bool add_current_process_windows_; const bool auto_show_delegated_source_list_; -@@ -601,6 +605,12 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() { +@@ -603,6 +607,12 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() { FROM_HERE, base::BindOnce(&NativeDesktopMediaList::UpdateNativeThumbnailsFinished, media_list_)); @@ -121,7 +121,7 @@ index 4383a2dd4a132e3012c206404399d73ac2d40ad4..912921c2b448e2badac50e8a7ed527ae } void NativeDesktopMediaList::Worker::OnCaptureResult( -@@ -1008,6 +1018,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows( +@@ -1009,6 +1019,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows( FROM_HERE, base::BindOnce(&Worker::RefreshThumbnails, base::Unretained(worker_.get()), std::move(native_ids), thumbnail_size_)); diff --git a/patches/chromium/disable_compositor_recycling.patch b/patches/chromium/disable_compositor_recycling.patch index 7c5570673d4de..5b97aba2d8ee4 100644 --- a/patches/chromium/disable_compositor_recycling.patch +++ b/patches/chromium/disable_compositor_recycling.patch @@ -6,11 +6,11 @@ Subject: fix: disabling compositor recycling Compositor recycling is useful for Chrome because there can be many tabs and spinning up a compositor for each one would be costly. In practice, Chrome uses the parent compositor code path of browser_compositor_view_mac.mm; the NSView of each tab is detached when it's hidden and attached when it's shown. For Electron, there is no parent compositor, so we're forced into the "own compositor" code path, which seems to be non-optimal and pretty ruthless in terms of the release of resources. Electron has no real concept of multiple tabs per window, so it should be okay to disable this ruthless recycling altogether in Electron. diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm -index 59c8d5a2e687ac6148889c87f353b33959e276f6..7ef10194f02e32a9ec137f7f2519c4a834b81b7a 100644 +index 00f9abc97d2001fc0bd095d2c62097f2ed1ae047..71fb36989aeb2c3232f624501933ed48a50e06cd 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm -@@ -561,7 +561,11 @@ - return; +@@ -559,7 +559,11 @@ + } host()->WasHidden(); - browser_compositor_->SetRenderWidgetHostIsHidden(true); diff --git a/patches/chromium/disable_hidden.patch b/patches/chromium/disable_hidden.patch index c7c6b9f145c4c..6572cc63d3e77 100644 --- a/patches/chromium/disable_hidden.patch +++ b/patches/chromium/disable_hidden.patch @@ -6,10 +6,10 @@ Subject: disable_hidden.patch Electron uses this to disable background throttling for hidden windows. diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc -index c28aa525c51e9be757d5d8f8e5a60857b7a451d4..e8baae79ab127e4626f39247a5e57fe6a6114453 100644 +index 4c3ab7e4a7d35a8933715ae2966768049f28b715..982b5edc933fdf1c4884dd0e0e7b957cee31c5ef 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc -@@ -847,6 +847,10 @@ void RenderWidgetHostImpl::WasHidden() { +@@ -841,6 +841,10 @@ void RenderWidgetHostImpl::WasHidden() { return; } @@ -21,29 +21,28 @@ index c28aa525c51e9be757d5d8f8e5a60857b7a451d4..e8baae79ab127e4626f39247a5e57fe6 // Prompts should remain open and functional across tab switches. if (!delegate_ || !delegate_->IsWaitingForPointerLockPrompt(this)) { diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h -index f07055487abd76b2a72ba555ff1b5bcd996bbd3a..7d46db80c667900576cf46264034890203020a75 100644 +index 2d32d91eb98fe749ae262ba06a1a399813aa7bab..8ebf542046ffba6823804b797e373c80bab12873 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h -@@ -1026,6 +1026,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl - // cpu-priority boosted to run discard logic. - void SetIsDiscarding(bool is_discarding); +@@ -1031,6 +1031,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl + return synthetic_gesture_controller_.get(); + } + // Electron: Prevents the widget from getting hidden. + bool disable_hidden_ = false; -+ protected: // |routing_id| must not be IPC::mojom::kRoutingIdNone. // If this object outlives |delegate|, DetachDelegate() must be called when diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc -index f4c657fe36eba54948cacf9770d9c6c1b55b5fe5..b14f5bc3f023c512a066ce9ec9f681c96b1fafc4 100644 +index 9b1712382e208ef949616243d6ec1feab46f8fb3..84899b5208f036bd58ba51513820404b6c5a24b9 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc -@@ -644,7 +644,7 @@ void RenderWidgetHostViewAura::HideImpl() { +@@ -696,7 +696,7 @@ void RenderWidgetHostViewAura::HideImpl() { CHECK(visibility_ == Visibility::HIDDEN || visibility_ == Visibility::OCCLUDED); -- if (!host()->is_hidden()) { -+ if (!host()->is_hidden() && !host()->disable_hidden_) { +- if (!host()->IsHidden()) { ++ if (!host()->IsHidden() && !host()->disable_hidden_) { host()->WasHidden(); aura::WindowTreeHost* host = window_->GetHost(); aura::Window* parent = window_->parent(); diff --git a/patches/chromium/dom_storage_limits.patch b/patches/chromium/dom_storage_limits.patch index 23e4b10695b87..2d44ada44adb3 100644 --- a/patches/chromium/dom_storage_limits.patch +++ b/patches/chromium/dom_storage_limits.patch @@ -9,7 +9,7 @@ Previous versions of this patch attempted to circumvent the restriction altogether. However, this can lead to other problems, such as crashing the Dev Tools when attempting to read or write values that exceed -`IPC::Channel::kMaximumMessageSize` (128MiB). +`IPC::mojom::kChannelMaximumMessageSize` (128MiB). Increasing the quota rather than bypassing it reduces the amount of chromium code that needs to be changed for Electron diff --git a/patches/chromium/enable_reset_aspect_ratio.patch b/patches/chromium/enable_reset_aspect_ratio.patch index c0ccee0126d7e..180416e36944f 100644 --- a/patches/chromium/enable_reset_aspect_ratio.patch +++ b/patches/chromium/enable_reset_aspect_ratio.patch @@ -6,10 +6,10 @@ Subject: feat: enable setting aspect ratio to 0 Make SetAspectRatio accept 0 as valid input, which would reset to null. diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -index 95f034ecf921265304cde98d2ce163a2ab09887a..315356b513e9f2c0ce7658aefeb69d0ac327c4de 100644 +index cb704a865eb1b748163a7c25b0a571585c2497b4..3b2fbefaeec2bac725d46bcfeea488122c873d76 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -@@ -619,7 +619,7 @@ void DesktopWindowTreeHostWin::SetOpacity(float opacity) { +@@ -614,7 +614,7 @@ void DesktopWindowTreeHostWin::SetOpacity(float opacity) { void DesktopWindowTreeHostWin::SetAspectRatio( const gfx::SizeF& aspect_ratio, const gfx::Size& excluded_margin) { @@ -19,10 +19,10 @@ index 95f034ecf921265304cde98d2ce163a2ab09887a..315356b513e9f2c0ce7658aefeb69d0a excluded_margin); } diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index df17e97666de639f05b92a79ee7fbd4a3da6c64f..f404c718e0242ec9269e7d14eb236aa928fb5d58 100644 +index e9197d95aa22f92007045537b004ea2e38a5d4f5..80683ec77cdc77d624254c19708f12acd47316a1 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -1050,8 +1050,11 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen, +@@ -1057,8 +1057,11 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen, void HWNDMessageHandler::SetAspectRatio(float aspect_ratio, const gfx::Size& excluded_margin) { @@ -35,4 +35,4 @@ index df17e97666de639f05b92a79ee7fbd4a3da6c64f..f404c718e0242ec9269e7d14eb236aa9 + } aspect_ratio_ = aspect_ratio; - + excluded_margin_dip_ = excluded_margin; diff --git a/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch b/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch index 9d478cd3aeddc..dec2581a04626 100644 --- a/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch +++ b/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch @@ -21,7 +21,7 @@ index 9dac402705385087ced2df2db757a07246984a94..cb49b4f085026658e920699ed285d524 ThreadIsolatedAllocator* GetThreadIsolatedAllocator() override; #endif diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc -index 698b29e9c31a2695cac30bf85c97a216ff8a6257..dbc38d0d87803496ce122da62e639f2a0334e0f6 100644 +index 43a2543499c1f21eb8d1e9a559466edbe15af9f5..dd4399819ef62187e038af40caff3e8018cba8dd 100644 --- a/gin/v8_platform.cc +++ b/gin/v8_platform.cc @@ -205,6 +205,10 @@ ThreadIsolatedAllocator* V8Platform::GetThreadIsolatedAllocator() { diff --git a/patches/chromium/expose_referrerscriptinfo_hostdefinedoptionsindex.patch b/patches/chromium/expose_referrerscriptinfo_hostdefinedoptionsindex.patch new file mode 100644 index 0000000000000..a95d1b500c0fb --- /dev/null +++ b/patches/chromium/expose_referrerscriptinfo_hostdefinedoptionsindex.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fedor Indutny <indutny@signal.org> +Date: Wed, 24 Sep 2025 10:08:48 -0700 +Subject: Expose ReferrerScriptInfo::HostDefinedOptionsIndex + +In `shell/common/node_bindings.cc`'s +`HostImportModuleWithPhaseDynamically` we route dynamic imports to +either Node.js's or Blink's resolver based on presence of Node.js +environment, process type, etc. Exporting `HostDefinedOptionsIndex` +allows us to route based on the size of `v8_host_defined_options` data +which enables us to support dynamic imports in non-context-isolated +preload scripts. + +diff --git a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc +index 1b797783987255622735047bd78ca0e8bb635d5e..b209c736bb80c186ed51999af1dac0a1d50fc232 100644 +--- a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc ++++ b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.cc +@@ -12,15 +12,6 @@ namespace blink { + + namespace { + +-enum HostDefinedOptionsIndex : size_t { +- kBaseURL, +- kCredentialsMode, +- kNonce, +- kParserState, +- kReferrerPolicy, +- kLength +-}; +- + // Omit storing base URL if it is same as ScriptOrigin::ResourceName(). + // Note: This improves chance of getting into a fast path in + // ReferrerScriptInfo::ToV8HostDefinedOptions. +diff --git a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h +index 0119624a028bec3e53e4e402938a98fe6def1483..743865839448748fe00e3e7d5027587cb65393c9 100644 +--- a/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h ++++ b/third_party/blink/renderer/bindings/core/v8/referrer_script_info.h +@@ -23,6 +23,15 @@ class CORE_EXPORT ReferrerScriptInfo { + STACK_ALLOCATED(); + + public: ++ enum HostDefinedOptionsIndex : size_t { ++ kBaseURL, ++ kCredentialsMode, ++ kNonce, ++ kParserState, ++ kReferrerPolicy, ++ kLength ++ }; ++ + ReferrerScriptInfo() {} + ReferrerScriptInfo(const KURL& base_url, + network::mojom::CredentialsMode credentials_mode, diff --git a/patches/chromium/expose_setuseragent_on_networkcontext.patch b/patches/chromium/expose_setuseragent_on_networkcontext.patch index f9b1aa3f85ae7..b65432f6f15d6 100644 --- a/patches/chromium/expose_setuseragent_on_networkcontext.patch +++ b/patches/chromium/expose_setuseragent_on_networkcontext.patch @@ -33,11 +33,11 @@ index 0ab8187b0db8ae6db46d81738f653a2bc4c566f6..de3d55e85c22317f7f9375eb94d0d5d4 } // namespace net diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index 7721b8e827d9aac6e90ddfe3de264f41915219f2..1bc4f24c3f0eb843033d2aa541d81e910f8021b0 100644 +index 61c7bd716e2ed78c8f71cba50d34e80d6effad4f..68ec7012adbdb1ac65fe784f4a928474a8894a70 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc -@@ -1872,6 +1872,13 @@ void NetworkContext::SetNetworkConditions( - std::move(network_conditions)); +@@ -1911,6 +1911,13 @@ void NetworkContext::EnableDurableMessageCollector( + it->second->AddReceiver(std::move(receiver)); } +void NetworkContext::SetUserAgent(const std::string& new_user_agent) { @@ -51,24 +51,24 @@ index 7721b8e827d9aac6e90ddfe3de264f41915219f2..1bc4f24c3f0eb843033d2aa541d81e91 // This may only be called on NetworkContexts created with the constructor // that calls MakeURLRequestContext(). diff --git a/services/network/network_context.h b/services/network/network_context.h -index b9f201ccf04433a29083cd15cfe599fe9600c9c0..137aaf96a8d02b81afe64fde6b19ed1153569941 100644 +index 90cf1a70c068771ac98b2d5a283cba5e54c05ff4..0dc8de8d4e37e48cb28d8112c0233ac80cfb9ba5 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h -@@ -326,6 +326,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext - void CloseIdleConnections(CloseIdleConnectionsCallback callback) override; - void SetNetworkConditions(const base::UnguessableToken& throttling_profile_id, - mojom::NetworkConditionsPtr conditions) override; +@@ -336,6 +336,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext + const base::UnguessableToken& throttling_profile_id, + mojo::PendingReceiver<network::mojom::DurableMessageCollector> receiver) + override; + void SetUserAgent(const std::string& new_user_agent) override; void SetAcceptLanguage(const std::string& new_accept_language) override; void SetEnableReferrers(bool enable_referrers) override; #if BUILDFLAG(IS_CT_SUPPORTED) diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom -index 1ed66c3b41e583745c5b309670fc4470fa1983cf..c7464641d0fc944aa47f3f1e0406dd4002d0bd0b 100644 +index 269b95a51029b2a2e42d663988f2c1b8a74f91a8..b819cd38ab8921d494caff3d2ae0ab86c9860d9c 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom -@@ -1288,6 +1288,9 @@ interface NetworkContext { - SetNetworkConditions(mojo_base.mojom.UnguessableToken throttling_profile_id, - NetworkConditions? conditions); +@@ -1345,6 +1345,9 @@ interface NetworkContext { + mojo_base.mojom.UnguessableToken throttling_profile_id, + pending_receiver<DurableMessageCollector> receiver); + // Updates the user agent to be used for requests. + SetUserAgent(string new_user_agent); @@ -77,13 +77,13 @@ index 1ed66c3b41e583745c5b309670fc4470fa1983cf..c7464641d0fc944aa47f3f1e0406dd40 SetAcceptLanguage(string new_accept_language); diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h -index 70a5ab342a8954354a3d8245d30df9520cfd398d..02700030ab651b6f8f0aecfe6857ca40e6f3839f 100644 +index ebcacbcb16057912693a6674e6b9ef5eeb671f91..1f3f18979b76be720a7c202f2a45fcc593c8fc01 100644 --- a/services/network/test/test_network_context.h +++ b/services/network/test/test_network_context.h -@@ -158,6 +158,7 @@ class TestNetworkContext : public mojom::NetworkContext { - void CloseIdleConnections(CloseIdleConnectionsCallback callback) override {} - void SetNetworkConditions(const base::UnguessableToken& throttling_profile_id, - mojom::NetworkConditionsPtr conditions) override {} +@@ -162,6 +162,7 @@ class TestNetworkContext : public mojom::NetworkContext { + void SetNetworkConditions( + const base::UnguessableToken& throttling_profile_id, + std::vector<mojom::MatchedNetworkConditionsPtr>) override {} + void SetUserAgent(const std::string& new_user_agent) override {} void SetAcceptLanguage(const std::string& new_accept_language) override {} void SetEnableReferrers(bool enable_referrers) override {} diff --git a/patches/chromium/extend_apply_webpreferences.patch b/patches/chromium/extend_apply_webpreferences.patch index dbd3c00b50748..e77220b149624 100644 --- a/patches/chromium/extend_apply_webpreferences.patch +++ b/patches/chromium/extend_apply_webpreferences.patch @@ -15,14 +15,14 @@ Ideally we could add an embedder observer pattern here but that can be done in future work. diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc -index b9799837c7ce14fc76045700b30e1358d4705251..5b3ab0837b5a85b4e7dd1685db75f65cd4d5ff43 100644 +index 0d1cd0e4f502f44362fba6552080f31fe5c6b7ea..6e303fd506aa52f8def296fdd15b429de1467abe 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc -@@ -1890,6 +1890,8 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs, +@@ -1893,6 +1893,8 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs, #if BUILDFLAG(IS_MAC) web_view_impl->SetMaximumLegibleScale( prefs.default_maximum_page_scale_factor); -+ web_view_impl->GetChromeClient().SetUseExternalPopupMenusForTesting( ++ web_view_impl->GetChromeClient().SetUseExternalPopupMenus( + !prefs.offscreen); #endif diff --git a/patches/chromium/feat_add_data_parameter_to_processsingleton.patch b/patches/chromium/feat_add_data_parameter_to_processsingleton.patch index 0a804cbcb1539..f969439c2dccf 100644 --- a/patches/chromium/feat_add_data_parameter_to_processsingleton.patch +++ b/patches/chromium/feat_add_data_parameter_to_processsingleton.patch @@ -180,7 +180,7 @@ index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { // Try to kill the other process, because it might have been dead. diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc -index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a02ccbac0 100644 +index ae659d84a5ae2f2e87ce288477506575f8d86839..d93c7e8487ab1a2bbb5f56f2ca44868f947e6bfc 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc @@ -81,10 +81,12 @@ BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { @@ -258,11 +258,11 @@ index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a - switch (AttemptToNotifyRunningChrome(remote_window_)) { + switch (AttemptToNotifyRunningChrome(remote_window_, additional_data_)) { - case NotifyChromeResult::NOTIFY_SUCCESS: + case NotifyChromeResult::kSuccess: return PROCESS_NOTIFIED; - case NotifyChromeResult::NOTIFY_FAILED: + case NotifyChromeResult::kFailed: diff --git a/chrome/browser/win/chrome_process_finder.cc b/chrome/browser/win/chrome_process_finder.cc -index 58a4c5adfda49fb4bd1b5351bd02d358946043bd..adaa070eb0f3cf8f771b57743a7436fd48a1e576 100644 +index 594f3bc08a4385c177fb488123cef79448e94850..5a1dde19a4bc2bf728eba4c738f831c3e5b73942 100644 --- a/chrome/browser/win/chrome_process_finder.cc +++ b/chrome/browser/win/chrome_process_finder.cc @@ -39,7 +39,9 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) { @@ -303,7 +303,7 @@ index 58a4c5adfda49fb4bd1b5351bd02d358946043bd..adaa070eb0f3cf8f771b57743a7436fd // window (otherwise it will just flash in the taskbar). ::AllowSetForegroundWindow(process_id); diff --git a/chrome/browser/win/chrome_process_finder.h b/chrome/browser/win/chrome_process_finder.h -index 91e5e623840b9912bd05d024c12e3eb3f1ba2f53..63b5b10013c96dea4e77e5e56a060973a1752faa 100644 +index 62e232f41189a557534e0b01d912469b2ca26148..3a4dfb027cdc690ee7561fc8b632f35cb6b8f4be 100644 --- a/chrome/browser/win/chrome_process_finder.h +++ b/chrome/browser/win/chrome_process_finder.h @@ -7,6 +7,7 @@ diff --git a/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch b/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch index 453b23e5ff63c..62b53c9aef8dc 100644 --- a/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch +++ b/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch @@ -12,28 +12,23 @@ uses internally for things like menus and devtools. We can remove this patch once it has in some shape been upstreamed. -diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc -index 3f8801c6042ef2b20635838e4d4c572d89b94601..055b15ff72844cd54c60cc92042a5465ce2870ad 100644 ---- a/ui/native_theme/native_theme.cc -+++ b/ui/native_theme/native_theme.cc -@@ -210,6 +210,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors, - NativeTheme::~NativeTheme() = default; - - bool NativeTheme::ShouldUseDarkColors() const { -+ if (theme_source() == ThemeSource::kForcedLight) return false; -+ if (theme_source() == ThemeSource::kForcedDark) return true; - return should_use_dark_colors_; - } - diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h -index 67d63aa0048c2a4e331763a869b46bc1142b921c..34ddc49fe66c1824734a6d524af68862892801e2 100644 +index d8c168edc6c92c8094bb37e4ac1eb703d9d1dc85..f103f2a095724f552b1917546a771168f64c53df 100644 --- a/ui/native_theme/native_theme.h +++ b/ui/native_theme/native_theme.h -@@ -459,6 +459,23 @@ class COMPONENT_EXPORT(NATIVE_THEME) NativeTheme { - scoped_refptr<ColorProviderKey::ThemeInitializerSupplier> custom_theme, - bool use_custom_frame = true) const; +@@ -500,6 +500,8 @@ class COMPONENT_EXPORT(NATIVE_THEME) NativeTheme { + } + + PreferredColorScheme preferred_color_scheme() const { ++ if (theme_source() == ThemeSource::kForcedLight) return PreferredColorScheme::kLight; ++ if (theme_source() == ThemeSource::kForcedDark) return PreferredColorScheme::kDark; + return preferred_color_scheme_; + } + void set_preferred_color_scheme(PreferredColorScheme preferred_color_scheme) { +@@ -531,6 +533,24 @@ class COMPONENT_EXPORT(NATIVE_THEME) NativeTheme { + caret_blink_interval_ = caret_blink_interval; + } -+ + enum ThemeSource { + kSystem, + kForcedDark, @@ -45,32 +40,21 @@ index 67d63aa0048c2a4e331763a869b46bc1142b921c..34ddc49fe66c1824734a6d524af68862 + } + + void set_theme_source(ThemeSource theme_source) { -+ bool original = ShouldUseDarkColors(); ++ bool was_dark = preferred_color_scheme() == PreferredColorScheme::kDark; + theme_source_ = theme_source; -+ if (ShouldUseDarkColors() != original) NotifyOnNativeThemeUpdated(); ++ if ((preferred_color_scheme() == PreferredColorScheme::kDark) != was_dark) { ++ NotifyOnNativeThemeUpdated(); ++ } + } + - // Returns a shared instance of the native theme that should be used for web - // rendering. Do not use it in a normal application context (i.e. browser). - // The returned object should not be deleted by the caller. This function is -@@ -714,6 +731,7 @@ class COMPONENT_EXPORT(NATIVE_THEME) NativeTheme { - PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference; - std::optional<base::TimeDelta> caret_blink_interval_; - bool use_overlay_scrollbars_ = false; + protected: + explicit NativeTheme(SystemTheme system_theme = SystemTheme::kDefault); + virtual ~NativeTheme(); +@@ -604,6 +624,7 @@ class COMPONENT_EXPORT(NATIVE_THEME) NativeTheme { + ColorProviderKey::UserColorSource preferred_color_source_ = + ColorProviderKey::UserColorSource::kAccent; + base::TimeDelta caret_blink_interval_; + ThemeSource theme_source_ = ThemeSource::kSystem; - SEQUENCE_CHECKER(sequence_checker_); - }; -diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc -index 0c6d689295a03fc088b57487037d85f4d634a5f4..8e3bab233e8611c68e79d53f125560f4fb086a1e 100644 ---- a/ui/native_theme/native_theme_win.cc -+++ b/ui/native_theme/native_theme_win.cc -@@ -697,6 +697,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const { - if (InForcedColorsMode() && !IsForcedDarkMode()) { - return false; - } -+ if (theme_source() == ThemeSource::kForcedLight) return false; -+ if (theme_source() == ThemeSource::kForcedDark) return true; - return NativeTheme::ShouldUseDarkColors(); - } + raw_ptr<NativeTheme> associated_web_instance_ = nullptr; diff --git a/patches/chromium/feat_add_signals_when_embedder_cleanup_callbacks_run_for.patch b/patches/chromium/feat_add_signals_when_embedder_cleanup_callbacks_run_for.patch index c9cc322a9fca2..8fa3633514bbc 100644 --- a/patches/chromium/feat_add_signals_when_embedder_cleanup_callbacks_run_for.patch +++ b/patches/chromium/feat_add_signals_when_embedder_cleanup_callbacks_run_for.patch @@ -16,7 +16,7 @@ remove this patch once gin::Wrappable can be managed by V8 Oilpan via https://github.com/electron/electron/issues/47922 diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc -index 656267caef2d515f8c3f77535b308108a0b30be1..083d59f78c542f4900e1b210a0935276516b894b 100644 +index 05c899258143a958471f361b87324f7500d594c9..1943413560f23c212d98fa1b368204c6e062bab2 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -35,6 +35,8 @@ v8::ArrayBuffer::Allocator* g_array_buffer_allocator = nullptr; @@ -56,10 +56,10 @@ index 656267caef2d515f8c3f77535b308108a0b30be1..083d59f78c542f4900e1b210a0935276 + } // namespace gin diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h -index dc3a5b0678b9c686e241b492e2c3b5ac833611a3..32a7ba4f557e65d9525d2ca07e8597e7bd070b12 100644 +index 902ad13dad8df57325f6c74ee3da9ec3148751cb..d0de06b55937d36848664c3817d098182c67f570 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h -@@ -132,6 +132,8 @@ class GIN_EXPORT IsolateHolder { +@@ -133,6 +133,8 @@ class GIN_EXPORT IsolateHolder { // Should only be called after v8::IsolateHolder::Initialize() is invoked. static std::unique_ptr<v8::Isolate::CreateParams> getDefaultIsolateParams(); @@ -68,7 +68,7 @@ index dc3a5b0678b9c686e241b492e2c3b5ac833611a3..32a7ba4f557e65d9525d2ca07e8597e7 v8::Isolate* isolate() { return isolate_; } // This method returns if v8::Locker is needed to access isolate. -@@ -145,6 +147,9 @@ class GIN_EXPORT IsolateHolder { +@@ -146,6 +148,9 @@ class GIN_EXPORT IsolateHolder { void EnableIdleTasks(std::unique_ptr<V8IdleTaskRunner> idle_task_runner); diff --git a/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch b/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch index 7d6bd4f2165ba..4d46496656b44 100644 --- a/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch +++ b/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch @@ -17,13 +17,13 @@ which removed range-requests-supported on non-http protocols. See https://issues for more information. diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc -index 5972dcf91aeb8446af4fa0b902b086a5492815bd..ac37d7f601f24d9ec53c4c1fd5e00c8a262e1580 100644 +index d1565bfe05342915d516d9c46eb7c4922c361b22..a5f35e7782c047b147458e569924de0fd30db7ce 100644 --- a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc +++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc @@ -11,8 +11,10 @@ #include "base/containers/adapters.h" #include "base/location.h" - #include "base/memory/raw_ptr.h" + #include "base/memory/raw_span.h" +#include "base/no_destructor.h" #include "base/numerics/safe_conversions.h" #include "base/task/single_thread_task_runner.h" @@ -42,7 +42,7 @@ index 5972dcf91aeb8446af4fa0b902b086a5492815bd..ac37d7f601f24d9ec53c4c1fd5e00c8a class MultiBufferDataSource::ReadOperation { public: ReadOperation() = delete; -@@ -143,13 +149,29 @@ MultiBufferDataSource::~MultiBufferDataSource() { +@@ -136,13 +142,29 @@ MultiBufferDataSource::~MultiBufferDataSource() { DCHECK(render_task_runner_->BelongsToCurrentThread()); } @@ -74,10 +74,10 @@ index 5972dcf91aeb8446af4fa0b902b086a5492815bd..ac37d7f601f24d9ec53c4c1fd5e00c8a void MultiBufferDataSource::SetReader( diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source.h b/third_party/blink/renderer/platform/media/multi_buffer_data_source.h -index 8c92f1c0c5028069cdad967b5be2bccf8005ed43..8b49dc182296f7f277981aed29b58947fb0980cb 100644 +index 5100bd21163f9ceadb728ed5306dcf8320e528a8..c2ee03ca6a75a2fef1ce778e663a74bda608acb4 100644 --- a/third_party/blink/renderer/platform/media/multi_buffer_data_source.h +++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source.h -@@ -17,6 +17,7 @@ +@@ -18,6 +18,7 @@ #include "media/base/data_source.h" #include "media/base/ranges.h" #include "media/base/tuneable.h" @@ -85,7 +85,7 @@ index 8c92f1c0c5028069cdad967b5be2bccf8005ed43..8b49dc182296f7f277981aed29b58947 #include "third_party/blink/renderer/platform/media/url_index.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -@@ -34,6 +35,8 @@ namespace blink { +@@ -35,6 +36,8 @@ namespace blink { class BufferedDataSourceHost; class MultiBufferReader; @@ -94,7 +94,7 @@ index 8c92f1c0c5028069cdad967b5be2bccf8005ed43..8b49dc182296f7f277981aed29b58947 // A data source capable of loading URLs and buffering the data using an // in-memory sliding window. // -@@ -63,6 +66,8 @@ class PLATFORM_EXPORT MultiBufferDataSource +@@ -64,6 +67,8 @@ class PLATFORM_EXPORT MultiBufferDataSource return url_data_->mime_type(); } @@ -104,7 +104,7 @@ index 8c92f1c0c5028069cdad967b5be2bccf8005ed43..8b49dc182296f7f277981aed29b58947 using InitializeCB = base::OnceCallback<void(bool)>; void Initialize(InitializeCB init_cb) override; diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc -index 1b5dc45902fc30386dfcb98a19d532e3be46706b..fb2c7f09c210f6aa178e663b1c1ce91468c71e10 100644 +index 093e01ba30f66e29d13c129a230f8acf875f5eb4..8fb40e4d5827985c2760e57f0dccfeb9ab700a03 100644 --- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc +++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc @@ -8,6 +8,7 @@ diff --git a/patches/chromium/feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch b/patches/chromium/feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch index 659446d75a94d..309c5f823a61a 100644 --- a/patches/chromium/feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch +++ b/patches/chromium/feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch @@ -16,10 +16,10 @@ It also: This may be partially upstreamed to Chromium in the future. diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc -index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea0328abcee4 100644 +index bf903ea436f5d0c8599f7a122828fc163a192247..e1c5c8e9241d29668d0c7dae12a46a5ded900fac 100644 --- a/ui/gtk/select_file_dialog_linux_gtk.cc +++ b/ui/gtk/select_file_dialog_linux_gtk.cc -@@ -261,8 +261,12 @@ void SelectFileDialogLinuxGtk::SelectFileImpl( +@@ -262,8 +262,12 @@ void SelectFileDialogLinuxGtk::SelectFileImpl( case SELECT_EXISTING_FOLDER: dialog = CreateSelectFolderDialog(type, title_string, default_path, owning_window); @@ -34,7 +34,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 break; case SELECT_OPEN_FILE: dialog = CreateFileOpenDialog(title_string, default_path, owning_window); -@@ -409,9 +413,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper( +@@ -410,9 +414,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper( const std::string& title, const base::FilePath& default_path, gfx::NativeWindow parent) { @@ -47,7 +47,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 SetGtkTransientForAura(dialog, parent); AddFilters(GTK_FILE_CHOOSER(dialog)); -@@ -427,6 +433,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper( +@@ -428,6 +434,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper( GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog), *last_opened_path()); } @@ -55,7 +55,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 return dialog; } -@@ -442,11 +449,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog( +@@ -443,11 +450,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog( ? l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE) : l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE); } @@ -76,7 +76,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 GtkWidget* dialog = GtkFileChooserDialogNew( title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, -@@ -468,7 +479,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog( +@@ -469,7 +480,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog( gtk_file_filter_add_mime_type(only_folders, "inode/directory"); gtk_file_filter_add_mime_type(only_folders, "text/directory"); gtk_file_chooser_add_filter(chooser, only_folders); @@ -86,7 +86,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 return dialog; } -@@ -505,10 +517,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog( +@@ -506,10 +518,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog( std::string title_string = !title.empty() ? title : l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE); @@ -100,7 +100,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 GTK_RESPONSE_ACCEPT); SetGtkTransientForAura(dialog, parent); -@@ -534,9 +547,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog( +@@ -535,9 +548,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog( gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); // Overwrite confirmation is always enabled in GTK4. if (!GtkCheckVersion(4)) { @@ -113,7 +113,7 @@ index 4a9118dcabbc0cffeea17dc26a8e1f2a54604766..4ae6001c0376822d41a77949ce05ea03 return dialog; } -@@ -591,15 +605,29 @@ void SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse( +@@ -592,15 +606,29 @@ void SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse( void SelectFileDialogLinuxGtk::OnSelectMultiFileDialogResponse( GtkWidget* dialog, int response_id) { @@ -173,7 +173,7 @@ index 213eaa5ec6d657a659726cb38103e8bd671fe907..f497447c598198bf690758b1d1c5c6fe void OnFileChooserDestroy(GtkWidget* dialog); diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h -index eb3d997598631b220c3566748f23a5cdac3e4692..b4b2f7294ce6e9349a4a8a05f614e93359eca25a 100644 +index b0f4b3df0a4f10b306ba2d25e5fd51440a25bcd4..4ac06587203d2d2adf1390d9256e537e8cf7b21d 100644 --- a/ui/shell_dialogs/select_file_dialog.h +++ b/ui/shell_dialogs/select_file_dialog.h @@ -224,6 +224,21 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog @@ -262,7 +262,7 @@ index 61683d0eddb04c494ca5e650e7d556b44968ec49..5492456a9138b250e97a5479838bb443 } // namespace ui diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc -index 54cefe5b6236b24cd9c4625d603fe9a7205676f5..1f70697a2f9ddba8151b4c4f497fbc007ee5fed8 100644 +index af5f9cdb01d18abf00bb5b20e5f2ab5e4ce24dc6..378939d2d2b48f1f591523db431005d038e2a88b 100644 --- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc +++ b/ui/shell_dialogs/select_file_dialog_linux_portal.cc @@ -25,6 +25,7 @@ @@ -272,7 +272,7 @@ index 54cefe5b6236b24cd9c4625d603fe9a7205676f5..1f70697a2f9ddba8151b4c4f497fbc00 +#include "electron/shell/browser/ui/file_dialog.h" #include "ui/aura/window_tree_host.h" #include "ui/base/l10n/l10n_util.h" - #include "ui/gfx/native_widget_types.h" + #include "ui/gfx/native_ui_types.h" @@ -96,7 +97,7 @@ void OnGetPropertyReply(dbus::Response* response) { : ServiceAvailability::kNotAvailable; } @@ -294,8 +294,8 @@ index 54cefe5b6236b24cd9c4625d603fe9a7205676f5..1f70697a2f9ddba8151b4c4f497fbc00 + file_dialog::StartPortalAvailabilityTestInBackground(); } - DbusByteArray PathToByteArray(const base::FilePath& path) { -@@ -170,17 +174,20 @@ void SelectFileDialogLinuxPortal::StartAvailabilityTestInBackground() { + std::vector<uint8_t> PathToByteArray(const base::FilePath& path) { +@@ -171,17 +175,20 @@ void SelectFileDialogLinuxPortal::StartAvailabilityTestInBackground() { GetMainTaskRunner() = base::SequencedTaskRunner::GetCurrentDefault(); dbus_xdg::SetSystemdScopeUnitNameForXdgPortal( @@ -317,18 +317,18 @@ index 54cefe5b6236b24cd9c4625d603fe9a7205676f5..1f70697a2f9ddba8151b4c4f497fbc00 + return file_dialog::IsPortalAvailable(); } - bool SelectFileDialogLinuxPortal::IsRunning( -@@ -385,11 +392,14 @@ DbusDictionary SelectFileDialogLinuxPortal::BuildOptionsDictionary( + void SelectFileDialogLinuxPortal::ListenerDestroyed() { +@@ -385,11 +392,14 @@ dbus_xdg::Dictionary SelectFileDialogLinuxPortal::BuildOptionsDictionary( const PortalFilterSet& filter_set) { - DbusDictionary dict; + dbus_xdg::Dictionary dict; + std::string accept_label = button_label().empty() ? "" : button_label(); + switch (type_) { case SelectFileDialog::SELECT_UPLOAD_FOLDER: -- dict.PutAs(kFileChooserOptionAcceptLabel, -- DbusString(l10n_util::GetStringUTF8( -- IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON))); +- dict[kFileChooserOptionAcceptLabel] = +- dbus_utils::Variant::Wrap<"s">(l10n_util::GetStringUTF8( +- IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)); + if (accept_label.empty()) { + accept_label = l10n_util::GetStringUTF8( + IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON); @@ -336,12 +336,13 @@ index 54cefe5b6236b24cd9c4625d603fe9a7205676f5..1f70697a2f9ddba8151b4c4f497fbc00 [[fallthrough]]; case SelectFileDialog::SELECT_FOLDER: case SelectFileDialog::Type::SELECT_EXISTING_FOLDER: -@@ -402,6 +412,10 @@ DbusDictionary SelectFileDialogLinuxPortal::BuildOptionsDictionary( +@@ -402,6 +412,11 @@ dbus_xdg::Dictionary SelectFileDialogLinuxPortal::BuildOptionsDictionary( break; } + if (!accept_label.empty()) { -+ dict.PutAs(kFileChooserOptionAcceptLabel, DbusString(accept_label)); ++ dict[kFileChooserOptionAcceptLabel] = ++ dbus_utils::Variant::Wrap<"s">(accept_label); + } + if (!default_path.empty() && base::IsStringUTF8(default_path.value())) { diff --git a/patches/chromium/feat_allow_code_cache_in_custom_schemes.patch b/patches/chromium/feat_allow_code_cache_in_custom_schemes.patch index cebc62f39b163..5b1e716e6d484 100644 --- a/patches/chromium/feat_allow_code_cache_in_custom_schemes.patch +++ b/patches/chromium/feat_allow_code_cache_in_custom_schemes.patch @@ -9,7 +9,7 @@ embedders to make custom schemes allow V8 code cache. Chromium CL: https://chromium-review.googlesource.com/c/chromium/src/+/5019665 diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc -index 1673dd4966365f31f1073a4c90743e6fe73880b6..cb3d3da5bc9da99c950521d18f28aa438467fdf4 100644 +index 445661be8089c8d52ade8c24603024afde27cedd..22c95824b703d6248475071c6bb3de91550eb0fa 100644 --- a/content/browser/code_cache/generated_code_cache.cc +++ b/content/browser/code_cache/generated_code_cache.cc @@ -8,6 +8,7 @@ @@ -28,21 +28,11 @@ index 1673dd4966365f31f1073a4c90743e6fe73880b6..cb3d3da5bc9da99c950521d18f28aa43 using storage::BigIOBuffer; -@@ -43,7 +45,7 @@ constexpr char kSeparator[] = " \n"; - - // We always expect to receive valid URLs that can be used as keys to the code - // cache. The relevant checks (for ex: resource_url is valid, origin_lock is --// not opque etc.,) must be done prior to requesting the code cache. -+// not opaque etc.,) must be done prior to requesting the code cache. - // - // This function doesn't enforce anything in the production code. It is here - // to make the assumptions explicit and to catch any errors when DCHECKs are -@@ -53,33 +55,55 @@ void CheckValidKeys(const GURL& resource_url, - GeneratedCodeCache::CodeCacheType cache_type) { +@@ -53,40 +55,55 @@ void CheckValidResource(const GURL& resource_url, + GeneratedCodeCache::CodeCacheType cache_type) { // If the resource url is invalid don't cache the code. DCHECK(resource_url.is_valid()); - bool resource_url_is_chrome_or_chrome_untrusted = -+ + // There are 3 kind of URL scheme compatible for the `resource_url`. + // 1. http: and https: URLs. + // 2. chrome: and chrome-untrusted: URLs. @@ -51,20 +41,27 @@ index 1673dd4966365f31f1073a4c90743e6fe73880b6..cb3d3da5bc9da99c950521d18f28aa43 + const bool resource_url_webui = resource_url.SchemeIs(content::kChromeUIScheme) || resource_url.SchemeIs(content::kChromeUIUntrustedScheme); -- DCHECK(resource_url.SchemeIsHTTPOrHTTPS() || -- resource_url_is_chrome_or_chrome_untrusted || -- blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.scheme())); +- DCHECK( +- resource_url.SchemeIsHTTPOrHTTPS() || +- resource_url_is_chrome_or_chrome_untrusted || +- blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.GetScheme())); - +- // The chrome and chrome-untrusted schemes are only used with the WebUI +- // code cache type. +- DCHECK_EQ(resource_url_is_chrome_or_chrome_untrusted, +- cache_type == GeneratedCodeCache::kWebUIJavaScript); ++ const bool resource_url_embedder = ++ base::Contains(url::GetCodeCacheSchemes(), resource_url.GetScheme()); ++ DCHECK(resource_url_http || resource_url_webui || resource_url_embedder); + } + + void CheckValidContext(const GURL& origin_lock, + GeneratedCodeCache::CodeCacheType cache_type) { - // |origin_lock| should be either empty or should have - // Http/Https/chrome/chrome-untrusted schemes and it should not be a URL with - // opaque origin. Empty origin_locks are allowed when the renderer is not - // locked to an origin. - bool origin_lock_is_chrome_or_chrome_untrusted = -+ -+ const bool resource_url_embedder = -+ base::Contains(url::GetCodeCacheSchemes(), resource_url.scheme()); -+ DCHECK(resource_url_http || resource_url_webui || resource_url_embedder); -+ + // |origin_lock| should be either empty or should have code cache allowed + // schemes (http/https/chrome/chrome-untrusted or other custom schemes added + // by url::AddCodeCacheScheme), and it should not be a URL with opaque @@ -75,21 +72,20 @@ index 1673dd4966365f31f1073a4c90743e6fe73880b6..cb3d3da5bc9da99c950521d18f28aa43 + const bool origin_lock_for_webui = origin_lock.SchemeIs(content::kChromeUIScheme) || origin_lock.SchemeIs(content::kChromeUIUntrustedScheme); -- DCHECK( -- origin_lock.is_empty() || -- ((origin_lock.SchemeIsHTTPOrHTTPS() || -- origin_lock_is_chrome_or_chrome_untrusted || -- blink::CommonSchemeRegistry::IsExtensionScheme(origin_lock.scheme())) && -- !url::Origin::Create(origin_lock).opaque())); +- DCHECK(origin_lock.is_empty() || +- ((origin_lock.SchemeIsHTTPOrHTTPS() || +- origin_lock_is_chrome_or_chrome_untrusted || +- blink::CommonSchemeRegistry::IsExtensionScheme( +- origin_lock.GetScheme())) && +- !url::Origin::Create(origin_lock).opaque())); - - // The chrome and chrome-untrusted schemes are only used with the WebUI - // code cache type. - DCHECK_EQ(origin_lock_is_chrome_or_chrome_untrusted, - cache_type == GeneratedCodeCache::kWebUIJavaScript); -- DCHECK_EQ(resource_url_is_chrome_or_chrome_untrusted, -- cache_type == GeneratedCodeCache::kWebUIJavaScript); ++ + const bool origin_lock_for_embedder = -+ base::Contains(url::GetCodeCacheSchemes(), origin_lock.scheme()); ++ base::Contains(url::GetCodeCacheSchemes(), origin_lock.GetScheme()); + + DCHECK(origin_lock_empty || ((origin_lock_for_http || origin_lock_for_webui || + origin_lock_for_embedder) && @@ -100,16 +96,14 @@ index 1673dd4966365f31f1073a4c90743e6fe73880b6..cb3d3da5bc9da99c950521d18f28aa43 + case GeneratedCodeCache::kJavaScript: + case GeneratedCodeCache::kWebAssembly: + DCHECK(!origin_lock_for_webui); -+ DCHECK(!resource_url_webui); + break; + case GeneratedCodeCache::kWebUIJavaScript: + DCHECK(origin_lock_for_webui); -+ DCHECK(resource_url_webui); + break; + } + + // The custom schemes share the cache type with http(s). -+ if (origin_lock_for_embedder || resource_url_embedder) { ++ if (origin_lock_for_embedder) { + DCHECK(cache_type == GeneratedCodeCache::kJavaScript || + cache_type == GeneratedCodeCache::kWebAssembly); + } @@ -117,7 +111,7 @@ index 1673dd4966365f31f1073a4c90743e6fe73880b6..cb3d3da5bc9da99c950521d18f28aa43 // Generates the cache key for the given |resource_url|, |origin_lock| and diff --git a/content/browser/code_cache/generated_code_cache.h b/content/browser/code_cache/generated_code_cache.h -index 94602e2319d3f7ed557da98e0598c9f96d986260..0a9a856d8bd9d702eb49e45a54c141a39f5ec622 100644 +index a01f0d96ef33ce9460a851b072b7ceed5227dee3..f7e39b28cc0ba2251123925c01083a7935f46f56 100644 --- a/content/browser/code_cache/generated_code_cache.h +++ b/content/browser/code_cache/generated_code_cache.h @@ -51,12 +51,14 @@ class CONTENT_EXPORT GeneratedCodeCache { @@ -140,7 +134,7 @@ index 94602e2319d3f7ed557da98e0598c9f96d986260..0a9a856d8bd9d702eb49e45a54c141a3 // JavaScript from chrome and chrome-untrusted pages. The resource URLs are diff --git a/content/browser/code_cache/generated_code_cache_browsertest.cc b/content/browser/code_cache/generated_code_cache_browsertest.cc -index 28556e56f2fd591c46ce6f48d39eb907876a499d..f5737ba60fb9e182459066ffa62c7c589f379954 100644 +index fb3fdfca483ff5041ee98095af3f6ac2640adbaf..ada19d78ec1337b0c49a1597c877886f69f84f13 100644 --- a/content/browser/code_cache/generated_code_cache_browsertest.cc +++ b/content/browser/code_cache/generated_code_cache_browsertest.cc @@ -16,17 +16,22 @@ @@ -166,7 +160,7 @@ index 28556e56f2fd591c46ce6f48d39eb907876a499d..f5737ba60fb9e182459066ffa62c7c58 #include "net/base/features.h" #include "net/dns/mock_host_resolver.h" #include "third_party/blink/public/common/features.h" -@@ -37,6 +42,8 @@ namespace content { +@@ -38,6 +43,8 @@ namespace content { namespace { @@ -175,7 +169,7 @@ index 28556e56f2fd591c46ce6f48d39eb907876a499d..f5737ba60fb9e182459066ffa62c7c58 bool SupportsSharedWorker() { return base::FeatureList::IsEnabled(blink::features::kSharedWorker); } -@@ -1044,4 +1051,82 @@ IN_PROC_BROWSER_TEST_F(LocalCompileHintsBrowserTest, LocalCompileHints) { +@@ -1063,4 +1070,82 @@ IN_PROC_BROWSER_TEST_F(LocalCompileHintsBrowserTest, LocalCompileHints) { } } @@ -259,38 +253,38 @@ index 28556e56f2fd591c46ce6f48d39eb907876a499d..f5737ba60fb9e182459066ffa62c7c58 + } // namespace content diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc -index d95cba73aacf4b9156e8c0c3100abd7934369fdd..1583ae512e34c29e849efc2f570e09e74b348406 100644 +index 95134893c5eb6fa22b8e535a3495b2d4b3325447..71003cc065b579992dab4a781b696685cf506cce 100644 --- a/content/browser/renderer_host/code_cache_host_impl.cc +++ b/content/browser/renderer_host/code_cache_host_impl.cc -@@ -6,6 +6,7 @@ - +@@ -8,6 +8,7 @@ + #include <string_view> #include <utility> +#include "base/containers/contains.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_functions.h" -@@ -29,6 +30,7 @@ - #include "third_party/blink/public/common/scheme_registry.h" +@@ -36,6 +37,7 @@ + #include "third_party/blink/public/mojom/loader/code_cache.mojom-data-view.h" #include "url/gurl.h" #include "url/origin.h" +#include "url/url_util.h" using blink::mojom::CacheStorageError; -@@ -36,6 +38,11 @@ namespace content { - - namespace { +@@ -110,6 +112,11 @@ std::optional<std::string> GetContextKeyForPersistentCacheCollection( + return context_key; + } +bool ProcessLockURLIsCodeCacheScheme(const ProcessLock& process_lock) { + return base::Contains(url::GetCodeCacheSchemes(), -+ process_lock.lock_url().scheme()); ++ process_lock.GetProcessLockURL().scheme()); +} + bool CheckSecurityForAccessingCodeCacheData( const GURL& resource_url, int render_process_id, -@@ -46,39 +53,57 @@ bool CheckSecurityForAccessingCodeCacheData( +@@ -120,40 +127,56 @@ bool CheckSecurityForAccessingCodeCacheData( // Code caching is only allowed for http(s) and chrome/chrome-untrusted // scripts. Furthermore, there is no way for http(s) pages to load chrome or @@ -305,14 +299,14 @@ index d95cba73aacf4b9156e8c0c3100abd7934369fdd..1583ae512e34c29e849efc2f570e09e7 // suspicious activity. - if (resource_url.SchemeIs(content::kChromeUIScheme) || - resource_url.SchemeIs(content::kChromeUIUntrustedScheme)) { -- if (!process_lock.is_locked_to_site()) { +- if (!process_lock.IsLockedToSite()) { - // We can't tell for certain whether this renderer is doing something - // malicious, but we don't trust it enough to store data. - return false; - } + if (resource_url.SchemeIsHTTPOrHTTPS()) { - if (process_lock.matches_scheme(url::kHttpScheme) || - process_lock.matches_scheme(url::kHttpsScheme)) { + if (process_lock.MatchesScheme(url::kHttpScheme) || + process_lock.MatchesScheme(url::kHttpsScheme)) { - if (operation == CodeCacheHostImpl::Operation::kWrite) { + return true; + } @@ -327,15 +321,15 @@ index d95cba73aacf4b9156e8c0c3100abd7934369fdd..1583ae512e34c29e849efc2f570e09e7 + return false; + } + -+ if (resource_url.SchemeIs(kChromeUIScheme) || -+ resource_url.SchemeIs(kChromeUIUntrustedScheme)) { -+ if (process_lock.matches_scheme(kChromeUIScheme) || -+ process_lock.matches_scheme(kChromeUIUntrustedScheme)) { ++ if (resource_url.SchemeIs(content::kChromeUIScheme) || ++ resource_url.SchemeIs(content::kChromeUIUntrustedScheme)) { ++ if (process_lock.MatchesScheme(content::kChromeUIScheme) || ++ process_lock.MatchesScheme(content::kChromeUIUntrustedScheme)) { + return true; -+ } ++ } + if (operation == CodeCacheHostImpl::Operation::kWrite) { -+ if (process_lock.matches_scheme(url::kHttpScheme) || -+ process_lock.matches_scheme(url::kHttpsScheme)) { ++ if (process_lock.MatchesScheme(url::kHttpScheme) || ++ process_lock.MatchesScheme(url::kHttpsScheme)) { mojo::ReportBadMessage("HTTP(S) pages cannot cache WebUI code"); } + if (ProcessLockURLIsCodeCacheScheme(process_lock)) { @@ -348,35 +342,35 @@ index d95cba73aacf4b9156e8c0c3100abd7934369fdd..1583ae512e34c29e849efc2f570e09e7 // Other schemes which might successfully load chrome or chrome-untrusted // scripts, such as the PDF viewer, are unsupported but not considered - // dangerous. -- return process_lock.matches_scheme(content::kChromeUIScheme) || -- process_lock.matches_scheme(content::kChromeUIUntrustedScheme); +- return process_lock.MatchesScheme(content::kChromeUIScheme) || +- process_lock.MatchesScheme(content::kChromeUIUntrustedScheme); + // dangerous. Similarly, the process might not be locked to a site. + return false; } - if (resource_url.SchemeIsHTTPOrHTTPS() || -- blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.scheme())) { -- if (process_lock.matches_scheme(content::kChromeUIScheme) || -- process_lock.matches_scheme(content::kChromeUIUntrustedScheme)) { +- blink::CommonSchemeRegistry::IsExtensionScheme( +- resource_url.GetScheme())) { +- if (process_lock.MatchesScheme(content::kChromeUIScheme) || +- process_lock.MatchesScheme(content::kChromeUIUntrustedScheme)) { - // It is possible for WebUI pages to include open-web content, but such - // usage is rare and we've decided that reasoning about security is easier - // if the WebUI code cache includes only WebUI scripts. - return false; - } - return true; -+ -+ if (base::Contains(url::GetCodeCacheSchemes(), resource_url.scheme())) { ++ if (base::Contains(url::GetCodeCacheSchemes(), resource_url.GetScheme())) { + return ProcessLockURLIsCodeCacheScheme(process_lock); } if (operation == CodeCacheHostImpl::Operation::kWrite) { -@@ -433,6 +458,7 @@ std::optional<GURL> CodeCacheHostImpl::GetSecondaryKeyForCodeCache( - process_lock.matches_scheme(url::kHttpsScheme) || - process_lock.matches_scheme(content::kChromeUIScheme) || - process_lock.matches_scheme(content::kChromeUIUntrustedScheme) || +@@ -607,6 +630,7 @@ std::optional<GURL> CodeCacheHostImpl::GetSecondaryKeyForCodeCache( + process_lock.MatchesScheme(url::kHttpsScheme) || + process_lock.MatchesScheme(content::kChromeUIScheme) || + process_lock.MatchesScheme(content::kChromeUIUntrustedScheme) || + ProcessLockURLIsCodeCacheScheme(process_lock) || blink::CommonSchemeRegistry::IsExtensionScheme( - process_lock.lock_url().scheme())) { - return process_lock.lock_url(); + process_lock.GetProcessLockURL().GetScheme())) { + return process_lock.GetProcessLockURL(); diff --git a/content/common/url_schemes.cc b/content/common/url_schemes.cc index 225e017909b8869231b870eaaf161a0b5e93e2a0..846a5251429630b8528a84a3d67ed56cb28df5a1 100644 --- a/content/common/url_schemes.cc @@ -397,7 +391,7 @@ index 225e017909b8869231b870eaaf161a0b5e93e2a0..846a5251429630b8528a84a3d67ed56c if (schemes.allow_non_standard_schemes_in_origins) url::EnableNonStandardSchemesForAndroidWebView(); diff --git a/content/public/common/content_client.h b/content/public/common/content_client.h -index 52f16979b05b692ef72762d0cbc16bcb361b047e..b658ebeb9c572158b27d94af56331be8cbb519e6 100644 +index 33e2ff42e4d9da442d522b959a4a21c2f7032b6b..a0d81212327fc17e1f4704e78803c1d7d82b2016 100644 --- a/content/public/common/content_client.h +++ b/content/public/common/content_client.h @@ -139,6 +139,9 @@ class CONTENT_EXPORT ContentClient { @@ -411,7 +405,7 @@ index 52f16979b05b692ef72762d0cbc16bcb361b047e..b658ebeb9c572158b27d94af56331be8 std::vector<std::string> extension_schemes; // Registers a URL scheme with a predefined default custom handler. diff --git a/url/url_util.cc b/url/url_util.cc -index f77ce7f6de0a183debfdf272aa17c35c8307c480..54cbc57dc5217447cdf2895d6918e27001a39b7e 100644 +index 94cbe0bb382b4b64db390dcd6d725e13f54b6666..5c3949c01f27cab5e4f8a56bbbf11c0f9718eed2 100644 --- a/url/url_util.cc +++ b/url/url_util.cc @@ -136,6 +136,9 @@ struct SchemeRegistry { @@ -424,11 +418,11 @@ index f77ce7f6de0a183debfdf272aa17c35c8307c480..54cbc57dc5217447cdf2895d6918e270 // Schemes with a predefined default custom handler. std::vector<SchemeWithHandler> predefined_handler_schemes; -@@ -694,6 +697,15 @@ const std::vector<std::string>& GetEmptyDocumentSchemes() { +@@ -673,6 +676,15 @@ const std::vector<std::string>& GetEmptyDocumentSchemes() { return GetSchemeRegistry().empty_document_schemes; } -+void AddCodeCacheScheme(const char* new_scheme) { ++void AddCodeCacheScheme(const std::string_view new_scheme) { + DoAddScheme(new_scheme, + &GetSchemeRegistryWithoutLocking()->code_cache_schemes); +} @@ -437,15 +431,15 @@ index f77ce7f6de0a183debfdf272aa17c35c8307c480..54cbc57dc5217447cdf2895d6918e270 + return GetSchemeRegistry().code_cache_schemes; +} + - void AddPredefinedHandlerScheme(const char* new_scheme, const char* handler) { + void AddPredefinedHandlerScheme(std::string_view new_scheme, + std::string_view handler) { DoAddSchemeWithHandler( - new_scheme, handler, diff --git a/url/url_util.h b/url/url_util.h -index 50c273fe9c2007ec5ac6675726ce0ae9811af9e2..5f7352ff5eba9c548aaaea63f75e9551c81ce305 100644 +index 501baa71f6ec135827b505c2eca78c7e9ac0b8d3..10bf2c6e27dca530906ef7acb7ac43fa5c731d22 100644 --- a/url/url_util.h +++ b/url/url_util.h @@ -115,6 +115,15 @@ COMPONENT_EXPORT(URL) const std::vector<std::string>& GetCSPBypassingSchemes(); - COMPONENT_EXPORT(URL) void AddEmptyDocumentScheme(const char* new_scheme); + COMPONENT_EXPORT(URL) void AddEmptyDocumentScheme(std::string_view new_scheme); COMPONENT_EXPORT(URL) const std::vector<std::string>& GetEmptyDocumentSchemes(); +// Adds an application-defined scheme to the list of schemes that have V8 code @@ -454,7 +448,7 @@ index 50c273fe9c2007ec5ac6675726ce0ae9811af9e2..5f7352ff5eba9c548aaaea63f75e9551 +// they are treated as a separate cache type for security purpose. +// The http(s) schemes do not belong to this list neither, they always have V8 +// code cache enabled. -+COMPONENT_EXPORT(URL) void AddCodeCacheScheme(const char* new_scheme); ++COMPONENT_EXPORT(URL) void AddCodeCacheScheme(std::string_view new_scheme); +COMPONENT_EXPORT(URL) const std::vector<std::string>& GetCodeCacheSchemes(); + // Adds a scheme with a predefined default handler. diff --git a/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch b/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch index a7491a3747ab8..bb455382c6ec1 100644 --- a/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch +++ b/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch @@ -7,10 +7,10 @@ Subject: feat: allow embedders to add observers on created hunspell This patch is used by Electron to implement spellchecker events. diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc -index 3928d6fdbda8aac5fb89ab148adaa18218e135f8..4c52386f9ddf13f1453903cda3954b6c596028f2 100644 +index 592ef6e731e0539471408ad0ce5f089bfe2549be..f8a36ced14288698849cd5730309e29d47d3d1d4 100644 --- a/chrome/browser/spellchecker/spellcheck_service.cc +++ b/chrome/browser/spellchecker/spellcheck_service.cc -@@ -478,6 +478,8 @@ void SpellcheckService::LoadDictionaries() { +@@ -477,6 +477,8 @@ void SpellcheckService::LoadDictionaries() { std::make_unique<SpellcheckHunspellDictionary>( dictionary, platform_spellcheck_language, context_, this)); hunspell_dictionaries_.back()->AddObserver(this); @@ -19,7 +19,7 @@ index 3928d6fdbda8aac5fb89ab148adaa18218e135f8..4c52386f9ddf13f1453903cda3954b6c hunspell_dictionaries_.back()->Load(); } -@@ -532,6 +534,20 @@ bool SpellcheckService::IsSpellcheckEnabled() const { +@@ -527,6 +529,20 @@ bool SpellcheckService::IsSpellcheckEnabled() const { (!hunspell_dictionaries_.empty() || enable_if_uninitialized); } diff --git a/patches/chromium/feat_allow_passing_of_objecttemplate_to_objecttemplatebuilder.patch b/patches/chromium/feat_allow_passing_of_objecttemplate_to_objecttemplatebuilder.patch index b3f38261de488..8f27c60811032 100644 --- a/patches/chromium/feat_allow_passing_of_objecttemplate_to_objecttemplatebuilder.patch +++ b/patches/chromium/feat_allow_passing_of_objecttemplate_to_objecttemplatebuilder.patch @@ -10,10 +10,10 @@ Electron needs this constructor, namely for gin_helper::Constructible objects. diff --git a/gin/object_template_builder.cc b/gin/object_template_builder.cc -index a694f7dc4da4f1bba579ab8c032eea21d8459995..8aaaba327166b1d3b884fe390a389c0c50890af9 100644 +index 90966dc917099ae749118f3e740b76ff477cf92d..b84f5fd336bc4b61b2cd0b2fc92382b00e928701 100644 --- a/gin/object_template_builder.cc +++ b/gin/object_template_builder.cc -@@ -146,6 +146,13 @@ ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate, +@@ -144,6 +144,13 @@ ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate, template_->SetInternalFieldCount(kNumberOfInternalFields); } @@ -28,10 +28,10 @@ index a694f7dc4da4f1bba579ab8c032eea21d8459995..8aaaba327166b1d3b884fe390a389c0c const ObjectTemplateBuilder& other) = default; diff --git a/gin/object_template_builder.h b/gin/object_template_builder.h -index 9d8f6e5de793ea419875d99a0b46898f2e40ead5..c803363b8050f4084c9250fce9b5b8b171082703 100644 +index cf4f1ae6598fdede655d33baccda254965566ea5..a4c16dc0ec3ff16413fc2a04225a2401989a084b 100644 --- a/gin/object_template_builder.h +++ b/gin/object_template_builder.h -@@ -46,6 +46,9 @@ class GIN_EXPORT ObjectTemplateBuilder { +@@ -48,6 +48,9 @@ class GIN_EXPORT ObjectTemplateBuilder { public: explicit ObjectTemplateBuilder(v8::Isolate* isolate); ObjectTemplateBuilder(v8::Isolate* isolate, const char* type_name); diff --git a/patches/chromium/feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch b/patches/chromium/feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch index f5e7abc1fb76d..98118597066f3 100644 --- a/patches/chromium/feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch +++ b/patches/chromium/feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch @@ -7,10 +7,10 @@ This is implemented as a magic "window id" that instead of pulling an SCStream m instead farms out to the screen picker. diff --git a/content/browser/media/capture/desktop_capture_device_mac.cc b/content/browser/media/capture/desktop_capture_device_mac.cc -index afb657b7c9e1ede1273532b16428d37cc5d75c59..16707cf516cd34682c84ea2ccebddaa0f84e01f8 100644 +index 120590a93bbc5a47e73c5d5515b7ad07b2364eb6..50a8b0dfe5400d1ab9da2893088583e4f815a140 100644 --- a/content/browser/media/capture/desktop_capture_device_mac.cc +++ b/content/browser/media/capture/desktop_capture_device_mac.cc -@@ -29,7 +29,7 @@ class DesktopCaptureDeviceMac : public IOSurfaceCaptureDeviceBase { +@@ -28,7 +28,7 @@ class DesktopCaptureDeviceMac : public IOSurfaceCaptureDeviceBase { ~DesktopCaptureDeviceMac() override = default; // IOSurfaceCaptureDeviceBase: @@ -46,7 +46,7 @@ index e2771b7b281274cdcb601a5bc78a948ad592087b..48d116823a28213e50775f378e6ce04c // OnStop is called by StopAndDeAllocate. virtual void OnStop() = 0; diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm -index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b4049610fd49da 100644 +index c2d8bbafa39c05f25641f2fd3491ef7f84f4f6a1..5506583824e10d664f32c71d63fda1aabccbdd31 100644 --- a/content/browser/media/capture/screen_capture_kit_device_mac.mm +++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm @@ -27,6 +27,61 @@ @@ -134,19 +134,16 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 _errorCallback = errorCallback; } return self; -@@ -211,29 +270,53 @@ + (SCStreamConfiguration*)streamConfigurationWithFrameSize:(gfx::Size)frameSize +@@ -224,28 +283,50 @@ class API_AVAILABLE(macos(12.3)) ScreenCaptureKitDeviceMac + base::OnceCallback<void(content::DesktopMediaID::Id, SCStream*)>; - class API_AVAILABLE(macos(12.3)) ScreenCaptureKitDeviceMac - : public IOSurfaceCaptureDeviceBase, -- public ScreenCaptureKitResetStreamInterface { -+ public ScreenCaptureKitResetStreamInterface -+ { - public: explicit ScreenCaptureKitDeviceMac(const DesktopMediaID& source, -- SCContentFilter* filter) -+ [[maybe_unused]] SCContentFilter* filter) +- SCContentFilter* filter, ++ [[maybe_unused]] SCContentFilter* filter, + StreamCallback stream_created_callback) : source_(source), - filter_(filter), + stream_created_callback_(std::move(stream_created_callback)), device_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) { SampleCallback sample_callback = base::BindPostTask( device_task_runner_, @@ -164,7 +161,6 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 initWithSampleCallback:sample_callback + cancelCallback:cancel_callback errorCallback:error_callback]; -+ + if (@available(macOS 15.0, *)) { + auto picker_callback = base::BindPostTask( + device_task_runner_, @@ -192,7 +188,7 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 void OnShareableContentCreated(SCShareableContent* content) { DCHECK(device_task_runner_->RunsTasksInCurrentSequence()); -@@ -301,7 +384,7 @@ void CreateStream(SCContentFilter* filter) { +@@ -313,7 +394,7 @@ void CreateStream(SCContentFilter* filter) { return; } @@ -201,7 +197,7 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 // Update the content size. This step is neccessary when used together // with SCContentSharingPicker. If the Chrome picker is used, it will // change to retina resolution if applicable. -@@ -310,6 +393,9 @@ void CreateStream(SCContentFilter* filter) { +@@ -322,6 +403,9 @@ void CreateStream(SCContentFilter* filter) { filter.contentRect.size.height * filter.pointPixelScale); } @@ -211,7 +207,7 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 gfx::RectF dest_rect_in_frame; actual_capture_format_ = capture_params().requested_format; actual_capture_format_.pixel_format = media::PIXEL_FORMAT_NV12; -@@ -323,6 +409,7 @@ void CreateStream(SCContentFilter* filter) { +@@ -335,6 +419,7 @@ void CreateStream(SCContentFilter* filter) { stream_ = [[SCStream alloc] initWithFilter:filter configuration:config delegate:helper_]; @@ -219,7 +215,7 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 { NSError* error = nil; bool add_stream_output_result = -@@ -480,7 +567,7 @@ void OnStreamError() { +@@ -495,7 +580,7 @@ void OnStreamError() { if (fullscreen_module_) { fullscreen_module_->Reset(); } @@ -228,7 +224,7 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 } else { client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError, FROM_HERE, "Stream delegate called didStopWithError"); -@@ -503,23 +590,41 @@ void OnUpdateConfigurationError() { +@@ -518,23 +603,41 @@ void OnUpdateConfigurationError() { } // IOSurfaceCaptureDeviceBase: @@ -285,18 +281,16 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 } void OnStop() override { DCHECK(device_task_runner_->RunsTasksInCurrentSequence()); -@@ -577,8 +682,9 @@ void ResetStreamTo(SCWindow* window) override { - } +@@ -593,7 +696,7 @@ void ResetStreamTo(SCWindow* window) override { private: -+ static int active_streams_; -+ const DesktopMediaID source_; - SCContentFilter* const filter_; ++ static int active_streams_; + StreamCallback stream_created_callback_; const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; - // The actual format of the video frames that are sent to `client`. -@@ -594,6 +700,10 @@ void ResetStreamTo(SCWindow* window) override { +@@ -610,6 +713,10 @@ void ResetStreamTo(SCWindow* window) override { // Helper class that acts as output and delegate for `stream_`. ScreenCaptureKitDeviceHelper* __strong helper_; @@ -307,7 +301,7 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 // This is used to detect when a captured presentation enters fullscreen mode. // If this happens, the module will call the ResetStreamTo function. std::unique_ptr<ScreenCaptureKitFullscreenModule> fullscreen_module_; -@@ -606,6 +716,8 @@ void ResetStreamTo(SCWindow* window) override { +@@ -622,6 +729,8 @@ void ResetStreamTo(SCWindow* window) override { base::WeakPtrFactory<ScreenCaptureKitDeviceMac> weak_factory_{this}; }; @@ -317,10 +311,10 @@ index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b40496 // Although ScreenCaptureKit is available in 12.3 there were some bugs that diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc -index a5bc6f63c771fdf68ed9251285eac9d2c91acdc0..f719ff68e18093791bf13e434f40a3d1a9626dca 100644 +index 2f871f0ef51e49d1f78e56b125bbf721dd3562e2..02da1596d4f1251f8e8a8bcba0b9372feb066647 100644 --- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc +++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc -@@ -321,8 +321,16 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync( +@@ -316,8 +316,16 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync( break; } @@ -338,7 +332,7 @@ index a5bc6f63c771fdf68ed9251285eac9d2c91acdc0..f719ff68e18093791bf13e434f40a3d1 // For the other capturers, when a bug reports the type of capture it's // easy enough to determine which capturer was used, but it's a little // fuzzier with window capture. -@@ -338,13 +346,15 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync( +@@ -333,13 +341,15 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync( } #endif // defined(USE_AURA) || BUILDFLAG(IS_MAC) @@ -356,10 +350,10 @@ index a5bc6f63c771fdf68ed9251285eac9d2c91acdc0..f719ff68e18093791bf13e434f40a3d1 kMaxNumberOfBuffers, std::move(receiver), std::move(receiver_on_io_thread)), diff --git a/content/public/browser/desktop_media_id.h b/content/public/browser/desktop_media_id.h -index 294b5f79955ba72976f8ba127fd19556c81e322c..27553e51b281575c5cb7a4ba4dab06d19704388e 100644 +index b10c5376caa9a832826868c72dbc44ee54705283..e9b27b53d9b34fbb0a3410eb2fcc15306497cdf4 100644 --- a/content/public/browser/desktop_media_id.h +++ b/content/public/browser/desktop_media_id.h -@@ -27,6 +27,8 @@ struct CONTENT_EXPORT DesktopMediaID { +@@ -28,6 +28,8 @@ struct CONTENT_EXPORT DesktopMediaID { static constexpr Id kNullId = 0; // Represents a fake id to create a dummy capturer for autotests. static constexpr Id kFakeId = -3; @@ -369,13 +363,13 @@ index 294b5f79955ba72976f8ba127fd19556c81e322c..27553e51b281575c5cb7a4ba4dab06d1 #if defined(USE_AURA) || BUILDFLAG(IS_MAC) // Assigns integer identifier to the |window| and returns its DesktopMediaID. diff --git a/media/capture/video_capture_types.h b/media/capture/video_capture_types.h -index 53e8077c9c0b635df0abdeca43fa9a6373c68252..2805e36cc42190d8197d83f5df235094570e3d5d 100644 +index 092bd4524b81734d1b428ab0b201887d411f8277..d0300a4b1a2265d1db977b9bf0ffdd6d0a9d9d37 100644 --- a/media/capture/video_capture_types.h +++ b/media/capture/video_capture_types.h -@@ -355,6 +355,8 @@ struct CAPTURE_EXPORT VideoCaptureParams { - // Flag indicating whether HiDPI mode should be enabled for tab capture - // sessions. - bool is_high_dpi_enabled = true; +@@ -365,6 +365,8 @@ struct CAPTURE_EXPORT VideoCaptureParams { + // of the capture is dynamically changed, as for example when using + // share-this-tab-instead. + uint32_t capture_version_source = 0; + + std::optional<bool> use_native_picker; }; diff --git a/patches/chromium/feat_configure_launch_options_for_service_process.patch b/patches/chromium/feat_configure_launch_options_for_service_process.patch index 0b2ab620f7343..74b5c390382a1 100644 --- a/patches/chromium/feat_configure_launch_options_for_service_process.patch +++ b/patches/chromium/feat_configure_launch_options_for_service_process.patch @@ -19,7 +19,7 @@ to STDOUT_FILENO/STD_OUTPUT_HANDLE and STDERR_FILENO/STD_ERROR_HANDLE allowing t parent process to read from the pipe. diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h -index 0a7e292f77a30f76eb413785551d7fa57acf1799..091628a0dd3ca9b4bdf06d484595342bc70e4427 100644 +index 0a47fb58e86d57d6cec3784d3b163c59592b585e..d2877fdd3bcff75248bad6a0462233cde82a104c 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h @@ -33,6 +33,7 @@ @@ -30,7 +30,7 @@ index 0a7e292f77a30f76eb413785551d7fa57acf1799..091628a0dd3ca9b4bdf06d484595342b #endif #if BUILDFLAG(IS_POSIX) -@@ -197,7 +198,10 @@ struct ChildProcessLauncherFileData { +@@ -194,7 +195,10 @@ struct ChildProcessLauncherFileData { delete; ~ChildProcessLauncherFileData(); @@ -42,7 +42,7 @@ index 0a7e292f77a30f76eb413785551d7fa57acf1799..091628a0dd3ca9b4bdf06d484595342b // Files opened by the browser and passed as corresponding file descriptors // in the child process. If a FilePath is provided, the file will be opened // and the descriptor cached for future process launches. If a ScopedFD is -@@ -212,6 +216,15 @@ struct ChildProcessLauncherFileData { +@@ -209,6 +213,15 @@ struct ChildProcessLauncherFileData { std::map<std::string, std::variant<base::FilePath, base::ScopedFD>> files_to_preload; #endif @@ -187,10 +187,10 @@ index d9c14f91747bde0e76056d7f2f2ada166e67f994..53be16879777a3b9bef58ead5f7e420c UtilityProcessHost::Start(std::move(utility_options), diff --git a/content/browser/service_host/utility_process_host.cc b/content/browser/service_host/utility_process_host.cc -index ab48c8b88a7cf311205b221169308d96e95f239f..d714d2022f685052e1def3b0d242d2ea596d790b 100644 +index c798b3394db7638e38613a016c2dbb0bfcf54d03..1298ea85a176db2150a4101afc205745f32eb8f5 100644 --- a/content/browser/service_host/utility_process_host.cc +++ b/content/browser/service_host/utility_process_host.cc -@@ -245,13 +245,13 @@ UtilityProcessHost::Options& UtilityProcessHost::Options::WithFileToPreload( +@@ -241,13 +241,13 @@ UtilityProcessHost::Options& UtilityProcessHost::Options::WithFileToPreload( } #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) @@ -207,7 +207,7 @@ index ab48c8b88a7cf311205b221169308d96e95f239f..d714d2022f685052e1def3b0d242d2ea #if BUILDFLAG(USE_ZYGOTE) UtilityProcessHost::Options& UtilityProcessHost::Options::WithZygoteForTesting( -@@ -261,6 +261,36 @@ UtilityProcessHost::Options& UtilityProcessHost::Options::WithZygoteForTesting( +@@ -257,6 +257,36 @@ UtilityProcessHost::Options& UtilityProcessHost::Options::WithZygoteForTesting( } #endif // BUILDFLAG(USE_ZYGOTE) @@ -244,7 +244,7 @@ index ab48c8b88a7cf311205b221169308d96e95f239f..d714d2022f685052e1def3b0d242d2ea UtilityProcessHost::Options& UtilityProcessHost::Options::WithBoundReceiverOnChildProcessForTesting( mojo::GenericPendingReceiver receiver) { -@@ -525,9 +555,26 @@ bool UtilityProcessHost::StartProcess() { +@@ -520,9 +550,26 @@ bool UtilityProcessHost::StartProcess() { } #endif // BUILDFLAG(ENABLE_GPU_CHANNEL_MEDIA_CAPTURE) && !BUILDFLAG(IS_WIN) @@ -348,10 +348,10 @@ index 580fa663e729a43bef44a10de8983c4aecc312fb..f39af3df87786a472f987309ac0dea69 // Whether or not to bind viz::mojom::Gpu to the utility process. bool allowed_gpu_; diff --git a/content/browser/service_host/utility_sandbox_delegate.cc b/content/browser/service_host/utility_sandbox_delegate.cc -index 8f89c28144e1ecf3d7dbf9a3b43031cbad12a8ea..faa49bb63bd2e9080da441286bdbf427f22cd26f 100644 +index ffa237864328e19868ed0d29590981e972cae9fb..877318c5158a3cd48ff23aa05d3570ff7bb01a6b 100644 --- a/content/browser/service_host/utility_sandbox_delegate.cc +++ b/content/browser/service_host/utility_sandbox_delegate.cc -@@ -43,17 +43,19 @@ UtilitySandboxedProcessLauncherDelegate:: +@@ -39,17 +39,19 @@ UtilitySandboxedProcessLauncherDelegate:: UtilitySandboxedProcessLauncherDelegate( sandbox::mojom::Sandbox sandbox_type, const base::EnvironmentMap& env, @@ -375,7 +375,7 @@ index 8f89c28144e1ecf3d7dbf9a3b43031cbad12a8ea..faa49bb63bd2e9080da441286bdbf427 #if DCHECK_IS_ON() bool supported_sandbox_type = sandbox_type_ == sandbox::mojom::Sandbox::kNoSandbox || -@@ -121,11 +123,28 @@ UtilitySandboxedProcessLauncherDelegate::GetSandboxType() { +@@ -111,11 +113,28 @@ UtilitySandboxedProcessLauncherDelegate::GetSandboxType() { return sandbox_type_; } @@ -707,10 +707,10 @@ index c5fee4ad8b246bc1113a383794c6101bade24df3..61f0a0f62795b30105c42da363205284 #if BUILDFLAG(IS_MAC) // Whether or not to disclaim TCC responsibility for the process, defaults to diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc -index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a305966c6833c4 100644 +index a2ceae2b3ef9f9586cd4ef068d75aeedf5d64905..dd8a2e0be806ecf0c0ff1286b8fc3cf85ab0161b 100644 --- a/sandbox/policy/win/sandbox_win.cc +++ b/sandbox/policy/win/sandbox_win.cc -@@ -588,11 +588,9 @@ base::win::ScopedHandle CreateUnsandboxedJob() { +@@ -605,11 +605,9 @@ base::win::ScopedHandle CreateUnsandboxedJob() { // command line flag. ResultCode LaunchWithoutSandbox( const base::CommandLine& cmd_line, @@ -723,7 +723,7 @@ index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a30596 options.feedback_cursor_off = true; // Network process runs in a job even when unsandboxed. This is to ensure it // does not outlive the browser, which could happen if there is a lot of I/O -@@ -895,7 +893,7 @@ bool SandboxWin::InitTargetServices(TargetServices* target_services) { +@@ -910,7 +908,7 @@ bool SandboxWin::InitTargetServices(TargetServices* target_services) { // static ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( const base::CommandLine& cmd_line, @@ -732,7 +732,7 @@ index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a30596 SandboxDelegate* delegate, TargetPolicy* policy) { const base::CommandLine& launcher_process_command_line = -@@ -909,7 +907,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( +@@ -924,7 +922,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( } // Add any handles to be inherited to the policy. @@ -741,7 +741,7 @@ index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a30596 policy->AddHandleToShare(handle); if (!policy->GetConfig()->IsConfigured()) { -@@ -924,6 +922,13 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( +@@ -939,6 +937,13 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( // have no effect. These calls can fail with SBOX_ERROR_BAD_PARAMS. policy->SetStdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE)); policy->SetStderrHandle(GetStdHandle(STD_ERROR_HANDLE)); @@ -755,7 +755,7 @@ index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a30596 #endif if (!delegate->PreSpawnTarget(policy)) -@@ -935,7 +940,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( +@@ -950,7 +955,7 @@ ResultCode SandboxWin::GeneratePolicyForSandboxedProcess( // static ResultCode SandboxWin::StartSandboxedProcess( const base::CommandLine& cmd_line, @@ -764,7 +764,7 @@ index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a30596 SandboxDelegate* delegate, StartSandboxedProcessCallback result_callback) { SandboxLaunchTimer timer; -@@ -945,7 +950,7 @@ ResultCode SandboxWin::StartSandboxedProcess( +@@ -960,7 +965,7 @@ ResultCode SandboxWin::StartSandboxedProcess( *base::CommandLine::ForCurrentProcess())) { base::Process process; ResultCode result = @@ -773,7 +773,7 @@ index a0a8545a9c967f1059119cf3dda849fa7d96cb15..3a3a9c1e2fa3ad88eaf721da75a30596 DWORD last_error = GetLastError(); std::move(result_callback).Run(std::move(process), last_error, result); return SBOX_ALL_OK; -@@ -955,7 +960,7 @@ ResultCode SandboxWin::StartSandboxedProcess( +@@ -970,7 +975,7 @@ ResultCode SandboxWin::StartSandboxedProcess( timer.OnPolicyCreated(); ResultCode result = GeneratePolicyForSandboxedProcess( diff --git a/patches/chromium/feat_corner_smoothing_css_rule_and_blink_painting.patch b/patches/chromium/feat_corner_smoothing_css_rule_and_blink_painting.patch index 7e9677b92b07e..e3b3ff9446bd3 100644 --- a/patches/chromium/feat_corner_smoothing_css_rule_and_blink_painting.patch +++ b/patches/chromium/feat_corner_smoothing_css_rule_and_blink_painting.patch @@ -20,7 +20,7 @@ making three primary changes to Blink: * Controls whether the CSS rule is available. diff --git a/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom -index bb284c62d1d0dcd693bcb092044e6723bb339258..3c754cf37c18d0d17dc27e184ba5e8c5ebf8bdae 100644 +index e8b4cb12e28b62f3955810e47e590cb7fcba60f0..bff96df0400accdb6738701e1c41070cca64e73f 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom @@ -48,6 +48,7 @@ enum CSSSampleId { @@ -45,10 +45,10 @@ index e189d584f05f2ce6354c03a9b19f56985df8a15e..41b430e8f2416be098494f5c49fb97ca 'internal-forced-visited-'): internal_visited_order = 0 diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 -index 27e52d4fd24d575fded2016a720d4587d5fb1998..e39ad72d2d3e56ff918f3274be86633e930fd24f 100644 +index a163c1a0790cb8deb4b09f6605876c24a4f79b64..a9a0548173ac9c903a208e4ef142a14a8506693f 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5 -@@ -8966,6 +8966,26 @@ +@@ -9153,6 +9153,26 @@ property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"], }, @@ -76,10 +76,10 @@ index 27e52d4fd24d575fded2016a720d4587d5fb1998..e39ad72d2d3e56ff918f3274be86633e { name: "-internal-visited-color", diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc -index 687332cf68b3b826d7dcbd5dc10d47f0cd7ce688..653bbb8aef7e6edb31d63b02a9799d5454ce8d57 100644 +index 1bff2c29379c4a1c1022440ce3d0048e08f63bd9..72b8c6f6c75a4c5d7455fa12180e574eb724a905 100644 --- a/third_party/blink/renderer/core/css/css_property_equality.cc +++ b/third_party/blink/renderer/core/css/css_property_equality.cc -@@ -352,6 +352,8 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property, +@@ -354,6 +354,8 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property, return a.DominantBaseline() == b.DominantBaseline(); case CSSPropertyID::kDynamicRangeLimit: return a.GetDynamicRangeLimit() == b.GetDynamicRangeLimit(); @@ -89,10 +89,10 @@ index 687332cf68b3b826d7dcbd5dc10d47f0cd7ce688..653bbb8aef7e6edb31d63b02a9799d54 return a.EmptyCells() == b.EmptyCells(); case CSSPropertyID::kFill: diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc -index 8833941b927a076a73336b5d651c033258c13793..525f2303efbe9222567a1bbcdbc7321d5d93048f 100644 +index 4d9c0422443a98ab9226f8b0f580a67cc3e41ff3..9be2a613df6e1ab4ebe1bf6929aed767d46dd753 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc -@@ -12289,5 +12289,36 @@ const CSSValue* InternalEmptyLineHeight::ParseSingleValue( +@@ -12628,5 +12628,36 @@ const CSSValue* InternalEmptyLineHeight::ParseSingleValue( CSSValueID::kNone>(stream); } @@ -130,10 +130,10 @@ index 8833941b927a076a73336b5d651c033258c13793..525f2303efbe9222567a1bbcdbc7321d } // namespace css_longhand } // namespace blink diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc -index 7a5a5e370daea769e710f56a8004d79efa721268..4ba371436c33049952d919dc734be835dfbc783a 100644 +index 4c4a4ca1c5d0d9ebfc361323bf932b2c36de9c49..e350bb786146ade7991422fc8f8c640daa7ea2a8 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc -@@ -4022,6 +4022,15 @@ PositionTryFallback StyleBuilderConverter::ConvertSinglePositionTryFallback( +@@ -4119,6 +4119,15 @@ PositionTryFallback StyleBuilderConverter::ConvertSinglePositionTryFallback( return PositionTryFallback(scoped_name, tactic_list); } @@ -150,13 +150,13 @@ index 7a5a5e370daea769e710f56a8004d79efa721268..4ba371436c33049952d919dc734be835 const CSSValue& value) { const auto& list = To<CSSValueList>(value); diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h -index 6b801bce099cf7311d487e3fae5065cb11529ca7..4e1c37274e29144a769a5a4916b07d4fa8b86e1d 100644 +index 4b08af59fc8e4b2721e343d0dbf3270c0df24326..052435ac938069a734f5bbb984006c5d6b9b19b2 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h -@@ -434,6 +434,7 @@ class StyleBuilderConverter { - static PositionTryFallback ConvertSinglePositionTryFallback( +@@ -448,6 +448,7 @@ class StyleBuilderConverter { StyleResolverState&, - const CSSValue&); + const CSSValue&, + bool allow_any_keyword_in_position_area = false); + static Length ConvertCornerSmoothing(StyleResolverState&, const CSSValue&); static FitText ConvertFitText(StyleResolverState&, const CSSValue&); static TextOverflowData ConvertTextOverflow(StyleResolverState&, @@ -201,10 +201,10 @@ index 0802c73aa4aaf4e1fb5efd367758f19c36691f71..5f06c0af277a7c937e694470beac707a return result; } diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn -index 4c0ab9ea098c76063ece82ee79e4fb6465f822c8..2eaf538e48407a4cb12d1509e012f41847c716f2 100644 +index 244fb5832fde6b71b59dbb7f6c83256c4ced7318..b12c3a23afecc024e9d60354d9d43ea000b1ee35 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn -@@ -1659,6 +1659,8 @@ component("platform") { +@@ -1671,6 +1671,8 @@ component("platform") { "widget/widget_base.h", "widget/widget_base_client.h", "windows_keyboard_codes.h", @@ -214,7 +214,7 @@ index 4c0ab9ea098c76063ece82ee79e4fb6465f822c8..2eaf538e48407a4cb12d1509e012f418 sources -= blink_platform_avx_files diff --git a/third_party/blink/renderer/platform/geometry/contoured_rect.h b/third_party/blink/renderer/platform/geometry/contoured_rect.h -index 59031b23d3c50aa87db48a5c5a66c5ab04a8103a..1f83cf0dff83d748bf1caafd3685202c14a3aaed 100644 +index 65bd093f56eafc7dac2cd51f9d32f5c2879cb2ea..9a56422bcef24d8fcbfa24a7ff4626c670f1491b 100644 --- a/third_party/blink/renderer/platform/geometry/contoured_rect.h +++ b/third_party/blink/renderer/platform/geometry/contoured_rect.h @@ -52,19 +52,29 @@ class PLATFORM_EXPORT ContouredRect { @@ -267,7 +267,7 @@ index 59031b23d3c50aa87db48a5c5a66c5ab04a8103a..1f83cf0dff83d748bf1caafd3685202c // A Corner is a axis-aligned quad, with the points ordered (start, outer, diff --git a/third_party/blink/renderer/platform/geometry/path_builder.cc b/third_party/blink/renderer/platform/geometry/path_builder.cc -index 7e3d46902fbf736b4240eb3fcb89975a7b222197..57fdc89fc265ad70cb0bff8443cc10268d154ed9 100644 +index 1d6b8160e8db2a94ee61ed41ac9a74db5b1bfb17..373bcd30c6a4526262912021aaf2b560fedc3667 100644 --- a/third_party/blink/renderer/platform/geometry/path_builder.cc +++ b/third_party/blink/renderer/platform/geometry/path_builder.cc @@ -4,6 +4,7 @@ @@ -278,7 +278,7 @@ index 7e3d46902fbf736b4240eb3fcb89975a7b222197..57fdc89fc265ad70cb0bff8443cc1026 #include "third_party/blink/renderer/platform/geometry/contoured_rect.h" #include "third_party/blink/renderer/platform/geometry/infinite_int_rect.h" #include "third_party/blink/renderer/platform/geometry/path.h" -@@ -244,6 +245,32 @@ PathBuilder& PathBuilder::AddContouredRect( +@@ -250,6 +251,32 @@ PathBuilder& PathBuilder::AddContouredRect( AddRoundedRect(target_rect); return *this; } @@ -312,7 +312,7 @@ index 7e3d46902fbf736b4240eb3fcb89975a7b222197..57fdc89fc265ad70cb0bff8443cc1026 auto DrawAsSinglePath = [&]() { diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 -index e58bd2c672fcfd68b7dbc0c861d5be1d2a099e97..7dbe46a7390a988c21b2fbfbd5fbb3a3e822b7f5 100644 +index a5dcd4c68acab6c6a294ababf5527496faec792e..463c97dbf245b1e57e2de5e5131044d89bbcdcd0 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5 @@ -214,6 +214,10 @@ @@ -324,5 +324,5 @@ index e58bd2c672fcfd68b7dbc0c861d5be1d2a099e97..7dbe46a7390a988c21b2fbfbd5fbb3a3 + status: "stable", + }, { - name: "Accelerated2dCanvas", - settable_from_internals: true, + // crbug.com/439682405 + name: "AbortByPlaceholderLayout", diff --git a/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch b/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch index d8f1258346eec..d8a38996d00b9 100644 --- a/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch +++ b/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch @@ -39,7 +39,7 @@ index aed835411f5728c5685baa43eda2dd1585119b18..0e66085b1c457c1f1f6be241c7d331d7 gpu::SurfaceHandle child_window) { NOTREACHED(); diff --git a/components/viz/host/host_display_client.h b/components/viz/host/host_display_client.h -index 9e94f648060e9873a120f2c45591ad599a2e62df..93dabe09e44bda68644dcab568a827a92c550e4a 100644 +index 07fe1ea0e8e5f28428a164eedc28d4e5150ab13b..1a20c4b5765ce504c64c0dabfe3080fb65dbc03d 100644 --- a/components/viz/host/host_display_client.h +++ b/components/viz/host/host_display_client.h @@ -39,6 +39,9 @@ class VIZ_HOST_EXPORT HostDisplayClient : public mojom::DisplayClient { @@ -62,7 +62,7 @@ index 9e94f648060e9873a120f2c45591ad599a2e62df..93dabe09e44bda68644dcab568a827a9 #endif diff --git a/components/viz/host/layered_window_updater_impl.cc b/components/viz/host/layered_window_updater_impl.cc -index 8f726bde2cb5da6acfe630006af0fc3a09811d6c..45d8cae3ba0fca9a1514f83032a10c8820b3126d 100644 +index 36b9e09ca63aeec83c381918be2dbc933611e6ee..e58cb70d07cc61478bbd4e9a0233a11af6148c20 100644 --- a/components/viz/host/layered_window_updater_impl.cc +++ b/components/viz/host/layered_window_updater_impl.cc @@ -46,7 +46,9 @@ void LayeredWindowUpdaterImpl::OnAllocatedSharedMemory( @@ -90,11 +90,11 @@ index 8af69cac78b7488d28f1f05ccb174793fe5148cd..9f74e511c263d147b5fbe81fe100d217 private: const HWND hwnd_; diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn -index de0ed691367bda45e5310b1f132171e3a1f2dd3f..53848189bc02cd73446409667ad918e456727ce9 100644 +index 9af007dfc14e442d34ebe82fc678ea9f32782cdf..850f8627170b4de652b2975f47d7bc48458d8ed7 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn -@@ -174,6 +174,8 @@ viz_component("service") { - "display_embedder/skia_output_surface_impl_on_gpu_debug_capture.h", +@@ -176,6 +176,8 @@ viz_component("service") { + "display_embedder/skia_output_surface_shared_image_interface.h", "display_embedder/skia_render_copy_results.cc", "display_embedder/skia_render_copy_results.h", + "display_embedder/software_output_device_proxy.cc", @@ -180,7 +180,7 @@ index 07502f4ff2afd53a43d8f0ab68d4c4c39f6c0737..20d51f86d5084edf0b05ce0ab11fcd12 HWND child_hwnd; auto device = CreateSoftwareOutputDeviceWin( diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.h b/components/viz/service/display_embedder/output_surface_provider_impl.h -index e4b46a79560e7698a6400b2ab8a57f38205a8718..3cb2518c6644cf0618f625d981befd466a3dfb2c 100644 +index f49bbc5d568f0cb323a22997a949e2cae8f35d59..c0154ee828e67b197eb2ddb1abf04c0aede0d264 100644 --- a/components/viz/service/display_embedder/output_surface_provider_impl.h +++ b/components/viz/service/display_embedder/output_surface_provider_impl.h @@ -54,7 +54,8 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl @@ -238,10 +238,10 @@ index 67d5ff67d74c107a867b39b306c6528425b87e05..5fd12a25c9e319e8e675955926271c9d diff --git a/components/viz/service/display_embedder/software_output_device_proxy.cc b/components/viz/service/display_embedder/software_output_device_proxy.cc new file mode 100644 -index 0000000000000000000000000000000000000000..ef5cb8ae4c398e5834496c8b24eb98c41b10a7b3 +index 0000000000000000000000000000000000000000..601e646c293ac18e692663642f540577168924d6 --- /dev/null +++ b/components/viz/service/display_embedder/software_output_device_proxy.cc -@@ -0,0 +1,162 @@ +@@ -0,0 +1,161 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. @@ -252,7 +252,7 @@ index 0000000000000000000000000000000000000000..ef5cb8ae4c398e5834496c8b24eb98c4 +#include "base/threading/thread_checker.h" +#include "base/trace_event/trace_event.h" +#include "build/build_config.h" -+#include "components/viz/common/resources/resource_sizes.h" ++#include "components/viz/common/resources/shared_image_format_utils.h" +#include "mojo/public/cpp/system/platform_handle.h" +#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h" +#include "skia/ext/platform_canvas.h" @@ -262,7 +262,7 @@ index 0000000000000000000000000000000000000000..ef5cb8ae4c398e5834496c8b24eb98c4 +#if BUILDFLAG(IS_WIN) +#include "components/viz/service/display_embedder/output_device_backing.h" +#include "skia/ext/skia_utils_win.h" -+#include "ui/gfx/gdi_util.h" ++#include "ui/gfx/win/gdi_util.h" +#include "ui/gfx/win/hwnd_util.h" +#else +#include "mojo/public/cpp/base/shared_memory_utils.h" @@ -337,18 +337,17 @@ index 0000000000000000000000000000000000000000..ef5cb8ae4c398e5834496c8b24eb98c4 +void SoftwareOutputDeviceProxy::ResizeDelegated() { + canvas_.reset(); + -+ size_t required_bytes; -+ if (!ResourceSizes::MaybeSizeInBytes(viewport_pixel_size_, -+ SinglePlaneFormat::kRGBA_8888, -+ &required_bytes)) { ++ auto required_bytes = SharedMemorySizeForSharedImageFormat( ++ SinglePlaneFormat::kRGBA_8888, viewport_pixel_size_); ++ if (!required_bytes) { + DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString(); + return; + } + + base::UnsafeSharedMemoryRegion region = -+ base::UnsafeSharedMemoryRegion::Create(required_bytes); ++ base::UnsafeSharedMemoryRegion::Create(required_bytes.value()); + if (!region.IsValid()) { -+ DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes"; ++ DLOG(ERROR) << "Failed to allocate " << required_bytes.value() << " bytes"; + return; + } + @@ -359,7 +358,7 @@ index 0000000000000000000000000000000000000000..ef5cb8ae4c398e5834496c8b24eb98c4 +#else + shm_mapping_ = region.Map(); + if (!shm_mapping_.IsValid()) { -+ DLOG(ERROR) << "Failed to map " << required_bytes << " bytes"; ++ DLOG(ERROR) << "Failed to map " << required_bytes.value() << " bytes"; + return; + } + @@ -509,10 +508,10 @@ index 0000000000000000000000000000000000000000..e1a22ee881c0fd679ac2d2d4d11a3c93 + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ diff --git a/components/viz/service/display_embedder/software_output_device_win.cc b/components/viz/service/display_embedder/software_output_device_win.cc -index 9119e302ad073a3b22ba47f800e7214b580e122b..0d5b95a424a62a77785088dbd759af4f977b010e 100644 +index b5154321105f08335b67ad2d552afa61337a4976..cb28230d9a8da6bd2259ef0c898013293421ac56 100644 --- a/components/viz/service/display_embedder/software_output_device_win.cc +++ b/components/viz/service/display_embedder/software_output_device_win.cc -@@ -157,7 +157,7 @@ void SoftwareOutputDeviceWinProxy::EndPaintDelegated( +@@ -156,7 +156,7 @@ void SoftwareOutputDeviceWinProxy::EndPaintDelegated( if (!canvas_) return; @@ -522,7 +521,7 @@ index 9119e302ad073a3b22ba47f800e7214b580e122b..0d5b95a424a62a77785088dbd759af4f waiting_on_draw_ack_ = true; diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc -index 346e41638ffefe5e5945aa3cfe0ec38887041a0b..38ed2eb97132201eb0adfd8b855c1611eab777f0 100644 +index d8f845998240032f668324665d61b2efd60c0e1c..9eb5ab874ceecb4902b9272ce574d81302cf2802 100644 --- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc @@ -131,7 +131,8 @@ RootCompositorFrameSinkImpl::Create( @@ -564,10 +563,10 @@ index 399fba1a3d4e601dc2cdd5f1f4def8b7fd7a3011..8bcbe0d26c80323155d536c0d3a177a1 gpu::SyncPointManager* GetSyncPointManager() override; gpu::Scheduler* GetGpuScheduler() override; diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc -index 0c9dabd7e85042499b60d0a27a506745771bea6f..5f1896f4494b86c8385d3f5415863f5a7167715a 100644 +index 43d29976d8bd42d3ee6857db7d61f31c26795848..1d5852b1e4f1e628bd9b24b381ff3b17a4dd9165 100644 --- a/content/browser/compositor/viz_process_transport_factory.cc +++ b/content/browser/compositor/viz_process_transport_factory.cc -@@ -386,8 +386,14 @@ void VizProcessTransportFactory::OnEstablishedGpuChannel( +@@ -381,8 +381,14 @@ void VizProcessTransportFactory::OnEstablishedGpuChannel( mojo::AssociatedRemote<viz::mojom::DisplayPrivate> display_private; root_params->display_private = display_private.BindNewEndpointAndPassReceiver(); @@ -585,10 +584,10 @@ index 0c9dabd7e85042499b60d0a27a506745771bea6f..5f1896f4494b86c8385d3f5415863f5a compositor_data.display_client->GetBoundRemote(resize_task_runner_); mojo::AssociatedRemote<viz::mojom::ExternalBeginFrameController> diff --git a/services/viz/privileged/mojom/compositing/display_private.mojom b/services/viz/privileged/mojom/compositing/display_private.mojom -index e063835e87f08e6a2359886a96d7b78954e3d5b2..34bcf67726f64466d11a56d7a315ce7e05a0cb3d 100644 +index 78a96bff9ba9e24dababf758ba38f9b430b39a14..7b46e68f52e3c13f731ce486706004423c871eb1 100644 --- a/services/viz/privileged/mojom/compositing/display_private.mojom +++ b/services/viz/privileged/mojom/compositing/display_private.mojom -@@ -119,7 +119,6 @@ interface DisplayClient { +@@ -120,7 +120,6 @@ interface DisplayClient { // Creates a LayeredWindowUpdater implementation to draw into a layered // window. @@ -597,10 +596,10 @@ index e063835e87f08e6a2359886a96d7b78954e3d5b2..34bcf67726f64466d11a56d7a315ce7e // Sends the created child window to the browser process so that it can be diff --git a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom -index 3066550e422058eec23d5fe3e655625f5446d694..7358b05a646a2f80717a91182c4929776a404179 100644 +index e440ae1c216333afe1d90114d48a3bf7f39cf41f..4b3aba1c87e2e0fe1628681fb8b5cf19bfc54f80 100644 --- a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom +++ b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom -@@ -39,6 +39,7 @@ struct RootCompositorFrameSinkParams { +@@ -40,6 +40,7 @@ struct RootCompositorFrameSinkParams { bool send_swap_size_notifications = false; // Disables begin frame rate limiting for the display compositor. bool disable_frame_rate_limit = false; @@ -620,7 +619,7 @@ index 2f462f0deb5fc8a637457243fb5d5849fc214d14..695869b83cefaa24af93a2e11b39de05 + Draw(gfx.mojom.Rect damage_rect) => (); }; diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h -index f1a4674323d96bc6a1a291b0aaa4c2a35b20648e..682b23f083eff17bc36cdc4698e35d853beb90cc 100644 +index 010a30bcd09ca39215f0b31ec59425067a2392a4..7f428fe96da978aa951354eb41f9ebec46cc6e9c 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h @@ -87,6 +87,7 @@ class DisplayPrivate; diff --git a/patches/chromium/feat_enable_passing_exit_code_on_service_process_crash.patch b/patches/chromium/feat_enable_passing_exit_code_on_service_process_crash.patch index bb84370fafa4d..a231dd82a3777 100644 --- a/patches/chromium/feat_enable_passing_exit_code_on_service_process_crash.patch +++ b/patches/chromium/feat_enable_passing_exit_code_on_service_process_crash.patch @@ -84,10 +84,10 @@ index 2648adb1cf38ab557b66ffd0e3034b26b04d76d6..98eab587f343f6ca472efc3d4e7b31b2 private: const std::string service_interface_name_; diff --git a/content/browser/service_host/utility_process_host.cc b/content/browser/service_host/utility_process_host.cc -index d714d2022f685052e1def3b0d242d2ea596d790b..fb4cee1416836c4d0b807a862507a52347f24dd2 100644 +index 1298ea85a176db2150a4101afc205745f32eb8f5..1668345fb66b5a150b01dc3cce2e7262890a9c66 100644 --- a/content/browser/service_host/utility_process_host.cc +++ b/content/browser/service_host/utility_process_host.cc -@@ -629,7 +629,7 @@ void UtilityProcessHost::OnProcessCrashed(int exit_code) { +@@ -624,7 +624,7 @@ void UtilityProcessHost::OnProcessCrashed(int exit_code) { : Client::CrashType::kPreIpcInitialization; } #endif // BUILDFLAG(IS_WIN) diff --git a/patches/chromium/feat_ensure_mas_builds_of_the_same_application_can_use_safestorage.patch b/patches/chromium/feat_ensure_mas_builds_of_the_same_application_can_use_safestorage.patch index 5356a433ff375..10b251615959a 100644 --- a/patches/chromium/feat_ensure_mas_builds_of_the_same_application_can_use_safestorage.patch +++ b/patches/chromium/feat_ensure_mas_builds_of_the_same_application_can_use_safestorage.patch @@ -11,10 +11,10 @@ We attempt to migrate the safe storage key from the old account, if that migrati Existing apps that aren't built for the app store should be unimpacted, there is one edge case where a user uses BOTH an AppStore and a darwin build of the same app only one will keep it's access to the safestorage key as during the migration we delete the old account. This is an acceptable edge case as no one should be actively using two versions of the same app. -diff --git a/components/os_crypt/sync/keychain_password_mac.mm b/components/os_crypt/sync/keychain_password_mac.mm -index 3bcbb33700b2b9349795c05c12e44b4fafcc0370..b55c72e236f05591d41b7146eab1662128d37eda 100644 ---- a/components/os_crypt/sync/keychain_password_mac.mm -+++ b/components/os_crypt/sync/keychain_password_mac.mm +diff --git a/components/os_crypt/common/keychain_password_mac.mm b/components/os_crypt/common/keychain_password_mac.mm +index f19628cc0cdba39b232f55935e8eee9786b02a77..036b50f53e78bc21ed1e1d6dd876b50ab1e8f05d 100644 +--- a/components/os_crypt/common/keychain_password_mac.mm ++++ b/components/os_crypt/common/keychain_password_mac.mm @@ -27,6 +27,12 @@ using KeychainNameContainerType = const base::NoDestructor<std::string>; #endif @@ -82,7 +82,7 @@ index 3bcbb33700b2b9349795c05c12e44b4fafcc0370..b55c72e236f05591d41b7146eab16621 } diff --git a/crypto/apple/keychain.h b/crypto/apple/keychain.h -index 2438c3947f330fb496886b85c8eaf49767c68413..dc7da2fd2819eb64f2083de722a1b2771380abd5 100644 +index b5e604c525d66c172c80f65f38cdb23dccd4259d..7f48d66c83cf41d6d097eb43e271dd5ab43d01e9 100644 --- a/crypto/apple/keychain.h +++ b/crypto/apple/keychain.h @@ -18,6 +18,14 @@ @@ -97,10 +97,10 @@ index 2438c3947f330fb496886b85c8eaf49767c68413..dc7da2fd2819eb64f2083de722a1b277 +using AppleSecKeychainItemRef = SecKeychainItemRef; +#endif + - // DEPRECATED: use `KeychainV2` instead. // Wraps the KeychainServices API in a very thin layer, to allow it to be // mocked out for testing. -@@ -46,13 +54,18 @@ class CRYPTO_EXPORT Keychain { + +@@ -45,13 +53,18 @@ class CRYPTO_EXPORT Keychain { // std::vector<uint8_t> arm is populated instead. virtual base::expected<std::vector<uint8_t>, OSStatus> FindGenericPassword( std::string_view service_name, @@ -170,63 +170,6 @@ index d2b9526f9a0bfa9d12a594c35c71499810cb6bb0..aef0eb3508fc37e3a0e9e1c27a71e1aa +} +#endif + - } // namespace crypto::apple -diff --git a/crypto/apple/keychain_seckeychain.cc b/crypto/apple/keychain_seckeychain.cc -index 4ad5acbf29607fe2ea28637f5470599984e317db..61056948062f3fcb5138e309b9f5019c96f9ce00 100644 ---- a/crypto/apple/keychain_seckeychain.cc -+++ b/crypto/apple/keychain_seckeychain.cc -@@ -25,14 +25,15 @@ KeychainSecKeychain::~KeychainSecKeychain() = default; - - base::expected<std::vector<uint8_t>, OSStatus> - KeychainSecKeychain::FindGenericPassword(std::string_view service_name, -- std::string_view account_name) const { -+ std::string_view account_name, -+ AppleSecKeychainItemRef* item) const { - base::AutoLock lock(GetMacSecurityServicesLock()); - uint32_t password_length = 0; - void* password_data = nullptr; - OSStatus status = SecKeychainFindGenericPassword( - nullptr, service_name.length(), service_name.data(), - account_name.length(), account_name.data(), &password_length, -- &password_data, nullptr); -+ &password_data, item); - if (status != noErr) { - return base::unexpected(status); - } -@@ -58,6 +59,11 @@ OSStatus KeychainSecKeychain::AddGenericPassword( - password.data(), nullptr); - } - -+OSStatus KeychainSecKeychain::ItemDelete(AppleSecKeychainItemRef item) const { -+ base::AutoLock lock(GetMacSecurityServicesLock()); -+ return SecKeychainItemDelete(item); -+} -+ - #pragma clang diagnostic pop - - } // namespace crypto::apple -diff --git a/crypto/apple/keychain_seckeychain.h b/crypto/apple/keychain_seckeychain.h -index 991b2c8debaa1812812fb04e7ab6bf437c874691..191ea7532d269eae7a975229b12227cd32b56ede 100644 ---- a/crypto/apple/keychain_seckeychain.h -+++ b/crypto/apple/keychain_seckeychain.h -@@ -20,12 +20,17 @@ class CRYPTO_EXPORT KeychainSecKeychain : public Keychain { - - base::expected<std::vector<uint8_t>, OSStatus> FindGenericPassword( - std::string_view service_name, -- std::string_view account_name) const override; -+ std::string_view account_name, -+ AppleSecKeychainItemRef* item) const override; - - OSStatus AddGenericPassword( - std::string_view service_name, - std::string_view account_name, - base::span<const uint8_t> password) const override; -+ -+#if !BUILDFLAG(IS_IOS) -+ OSStatus ItemDelete(SecKeychainItemRef itemRef) const override; -+#endif // !BUILDFLAG(IS_IOS) - }; - } // namespace crypto::apple diff --git a/crypto/apple/mock_keychain.cc b/crypto/apple/mock_keychain.cc index 080806aaf3fc10548b160850ad36ef3519ea2b6f..21f04059d67ba41118face6ee9327aa05e854362 100644 @@ -254,10 +197,10 @@ index 080806aaf3fc10548b160850ad36ef3519ea2b6f..21f04059d67ba41118face6ee9327aa0 IncrementKeychainAccessHistogram(); return kPassword; diff --git a/crypto/apple/mock_keychain.h b/crypto/apple/mock_keychain.h -index 40fb4e1f75a2b7f021a8a20b01d63c7e3b8c5fa3..3c3f41e7ffcaeb74aaff872ce3b54027312ec0dd 100644 +index 680efe0312c81449e069c19d9c6ef146da7834db..b49c2ba5f639344ab57e9f14c098effc38729d1f 100644 --- a/crypto/apple/mock_keychain.h +++ b/crypto/apple/mock_keychain.h -@@ -37,13 +37,18 @@ class CRYPTO_EXPORT MockKeychain : public Keychain { +@@ -36,13 +36,18 @@ class CRYPTO_EXPORT MockKeychain : public Keychain { // Keychain implementation. base::expected<std::vector<uint8_t>, OSStatus> FindGenericPassword( std::string_view service_name, diff --git a/patches/chromium/feat_expose_documentloader_setdefersloading_on_webdocumentloader.patch b/patches/chromium/feat_expose_documentloader_setdefersloading_on_webdocumentloader.patch index 221bd48845ca5..036ac4ed36904 100644 --- a/patches/chromium/feat_expose_documentloader_setdefersloading_on_webdocumentloader.patch +++ b/patches/chromium/feat_expose_documentloader_setdefersloading_on_webdocumentloader.patch @@ -28,7 +28,7 @@ index 33e23680b927d417b0882c7572fe32dc2d2b90c3..9413492f8e0fd6c5371c66329e1ad6d4 // Returns the http referrer of original request which initited this load. diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h -index a41f344dca8ec3a9004874f4820b742c27999738..222c1d749174e434878cc762625ac8aabe10f5e6 100644 +index 054d0d7e9f62c197ab4e1db82e67eadced3f815d..578fccb657443110d6da486d31afe38c57ac00e3 100644 --- a/third_party/blink/renderer/core/loader/document_loader.h +++ b/third_party/blink/renderer/core/loader/document_loader.h @@ -322,7 +322,7 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>, diff --git a/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch b/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch index cdcaff7156e38..4cbbe91d39ffa 100644 --- a/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch +++ b/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch @@ -17,7 +17,7 @@ headers, moving forward we should find a way in upstream to provide access to these headers for loader clients created on the browser process. diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc -index 4c6da7daa167e8e687d43b6c59948fdc694052f7..1f9a142462146f1cef675455a782996b0d533cfd 100644 +index 177aa95b01f8020d3a6a61124405f03ad4c1bace..645bafa225b758cd1aab1e998da740758337cba6 100644 --- a/services/network/public/cpp/resource_request.cc +++ b/services/network/public/cpp/resource_request.cc @@ -196,6 +196,7 @@ ResourceRequest::TrustedParams& ResourceRequest::TrustedParams::operator=( @@ -37,10 +37,10 @@ index 4c6da7daa167e8e687d43b6c59948fdc694052f7..1f9a142462146f1cef675455a782996b allow_cookies_from_browser == other.allow_cookies_from_browser && include_request_cookies_with_response == diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h -index 3137a61cba8ea72aaa422fadaf4f530b22832aa5..3bb07ad3981e21563debfab1d8080767fd349c72 100644 +index 53143c10acf2ac064cbc6605ef60ada3ab648c0d..c08a0ac7eadd749e3a3dc2c5fd489472665bb8df 100644 --- a/services/network/public/cpp/resource_request.h +++ b/services/network/public/cpp/resource_request.h -@@ -91,6 +91,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest { +@@ -99,6 +99,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest { bool has_user_activation = false; bool allow_cookies_from_browser = false; bool include_request_cookies_with_response = false; @@ -49,10 +49,10 @@ index 3137a61cba8ea72aaa422fadaf4f530b22832aa5..3bb07ad3981e21563debfab1d8080767 mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer; mojo::PendingRemote<mojom::TrustTokenAccessObserver> trust_token_observer; diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc -index 1d4476c7a6d75bf1a02dc874c971068ab99345bd..4b5113ce912bdbe8eb75482bb9d5361272a3a628 100644 +index 646be484e4d5b3b917bed0ee2d0a52fdf57a8291..b49035fab82ddb29e211e1e215c70aab0a625222 100644 --- a/services/network/public/cpp/url_request_mojom_traits.cc +++ b/services/network/public/cpp/url_request_mojom_traits.cc -@@ -64,6 +64,7 @@ bool StructTraits<network::mojom::TrustedUrlRequestParamsDataView, +@@ -67,6 +67,7 @@ bool StructTraits<network::mojom::TrustedUrlRequestParamsDataView, out->allow_cookies_from_browser = data.allow_cookies_from_browser(); out->include_request_cookies_with_response = data.include_request_cookies_with_response(); @@ -61,10 +61,10 @@ index 1d4476c7a6d75bf1a02dc874c971068ab99345bd..4b5113ce912bdbe8eb75482bb9d53612 return false; } diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h -index 933a3ccdbea3182035a6626f6c288719ce46ab62..5fdc6cd9539ed4501bc577b7eefb629e0d8912f0 100644 +index 9867e5115459f6d0a074d79183e53c3dba0187db..06ec0cea64750057b67108fbfeb1f9d850b0793f 100644 --- a/services/network/public/cpp/url_request_mojom_traits.h +++ b/services/network/public/cpp/url_request_mojom_traits.h -@@ -101,6 +101,10 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) +@@ -108,6 +108,10 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) const network::ResourceRequest::TrustedParams& trusted_params) { return trusted_params.include_request_cookies_with_response; } @@ -76,10 +76,10 @@ index 933a3ccdbea3182035a6626f6c288719ce46ab62..5fdc6cd9539ed4501bc577b7eefb629e network::ResourceRequest::TrustedParams::EnabledClientHints>& enabled_client_hints( diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom -index 02651c7b3b0cb0ab8fd3a4c84ab5b39b0e773536..0cbf060b11cc47c24e5cde0d36edb88cd50d5c98 100644 +index affb80d9ffcc8da3f572b1a1461d2cd648ef3376..3f6301b1732171073c5fb072feaf12e3fb55c74c 100644 --- a/services/network/public/mojom/url_request.mojom +++ b/services/network/public/mojom/url_request.mojom -@@ -103,6 +103,9 @@ struct TrustedUrlRequestParams { +@@ -111,6 +111,9 @@ struct TrustedUrlRequestParams { // client which should not be able to see them. bool include_request_cookies_with_response = false; @@ -90,7 +90,7 @@ index 02651c7b3b0cb0ab8fd3a4c84ab5b39b0e773536..0cbf060b11cc47c24e5cde0d36edb88c // when it receives the AcceptCHFrame. EnabledClientHints? enabled_client_hints; diff --git a/services/network/public/mojom/url_response_head.mojom b/services/network/public/mojom/url_response_head.mojom -index 3a5fbaea905e7c01caee3659ff3be06e8def5615..89da9461e8290b8099456e5222f278770e09f883 100644 +index 13a211107294e856616d1626fa1dc9c79eb5646c..549a36886d665c1a8100f09b7a86c8dc13c80e84 100644 --- a/services/network/public/mojom/url_response_head.mojom +++ b/services/network/public/mojom/url_response_head.mojom @@ -14,6 +14,7 @@ import "services/network/public/mojom/encoded_body_length.mojom"; @@ -112,10 +112,10 @@ index 3a5fbaea905e7c01caee3659ff3be06e8def5615..89da9461e8290b8099456e5222f27877 string mime_type; diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc -index 61f3909c6f0fe606d30da08fbd3222af44c1a9e4..8b5f2162a2bbfe0bd422b89bc13e9ff93d826afe 100644 +index a28a4bfc26a797dc862c59a337b4ed43b76eb06d..4da33fa9eef14b76f06d2741942fc387b2cde37d 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc -@@ -398,6 +398,9 @@ URLLoader::URLLoader( +@@ -386,6 +386,9 @@ URLLoader::URLLoader( mojo::SimpleWatcher::ArmingPolicy::MANUAL, TaskRunner(request.priority)), per_factory_orb_state_(context.GetMutableOrbState()), @@ -125,7 +125,7 @@ index 61f3909c6f0fe606d30da08fbd3222af44c1a9e4..8b5f2162a2bbfe0bd422b89bc13e9ff9 devtools_request_id_(request.devtools_request_id), options_(PopulateOptions(options, factory_params_->is_orb_enabled, -@@ -536,7 +539,7 @@ void URLLoader::SetUpUrlRequestCallbacks( +@@ -525,7 +528,7 @@ void URLLoader::SetUpUrlRequestCallbacks( &URLLoader::IsSharedDictionaryReadAllowed, base::Unretained(this))); } @@ -134,7 +134,7 @@ index 61f3909c6f0fe606d30da08fbd3222af44c1a9e4..8b5f2162a2bbfe0bd422b89bc13e9ff9 url_request_->SetResponseHeadersCallback(base::BindRepeating( &URLLoader::SetRawResponseHeaders, base::Unretained(this))); } -@@ -1151,6 +1154,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { +@@ -1122,6 +1125,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { } response_ = BuildResponseHead(); @@ -155,10 +155,10 @@ index 61f3909c6f0fe606d30da08fbd3222af44c1a9e4..8b5f2162a2bbfe0bd422b89bc13e9ff9 ad_auction_event_record_request_helper_.HandleResponse( diff --git a/services/network/url_loader.h b/services/network/url_loader.h -index 6ba39c957af7927b060be59f7d8837a3e2d41215..e52a276b0dd671317797104d85ccf75f5a333153 100644 +index f437df6e20b7d4e28f5e57e2134c5c7fa9da2bdc..661fef04f6b76abef852ba8eef63b1f78b01652c 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h -@@ -615,6 +615,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader +@@ -624,6 +624,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader std::unique_ptr<ResourceScheduler::ScheduledResourceRequest> resource_scheduler_request_handle_; diff --git a/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch b/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch index 5da28b3c084f9..c052fef3c9a29 100644 --- a/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch +++ b/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch @@ -7,10 +7,10 @@ Subject: feat: filter out non-shareable windows in the current application in This patch ensures that windows protected via win.setContentProtection(true) do not appear in full display captures via desktopCapturer. This patch could be upstreamed but as the check is limited to in-process windows it doesn't make a lot of sense for Chromium itself. This patch currently has a limitation that it only function for windows created / protected BEFORE the stream is started. There is theoretical future work we can do via polling / observers to automatically update the SCContentFilter when new windows are made but for now this will solve 99+% of the problem and folks can re-order their logic a bit to get it working for their use cases. diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm -index 42705a5c59fb76ba4a6a17a060e215436307de49..7e17594c30ac3cf8cb484b53563b03fc75bd2e0b 100644 +index 404085d1ccf3ea7f4d11941efa64dc1a193552e0..c2d8bbafa39c05f25641f2fd3491ef7f84f4f6a1 100644 --- a/content/browser/media/capture/screen_capture_kit_device_mac.mm +++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm -@@ -254,8 +254,17 @@ void OnShareableContentCreated(SCShareableContent* content) { +@@ -266,8 +266,17 @@ void OnShareableContentCreated(SCShareableContent* content) { // fallback. See https://crbug.com/325530044. if (source_.id == display.displayID || source_.id == webrtc::kFullDesktopScreenId) { diff --git a/patches/chromium/feat_separate_content_settings_callback_for_sync_and_async_clipboard.patch b/patches/chromium/feat_separate_content_settings_callback_for_sync_and_async_clipboard.patch index f09102aa996b6..9a6611357a6d5 100644 --- a/patches/chromium/feat_separate_content_settings_callback_for_sync_and_async_clipboard.patch +++ b/patches/chromium/feat_separate_content_settings_callback_for_sync_and_async_clipboard.patch @@ -20,7 +20,7 @@ This patch will be removed when the deprecated sync api support is removed. diff --git a/components/permissions/permission_util.cc b/components/permissions/permission_util.cc -index 21abffe390a8213ce1a5b71f382b37a60a014f52..38134a075fbb3586eec543591c88fcf7dcd53e3d 100644 +index c9b607c9bd09d43099a1704d5d4139c64e4beac4..18ad7ed73b0ed4de158519c01342f0bfd7cc3666 100644 --- a/components/permissions/permission_util.cc +++ b/components/permissions/permission_util.cc @@ -536,6 +536,7 @@ ContentSettingsType PermissionUtil::PermissionTypeToContentSettingsTypeSafe( @@ -32,10 +32,10 @@ index 21abffe390a8213ce1a5b71f382b37a60a014f52..38134a075fbb3586eec543591c88fcf7 break; } diff --git a/content/browser/permissions/permission_controller_impl.cc b/content/browser/permissions/permission_controller_impl.cc -index 93375d87a26961edd8ae0c25fecc0ea5afc8c0bc..f6a28f5efae758a93aa52ebd28e25ece996f0e7e 100644 +index eeacd30992233f44f8972f242f37637cb240dc06..e56096991dfbffa3a16aa3aca602b59fbd48a4d5 100644 --- a/content/browser/permissions/permission_controller_impl.cc +++ b/content/browser/permissions/permission_controller_impl.cc -@@ -88,6 +88,7 @@ PermissionToSchedulingFeature(PermissionType permission_name) { +@@ -94,6 +94,7 @@ PermissionToSchedulingFeature(PermissionType permission_name) { case PermissionType::AUTOMATIC_FULLSCREEN: case PermissionType::WEB_APP_INSTALLATION: case PermissionType::LOCAL_NETWORK_ACCESS: @@ -91,7 +91,7 @@ index 5c82a641538802bc459782ea422a1186045b054a..c286d87043ec4cb2e51ec9d82d08e4c8 // Always keep this at the end. NUM, diff --git a/third_party/blink/public/mojom/permissions/permission.mojom b/third_party/blink/public/mojom/permissions/permission.mojom -index 66270fa219491e0b9f09113e45452cd8c2890b52..47c73522cbd7c1d12dabfecf6f55a74690ebc189 100644 +index da2bcae965ddc183b5794bc8c44aec4f1754f1d2..2b24e692042a352e931278ead6a06e057f73eda6 100644 --- a/third_party/blink/public/mojom/permissions/permission.mojom +++ b/third_party/blink/public/mojom/permissions/permission.mojom @@ -43,7 +43,8 @@ enum PermissionName { @@ -119,7 +119,7 @@ index 36410ff29d9c82e59f93fbb82968064bd330dfde..6c3f994e0b184f78bd9442002bb4dfae virtual void PassiveInsecureContentFound(const WebURL&) {} diff --git a/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc b/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc -index a5ac9d4a417ac8e75e761c40841f41ab9057c761..292bd1f9de78828e739dae24a45a1dd3d6585240 100644 +index 80c15ef5381aa08c0c6ce3f51534bb04af64775d..9a9024ba766226848974e5518ccbffa79ee55e65 100644 --- a/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc +++ b/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc @@ -123,7 +123,7 @@ bool ClipboardCommands::CanReadClipboard(LocalFrame& frame, @@ -141,10 +141,10 @@ index a5ac9d4a417ac8e75e761c40841f41ab9057c761..292bd1f9de78828e739dae24a45a1dd3 bool ClipboardCommands::ExecuteCopy(LocalFrame& frame, diff --git a/third_party/blink/renderer/modules/permissions/permission_utils.cc b/third_party/blink/renderer/modules/permissions/permission_utils.cc -index b533436f91ba67c6060d4a1976f7c197b6db3afc..63df740efad1e407f0990d2ba48a9cbcb8bdb6f8 100644 +index 691726eb23434005adc559534fc0aeede937cc92..a980ed6afb84eceef9c9b594b325e8e3783821ec 100644 --- a/third_party/blink/renderer/modules/permissions/permission_utils.cc +++ b/third_party/blink/renderer/modules/permissions/permission_utils.cc -@@ -146,6 +146,8 @@ String PermissionNameToString(PermissionName name) { +@@ -145,6 +145,8 @@ String PermissionNameToString(PermissionName name) { return "web-printing"; case PermissionName::SMART_CARD: return "smart-card"; diff --git a/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch b/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch index 2a4ea12135311..0b5c0156dba90 100644 --- a/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch +++ b/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch @@ -16,10 +16,10 @@ Linux or Windows to un-fullscreen in some circumstances without this change. diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc -index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf9d1f5c19 100644 +index 3d17e79f291e6d3925d29cf349c30b4f7c7a6f54..a7494e62a6a49a71e5aef2c8abb4ec29426a5d23 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc -@@ -46,7 +46,7 @@ +@@ -47,7 +47,7 @@ #include "components/prefs/pref_service.h" #endif @@ -28,7 +28,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf #include "chrome/browser/ui/blocked_content/popunder_preventer.h" #endif // !BUILDFLAG(IS_ANDROID) -@@ -271,7 +271,7 @@ void FullscreenController::EnterFullscreenModeForTab( +@@ -196,7 +196,7 @@ void FullscreenController::EnterFullscreenModeForTab( return; } @@ -37,7 +37,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf if (!popunder_preventer_) { popunder_preventer_ = std::make_unique<PopunderPreventer>(web_contents); } else { -@@ -391,12 +391,14 @@ void FullscreenController::ExitFullscreenModeForTab(WebContents* web_contents) { +@@ -326,12 +326,14 @@ void FullscreenController::ExitFullscreenModeForTab(WebContents* web_contents) { void FullscreenController::FullscreenTabOpeningPopup( content::WebContents* opener, content::WebContents* popup) { @@ -52,7 +52,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf } #endif // !BUILDFLAG(IS_ANDROID) -@@ -487,8 +489,7 @@ void FullscreenController::FullscreenTransitionCompleted() { +@@ -415,8 +417,7 @@ void FullscreenController::FullscreenTransitionCompleted() { #endif // DCHECK_IS_ON() tab_fullscreen_target_display_id_ = display::kInvalidDisplayId; started_fullscreen_transition_ = false; @@ -62,7 +62,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf if (!IsTabFullscreen()) { // Activate any popup windows created while content fullscreen, after exit. popunder_preventer_.reset(); -@@ -623,18 +624,17 @@ void FullscreenController::EnterFullscreenModeInternal( +@@ -552,19 +553,18 @@ void FullscreenController::EnterFullscreenModeInternal( // Do not enter fullscreen mode if disallowed by pref. This prevents the user // from manually entering fullscreen mode and also disables kiosk mode on // desktop platforms. @@ -76,6 +76,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf return; - } #endif + fullscreen_parameters_ = fullscreen_tab_params; started_fullscreen_transition_ = true; toggled_into_fullscreen_ = true; +#if 0 @@ -86,7 +87,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf if (option == TAB) { origin = GetRequestingOrigin(); tab_fullscreen_ = true; -@@ -671,6 +671,7 @@ void FullscreenController::EnterFullscreenModeInternal( +@@ -602,6 +602,7 @@ void FullscreenController::EnterFullscreenModeInternal( origin = url::Origin::Create(extension_url_.value()); } } @@ -94,7 +95,7 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf fullscreen_start_time_ = base::TimeTicks::Now(); if (option == BROWSER) { -@@ -692,6 +693,7 @@ void FullscreenController::ExitFullscreenModeInternal() { +@@ -623,6 +624,7 @@ void FullscreenController::ExitFullscreenModeInternal() { return; } @@ -102,12 +103,13 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf // `fullscreen_start_time_` is null if a fullscreen tab moves to a new window. if (fullscreen_start_time_ && exclusive_access_tab()) { ukm::SourceId source_id = -@@ -703,18 +705,19 @@ void FullscreenController::ExitFullscreenModeInternal() { +@@ -634,19 +636,20 @@ void FullscreenController::ExitFullscreenModeInternal() { .Record(ukm::UkmRecorder::Get()); fullscreen_start_time_.reset(); } +#endif + fullscreen_parameters_.reset(); toggled_into_fullscreen_ = false; started_fullscreen_transition_ = true; -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) @@ -125,26 +127,13 @@ index c38ce5558472c785837f1d4d2542f2edf2ffab58..219f562f51b45d2c961246e232ef4daf exclusive_access_manager()->context()->ExitFullscreen(); extension_url_.reset(); exclusive_access_manager()->UpdateBubble(base::NullCallback()); -@@ -778,8 +781,12 @@ url::Origin FullscreenController::GetEmbeddingOrigin() const { - void FullscreenController::RecordMetricsOnFullscreenApiRequested( - content::RenderFrameHost* requesting_frame) { - history::HistoryService* service = -+ #if 0 - HistoryServiceFactory::GetForProfileWithoutCreating( - exclusive_access_manager()->context()->GetProfile()); -+ #else -+ nullptr; -+ #endif - if (service) { - // Check if the origin has been visited more than a day ago and whether it's - // on an allowlist, then record those bits of information in a metric. diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h -index 0fa707f6dfcfb26ed15488b099cc03efe548785b..0ef6faf1e2385b091df36b0c0efb89167b17ac34 100644 +index e80fa0ad07db3b670812b7b8b4fe09e1986933be..f86bd0cbfe79462617ed191b616cb5b6237c5ce8 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h -@@ -254,7 +254,7 @@ class FullscreenController : public ExclusiveAccessControllerBase { - // Used in testing to set the state to tab fullscreen. - bool is_tab_fullscreen_for_testing_ = false; +@@ -261,7 +261,7 @@ class FullscreenController : public ExclusiveAccessControllerBase { + // Set of parameters used to enter fullscreen + std::optional<FullscreenTabParams> fullscreen_parameters_; -#if !BUILDFLAG(IS_ANDROID) +#if 0 diff --git a/patches/chromium/fix_adjust_headless_mode_handling_in_native_widget.patch b/patches/chromium/fix_adjust_headless_mode_handling_in_native_widget.patch index fc6206fe10c42..a7be415abddf2 100644 --- a/patches/chromium/fix_adjust_headless_mode_handling_in_native_widget.patch +++ b/patches/chromium/fix_adjust_headless_mode_handling_in_native_widget.patch @@ -14,32 +14,157 @@ input list). We also need to ensure that an initial paint is scheduled when the compositor is unsuspended in headles mode. +Additionally, this patch reverts +https://chromium-review.googlesource.com/c/chromium/src/+/6936895 +as we depend on the removed functionality in this patch. + +diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +index ce52245628c72018da8ec4a3155dafa74e42c8e3..89a078d1ce00667bd83def21e341b03ca6c79ee3 100644 +--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm ++++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +@@ -522,7 +522,7 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { + is_translucent_window_ = params->is_translucent; + pending_restoration_data_ = params->state_restoration_data; + +- if (display::Screen::Get()->IsHeadless()) { ++ if (params->is_headless_mode_window) { + headless_mode_window_ = std::make_optional<HeadlessModeWindow>(); + } + +diff --git a/components/remote_cocoa/common/native_widget_ns_window.mojom b/components/remote_cocoa/common/native_widget_ns_window.mojom +index 11954a3adfb6d517b6dc8e780a4a9aba8a0bf98a..1ddc1f34055c8b42177703ccc2f0d006294430da 100644 +--- a/components/remote_cocoa/common/native_widget_ns_window.mojom ++++ b/components/remote_cocoa/common/native_widget_ns_window.mojom +@@ -81,6 +81,8 @@ struct NativeWidgetNSWindowInitParams { + // NSWindowCollectionBehaviorParticipatesInCycle (this is not the + // default for NSWindows with NSWindowStyleMaskBorderless). + bool force_into_collection_cycle; ++ // If true, the window was created in headless mode. ++ bool is_headless_mode_window; + // An opaque blob of AppKit data which includes, among other things, a + // window's workspace and fullscreen state, and can be retrieved from or + // applied to a window. +diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.h b/ui/views/cocoa/native_widget_mac_ns_window_host.h +index 2239b085ac7fd87fe06aef1001551f8afe8e21e4..9ead3ab0755fe5c3500893325f0597e07e7241cc 100644 +--- a/ui/views/cocoa/native_widget_mac_ns_window_host.h ++++ b/ui/views/cocoa/native_widget_mac_ns_window_host.h +@@ -556,6 +556,7 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost + bool is_miniaturized_ = false; + bool is_window_key_ = false; + bool is_mouse_capture_active_ = false; ++ bool is_headless_mode_window_ = false; + bool is_zoomed_ = false; + gfx::Rect window_bounds_before_fullscreen_; + diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm -index 48dfca966a594f54523c129fa49d2a561cb41dec..049cf4f1adcf4f64cd8692f6e6eda7418008e799 100644 +index d2204fd2b737f7f3e146cb1be80c3be6bfce8cd4..9064b3d019aca6e8b77b10c3f0d0447b52f5245a 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm -@@ -664,9 +664,10 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -467,6 +467,7 @@ void HandleAccelerator(const ui::Accelerator& accelerator, + if (!is_tooltip) { + tooltip_manager_ = std::make_unique<TooltipManagerMac>(GetNSWindowMojo()); + } ++ is_headless_mode_window_ = params.ShouldInitAsHeadless(); + + if (params.workspace.length()) { + std::string restoration_data; +@@ -484,6 +485,7 @@ void HandleAccelerator(const ui::Accelerator& accelerator, + window_params->modal_type = widget->widget_delegate()->GetModalType(); + window_params->is_translucent = + params.opacity == Widget::InitParams::WindowOpacity::kTranslucent; ++ window_params->is_headless_mode_window = is_headless_mode_window_; + window_params->is_tooltip = is_tooltip; + + // macOS likes to put shadows on most things. However, frameless windows +@@ -665,9 +667,10 @@ void HandleAccelerator(const ui::Accelerator& accelerator, // case it will never become visible but we want its compositor to produce // frames for screenshooting and screencasting. UpdateCompositorProperties(); - layer()->SetVisible(is_visible_); +- if (is_visible_ || display::Screen::Get()->IsHeadless()) { + layer()->SetVisible(is_visible_ || is_headless_mode_window_); - if (is_visible_ || is_headless_mode_window_) { ++ if (is_visible_ || is_headless_mode_window_) { compositor_->Unsuspend(); + layer()->SchedulePaint(layer()->bounds()); } // Register the CGWindowID (used to identify this window for video capture) +diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc +index c44058711170316552ea05f97b8b8af694da8ca3..2895f8d17e7d045a3fae3f83e4dc117d48b7b29f 100644 +--- a/ui/views/widget/widget.cc ++++ b/ui/views/widget/widget.cc +@@ -222,6 +222,18 @@ ui::ZOrderLevel Widget::InitParams::EffectiveZOrderLevel() const { + } + } + ++bool Widget::InitParams::ShouldInitAsHeadless() const { ++ if (headless_mode) { ++ return true; ++ } ++ ++ if (Widget* top_level_widget = GetTopLevelWidgetForNativeView(parent)) { ++ return top_level_widget->is_headless(); ++ } ++ ++ return false; ++} ++ + void Widget::InitParams::SetParent(Widget* parent_widget) { + SetParent(parent_widget->GetNativeView()); + } +@@ -469,6 +481,7 @@ void Widget::Init(InitParams params) { + + params.child |= (params.type == InitParams::TYPE_CONTROL); + is_top_level_ = !params.child; ++ is_headless_ = params.ShouldInitAsHeadless(); + is_autosized_ = params.autosize; + + if (params.opacity == views::Widget::InitParams::WindowOpacity::kInferred && diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h -index b1bae5f73c9509e9fc837220a103d0dcff501ab2..aa5ab5fe546c1ebf8cc57b2a32f21b7c1802e4f2 100644 +index 64d07b209f72fc593c861d84d2baf0ca52ce9aed..1569f9115371d4eaa18bb34eb4d91a1380d257d5 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h -@@ -1298,6 +1298,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, - // True if widget was created in headless mode. - bool is_headless() const { return is_headless_; } +@@ -324,6 +324,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, + // case where |activatable| is |kDefault|. + bool CanActivate() const; + ++ // Returns whether the widget should be initialized as headless by checking ++ // if |headless_mode| or the associated top level widget's |is_headless_| ++ // are set. ++ bool ShouldInitAsHeadless() const; ++ + // Returns the z-order level, based on the overriding |z_order| but also + // taking into account special levels due to |type|. + ui::ZOrderLevel EffectiveZOrderLevel() const; +@@ -504,6 +509,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, + // If true then the widget uses software compositing. + bool force_software_compositing = false; + ++ // If set, the widget was created in headless mode. ++ bool headless_mode = false; ++ + // If set, the window size will follow the content preferred size. + bool autosize = false; + +@@ -1291,6 +1299,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, + // with it. TYPE_CONTROL and TYPE_TOOLTIP is not considered top level. + bool is_top_level() const { return is_top_level_; } ++ // True if widget was created in headless mode. ++ bool is_headless() const { return is_headless_; } ++ + void DisableHeadlessMode() { is_headless_ = false; } + // True if the window size will follow the content preferred size. bool is_autosized() const { return is_autosized_; } +@@ -1718,6 +1731,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, + // If true, the mouse is currently down. + bool is_mouse_button_pressed_ = false; + ++ // If set, the widget was created in headless mode. ++ bool is_headless_ = false; ++ + // If set, the window size will follow the content preferred size. + bool is_autosized_ = false; + diff --git a/patches/chromium/fix_aspect_ratio_with_max_size.patch b/patches/chromium/fix_aspect_ratio_with_max_size.patch index 3a64048c8e9de..e05675df51c7d 100644 --- a/patches/chromium/fix_aspect_ratio_with_max_size.patch +++ b/patches/chromium/fix_aspect_ratio_with_max_size.patch @@ -11,10 +11,10 @@ enlarge window above dimensions set during creation of the BrowserWindow. diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index f404c718e0242ec9269e7d14eb236aa928fb5d58..3637176c05a7074cb9042b74f7c9ea2e29af5ee5 100644 +index 80683ec77cdc77d624254c19708f12acd47316a1..a71630354ee345224371980675d09dc16fdcff16 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -3843,15 +3843,30 @@ void HWNDMessageHandler::SizeWindowToAspectRatio(UINT param, +@@ -3838,17 +3838,30 @@ void HWNDMessageHandler::SizeWindowToAspectRatio(UINT param, delegate_->GetMinMaxSize(&min_window_size, &max_window_size); min_window_size = delegate_->DIPToScreenSize(min_window_size); max_window_size = delegate_->DIPToScreenSize(max_window_size); @@ -39,10 +39,12 @@ index f404c718e0242ec9269e7d14eb236aa928fb5d58..3637176c05a7074cb9042b74f7c9ea2e max_size_param = max_window_size; } +- gfx::Size excluded_margin = delegate_->DIPToScreenSize(excluded_margin_dip_); +- - gfx::SizeRectToAspectRatioWithExcludedMargin( + gfx::SizeRectToAspectRatio( GetWindowResizeEdge(param), aspect_ratio_.value(), min_window_size, -- max_size_param, excluded_margin_, *window_rect); +- max_size_param, excluded_margin, *window_rect); + max_size_param, window_rect); } diff --git a/patches/chromium/fix_check_for_file_existence_before_setting_mtime.patch b/patches/chromium/fix_check_for_file_existence_before_setting_mtime.patch new file mode 100644 index 0000000000000..194fb15119955 --- /dev/null +++ b/patches/chromium/fix_check_for_file_existence_before_setting_mtime.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Charles Kerr <charles@charleskerr.com> +Date: Tue, 21 Oct 2025 18:44:52 -0500 +Subject: fix: check for file existence before setting mtime + +Check for broken links by confirming the file exists before setting its utime. + +This patch should be upstreamed & removed. + +diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py +index 1a35e992913acae102adc3faf0065ef13e6dbd1b..39e0d541e228e71108fa23717a906a0c543fe268 100755 +--- a/tools/clang/scripts/update.py ++++ b/tools/clang/scripts/update.py +@@ -201,10 +201,9 @@ def DownloadAndUnpack(url, output_dir, path_prefixes=None, is_known_zip=False): + # The nicest way to do this would be by passing a filter to extractall, + # but that functionality is not available in macOS system Python (3.9.6). + for m in members: +- # Confusingly, this checks if you're allowed to _not_ follow symlinks. +- if os.utime in os.supports_follow_symlinks: +- os.utime(os.path.join(output_dir, m.name), follow_symlinks=False) +- else: ++ # check for broken links before setting the file's utime ++ member_path = os.path.join(output_dir, m.name) ++ if os.path.exists(member_path): + os.utime(os.path.join(output_dir, m.name)) + + diff --git a/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch b/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch index c1117059342ec..9a10dbdc5af93 100644 --- a/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch +++ b/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch @@ -28,10 +28,10 @@ The patch should be removed in favor of either: Upstream bug https://bugs.chromium.org/p/chromium/issues/detail?id=1081397. diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc -index 07284d1cca9d78cfd0081d41823766e0051e1eed..2daded6fb83043ced67378fca9367168e5e76f4f 100644 +index 06b6f3ac21407d670d6eeac279ac5e876f6f900b..2b9d0a355b89f9eacf79a068ead7bef35915a6e3 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc -@@ -11392,6 +11392,11 @@ url::Origin NavigationRequest::GetOriginForURLLoaderFactoryUnchecked() { +@@ -11457,6 +11457,11 @@ url::Origin NavigationRequest::GetOriginForURLLoaderFactoryUnchecked() { target_rph_id); } @@ -44,10 +44,10 @@ index 07284d1cca9d78cfd0081d41823766e0051e1eed..2daded6fb83043ced67378fca9367168 // origin of |common_params.url| and/or |common_params.initiator_origin|. url::Origin resolved_origin = url::Origin::Resolve( diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc -index a7c069c44622d1a247b44395007261b5323da982..639f9a93f4b27bda9082ed1b7a4c914c493b714f 100644 +index 4fd00e73d1805a8579f8b762fe4f105759df8f14..2b5fefefb928d91c22c4e9fbd219a54801357bac 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc -@@ -2322,6 +2322,10 @@ Frame* DocumentLoader::CalculateOwnerFrame() { +@@ -2324,6 +2324,10 @@ Frame* DocumentLoader::CalculateOwnerFrame() { scoped_refptr<SecurityOrigin> DocumentLoader::CalculateOrigin( Document* owner_document) { scoped_refptr<SecurityOrigin> origin; @@ -58,7 +58,7 @@ index a7c069c44622d1a247b44395007261b5323da982..639f9a93f4b27bda9082ed1b7a4c914c // Whether the origin is newly created within this call, instead of copied // from an existing document's origin or from `origin_to_commit_`. If this is // true, we won't try to compare the nonce of this origin (if it's opaque) to -@@ -2358,6 +2362,9 @@ scoped_refptr<SecurityOrigin> DocumentLoader::CalculateOrigin( +@@ -2360,6 +2364,9 @@ scoped_refptr<SecurityOrigin> DocumentLoader::CalculateOrigin( // non-renderer only origin bits will be the same, which will be asserted at // the end of this function. origin = origin_to_commit_; diff --git a/patches/chromium/fix_disabling_background_throttling_in_compositor.patch b/patches/chromium/fix_disabling_background_throttling_in_compositor.patch index 906bc3c6a1623..a953a7849edf9 100644 --- a/patches/chromium/fix_disabling_background_throttling_in_compositor.patch +++ b/patches/chromium/fix_disabling_background_throttling_in_compositor.patch @@ -12,7 +12,7 @@ invisible state of the `viz::DisplayScheduler` owned by the `ui::Compositor`. diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc -index 1cb8ea92e46ad45cd8bf9e99f38889964b16768f..3e80241add13eeeb3b5970932f23acec0d91fd4e 100644 +index c0a2f822e38712eaad30c5d1104b149fa28d985d..b967896479c7fd0f71c7b9e5407d63e1d62bfadd 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc @@ -358,7 +358,8 @@ void Compositor::SetLayerTreeFrameSink( @@ -53,7 +53,7 @@ index 1cb8ea92e46ad45cd8bf9e99f38889964b16768f..3e80241add13eeeb3b5970932f23acec void Compositor::SetSeamlessRefreshRates( const std::vector<float>& seamless_refresh_rates) { diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h -index 682b23f083eff17bc36cdc4698e35d853beb90cc..df9e598b65594748d59284e1e91d61233eef83a0 100644 +index 7f428fe96da978aa951354eb41f9ebec46cc6e9c..7e5a008d7b158c1af9a47f549426818bc22212f5 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h @@ -514,6 +514,10 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver, diff --git a/patches/chromium/fix_export_zlib_symbols.patch b/patches/chromium/fix_export_zlib_symbols.patch index 74663cd426e1a..39d76d3b68118 100644 --- a/patches/chromium/fix_export_zlib_symbols.patch +++ b/patches/chromium/fix_export_zlib_symbols.patch @@ -6,7 +6,7 @@ Subject: fix: export zlib symbols This patch sets ZLIB_DLL so that we properly export zlib symbols. diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn -index 3d0735452a66d4213d1c4cf7c36cd36b3bf1c6f8..3dc1b24fe5f25b0a8b00d1a7918f518f0bad091d 100644 +index afd3e8cc0f38e95b3b04835b46bd1197a63b4ed1..652fa32d49de9f0c73777c0d4d99421f52e16b38 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn @@ -333,6 +333,10 @@ component("zlib") { diff --git a/patches/chromium/fix_font_face_resolution_when_renderer_is_blocked.patch b/patches/chromium/fix_font_face_resolution_when_renderer_is_blocked.patch deleted file mode 100644 index 714b48a48bfa9..0000000000000 --- a/patches/chromium/fix_font_face_resolution_when_renderer_is_blocked.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr <shelley.vohr@gmail.com> -Date: Tue, 4 Jun 2024 15:29:10 +0200 -Subject: Fix font face resolution when renderer is blocked - -Backports https://chromium-review.googlesource.com/c/chromium/src/+/5584820 - -As a result of https://chromium-review.googlesource.com/c/chromium/src/+/5290838, -the FontFaceSet promise in e.g. contentWindow.document.fonts.ready will never resolve -while the renderer is blocked. This Cl takes an approach similar to that taken in -MediaQueryList in order to enable the promise to be resolved. - -diff --git a/third_party/blink/renderer/core/css/font_face_set_document.cc b/third_party/blink/renderer/core/css/font_face_set_document.cc -index 79d15ae4d9de6350429b9b907d5136266d02c579..7e26808b3ef4437940ee6745d2651037c1bba9a2 100644 ---- a/third_party/blink/renderer/core/css/font_face_set_document.cc -+++ b/third_party/blink/renderer/core/css/font_face_set_document.cc -@@ -27,6 +27,7 @@ - - #include "base/metrics/histogram_functions.h" - #include "third_party/blink/public/common/features.h" -+#include "third_party/blink/public/common/metrics/document_update_reason.h" - #include "third_party/blink/renderer/bindings/core/v8/dictionary.h" - #include "third_party/blink/renderer/core/css/css_font_face.h" - #include "third_party/blink/renderer/core/css/css_font_selector.h" -@@ -141,21 +142,27 @@ FontFaceSetDocument::CSSConnectedFontFaceList() const { - } - - void FontFaceSetDocument::FireDoneEventIfPossible() { -- if (should_fire_loading_event_) { -+ Document* d = GetDocument(); -+ if (!d || !d->View()) { - return; - } -+ - if (!ShouldSignalReady()) { - return; - } -- Document* d = GetDocument(); -- if (!d) { -+ -+ // FireDoneEventIfPossible gets scheduled via PostTask at the end of a -+ // successful style+layout update. An invalidation may have occurred in -+ // the interim, so update style and layout synchronously here. -+ d->UpdateStyleAndLayout(DocumentUpdateReason::kUnknown); -+ -+ // These values can change during style+layout update, so check them -+ // *after* the call to UpdateStyleAndLayout. -+ if (should_fire_loading_event_) { - return; - } - -- // If the layout was invalidated in between when we thought layout -- // was updated and when we're ready to fire the event, just wait -- // until after the next layout before firing events. -- if (!d->View() || d->View()->NeedsLayout()) { -+ if (!ShouldSignalReady()) { - return; - } - diff --git a/patches/chromium/fix_harden_blink_scriptstate_maybefrom.patch b/patches/chromium/fix_harden_blink_scriptstate_maybefrom.patch index 9fc80aaa197bd..414ef004c2861 100644 --- a/patches/chromium/fix_harden_blink_scriptstate_maybefrom.patch +++ b/patches/chromium/fix_harden_blink_scriptstate_maybefrom.patch @@ -3,6 +3,9 @@ From: deepak1556 <hop2deep@gmail.com> Date: Wed, 28 Jun 2023 21:11:40 +0900 Subject: fix: harden blink::ScriptState::MaybeFrom +NOTE: since https://chromium-review.googlesource.com/c/chromium/src/+/6973697 +the patch is only needed for 32-bit builds. + This is needed as side effect of https://chromium-review.googlesource.com/c/chromium/src/+/4609446 which now gets blink::ExecutionContext from blink::ScriptState and there are isolate callbacks which get entered from Node.js @@ -40,7 +43,7 @@ accessing uninitialized lower indexes can return garbage values that cannot be n Refer to v8::EmbedderDataSlot::store_aligned_pointer for context. diff --git a/gin/public/gin_embedders.h b/gin/public/gin_embedders.h -index 8d7c5631fd8f1499c67384286f0e3c4037673b32..2b7bdfbac06a42e6bc51eb65e023c3673e6eb885 100644 +index cecf528475cb832ed1876381878eade582bc83d6..71308b2d963c2d083328aad6be356dc547ba5629 100644 --- a/gin/public/gin_embedders.h +++ b/gin/public/gin_embedders.h @@ -20,6 +20,8 @@ enum GinEmbedder : uint16_t { @@ -51,75 +54,87 @@ index 8d7c5631fd8f1499c67384286f0e3c4037673b32..2b7bdfbac06a42e6bc51eb65e023c367 + kEmbedderBlinkTag, }; - } // namespace gin + enum EmbedderDataTag : uint16_t { diff --git a/third_party/blink/renderer/platform/bindings/script_state.cc b/third_party/blink/renderer/platform/bindings/script_state.cc -index 2d5df763b6ebb2333ae4aef909865213fb9ad4df..2370f00a3f5ee70604c93a0999ea5cee3c9898f9 100644 +index 8b6522c9299bef5ab766795b64a1ba30bc382a12..a714aeb8a62886bedb3820b33b49b1ebdb9c7cc0 100644 --- a/third_party/blink/renderer/platform/bindings/script_state.cc +++ b/third_party/blink/renderer/platform/bindings/script_state.cc -@@ -13,6 +13,10 @@ namespace blink { +@@ -14,6 +14,12 @@ namespace blink { ScriptState::CreateCallback ScriptState::s_create_callback_ = nullptr; ++#if defined(ARCH_CPU_32_BITS) +int const ScriptState::kScriptStateTag = 0x6e6f64; +void* const ScriptState::kScriptStateTagPtr = const_cast<void*>( + static_cast<const void*>(&ScriptState::kScriptStateTag)); ++#endif // defined(ARCH_CPU_32_BITS) + // static void ScriptState::SetCreateCallback(CreateCallback create_callback) { DCHECK(create_callback); -@@ -37,6 +41,8 @@ ScriptState::ScriptState(v8::Local<v8::Context> context, - DCHECK(world_); +@@ -40,6 +46,10 @@ ScriptState::ScriptState(v8::Local<v8::Context> context, context_.SetWeak(this, &OnV8ContextCollectedCallback); - context->SetAlignedPointerInEmbedderData(kV8ContextPerContextDataIndex, this); + context->SetAlignedPointerInEmbedderData(kV8ContextPerContextDataIndex, this, + gin::kBlinkScriptState); ++#if defined(ARCH_CPU_32_BITS) + context->SetAlignedPointerInEmbedderData( -+ kV8ContextPerContextDataTagIndex, ScriptState::kScriptStateTagPtr); ++ kV8ContextPerContextDataTagIndex, ScriptState::kScriptStateTagPtr, v8::kEmbedderDataTypeTagDefault); ++#endif // defined(ARCH_CPU_32_BITS) RendererResourceCoordinator::Get()->OnScriptStateCreated(this, execution_context); } -@@ -80,6 +86,8 @@ void ScriptState::DissociateContext() { +@@ -83,6 +93,10 @@ void ScriptState::DissociateContext() { // Cut the reference from V8 context to ScriptState. - GetContext()->SetAlignedPointerInEmbedderData(kV8ContextPerContextDataIndex, - nullptr); + GetContext()->SetAlignedPointerInEmbedderData( + kV8ContextPerContextDataIndex, nullptr, gin::kBlinkScriptState); ++#if defined(ARCH_CPU_32_BITS) + GetContext()->SetAlignedPointerInEmbedderData( -+ kV8ContextPerContextDataTagIndex, nullptr); ++ kV8ContextPerContextDataTagIndex, nullptr, v8::kEmbedderDataTypeTagDefault); ++#endif // defined(ARCH_CPU_32_BITS) reference_from_v8_context_.Clear(); // Cut the reference from ScriptState to V8 context. diff --git a/third_party/blink/renderer/platform/bindings/script_state.h b/third_party/blink/renderer/platform/bindings/script_state.h -index b3cc8d819b06108386aed9465cab4f27a28b675f..9c8818f10de59fdd2a3fd44d9cd23d40a93b53a7 100644 +index 5ccdf26cead17031d510589b74288cbe79692779..bf3023d5305c05c5d92953b5bf5f655f964e5c28 100644 --- a/third_party/blink/renderer/platform/bindings/script_state.h +++ b/third_party/blink/renderer/platform/bindings/script_state.h -@@ -185,7 +185,12 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> { - v8::Local<v8::Context> context) { - DCHECK(!context.IsEmpty()); - if (context->GetNumberOfEmbedderDataFields() <= -- kV8ContextPerContextDataIndex) { -+ kV8ContextPerContextDataTagIndex) { -+ return nullptr; -+ } -+ if (context->GetAlignedPointerFromEmbedderData( -+ kV8ContextPerContextDataTagIndex) != -+ ScriptState::kScriptStateTagPtr) { +@@ -6,6 +6,7 @@ + #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_SCRIPT_STATE_H_ + + #include "base/memory/raw_ptr.h" ++#include "build/build_config.h" + #include "gin/public/context_holder.h" + #include "gin/public/gin_embedders.h" + #include "third_party/blink/public/common/tokens/tokens.h" +@@ -188,6 +189,16 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> { + kV8ContextPerContextDataIndex) { return nullptr; } ++#if defined(ARCH_CPU_32_BITS) ++ if (context->GetNumberOfEmbedderDataFields() <= ++ kV8ContextPerContextDataTagIndex || ++ context->GetAlignedPointerFromEmbedderData( ++ kV8ContextPerContextDataTagIndex, ++ v8::kEmbedderDataTypeTagDefault) != ++ ScriptState::kScriptStateTagPtr) { ++ return nullptr; ++ } ++#endif // defined(ARCH_CPU_32_BITS) ScriptState* script_state = -@@ -263,6 +268,8 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> { - static void SetCreateCallback(CreateCallback); - friend class ScriptStateImpl; + static_cast<ScriptState*>(context->GetAlignedPointerFromEmbedderData( + isolate, kV8ContextPerContextDataIndex, gin::kBlinkScriptState)); +@@ -270,6 +281,14 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> { + static_cast<int>(gin::kPerContextDataStartIndex) + + static_cast<int>(gin::kEmbedderBlink); ++#if defined(ARCH_CPU_32_BITS) + static void* const kScriptStateTagPtr; + static int const kScriptStateTag; - static constexpr int kV8ContextPerContextDataIndex = - static_cast<int>(gin::kPerContextDataStartIndex) + - static_cast<int>(gin::kEmbedderBlink); -@@ -271,6 +278,10 @@ class PLATFORM_EXPORT ScriptState : public GarbageCollected<ScriptState> { - // internals.idl. - String last_compiled_script_file_name_; - bool last_compiled_script_used_code_cache_ = false; -+ + static constexpr int kV8ContextPerContextDataTagIndex = + static_cast<int>(gin::kPerContextDataStartIndex) + + static_cast<int>(gin::kEmbedderBlinkTag); - }; - - // ScriptStateProtectingContext keeps the context associated with the ++#endif // defined(ARCH_CPU_32_BITS) ++ + // For accessing information about the last script compilation via + // internals.idl. + String last_compiled_script_file_name_; diff --git a/patches/chromium/fix_linux_tray_id.patch b/patches/chromium/fix_linux_tray_id.patch new file mode 100644 index 0000000000000..44e657298b898 --- /dev/null +++ b/patches/chromium/fix_linux_tray_id.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Damglador <vse.stopchanskyi@gmail.com> +Date: Mon, 27 Oct 2025 23:35:43 +0100 +Subject: fix: allow setting tray id + +This is needed to allow setting custom tray id when initializing a tray icon. +With current behaviour all programs get chrome_status_icon_1 as their id in tray. +So tray can't tell apart Electron apps, +which introduces issues like https://bugs.kde.org/show_bug.cgi?id=470840. + +This patch can be removed after being upstreamed. See discussion at +https://github.com/electron/electron/pull/48675#issuecomment-3452781711 +for more info. + +diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc +index 72a61f80eb5dfafe2609ec9e3f8f34c7c84f7abe..c5c3092607b4dc0e1fa7f7fc39b8f7e82d59ffd7 100644 +--- a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc ++++ b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc +@@ -133,8 +133,8 @@ int NextServiceId() { + return ++status_icon_count; + } + +-std::string PropertyIdFromId(int service_id) { +- return "chrome_status_icon_" + base::NumberToString(service_id); ++std::string PropertyIdFromId(int service_id, const std::string_view app_name) { ++ return base::StrCat({ app_name, "_status_icon_", base::NumberToString(service_id) }); + } + + using DbusImage = std::tuple</*width=*/int32_t, +@@ -224,12 +224,13 @@ base::FilePath WriteIconFile(size_t icon_file_id, + + } // namespace + +-StatusIconLinuxDbus::StatusIconLinuxDbus() ++StatusIconLinuxDbus::StatusIconLinuxDbus(const std::string_view app_name) + : bus_(dbus_thread_linux::GetSharedSessionBus()), + should_write_icon_to_file_(ShouldWriteIconToFile()), + icon_task_runner_(base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::USER_VISIBLE, +- base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) { ++ base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), ++ app_name_(app_name) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + CheckStatusNotifierWatcherHasOwner(); + } +@@ -405,7 +406,7 @@ void StatusIconLinuxDbus::OnHostRegisteredResponse( + properties_->SetProperty<"s">(kInterfaceStatusNotifierItem, kPropertyCategory, + kPropertyValueCategory, false); + properties_->SetProperty<"s">(kInterfaceStatusNotifierItem, kPropertyId, +- PropertyIdFromId(service_id_), false); ++ PropertyIdFromId(service_id_, app_name_), false); + properties_->SetProperty<"s">(kInterfaceStatusNotifierItem, + kPropertyOverlayIconName, "", false); + properties_->SetProperty<"s">(kInterfaceStatusNotifierItem, kPropertyStatus, +diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h +index 5457f98158a094a5b8768352d2868e3005afd395..13ac4e51019ea68fdccd17aac8a4855bde50964b 100644 +--- a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h ++++ b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h +@@ -37,7 +37,7 @@ class StatusIconLinuxDbus : public ui::StatusIconLinux, + public ui::SimpleMenuModel::Delegate, + public base::RefCounted<StatusIconLinuxDbus> { + public: +- StatusIconLinuxDbus(); ++ StatusIconLinuxDbus(const std::string_view app_name = "chrome"); + + StatusIconLinuxDbus(const StatusIconLinuxDbus&) = delete; + StatusIconLinuxDbus& operator=(const StatusIconLinuxDbus&) = delete; +@@ -135,6 +135,8 @@ class StatusIconLinuxDbus : public ui::StatusIconLinux, + size_t icon_file_id_ = 0; + base::FilePath icon_file_; + ++ std::string app_name_; ++ + base::WeakPtrFactory<StatusIconLinuxDbus> weak_factory_{this}; + }; + diff --git a/patches/chromium/fix_move_autopipsettingshelper_behind_branding_buildflag.patch b/patches/chromium/fix_move_autopipsettingshelper_behind_branding_buildflag.patch index 3dcd4fd9c4dd6..2123f36cd5102 100644 --- a/patches/chromium/fix_move_autopipsettingshelper_behind_branding_buildflag.patch +++ b/patches/chromium/fix_move_autopipsettingshelper_behind_branding_buildflag.patch @@ -9,7 +9,7 @@ to support content settings UI. The support pulls in chrome content settings and UI code which are not valid in the scope of Electron. diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc -index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6779840a4 100644 +index a8a1ec300d9286f641f4676be54121eddc9c0ba1..b25a7fe369207f24b52cf1c98abe70f403b95ded 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc @@ -6,6 +6,7 @@ @@ -18,20 +18,20 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 #include "base/numerics/safe_conversions.h" +#include "build/branding_buildflags.h" #include "chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.h" - #include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h" #include "chrome/browser/ui/browser_navigator_params.h" -@@ -28,8 +29,10 @@ + #include "content/public/browser/document_picture_in_picture_window_controller.h" +@@ -31,8 +32,10 @@ #include "base/task/sequenced_task_runner.h" // TODO(crbug.com/421608904): include auto_picture_in_picture_tab_helper for - // Android. + // Android when supporting document PiP. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" #include "chrome/browser/picture_in_picture/auto_pip_setting_overlay_view.h" +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) + #include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h" #include "chrome/browser/picture_in_picture/picture_in_picture_window.h" #include "media/base/media_switches.h" - #include "net/base/url_util.h" -@@ -64,6 +67,7 @@ constexpr double kMaxWindowSizeRatio = 0.8; +@@ -67,6 +70,7 @@ constexpr double kMaxWindowSizeRatio = 0.8; // `kMaxWindowSizeRatio`. constexpr double kMaxSiteRequestedWindowSizeRatio = 0.25; @@ -39,7 +39,7 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 // Returns true if a document picture-in-picture window should be focused upon // opening it. bool ShouldFocusPictureInPictureWindow(const NavigateParams& params) { -@@ -80,6 +84,7 @@ bool ShouldFocusPictureInPictureWindow(const NavigateParams& params) { +@@ -83,6 +87,7 @@ bool ShouldFocusPictureInPictureWindow(const NavigateParams& params) { // AutoPictureInPictureTabHelper. return !auto_picture_in_picture_tab_helper->IsInAutoPictureInPicture(); } @@ -47,7 +47,7 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 // Returns the maximum area in pixels that the site can request a // picture-in-picture window to be. -@@ -217,7 +222,7 @@ bool PictureInPictureWindowManager::ExitPictureInPictureViaWindowUi( +@@ -220,7 +225,7 @@ bool PictureInPictureWindowManager::ExitPictureInPictureViaWindowUi( return false; } @@ -56,7 +56,7 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 // The user manually closed the pip window, so let the tab helper know in case // the auto-pip permission dialog was visible. if (auto* tab_helper = AutoPictureInPictureTabHelper::FromWebContents( -@@ -556,7 +561,7 @@ gfx::Size PictureInPictureWindowManager::GetMaximumWindowSize( +@@ -571,7 +576,7 @@ gfx::Size PictureInPictureWindowManager::GetMaximumWindowSize( // static void PictureInPictureWindowManager::SetWindowParams(NavigateParams& params) { @@ -64,8 +64,8 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 +#if !BUILDFLAG(IS_ANDROID) && BUILDFLAG(GOOGLE_CHROME_BRANDING) // Always show document picture-in-picture in a new window. When this is // not opened via the AutoPictureInPictureTabHelper, focus the window. - params.window_action = ShouldFocusPictureInPictureWindow(params) -@@ -657,6 +662,7 @@ PictureInPictureWindowManager::GetOverlayView( + params.window_action = +@@ -672,6 +677,7 @@ PictureInPictureWindowManager::GetOverlayView( return nullptr; } @@ -73,7 +73,7 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 // It would be nice to create this in `EnterPictureInPicture*`, but detecting // auto-pip while pip is in the process of opening doesn't work. // -@@ -695,6 +701,8 @@ PictureInPictureWindowManager::GetOverlayView( +@@ -710,6 +716,8 @@ PictureInPictureWindowManager::GetOverlayView( } return overlay_view; @@ -83,10 +83,10 @@ index 32f0f62dbc4f0c541440fd99d20e0fc80825f480..bcf7e67eb024a6ec8d2470a338e016c6 PictureInPictureOcclusionTracker* diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc -index 489d68b6452a4814f4cba1e65ab036629583f5b5..a306cbb8e5bfa585bceb140a0c66d1c64b7a8813 100644 +index 601b178ef0e90753559083f506c9a62a7434c530..2a0f9f87d833504e34ad7d72c0cdd974c0318639 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc -@@ -471,11 +471,13 @@ std::unique_ptr<VideoOverlayWindowViews> VideoOverlayWindowViews::Create( +@@ -451,11 +451,13 @@ std::unique_ptr<VideoOverlayWindowViews> VideoOverlayWindowViews::Create( #endif // BUILDFLAG(IS_WIN) diff --git a/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch b/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch index 1fa8621a09e87..e122bee517cdb 100644 --- a/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch +++ b/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch @@ -13,13 +13,13 @@ messages in the legacy window handle layer. These conditions are regularly hit with WCO-enabled windows on Windows. diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc -index 475629d48e8807547e0c79f6fa00d458bac3416c..97f4520fbf7797b19747b5101097d93cf475fb5c 100644 +index 54ef4e8fb7dc5a942741912e1662ae132a56e984..1a7ce67dc418119b0a2b432f41ccc3b672a8da96 100644 --- a/content/browser/renderer_host/legacy_render_widget_host_win.cc +++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc -@@ -375,12 +375,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, +@@ -378,12 +378,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message, + LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, WPARAM w_param, - LPARAM l_param, - BOOL& handled) { + LPARAM l_param) { - if (message == WM_MOUSEMOVE) { + if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE) { if (!mouse_tracking_enabled_) { @@ -31,27 +31,27 @@ index 475629d48e8807547e0c79f6fa00d458bac3416c..97f4520fbf7797b19747b5101097d93c tme.hwndTrack = hwnd(); tme.dwHoverTime = 0; TrackMouseEvent(&tme); -@@ -413,7 +413,10 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, +@@ -416,7 +416,10 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, // the picture. - if (!handled && + if (!msg_handled && (message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) { - ret = ::DefWindowProc(GetParent(), message, w_param, l_param); + // Send WM_NCMOUSEMOVE messages using the LegacyRenderWidgetHostHWND's + // handle so mouse tracking on non-client areas doesn't break. + HWND target = message == WM_NCMOUSEMOVE ? hwnd() : GetParent(); + ret = ::DefWindowProc(target, message, w_param, l_param); - handled = TRUE; + SetMsgHandled(TRUE); } return ret; diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h -index f9699ff0abf9036e9e1cabf626aa6395584cf896..94a8a50cb630182103c4256352d7a8a2acc8c76a 100644 +index ec3e5576b0b5f5c6f2ed5158a80d7816dbfbb702..ac5005fe7378ae1628db161b49fe16ea0a93b33a 100644 --- a/content/browser/renderer_host/legacy_render_widget_host_win.h +++ b/content/browser/renderer_host/legacy_render_widget_host_win.h -@@ -105,6 +105,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND - MESSAGE_HANDLER_EX(WM_VSCROLL, OnScroll) - MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest) - MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange) -+ MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave) - MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize) - MESSAGE_HANDLER_EX(WM_SIZE, OnSize) - MESSAGE_HANDLER_EX(WM_DESTROY, OnDestroy) +@@ -109,6 +109,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND + CR_MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest) + CR_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, + OnMouseRange) ++ CR_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave) + CR_MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize) + CR_MESSAGE_HANDLER_EX(WM_SIZE, OnSize) + CR_MESSAGE_HANDLER_EX(WM_CREATE, OnCreate) diff --git a/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch b/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch index 94c8680e86009..984cdb085b8e6 100644 --- a/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch +++ b/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch @@ -9,10 +9,10 @@ focus node change via TextInputManager. chromium-bug: https://crbug.com/1369605 diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc -index b930145db575eb8c4e84297ddd610bd90fb5d3a8..8407b3a87219d314617295fa664c39b5daa2ce0a 100644 +index 87fd5aa4fab7ddd0b444a3c8473ae35066c87054..6edf04acfaea8029e7dd1a573942cdd0ecd610c3 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc -@@ -3249,6 +3249,12 @@ void RenderWidgetHostViewAura::OnTextSelectionChanged( +@@ -3345,6 +3345,12 @@ void RenderWidgetHostViewAura::OnTextSelectionChanged( } } @@ -26,10 +26,10 @@ index b930145db575eb8c4e84297ddd610bd90fb5d3a8..8407b3a87219d314617295fa664c39b5 RenderWidgetHostViewAura* popup_child_host_view) { popup_child_host_view_ = popup_child_host_view; diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h -index 7328d8cc05de07a66685ce4ca41a57385b7acc6b..6c757ec57d2bffa638b49c9c1d9c0825ccc0d909 100644 +index da64a2093e5ab60b320a1ea2b12a920956ef9605..9f1e856d0947c3ce1f21e001c5278f61cbda05d3 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h -@@ -652,6 +652,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura +@@ -664,6 +664,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura RenderWidgetHostViewBase* updated_view) override; void OnTextSelectionChanged(TextInputManager* text_input_mangager, RenderWidgetHostViewBase* updated_view) override; @@ -87,10 +87,10 @@ index 75df43e3cd2721a92c90c18154d53d5c203e2465..ce42c75c8face36d21f53f44c0201ac4 // The view with active text input state, i.e., a focused <input> element. // It will be nullptr if no such view exists. Note that the active view diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index 0a6a205f49d7bc853879ac4919868aadd6fdd42f..3a9264493f90fb8e82e34e13328d74c00d156966 100644 +index 075ea7cd9f097b60adcad2857cf7115deb3741bc..6b58df7202c19bda334f711d91af09839f461911 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -10089,7 +10089,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame( +@@ -10133,7 +10133,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame( "WebContentsImpl::OnFocusedElementChangedInFrame", "render_frame_host", frame); RenderWidgetHostViewBase* root_view = diff --git a/patches/chromium/fix_properly_honor_printing_page_ranges.patch b/patches/chromium/fix_properly_honor_printing_page_ranges.patch index 972d369b3ccd8..8194b41fb0de8 100644 --- a/patches/chromium/fix_properly_honor_printing_page_ranges.patch +++ b/patches/chromium/fix_properly_honor_printing_page_ranges.patch @@ -25,10 +25,10 @@ index 8be4ca70ff71cfc33cd812ec0cc9ae8155538532..f7985331838387232b27e557e4351134 // Returns true if duplex mode is set. bool SetDuplexModeInPrintSettings(mojom::DuplexMode mode); diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm -index b504350cb53273d1db7204771ae080647fe6b878..8fdf6a14d0913aca8f14c412c4afae3ad7ec37e5 100644 +index a8afc92f4894f32774573920271f1eb7c47822c2..963ad79fb4b46e048a36e1b7e696f7e0d26ed151 100644 --- a/printing/printing_context_mac.mm +++ b/printing/printing_context_mac.mm -@@ -522,7 +522,8 @@ bool IsIppColorModelColorful(mojom::ColorModel color_model) { +@@ -544,7 +544,8 @@ bool IsIppColorModelColorful(mojom::ColorModel color_model) { !SetCollateInPrintSettings(settings_->collate()) || !SetDuplexModeInPrintSettings(settings_->duplex_mode()) || !SetOutputColor(static_cast<int>(settings_->color())) || @@ -38,7 +38,7 @@ index b504350cb53273d1db7204771ae080647fe6b878..8fdf6a14d0913aca8f14c412c4afae3a return OnError(); } } -@@ -675,6 +676,22 @@ bool IsIppColorModelColorful(mojom::ColorModel color_model) { +@@ -697,6 +698,22 @@ bool IsIppColorModelColorful(mojom::ColorModel color_model) { return PMSetCopies(print_settings, copies, false) == noErr; } @@ -62,7 +62,7 @@ index b504350cb53273d1db7204771ae080647fe6b878..8fdf6a14d0913aca8f14c412c4afae3a PMPrintSettings print_settings = static_cast<PMPrintSettings>([print_info_ PMPrintSettings]); diff --git a/printing/printing_context_system_dialog_win.cc b/printing/printing_context_system_dialog_win.cc -index 2808248f6eb3f5c75f20775d61c9d0d20aaaecf6..c7367251f5b9735994ac4c173281b89d1c5f4579 100644 +index f8e903f21cee7041dea67b479c298baf9093d719..ed5d59f29992b0925efd89cb0ac4b33a03a31788 100644 --- a/printing/printing_context_system_dialog_win.cc +++ b/printing/printing_context_system_dialog_win.cc @@ -4,10 +4,12 @@ @@ -78,12 +78,11 @@ index 2808248f6eb3f5c75f20775d61c9d0d20aaaecf6..c7367251f5b9735994ac4c173281b89d #include "base/strings/utf_string_conversions.h" #include "base/task/current_thread.h" #include "printing/backend/win_helper.h" -@@ -74,14 +76,28 @@ void PrintingContextSystemDialogWin::AskUserForSettings( - PRINTPAGERANGE ranges[32]; +@@ -74,13 +76,28 @@ void PrintingContextSystemDialogWin::AskUserForSettings( + PRINTPAGERANGE ranges[32] = {}; dialog_options.nStartPage = START_PAGE_GENERAL; if (max_pages) { - // Default initialize to print all the pages. -- UNSAFE_TODO(memset(ranges, 0, sizeof(ranges))); - ranges[0].nFromPage = 1; - ranges[0].nToPage = max_pages; - dialog_options.nPageRanges = 1; diff --git a/patches/chromium/fix_remove_caption-removing_style_call.patch b/patches/chromium/fix_remove_caption-removing_style_call.patch index 610abd8000b5e..48214c6be71e2 100644 --- a/patches/chromium/fix_remove_caption-removing_style_call.patch +++ b/patches/chromium/fix_remove_caption-removing_style_call.patch @@ -18,10 +18,10 @@ or resizing, but Electron does not seem to run into that issue for opaque frameless windows even with that block commented out. diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index 3ed583cf09dec0ae83c3c9449e6ef7e1fa92aa8d..1287e9eda295061a7ee9b758b3c0618933896d82 100644 +index a834cc49a3a02acdcd127f3f0fb084fa806435e5..1633d495f43d34f71e8238dca0b30e990f96b459 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -1857,7 +1857,23 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) { +@@ -1864,7 +1864,23 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) { SendMessage(hwnd(), WM_CHANGEUISTATE, MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0); diff --git a/patches/chromium/fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch b/patches/chromium/fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch index 6ebdf419dba5f..b02b34ac72df0 100644 --- a/patches/chromium/fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch +++ b/patches/chromium/fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch @@ -8,7 +8,7 @@ such as the background turning black when maximizing the window and dynamic background material settings not taking effect. diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -index ed4d2c4d849085c0e7830c5d52d47daf2700ce34..31ee28c3f8d04a4a9239a781ef9f79da8ee699b9 100644 +index 392de361fe395b81b346abb477d91d495d00ba34..14b5a59b307179722f28e1cbcf1de220055d0075 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -183,6 +183,10 @@ void DesktopWindowTreeHostWin::FinishTouchDrag(gfx::Point screen_point) { @@ -23,7 +23,7 @@ index ed4d2c4d849085c0e7830c5d52d47daf2700ce34..31ee28c3f8d04a4a9239a781ef9f79da void DesktopWindowTreeHostWin::Init(const Widget::InitParams& params) { diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h -index d8be4dffee3947e7ac6dc09cb8e1f2a6a834789b..8eb539af74c1934a55f9b14ad97dd93bca828d34 100644 +index 0cd07fd5fb55dcc0d972de4c027fcb895d156592..0f4d335e1d54b5e92fc217080d86513db94d4122 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h @@ -93,6 +93,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin @@ -36,10 +36,10 @@ index d8be4dffee3947e7ac6dc09cb8e1f2a6a834789b..8eb539af74c1934a55f9b14ad97dd93b // Overridden from DesktopWindowTreeHost: void Init(const Widget::InitParams& params) override; diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index 1287e9eda295061a7ee9b758b3c0618933896d82..e2b899dd25c12448068c99f1344cba4fea26e2c6 100644 +index 1633d495f43d34f71e8238dca0b30e990f96b459..60d952d3d0ebf99c6b22bd35b952cea39cdd82ef 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -994,13 +994,13 @@ void HWNDMessageHandler::FrameTypeChanged() { +@@ -1001,13 +1001,13 @@ void HWNDMessageHandler::FrameTypeChanged() { void HWNDMessageHandler::PaintAsActiveChanged() { if (!delegate_->HasNonClientView() || !delegate_->CanActivate() || @@ -55,7 +55,7 @@ index 1287e9eda295061a7ee9b758b3c0618933896d82..e2b899dd25c12448068c99f1344cba4f } void HWNDMessageHandler::SetWindowIcons(const gfx::ImageSkia& window_icon, -@@ -1084,7 +1084,14 @@ void HWNDMessageHandler::SizeConstraintsChanged() { +@@ -1088,7 +1088,14 @@ void HWNDMessageHandler::SizeConstraintsChanged() { // allowing ui::GetResizableFrameThickness() to be used consistently when // removing the visible system frame. const bool had_caption_on_init = window_style() & WS_CAPTION; @@ -71,7 +71,7 @@ index 1287e9eda295061a7ee9b758b3c0618933896d82..e2b899dd25c12448068c99f1344cba4f const bool can_maximize = can_resize && delegate_->CanMaximize(); auto set_style_func = [&style](LONG bit, bool should_set) { -@@ -1679,11 +1686,16 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) { +@@ -1686,11 +1693,16 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) { // through, but that isn't the case when using Direct3D to draw transparent // windows. So we route translucent windows throught to the delegate to // allow for a custom hit mask. @@ -89,7 +89,7 @@ index 1287e9eda295061a7ee9b758b3c0618933896d82..e2b899dd25c12448068c99f1344cba4f return; } -@@ -2415,17 +2427,18 @@ LRESULT HWNDMessageHandler::OnNCActivate(UINT message, +@@ -2423,17 +2435,18 @@ LRESULT HWNDMessageHandler::OnNCActivate(UINT message, delegate_->SchedulePaint(); } diff --git a/patches/chromium/fix_restore_original_resize_performance_on_macos.patch b/patches/chromium/fix_restore_original_resize_performance_on_macos.patch index a3e7d3b7dbaeb..a6c2b8dd4d6fe 100644 --- a/patches/chromium/fix_restore_original_resize_performance_on_macos.patch +++ b/patches/chromium/fix_restore_original_resize_performance_on_macos.patch @@ -11,10 +11,10 @@ This patch should be upstreamed as a conditional revert of the logic in desktop vs mobile runtimes. i.e. restore the old logic only on desktop platforms diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc -index 8073bdba33d6ddbc0306e8e9256b36cd87537eca..7ae6336c4e3c09ae16639b616a4757f75a044bc4 100644 +index f28d6f919b5c6aca87c3feb701967a255c45d7db..2fa9876286ecda6a60a2c1970896cb275bbd7ab9 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc -@@ -2164,9 +2164,8 @@ RenderWidgetHostImpl::GetWidgetInputHandler() { +@@ -2156,9 +2156,8 @@ RenderWidgetHostImpl::GetWidgetInputHandler() { void RenderWidgetHostImpl::NotifyScreenInfoChanged() { // The resize message (which may not happen immediately) will carry with it // the screen info as well as the new size (if the screen has changed scale diff --git a/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch b/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch index 49cc427c921c2..9a2da412b0b81 100644 --- a/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch +++ b/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch @@ -20,10 +20,10 @@ index fc9cb7e68bdad4c40fab63f70243e09ad005ab80..199fbceda530da31aab9126d78b4bd21 injector_->ExpectsResults(), injector_->ShouldWaitForPromise()); } diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h -index ca2155188474863dca7a811a9c484027447026e8..4c4064f99bbffe03c525694797aef70e9decd346 100644 +index e4362d8b19bc91a56d84f2fb2756cc8489b98287..a4594215dbec1a77bf511297a5a1a8886b542e97 100644 --- a/third_party/blink/public/web/web_local_frame.h +++ b/third_party/blink/public/web/web_local_frame.h -@@ -462,6 +462,7 @@ class BLINK_EXPORT WebLocalFrame : public WebFrame { +@@ -463,6 +463,7 @@ class BLINK_EXPORT WebLocalFrame : public WebFrame { mojom::EvaluationTiming, mojom::LoadEventBlockingOption, WebScriptExecutionCallback, @@ -59,10 +59,10 @@ index cba373664bec3a32abad6fe0396bd67b53b7e67f..a54f1b3351efd2d8f324436f7f35cd43 #endif // THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SCRIPT_EXECUTION_CALLBACK_H_ diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc -index 7aeff27d6005d70f962fcbd90e6902987e3abd09..37eb4b97f9f1f90998e65f6cb253f826b27088a4 100644 +index b299f0dbfcc23458390d2c7298cc5df33f129b2b..80e7e0674d5b11836f40a5f338e7f850050e1776 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc -@@ -3176,6 +3176,7 @@ void LocalFrame::RequestExecuteScript( +@@ -3192,6 +3192,7 @@ void LocalFrame::RequestExecuteScript( mojom::blink::EvaluationTiming evaluation_timing, mojom::blink::LoadEventBlockingOption blocking_option, WebScriptExecutionCallback callback, @@ -70,7 +70,7 @@ index 7aeff27d6005d70f962fcbd90e6902987e3abd09..37eb4b97f9f1f90998e65f6cb253f826 BackForwardCacheAware back_forward_cache_aware, mojom::blink::WantResultOption want_result_option, mojom::blink::PromiseResultOption promise_behavior) { -@@ -3208,7 +3209,7 @@ void LocalFrame::RequestExecuteScript( +@@ -3250,7 +3251,7 @@ void LocalFrame::RequestExecuteScript( PausableScriptExecutor::CreateAndRun( script_state, std::move(script_sources), execute_script_policy, user_gesture, evaluation_timing, blocking_option, want_result_option, @@ -80,10 +80,10 @@ index 7aeff27d6005d70f962fcbd90e6902987e3abd09..37eb4b97f9f1f90998e65f6cb253f826 void LocalFrame::SetEvictCachedSessionStorageOnFreezeOrUnload() { diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h -index b68a56d2dd05ce614c9b2c387dc960bad58fab0b..e53bad5ef91d6d86d25996a62f26a24015b607fe 100644 +index 6a09da6989fc007aed611cdce1939c2bf03deb49..daf57898ecd61dadb53761ad413f44d92c647e2f 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h -@@ -831,6 +831,7 @@ class CORE_EXPORT LocalFrame final +@@ -834,6 +834,7 @@ class CORE_EXPORT LocalFrame final mojom::blink::EvaluationTiming, mojom::blink::LoadEventBlockingOption, WebScriptExecutionCallback, @@ -92,10 +92,10 @@ index b68a56d2dd05ce614c9b2c387dc960bad58fab0b..e53bad5ef91d6d86d25996a62f26a240 mojom::blink::WantResultOption, mojom::blink::PromiseResultOption); diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc -index a7d638b474011b564f326b128183278fd3fdb6e2..11a49018d7c004f34897d1a7f21c7e4705da023c 100644 +index f3ea156c7ea1f215476976bcea2438d04c59a63f..146d44491158c4b6d3f33d61a6f242e8d8d42faf 100644 --- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc +++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc -@@ -968,6 +968,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld( +@@ -981,6 +981,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld( std::move(callback).Run(value ? std::move(*value) : base::Value()); }, std::move(callback)), @@ -104,7 +104,7 @@ index a7d638b474011b564f326b128183278fd3fdb6e2..11a49018d7c004f34897d1a7f21c7e47 wants_result ? mojom::blink::WantResultOption::kWantResultDateAndRegExpAllowed diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc -index 19e5c838cc17844092df5652542a767316bc03b2..105f61bf14cdcfbf9cd284d80ba7bde756d5fcf2 100644 +index 7c31a69ccd7a74d75e5df63d895b91239d243a92..1b435cb43592afba984fe203d1ccf2d9f4ef85f5 100644 --- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc +++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc @@ -243,7 +243,7 @@ void PausableScriptExecutor::CreateAndRun( @@ -173,10 +173,10 @@ index 19e5c838cc17844092df5652542a767316bc03b2..105f61bf14cdcfbf9cd284d80ba7bde7 } diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.h b/third_party/blink/renderer/core/frame/pausable_script_executor.h -index fa65331f40b90d812b71a489fd560e9359152d2b..390714d631dc88ef92d59ef9618a5706b4b52f22 100644 +index f2c94689450f0333a144ccf82cf147c194896e6b..1c2e9fe36c297f7d614d9ca290e4d13c83d11eb5 100644 --- a/third_party/blink/renderer/core/frame/pausable_script_executor.h +++ b/third_party/blink/renderer/core/frame/pausable_script_executor.h -@@ -48,7 +48,8 @@ class CORE_EXPORT PausableScriptExecutor final +@@ -47,7 +47,8 @@ class CORE_EXPORT PausableScriptExecutor final mojom::blink::LoadEventBlockingOption, mojom::blink::WantResultOption, mojom::blink::PromiseResultOption, @@ -186,7 +186,7 @@ index fa65331f40b90d812b71a489fd560e9359152d2b..390714d631dc88ef92d59ef9618a5706 class Executor : public GarbageCollected<Executor> { public: -@@ -65,6 +66,7 @@ class CORE_EXPORT PausableScriptExecutor final +@@ -64,6 +65,7 @@ class CORE_EXPORT PausableScriptExecutor final mojom::blink::WantResultOption, mojom::blink::PromiseResultOption, WebScriptExecutionCallback, @@ -194,7 +194,7 @@ index fa65331f40b90d812b71a489fd560e9359152d2b..390714d631dc88ef92d59ef9618a5706 Executor*); ~PausableScriptExecutor() override; -@@ -83,6 +85,7 @@ class CORE_EXPORT PausableScriptExecutor final +@@ -82,6 +84,7 @@ class CORE_EXPORT PausableScriptExecutor final Member<ScriptState> script_state_; WebScriptExecutionCallback callback_; @@ -203,10 +203,10 @@ index fa65331f40b90d812b71a489fd560e9359152d2b..390714d631dc88ef92d59ef9618a5706 const mojom::blink::UserActivationOption user_activation_option_; const mojom::blink::LoadEventBlockingOption blocking_option_; diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc -index bb32bd4b10280ec767af6589efc843c264e13533..06e70645fe57b1d0576c69fd64d3532636dd9184 100644 +index 4aea5af7b5f5b389a046cbc4da42336f5987688e..317b5ec050c4221595a77f87ca320ca07e335e04 100644 --- a/third_party/blink/renderer/core/frame/web_frame_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_test.cc -@@ -295,6 +295,7 @@ void ExecuteScriptsInMainWorld( +@@ -296,6 +296,7 @@ void ExecuteScriptsInMainWorld( DOMWrapperWorld::kMainWorldId, sources, user_gesture, mojom::blink::EvaluationTiming::kSynchronous, mojom::blink::LoadEventBlockingOption::kDoNotBlock, std::move(callback), @@ -215,10 +215,10 @@ index bb32bd4b10280ec767af6589efc843c264e13533..06e70645fe57b1d0576c69fd64d35326 mojom::blink::WantResultOption::kWantResult, wait_for_promise); } diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc -index 8fd3d92ef3fb132922bcf041840161f32804fd1f..212e6d5678fbc50fc155bd9beb4806315e5c2202 100644 +index 6566e16a08dfcb02cd17a18f627c3ad425485c15..10fe6ab8e8f0fce54c00aec08325f74d0ca7c25c 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc -@@ -1121,14 +1121,15 @@ void WebLocalFrameImpl::RequestExecuteScript( +@@ -1128,14 +1128,15 @@ void WebLocalFrameImpl::RequestExecuteScript( mojom::blink::EvaluationTiming evaluation_timing, mojom::blink::LoadEventBlockingOption blocking_option, WebScriptExecutionCallback callback, @@ -237,7 +237,7 @@ index 8fd3d92ef3fb132922bcf041840161f32804fd1f..212e6d5678fbc50fc155bd9beb480631 bool WebLocalFrameImpl::IsInspectorConnected() { diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h -index a605d360906b68cd55bba57d383ff92a326d8b98..2806254047b707b65ea6117066734505b715f6d7 100644 +index a2850434615d5439fa25bcb75c8d23811564d1bc..2be52adcae8ec252a1274ccf0ca21838727e0564 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h @@ -199,6 +199,7 @@ class CORE_EXPORT WebLocalFrameImpl final @@ -248,15 +248,3 @@ index a605d360906b68cd55bba57d383ff92a326d8b98..2806254047b707b65ea6117066734505 BackForwardCacheAware back_forward_cache_aware, mojom::blink::WantResultOption, mojom::blink::PromiseResultOption) override; -diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/virtual_time_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/virtual_time_test.cc -index 5e66719cf6d8170039c011ad03d56ea55ee8f2cb..5a71dd5172c88aed1498dea02f790a7f278ac174 100644 ---- a/third_party/blink/renderer/core/scheduler_integration_tests/virtual_time_test.cc -+++ b/third_party/blink/renderer/core/scheduler_integration_tests/virtual_time_test.cc -@@ -59,6 +59,7 @@ class VirtualTimeTest : public SimTest { - mojom::blink::LoadEventBlockingOption::kDoNotBlock, - WTF::BindOnce(&ScriptExecutionCallbackHelper::Completed, - base::Unretained(&callback_helper)), -+ base::NullCallback(), - BackForwardCacheAware::kAllow, - mojom::blink::WantResultOption::kWantResult, - mojom::blink::PromiseResultOption::kDoNotWait); diff --git a/patches/chromium/fix_select_the_first_menu_item_when_opened_via_keyboard.patch b/patches/chromium/fix_select_the_first_menu_item_when_opened_via_keyboard.patch index bfabf4fc4280d..35d224ff449fc 100644 --- a/patches/chromium/fix_select_the_first_menu_item_when_opened_via_keyboard.patch +++ b/patches/chromium/fix_select_the_first_menu_item_when_opened_via_keyboard.patch @@ -6,7 +6,7 @@ Subject: fix: select the first menu item when opened via keyboard This fixes an accessibility issue where the root view is 'focused' to the screen reader instead of the first menu item as with all other native menus. This patch will be upstreamed. diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc -index c206a2ebcb069616be1205efc261ec060249f35b..0300e9b05feaa14895a05eb9ca7b41fb84a05bee 100644 +index 4fd9d4eb67842ac4232d1fe4cbb3da60c2d8c9bb..750e8886015692287bc7fa045b40c5a030cf886b 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc @@ -713,6 +713,16 @@ void MenuController::Run(Widget* parent, @@ -26,7 +26,7 @@ index c206a2ebcb069616be1205efc261ec060249f35b..0300e9b05feaa14895a05eb9ca7b41fb if (button_controller) { pressed_lock_ = button_controller->TakeLock( false, ui::LocatedEvent::FromIfValid(event)); -@@ -2456,19 +2466,15 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) { +@@ -2480,18 +2490,15 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) { } item->GetSubmenu()->ShowAt(params); @@ -39,13 +39,14 @@ index c206a2ebcb069616be1205efc261ec060249f35b..0300e9b05feaa14895a05eb9ca7b41fb + // `ConvertFromScreen` doesn't work correctly if the widget isn't shown. if (item->GetSubmenu()->GetWidget()) { const gfx::Point mouse_pos = ConvertFromScreen( - *item->submenu_, - display::Screen::GetScreen()->GetCursorScreenPoint()); +- *item->submenu_, display::Screen::Get()->GetCursorScreenPoint()); - MenuPart part_under_mouse = GetMenuPart(item->submenu_.get(), mouse_pos); - if (part_under_mouse.type != MenuPartType::kNone) { - menu_open_mouse_loc_ = - GetLocationInRootMenu(*item->submenu_, mouse_pos); - } ++ *item->submenu_, ++ display::Screen::Get()->GetCursorScreenPoint()); + menu_open_mouse_loc_ = + GetLocationInRootMenu(*item->submenu_, mouse_pos); } diff --git a/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch b/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch index dc9eef1e26e5f..5f9902240cafc 100644 --- a/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch +++ b/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch @@ -15,10 +15,10 @@ capturer was window or screen-specific, as the IDs remain valid for generic capturer as well. diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc -index d076c0f19c51c9f5aced0a6db0474089ce153496..e871d1ceff47c16fdd98d85f8ff8169041c63a79 100644 +index 24eac68b596bc11af617d1a27b20d3e8e7ab742b..ac439cbae8cb45f8f7f423aa09651109b4d874fe 100644 --- a/content/browser/media/capture/desktop_capture_device.cc +++ b/content/browser/media/capture/desktop_capture_device.cc -@@ -939,9 +939,16 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create( +@@ -1007,9 +1007,16 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create( switch (source.type) { case DesktopMediaID::TYPE_SCREEN: { @@ -38,7 +38,7 @@ index d076c0f19c51c9f5aced0a6db0474089ce153496..e871d1ceff47c16fdd98d85f8ff81690 if (screen_capturer && screen_capturer->SelectSource(source.id)) { capturer = std::make_unique<webrtc::DesktopAndCursorComposer>( std::move(screen_capturer), options); -@@ -954,8 +961,15 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create( +@@ -1026,8 +1033,15 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create( } case DesktopMediaID::TYPE_WINDOW: { diff --git a/patches/chromium/frame_host_manager.patch b/patches/chromium/frame_host_manager.patch index 27d5491f24ac2..94d421e1ff586 100644 --- a/patches/chromium/frame_host_manager.patch +++ b/patches/chromium/frame_host_manager.patch @@ -6,10 +6,10 @@ Subject: frame_host_manager.patch Allows embedder to intercept site instances created by chromium. diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc -index 15da2281d9b2e556aecd723802c952a7135edde7..4802bba61e069b99af76716c148aaaa04b7bdfad 100644 +index 53bbf0174048d62b252b797b06695e6290273e80..4350b57ebf424e392c54dd2b54e62690527ca9b6 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc -@@ -4780,6 +4780,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest( +@@ -4809,6 +4809,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest( request->ResetStateForSiteInstanceChange(); } @@ -20,10 +20,10 @@ index 15da2281d9b2e556aecd723802c952a7135edde7..4802bba61e069b99af76716c148aaaa0 } diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h -index 77addfedac20cf8ecf656321dda53ada149f17ff..b813b39b83ebb777a6de960d32ba3b64d2a31907 100644 +index 9f8fe55d6c360e3a709f2e5f05baf02c9ca29101..83a45bf47d98bef95bde6333758316aeb2a7e357 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h -@@ -339,6 +339,11 @@ class CONTENT_EXPORT ContentBrowserClient { +@@ -342,6 +342,11 @@ class CONTENT_EXPORT ContentBrowserClient { virtual ~ContentBrowserClient() = default; diff --git a/patches/chromium/gin_enable_disable_v8_platform.patch b/patches/chromium/gin_enable_disable_v8_platform.patch index c5b9746fe3f68..0e0b77efac675 100644 --- a/patches/chromium/gin_enable_disable_v8_platform.patch +++ b/patches/chromium/gin_enable_disable_v8_platform.patch @@ -7,7 +7,7 @@ We don't use gin to create the V8 platform, because we need to inject Node things. diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc -index 8a9be905bcbe9ccc8afaae2795605f87b81465d9..ab574fd81bc08e109123f07f095d26e19504baa0 100644 +index 456409c9e84c7a061d474470c8e42c5ddb5eb799..87187d05175a9da4fd7af03ba8a139a2d9554551 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -162,11 +162,13 @@ void IsolateHolder::Initialize(ScriptMode mode, @@ -27,10 +27,10 @@ index 8a9be905bcbe9ccc8afaae2795605f87b81465d9..ab574fd81bc08e109123f07f095d26e1 g_reference_table = reference_table; g_fatal_error_callback = fatal_error_callback; diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h -index ff42cfbb6a228e902317c7e3ab035d8437d5dd62..e27f177ce27e177abf6cee84cd466e7a8a829ee7 100644 +index 3909e70dc1425c2cb02624f4b3017784a2ae6c9d..a57b92f02085d6392e6d9d0cc037df6b972f3c31 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h -@@ -119,7 +119,8 @@ class GIN_EXPORT IsolateHolder { +@@ -120,7 +120,8 @@ class GIN_EXPORT IsolateHolder { std::string js_command_line_flags = {}, bool disallow_v8_feature_flag_overrides = false, v8::FatalErrorCallback fatal_error_callback = nullptr, diff --git a/patches/chromium/gritsettings_resource_ids.patch b/patches/chromium/gritsettings_resource_ids.patch index eb6127622930d..4618d5ba4a287 100644 --- a/patches/chromium/gritsettings_resource_ids.patch +++ b/patches/chromium/gritsettings_resource_ids.patch @@ -6,11 +6,11 @@ Subject: gritsettings_resource_ids.patch Add electron resources file to the list of resource ids generation. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec -index b1ac3dbdae5f57873a3259d90883500b01c5fe1a..bffba25874c654a8bbd784c48e8d49f4db2d8f26 100644 +index 6ed8fba243f6351a0f45cf459379e45ba405cf72..1dcc6586a91f716da58c09e1f5a690c75a763136 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec -@@ -1566,6 +1566,11 @@ - "structures": [10100], +@@ -1619,6 +1619,11 @@ + "messages": [10120], }, + "electron/build/electron_resources.grd": { diff --git a/patches/chromium/gtk_visibility.patch b/patches/chromium/gtk_visibility.patch index 6c8d876475640..8b0eeae1b0426 100644 --- a/patches/chromium/gtk_visibility.patch +++ b/patches/chromium/gtk_visibility.patch @@ -18,7 +18,7 @@ index fdc3442590bddda969681d49c451d32f086bd5d1..b6fd63c0c845e5d7648e8693f1639b1f # on GTK. "//examples:peerconnection_client", diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn -index e0febafa0b15711b129f9d34b88156cd76216238..f1d77b3a066d35f1d5f137f6e21e32261b4ed49a 100644 +index b7b958cf96138334f356f1d27eaabd2de75e4b5a..81e45be92cf02ea5ef9e4180d6c03c681dd1e864 100644 --- a/ui/ozone/platform/x11/BUILD.gn +++ b/ui/ozone/platform/x11/BUILD.gn @@ -6,7 +6,7 @@ import("//build/config/chromeos/ui_mode.gni") diff --git a/patches/chromium/isolate_holder.patch b/patches/chromium/isolate_holder.patch index 75aa3b9884dc7..ac281b74a347f 100644 --- a/patches/chromium/isolate_holder.patch +++ b/patches/chromium/isolate_holder.patch @@ -15,7 +15,7 @@ for us to register the isolate in between Isolate::Allocate and Isolate::Initialize. diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc -index ab574fd81bc08e109123f07f095d26e19504baa0..656267caef2d515f8c3f77535b308108a0b30be1 100644 +index 87187d05175a9da4fd7af03ba8a139a2d9554551..05c899258143a958471f361b87324f7500d594c9 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -81,7 +81,8 @@ IsolateHolder::IsolateHolder( @@ -58,10 +58,10 @@ index ab574fd81bc08e109123f07f095d26e19504baa0..656267caef2d515f8c3f77535b308108 isolate_, allocator, access_mode_, task_runner, std::move(user_visible_task_runner), std::move(best_effort_task_runner)); diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h -index e27f177ce27e177abf6cee84cd466e7a8a829ee7..dc3a5b0678b9c686e241b492e2c3b5ac833611a3 100644 +index a57b92f02085d6392e6d9d0cc037df6b972f3c31..902ad13dad8df57325f6c74ee3da9ec3148751cb 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h -@@ -88,7 +88,8 @@ class GIN_EXPORT IsolateHolder { +@@ -89,7 +89,8 @@ class GIN_EXPORT IsolateHolder { nullptr, scoped_refptr<base::SingleThreadTaskRunner> best_effort_task_runner = nullptr, @@ -71,7 +71,7 @@ index e27f177ce27e177abf6cee84cd466e7a8a829ee7..dc3a5b0678b9c686e241b492e2c3b5ac IsolateHolder( scoped_refptr<base::SingleThreadTaskRunner> task_runner, AccessMode access_mode, -@@ -98,7 +99,8 @@ class GIN_EXPORT IsolateHolder { +@@ -99,7 +100,8 @@ class GIN_EXPORT IsolateHolder { scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner = nullptr, scoped_refptr<base::SingleThreadTaskRunner> best_effort_task_runner = diff --git a/patches/chromium/load_v8_snapshot_in_browser_process.patch b/patches/chromium/load_v8_snapshot_in_browser_process.patch index 98f952b6b6f8f..38fb822adf1ba 100644 --- a/patches/chromium/load_v8_snapshot_in_browser_process.patch +++ b/patches/chromium/load_v8_snapshot_in_browser_process.patch @@ -9,10 +9,10 @@ but due to the nature of electron, we need to load the v8 snapshot in the browser process. diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc -index 733dfb4b06214f7dfe084c2ef945cad9f914eabb..46c7c57b5ff40b0e40d66bbeb8ec3f2b7f86cea0 100644 +index 86bb51dbba93f87b09b5c0003e9d700a277615dc..9240e8485a8dc895eb455b1418fc7559e52a5dd5 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc -@@ -293,11 +293,8 @@ void LoadV8SnapshotFile(const base::CommandLine& command_line) { +@@ -294,11 +294,8 @@ void LoadV8SnapshotFile(const base::CommandLine& command_line) { bool ShouldLoadV8Snapshot(const base::CommandLine& command_line, const std::string& process_type) { diff --git a/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch b/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch index 19de0716b7e6a..32512d1922ce2 100644 --- a/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch +++ b/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch @@ -9,10 +9,10 @@ be created for each child process, despite logs being redirected to a file. diff --git a/content/app/content_main.cc b/content/app/content_main.cc -index 1be84c4cc45951ce874fb4a56d18bd2cbee440a4..c51d40ccef015d6453878debecccdec5681c9614 100644 +index 47ffb24940071be6f3747a85022a2b226ae8b63b..4632bc6e1801da827a7db37484084288fd709268 100644 --- a/content/app/content_main.cc +++ b/content/app/content_main.cc -@@ -327,16 +327,14 @@ NO_STACK_PROTECTOR int RunContentProcess( +@@ -324,16 +324,14 @@ NO_STACK_PROTECTOR int RunContentProcess( #if BUILDFLAG(IS_WIN) base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); diff --git a/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch b/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch index cb66c64ff8650..9ec276281d437 100644 --- a/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch +++ b/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch @@ -35,10 +35,10 @@ system font by checking if it's kCTFontPriorityAttribute is set to system priority. diff --git a/base/BUILD.gn b/base/BUILD.gn -index 39780da0d0074845b4d17ff4f6f7e2fbf2aec59f..3eab6a8c37f351bce24b7b581e09e9471cbd527b 100644 +index 73d636ded85feb3db6582d5eab8c713fb7304b31..9c2c027ec7c22578d10d089d624f3ec395d23f1c 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn -@@ -1061,6 +1061,7 @@ component("base") { +@@ -1069,6 +1069,7 @@ component("base") { "//build:ios_buildflags", "//build/config/compiler:compiler_buildflags", "//third_party/modp_b64", @@ -194,23 +194,10 @@ index e12c1d078147d956a1d9b1bc498c1b1d6fe7b974..233362259dc4e728ed37435e65041764 } } // namespace base -diff --git a/components/os_crypt/sync/BUILD.gn b/components/os_crypt/sync/BUILD.gn -index ff1e356ff696d3830d02644969c36a71fdf32ff6..b39c716c52524b95f2d3417a98e60c0c41147c93 100644 ---- a/components/os_crypt/sync/BUILD.gn -+++ b/components/os_crypt/sync/BUILD.gn -@@ -38,6 +38,8 @@ component("sync") { - "os_crypt_mac.mm", - ] - deps += [ "//crypto:mock_apple_keychain" ] -+ deps += ["//electron/build/config:generate_mas_config"] -+ - } else if (is_win) { - sources += [ "os_crypt_win.cc" ] - deps += [ "//components/version_info" ] -diff --git a/components/os_crypt/sync/keychain_password_mac.mm b/components/os_crypt/sync/keychain_password_mac.mm -index 1d4c16a300227e5e8269e2c2564cb5e87ec8ee65..3bcbb33700b2b9349795c05c12e44b4fafcc0370 100644 ---- a/components/os_crypt/sync/keychain_password_mac.mm -+++ b/components/os_crypt/sync/keychain_password_mac.mm +diff --git a/components/os_crypt/common/keychain_password_mac.mm b/components/os_crypt/common/keychain_password_mac.mm +index caa0e420956a31be1bd744319a0e40a0e50b46cf..f19628cc0cdba39b232f55935e8eee9786b02a77 100644 +--- a/components/os_crypt/common/keychain_password_mac.mm ++++ b/components/os_crypt/common/keychain_password_mac.mm @@ -16,6 +16,7 @@ #include "base/strings/string_view_util.h" #include "build/branding_buildflags.h" @@ -219,11 +206,23 @@ index 1d4c16a300227e5e8269e2c2564cb5e87ec8ee65..3bcbb33700b2b9349795c05c12e44b4f #include "third_party/abseil-cpp/absl/cleanup/cleanup.h" using crypto::apple::Keychain; +diff --git a/components/os_crypt/sync/BUILD.gn b/components/os_crypt/sync/BUILD.gn +index 2d155f49248a24b5551cb93e010ac1a0c0f94261..23aa391aaf380f87310fb295277809f8b105d6e8 100644 +--- a/components/os_crypt/sync/BUILD.gn ++++ b/components/os_crypt/sync/BUILD.gn +@@ -61,6 +61,7 @@ component("sync") { + deps += [ + "//components/os_crypt/common:keychain_password_mac", + "//crypto:mock_apple_keychain", ++ "//electron/build/config:generate_mas_config" + ] + } else if (is_win) { + sources += [ "os_crypt_win.cc" ] diff --git a/components/remote_cocoa/app_shim/BUILD.gn b/components/remote_cocoa/app_shim/BUILD.gn -index f93b68dacdba883b259555f486417b94e80152bf..21b6b7a169e201d570d77da9dde54cc2a334c21c 100644 +index ba813851fde2660c21f99248a124161d2ac2ca07..c34f920e4a592b6798f5307c726bc34ebedf3f88 100644 --- a/components/remote_cocoa/app_shim/BUILD.gn +++ b/components/remote_cocoa/app_shim/BUILD.gn -@@ -75,6 +75,7 @@ component("app_shim") { +@@ -77,6 +77,7 @@ component("app_shim") { "//components/crash/core/common", "//components/remote_cocoa/common:mojo", "//components/system_media_controls", @@ -232,7 +231,7 @@ index f93b68dacdba883b259555f486417b94e80152bf..21b6b7a169e201d570d77da9dde54cc2 "//net", "//ui/accelerated_widget_mac", diff --git a/components/remote_cocoa/app_shim/application_bridge.mm b/components/remote_cocoa/app_shim/application_bridge.mm -index e9f4e5131238b9fb5f1b4b3e90a0cb84a7fc15b4..8b5f4cae3123ac5480ad73f0c873fca0d62f7c9f 100644 +index b5801f8d4b4d5f5ed9f70b61cbd63f28a80840a6..7bf371952ba5ce01f28c79ffe156ee33812d6874 100644 --- a/components/remote_cocoa/app_shim/application_bridge.mm +++ b/components/remote_cocoa/app_shim/application_bridge.mm @@ -12,6 +12,7 @@ @@ -270,7 +269,7 @@ index e9f4e5131238b9fb5f1b4b3e90a0cb84a7fc15b4..8b5f4cae3123ac5480ad73f0c873fca0 +#endif }; - } // namespace + bool g_is_out_of_process_app_shim = false; diff --git a/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm b/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm index f7200edbe6059ac6d7ade0672852b52da7642a71..0cc5da96411b46eb39d0c01dfec59cb503df0d9b 100644 --- a/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm @@ -385,7 +384,7 @@ index 71158ca9a7101911bb76f0c1b5300b0ff0e326b3..1441b9d4f9560c8b26d4beffe31449ed // The NSWindow used by BridgedNativeWidget. Provides hooks into AppKit that // can only be accomplished by overriding methods. diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm -index d2200451e0040a0f597a8ee28de4d16398bdf9ea..49f6579f997c8d60288add0ed8ab7bab69e1a550 100644 +index e00bf1b56121eca5ebcedc3dac25c7f873828523..40e1dec573cd626cad415e419204d10516b0ec0f 100644 --- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm +++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm @@ -21,6 +21,7 @@ @@ -433,7 +432,7 @@ index d2200451e0040a0f597a8ee28de4d16398bdf9ea..49f6579f997c8d60288add0ed8ab7bab @implementation NativeWidgetMacNSWindow { @private CommandDispatcher* __strong _commandDispatcher; -@@ -389,6 +398,8 @@ - (NSAccessibilityRole)accessibilityRole { +@@ -399,6 +408,8 @@ - (NSAccessibilityRole)accessibilityRole { // NSWindow overrides. @@ -442,7 +441,7 @@ index d2200451e0040a0f597a8ee28de4d16398bdf9ea..49f6579f997c8d60288add0ed8ab7bab + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle { if (windowStyle & NSWindowStyleMaskTitled) { if (Class customFrame = [NativeWidgetMacNSWindowTitledFrame class]) -@@ -400,6 +411,8 @@ + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle { +@@ -410,6 +421,8 @@ + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle { return [super frameViewClassForStyleMask:windowStyle]; } @@ -452,7 +451,7 @@ index d2200451e0040a0f597a8ee28de4d16398bdf9ea..49f6579f997c8d60288add0ed8ab7bab bool shouldShowWindowTitle = YES; if (_bridge) diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm -index acc9537464c2a54ffc22956873dbdba74500c20b..b0b7d98e20ed0cc63a38d6a2ce462ac63e183ed9 100644 +index f3ea2bf2d15d815a2409441a9033a92d5d8967c1..ce52245628c72018da8ec4a3155dafa74e42c8e3 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm @@ -42,6 +42,7 @@ @@ -463,7 +462,7 @@ index acc9537464c2a54ffc22956873dbdba74500c20b..b0b7d98e20ed0cc63a38d6a2ce462ac6 #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/cert/x509_util_apple.h" #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" -@@ -691,10 +692,12 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { +@@ -692,10 +693,12 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { // this should be treated as an error and caught early. CHECK(bridged_view_); @@ -477,10 +476,10 @@ index acc9537464c2a54ffc22956873dbdba74500c20b..b0b7d98e20ed0cc63a38d6a2ce462ac6 // Beware: This view was briefly removed (in favor of a bare CALayer) in // https://crrev.com/c/1236675. The ordering of unassociated layers relative diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn -index 4017fef63c549b535c1eedd3571e69b7fac6f3e2..de0ed691367bda45e5310b1f132171e3a1f2dd3f 100644 +index da33fa857f85484853d14f24d0601f4c284fd67a..9af007dfc14e442d34ebe82fc678ea9f32782cdf 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn -@@ -383,6 +383,7 @@ viz_component("service") { +@@ -387,6 +387,7 @@ viz_component("service") { "frame_sinks/external_begin_frame_source_mac.h", ] } @@ -488,7 +487,7 @@ index 4017fef63c549b535c1eedd3571e69b7fac6f3e2..de0ed691367bda45e5310b1f132171e3 } if (is_ios) { -@@ -706,6 +707,7 @@ viz_source_set("unit_tests") { +@@ -712,6 +713,7 @@ viz_source_set("unit_tests") { "display_embedder/software_output_device_mac_unittest.mm", ] frameworks = [ "IOSurface.framework" ] @@ -548,7 +547,7 @@ index 010c713090e5038dc90db131c8f621422d30c03b..20c35e887a0496ee609c077e3b0494bd void ForwardKeyboardEvent(const input::NativeWebKeyboardEvent& key_event, diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm -index 437b47fd3a1a43fd52980ea550db953ba47990eb..180b186de6177bcf3345c71646362e9655b9a81f 100644 +index f69cd6100f2ac5ccb6f185e0d0bf186073ed5953..29a40923a55287b608c2ffae63a1dbbc2a7e7c1d 100644 --- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm +++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm @@ -34,6 +34,7 @@ @@ -559,7 +558,7 @@ index 437b47fd3a1a43fd52980ea550db953ba47990eb..180b186de6177bcf3345c71646362e96 #include "skia/ext/skia_utils_mac.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/input/input_handler.mojom.h" -@@ -2086,15 +2087,21 @@ - (NSAccessibilityRole)accessibilityRole { +@@ -2090,15 +2091,21 @@ - (NSAccessibilityRole)accessibilityRole { // Since this implementation doesn't have to wait any IPC calls, this doesn't // make any key-typing jank. --hbono 7/23/09 // @@ -582,10 +581,10 @@ index 437b47fd3a1a43fd52980ea550db953ba47990eb..180b186de6177bcf3345c71646362e96 return kAttributes; } diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn -index 17ec69e510d6af3d64053edce8efc7188a0c62ed..57358a499c0e713c6cec98229fd304636467234d 100644 +index 28140ff5ea05a3edf32034d6dcd4305bc35ce523..ba75db5616911295d69e9e20fed88cb7cd14478d 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn -@@ -345,6 +345,7 @@ source_set("browser") { +@@ -342,6 +342,7 @@ source_set("browser") { "//ui/webui/resources", "//v8", "//v8:v8_version", @@ -594,7 +593,7 @@ index 17ec69e510d6af3d64053edce8efc7188a0c62ed..57358a499c0e713c6cec98229fd30463 public_deps = [ diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h -index e7007a9a7788cbc89a0bbb2387ff2c62bb7d2c79..c2b672a3bd1e61089b411d139f7083714a345a9c 100644 +index 29a5a99fa2c8e90812bd7ff40b153ead807bdbef..c8683c70f8cabfa89c95c28dc5fe59f42e9970c6 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h @@ -24,6 +24,7 @@ @@ -605,7 +604,7 @@ index e7007a9a7788cbc89a0bbb2387ff2c62bb7d2c79..c2b672a3bd1e61089b411d139f708371 #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "third_party/blink/public/mojom/webshare/webshare.mojom.h" -@@ -54,7 +55,9 @@ class CursorManager; +@@ -58,7 +59,9 @@ struct CopyOutputBitmapWithMetadata; @protocol RenderWidgetHostViewMacDelegate; @@ -615,7 +614,7 @@ index e7007a9a7788cbc89a0bbb2387ff2c62bb7d2c79..c2b672a3bd1e61089b411d139f708371 @class RenderWidgetHostViewCocoa; namespace content { -@@ -671,9 +674,11 @@ class CONTENT_EXPORT RenderWidgetHostViewMac +@@ -680,9 +683,11 @@ class CONTENT_EXPORT RenderWidgetHostViewMac // EnsureSurfaceSynchronizedForWebTest(). uint32_t latest_capture_sequence_number_ = 0u; @@ -628,7 +627,7 @@ index e7007a9a7788cbc89a0bbb2387ff2c62bb7d2c79..c2b672a3bd1e61089b411d139f708371 // Used to force the NSApplication's focused accessibility element to be the // content::BrowserAccessibilityCocoa accessibility tree when the NSView for diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm -index 7cd35ebe42cf3b5604a001baf3d4353d6a2bf777..59c8d5a2e687ac6148889c87f353b33959e276f6 100644 +index 503af3ee51ac6058a803a10e7c9cfea985866188..00f9abc97d2001fc0bd095d2c62097f2ed1ae047 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -52,6 +52,7 @@ @@ -639,7 +638,7 @@ index 7cd35ebe42cf3b5604a001baf3d4353d6a2bf777..59c8d5a2e687ac6148889c87f353b339 #include "media/base/media_switches.h" #include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_mac.h" -@@ -275,8 +276,10 @@ +@@ -274,8 +275,10 @@ void RenderWidgetHostViewMac::MigrateNSViewBridge( remote_cocoa::mojom::Application* remote_cocoa_application, uint64_t parent_ns_view_id) { @@ -650,7 +649,7 @@ index 7cd35ebe42cf3b5604a001baf3d4353d6a2bf777..59c8d5a2e687ac6148889c87f353b339 // Reset `ns_view_` before resetting `remote_ns_view_` to avoid dangling // pointers. `ns_view_` gets reinitialized later in this method. -@@ -1633,10 +1636,12 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, +@@ -1655,10 +1658,12 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, gfx::NativeViewAccessible RenderWidgetHostViewMac::AccessibilityGetNativeViewAccessibleForWindow() { @@ -663,7 +662,7 @@ index 7cd35ebe42cf3b5604a001baf3d4353d6a2bf777..59c8d5a2e687ac6148889c87f353b339 return gfx::NativeViewAccessible([GetInProcessNSView() window]); } -@@ -1688,9 +1693,11 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, +@@ -1710,9 +1715,11 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, } void RenderWidgetHostViewMac::SetAccessibilityWindow(NSWindow* window) { @@ -675,7 +674,7 @@ index 7cd35ebe42cf3b5604a001baf3d4353d6a2bf777..59c8d5a2e687ac6148889c87f353b339 } bool RenderWidgetHostViewMac::SyncIsWidgetForMainFrame( -@@ -2193,20 +2200,26 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, +@@ -2215,20 +2222,26 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, void RenderWidgetHostViewMac::GetRenderWidgetAccessibilityToken( GetRenderWidgetAccessibilityTokenCallback callback) { base::ProcessId pid = getpid(); @@ -703,10 +702,10 @@ index 7cd35ebe42cf3b5604a001baf3d4353d6a2bf777..59c8d5a2e687ac6148889c87f353b339 /////////////////////////////////////////////////////////////////////////////// diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn -index 733ae2d15c3ff85faa06db70dc24fdc611113fa4..2424410cc68fe14db6024b6ec41aa73da02fc120 100644 +index f57ce1a0430df7692be55685e79121ed604daf2a..3fbc26fb179a64a2f1eab027a05b16241c185b28 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn -@@ -275,6 +275,7 @@ source_set("common") { +@@ -273,6 +273,7 @@ source_set("common") { "//ui/shell_dialogs", "//url", "//url/ipc:url_ipc", @@ -715,11 +714,11 @@ index 733ae2d15c3ff85faa06db70dc24fdc611113fa4..2424410cc68fe14db6024b6ec41aa73d defines = [] diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn -index b31aef089e03d530831df59327936785f026a300..457f5c907169da132cfd6304241dcecae779fc69 100644 +index 28e7f247df52ff84f50811e05ef22027a1a92536..780f0b5a528c2344d1d8a30b1f4a846e1eaa7192 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn -@@ -320,6 +320,7 @@ target(link_target_type, "renderer") { - "//ui/surface", +@@ -327,6 +327,7 @@ target(link_target_type, "renderer") { + "//ui/strings:auto_image_annotation_strings_grit", "//url", "//v8", + "//electron/build/config:generate_mas_config", @@ -797,10 +796,10 @@ index a1068589ad844518038ee7bc15a3de9bc5cba525..1ff781c49f086ec8015c7d3c44567dbe } // namespace content diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn -index 738aff50df5ca48ebd0d142dd738c7c8bfab635d..ae293d37bf014c8c899bb2105a941bd2c092ae86 100644 +index f9c5e8de687409857baf732a4227317e7d503b40..5adbe891175aa1f762558bfa0251e12ca6a94c6f 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn -@@ -673,6 +673,7 @@ static_library("test_support") { +@@ -702,6 +702,7 @@ static_library("test_support") { "//url", "//url/mojom:url_mojom_gurl", "//v8", @@ -808,7 +807,7 @@ index 738aff50df5ca48ebd0d142dd738c7c8bfab635d..ae293d37bf014c8c899bb2105a941bd2 ] data_deps = [ -@@ -1127,6 +1128,8 @@ static_library("browsertest_support") { +@@ -1177,6 +1178,8 @@ static_library("browsertest_support") { # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and # enable the diagnostic by removing this line. configs += [ "//build/config/compiler:no_exit_time_destructors" ] @@ -817,7 +816,7 @@ index 738aff50df5ca48ebd0d142dd738c7c8bfab635d..ae293d37bf014c8c899bb2105a941bd2 } mojom("content_test_mojo_bindings") { -@@ -2014,6 +2017,7 @@ test("content_browsertests") { +@@ -2065,6 +2068,7 @@ test("content_browsertests") { "//ui/shell_dialogs", "//ui/snapshot", "//ui/webui:test_support", @@ -825,19 +824,19 @@ index 738aff50df5ca48ebd0d142dd738c7c8bfab635d..ae293d37bf014c8c899bb2105a941bd2 ] if (!(is_chromeos && target_cpu == "arm64" && current_cpu == "arm")) { -@@ -3330,6 +3334,7 @@ test("content_unittests") { +@@ -3406,6 +3410,7 @@ test("content_unittests") { "//ui/shell_dialogs", "//ui/webui:test_support", "//url", + "//electron/build/config:generate_mas_config", ] - if (enable_nocompile_tests) { + if (is_chromeos) { diff --git a/content/web_test/BUILD.gn b/content/web_test/BUILD.gn -index ab961bccc3e4f0f5a40ac74df97447118b256c68..43f00bf0879809e986308a2cb26145c4a2a51dd3 100644 +index 23eccafa5fbc79d633168923855644f5811a4b80..7174d4816765fa2d3cde99a6756048a42b0c4a5a 100644 --- a/content/web_test/BUILD.gn +++ b/content/web_test/BUILD.gn -@@ -227,6 +227,7 @@ static_library("web_test_browser") { +@@ -228,6 +228,7 @@ static_library("web_test_browser") { "//ui/gl", "//ui/shell_dialogs", "//url", @@ -846,10 +845,10 @@ index ab961bccc3e4f0f5a40ac74df97447118b256c68..43f00bf0879809e986308a2cb26145c4 if (is_mac) { diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn -index fdb2993ab0879c5693008fdabc10566d11e471aa..2af4bf9975385ea8080cd9bd2b55f24e3ab7a2f1 100644 +index 3504d7197bd3225b6b83d7e057f389d8327b9ff7..92547d8bc700f3139f4bbc77d621152e0bc2a81c 100644 --- a/device/bluetooth/BUILD.gn +++ b/device/bluetooth/BUILD.gn -@@ -256,6 +256,7 @@ component("bluetooth") { +@@ -257,6 +257,7 @@ component("bluetooth") { "CoreBluetooth.framework", "Foundation.framework", ] @@ -904,10 +903,10 @@ index f300e8d331057e894b43b74944e5052c39206844..4ff5277d550485cd79c5b5316d89c730 base::WeakPtr<BluetoothLowEnergyAdapterApple> diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn -index 1e35afb74f7a149fb01ec2a2c62547a8aa6f1de1..05f4628930e74ea668a85968f74c678e57a6429d 100644 +index 327c2a54f2977ec99885c8c50709129cd5dcd87f..67c1b8a68dec740d0230d6b2396234b9a8b39a8a 100644 --- a/gpu/ipc/service/BUILD.gn +++ b/gpu/ipc/service/BUILD.gn -@@ -128,6 +128,7 @@ component("service") { +@@ -119,6 +119,7 @@ component("service") { "QuartzCore.framework", ] defines += [ "GL_SILENCE_DEPRECATION" ] @@ -916,7 +915,7 @@ index 1e35afb74f7a149fb01ec2a2c62547a8aa6f1de1..05f4628930e74ea668a85968f74c678e if (is_ios) { sources += [ "image_transport_surface_ios.mm" ] diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.h b/gpu/ipc/service/image_transport_surface_overlay_mac.h -index d288ffce5c1265adbdefc571f840851026e7479e..e9a6e8c31401750d270fcc55ef1116b2608b65b5 100644 +index 8b7a675d95ad36cbb9528bc5bc7ef05e5124e5a3..ed6a9a326b82b177059317dc4bc54b102f9bcc78 100644 --- a/gpu/ipc/service/image_transport_surface_overlay_mac.h +++ b/gpu/ipc/service/image_transport_surface_overlay_mac.h @@ -8,6 +8,7 @@ @@ -938,10 +937,10 @@ index d288ffce5c1265adbdefc571f840851026e7479e..e9a6e8c31401750d270fcc55ef1116b2 namespace ui { diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn -index 90e73686ebc5befecaa64d745b474ed46a1d4293..96d2c7fa2c8960263215d12fc5a15b4d16d3c3fe 100644 +index 9388ffac4f70746b04e533b51faf4f2d55ab3358..98f45dc973159b5823d8a0433dfd4bc634874b1e 100644 --- a/media/audio/BUILD.gn +++ b/media/audio/BUILD.gn -@@ -201,6 +201,7 @@ source_set("audio") { +@@ -203,6 +203,7 @@ source_set("audio") { "CoreMedia.framework", ] weak_frameworks = [ "ScreenCaptureKit.framework" ] # macOS 13.0 @@ -950,7 +949,7 @@ index 90e73686ebc5befecaa64d745b474ed46a1d4293..96d2c7fa2c8960263215d12fc5a15b4d if (is_ios) { diff --git a/media/audio/apple/audio_low_latency_input.cc b/media/audio/apple/audio_low_latency_input.cc -index 0f7c441ba44fe22b1bf4913ae8e61a8bb7ef7fe7..2311fdbbfa566e76b4709059b707ac4d4ff195d9 100644 +index 686c7e9b126260720424cd72d91a3f27002c5af8..e181ff1b909d928a3aa3a913a267d01f0fd647ec 100644 --- a/media/audio/apple/audio_low_latency_input.cc +++ b/media/audio/apple/audio_low_latency_input.cc @@ -29,6 +29,7 @@ @@ -961,7 +960,7 @@ index 0f7c441ba44fe22b1bf4913ae8e61a8bb7ef7fe7..2311fdbbfa566e76b4709059b707ac4d #include "media/audio/apple/audio_manager_apple.h" #include "media/audio/apple/scoped_audio_unit.h" #include "media/base/audio_bus.h" -@@ -41,19 +42,23 @@ +@@ -42,19 +43,23 @@ namespace { extern "C" { @@ -986,10 +985,10 @@ index 0f7c441ba44fe22b1bf4913ae8e61a8bb7ef7fe7..2311fdbbfa566e76b4709059b707ac4d } // namespace #endif diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn -index 7f9f28b70a4cf5323fdbb01567170e8856113031..ba1da643abd8ba9db6f144e24b927116233dabc1 100644 +index 5ed1605df7339b504838dfd949772b47ed72a89f..07ccbd74e0835f20edfeef76d0e5e1241a48a65c 100644 --- a/net/dns/BUILD.gn +++ b/net/dns/BUILD.gn -@@ -193,6 +193,8 @@ source_set("dns") { +@@ -197,6 +197,8 @@ source_set("dns") { ":host_resolver_manager", ":mdns_client", ] @@ -1396,10 +1395,10 @@ index eb81a70e4d5d5cd3e6ae9b45f8cd1c795ea76c51..9921ccb10d3455600eddd85f77f10228 } // namespace sandbox diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn -index 29c93be451657a8844210acba66fe8b9b4b2eed0..64300176d5a2cd4d2243d22d1c298c5315d24474 100644 +index aa7ca96851b87c8b32fd22a1388e8dba8973d3e7..2998555b064d91a9f1f2df9fc1a913d00c2d61d4 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn -@@ -425,6 +425,7 @@ component("core") { +@@ -443,6 +443,7 @@ component("core") { "//ui/gfx/geometry", "//ui/gfx/geometry:geometry_skia", "//ui/strings", @@ -1408,7 +1407,7 @@ index 29c93be451657a8844210acba66fe8b9b4b2eed0..64300176d5a2cd4d2243d22d1c298c53 if (is_mac) { diff --git a/third_party/blink/renderer/core/editing/build.gni b/third_party/blink/renderer/core/editing/build.gni -index c771cee7be34f36521de34ef893ee578b648a8c8..b0bd447b848bfdb7a9ff9cd98ba95574cb846cc2 100644 +index 4f04476e9175bae9e89eb9ea4316bffe49a9eb91..e77615c7b26518f4930ac1b004b413173fa0f46b 100644 --- a/third_party/blink/renderer/core/editing/build.gni +++ b/third_party/blink/renderer/core/editing/build.gni @@ -362,10 +362,14 @@ blink_core_sources_editing = [ @@ -1428,10 +1427,10 @@ index c771cee7be34f36521de34ef893ee578b648a8c8..b0bd447b848bfdb7a9ff9cd98ba95574 blink_core_sources_editing += [ "kill_ring_none.cc" ] } diff --git a/ui/accelerated_widget_mac/BUILD.gn b/ui/accelerated_widget_mac/BUILD.gn -index 8c07f1ad347cbc3e5024b25e1dd4a9d14396a82b..601df4d169d7ff2925a9762d353438b3eb8665b5 100644 +index 0f8a6f75b7f01029adc2f5fd23559bacce19cf72..cf66c2f4f02a8e21cc83c3b7389fc5156bcd93ba 100644 --- a/ui/accelerated_widget_mac/BUILD.gn +++ b/ui/accelerated_widget_mac/BUILD.gn -@@ -81,6 +81,7 @@ component("accelerated_widget_mac") { +@@ -83,6 +83,7 @@ component("accelerated_widget_mac") { "//ui/gfx", "//ui/gfx/geometry", "//ui/gl", @@ -1440,19 +1439,18 @@ index 8c07f1ad347cbc3e5024b25e1dd4a9d14396a82b..601df4d169d7ff2925a9762d353438b3 } diff --git a/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h b/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h -index ce6a061b57cce101c103527dbbbe5ed47b2ecaf8..616922c34e1f3bc50584c0417129b78e3ff651d1 100644 +index d5f35d2ccfb21b231e235dbfae3eee96a488eb20..14592180823131ca87bc95300c8d9a82451e6628 100644 --- a/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h +++ b/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h -@@ -7,6 +7,7 @@ - +@@ -8,13 +8,16 @@ #include <queue> + #include "base/containers/queue.h" +#include "electron/mas.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" - #include "ui/accelerated_widget_mac/ca_renderer_layer_tree.h" #include "ui/gfx/ca_layer_result.h" -@@ -14,7 +15,9 @@ - #include "ui/gl/gl_surface.h" + #include "ui/gfx/presentation_feedback.h" + #include "ui/gl/gl_context.h" #include "ui/gl/presenter.h" +#if !IS_MAS_BUILD() @@ -1461,7 +1459,7 @@ index ce6a061b57cce101c103527dbbbe5ed47b2ecaf8..616922c34e1f3bc50584c0417129b78e @class CALayer; @protocol MTLDevice; -@@ -113,7 +116,9 @@ class ACCELERATED_WIDGET_MAC_EXPORT CALayerTreeCoordinator { +@@ -119,7 +122,9 @@ class ACCELERATED_WIDGET_MAC_EXPORT CALayerTreeCoordinator { // both the current tree and the pending trees. size_t presented_ca_layer_trees_max_length_ = 2; @@ -1472,7 +1470,7 @@ index ce6a061b57cce101c103527dbbbe5ed47b2ecaf8..616922c34e1f3bc50584c0417129b78e // The root CALayer to display the current frame. This does not change // over the lifetime of the object. diff --git a/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm b/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm -index 54651172993f7d07f21a395511f773bff40115d8..295d8bef6e9ec966db570d7537abfc049324512d 100644 +index 5e50feb42b4a49b03a75b510bb3ddc269282aa2f..1519401a362530b7107eab17c28b63486e7455ff 100644 --- a/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm +++ b/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm @@ -10,6 +10,7 @@ @@ -1480,18 +1478,18 @@ index 54651172993f7d07f21a395511f773bff40115d8..295d8bef6e9ec966db570d7537abfc04 #include "base/task/single_thread_task_runner.h" #include "base/trace_event/trace_event.h" +#include "electron/mas.h" + #include "ui/accelerated_widget_mac/ca_renderer_layer_tree.h" #include "ui/base/cocoa/animation_utils.h" #include "ui/base/cocoa/remote_layer_api.h" - #include "ui/gfx/ca_layer_params.h" -@@ -32,6 +33,7 @@ - allow_av_sample_buffer_display_layer), +@@ -37,6 +38,7 @@ buffer_presented_callback_(buffer_presented_callback), + gl_make_current_callback_(gl_make_current_callback), metal_device_(metal_device) { +#if !IS_MAS_BUILD() if (allow_remote_layers_) { root_ca_layer_ = [[CALayer alloc] init]; #if BUILDFLAG(IS_MAC) -@@ -60,6 +62,7 @@ +@@ -65,6 +67,7 @@ #endif ca_context_.layer = root_ca_layer_; } @@ -1499,7 +1497,7 @@ index 54651172993f7d07f21a395511f773bff40115d8..295d8bef6e9ec966db570d7537abfc04 } CALayerTreeCoordinator::~CALayerTreeCoordinator() = default; -@@ -163,9 +166,13 @@ +@@ -207,9 +210,13 @@ TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", TRACE_EVENT_SCOPE_THREAD, "GLImpl", static_cast<int>(gl::GetGLImplementation()), "width", pixel_size_.width()); @@ -1510,7 +1508,7 @@ index 54651172993f7d07f21a395511f773bff40115d8..295d8bef6e9ec966db570d7537abfc04 +#else + if (true) { +#endif - IOSurfaceRef io_surface = frame->layer_tree->GetContentIOSurface(); + IOSurfaceRef io_surface = frame.layer_tree->GetContentIOSurface(); if (io_surface) { DCHECK(!allow_remote_layers_); diff --git a/ui/accelerated_widget_mac/display_ca_layer_tree.mm b/ui/accelerated_widget_mac/display_ca_layer_tree.mm @@ -1544,10 +1542,10 @@ index dcf493d62990018040a3f84b6f875af737bd2214..3d1c4dcc9ee0bbfdac15f40d9c74e9f3 void DisplayCALayerTree::GotIOSurfaceFrame( diff --git a/ui/accessibility/platform/BUILD.gn b/ui/accessibility/platform/BUILD.gn -index 79a01b007924230edf8c0b32945d3fb4e6f2445d..649a4a80b023808b2c4c28689a0da0401560090a 100644 +index 54d483d6b3f1a56573e21b1f873b8dee8fc25a0f..33bc8c9ef097a907060ed347dca2ad46b6d081f5 100644 --- a/ui/accessibility/platform/BUILD.gn +++ b/ui/accessibility/platform/BUILD.gn -@@ -298,6 +298,7 @@ component("platform") { +@@ -299,6 +299,7 @@ component("platform") { "AppKit.framework", "Foundation.framework", ] @@ -1556,7 +1554,7 @@ index 79a01b007924230edf8c0b32945d3fb4e6f2445d..649a4a80b023808b2c4c28689a0da040 if (is_ios) { diff --git a/ui/accessibility/platform/browser_accessibility_manager_mac.mm b/ui/accessibility/platform/browser_accessibility_manager_mac.mm -index 2a7352c1925bdce988c9f1a44f387e160532f508..8c07cc82bd6c42e6da8de314ca52867bcb3b9532 100644 +index 3e6426f895b55168834809ed6b91916f447d7ea3..33ec3f6ce4e5a69760779d28a3ae2b07a183afa4 100644 --- a/ui/accessibility/platform/browser_accessibility_manager_mac.mm +++ b/ui/accessibility/platform/browser_accessibility_manager_mac.mm @@ -14,6 +14,7 @@ @@ -1593,7 +1591,7 @@ index 2a7352c1925bdce988c9f1a44f387e160532f508..8c07cc82bd6c42e6da8de314ca52867b // Use native VoiceOver support for live regions. BrowserAccessibilityCocoa* retained_node = native_node; -@@ -703,6 +708,7 @@ void PostAnnouncementNotification(NSString* announcement, +@@ -696,6 +701,7 @@ void PostAnnouncementNotification(NSString* announcement, return window == [NSApp accessibilityFocusedWindow]; } @@ -1601,7 +1599,7 @@ index 2a7352c1925bdce988c9f1a44f387e160532f508..8c07cc82bd6c42e6da8de314ca52867b // TODO(accessibility): We need a solution to the problem described below. // If the window is NSAccessibilityRemoteUIElement, there are some challenges: // 1. NSApp is the browser which spawned the PWA, and what it considers the -@@ -731,6 +737,7 @@ void PostAnnouncementNotification(NSString* announcement, +@@ -724,6 +730,7 @@ void PostAnnouncementNotification(NSString* announcement, if ([window isKindOfClass:[NSAccessibilityRemoteUIElement class]]) { return true; } @@ -1638,10 +1636,10 @@ index 6846060ef9622d8fc8d1d6c8da16e2f1b785e6bd..05c22db87e882b246bd7034e027cf149 // Accessible object if (AXElementWrapper::IsValidElement(value)) { diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn -index 660c4f5939df164ab5db868ddd19c97e2c782f36..3dae3e6d8aa651f0f382a7af7f1fa8a6ebd480f4 100644 +index 1428a0aa8d233062990e825050e71d3e3b6dd6f0..009d3446ae976150b25c92ee50590f0926956bca 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn -@@ -369,6 +369,13 @@ component("base") { +@@ -355,6 +355,13 @@ component("base") { ] } @@ -1655,7 +1653,7 @@ index 660c4f5939df164ab5db868ddd19c97e2c782f36..3dae3e6d8aa651f0f382a7af7f1fa8a6 if (is_ios) { sources += [ "device_form_factor_ios.mm", -@@ -517,6 +524,12 @@ component("base") { +@@ -503,6 +510,12 @@ component("base") { "//url", ] @@ -1722,10 +1720,10 @@ index 59dc2f82214cfd883b6ebef3b0fb25af6387a9cd..912c5252d1b30d943a1552739b9eef9a // This function will check if all of the interfaces listed above are supported diff --git a/ui/base/cocoa/remote_layer_api.mm b/ui/base/cocoa/remote_layer_api.mm -index fc25ba79d2b0e1acdb7ba54b89e7d6e16f94771b..de771ef414b9a69e331261524f08e9a12145ec60 100644 +index 93e90c4eba9bc9b93d68e834eb6baabeb2d0ecf0..1b90f41d05f847a94adf2f4da827b1d0143b7bcf 100644 --- a/ui/base/cocoa/remote_layer_api.mm +++ b/ui/base/cocoa/remote_layer_api.mm -@@ -5,11 +5,13 @@ +@@ -5,18 +5,22 @@ #include "ui/base/cocoa/remote_layer_api.h" #include "base/feature_list.h" @@ -1739,9 +1737,7 @@ index fc25ba79d2b0e1acdb7ba54b89e7d6e16f94771b..de771ef414b9a69e331261524f08e9a1 namespace { // Control use of cross-process CALayers to display content directly from the // GPU process on Mac. -@@ -17,8 +19,10 @@ - "RemoteCoreAnimationAPI", - base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kRemoteCoreAnimationAPI, base::FEATURE_ENABLED_BY_DEFAULT); } // namespace +#endif @@ -1750,7 +1746,7 @@ index fc25ba79d2b0e1acdb7ba54b89e7d6e16f94771b..de771ef414b9a69e331261524f08e9a1 if (!base::FeatureList::IsEnabled(kRemoteCoreAnimationAPI)) return false; -@@ -55,6 +59,9 @@ bool RemoteLayerAPISupported() { +@@ -53,6 +57,9 @@ bool RemoteLayerAPISupported() { // If everything is there, we should be able to use the API. return true; @@ -1761,10 +1757,10 @@ index fc25ba79d2b0e1acdb7ba54b89e7d6e16f94771b..de771ef414b9a69e331261524f08e9a1 } // namespace diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn -index 5c78ec26210044b8c556431212e9b201dbf0fd8b..a23edba020ca7cd34f7f806d923ad5f1464061b2 100644 +index 41572ec01d71f56eb8815cf9845e2c4ccefb9964..90c72f19b557d985581c7250187616ee85821964 100644 --- a/ui/display/BUILD.gn +++ b/ui/display/BUILD.gn -@@ -129,6 +129,12 @@ component("display") { +@@ -132,6 +132,12 @@ component("display") { "//ui/gfx/geometry", ] @@ -1778,18 +1774,18 @@ index 5c78ec26210044b8c556431212e9b201dbf0fd8b..a23edba020ca7cd34f7f806d923ad5f1 deps += [ "//build:ios_buildflags" ] } diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm -index 85d9170ae8de43ec0fa18c033d66c0583c26ec2f..c4f76301818404ce853583adf01af85cddd6a6e5 100644 +index 890d86acb0e92760590b4d0860dd41eaa70486c7..2e9e16cb47606f627b1473a479a6e8ae514cb88e 100644 --- a/ui/display/mac/screen_mac.mm +++ b/ui/display/mac/screen_mac.mm -@@ -33,6 +33,7 @@ - #include "base/trace_event/trace_event.h" +@@ -29,6 +29,7 @@ #include "build/build_config.h" #include "components/device_event_log/device_event_log.h" + #include "components/viz/common/resources/shared_image_format.h" +#include "electron/mas.h" #include "ui/display/display.h" #include "ui/display/display_change_notifier.h" #include "ui/display/mac/screen_mac_headless.h" -@@ -182,7 +183,17 @@ DisplayMac BuildDisplayForScreen(NSScreen* screen) { +@@ -179,7 +180,17 @@ DisplayMac BuildDisplayForScreen(NSScreen* screen) { display.set_color_depth(Display::kDefaultBitsPerPixel); display.set_depth_per_component(Display::kDefaultBitsPerComponent); } @@ -1808,24 +1804,20 @@ index 85d9170ae8de43ec0fa18c033d66c0583c26ec2f..c4f76301818404ce853583adf01af85c // Query the display's refresh rate. double refresh_rate = 1.0 / screen.minimumRefreshInterval; diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn -index a4226f4f8d4bb5401edb79855e95c7fff3cd0bb1..9e8da8ab0b21c2b8d7a3a0b9c9eeeb2fdd15201e 100644 +index 35e9149e221721c6d4332de530877588022bc7c7..2910455828b7d5025daa8e62071a68a67bed46d5 100644 --- a/ui/gfx/BUILD.gn +++ b/ui/gfx/BUILD.gn -@@ -337,6 +337,12 @@ component("gfx") { - "//ui/base:ui_data_pack", - ] - -+ if (is_mac) { -+ deps += [ -+ "//electron/build/config:generate_mas_config" -+ ] -+ } +@@ -277,6 +277,8 @@ component("gfx") { + "CoreGraphics.framework", + "CoreText.framework", + ] + - if (!is_apple) { ++ deps += ["//electron/build/config:generate_mas_config"] + } + if (is_ios) { sources += [ - "platform_font_skia.cc", diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm -index fe3f85073e31de487a08e57d7f9b07aa4eccf8f3..cf5b07203c8bd559a404600cc98cc8eccdefd4d7 100644 +index bbe355cf69f160866188216cc274d75bd35603db..06ee100d7ea2e892dbf3c0b1adc96c5013ef678a 100644 --- a/ui/gfx/platform_font_mac.mm +++ b/ui/gfx/platform_font_mac.mm @@ -19,6 +19,7 @@ @@ -1863,10 +1855,10 @@ index fe3f85073e31de487a08e57d7f9b07aa4eccf8f3..cf5b07203c8bd559a404600cc98cc8ec // enough. return PlatformFontMac::SystemFontType::kGeneral; diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn -index f3db960f1963e9fbc575a13b570a8b7564535a5d..0bbf9182ec826a7add3a52b782b9ba319548c687 100644 +index becf47ac859e2ea5d68d449010606bc787606239..45f13c71703bc2e67aa668b8360f555f592c9555 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn -@@ -724,6 +724,8 @@ component("views") { +@@ -723,6 +723,8 @@ component("views") { "IOSurface.framework", "QuartzCore.framework", ] @@ -1885,7 +1877,7 @@ index f3db960f1963e9fbc575a13b570a8b7564535a5d..0bbf9182ec826a7add3a52b782b9ba31 sources += [ "test/desktop_window_tree_host_win_test_api.cc", diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.h b/ui/views/cocoa/native_widget_mac_ns_window_host.h -index 4cc9db3ae1ef2443b1ecf923c9c572b7d0e85662..f7bf6a6bb63f9c38cc21c03da1c884d6bee8ab9a 100644 +index fdc7eb4e4c5e8338c725f7d317559b091d8b38fe..2239b085ac7fd87fe06aef1001551f8afe8e21e4 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.h +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.h @@ -19,6 +19,7 @@ @@ -1906,7 +1898,7 @@ index 4cc9db3ae1ef2443b1ecf923c9c572b7d0e85662..f7bf6a6bb63f9c38cc21c03da1c884d6 @class NSView; namespace remote_cocoa { -@@ -502,10 +505,12 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost +@@ -506,10 +509,12 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost mojo::AssociatedRemote<remote_cocoa::mojom::NativeWidgetNSWindow> remote_ns_window_remote_; @@ -1920,7 +1912,7 @@ index 4cc9db3ae1ef2443b1ecf923c9c572b7d0e85662..f7bf6a6bb63f9c38cc21c03da1c884d6 // Used to force the NSApplication's focused accessibility element to be the // views::Views accessibility tree when the NSView for this is focused. diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm -index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a561cb41dec 100644 +index 5c0d4134c8205b018a4f71509879485a7f92bcf2..d2204fd2b737f7f3e146cb1be80c3be6bfce8cd4 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm @@ -21,6 +21,7 @@ @@ -1931,7 +1923,7 @@ index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a56 #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" #include "ui/accessibility/accessibility_features.h" -@@ -359,8 +360,12 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -362,8 +363,12 @@ void HandleAccelerator(const ui::Accelerator& accelerator, if (in_process_ns_window_bridge_) { return gfx::NativeViewAccessible(in_process_ns_window_bridge_->ns_view()); } @@ -1944,7 +1936,7 @@ index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a56 } gfx::NativeViewAccessible -@@ -376,8 +381,12 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -379,8 +384,12 @@ void HandleAccelerator(const ui::Accelerator& accelerator, [in_process_ns_window_bridge_->ns_view() window]); } @@ -1957,7 +1949,7 @@ index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a56 } remote_cocoa::mojom::NativeWidgetNSWindow* -@@ -1439,9 +1448,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -1451,9 +1460,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator, // for PWAs. However this breaks accessibility on in-process windows, // so set it back to NO when a local window gains focus. See // https://crbug.com/41485830. @@ -1969,7 +1961,7 @@ index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a56 // Explicitly set the keyboard accessibility state on regaining key // window status. if (is_key && is_content_first_responder) { -@@ -1582,17 +1593,20 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -1606,17 +1617,20 @@ void HandleAccelerator(const ui::Accelerator& accelerator, void NativeWidgetMacNSWindowHost::SetRemoteAccessibilityTokens( const std::vector<uint8_t>& window_token, const std::vector<uint8_t>& view_token) { @@ -1990,7 +1982,7 @@ index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a56 *pid = getpid(); id element_id = GetNativeViewAccessible(); -@@ -1605,6 +1619,7 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -1629,6 +1643,7 @@ void HandleAccelerator(const ui::Accelerator& accelerator, } *token = ui::RemoteAccessibility::GetTokenForLocalElement(element_id); @@ -1999,7 +1991,7 @@ index 7c4250a4b5610182abd97469e83e71f32f5bd2b3..48dfca966a594f54523c129fa49d2a56 } diff --git a/ui/views/controls/webview/BUILD.gn b/ui/views/controls/webview/BUILD.gn -index 111d6432586f47833dde50678b908c76ad88d37a..429ca4402652a2d89ead228d92971f0cb3b6222c 100644 +index 50bb38a38dca67f9f393c48efe123f7dd7ca2594..2062e479581d63325de3c3398844acca0601c86c 100644 --- a/ui/views/controls/webview/BUILD.gn +++ b/ui/views/controls/webview/BUILD.gn @@ -46,6 +46,12 @@ component("webview") { diff --git a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch index 6be75cb340423..4a7165124f5cb 100644 --- a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch +++ b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch @@ -7,10 +7,10 @@ This adds a callback from the network service that's used to implement session.setCertificateVerifyCallback. diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index a5fa5553641c2be3a3e73e362f89dd3defd90947..7721b8e827d9aac6e90ddfe3de264f41915219f2 100644 +index 3534a4b276fe96d56a9e7663b35b44aec44344c6..61c7bd716e2ed78c8f71cba50d34e80d6effad4f 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc -@@ -165,6 +165,11 @@ +@@ -166,6 +166,11 @@ #include "services/network/web_transport.h" #include "url/gurl.h" @@ -22,7 +22,7 @@ index a5fa5553641c2be3a3e73e362f89dd3defd90947..7721b8e827d9aac6e90ddfe3de264f41 #if BUILDFLAG(IS_CT_SUPPORTED) // gn check does not account for BUILDFLAG(). So, for iOS builds, it will // complain about a missing dependency on the target exposing this header. Add a -@@ -620,6 +625,111 @@ void RecordHSTSPreconnectUpgradeReason(HSTSRedirectUpgradeReason reason) { +@@ -621,6 +626,111 @@ void RecordHSTSPreconnectUpgradeReason(HSTSRedirectUpgradeReason reason) { } // namespace @@ -134,7 +134,7 @@ index a5fa5553641c2be3a3e73e362f89dd3defd90947..7721b8e827d9aac6e90ddfe3de264f41 constexpr uint32_t NetworkContext::kMaxOutstandingRequestsPerProcess; NetworkContext::NetworkContextHttpAuthPreferences:: -@@ -1023,6 +1133,13 @@ void NetworkContext::SetClient( +@@ -1022,6 +1132,13 @@ void NetworkContext::SetClient( client_.Bind(std::move(client)); } @@ -148,7 +148,7 @@ index a5fa5553641c2be3a3e73e362f89dd3defd90947..7721b8e827d9aac6e90ddfe3de264f41 void NetworkContext::CreateURLLoaderFactory( mojo::PendingReceiver<mojom::URLLoaderFactory> receiver, mojom::URLLoaderFactoryParamsPtr params) { -@@ -2660,6 +2777,10 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( +@@ -2689,6 +2806,10 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( cert_verifier = std::make_unique<net::CachingCertVerifier>( std::make_unique<net::CoalescingCertVerifier>( std::move(cert_verifier))); @@ -160,10 +160,10 @@ index a5fa5553641c2be3a3e73e362f89dd3defd90947..7721b8e827d9aac6e90ddfe3de264f41 builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier( diff --git a/services/network/network_context.h b/services/network/network_context.h -index 6a60953f3b51dcfdfed8cf6516846c915a583e0b..b9f201ccf04433a29083cd15cfe599fe9600c9c0 100644 +index 3795ce4def719c36e1dace911be53b0103aeafc5..90cf1a70c068771ac98b2d5a283cba5e54c05ff4 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h -@@ -115,6 +115,7 @@ class URLMatcher; +@@ -117,6 +117,7 @@ class URLMatcher; } namespace network { @@ -171,7 +171,7 @@ index 6a60953f3b51dcfdfed8cf6516846c915a583e0b..b9f201ccf04433a29083cd15cfe599fe class CookieManager; class HostResolver; class MdnsResponderManager; -@@ -252,6 +253,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext +@@ -254,6 +255,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext void CreateURLLoaderFactory( mojo::PendingReceiver<mojom::URLLoaderFactory> receiver, mojom::URLLoaderFactoryParamsPtr params) override; @@ -180,7 +180,7 @@ index 6a60953f3b51dcfdfed8cf6516846c915a583e0b..b9f201ccf04433a29083cd15cfe599fe void ResetURLLoaderFactories() override; void GetViaObliviousHttp( mojom::ObliviousHttpRequestPtr request, -@@ -971,6 +974,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext +@@ -995,6 +998,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext std::vector<base::OnceClosure> dismount_closures_; #endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) @@ -190,10 +190,10 @@ index 6a60953f3b51dcfdfed8cf6516846c915a583e0b..b9f201ccf04433a29083cd15cfe599fe std::unique_ptr<HostResolver> internal_host_resolver_; std::set<std::unique_ptr<HostResolver>, base::UniquePtrComparator> diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom -index 5986f8444e582ea0571590060dbcddbe366df74d..1ed66c3b41e583745c5b309670fc4470fa1983cf 100644 +index f2de77f154f4290f4bbf60f6b5697fdc9383427a..269b95a51029b2a2e42d663988f2c1b8a74f91a8 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom -@@ -315,6 +315,17 @@ struct SocketBrokerRemotes { +@@ -311,6 +311,17 @@ struct SocketBrokerRemotes { pending_remote<SocketBroker> server; }; @@ -211,7 +211,7 @@ index 5986f8444e582ea0571590060dbcddbe366df74d..1ed66c3b41e583745c5b309670fc4470 // Parameters for constructing a network context. struct NetworkContextParams { // The user agent string. -@@ -967,6 +978,9 @@ interface NetworkContext { +@@ -1001,6 +1012,9 @@ interface NetworkContext { // Sets a client for this network context. SetClient(pending_remote<NetworkContextClient> client); @@ -222,7 +222,7 @@ index 5986f8444e582ea0571590060dbcddbe366df74d..1ed66c3b41e583745c5b309670fc4470 CreateURLLoaderFactory( pending_receiver<URLLoaderFactory> url_loader_factory, diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h -index 54bfe6a699a5de7641423548a2a4f5de5a582786..70a5ab342a8954354a3d8245d30df9520cfd398d 100644 +index 56971f00eea555b3e67e0c20d5e7a8572444690b..ebcacbcb16057912693a6674e6b9ef5eeb671f91 100644 --- a/services/network/test/test_network_context.h +++ b/services/network/test/test_network_context.h @@ -63,6 +63,8 @@ class TestNetworkContext : public mojom::NetworkContext { diff --git a/patches/chromium/notification_provenance.patch b/patches/chromium/notification_provenance.patch index ed7ba67c81e75..15869368cbd9e 100644 --- a/patches/chromium/notification_provenance.patch +++ b/patches/chromium/notification_provenance.patch @@ -7,10 +7,10 @@ Pass RenderFrameHost through to PlatformNotificationService so Electron can identify which renderer a notification came from. diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc -index 03d15ec6e6f4adb6339501472de27b7bec5f50e3..364c95a765a0cbf568f14ebd4dce347e3c54f70d 100644 +index 5b2b9b50fd76526e790055b3ed2ebbe966db850e..a3fdfaa605e5b6df1828b38d0ed05776397e3122 100644 --- a/chrome/browser/notifications/platform_notification_service_impl.cc +++ b/chrome/browser/notifications/platform_notification_service_impl.cc -@@ -252,6 +252,7 @@ bool PlatformNotificationServiceImpl::WasClosedProgrammatically( +@@ -265,6 +265,7 @@ bool PlatformNotificationServiceImpl::WasClosedProgrammatically( // TODO(awdf): Rename to DisplayNonPersistentNotification (Similar for Close) void PlatformNotificationServiceImpl::DisplayNotification( @@ -19,10 +19,10 @@ index 03d15ec6e6f4adb6339501472de27b7bec5f50e3..364c95a765a0cbf568f14ebd4dce347e const GURL& origin, const GURL& document_url, diff --git a/chrome/browser/notifications/platform_notification_service_impl.h b/chrome/browser/notifications/platform_notification_service_impl.h -index ec5ca87810d590fc95eda2006b8653bb12711b8e..203cd9645523c4f0adf90e78fa3d8f3d0aad54dc 100644 +index 76c0d0763cdb85888c5b02e62006ad30ca6a80ff..eec3dce46eb283b0721dc66ce5f1b254c490476a 100644 --- a/chrome/browser/notifications/platform_notification_service_impl.h +++ b/chrome/browser/notifications/platform_notification_service_impl.h -@@ -57,6 +57,7 @@ class PlatformNotificationServiceImpl +@@ -56,6 +56,7 @@ class PlatformNotificationServiceImpl // content::PlatformNotificationService implementation. void DisplayNotification( @@ -31,10 +31,10 @@ index ec5ca87810d590fc95eda2006b8653bb12711b8e..203cd9645523c4f0adf90e78fa3d8f3d const GURL& origin, const GURL& document_url, diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc -index 1b3d77e66432b1f7b8c6f87634644776cd9ccb5b..147da7ad0c830c2c8e0f62f9df0e365a14764280 100644 +index 2fd342198d04c5d7fa7e80c0893a905a22ff4601..b907b5588541337576e96bbee7c2c29c1b7355a5 100644 --- a/content/browser/notifications/blink_notification_service_impl.cc +++ b/content/browser/notifications/blink_notification_service_impl.cc -@@ -85,12 +85,14 @@ BlinkNotificationServiceImpl::BlinkNotificationServiceImpl( +@@ -87,12 +87,14 @@ BlinkNotificationServiceImpl::BlinkNotificationServiceImpl( BrowserContext* browser_context, scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, RenderProcessHost* render_process_host, @@ -49,7 +49,7 @@ index 1b3d77e66432b1f7b8c6f87634644776cd9ccb5b..147da7ad0c830c2c8e0f62f9df0e365a browser_context_(browser_context), service_worker_context_(std::move(service_worker_context)), render_process_host_id_(render_process_host->GetDeprecatedID()), -@@ -182,7 +184,7 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( +@@ -198,7 +200,7 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( creator_type_); browser_context_->GetPlatformNotificationService()->DisplayNotification( @@ -59,7 +59,7 @@ index 1b3d77e66432b1f7b8c6f87634644776cd9ccb5b..147da7ad0c830c2c8e0f62f9df0e365a } diff --git a/content/browser/notifications/blink_notification_service_impl.h b/content/browser/notifications/blink_notification_service_impl.h -index e7cc73f375ada7ee8715d331c3d372e0f59a0cdf..c0a142bea4a9a30c10dbb30c72fedce9ab4d1e62 100644 +index 89edc47028e80170bcc0f11a0f27d30067d1ef6c..313bbe4f1815c7e2042d4a4600f922031727d274 100644 --- a/content/browser/notifications/blink_notification_service_impl.h +++ b/content/browser/notifications/blink_notification_service_impl.h @@ -44,6 +44,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl @@ -70,7 +70,7 @@ index e7cc73f375ada7ee8715d331c3d372e0f59a0cdf..c0a142bea4a9a30c10dbb30c72fedce9 const blink::StorageKey& storage_key, const GURL& document_url, const WeakDocumentPtr& weak_document_ptr, -@@ -113,6 +114,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl +@@ -119,6 +120,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl raw_ptr<PlatformNotificationContextImpl, DanglingUntriaged> notification_context_; @@ -79,7 +79,7 @@ index e7cc73f375ada7ee8715d331c3d372e0f59a0cdf..c0a142bea4a9a30c10dbb30c72fedce9 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; diff --git a/content/browser/notifications/blink_notification_service_impl_unittest.cc b/content/browser/notifications/blink_notification_service_impl_unittest.cc -index 33e28b6b05a56ba621b982c6263c89506625172a..329edb751d675b2de8cb6250cf16d6bf98ac925f 100644 +index 8ccff8edf6c45a96978fea0b02a8d7ebd8768578..264af7461226718ff300faa22ba4587594b79ae4 100644 --- a/content/browser/notifications/blink_notification_service_impl_unittest.cc +++ b/content/browser/notifications/blink_notification_service_impl_unittest.cc @@ -135,7 +135,7 @@ class BlinkNotificationServiceImplTest : public ::testing::Test { @@ -92,10 +92,10 @@ index 33e28b6b05a56ba621b982c6263c89506625172a..329edb751d675b2de8cb6250cf16d6bf contents_.get()->GetPrimaryMainFrame()->GetWeakDocumentPtr(), RenderProcessHost::NotificationServiceCreatorType::kDocument, diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc -index b09a71544475f5810e26006d9a2f975176b28bb8..e6c77f27d6a71d1d065e292963072186a257aca6 100644 +index 2c9e6225d0085c67dc1ae51cca2614b2c74120a7..ad194578a06e74488a853cb8f3f042fd339eefea 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc -@@ -281,6 +281,7 @@ void PlatformNotificationContextImpl::Shutdown() { +@@ -286,6 +286,7 @@ void PlatformNotificationContextImpl::Shutdown() { void PlatformNotificationContextImpl::CreateService( RenderProcessHost* render_process_host, @@ -103,7 +103,7 @@ index b09a71544475f5810e26006d9a2f975176b28bb8..e6c77f27d6a71d1d065e292963072186 const blink::StorageKey& storage_key, const GURL& document_url, const WeakDocumentPtr& weak_document_ptr, -@@ -289,7 +290,7 @@ void PlatformNotificationContextImpl::CreateService( +@@ -294,7 +295,7 @@ void PlatformNotificationContextImpl::CreateService( DCHECK_CURRENTLY_ON(BrowserThread::UI); services_.push_back(std::make_unique<BlinkNotificationServiceImpl>( this, browser_context_, service_worker_context_, render_process_host, @@ -113,7 +113,7 @@ index b09a71544475f5810e26006d9a2f975176b28bb8..e6c77f27d6a71d1d065e292963072186 } diff --git a/content/browser/notifications/platform_notification_context_impl.h b/content/browser/notifications/platform_notification_context_impl.h -index 5be62a3fb27e37f3c1db6b811172f6dfebe18f61..34349f9832fe4b9a3d48db613a789afb87cb2a68 100644 +index 9bf238e64af483294ae3c3f18a4e9aed49a8658d..b9b2a4c8c387b8e8b4eb1f02fc0f891ceaa105a0 100644 --- a/content/browser/notifications/platform_notification_context_impl.h +++ b/content/browser/notifications/platform_notification_context_impl.h @@ -47,6 +47,7 @@ class PlatformNotificationServiceProxy; @@ -133,10 +133,10 @@ index 5be62a3fb27e37f3c1db6b811172f6dfebe18f61..34349f9832fe4b9a3d48db613a789afb const GURL& document_url, const WeakDocumentPtr& weak_document_ptr, diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc -index d3f53f539544e5206e1c8cf8d3f9f87906630954..c20d6b898f517856efb01e9f504a9dfa967fa3c3 100644 +index c6830a02a66b2b2898b40070916b29cc21c5e68c..1aabeee15e34c31a2ceeb3584c934abbb3b0e01b 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc -@@ -2218,7 +2218,7 @@ void RenderProcessHostImpl::CreateNotificationService( +@@ -2360,7 +2360,7 @@ void RenderProcessHostImpl::CreateNotificationService( case RenderProcessHost::NotificationServiceCreatorType::kSharedWorker: case RenderProcessHost::NotificationServiceCreatorType::kDedicatedWorker: { storage_partition_impl_->GetPlatformNotificationContext()->CreateService( @@ -145,7 +145,7 @@ index d3f53f539544e5206e1c8cf8d3f9f87906630954..c20d6b898f517856efb01e9f504a9dfa creator_type, std::move(receiver)); break; } -@@ -2226,7 +2226,7 @@ void RenderProcessHostImpl::CreateNotificationService( +@@ -2368,7 +2368,7 @@ void RenderProcessHostImpl::CreateNotificationService( CHECK(rfh); storage_partition_impl_->GetPlatformNotificationContext()->CreateService( diff --git a/patches/chromium/osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch b/patches/chromium/osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch index fe039ce3f537a..ba5a26f5ab6c0 100644 --- a/patches/chromium/osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch +++ b/patches/chromium/osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch @@ -10,11 +10,11 @@ The keyed mutex introduce extra performance cost and spikes. However, at offscre For resolving complex conflict please pin @reitowo For more reason please see: https://crrev.com/c/5465148 -diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc -index 31543b5b018313d2e5890f599109bd48d7bc5e64..2f4003b0557ae275ee3697062fafb6428f5da010 100644 ---- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc -+++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc -@@ -166,7 +166,8 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferFactoryDXGI::CreateNativeGmbHandle( +diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc +index 93fca64b215fb2f9170fcf5883cfed29ec3f5f69..cc95dab3bb5d4afebddb83154c47f200e282e521 100644 +--- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc ++++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc +@@ -381,7 +381,8 @@ gfx::GpuMemoryBufferHandle D3DImageBackingFactory::CreateGpuMemoryBufferHandle( // so make sure that the usage is one that we support. DCHECK(usage == gfx::BufferUsage::GPU_READ || usage == gfx::BufferUsage::SCANOUT || @@ -24,7 +24,7 @@ index 31543b5b018313d2e5890f599109bd48d7bc5e64..2f4003b0557ae275ee3697062fafb642 << "Incorrect usage, usage=" << gfx::BufferUsageToString(usage); D3D11_TEXTURE2D_DESC desc = { -@@ -180,7 +181,9 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferFactoryDXGI::CreateNativeGmbHandle( +@@ -395,7 +396,9 @@ gfx::GpuMemoryBufferHandle D3DImageBackingFactory::CreateGpuMemoryBufferHandle( D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, 0, D3D11_RESOURCE_MISC_SHARED_NTHANDLE | @@ -36,7 +36,7 @@ index 31543b5b018313d2e5890f599109bd48d7bc5e64..2f4003b0557ae275ee3697062fafb642 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture; diff --git a/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc b/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc -index 4de36674acee427da3a43891f780102d7e08d9cb..d32bf712107f02991717da626b5dd25c6e6973d3 100644 +index 5e025cfae4ac056791fab1b7016b5f7da3204239..ac428cffba7854c28c5e71fefa67c51bbeb34248 100644 --- a/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc +++ b/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc @@ -209,6 +209,23 @@ bool FrameResources::Initialize(VideoPixelFormat format, diff --git a/patches/chromium/picture-in-picture.patch b/patches/chromium/picture-in-picture.patch index 5f5a8b5a1e8fc..23eb19a4eef37 100644 --- a/patches/chromium/picture-in-picture.patch +++ b/patches/chromium/picture-in-picture.patch @@ -9,23 +9,23 @@ don't get errors for Chrome's generated resources, which are non-existent because we don't generate them in our build. diff --git a/chrome/browser/ui/views/overlay/close_image_button.cc b/chrome/browser/ui/views/overlay/close_image_button.cc -index 8168b4cfbafd42fa93a5aa9a3691c2552fabfb86..ba49212bd76d209f99c1cee649fc1466215a13c1 100644 +index a7a637438116a1c7846194dea4412100a45c9331..bb3877d546bfea141d3d6ebb396b88faab6ee34e 100644 --- a/chrome/browser/ui/views/overlay/close_image_button.cc +++ b/chrome/browser/ui/views/overlay/close_image_button.cc -@@ -5,9 +5,12 @@ +@@ -4,9 +4,12 @@ + #include "chrome/browser/ui/views/overlay/close_image_button.h" - #include "base/feature_list.h" +#include "build/branding_buildflags.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/grit/generated_resources.h" +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) #include "components/vector_icons/vector_icons.h" +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - #include "media/base/media_switches.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" -@@ -29,7 +32,10 @@ CloseImageButton::CloseImageButton(PressedCallback callback) + #include "ui/base/models/image_model.h" +@@ -27,7 +30,10 @@ CloseImageButton::CloseImageButton(PressedCallback callback) : OverlayWindowImageButton(std::move(callback)) { SetSize(gfx::Size(kCloseButtonSize, kCloseButtonSize)); @@ -38,7 +38,7 @@ index 8168b4cfbafd42fa93a5aa9a3691c2552fabfb86..ba49212bd76d209f99c1cee649fc1466 ui::ImageModel::FromVectorIcon(*icon, kColorPipWindowForeground, kCloseButtonIconSize)); diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc -index 937c84308a2894e2abaaec3f068be0ba1741e448..489d68b6452a4814f4cba1e65ab036629583f5b5 100644 +index 6cfeed24487c026d13034b5ea7a8fb275bff4006..601b178ef0e90753559083f506c9a62a7434c530 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc @@ -18,12 +18,16 @@ @@ -58,7 +58,18 @@ index 937c84308a2894e2abaaec3f068be0ba1741e448..489d68b6452a4814f4cba1e65ab03662 #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/views/overlay/back_to_tab_button.h" #include "chrome/browser/ui/views/overlay/back_to_tab_label_button.h" -@@ -79,7 +83,7 @@ +@@ -32,8 +36,10 @@ + #include "chrome/browser/ui/views/overlay/hang_up_button.h" + #include "chrome/browser/ui/views/overlay/minimize_button.h" + #include "chrome/browser/ui/views/overlay/overlay_controls_fade_animation.h" ++#if 0 + #include "chrome/browser/ui/views/overlay/overlay_window_live_caption_button.h" + #include "chrome/browser/ui/views/overlay/overlay_window_live_caption_dialog.h" ++#endif + #include "chrome/browser/ui/views/overlay/playback_image_button.h" + #include "chrome/browser/ui/views/overlay/resize_handle_button.h" + #include "chrome/browser/ui/views/overlay/simple_overlay_window_image_button.h" +@@ -79,7 +85,7 @@ #include "ui/aura/window.h" #endif @@ -67,7 +78,7 @@ index 937c84308a2894e2abaaec3f068be0ba1741e448..489d68b6452a4814f4cba1e65ab03662 #include "chrome/browser/shell_integration_win.h" #include "content/public/browser/render_widget_host_view.h" #include "ui/aura/window.h" -@@ -434,7 +438,7 @@ std::unique_ptr<VideoOverlayWindowViews> VideoOverlayWindowViews::Create( +@@ -409,7 +415,7 @@ std::unique_ptr<VideoOverlayWindowViews> VideoOverlayWindowViews::Create( overlay_window->Init(std::move(params)); overlay_window->OnRootViewReady(); @@ -76,21 +87,136 @@ index 937c84308a2894e2abaaec3f068be0ba1741e448..489d68b6452a4814f4cba1e65ab03662 std::wstring app_user_model_id; Browser* browser = chrome::FindBrowserWithTab(controller->GetWebContents()); if (browser) { -@@ -1247,11 +1251,13 @@ void VideoOverlayWindowViews::SetUpViews() { - &VideoOverlayWindowViews::OnLiveCaptionButtonPressed, - base::Unretained(this))); - live_caption_button->SetSize(kActionButtonSize); -+#if 0 - live_caption_button->SetIsLiveCaptionDialogOpen(false); - live_caption_dialog = std::make_unique<OverlayWindowLiveCaptionDialog>( - Profile::FromBrowserContext( - controller_->GetWebContents()->GetBrowserContext())); - live_caption_dialog->SetVisible(false); +@@ -702,6 +708,7 @@ void VideoOverlayWindowViews::OnMouseEvent(ui::MouseEvent* event) { + } + + case ui::EventType::kMousePressed: ++#if 0 + // Hide the live caption dialog if it's visible and the user clicks + // outside of it. + if (live_caption_dialog_ && live_caption_dialog_->GetVisible() && +@@ -710,6 +717,7 @@ void VideoOverlayWindowViews::OnMouseEvent(ui::MouseEvent* event) { + SetLiveCaptionDialogVisibility(false); + return; + } ++#endif + break; + + default: +@@ -1213,6 +1221,7 @@ void VideoOverlayWindowViews::SetUpViews() { + timestamp->SetBackgroundColor(SK_ColorTRANSPARENT); + timestamp->SetHorizontalAlignment(gfx::ALIGN_LEFT); + ++#if 0 + auto live_status = std::make_unique<views::Label>( + l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_LIVE_STATUS_TEXT), + views::style::CONTEXT_LABEL, views::style::STYLE_CAPTION_BOLD); +@@ -1232,6 +1241,7 @@ void VideoOverlayWindowViews::SetUpViews() { + Profile::FromBrowserContext( + controller_->GetWebContents()->GetBrowserContext())); + live_caption_dialog->SetVisible(false); ++#endif + + auto toggle_microphone_button = + std::make_unique<ToggleMicrophoneButton>(base::BindRepeating( +@@ -1367,6 +1377,7 @@ void VideoOverlayWindowViews::SetUpViews() { + timestamp->layer()->SetFillsBoundsOpaquely(false); + timestamp->layer()->SetName("Timestamp"); + ++#if 0 + live_status->SetPaintToLayer(ui::LAYER_TEXTURED); + live_status->layer()->SetFillsBoundsOpaquely(false); + live_status->layer()->SetName("LiveStatus"); +@@ -1378,6 +1389,7 @@ void VideoOverlayWindowViews::SetUpViews() { + live_caption_dialog->SetPaintToLayer(ui::LAYER_TEXTURED); + live_caption_dialog->layer()->SetFillsBoundsOpaquely(false); + live_caption_dialog->layer()->SetName("LiveCaptionDialog"); ++#endif + + toggle_microphone_button->SetPaintToLayer(ui::LAYER_TEXTURED); + toggle_microphone_button->layer()->SetFillsBoundsOpaquely(false); +@@ -1441,13 +1453,15 @@ void VideoOverlayWindowViews::SetUpViews() { + + timestamp_ = + playback_controls_container_view_->AddChildView(std::move(timestamp)); ++ ++#if 0 + live_status_ = + playback_controls_container_view_->AddChildView(std::move(live_status)); +- + live_caption_button_ = playback_controls_container_view_->AddChildView( + std::move(live_caption_button)); + live_caption_dialog_ = + controls_container_view->AddChildView(std::move(live_caption_dialog)); ++#endif + + toggle_camera_button_ = vc_controls_container_view_->AddChildView( + std::move(toggle_camera_button)); +@@ -1709,6 +1723,7 @@ void VideoOverlayWindowViews::OnUpdateControlsBounds() { + timestamp_->SetSize({max_timestamp_width, kTimestampHeight}); + timestamp_->SetVisible(!is_live_); + ++#if 0 + live_status_->SetPosition(timestamp_position); + live_status_->SetMaximumWidthSingleLine(max_timestamp_width); + live_status_->SetSize( +@@ -1716,7 +1731,6 @@ void VideoOverlayWindowViews::OnUpdateControlsBounds() { + .width(), + kTimestampHeight}); + live_status_->SetVisible(is_live_); +- + gfx::Rect live_caption_button_bounds( + bottom_controls_bounds.right() - kBottomControlsHorizontalMargin - + kActionButtonSize.width(), +@@ -1729,7 +1743,7 @@ void VideoOverlayWindowViews::OnUpdateControlsBounds() { + live_caption_dialog_->SetPosition( + {live_caption_button_bounds.right() - live_caption_dialog_->width(), + live_caption_button_bounds.y() - live_caption_dialog_->height()}); +- +#endif - toggle_microphone_button = - std::make_unique<ToggleMicrophoneButton>(base::BindRepeating( - [](VideoOverlayWindowViews* overlay) { -@@ -2541,6 +2547,7 @@ gfx::Rect VideoOverlayWindowViews::GetLiveCaptionDialogBounds() { + // The play/pause button and replay/forward 10 seconds buttons should not be + // visible while dragging the progress bar or for live media. + const bool is_dragging_progress_bar = +@@ -2053,6 +2067,7 @@ void VideoOverlayWindowViews::OnGestureEvent(ui::GestureEvent* event) { + return; + } + ++#if 0 + if (live_caption_dialog_ && live_caption_dialog_->GetVisible()) { + if (!GetLiveCaptionDialogBounds().Contains(event->location())) { + // Hide the live caption dialog if it's visible and the user taps outside +@@ -2061,11 +2076,11 @@ void VideoOverlayWindowViews::OnGestureEvent(ui::GestureEvent* event) { + event->SetHandled(); + return; + } +- + // Otherwise, let the live caption dialog handle the gesture. + live_caption_dialog_->OnGestureTapEvent(event); + return; + } ++#endif + + if (GetBackToTabControlsBounds().Contains(event->location())) { + controller_->CloseAndFocusInitiator(); +@@ -2171,18 +2186,25 @@ gfx::Rect VideoOverlayWindowViews::GetProgressViewBounds() { + } + + gfx::Rect VideoOverlayWindowViews::GetLiveCaptionButtonBounds() { ++#if 0 + return live_caption_button_->GetMirroredBounds(); ++#endif ++ return gfx::Rect(); + } + + gfx::Rect VideoOverlayWindowViews::GetLiveCaptionDialogBounds() { ++#if 0 + if (!live_caption_dialog_->GetVisible()) { + return gfx::Rect(); + } + return live_caption_dialog_->GetMirroredBounds(); ++#endif ++ return gfx::Rect(); + } bool VideoOverlayWindowViews::HasHighMediaEngagement( const url::Origin& origin) const { @@ -98,7 +224,7 @@ index 937c84308a2894e2abaaec3f068be0ba1741e448..489d68b6452a4814f4cba1e65ab03662 MediaEngagementService* service = MediaEngagementService::Get(Profile::FromBrowserContext( GetController()->GetWebContents()->GetBrowserContext())); -@@ -2549,6 +2556,8 @@ bool VideoOverlayWindowViews::HasHighMediaEngagement( +@@ -2191,6 +2213,8 @@ bool VideoOverlayWindowViews::HasHighMediaEngagement( } return service->HasHighEngagement(origin); @@ -107,3 +233,24 @@ index 937c84308a2894e2abaaec3f068be0ba1741e448..489d68b6452a4814f4cba1e65ab03662 } bool VideoOverlayWindowViews::IsTrustedForMediaPlayback() const { +@@ -2447,16 +2471,20 @@ void VideoOverlayWindowViews::UpdateTimestampLabel(base::TimeDelta current_time, + } + + void VideoOverlayWindowViews::OnLiveCaptionButtonPressed() { ++#if 0 + SetLiveCaptionDialogVisibility(!live_caption_dialog_->GetVisible()); ++#endif + } + + void VideoOverlayWindowViews::SetLiveCaptionDialogVisibility( + bool wanted_visibility) { ++#if 0 + if (wanted_visibility == live_caption_dialog_->GetVisible()) { + return; + } + live_caption_dialog_->SetVisible(wanted_visibility); + live_caption_button_->SetIsLiveCaptionDialogOpen(wanted_visibility); ++#endif + + views::View* controls_to_be_disabled_when_live_caption_is_open[] = { + minimize_button_.get(), diff --git a/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch b/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch index bc040f92d1550..1ae35ff24eb4e 100644 --- a/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch +++ b/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch @@ -8,7 +8,7 @@ needed in chromium but our autofill implementation uses them. This patch can be our autofill implementation to work like Chromium's. diff --git a/ui/color/color_id.h b/ui/color/color_id.h -index 8308dd53c198e4e3c7fe08fd6115b0ed53cf466c..e3323e4c4ff4f96ce235511a38e4e2d8cbb701c0 100644 +index e340ccdfb4c364774679c1b68df4b1340286d41a..72ebf04033e4ec67acb26780d4f252fc0b1d9917 100644 --- a/ui/color/color_id.h +++ b/ui/color/color_id.h @@ -431,6 +431,10 @@ @@ -31,10 +31,10 @@ index 8308dd53c198e4e3c7fe08fd6115b0ed53cf466c..e3323e4c4ff4f96ce235511a38e4e2d8 /* ui::NativeThemeBase::ControlColorId. */ \ E_CPONLY(kColorWebNativeControlAccent) \ diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc -index f606d2a058ed9ebf86b5f020b6897be718a40b68..003e95ca8bb6364fb6b937871b2c78b9ec798bd0 100644 +index 8817142344cc9abed442f07b5cbe759b82901c06..edf6d4ca1bfce93f8dcbeb2585c9ec07e3ff7f76 100644 --- a/ui/color/ui_color_mixer.cc +++ b/ui/color/ui_color_mixer.cc -@@ -180,6 +180,17 @@ void AddUiColorMixer(ColorProvider* provider, const ColorProviderKey& key) { +@@ -181,6 +181,17 @@ void AddUiColorMixer(ColorProvider* provider, const ColorProviderKey& key) { mixer[kColorProgressBarPaused] = {kColorDisabledForeground}; mixer[kColorRadioButtonForegroundChecked] = {kColorButtonForeground}; mixer[kColorRadioButtonForegroundUnchecked] = {kColorSecondaryForeground}; @@ -52,19 +52,19 @@ index f606d2a058ed9ebf86b5f020b6897be718a40b68..003e95ca8bb6364fb6b937871b2c78b9 mixer[kColorSeparator] = {kColorMidground}; mixer[kColorShadowBase] = {dark_mode ? SK_ColorBLACK : gfx::kGoogleGrey800}; mixer[kColorShadowValueAmbientShadowElevationThree] = -@@ -276,6 +287,7 @@ void AddUiColorMixer(ColorProvider* provider, const ColorProviderKey& key) { +@@ -277,6 +288,7 @@ void AddUiColorMixer(ColorProvider* provider, const ColorProviderKey& key) { mixer[kColorTreeNodeForegroundSelectedFocused] = {kColorTreeNodeForeground}; mixer[kColorTreeNodeForegroundSelectedUnfocused] = { kColorTreeNodeForegroundSelectedFocused}; + mixer[kColorUnfocusedBorder] = {kColorMidground}; - mixer[kColorWebNativeControlAccent] = {dark_mode - ? SkColorSetRGB(0x99, 0xC8, 0xFF) - : SkColorSetRGB(0x00, 0x75, 0xFF)}; + mixer[kColorWindowBackground] = {kColorPrimaryBackground}; + CompleteDefaultWebNativeRendererColorIdsDefinition( + mixer, dark_mode, diff --git a/ui/color/win/native_color_mixers_win.cc b/ui/color/win/native_color_mixers_win.cc -index ebc3156ef1df8bfc9bc6e20ddddea4a0259e17e9..c5cbe13ad241564ecdef320de8a10112cda4cdfc 100644 +index dadb94f18feccb570680fc74a899a957f8f7ce1b..dac1ab13e5bb91d5a0901b7988d4ee02a725837d 100644 --- a/ui/color/win/native_color_mixers_win.cc +++ b/ui/color/win/native_color_mixers_win.cc -@@ -171,6 +171,10 @@ void AddNativeUiColorMixer(ColorProvider* provider, +@@ -145,6 +145,10 @@ void AddNativeUiColorMixer(ColorProvider* provider, SetAlpha(kColorNotificationInputForeground, gfx::kGoogleGreyAlpha700); mixer[kColorSliderTrack] = AlphaBlend( kColorNativeHighlight, kColorNativeWindow, gfx::kGoogleGreyAlpha400); @@ -75,7 +75,7 @@ index ebc3156ef1df8bfc9bc6e20ddddea4a0259e17e9..c5cbe13ad241564ecdef320de8a10112 // Window Background mixer[kColorBubbleFooterBackground] = {kColorNativeWindow}; -@@ -179,6 +183,7 @@ void AddNativeUiColorMixer(ColorProvider* provider, +@@ -153,6 +157,7 @@ void AddNativeUiColorMixer(ColorProvider* provider, mixer[kColorFrameInactive] = {kColorNativeWindow}; mixer[kColorPrimaryBackground] = {kColorNativeWindow}; mixer[kColorTooltipBackground] = {kColorNativeWindow}; @@ -83,7 +83,7 @@ index ebc3156ef1df8bfc9bc6e20ddddea4a0259e17e9..c5cbe13ad241564ecdef320de8a10112 // Window Text mixer[kColorAlertLowSeverity] = {kColorNativeWindowText}; -@@ -192,6 +197,7 @@ void AddNativeUiColorMixer(ColorProvider* provider, +@@ -166,6 +171,7 @@ void AddNativeUiColorMixer(ColorProvider* provider, mixer[kColorTableGroupingIndicator] = {kColorNativeWindowText}; mixer[kColorThrobber] = {kColorNativeWindowText}; mixer[kColorTooltipForeground] = {kColorNativeWindowText}; @@ -91,7 +91,7 @@ index ebc3156ef1df8bfc9bc6e20ddddea4a0259e17e9..c5cbe13ad241564ecdef320de8a10112 // Hyperlinks mixer[kColorLinkForegroundDefault] = {kColorNativeHotlight}; -@@ -234,6 +240,7 @@ void AddNativeUiColorMixer(ColorProvider* provider, +@@ -208,6 +214,7 @@ void AddNativeUiColorMixer(ColorProvider* provider, mixer[kColorTextfieldForeground] = {kColorNativeBtnText}; mixer[kColorTextfieldForegroundPlaceholder] = {kColorNativeBtnText}; mixer[kColorTextfieldForegroundDisabled] = {kColorNativeBtnText}; diff --git a/patches/chromium/printing.patch b/patches/chromium/printing.patch index e77bf1cabefed..11c9e3724f584 100644 --- a/patches/chromium/printing.patch +++ b/patches/chromium/printing.patch @@ -11,7 +11,7 @@ majority of changes originally come from these PRs: This patch also fixes callback for manual user cancellation and success. diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc -index 6f35d5ab358627ff8b1cbf09f5643f0f484e027a..5e736b846880a7d4a1e1611a0f70feca102bfbbc 100644 +index f91857eb0b6ad385721b8224100de26dfdd7dd8d..45e8766fcb8d46d8edc3bf8d21d3f826a8ae24be 100644 --- a/chrome/browser/printing/print_job.cc +++ b/chrome/browser/printing/print_job.cc @@ -97,6 +97,7 @@ bool PrintWithReducedRasterization(PrefService* prefs) { @@ -30,7 +30,7 @@ index 6f35d5ab358627ff8b1cbf09f5643f0f484e027a..5e736b846880a7d4a1e1611a0f70feca #endif // BUILDFLAG(IS_WIN) -@@ -151,10 +153,8 @@ void PrintJob::Initialize(std::unique_ptr<PrinterQuery> query, +@@ -204,10 +206,8 @@ void PrintJob::Initialize(std::unique_ptr<PrinterQuery> query, #if BUILDFLAG(IS_WIN) pdf_page_mapping_ = PageNumber::GetPages(settings->ranges(), page_count); @@ -43,7 +43,7 @@ index 6f35d5ab358627ff8b1cbf09f5643f0f484e027a..5e736b846880a7d4a1e1611a0f70feca #endif auto new_doc = base::MakeRefCounted<PrintedDocument>(std::move(settings), -@@ -404,8 +404,10 @@ void PrintJob::StartPdfToEmfConversion( +@@ -407,8 +407,10 @@ void PrintJob::StartPdfToEmfConversion( const PrintSettings& settings = document()->settings(); @@ -55,7 +55,7 @@ index 6f35d5ab358627ff8b1cbf09f5643f0f484e027a..5e736b846880a7d4a1e1611a0f70feca using RenderMode = PdfRenderSettings::Mode; RenderMode mode = print_with_reduced_rasterization -@@ -497,8 +499,10 @@ void PrintJob::StartPdfToPostScriptConversion( +@@ -500,8 +502,10 @@ void PrintJob::StartPdfToPostScriptConversion( if (ps_level2) { mode = PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2; } else { @@ -577,7 +577,7 @@ index 824d6d8a9242302c2ab0c0c517d0cc329e607100..d3b25c90c90fe860990789aa96c872b4 // Indication that the job is getting canceled. bool canceling_job_ = false; diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc -index 4b1775f4a882fbabfe65df7784baebe6d8bee788..5a3e71dc3894fa96ac7a6b93b3552a90f36fe7a2 100644 +index 20bbbeddd18ef26b68defcdbd4a7c62706c43d0b..7b0071c169556a080ecbf5e8a6a3b878675f6bf7 100644 --- a/chrome/browser/printing/printer_query.cc +++ b/chrome/browser/printing/printer_query.cc @@ -356,17 +356,19 @@ void PrinterQuery::UpdatePrintSettings(base::Value::Dict new_settings, @@ -666,7 +666,7 @@ index ac2f719be566020d9f41364560c12e6d6d0fe3d8..16d758a6936f66148a196761cfb875f6 PrintingFailed(int32 cookie, PrintFailureReason reason); diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc -index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e62cb2cc4 100644 +index a53e79851e4f01c8d256cf36d8fd6838737aa740..5d786ca1b6ae4314a871dee16b183f34669bcbf6 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc @@ -53,6 +53,7 @@ @@ -677,7 +677,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e #include "printing/units.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" -@@ -1246,14 +1247,14 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) { +@@ -1240,14 +1241,14 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) { } print_in_progress_ = true; @@ -694,7 +694,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e if (!weak_this) { return; } -@@ -1284,12 +1285,14 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver( +@@ -1278,12 +1279,14 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver( receivers_.Add(this, std::move(receiver)); } @@ -712,7 +712,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e ScopedIPC scoped_ipc(weak_ptr_factory_.GetWeakPtr()); if (ipc_nesting_level_ > kAllowedIpcDepthForPrint) { return; -@@ -1306,9 +1309,10 @@ void PrintRenderFrameHelper::PrintRequestedPagesInternal( +@@ -1300,9 +1303,10 @@ void PrintRenderFrameHelper::PrintRequestedPagesInternal( is_loading_ = frame->WillPrintSoon(); if (is_loading_) { @@ -726,7 +726,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e SetupOnStopLoadingTimeout(); return; } -@@ -1318,7 +1322,7 @@ void PrintRenderFrameHelper::PrintRequestedPagesInternal( +@@ -1312,7 +1316,7 @@ void PrintRenderFrameHelper::PrintRequestedPagesInternal( // plugin node and print that instead. auto plugin = delegate_->GetPdfElement(frame); @@ -735,7 +735,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e if (render_frame_gone_) { return; -@@ -1474,6 +1478,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) { +@@ -1468,6 +1472,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) { if (ipc_nesting_level_ > kAllowedIpcDepthForPrint) return; @@ -744,7 +744,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e print_preview_context_.OnPrintPreview(); #if BUILDFLAG(IS_CHROMEOS) -@@ -2086,17 +2092,25 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) { +@@ -2080,17 +2086,25 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) { void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, const blink::WebNode& node, @@ -773,7 +773,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e DidFinishPrinting(PrintingResult::kFailPrintInit); return; } -@@ -2117,8 +2131,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, +@@ -2111,8 +2125,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, print_pages_params_->params->print_scaling_option; auto self = weak_ptr_factory_.GetWeakPtr(); @@ -790,7 +790,7 @@ index d7555d8c33ca05525454eb6583b4b37a4bcae558..ebddc2487818388675cc14c789b8b67e // Check if `this` is still valid. if (!self) return; -@@ -2385,29 +2406,43 @@ void PrintRenderFrameHelper::IPCProcessed() { +@@ -2379,29 +2400,43 @@ void PrintRenderFrameHelper::IPCProcessed() { } bool PrintRenderFrameHelper::InitPrintSettings(blink::WebLocalFrame* frame, @@ -899,7 +899,7 @@ index 746a056e1c7980803323739c51cedb930c62de25..34a9e45a3407612d6960a7cad798cf30 std::unique_ptr<PrintSettings> settings = PrintSettingsFromJobSettings(job_settings); diff --git a/printing/printing_context.h b/printing/printing_context.h -index 3a98838e27621e34ab050a0f5dce7110f0d88641..3cce0abe2a2893f1ad5ee747008b66c74e2c2434 100644 +index 2f34f45aaf89e6f4600be1d2b8444c636b0cc83f..5bfd45c5efbf300a36e016af80e18fb9ad376d41 100644 --- a/printing/printing_context.h +++ b/printing/printing_context.h @@ -208,6 +208,9 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext { @@ -923,16 +923,16 @@ index 3a98838e27621e34ab050a0f5dce7110f0d88641..3cce0abe2a2893f1ad5ee747008b66c7 virtual mojom::ResultCode OnError(); diff --git a/printing/printing_context_linux.cc b/printing/printing_context_linux.cc -index 1bf52330b555e14cf32c356321bef36442fab3d5..ee7ab77226a2aaf8f4250188a15af63dde70bce0 100644 +index e83735211e30a77ef1bc82b6a252da02a18626fc..b0c8fd3c5e3c5b3d2d64bee9df513e1b4829809c 100644 --- a/printing/printing_context_linux.cc +++ b/printing/printing_context_linux.cc -@@ -55,9 +55,8 @@ void PrintingContextLinux::AskUserForSettings(int max_pages, +@@ -54,9 +54,8 @@ void PrintingContextLinux::AskUserForSettings(int max_pages, bool is_scripted, PrintSettingsCallback callback) { if (!print_dialog_) { -- // Can only get here if the renderer is sending bad messages. -- // http://crbug.com/341777 -- NOTREACHED(); +- // Can only get here if the renderer is sending bad messages. Ignore. +- // https://crbug.com/41088489 +- return; + print_dialog_ = ui::LinuxUi::instance()->CreatePrintDialog(this); + print_dialog_->UseDefaultSettings(); } diff --git a/patches/chromium/process_singleton.patch b/patches/chromium/process_singleton.patch index 11fc6d2189648..03e259fc23d20 100644 --- a/patches/chromium/process_singleton.patch +++ b/patches/chromium/process_singleton.patch @@ -51,7 +51,7 @@ index c19313c0b58baf0597a99d52ed7fcdb7faacc934..2748dd196fe1f56357348a204e24f0b8 base::win::MessageWindow window_; // The message-only window. bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment. diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc -index e0cfeb40e887545830a3294d865c2df466dda8fe..08cbe32a258bf478f1da0a07064d3e9ef14c44a5 100644 +index 9d7be37f1d1fbde55773b4005878d8ff03cac22a..08cbe32a258bf478f1da0a07064d3e9ef14c44a5 100644 --- a/chrome/browser/process_singleton_posix.cc +++ b/chrome/browser/process_singleton_posix.cc @@ -59,6 +59,7 @@ @@ -133,7 +133,7 @@ index e0cfeb40e887545830a3294d865c2df466dda8fe..08cbe32a258bf478f1da0a07064d3e9e // Create the socket file somewhere in /tmp which is usually mounted as a // normal filesystem. Some network filesystems (notably AFS) are screwy and // do not support Unix domain sockets. -- if (!socket_dir_.CreateUniqueTempDir()) { +- if (!socket_dir_.CreateUniqueTempDir(/*prefix=*/FILE_PATH_LITERAL(""))) { - LOG(ERROR) << "Failed to create socket directory."; + base::FilePath tmp_dir; + if (!base::GetTempDir(&tmp_dir)) { @@ -165,7 +165,7 @@ index e0cfeb40e887545830a3294d865c2df466dda8fe..08cbe32a258bf478f1da0a07064d3e9e int dir_mode = 0; CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) && diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc -index 1bc2d932c882d68b5ed4ed3cdaaa903850ab4989..64ebf49c0d1b6396d1cfbe3bf91480f61b47688d 100644 +index ff44618efa8f8082b5da2c416802b781290c6cac..ae659d84a5ae2f2e87ce288477506575f8d86839 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc @@ -29,7 +29,9 @@ @@ -226,7 +226,7 @@ index 1bc2d932c882d68b5ed4ed3cdaaa903850ab4989..64ebf49c0d1b6396d1cfbe3bf91480f6 // without ownership and explicitly get the ownership afterward. - base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName)); + base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, mutexName.c_str())); - if (!only_me.IsValid()) { + if (!only_me.is_valid()) { DPLOG(FATAL) << "CreateMutex failed"; return false; @@ -429,6 +440,17 @@ bool ProcessSingleton::Create() { diff --git a/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch b/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch index b774bce37da97..00dcc3dfe19a6 100644 --- a/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch +++ b/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch @@ -8,18 +8,18 @@ Chrome moved the SetCursor IPC message to mojo, which we use to tell OSR about ` Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2172779 diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h -index 18c6ee6657e5edb5e90102dd9a20e5c0efeed843..af763ad4e441e54556854cd40c4cb9098f84bb58 100644 +index 9a4195a3e53353342c75d6c4372ed4c27ef13fd3..bc1bfa1ac381ec94121a264d9dcbae9e02ab5a81 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h -@@ -27,6 +27,7 @@ +@@ -26,6 +26,7 @@ + #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" #include "ui/base/mojom/window_show_state.mojom-forward.h" #include "ui/base/ui_base_types.h" - #include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" +#include "ui/base/cursor/cursor.h" - #include "ui/gfx/native_widget_types.h" + #include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" + #include "ui/gfx/native_ui_types.h" - namespace blink { -@@ -299,6 +300,9 @@ class CONTENT_EXPORT RenderWidgetHostDelegate { +@@ -293,6 +294,9 @@ class CONTENT_EXPORT RenderWidgetHostDelegate { // Returns the associated RenderViewHostDelegateView*, if possible. virtual RenderViewHostDelegateView* GetDelegateView(); @@ -30,10 +30,10 @@ index 18c6ee6657e5edb5e90102dd9a20e5c0efeed843..af763ad4e441e54556854cd40c4cb909 // RenderWidgetHost on the primary main frame, and false otherwise. virtual bool IsWidgetForPrimaryMainFrame(RenderWidgetHostImpl*); diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc -index e8baae79ab127e4626f39247a5e57fe6a6114453..8073bdba33d6ddbc0306e8e9256b36cd87537eca 100644 +index 982b5edc933fdf1c4884dd0e0e7b957cee31c5ef..f28d6f919b5c6aca87c3feb701967a255c45d7db 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc -@@ -2083,6 +2083,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) { +@@ -2075,6 +2075,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) { if (view_) { view_->UpdateCursor(cursor); } @@ -44,10 +44,10 @@ index e8baae79ab127e4626f39247a5e57fe6a6114453..8073bdba33d6ddbc0306e8e9256b36cd void RenderWidgetHostImpl::ShowContextMenuAtPoint( diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index 5e35d7af2bcf9078887f4e2658e3f067f3b4f1b7..95ea7eb743ae3e4de52741be7f2969bbf86d8a29 100644 +index e003e3a9784e3a9741283128a97f4e3bc255935b..b50aa1890036c762ec0df75d133f7b9fb29df4cd 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -6116,6 +6116,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() { +@@ -6123,6 +6123,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() { return text_input_manager_.get(); } @@ -60,10 +60,10 @@ index 5e35d7af2bcf9078887f4e2658e3f067f3b4f1b7..95ea7eb743ae3e4de52741be7f2969bb RenderWidgetHostImpl* render_widget_host) { return render_widget_host == GetPrimaryMainFrame()->GetRenderWidgetHost(); diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h -index 8ae956ce13ae0be1436875228bc5f2915caf9f91..aff1ff3112b2d52f5e111fe7343aca2d59165e64 100644 +index 477abb0581334f2c0bee43982426cc87309024ce..563e943c90c03876dce8846ca32775b8929e569e 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h -@@ -1176,6 +1176,7 @@ class CONTENT_EXPORT WebContentsImpl +@@ -1190,6 +1190,7 @@ class CONTENT_EXPORT WebContentsImpl void SendScreenRects() override; void SendActiveState(bool active) override; TextInputManager* GetTextInputManager() override; @@ -72,18 +72,18 @@ index 8ae956ce13ae0be1436875228bc5f2915caf9f91..aff1ff3112b2d52f5e111fe7343aca2d RenderWidgetHostImpl* render_widget_host) override; bool IsShowingContextMenuOnPage() const override; diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h -index c6af2619bf13c2a6982834c6b888ad15da275627..5ed2521d5cb21341cc4056cb1f1a69c9129967f5 100644 +index 8e0a8b0e3e005d81c7fec493eca9e8262edb2853..1fb13e811d5ee2875b6c4162c6b9843d3e59d431 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h -@@ -35,6 +35,7 @@ +@@ -33,6 +33,7 @@ + #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-forward.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-forward.h" #include "third_party/blink/public/mojom/media/capture_handle_config.mojom-forward.h" - #include "third_party/skia/include/core/SkColor.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/page_transition_types.h" #include "ui/base/window_open_disposition.h" -@@ -643,6 +644,9 @@ class CONTENT_EXPORT WebContentsObserver : public base::CheckedObserver { +@@ -641,6 +642,9 @@ class CONTENT_EXPORT WebContentsObserver : public base::CheckedObserver { // Invoked when the primary main frame changes size. virtual void PrimaryMainFrameWasResized(bool width_changed) {} diff --git a/patches/chromium/refactor_expose_file_system_access_blocklist.patch b/patches/chromium/refactor_expose_file_system_access_blocklist.patch index 0d20c82bcbcb0..ad51081667622 100644 --- a/patches/chromium/refactor_expose_file_system_access_blocklist.patch +++ b/patches/chromium/refactor_expose_file_system_access_blocklist.patch @@ -8,11 +8,11 @@ it in Electron and prevent drift from Chrome's blocklist. We should look for a w to upstream this change to Chrome. diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc -index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333fc01c4ee 100644 +index ff5f771212a489cc202b39100a0b42413b904e0c..ebede6f938eb1ec08cc472cba65f2faf1c6f971c 100644 --- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc +++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc -@@ -82,11 +82,13 @@ - #include "chrome/browser/ui/browser_window.h" +@@ -84,11 +84,13 @@ + #include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h" // nogncheck crbug.com/40147906 #include "chrome/browser/ui/tabs/public/tab_features.h" #include "chrome/browser/ui/views/file_system_access/file_system_access_page_action_controller.h" +#if 0 @@ -25,7 +25,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 #include "components/tabs/public/tab_interface.h" #if BUILDFLAG(ENABLE_PLATFORM_APPS) #include "extensions/browser/extension_registry.h" // nogncheck -@@ -262,190 +264,10 @@ bool MaybeIsLocalUNCPath(const base::FilePath& path) { +@@ -288,190 +290,10 @@ bool MaybeIsLocalUNCPath(const base::FilePath& path) { } #endif @@ -220,7 +220,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 // Checks if `path` should be blocked by the `rules`. // The BlockType of the nearest ancestor of a path to check is what -@@ -1271,16 +1093,6 @@ struct ChromeFileSystemAccessPermissionContext::OriginState { +@@ -1405,16 +1227,6 @@ struct ChromeFileSystemAccessPermissionContext::OriginState { std::unique_ptr<base::RetainingOneShotTimer> cleanup_timer; }; @@ -237,7 +237,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 ChromeFileSystemAccessPermissionContext:: ChromeFileSystemAccessPermissionContext(content::BrowserContext* context, const base::Clock* clock) -@@ -1299,7 +1111,7 @@ ChromeFileSystemAccessPermissionContext:: +@@ -1433,7 +1245,7 @@ ChromeFileSystemAccessPermissionContext:: #if BUILDFLAG(IS_ANDROID) one_time_permissions_tracker_.Observe( OneTimePermissionsTrackerFactory::GetForBrowserContext(context)); @@ -246,7 +246,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 auto* provider = web_app::WebAppProvider::GetForWebApps( Profile::FromBrowserContext(profile_)); if (provider) { -@@ -2566,7 +2378,7 @@ void ChromeFileSystemAccessPermissionContext::OnShutdown() { +@@ -2818,7 +2630,7 @@ void ChromeFileSystemAccessPermissionContext::OnShutdown() { one_time_permissions_tracker_.Reset(); } @@ -255,7 +255,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 void ChromeFileSystemAccessPermissionContext::OnWebAppInstalled( const webapps::AppId& app_id) { if (!base::FeatureList::IsEnabled( -@@ -2901,11 +2713,7 @@ bool ChromeFileSystemAccessPermissionContext:: +@@ -3176,11 +2988,7 @@ bool ChromeFileSystemAccessPermissionContext:: HandleType handle_type, UserAction user_action, GrantType grant_type) { @@ -268,7 +268,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 if (!base::FeatureList::IsEnabled( features::kFileSystemAccessPersistentPermissions)) { return false; -@@ -2956,6 +2764,7 @@ bool ChromeFileSystemAccessPermissionContext:: +@@ -3231,6 +3039,7 @@ bool ChromeFileSystemAccessPermissionContext:: return false; #endif // BUILDFLAG(IS_ANDROID) @@ -277,7 +277,7 @@ index 7611ba742de5b11c5a1f43c2e18d78cb01c9562f..640076ba6fc15637e53e1126db4f5333 std::vector<FileRequestData> ChromeFileSystemAccessPermissionContext:: diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.h b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.h -index 51bec8ef2a5212494625898fdeb500344525d8f4..6deb4b86b35c2ba38849e25af7691ac858dfaa3e 100644 +index c026a5ac558d3570c8d893943f93a5833c16ccd2..4a9bc924e609066086812bc1002258b6ce586c14 100644 --- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.h +++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.h @@ -9,10 +9,13 @@ @@ -302,9 +302,9 @@ index 51bec8ef2a5212494625898fdeb500344525d8f4..6deb4b86b35c2ba38849e25af7691ac8 #include "components/enterprise/buildflags/buildflags.h" #include "components/permissions/features.h" #include "components/permissions/object_permission_context_base.h" -@@ -403,6 +407,191 @@ class ChromeFileSystemAccessPermissionContext - return is_block_path_rules_init_complete_; - } +@@ -419,6 +423,191 @@ class ChromeFileSystemAccessPermissionContext + bool IsPathInDowngradedReadPathsForTesting(const url::Origin& origin, + const base::FilePath& path); + // Sentinel used to indicate that no PathService key is specified for a path in + // the struct below. diff --git a/patches/chromium/refactor_expose_hostimportmoduledynamically_and.patch b/patches/chromium/refactor_expose_hostimportmoduledynamically_and.patch index 2c58d3c9665fa..031d0e6982534 100644 --- a/patches/chromium/refactor_expose_hostimportmoduledynamically_and.patch +++ b/patches/chromium/refactor_expose_hostimportmoduledynamically_and.patch @@ -7,11 +7,11 @@ Subject: refactor: expose HostImportModuleDynamically and This is so that Electron can blend Blink's and Node's implementations of these isolate handlers. diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc -index d7a222d99389ae8f826080ae31321043e75b3fc9..9b31bf1176e72b69468244a1a4be24ab5878c74a 100644 +index b55ebf73e7afb85f56424a093c0934ee3a87436b..1612ec99332d134ba7e59f4a522bbb06f728c63a 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc -@@ -645,8 +645,9 @@ bool WasmJSPromiseIntegrationEnabledCallback(v8::Local<v8::Context> context) { - return RuntimeEnabledFeatures::WebAssemblyJSPromiseIntegrationEnabled( +@@ -710,8 +710,9 @@ bool WasmCustomDescriptorsEnabledCallback(v8::Local<v8::Context> context) { + return RuntimeEnabledFeatures::WebAssemblyCustomDescriptorsEnabled( execution_context); } +} // namespace @@ -21,7 +21,7 @@ index d7a222d99389ae8f826080ae31321043e75b3fc9..9b31bf1176e72b69468244a1a4be24ab v8::Local<v8::Context> context, v8::Local<v8::Data> v8_host_defined_options, v8::Local<v8::Value> v8_referrer_resource_url, -@@ -724,20 +725,23 @@ v8::MaybeLocal<v8::Promise> HostImportModuleWithPhaseDynamically( +@@ -789,20 +790,23 @@ v8::MaybeLocal<v8::Promise> HostImportModuleWithPhaseDynamically( return resolver->Promise().V8Promise(); } @@ -47,7 +47,7 @@ index d7a222d99389ae8f826080ae31321043e75b3fc9..9b31bf1176e72b69468244a1a4be24ab v8::Local<v8::Module> module, v8::Local<v8::Object> meta) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); -@@ -764,6 +768,7 @@ void HostGetImportMetaProperties(v8::Local<v8::Context> context, +@@ -829,6 +833,7 @@ void HostGetImportMetaProperties(v8::Local<v8::Context> context, meta->CreateDataProperty(context, resolve_key, resolve_value).ToChecked(); } @@ -55,7 +55,7 @@ index d7a222d99389ae8f826080ae31321043e75b3fc9..9b31bf1176e72b69468244a1a4be24ab bool IsDOMExceptionWrapper(v8::Isolate* isolate, v8::Local<v8::Object> object) { return V8DOMException::HasInstance(isolate, object); } -@@ -794,7 +799,6 @@ void EmitDevToolsEvent(v8::Isolate* isolate) { +@@ -859,7 +864,6 @@ void EmitDevToolsEvent(v8::Isolate* isolate) { } // namespace @@ -63,7 +63,7 @@ index d7a222d99389ae8f826080ae31321043e75b3fc9..9b31bf1176e72b69468244a1a4be24ab void V8Initializer::InitializeV8Common(v8::Isolate* isolate) { // Set up garbage collection before setting up anything else as V8 may trigger // GCs during Blink setup. -@@ -811,9 +815,9 @@ void V8Initializer::InitializeV8Common(v8::Isolate* isolate) { +@@ -875,9 +879,9 @@ void V8Initializer::InitializeV8Common(v8::Isolate* isolate) { SharedArrayBufferConstructorEnabledCallback); isolate->SetHostImportModuleDynamicallyCallback(HostImportModuleDynamically); isolate->SetHostImportModuleWithPhaseDynamicallyCallback( diff --git a/patches/chromium/refactor_patch_electron_permissiontypes_into_blink.patch b/patches/chromium/refactor_patch_electron_permissiontypes_into_blink.patch index dece1ac680550..af8b5a6e251c5 100644 --- a/patches/chromium/refactor_patch_electron_permissiontypes_into_blink.patch +++ b/patches/chromium/refactor_patch_electron_permissiontypes_into_blink.patch @@ -6,7 +6,7 @@ Subject: refactor: patch electron PermissionTypes into blink 6387077: [PermissionOptions] Generalize PermissionRequestDescription | https://chromium-review.googlesource.com/c/chromium/src/+/6387077 diff --git a/components/permissions/permission_util.cc b/components/permissions/permission_util.cc -index 38134a075fbb3586eec543591c88fcf7dcd53e3d..a65838e017a01c8fbb8cd9afe7e3edcce22bf947 100644 +index 18ad7ed73b0ed4de158519c01342f0bfd7cc3666..43f46dbbba4fb66b2a2c66580b85de0d7e16bf57 100644 --- a/components/permissions/permission_util.cc +++ b/components/permissions/permission_util.cc @@ -536,7 +536,17 @@ ContentSettingsType PermissionUtil::PermissionTypeToContentSettingsTypeSafe( @@ -28,10 +28,10 @@ index 38134a075fbb3586eec543591c88fcf7dcd53e3d..a65838e017a01c8fbb8cd9afe7e3edcc break; } diff --git a/content/browser/permissions/permission_controller_impl.cc b/content/browser/permissions/permission_controller_impl.cc -index f6a28f5efae758a93aa52ebd28e25ece996f0e7e..7a6e702126234fa8f09ea5e8eeb3bc67155f76ca 100644 +index e56096991dfbffa3a16aa3aca602b59fbd48a4d5..80451d235373443f4e3d3f26d64e927b7951bdb5 100644 --- a/content/browser/permissions/permission_controller_impl.cc +++ b/content/browser/permissions/permission_controller_impl.cc -@@ -88,7 +88,15 @@ PermissionToSchedulingFeature(PermissionType permission_name) { +@@ -94,7 +94,15 @@ PermissionToSchedulingFeature(PermissionType permission_name) { case PermissionType::AUTOMATIC_FULLSCREEN: case PermissionType::WEB_APP_INSTALLATION: case PermissionType::LOCAL_NETWORK_ACCESS: @@ -164,7 +164,7 @@ index c286d87043ec4cb2e51ec9d82d08e4c84f5a270c..164a2a446947dae687922363d324a6d3 // Always keep this at the end. NUM, diff --git a/third_party/blink/public/mojom/permissions/permission.mojom b/third_party/blink/public/mojom/permissions/permission.mojom -index 47c73522cbd7c1d12dabfecf6f55a74690ebc189..6b8ed935e8c440cbf655d122a398d33e3e4ad89b 100644 +index 2b24e692042a352e931278ead6a06e057f73eda6..8bee55daa5e1d1fe115693dbf020c7bc7d3b61fd 100644 --- a/third_party/blink/public/mojom/permissions/permission.mojom +++ b/third_party/blink/public/mojom/permissions/permission.mojom @@ -44,7 +44,15 @@ enum PermissionName { @@ -185,10 +185,10 @@ index 47c73522cbd7c1d12dabfecf6f55a74690ebc189..6b8ed935e8c440cbf655d122a398d33e struct MidiPermissionDescriptor { diff --git a/third_party/blink/renderer/modules/permissions/permission_utils.cc b/third_party/blink/renderer/modules/permissions/permission_utils.cc -index 63df740efad1e407f0990d2ba48a9cbcb8bdb6f8..3973be677468b36124b88293c46cab615a4a63c5 100644 +index a980ed6afb84eceef9c9b594b325e8e3783821ec..ff2898ca035ae5f2bc218615a87ec148e3764385 100644 --- a/third_party/blink/renderer/modules/permissions/permission_utils.cc +++ b/third_party/blink/renderer/modules/permissions/permission_utils.cc -@@ -146,8 +146,22 @@ String PermissionNameToString(PermissionName name) { +@@ -145,8 +145,22 @@ String PermissionNameToString(PermissionName name) { return "web-printing"; case PermissionName::SMART_CARD: return "smart-card"; diff --git a/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch b/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch deleted file mode 100644 index 5b21cb50a234d..0000000000000 --- a/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Charles Kerr <charles@charleskerr.com> -Date: Wed, 9 Jun 2021 14:28:08 -0500 -Subject: refactor: restore base::AdaptCallbackForRepeating - -Undo https://chromium-review.googlesource.com/c/chromium/src/+/2941842 -to reinstate base::AdaptCallbackForRepeating(). It was removed to fix -https://bugs.chromium.org/p/chromium/issues/detail?id=730593 . - -We use AdaptCallbackForRepeating() in about a dozen places. This patch -should be removed as soon as those have been updated. Patching because -every instance is a FTBFS that prevents testing any one instance's fix. - -diff --git a/base/functional/callback_helpers.h b/base/functional/callback_helpers.h -index f1aa11fec7c0994ac19a26a02800f25de8f2f519..bbfdb3e4839ed96e4c6238235458a421c917411f 100644 ---- a/base/functional/callback_helpers.h -+++ b/base/functional/callback_helpers.h -@@ -99,6 +99,22 @@ RepeatingCallback<void(Args...)> ForwardRepeatingCallbacks( - std::move(v)); - } - -+// Wraps the given OnceCallback into a RepeatingCallback that relays its -+// invocation to the original OnceCallback on the first invocation. The -+// following invocations are just ignored. -+// -+// Note that this deliberately subverts the Once/Repeating paradigm of Callbacks -+// but helps ease the migration from old-style Callbacks. Avoid if possible; use -+// if necessary for migration. TODO(tzik): Remove it. https://crbug.com/730593 -+template <typename... Args> -+RepeatingCallback<void(Args...)> AdaptCallbackForRepeating( -+ OnceCallback<void(Args...)> callback) { -+ using Helper = internal::OnceCallbackHolder<Args...>; -+ return base::BindRepeating( -+ &Helper::Run, std::make_unique<Helper>(std::move(callback), -+ /*ignore_extra_runs=*/true)); -+} -+ - // Wraps the given OnceCallback and returns two OnceCallbacks with an identical - // signature. On first invokation of either returned callbacks, the original - // callback is invoked. Invoking the remaining callback results in a crash. diff --git a/patches/chromium/refactor_unfilter_unresponsive_events.patch b/patches/chromium/refactor_unfilter_unresponsive_events.patch index 127bc7d374fb1..80267dbac2144 100644 --- a/patches/chromium/refactor_unfilter_unresponsive_events.patch +++ b/patches/chromium/refactor_unfilter_unresponsive_events.patch @@ -15,10 +15,10 @@ This CL removes these filters so the unresponsive event can still be accessed from our JS event. The filtering is moved into Electron's code. diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index dd274924f1c26efbc9fc3683f69647a0933a9855..35def2ce3af887c8f13f2d55590468397c89c708 100644 +index 93c078a29e7142e54a20470f7c18f8aa8abf63bf..70ce66aeaecb2f34efb7db8a74c63f9f7f8cdbc8 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -10226,25 +10226,13 @@ void WebContentsImpl::RendererUnresponsive( +@@ -10282,25 +10282,13 @@ void WebContentsImpl::RendererUnresponsive( base::RepeatingClosure hang_monitor_restarter) { OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RendererUnresponsive", "render_widget_host", render_widget_host); diff --git a/patches/chromium/render_widget_host_view_mac.patch b/patches/chromium/render_widget_host_view_mac.patch index 8a814118a29e1..9e7254cbb6954 100644 --- a/patches/chromium/render_widget_host_view_mac.patch +++ b/patches/chromium/render_widget_host_view_mac.patch @@ -8,7 +8,7 @@ respond to the first mouse click in their window, which is desirable for some kinds of utility windows. Similarly for `disableAutoHideCursor`. diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm -index 4c2223346b3db6d12585cf8ca9f0fb55dfc327f0..437b47fd3a1a43fd52980ea550db953ba47990eb 100644 +index b17bc8928cc86536fa01bd85b921020a2c656ca3..f69cd6100f2ac5ccb6f185e0d0bf186073ed5953 100644 --- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm +++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm @@ -167,6 +167,15 @@ void ExtractUnderlines(NSAttributedString* string, @@ -27,28 +27,27 @@ index 4c2223346b3db6d12585cf8ca9f0fb55dfc327f0..437b47fd3a1a43fd52980ea550db953b // RenderWidgetHostViewCocoa --------------------------------------------------- // Private methods: -@@ -781,6 +790,9 @@ - (AcceptMouseEvents)acceptsMouseEventsOption { +@@ -781,6 +790,10 @@ - (AcceptMouseEvents)acceptsMouseEventsOption { } - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent { + if ([self.window respondsToSelector:@selector(acceptsFirstMouse)] && + [self.window acceptsFirstMouse]) + return YES; ++ // Enable "click-through" if mouse clicks are accepted in inactive windows. return [self acceptsMouseEventsOption] > AcceptMouseEvents::kWhenInActiveWindow; -@@ -933,6 +945,10 @@ - (BOOL)shouldIgnoreMouseEvent:(NSEvent*)theEvent { +@@ -933,6 +946,8 @@ - (BOOL)shouldIgnoreMouseEvent:(NSEvent*)theEvent { // its parent view. BOOL hitSelf = NO; while (view) { -+ if ([view respondsToSelector:@selector(shouldIgnoreMouseEvent)] && ![view shouldIgnoreMouseEvent]) { ++ if ([view respondsToSelector:@selector(shouldIgnoreMouseEvent)] && ![view shouldIgnoreMouseEvent]) + return NO; -+ } -+ if (view == self) hitSelf = YES; if ([view isKindOfClass:[self class]] && ![view isEqual:self] && -@@ -1267,6 +1283,10 @@ - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv { +@@ -1267,6 +1282,10 @@ - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv { eventType == NSEventTypeKeyDown && !(modifierFlags & NSEventModifierFlagCommand); diff --git a/patches/chromium/resource_file_conflict.patch b/patches/chromium/resource_file_conflict.patch index 6d13b85c3a3fe..5afdc028393bc 100644 --- a/patches/chromium/resource_file_conflict.patch +++ b/patches/chromium/resource_file_conflict.patch @@ -52,7 +52,7 @@ Some alternatives to this patch: None of these options seems like a substantial maintainability win over this patch to me (@nornagon). diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn -index 9fd2e83b2a7bc7e8dae09e45bec64ad41e06ee6a..e648bb4ed2ff72441faa8773e449e0b6174f5af5 100644 +index fa036801ce974378c5fb586bcf0609da24dd8547..606b3bd43179a5b4179a6ec9f58e531d55c1acb5 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn @@ -1538,7 +1538,7 @@ if (is_chrome_branded && !is_android) { diff --git a/patches/chromium/revert_code_health_clean_up_stale_macwebcontentsocclusion.patch b/patches/chromium/revert_code_health_clean_up_stale_macwebcontentsocclusion.patch index 968a7f21cebbb..00d6995ff2fce 100644 --- a/patches/chromium/revert_code_health_clean_up_stale_macwebcontentsocclusion.patch +++ b/patches/chromium/revert_code_health_clean_up_stale_macwebcontentsocclusion.patch @@ -18,12 +18,12 @@ This partially (leaves the removal of the feature flag) reverts ef865130abd5539e7bce12308659b19980368f12. diff --git a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h -index 428902f90950b2e9434c8a624a313268ebb80cd4..afcc3bc481be6a16119f7e2af647276cb0dafa1e 100644 +index 13e928e3790735fdad68fbca0a8a8e9d0836fdee..2719f8853e840d6f890d01220345644db163fd07 100644 --- a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h +++ b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.h -@@ -12,6 +12,8 @@ +@@ -11,6 +11,8 @@ + #include "base/metrics/field_trial_params.h" #import "content/app_shim_remote_cocoa/web_contents_view_cocoa.h" - #include "content/common/web_contents_ns_view_bridge.mojom.h" +extern CONTENT_EXPORT const base::FeatureParam<bool> + kEnhancedWindowOcclusionDetection; @@ -31,10 +31,14 @@ index 428902f90950b2e9434c8a624a313268ebb80cd4..afcc3bc481be6a16119f7e2af647276c kDisplaySleepAndAppHideDetection; diff --git a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm -index 32523e6a6f800de3917d18825f94c66ef4ea4388..634d68b9a2840d7c9e7c3b5e23d8b1b8ac02456b 100644 +index a5570988c3721d9f6bd05c402a7658d3af6f2c2c..0a2dba6aa2d48bc39d2a55c8b4d6606744c10ca7 100644 --- a/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm +++ b/content/app_shim_remote_cocoa/web_contents_occlusion_checker_mac.mm -@@ -19,6 +19,12 @@ +@@ -14,9 +14,16 @@ + #include "base/mac/mac_util.h" + #include "base/metrics/field_trial_params.h" + #include "base/no_destructor.h" ++#include "content/common/features.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_client.h" @@ -47,7 +51,7 @@ index 32523e6a6f800de3917d18825f94c66ef4ea4388..634d68b9a2840d7c9e7c3b5e23d8b1b8 namespace { NSString* const kWindowDidChangePositionInWindowList = -@@ -127,7 +133,8 @@ - (void)dealloc { +@@ -125,7 +132,8 @@ - (void)dealloc { - (BOOL)isManualOcclusionDetectionEnabled { return [WebContentsOcclusionCheckerMac @@ -58,10 +62,18 @@ index 32523e6a6f800de3917d18825f94c66ef4ea4388..634d68b9a2840d7c9e7c3b5e23d8b1b8 // Alternative implementation of orderWindow:relativeTo:. Replaces diff --git a/content/app_shim_remote_cocoa/web_contents_view_cocoa.mm b/content/app_shim_remote_cocoa/web_contents_view_cocoa.mm -index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7cef78ca4ee 100644 +index 17d6d7d935f93afefa9123f56ef9c138c3070f93..8dfa7501a6a2998e107bf9b51f5e5c3d52e880bf 100644 --- a/content/app_shim_remote_cocoa/web_contents_view_cocoa.mm +++ b/content/app_shim_remote_cocoa/web_contents_view_cocoa.mm -@@ -29,6 +29,7 @@ +@@ -16,6 +16,7 @@ + #import "content/app_shim_remote_cocoa/web_drag_source_mac.h" + #import "content/browser/web_contents/web_contents_view_mac.h" + #import "content/browser/web_contents/web_drag_dest_mac.h" ++#include "content/common/features.h" + #include "content/public/browser/content_browser_client.h" + #include "content/public/common/content_client.h" + #include "ui/base/clipboard/clipboard_constants.h" +@@ -28,6 +29,7 @@ #include "ui/resources/grit/ui_resources.h" using content::DropData; @@ -69,7 +81,7 @@ index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7ce using remote_cocoa::mojom::DraggingInfo; using remote_cocoa::mojom::SelectionDirection; -@@ -124,12 +125,15 @@ @implementation WebContentsViewCocoa { +@@ -123,17 +125,20 @@ @implementation WebContentsViewCocoa { WebDragSource* __strong _dragSource; NSDragOperation _dragOperation; @@ -78,16 +90,25 @@ index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7ce } + (void)initialize { +- if (![WebContentsOcclusionCheckerMac +- manualOcclusionDetectionSupportedForCurrentMacOSVersion]) { +- return; +- } ++ if (base::FeatureList::IsEnabled(kMacWebContentsOcclusion)) { ++ if (![WebContentsOcclusionCheckerMac ++ manualOcclusionDetectionSupportedForCurrentMacOSVersion]) { ++ return; ++ } + - // Create the WebContentsOcclusionCheckerMac shared instance. - [WebContentsOcclusionCheckerMac sharedInstance]; -+ if (base::FeatureList::IsEnabled(kMacWebContentsOcclusion)) { + // Create the WebContentsOcclusionCheckerMac shared instance. + [WebContentsOcclusionCheckerMac sharedInstance]; + } } - (instancetype)initWithViewsHostableView:(ui::ViewsHostableView*)v { -@@ -440,6 +444,7 @@ - (void)updateWebContentsVisibility: +@@ -444,6 +449,7 @@ - (void)updateWebContentsVisibility: (remote_cocoa::mojom::Visibility)visibility { using remote_cocoa::mojom::Visibility; @@ -95,7 +116,7 @@ index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7ce if (!_host) return; -@@ -485,6 +490,20 @@ - (void)updateWebContentsVisibility { +@@ -489,6 +495,20 @@ - (void)updateWebContentsVisibility { [self updateWebContentsVisibility:visibility]; } @@ -116,7 +137,7 @@ index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7ce - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { // Subviews do not participate in auto layout unless the the size this view // changes. This allows RenderWidgetHostViewMac::SetBounds(..) to select a -@@ -507,11 +526,39 @@ - (void)viewWillMoveToWindow:(NSWindow*)newWindow { +@@ -511,11 +531,39 @@ - (void)viewWillMoveToWindow:(NSWindow*)newWindow { NSWindow* oldWindow = [self window]; @@ -160,7 +181,7 @@ index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7ce } if (newWindow) { -@@ -519,26 +566,66 @@ - (void)viewWillMoveToWindow:(NSWindow*)newWindow { +@@ -523,26 +571,66 @@ - (void)viewWillMoveToWindow:(NSWindow*)newWindow { selector:@selector(windowChangedOcclusionState:) name:NSWindowDidChangeOcclusionStateNotification object:newWindow]; @@ -233,11 +254,11 @@ index d8167e854a3264b19a07544039fd01aba45e27a1..2e5a4ae715529e3b7b5c8fbb7195c7ce } diff --git a/content/common/features.cc b/content/common/features.cc -index c0723c13069f570206ea6b536b1a41a1200e3d48..fe5b95303d6cf06b99889307930252effdea6e0f 100644 +index d9fdcd11f23449e22e17df833140c1f80d503486..18d3c146ec38ada48dc1c32904fe170a0a53a6f2 100644 --- a/content/common/features.cc +++ b/content/common/features.cc -@@ -324,6 +324,14 @@ BASE_FEATURE(kIOSurfaceCapturer, - base::FEATURE_ENABLED_BY_DEFAULT); +@@ -312,6 +312,14 @@ BASE_FEATURE(kInterestGroupUpdateIfOlderThan, base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kIOSurfaceCapturer, base::FEATURE_ENABLED_BY_DEFAULT); #endif +// Feature that controls whether WebContentsOcclusionChecker should handle @@ -249,13 +270,13 @@ index c0723c13069f570206ea6b536b1a41a1200e3d48..fe5b95303d6cf06b99889307930252ef +#endif + // When enabled, child process will not terminate itself when IPC is reset. - BASE_FEATURE(kKeepChildProcessAfterIPCReset, - "KeepChildProcessAfterIPCReset", + BASE_FEATURE(kKeepChildProcessAfterIPCReset, base::FEATURE_DISABLED_BY_DEFAULT); + diff --git a/content/common/features.h b/content/common/features.h -index 93017367d5ef77b00a73d849608a7af16fe44527..394ee07b58a9b6021143b2168b1065350420cfca 100644 +index 5b6d84c51b082bc80e9fd03b79a4ff4704b75eb7..b043a236891cdc83342820a38babf4cfd99b4d40 100644 --- a/content/common/features.h +++ b/content/common/features.h -@@ -101,6 +101,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan); +@@ -112,6 +112,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan); #if BUILDFLAG(IS_MAC) CONTENT_EXPORT BASE_DECLARE_FEATURE(kIOSurfaceCapturer); #endif diff --git a/patches/chromium/revert_partial_remove_unused_prehandlemouseevent.patch b/patches/chromium/revert_partial_remove_unused_prehandlemouseevent.patch new file mode 100644 index 0000000000000..61623bb68826e --- /dev/null +++ b/patches/chromium/revert_partial_remove_unused_prehandlemouseevent.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 <hop2deep@gmail.com> +Date: Mon, 1 Sep 2025 23:31:49 +0900 +Subject: Revert: partial "Remove unused PreHandleMouseEvent" + +Refs https://chromium-review.googlesource.com/c/chromium/src/+/6880411 + +diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc +index 74fea36ea7f9a345b3474ea18be00704831a685e..c75785d5a26fa52a39d1a3552da9a7621e4c8430 100644 +--- a/content/browser/renderer_host/render_widget_host_delegate.cc ++++ b/content/browser/renderer_host/render_widget_host_delegate.cc +@@ -13,6 +13,11 @@ + + namespace content { + ++bool RenderWidgetHostDelegate::PreHandleMouseEvent( ++ const blink::WebMouseEvent& event) { ++ return false; ++} ++ + KeyboardEventProcessingResult RenderWidgetHostDelegate::PreHandleKeyboardEvent( + const input::NativeWebKeyboardEvent& event) { + return KeyboardEventProcessingResult::NOT_HANDLED; +diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h +index bc1bfa1ac381ec94121a264d9dcbae9e02ab5a81..c6fc03ae158b3ce87fd684d765a3f1b0e9f79212 100644 +--- a/content/browser/renderer_host/render_widget_host_delegate.h ++++ b/content/browser/renderer_host/render_widget_host_delegate.h +@@ -103,6 +103,12 @@ class CONTENT_EXPORT RenderWidgetHostDelegate { + virtual void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host, + const gfx::Size& new_size) {} + ++ // Callback to give the browser a chance to handle the specified mouse ++ // event before sending it to the renderer. Returns true if the event was ++ // handled, false otherwise. A true value means no more processing should ++ // happen on the event. The default return value is false. ++ virtual bool PreHandleMouseEvent(const blink::WebMouseEvent& event); ++ + // Callback to give the browser a chance to handle the specified keyboard + // event before sending it to the renderer. See enum for details on return + // value. +diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc +index 2fa9876286ecda6a60a2c1970896cb275bbd7ab9..3f14e59de0e296b17f574aa40b879d2f373bb93e 100644 +--- a/content/browser/renderer_host/render_widget_host_impl.cc ++++ b/content/browser/renderer_host/render_widget_host_impl.cc +@@ -1589,6 +1589,10 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo( + CHECK_GE(mouse_event.GetType(), WebInputEvent::Type::kMouseTypeFirst); + CHECK_LE(mouse_event.GetType(), WebInputEvent::Type::kMouseTypeLast); + ++ if (delegate_ && delegate_->PreHandleMouseEvent(mouse_event)) { ++ return; ++ } ++ + for (auto& mouse_event_callback : mouse_event_callbacks_) { + if (mouse_event_callback.Run(mouse_event)) { + return; +diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc +index 70ce66aeaecb2f34efb7db8a74c63f9f7f8cdbc8..e3769d79b173f758939981b6e58cc97e39cd71c1 100644 +--- a/content/browser/web_contents/web_contents_impl.cc ++++ b/content/browser/web_contents/web_contents_impl.cc +@@ -4448,6 +4448,12 @@ void WebContentsImpl::RenderWidgetWasResized( + width_changed); + } + ++bool WebContentsImpl::PreHandleMouseEvent(const blink::WebMouseEvent& event) { ++ OPTIONAL_TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("content.verbose"), ++ "WebContentsImpl::PreHandleMouseEvent"); ++ return delegate_ ? delegate_->PreHandleMouseEvent(this, event) : false; ++} ++ + void WebContentsImpl::PreHandleDragUpdate(const DropData& drop_data, + const gfx::PointF& client_pt) { + if (delegate_) { +diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h +index 563e943c90c03876dce8846ca32775b8929e569e..af8a1d0dfe51f641db7440f8df7faa9f5e37cf64 100644 +--- a/content/browser/web_contents/web_contents_impl.h ++++ b/content/browser/web_contents/web_contents_impl.h +@@ -1121,6 +1121,7 @@ class CONTENT_EXPORT WebContentsImpl + + double GetPendingZoomLevel(RenderWidgetHostImpl* rwh) override; + ++ bool PreHandleMouseEvent(const blink::WebMouseEvent& event) override; + void PreHandleDragUpdate(const DropData& drop_data, + const gfx::PointF& client_pt); + void PreHandleDragExit(); +diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc +index 923d8834e231b91e7a692e0178ece122b8d70536..bdb490b9f5b76faf2f5ed09812b202fea1c63a73 100644 +--- a/content/public/browser/web_contents_delegate.cc ++++ b/content/public/browser/web_contents_delegate.cc +@@ -127,6 +127,12 @@ bool WebContentsDelegate::HandleContextMenu(RenderFrameHost& render_frame_host, + return false; + } + ++bool WebContentsDelegate::PreHandleMouseEvent( ++ WebContents* source, ++ const blink::WebMouseEvent& event) { ++ return false; ++} ++ + KeyboardEventProcessingResult WebContentsDelegate::PreHandleKeyboardEvent( + WebContents* source, + const input::NativeWebKeyboardEvent& event) { +diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h +index 30d7c81394df4e0f382d9a67fcd414b2d07903db..b92971710565bcf650f47d83d3e6163095b345da 100644 +--- a/content/public/browser/web_contents_delegate.h ++++ b/content/public/browser/web_contents_delegate.h +@@ -323,6 +323,13 @@ class CONTENT_EXPORT WebContentsDelegate { + virtual bool HandleContextMenu(RenderFrameHost& render_frame_host, + const ContextMenuParams& params); + ++ // Allows delegates to handle mouse events before sending to the renderer. ++ // Returns true if the event was handled, false otherwise. A true value means ++ // no more processing should happen on the event. The default return value is ++ // false. ++ virtual bool PreHandleMouseEvent(WebContents* source, ++ const blink::WebMouseEvent& event); ++ + // Allows delegates to handle mouse drag events before sending to the + // renderer. Returns true if the event was handled, false otherwise. A true + // value means no more processing should happen on the event. The default diff --git a/patches/chromium/revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch b/patches/chromium/revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch index 9b65125aef097..b2e7b56240b45 100644 --- a/patches/chromium/revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch +++ b/patches/chromium/revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch @@ -6,10 +6,10 @@ Subject: Revert "Remove the AllowAggressiveThrottlingWithWebSocket feature." This reverts commit 615c1810a187840ffeb04096087efff86edb37de. diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc -index b5dde9f0b46663db5c7cf072cc58e271f83995eb..88a503e23ea4fa787a91a2a7934dc1783264a700 100644 +index 485ae01ebe560b118624706c8ca415e43e1b7d8f..71c95266bd982168c7b1929f0455335574d54169 100644 --- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc +++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc -@@ -101,6 +101,17 @@ enum WebSocketOpCode { +@@ -102,6 +102,17 @@ enum WebSocketOpCode { kOpCodeBinary = 0x2, }; @@ -27,7 +27,7 @@ index b5dde9f0b46663db5c7cf072cc58e271f83995eb..88a503e23ea4fa787a91a2a7934dc178 } // namespace WebSocketChannelImpl::MessageDataDeleter::MessageDataDeleter( -@@ -294,7 +305,10 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) { +@@ -297,7 +308,10 @@ bool WebSocketChannelImpl::Connect(const KURL& url, const String& protocol) { // even if the `WebSocketChannel` is closed. feature_handle_for_scheduler_ = scheduler->RegisterFeature( SchedulingPolicy::Feature::kWebSocket, diff --git a/patches/chromium/revert_views_remove_desktopwindowtreehostwin_window_enlargement.patch b/patches/chromium/revert_views_remove_desktopwindowtreehostwin_window_enlargement.patch index b91614ca15b88..b7a78ce782901 100644 --- a/patches/chromium/revert_views_remove_desktopwindowtreehostwin_window_enlargement.patch +++ b/patches/chromium/revert_views_remove_desktopwindowtreehostwin_window_enlargement.patch @@ -10,10 +10,10 @@ on Windows. We should refactor our code so that this patch isn't necessary. diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json -index 85f5e8902836f91994e9dd4018d1db4d126ffc69..f17308098e72c0087203a18ddd2967cb50b424c1 100644 +index 21026b6a40bbccf616b3a6390bb8359d23470380..c52e49e673616df91b115d39c5c78bcd1d7db7ff 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json -@@ -25240,6 +25240,21 @@ +@@ -25731,6 +25731,21 @@ ] } ], @@ -36,12 +36,12 @@ index 85f5e8902836f91994e9dd4018d1db4d126ffc69..f17308098e72c0087203a18ddd2967cb { "platforms": [ diff --git a/ui/views/views_features.cc b/ui/views/views_features.cc -index 52c03930806efdb180d45bb68d4b6cd72cb8bec7..8307938f271c46b57aeceb6e4faaad88f45add5e 100644 +index 9ecf5330bb9b3a5a7b12f3b9bb76192ea1694d07..202d3e3df60ec8d23b4cbd3e5814c3fce1b07871 100644 --- a/ui/views/views_features.cc +++ b/ui/views/views_features.cc -@@ -31,6 +31,14 @@ BASE_FEATURE(kEnableTouchDragCursorSync, - "EnableTouchDragCursorSync", - base::FEATURE_ENABLED_BY_DEFAULT); +@@ -22,6 +22,14 @@ BASE_FEATURE(kAnnounceTextAdditionalAttributes, + // crbug.com/370856871. + BASE_FEATURE(kEnableTouchDragCursorSync, base::FEATURE_ENABLED_BY_DEFAULT); +// Enables enlargement of HWNDs to a minimum size of 64x64 to handle reported +// graphical glitches on certain hardware. @@ -55,19 +55,19 @@ index 52c03930806efdb180d45bb68d4b6cd72cb8bec7..8307938f271c46b57aeceb6e4faaad88 // to kKeyboardAccessibleTooltip in //ui/base/ui_base_features.cc. BASE_FEATURE(kKeyboardAccessibleTooltipInViews, diff --git a/ui/views/views_features.h b/ui/views/views_features.h -index 58063f2452dc484a97c79b382067d9b34875e344..d586436498263c595a17454f54644d2deb05f308 100644 +index 5f5ea15678bd76399fdbbb8904fe155657f49335..a67c124878fb710599fed5d9714bfa723d0d67a5 100644 --- a/ui/views/views_features.h +++ b/ui/views/views_features.h -@@ -15,6 +15,7 @@ namespace views::features { +@@ -14,6 +14,7 @@ namespace views::features { + // Please keep alphabetized. VIEWS_EXPORT BASE_DECLARE_FEATURE(kAnnounceTextAdditionalAttributes); - VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnablePlatformHighContrastInkDrop); VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableTouchDragCursorSync); +VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableTransparentHwndEnlargement); VIEWS_EXPORT BASE_DECLARE_FEATURE(kKeyboardAccessibleTooltipInViews); + VIEWS_EXPORT BASE_DECLARE_FEATURE(kApplyInitialUrlToWebContents); - } // namespace views::features diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf2700ce34 100644 +index fd23b8036c7f2d8bf3ed1bba126f8ee813f688a8..392de361fe395b81b346abb477d91d495d00ba34 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -84,6 +84,23 @@ namespace { @@ -94,7 +94,7 @@ index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf // Updates the cursor clip region. Used for mouse locking. void UpdateMouseLockRegion(aura::Window* window, bool locked) { if (!locked) { -@@ -333,9 +350,14 @@ bool DesktopWindowTreeHostWin::IsVisible() const { +@@ -329,9 +346,14 @@ bool DesktopWindowTreeHostWin::IsVisible() const { } void DesktopWindowTreeHostWin::SetSize(const gfx::Size& size) { @@ -111,7 +111,7 @@ index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf } void DesktopWindowTreeHostWin::StackAbove(aura::Window* window) { -@@ -350,30 +372,40 @@ void DesktopWindowTreeHostWin::StackAtTop() { +@@ -346,30 +368,40 @@ void DesktopWindowTreeHostWin::StackAtTop() { } void DesktopWindowTreeHostWin::CenterWindow(const gfx::Size& size) { @@ -154,7 +154,7 @@ index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf return display::win::GetScreenWin()->ScreenToDIPRect(GetHWND(), pixel_bounds); } -@@ -682,37 +714,44 @@ void DesktopWindowTreeHostWin::HideImpl() { +@@ -677,37 +709,44 @@ void DesktopWindowTreeHostWin::HideImpl() { // other get/set methods work in DIP. gfx::Rect DesktopWindowTreeHostWin::GetBoundsInPixels() const { @@ -219,7 +219,7 @@ index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf } gfx::Rect -@@ -922,21 +961,29 @@ int DesktopWindowTreeHostWin::GetNonClientComponent( +@@ -917,18 +956,26 @@ int DesktopWindowTreeHostWin::GetNonClientComponent( void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size_px, SkPath* path) { @@ -239,10 +239,7 @@ index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf - if (!path->isEmpty()) { - const float scale = - display::win::GetScreenWin()->GetScaleFactorForHWND(GetHWND()); -- SkScalar sk_scale = SkFloatToScalar(scale); -- SkMatrix matrix; -- matrix.setScale(sk_scale, sk_scale); -- path->transform(matrix); +- *path = path->makeTransform(SkMatrix::Scale(scale, scale)); + if (Widget* widget = GetWidget(); widget && widget->non_client_view()) { + widget->non_client_view()->GetWindowMask( + display::win::GetScreenWin()->ScreenToDIPSize(GetHWND(), @@ -252,22 +249,19 @@ index 54a94e1348fa196eaee8314076c47286c9ab0bcc..ed4d2c4d849085c0e7830c5d52d47daf + if (!path->isEmpty()) { + const float scale = + display::win::GetScreenWin()->GetScaleFactorForHWND(GetHWND()); -+ SkScalar sk_scale = SkFloatToScalar(scale); -+ SkMatrix matrix; -+ matrix.setScale(sk_scale, sk_scale); -+ path->transform(matrix); ++ *path = path->makeTransform(SkMatrix::Scale(scale, scale)); + } + } else if (!window_enlargement_.IsZero()) { -+ path->addRect(SkRect::MakeXYWH(0, 0, adjusted_size_in_px.width(), -+ adjusted_size_in_px.height())); ++ *path = SkPath::Rect(SkRect::MakeXYWH(0, 0, adjusted_size_in_px.width(), ++ adjusted_size_in_px.height())); } } diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h -index 13cfa18bf406f244ec361a1230ccce440ad9785a..d8be4dffee3947e7ac6dc09cb8e1f2a6a834789b 100644 +index e8acd2828ed05deefa335ce2bb461f0c3be8d7b7..0cd07fd5fb55dcc0d972de4c027fcb895d156592 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h -@@ -176,7 +176,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin +@@ -175,7 +175,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin void ShowImpl() override; void HideImpl() override; gfx::Rect GetBoundsInPixels() const override; diff --git a/patches/chromium/scroll_bounce_flag.patch b/patches/chromium/scroll_bounce_flag.patch index ceb2f66520567..9c76c29f9ce59 100644 --- a/patches/chromium/scroll_bounce_flag.patch +++ b/patches/chromium/scroll_bounce_flag.patch @@ -6,10 +6,10 @@ Subject: scroll_bounce_flag.patch Patch to make scrollBounce option work. diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc -index 69e4b789138ae4de83d93e177e1e5ef02d3246bc..038980cc833e17ee1b0383e92d190c4d92d880c8 100644 +index 90ba3ac24eaeb4897f410b1a787852f003e56d88..b1294e12137254dea7618907aa03f9f7bedda13b 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc -@@ -1261,7 +1261,7 @@ bool RenderThreadImpl::IsLcdTextEnabled() { +@@ -1212,7 +1212,7 @@ bool RenderThreadImpl::IsLcdTextEnabled() { } bool RenderThreadImpl::IsElasticOverscrollEnabled() { diff --git a/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch b/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch index a37e6eff5454d..5a3c799fb425b 100644 --- a/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch +++ b/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch @@ -15,7 +15,7 @@ short-circuit all the permissions checks in MSDC for now to allow us to unduplicate this code. diff --git a/components/webrtc/media_stream_devices_controller.cc b/components/webrtc/media_stream_devices_controller.cc -index 50b665fea15c81326ea7610c66ecad970bc5b261..99c34a259786176c24c67cf91aa528ce88a6e58d 100644 +index 0e528c5356f333f1397e569d0403c6c121f1b175..3c1ca4e67547118ebf2ec1ddf3847c741f2d00f3 100644 --- a/components/webrtc/media_stream_devices_controller.cc +++ b/components/webrtc/media_stream_devices_controller.cc @@ -57,7 +57,8 @@ bool PermissionIsRequested(blink::PermissionType permission, @@ -37,7 +37,7 @@ index 50b665fea15c81326ea7610c66ecad970bc5b261..99c34a259786176c24c67cf91aa528ce content::PermissionController* permission_controller = web_contents->GetBrowserContext()->GetPermissionController(); -@@ -174,19 +175,26 @@ void MediaStreamDevicesController::RequestPermissions( +@@ -174,19 +175,31 @@ void MediaStreamDevicesController::RequestPermissions( requested_audio_capture_device_ids; permission_request_description.requested_video_capture_device_ids = requested_video_capture_device_ids; @@ -56,8 +56,13 @@ index 50b665fea15c81326ea7610c66ecad970bc5b261..99c34a259786176c24c67cf91aa528ce - &MediaStreamDevicesController::PromptAnsweredGroupedRequest, - std::move(controller))); + if (previously_approved) { -+ controller->PromptAnsweredGroupedRequest({blink::mojom::PermissionStatus::GRANTED /*audio*/, -+ blink::mojom::PermissionStatus::GRANTED /*video*/}); ++ controller->PromptAnsweredGroupedRequest( ++ {content::PermissionResult( ++ content::PermissionStatus::GRANTED /*audio*/, ++ content::PermissionStatusSource::UNSPECIFIED), ++ content::PermissionResult( ++ content::PermissionStatus::GRANTED /*video*/, ++ content::PermissionStatusSource::UNSPECIFIED)}); + } else { + rfh->GetBrowserContext() + ->GetPermissionController() @@ -72,7 +77,7 @@ index 50b665fea15c81326ea7610c66ecad970bc5b261..99c34a259786176c24c67cf91aa528ce } MediaStreamDevicesController::~MediaStreamDevicesController() { -@@ -436,6 +444,7 @@ bool MediaStreamDevicesController::PermissionIsBlockedForReason( +@@ -436,6 +449,7 @@ bool MediaStreamDevicesController::PermissionIsBlockedForReason( return false; } @@ -80,7 +85,7 @@ index 50b665fea15c81326ea7610c66ecad970bc5b261..99c34a259786176c24c67cf91aa528ce // TODO(raymes): This function wouldn't be needed if // PermissionManager::RequestPermissions returned a denial reason. content::PermissionResult result = -@@ -449,6 +458,7 @@ bool MediaStreamDevicesController::PermissionIsBlockedForReason( +@@ -449,6 +463,7 @@ bool MediaStreamDevicesController::PermissionIsBlockedForReason( DCHECK_EQ(blink::mojom::PermissionStatus::DENIED, result.status); return true; } @@ -89,10 +94,10 @@ index 50b665fea15c81326ea7610c66ecad970bc5b261..99c34a259786176c24c67cf91aa528ce } diff --git a/components/webrtc/media_stream_devices_controller.h b/components/webrtc/media_stream_devices_controller.h -index a976526aedc2107dd43242199b04142ca4d34eda..0410c8818d6ffdd55c49f1bef27ddb4ea16d8ab9 100644 +index 5e46e66f51994d3eef3b19ee57b37e6cf32658e8..d01403717a0df2c18b3d88495d9a4f85f242693a 100644 --- a/components/webrtc/media_stream_devices_controller.h +++ b/components/webrtc/media_stream_devices_controller.h -@@ -49,7 +49,8 @@ class MediaStreamDevicesController { +@@ -50,7 +50,8 @@ class MediaStreamDevicesController { // synchronously or asynchronously returned via |callback|. static void RequestPermissions(const content::MediaStreamRequest& request, MediaStreamDeviceEnumerator* enumerator, diff --git a/patches/chromium/support_mixed_sandbox_with_zygote.patch b/patches/chromium/support_mixed_sandbox_with_zygote.patch index a14d76dffbd1d..5c932ada0228c 100644 --- a/patches/chromium/support_mixed_sandbox_with_zygote.patch +++ b/patches/chromium/support_mixed_sandbox_with_zygote.patch @@ -22,10 +22,10 @@ However, the patch would need to be reviewed by the security team, as it does touch a security-sensitive class. diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc -index c20d6b898f517856efb01e9f504a9dfa967fa3c3..95b4a649055e03ef7822a33347ed904ac7d64695 100644 +index 1aabeee15e34c31a2ceeb3584c934abbb3b0e01b..ede92bd9fd24f5d1950e36a2204b8427b61c5451 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc -@@ -1833,6 +1833,10 @@ bool RenderProcessHostImpl::Init() { +@@ -1938,6 +1938,10 @@ bool RenderProcessHostImpl::Init() { std::unique_ptr<SandboxedProcessLauncherDelegate> sandbox_delegate = std::make_unique<RendererSandboxedProcessLauncherDelegateWin>( *cmd_line, IsPdf(), IsJitDisabled()); @@ -37,7 +37,7 @@ index c20d6b898f517856efb01e9f504a9dfa967fa3c3..95b4a649055e03ef7822a33347ed904a std::unique_ptr<SandboxedProcessLauncherDelegate> sandbox_delegate = std::make_unique<RendererSandboxedProcessLauncherDelegate>(); diff --git a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc -index 33c2fb1dde3cc92383c085fc1277c71ccfffedc0..033a3692e59e9a220a635462542f4f34e7a14f26 100644 +index 0936beb23188f0d07cd5750f3a2e56dc560fdef2..996eab5dae4ffa6b7898cc070de8162ad2130d70 100644 --- a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc +++ b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc @@ -35,6 +35,9 @@ namespace content { @@ -50,7 +50,7 @@ index 33c2fb1dde3cc92383c085fc1277c71ccfffedc0..033a3692e59e9a220a635462542f4f34 const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); base::CommandLine::StringType renderer_prefix = -@@ -73,6 +76,9 @@ RendererSandboxedProcessLauncherDelegateWin:: +@@ -71,6 +74,9 @@ RendererSandboxedProcessLauncherDelegateWin:: ->ShouldRestrictCoreSharingOnRenderer()) { // PDF renderers must be jitless. CHECK(!is_pdf_renderer || is_jit_disabled); @@ -61,7 +61,7 @@ index 33c2fb1dde3cc92383c085fc1277c71ccfffedc0..033a3692e59e9a220a635462542f4f34 dynamic_code_can_be_disabled_ = true; return; diff --git a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h -index 85e9366a5bb28da302e475c99feb59863890ca09..ce29836e57dc72e0719998e1fa8734fd256e5633 100644 +index b98b23a95003c3e3dd7b2da6a48b956cdbeb5251..0597eca8efa2bea2cb800c6919b59dfb64c87083 100644 --- a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h +++ b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h @@ -18,6 +18,11 @@ class CONTENT_EXPORT RendererSandboxedProcessLauncherDelegate diff --git a/patches/chromium/web_contents.patch b/patches/chromium/web_contents.patch index 4e71f8a943f20..e8be63cad2724 100644 --- a/patches/chromium/web_contents.patch +++ b/patches/chromium/web_contents.patch @@ -9,10 +9,10 @@ is needed for OSR. Originally landed in https://github.com/electron/libchromiumcontent/pull/226. diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index c9472325e55052ead090c55704b590bb6722c429..fbf58cc058ee37aab227a632c5f4caf8c4cd6620 100644 +index f2f80c86e7910cf513aa916a80c51502bb186f58..0c6c8b099036f2945872632d6d78343eab442570 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -4160,6 +4160,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, +@@ -4179,6 +4179,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, params.main_frame_name, GetOpener(), primary_main_frame_policy, base::UnguessableToken::Create()); @@ -26,7 +26,7 @@ index c9472325e55052ead090c55704b590bb6722c429..fbf58cc058ee37aab227a632c5f4caf8 std::unique_ptr<WebContentsViewDelegate> delegate = GetContentClient()->browser()->GetWebContentsViewDelegate(this); -@@ -4170,6 +4177,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, +@@ -4189,6 +4196,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, view_ = CreateWebContentsView(this, std::move(delegate), &render_view_host_delegate_view_); } @@ -35,10 +35,10 @@ index c9472325e55052ead090c55704b590bb6722c429..fbf58cc058ee37aab227a632c5f4caf8 CHECK(view_.get()); diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h -index f196deb55065a6016ceabbdb8d165eb9f15add74..53bf8f0368f33926a4d2e7f945db7f871558647f 100644 +index fc95615d2f09678fc9cbd32c777d04b66e259047..d7e026c481b6de4bcf33c0ab48f2b0a27ed7a9fa 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h -@@ -125,11 +125,14 @@ class PrerenderHandle; +@@ -129,11 +129,14 @@ class PrerenderHandle; class RenderFrameHost; class RenderViewHost; class RenderWidgetHost; @@ -52,8 +52,8 @@ index f196deb55065a6016ceabbdb8d165eb9f15add74..53bf8f0368f33926a4d2e7f945db7f87 +class WebContentsView; class WebUI; struct DropData; - struct MHTMLGenerationParams; -@@ -283,6 +286,10 @@ class WebContents : public PageNavigator, public base::SupportsUserData { + struct GlobalRenderFrameHostId; +@@ -291,6 +294,10 @@ class WebContents : public PageNavigator, public base::SupportsUserData { network::mojom::WebSandboxFlags starting_sandbox_flags = network::mojom::WebSandboxFlags::kNone; diff --git a/patches/chromium/webview_fullscreen.patch b/patches/chromium/webview_fullscreen.patch index fe95d84fbf7df..277ede025fd48 100644 --- a/patches/chromium/webview_fullscreen.patch +++ b/patches/chromium/webview_fullscreen.patch @@ -15,10 +15,10 @@ Note that we also need to manually update embedder's `api::WebContents::IsFullscreenForTabOrPending` value. diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc -index 4f8e3a08890ed7498b29a900ccf4bbda5f9cb494..bfce01f531d30cabe5fc33d258652597922a1de8 100644 +index 772cff9b1a9a061645f2220fdc3003627679ac58..9fbc1891a2298c04a461bc717c2431eef415aa72 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc -@@ -8925,6 +8925,17 @@ void RenderFrameHostImpl::EnterFullscreen( +@@ -9001,6 +9001,17 @@ void RenderFrameHostImpl::EnterFullscreen( } } @@ -34,13 +34,13 @@ index 4f8e3a08890ed7498b29a900ccf4bbda5f9cb494..bfce01f531d30cabe5fc33d258652597 + } + // Focus the window if another frame may have delegated the capability. - if (had_fullscreen_token && !GetView()->HasFocus()) + if (had_fullscreen_token && !GetView()->HasFocus()) { GetView()->Focus(); diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index fbf58cc058ee37aab227a632c5f4caf8c4cd6620..0a6a205f49d7bc853879ac4919868aadd6fdd42f 100644 +index 0c6c8b099036f2945872632d6d78343eab442570..075ea7cd9f097b60adcad2857cf7115deb3741bc 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -4449,21 +4449,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent( +@@ -4465,21 +4465,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent( const input::NativeWebKeyboardEvent& event) { OPTIONAL_TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("content.verbose"), "WebContentsImpl::PreHandleKeyboardEvent"); @@ -80,7 +80,7 @@ index fbf58cc058ee37aab227a632c5f4caf8c4cd6620..0a6a205f49d7bc853879ac4919868aad } bool WebContentsImpl::HandleMouseEvent(const blink::WebMouseEvent& event) { -@@ -4622,7 +4626,7 @@ void WebContentsImpl::EnterFullscreenMode( +@@ -4638,7 +4642,7 @@ void WebContentsImpl::EnterFullscreenMode( OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::EnterFullscreenMode"); DCHECK(CanEnterFullscreenMode(requesting_frame)); DCHECK(requesting_frame->IsActive()); @@ -90,7 +90,7 @@ index fbf58cc058ee37aab227a632c5f4caf8c4cd6620..0a6a205f49d7bc853879ac4919868aad // inactive when sites request fullscreen via capability delegation, consume // transient activation from a gesture made before another window was focused, diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc -index 4bfea29fb8bcdf8af69fa686d1474c3530e2d3f9..d4d5f89452f0199c8833cb5f644fa4e85bec1660 100644 +index 6298158d9b007fb33ccc6551d3caad0e596d8f59..f0c4093742c1ade422b73f0d7d335311522506fe 100644 --- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc +++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc @@ -105,7 +105,6 @@ void FullscreenElementChanged(Document& document, diff --git a/patches/chromium/worker_context_will_destroy.patch b/patches/chromium/worker_context_will_destroy.patch index fb09a140de830..515cb275191e4 100644 --- a/patches/chromium/worker_context_will_destroy.patch +++ b/patches/chromium/worker_context_will_destroy.patch @@ -10,10 +10,10 @@ An attempt to upstream this was made, but rejected: https://chromium-review.googlesource.com/c/chromium/src/+/1954347 diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h -index d794a461eedde1003c72f47af0517249ab20806d..6d2033d2023a7c4c936933a050d2372cf490eb44 100644 +index d63a25362fbfa35677de03fd09da535780feb1c9..c2fa875848478bca9115fc94271fde920e6b62fa 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h -@@ -428,6 +428,11 @@ class CONTENT_EXPORT ContentRendererClient { +@@ -419,6 +419,11 @@ class CONTENT_EXPORT ContentRendererClient { virtual void DidInitializeWorkerContextOnWorkerThread( v8::Local<v8::Context> context) {} @@ -26,7 +26,7 @@ index d794a461eedde1003c72f47af0517249ab20806d..6d2033d2023a7c4c936933a050d2372c // An empty URL is returned if the URL is not overriden. virtual GURL OverrideFlashEmbedWithHTML(const GURL& url); diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc -index 74ae1472a2134efcab4f3b258911b39a8e8ed27a..c74f99805cea8c939a5278d120fd348df7a94d32 100644 +index 7a3bdc05630d997824bb6ea46fe3ad911746ca73..eb5550609ec1361cafa1770dda2a3433336a71c1 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc @@ -903,6 +903,12 @@ void RendererBlinkPlatformImpl::WillStopWorkerThread() { @@ -43,10 +43,10 @@ index 74ae1472a2134efcab4f3b258911b39a8e8ed27a..c74f99805cea8c939a5278d120fd348d const v8::Local<v8::Context>& worker) { GetContentClient()->renderer()->DidInitializeWorkerContextOnWorkerThread( diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h -index c2c2b533e42cfcc8c3ecdde1ab6ed9bc2a353b5e..b2238f512b30e64399a901a3c9f430e5be54c27c 100644 +index e6180f6f86163130a63a2dd057799b54379efd4e..f53a619169a5cc82b7ae8ac13c4263ddcd432369 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h -@@ -200,6 +200,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { +@@ -206,6 +206,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { void DidStartWorkerThread() override; void WillStopWorkerThread() override; void WorkerContextCreated(const v8::Local<v8::Context>& worker) override; @@ -55,10 +55,10 @@ index c2c2b533e42cfcc8c3ecdde1ab6ed9bc2a353b5e..b2238f512b30e64399a901a3c9f430e5 const blink::WebSecurityOrigin& script_origin) override; blink::ProtocolHandlerSecurityLevel GetProtocolHandlerSecurityLevel( diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h -index 87aebe19abd4690ace9d524364ef32a34afd3592..e33318c3e673741a05083cf064152e24ff39ca02 100644 +index d182d973c5ae089b5c7919427c4bc822ef742d69..21da7570508b6929b8dd57957454d280119f7463 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h -@@ -673,6 +673,7 @@ class BLINK_PLATFORM_EXPORT Platform { +@@ -674,6 +674,7 @@ class BLINK_PLATFORM_EXPORT Platform { virtual void DidStartWorkerThread() {} virtual void WillStopWorkerThread() {} virtual void WorkerContextCreated(const v8::Local<v8::Context>& worker) {} @@ -67,10 +67,10 @@ index 87aebe19abd4690ace9d524364ef32a34afd3592..e33318c3e673741a05083cf064152e24 const WebSecurityOrigin& script_origin) { return false; diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc -index 8aaf3c12144273bb35bba3e77e0fd505282213df..a6eab67460b49b4594440be2f6e41f852b201e12 100644 +index 0660054931e295abafb420ce567f6b45d9af39d6..bea00fa0a9faaa0c0e7fa5b444c1e485d1e883d1 100644 --- a/third_party/blink/renderer/core/workers/worker_thread.cc +++ b/third_party/blink/renderer/core/workers/worker_thread.cc -@@ -823,6 +823,12 @@ void WorkerThread::PrepareForShutdownOnWorkerThread() { +@@ -824,6 +824,12 @@ void WorkerThread::PrepareForShutdownOnWorkerThread() { } pause_handle_.reset(); diff --git a/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch b/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch index 04770e62499e9..6b2cce880a9e6 100644 --- a/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch +++ b/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch @@ -19,10 +19,10 @@ that clearly establishes the worker script is ready for evaluation with the scop initialized. diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h -index 6d2033d2023a7c4c936933a050d2372cf490eb44..79d59c3f4d3d2d5ff39bd65ded489183247656a8 100644 +index c2fa875848478bca9115fc94271fde920e6b62fa..6fa11f89ea212eabd7fdc979d2d99138b1f3c88e 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h -@@ -428,6 +428,11 @@ class CONTENT_EXPORT ContentRendererClient { +@@ -419,6 +419,11 @@ class CONTENT_EXPORT ContentRendererClient { virtual void DidInitializeWorkerContextOnWorkerThread( v8::Local<v8::Context> context) {} @@ -35,7 +35,7 @@ index 6d2033d2023a7c4c936933a050d2372cf490eb44..79d59c3f4d3d2d5ff39bd65ded489183 // from the worker thread. virtual void WillDestroyWorkerContextOnWorkerThread( diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc -index c74f99805cea8c939a5278d120fd348df7a94d32..a1e92922c11cb995e8814ca693332a9c075ca012 100644 +index eb5550609ec1361cafa1770dda2a3433336a71c1..87d3968badf815da3e2e6642f6c50d4676b1e439 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc @@ -915,6 +915,12 @@ void RendererBlinkPlatformImpl::WorkerContextCreated( @@ -52,10 +52,10 @@ index c74f99805cea8c939a5278d120fd348df7a94d32..a1e92922c11cb995e8814ca693332a9c const blink::WebSecurityOrigin& script_origin) { return GetContentClient()->renderer()->AllowScriptExtensionForServiceWorker( diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h -index b2238f512b30e64399a901a3c9f430e5be54c27c..6231d97d52de2245c6f9396d9769554fd590c128 100644 +index f53a619169a5cc82b7ae8ac13c4263ddcd432369..586167d5984d0163f17e3bbacca34f51ae48e8d5 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h -@@ -200,6 +200,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { +@@ -206,6 +206,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { void DidStartWorkerThread() override; void WillStopWorkerThread() override; void WorkerContextCreated(const v8::Local<v8::Context>& worker) override; @@ -65,10 +65,10 @@ index b2238f512b30e64399a901a3c9f430e5be54c27c..6231d97d52de2245c6f9396d9769554f bool AllowScriptExtensionForServiceWorker( const blink::WebSecurityOrigin& script_origin) override; diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h -index e33318c3e673741a05083cf064152e24ff39ca02..a5a13ad4724aec8b5c471fd81995cf19c3ff7086 100644 +index 21da7570508b6929b8dd57957454d280119f7463..459ea5c34c3c09099f064fff2684de1228658739 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h -@@ -673,6 +673,8 @@ class BLINK_PLATFORM_EXPORT Platform { +@@ -674,6 +674,8 @@ class BLINK_PLATFORM_EXPORT Platform { virtual void DidStartWorkerThread() {} virtual void WillStopWorkerThread() {} virtual void WorkerContextCreated(const v8::Local<v8::Context>& worker) {} diff --git a/patches/config.json b/patches/config.json index 8d297c0fd3e66..e16ddfda0eaa0 100644 --- a/patches/config.json +++ b/patches/config.json @@ -8,7 +8,6 @@ { "patch_dir": "src/electron/patches/nan", "repo": "src/third_party/nan" }, { "patch_dir": "src/electron/patches/perfetto", "repo": "src/third_party/perfetto" }, { "patch_dir": "src/electron/patches/squirrel.mac", "repo": "src/third_party/squirrel.mac" }, - { "patch_dir": "src/electron/patches/Mantle", "repo": "src/third_party/squirrel.mac/vendor/Mantle" }, { "patch_dir": "src/electron/patches/ReactiveObjC", "repo": "src/third_party/squirrel.mac/vendor/ReactiveObjC" }, { "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" }, { "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" }, diff --git a/patches/devtools_frontend/chore_expose_ui_to_allow_electron_to_set_dock_side.patch b/patches/devtools_frontend/chore_expose_ui_to_allow_electron_to_set_dock_side.patch index 8798d2b26a32e..0c44714b73294 100644 --- a/patches/devtools_frontend/chore_expose_ui_to_allow_electron_to_set_dock_side.patch +++ b/patches/devtools_frontend/chore_expose_ui_to_allow_electron_to_set_dock_side.patch @@ -10,10 +10,10 @@ to handle this without patching, but this is fairly clean for now and no longer patching legacy devtools code. diff --git a/front_end/entrypoints/main/MainImpl.ts b/front_end/entrypoints/main/MainImpl.ts -index d3d9a5f373d324eb3cb234c43915476716912cdb..b0ed5173e52abd4eeed4f069d6960c6b01e5e076 100644 +index ad6c608d8a1caecbffba95bb911abe5639e13449..d9ef6e74d767b1712be1d4ca503c1d21973ba372 100644 --- a/front_end/entrypoints/main/MainImpl.ts +++ b/front_end/entrypoints/main/MainImpl.ts -@@ -733,6 +733,8 @@ export class MainImpl { +@@ -769,6 +769,8 @@ export class MainImpl { globalThis.Main = globalThis.Main || {}; // @ts-expect-error Exported for Tests.js globalThis.Main.Main = MainImpl; diff --git a/patches/nan/.patches b/patches/nan/.patches index 0b1553be338c5..281c837d33824 100644 --- a/patches/nan/.patches +++ b/patches/nan/.patches @@ -1,8 +1,7 @@ -use_new_constructor_for_scriptorigin_when_17_x.patch -fix_define_nan_copyablepersistenttraits_for_v8_12_5.patch -remove_deprecated_v8_isolate_idlenotificationdeadline.patch -remove_several_apis_deprecated_in_version_12_6.patch -apply_allcan_read_write.patch -fix_support_new_variant_of_namedpropertyhandlerconfiguration_and.patch fix_correct_usages_of_v8_returnvalue_void_set_nonempty_for_new.patch -chore_remove_deprecated_functioncallbackinfo_holder.patch +fix_replace_deprecated_get_setprototype.patch +fix_replace_usage_of_removed_writeutf8_with_writeutf8v2.patch +test_use_v8_version_check_instead_of_node_version_check.patch +fix_remove_deprecated_propertycallbackinfo_holder.patch +fix_deprecation_of_v8_context_and_v8_object_api_methods.patch +remove_accesscontrol_enum_for_v8_14_4_59.patch diff --git a/patches/nan/apply_allcan_read_write.patch b/patches/nan/apply_allcan_read_write.patch deleted file mode 100644 index 23f899dd8fa72..0000000000000 --- a/patches/nan/apply_allcan_read_write.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Keeley Hammond <khammond@slack-corp.com> -Date: Thu, 20 Jun 2024 14:42:08 -0700 -Subject: Check for NODE_21_0_MODULE_VERSION - -Refs https://chromium-review.googlesource.com/c/v8/v8/+/5006387 -Should be upstreamed. - -Module version checks are made against 119 since that is the current assigned version -for Electron 28 in https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json. -The version should be updateed to the one assinged for Electron 29 when it is available. - -Steps for upstreaming this patch: - -- Get a new module version assigned for Electron 29 in nodejs/node -- Update NODE_21_0_MODULE_VERSION to the new version number -- Upstream patch to nodejs/nan before Electron 29 is branched - -diff --git a/nan.h b/nan.h -index 9a9112afe0cc94ce58ed3cce9763ace7c160a932..f4865a77e60d5105ed2426037984ddcbfa58bbca 100644 ---- a/nan.h -+++ b/nan.h -@@ -47,6 +47,7 @@ - #define NODE_18_0_MODULE_VERSION 108 - #define NODE_19_0_MODULE_VERSION 111 - #define NODE_20_0_MODULE_VERSION 115 -+#define NODE_21_0_MODULE_VERSION 119 - - #ifdef _MSC_VER - # define NAN_HAS_CPLUSPLUS_11 (_MSC_VER >= 1800) -@@ -2525,7 +2526,9 @@ NAN_DEPRECATED inline void SetAccessor( - , GetterCallback getter - , SetterCallback setter - , v8::Local<v8::Value> data -+#if (NODE_MODULE_VERSION < NODE_21_0_MODULE_VERSION) - , v8::AccessControl settings -+#endif - , v8::PropertyAttribute attribute - , imp::Sig signature) { - HandleScope scope; -@@ -2553,17 +2556,28 @@ NAN_DEPRECATED inline void SetAccessor( - obj->SetInternalField(imp::kDataIndex, data); - } - -+#if (NODE_MODULE_VERSION >= NODE_21_0_MODULE_VERSION) -+ tpl->SetNativeDataProperty( -+ name -+ , getter_ -+ , setter_ -+ , obj -+ , attribute); -+#else - tpl->SetAccessor( - name - , getter_ - , setter_ - , obj -+#if (NODE_MODULE_VERSION < NODE_21_0_MODULE_VERSION) - , settings -+#endif - , attribute - #if (NODE_MODULE_VERSION < NODE_16_0_MODULE_VERSION) - , signature - #endif - ); -+#endif - } - - inline void SetAccessor( -@@ -2572,7 +2586,9 @@ inline void SetAccessor( - , GetterCallback getter - , SetterCallback setter = 0 - , v8::Local<v8::Value> data = v8::Local<v8::Value>() -+#if (NODE_MODULE_VERSION < NODE_21_0_MODULE_VERSION) - , v8::AccessControl settings = v8::DEFAULT -+#endif - , v8::PropertyAttribute attribute = v8::None) { - HandleScope scope; - -@@ -2599,14 +2615,25 @@ inline void SetAccessor( - obj->SetInternalField(imp::kDataIndex, data); - } - -+#if (NODE_MODULE_VERSION >= NODE_21_0_MODULE_VERSION) -+ tpl->SetNativeDataProperty( -+ name -+ , getter_ -+ , setter_ -+ , obj -+ , attribute); -+#else - tpl->SetAccessor( - name - , getter_ - , setter_ - , obj -+#if (NODE_MODULE_VERSION < NODE_21_0_MODULE_VERSION) - , settings -+#endif - , attribute - ); -+#endif - } - - inline bool SetAccessor( -@@ -2642,7 +2669,15 @@ inline bool SetAccessor( - , New<v8::External>(reinterpret_cast<void *>(setter))); - } - --#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION) -+#if (NODE_MODULE_VERSION >= NODE_21_0_MODULE_VERSION) -+ return obj->SetNativeDataProperty( -+ GetCurrentContext() -+ , name -+ , getter_ -+ , setter_ -+ , dataobj -+ , attribute).FromMaybe(false); -+#elif (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION) - return obj->SetAccessor( - GetCurrentContext() - , name -diff --git a/test/js/accessors-test.js b/test/js/accessors-test.js -index e6ad45737e2ac18da3fa936b1de618e7389933bc..025f5b66774c2f5fe0ccb98c91fc714dd916fcb1 100644 ---- a/test/js/accessors-test.js -+++ b/test/js/accessors-test.js -@@ -11,7 +11,7 @@ const test = require('tap').test - , bindings = require('bindings')({ module_root: testRoot, bindings: 'accessors' }); - - test('accessors', function (t) { -- t.plan(7) -+ t.plan(6) - var settergetter = bindings.create() - t.equal(settergetter.prop1, 'this is property 1') - t.ok(settergetter.prop2 === '') -@@ -28,5 +28,4 @@ test('accessors', function (t) { - t.equal(derived.prop1, 'this is property 1') - derived.prop2 = 'setting a new value' - t.equal(derived.prop2, 'setting a new value') -- t.equal(settergetter.prop2, 'setting a new value') - }) diff --git a/patches/nan/chore_remove_deprecated_functioncallbackinfo_holder.patch b/patches/nan/chore_remove_deprecated_functioncallbackinfo_holder.patch deleted file mode 100644 index c6ee275913d23..0000000000000 --- a/patches/nan/chore_remove_deprecated_functioncallbackinfo_holder.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: John Kleinschmidt <jkleinsc@electronjs.org> -Date: Fri, 28 Feb 2025 11:17:01 -0500 -Subject: chore remove deprecated FunctionCallbackInfo Holder - -v8 version 13.5.191 removed the deprecated FunctionCallbackInfo::Holder(). - -Callers are supposed to use FunctionCallbackInfo::This() instead. - -See https://chromium-review.googlesource.com/c/v8/v8/+/6309166 - -diff --git a/nan_callbacks_12_inl.h b/nan_callbacks_12_inl.h -index 1af2459efcf54fa97ff24aaa221892eede6eb0d3..e8505247a5070dba572954ba63bc193c9fd51eb6 100644 ---- a/nan_callbacks_12_inl.h -+++ b/nan_callbacks_12_inl.h -@@ -109,7 +109,14 @@ class FunctionCallbackInfo { - inline v8::Local<v8::Function> Callee() const { return info_.Callee(); } - #endif - inline v8::Local<v8::Value> Data() const { return data_; } -+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION < 13 || \ -+(V8_MAJOR_VERSION == 13 && defined(V8_MINOR_VERSION) && \ -+(V8_MINOR_VERSION < 5 || (V8_MINOR_VERSION == 5 && \ -+defined(V8_BUILD_NUMBER) && V8_BUILD_NUMBER < 191)))) - inline v8::Local<v8::Object> Holder() const { return info_.Holder(); } -+#else -+ inline v8::Local<v8::Object> Holder() const { return info_.This(); } -+#endif - inline bool IsConstructCall() const { return info_.IsConstructCall(); } - inline int Length() const { return info_.Length(); } - inline v8::Local<v8::Value> operator[](int i) const { return info_[i]; } diff --git a/patches/nan/fix_correct_usages_of_v8_returnvalue_void_set_nonempty_for_new.patch b/patches/nan/fix_correct_usages_of_v8_returnvalue_void_set_nonempty_for_new.patch index 5ae158c3ab354..26cb0e8e3473e 100644 --- a/patches/nan/fix_correct_usages_of_v8_returnvalue_void_set_nonempty_for_new.patch +++ b/patches/nan/fix_correct_usages_of_v8_returnvalue_void_set_nonempty_for_new.patch @@ -14,10 +14,10 @@ succeeded or not which was incorrect. This should be upstreamed. diff --git a/test/cpp/indexedinterceptors.cpp b/test/cpp/indexedinterceptors.cpp -index f2cd97ac9c40070c127bf9d682401c33955d6d6a..38f1298c2b44130eca73d9d005d2d7ab5f234926 100644 +index 11f573f15109620c5105f1c212a5555bedd7e246..19b7673ff4c07236b11e1947d805979c21a0876e 100644 --- a/test/cpp/indexedinterceptors.cpp +++ b/test/cpp/indexedinterceptors.cpp -@@ -90,9 +90,9 @@ NAN_INDEX_SETTER(IndexedInterceptor::PropertySetter) { +@@ -91,9 +91,9 @@ NAN_INDEX_SETTER(IndexedInterceptor::PropertySetter) { interceptor->buf , *Nan::Utf8String(value) , sizeof (interceptor->buf)); @@ -27,21 +27,21 @@ index f2cd97ac9c40070c127bf9d682401c33955d6d6a..38f1298c2b44130eca73d9d005d2d7ab - info.GetReturnValue().Set(info.This()); + info.GetReturnValue().Set(True()); } + return Intercepted::Yes(); } - diff --git a/test/cpp/namedinterceptors.cpp b/test/cpp/namedinterceptors.cpp -index 8ab5f47db4b9830dd18c36d1a7cb0fced5925355..ae67f2391906fa0e9a60bc406bde86550965dab9 100644 +index 4d8bf5c56ad888234e789f638859142ec92c0fd8..9f4b3b2000188fbeb53a5ec53969226916bac9da 100644 --- a/test/cpp/namedinterceptors.cpp +++ b/test/cpp/namedinterceptors.cpp -@@ -90,10 +90,8 @@ NAN_PROPERTY_SETTER(NamedInterceptor::PropertySetter) { +@@ -91,9 +91,9 @@ NAN_PROPERTY_SETTER(NamedInterceptor::PropertySetter) { interceptor->buf , *Nan::Utf8String(value) , sizeof (interceptor->buf)); - info.GetReturnValue().Set(info.This()); -- } else { ++ info.GetReturnValue().Set(True()); + } else { - info.GetReturnValue().Set(info.This()); ++ info.GetReturnValue().Set(True()); } -+ info.GetReturnValue().Set(True()); + return Intercepted::Yes(); } - - NAN_PROPERTY_ENUMERATOR(NamedInterceptor::PropertyEnumerator) { diff --git a/patches/nan/fix_define_nan_copyablepersistenttraits_for_v8_12_5.patch b/patches/nan/fix_define_nan_copyablepersistenttraits_for_v8_12_5.patch deleted file mode 100644 index 5479a1e97ff9e..0000000000000 --- a/patches/nan/fix_define_nan_copyablepersistenttraits_for_v8_12_5.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: deepak1556 <hop2deep@gmail.com> -Date: Fri, 12 Apr 2024 22:16:58 +0900 -Subject: fix: define Nan::CopyablePersistentTraits for v8 >= 12.5 - -Refs https://chromium-review.googlesource.com/c/v8/v8/+/5403708 -Should be upstreamed. - -diff --git a/nan.h b/nan.h -index 2a68349448c163fa29af327a03b11678e61f5789..42285328055ddb7c76548258f3c4847d2c278ad6 100644 ---- a/nan.h -+++ b/nan.h -@@ -203,9 +203,11 @@ typedef v8::String::ExternalOneByteStringResource - template<typename T> - class NonCopyablePersistentTraits : - public v8::NonCopyablePersistentTraits<T> {}; -+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION <= 12 && V8_MINOR_VERSION < 5) - template<typename T> - class CopyablePersistentTraits : - public v8::CopyablePersistentTraits<T> {}; -+#endif - - template<typename T> - class PersistentBase : -diff --git a/nan_persistent_12_inl.h b/nan_persistent_12_inl.h -index d9649e867606c6356e393e9964b5607a08ea4e3a..ad89657e204259018f1e3814a864410a0917a915 100644 ---- a/nan_persistent_12_inl.h -+++ b/nan_persistent_12_inl.h -@@ -129,4 +129,15 @@ class Global : public v8::UniquePersistent<T> { - }; - #endif - -+#if defined(V8_MAJOR_VERSION) && ((V8_MAJOR_VERSION >= 12 && V8_MINOR_VERSION >= 5) || V8_MAJOR_VERSION >= 13) -+template<typename T> -+struct CopyablePersistentTraits { -+ typedef v8::Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent; -+ static const bool kResetInDestructor = true; -+ template<typename S, typename M> -+ static inline void Copy(const v8::Persistent<S, M> &source, -+ CopyablePersistent *dest) {} -+}; -+#endif -+ - #endif // NAN_PERSISTENT_12_INL_H_ diff --git a/patches/nan/fix_deprecation_of_v8_context_and_v8_object_api_methods.patch b/patches/nan/fix_deprecation_of_v8_context_and_v8_object_api_methods.patch new file mode 100644 index 0000000000000..e866bbf3f4d6d --- /dev/null +++ b/patches/nan/fix_deprecation_of_v8_context_and_v8_object_api_methods.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt <jkleinsc@electronjs.org> +Date: Thu, 6 Nov 2025 11:47:29 -0500 +Subject: fix deprecation of v8::Context and v8::Object API methods + +ref: https://chromium-review.googlesource.com/c/v8/v8/+/7087956 + +diff --git a/nan.h b/nan.h +index 0f120365630e7e2a37964f09cc129d05c6648c90..20ec9daca6befd0ff2bf7eff6a164d4e47a545aa 100644 +--- a/nan.h ++++ b/nan.h +@@ -823,14 +823,14 @@ inline uv_loop_t* GetCurrentEventLoop() { + inline void* GetInternalFieldPointer( + v8::Local<v8::Object> object + , int index) { +- return object->GetAlignedPointerFromInternalField(index); ++ return object->GetAlignedPointerFromInternalField(index, v8::kEmbedderDataTypeTagDefault); + } + + inline void SetInternalFieldPointer( + v8::Local<v8::Object> object + , int index + , void* value) { +- object->SetAlignedPointerInInternalField(index, value); ++ object->SetAlignedPointerInInternalField(index, value, v8::kEmbedderDataTypeTagDefault); + } + + # define NAN_GC_CALLBACK(name) \ +diff --git a/nan_weak.h b/nan_weak.h +index 7e7ab07b8512dbbcc1f09c498e221032d2cd345f..968ecee9e95b4c841406d900cf177a37564561d5 100644 +--- a/nan_weak.h ++++ b/nan_weak.h +@@ -276,7 +276,7 @@ inline void Persistent<T, M>::SetWeak( + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { +- internal_fields[i] = self->GetAlignedPointerFromInternalField(i); ++ internal_fields[i] = self->GetAlignedPointerFromInternalField(i, v8::kEmbedderDataTypeTagDefault); + } + wcbd = new WeakCallbackInfo<P>( + reinterpret_cast<Persistent<v8::Value>*>(this) +@@ -284,7 +284,7 @@ inline void Persistent<T, M>::SetWeak( + , 0 + , internal_fields[0] + , internal_fields[1]); +- self->SetAlignedPointerInInternalField(0, wcbd); ++ self->SetAlignedPointerInInternalField(0, wcbd, v8::kEmbedderDataTypeTagDefault); + v8::PersistentBase<T>::SetWeak( + static_cast<WeakCallbackInfo<P>*>(0) + , WeakCallbackInfo<P>::template invoketwofield<true> +@@ -314,7 +314,7 @@ inline void Persistent<T, M>::SetWeak( + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { +- internal_fields[i] = self->GetAlignedPointerFromInternalField(i); ++ internal_fields[i] = self->GetAlignedPointerFromInternalField(i, v8::kEmbedderDataTypeTagDefault); + } + wcbd = new WeakCallbackInfo<P>( + reinterpret_cast<Persistent<v8::Value>*>(this) +@@ -322,7 +322,7 @@ inline void Persistent<T, M>::SetWeak( + , 0 + , internal_fields[0] + , internal_fields[1]); +- self->SetAlignedPointerInInternalField(0, wcbd); ++ self->SetAlignedPointerInInternalField(0, wcbd, v8::kEmbedderDataTypeTagDefault); + v8::PersistentBase<T>::SetPhantom( + static_cast<WeakCallbackInfo<P>*>(0) + , WeakCallbackInfo<P>::invoketwofield +@@ -353,7 +353,7 @@ inline void Persistent<T, M>::SetWeak( + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { +- internal_fields[i] = self->GetAlignedPointerFromInternalField(i); ++ internal_fields[i] = self->GetAlignedPointerFromInternalField(i, v8::kEmbedderDataTypeTagDefault); + } + wcbd = new WeakCallbackInfo<P>( + reinterpret_cast<Persistent<v8::Value>*>(this) +@@ -361,7 +361,7 @@ inline void Persistent<T, M>::SetWeak( + , 0 + , internal_fields[0] + , internal_fields[1]); +- self->SetAlignedPointerInInternalField(0, wcbd); ++ self->SetAlignedPointerInInternalField(0, wcbd, v8::kEmbedderDataTypeTagDefault); + v8::PersistentBase<T>::SetPhantom( + WeakCallbackInfo<P>::invoketwofield + , 0 +@@ -389,7 +389,7 @@ inline void Persistent<T, M>::SetWeak( + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { +- internal_fields[i] = self->GetAlignedPointerFromInternalField(i); ++ internal_fields[i] = self->GetAlignedPointerFromInternalField(i, v8::kEmbedderDataTypeTagDefault); + } + wcbd = new WeakCallbackInfo<P>( + reinterpret_cast<Persistent<v8::Value>*>(this) diff --git a/patches/nan/fix_remove_deprecated_propertycallbackinfo_holder.patch b/patches/nan/fix_remove_deprecated_propertycallbackinfo_holder.patch new file mode 100644 index 0000000000000..eae76d8546ad7 --- /dev/null +++ b/patches/nan/fix_remove_deprecated_propertycallbackinfo_holder.patch @@ -0,0 +1,199 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr <shelley.vohr@gmail.com> +Date: Thu, 30 Oct 2025 09:11:54 +0000 +Subject: fix: remove deprecated PropertyCallbackInfo::Holder() + +Removed upstream in https://chromium-review.googlesource.com/c/v8/v8/+/7013355. + +Property interceptors should be migrated to use info.This if they are installed +on the object instance otherwise info.HolderV2 if they are installed on the +prototype chain. + +diff --git a/nan_callbacks_12_inl.h b/nan_callbacks_12_inl.h +index ff3b654de5bcc7a187c4361b9eec26ea4b62a1eb..e40383c095ab329b2e20b7e68ade507788a79fb6 100644 +--- a/nan_callbacks_12_inl.h ++++ b/nan_callbacks_12_inl.h +@@ -160,7 +160,7 @@ class PropertyCallbackInfo { + inline v8::Isolate* GetIsolate() const { return info_.GetIsolate(); } + inline v8::Local<v8::Value> Data() const { return data_; } + inline v8::Local<v8::Object> This() const { return info_.This(); } +- inline v8::Local<v8::Object> Holder() const { return info_.Holder(); } ++ inline v8::Local<v8::Object> Holder() const { return info_.HolderV2(); } + inline ReturnValue<T> GetReturnValue() const { + return ReturnValue<T>(info_.GetReturnValue()); + } +diff --git a/test/cpp/accessors.cpp b/test/cpp/accessors.cpp +index 5848a40920c35680360a9d8b1390e983c6896996..e8506e4727e707ca766fe1b4229272ba18864ae0 100644 +--- a/test/cpp/accessors.cpp ++++ b/test/cpp/accessors.cpp +@@ -159,7 +159,7 @@ NAN_SETTER(SetterGetter::SetProp2) { + + NAN_METHOD(SetterGetter::Log) { + SetterGetter* settergetter = +- ObjectWrap::Unwrap<SetterGetter>(info.Holder()); ++ ObjectWrap::Unwrap<SetterGetter>(info.This()); + + info.GetReturnValue().Set(Nan::New(settergetter->log).ToLocalChecked()); + } +diff --git a/test/cpp/accessors2.cpp b/test/cpp/accessors2.cpp +index f5a2b312ca62256bc43141fad145cd68fc300446..59125d33c19856938907ab4dd28dc60037065a16 100644 +--- a/test/cpp/accessors2.cpp ++++ b/test/cpp/accessors2.cpp +@@ -88,7 +88,7 @@ NAN_METHOD(SetterGetter::New) { + + NAN_GETTER(SetterGetter::GetProp1) { + SetterGetter* settergetter = +- ObjectWrap::Unwrap<SetterGetter>(info.Holder()); ++ ObjectWrap::Unwrap<SetterGetter>(info.This()); + assert(strlen(settergetter->log) < sizeof (settergetter->log)); + strncat( + settergetter->log +@@ -110,7 +110,7 @@ NAN_GETTER(SetterGetter::GetProp1) { + + NAN_GETTER(SetterGetter::GetProp2) { + SetterGetter* settergetter = +- ObjectWrap::Unwrap<SetterGetter>(info.Holder()); ++ ObjectWrap::Unwrap<SetterGetter>(info.This()); + assert(strlen(settergetter->log) < sizeof (settergetter->log)); + strncat( + settergetter->log +@@ -132,7 +132,7 @@ NAN_GETTER(SetterGetter::GetProp2) { + + NAN_SETTER(SetterGetter::SetProp2) { + SetterGetter* settergetter = +- ObjectWrap::Unwrap<SetterGetter>(info.Holder()); ++ ObjectWrap::Unwrap<SetterGetter>(info.This()); + strncpy( + settergetter->prop2 + , *Nan::Utf8String(value) +@@ -157,7 +157,7 @@ NAN_SETTER(SetterGetter::SetProp2) { + + NAN_METHOD(SetterGetter::Log) { + SetterGetter* settergetter = +- ObjectWrap::Unwrap<SetterGetter>(info.Holder()); ++ ObjectWrap::Unwrap<SetterGetter>(info.This()); + + info.GetReturnValue().Set(Nan::New(settergetter->log).ToLocalChecked()); + } +diff --git a/test/cpp/indexedinterceptors.cpp b/test/cpp/indexedinterceptors.cpp +index 19b7673ff4c07236b11e1947d805979c21a0876e..668aa22f00ecc624ea4a66de93d289cdc7aad722 100644 +--- a/test/cpp/indexedinterceptors.cpp ++++ b/test/cpp/indexedinterceptors.cpp +@@ -74,7 +74,7 @@ NAN_METHOD(IndexedInterceptor::New) { + + NAN_INDEX_GETTER(IndexedInterceptor::PropertyGetter) { + IndexedInterceptor* interceptor = +- ObjectWrap::Unwrap<IndexedInterceptor>(info.Holder()); ++ ObjectWrap::Unwrap<IndexedInterceptor>(info.This()); + if (index == 0) { + info.GetReturnValue().Set(Nan::New(interceptor->buf).ToLocalChecked()); + } else { +@@ -85,7 +85,7 @@ NAN_INDEX_GETTER(IndexedInterceptor::PropertyGetter) { + + NAN_INDEX_SETTER(IndexedInterceptor::PropertySetter) { + IndexedInterceptor* interceptor = +- ObjectWrap::Unwrap<IndexedInterceptor>(info.Holder()); ++ ObjectWrap::Unwrap<IndexedInterceptor>(info.This()); + if (index == 0) { + std::strncpy( + interceptor->buf +@@ -107,7 +107,7 @@ NAN_INDEX_ENUMERATOR(IndexedInterceptor::PropertyEnumerator) { + + NAN_INDEX_DELETER(IndexedInterceptor::PropertyDeleter) { + IndexedInterceptor* interceptor = +- ObjectWrap::Unwrap<IndexedInterceptor>(info.Holder()); ++ ObjectWrap::Unwrap<IndexedInterceptor>(info.This()); + std::strncpy(interceptor->buf, "goober", sizeof (interceptor->buf)); + info.GetReturnValue().Set(True()); + return Intercepted::Yes(); +diff --git a/test/cpp/methodswithdata.cpp b/test/cpp/methodswithdata.cpp +index 8a908e3246f1efd77290597e500185010293c473..a1ac03c891c14bcd96c139514866acc4c2bd393c 100644 +--- a/test/cpp/methodswithdata.cpp ++++ b/test/cpp/methodswithdata.cpp +@@ -150,7 +150,7 @@ NAN_SETTER(SetterGetter::SetProp2) { + + NAN_METHOD(SetterGetter::Log) { + SetterGetter* settergetter = +- ObjectWrap::Unwrap<SetterGetter>(info.Holder()); ++ ObjectWrap::Unwrap<SetterGetter>(info.This()); + + info.GetReturnValue().Set(Nan::New(settergetter->log).ToLocalChecked()); + } +diff --git a/test/cpp/namedinterceptors.cpp b/test/cpp/namedinterceptors.cpp +index 9f4b3b2000188fbeb53a5ec53969226916bac9da..d0761e5880d91792470ae4fecd0b5dfd3770bfef 100644 +--- a/test/cpp/namedinterceptors.cpp ++++ b/test/cpp/namedinterceptors.cpp +@@ -74,7 +74,7 @@ NAN_METHOD(NamedInterceptor::New) { + + NAN_PROPERTY_GETTER(NamedInterceptor::PropertyGetter) { + NamedInterceptor* interceptor = +- ObjectWrap::Unwrap<NamedInterceptor>(info.Holder()); ++ ObjectWrap::Unwrap<NamedInterceptor>(info.This()); + if (!std::strcmp(*Nan::Utf8String(property), "prop")) { + info.GetReturnValue().Set(Nan::New(interceptor->buf).ToLocalChecked()); + } else { +@@ -85,7 +85,7 @@ NAN_PROPERTY_GETTER(NamedInterceptor::PropertyGetter) { + + NAN_PROPERTY_SETTER(NamedInterceptor::PropertySetter) { + NamedInterceptor* interceptor = +- ObjectWrap::Unwrap<NamedInterceptor>(info.Holder()); ++ ObjectWrap::Unwrap<NamedInterceptor>(info.This()); + if (!std::strcmp(*Nan::Utf8String(property), "prop")) { + std::strncpy( + interceptor->buf +@@ -106,7 +106,7 @@ NAN_PROPERTY_ENUMERATOR(NamedInterceptor::PropertyEnumerator) { + + NAN_PROPERTY_DELETER(NamedInterceptor::PropertyDeleter) { + NamedInterceptor* interceptor = +- ObjectWrap::Unwrap<NamedInterceptor>(info.Holder()); ++ ObjectWrap::Unwrap<NamedInterceptor>(info.This()); + std::strncpy(interceptor->buf, "goober", sizeof (interceptor->buf)); + info.GetReturnValue().Set(True()); + return Intercepted::Yes(); +diff --git a/test/cpp/objectwraphandle.cpp b/test/cpp/objectwraphandle.cpp +index ac4f79aa256c82d2a8b64fa5a0d44d5c2ebbd9c7..64dd9e7ad95d1f37a6223dfd8e385b9d122ba3bc 100644 +--- a/test/cpp/objectwraphandle.cpp ++++ b/test/cpp/objectwraphandle.cpp +@@ -47,17 +47,17 @@ class MyObject : public ObjectWrap { + } + + static NAN_METHOD(GetHandle) { +- MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder()); ++ MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.This()); + info.GetReturnValue().Set(obj->handle()); + } + + static NAN_METHOD(GetHandleConst) { +- MyObject const *obj = ObjectWrap::Unwrap<MyObject>(info.Holder()); ++ MyObject const *obj = ObjectWrap::Unwrap<MyObject>(info.This()); + info.GetReturnValue().Set(obj->handle()); + } + + static NAN_METHOD(GetValue) { +- MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder()); ++ MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.This()); + info.GetReturnValue().Set(obj->value_); + } + +diff --git a/test/cpp/wrappedobjectfactory.cpp b/test/cpp/wrappedobjectfactory.cpp +index 9930a5f12913f703391e3d183b56a37569c60887..ec3955e496ed623966c83b5a5b661103892622fd 100644 +--- a/test/cpp/wrappedobjectfactory.cpp ++++ b/test/cpp/wrappedobjectfactory.cpp +@@ -49,7 +49,7 @@ class InnerObject : public ObjectWrap { + } + + static NAN_METHOD(GetValue) { +- InnerObject* obj = ObjectWrap::Unwrap<InnerObject>(info.Holder()); ++ InnerObject* obj = ObjectWrap::Unwrap<InnerObject>(info.This()); + info.GetReturnValue().Set(obj->value_); + } + +@@ -102,7 +102,7 @@ class MyObject : public ObjectWrap { + } + + static NAN_METHOD(GetValue) { +- MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder()); ++ MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.This()); + info.GetReturnValue().Set(obj->value_); + } + diff --git a/patches/nan/fix_replace_deprecated_get_setprototype.patch b/patches/nan/fix_replace_deprecated_get_setprototype.patch new file mode 100644 index 0000000000000..9e0a3a494e72e --- /dev/null +++ b/patches/nan/fix_replace_deprecated_get_setprototype.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Maddock <smaddock@slack-corp.com> +Date: Thu, 9 Oct 2025 23:25:59 -0400 +Subject: fix: replace deprecated Get/SetPrototype + +https://chromium-review.googlesource.com/c/v8/v8/+/6983465 + +Replaces the deprecated usage of SetPrototype. + +diff --git a/nan_maybe_43_inl.h b/nan_maybe_43_inl.h +index f37ce9732d556b58e4b755e1688cfb481ee40b61..8c3362e5d9dfeac385089100bf6414f628a98f33 100644 +--- a/nan_maybe_43_inl.h ++++ b/nan_maybe_43_inl.h +@@ -207,7 +207,7 @@ inline Maybe<bool> SetPrototype( + , v8::Local<v8::Value> prototype) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); +- return obj->SetPrototype(isolate->GetCurrentContext(), prototype); ++ return obj->SetPrototypeV2(isolate->GetCurrentContext(), prototype); + } + + inline MaybeLocal<v8::String> ObjectProtoToString( +diff --git a/nan_maybe_pre_43_inl.h b/nan_maybe_pre_43_inl.h +index 84e2c11c26d5706bf345d347bc405b90bd14607c..4e0cfa183405142aa3013080d0f938dd2d731168 100644 +--- a/nan_maybe_pre_43_inl.h ++++ b/nan_maybe_pre_43_inl.h +@@ -174,7 +174,7 @@ MaybeLocal<v8::Array> GetOwnPropertyNames(v8::Handle<v8::Object> obj) { + inline Maybe<bool> SetPrototype( + v8::Handle<v8::Object> obj + , v8::Handle<v8::Value> prototype) { +- return Just<bool>(obj->SetPrototype(prototype)); ++ return Just<bool>(obj->SetPrototypeV2(prototype)); + } + + inline MaybeLocal<v8::String> ObjectProtoToString( diff --git a/patches/nan/fix_replace_usage_of_removed_writeutf8_with_writeutf8v2.patch b/patches/nan/fix_replace_usage_of_removed_writeutf8_with_writeutf8v2.patch new file mode 100644 index 0000000000000..ff87e083bc9e8 --- /dev/null +++ b/patches/nan/fix_replace_usage_of_removed_writeutf8_with_writeutf8v2.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Sanders <dsanders11@ucsbalum.com> +Date: Tue, 14 Oct 2025 19:55:10 -0700 +Subject: fix: replace usage of removed WriteUtf8 with WriteUtf8V2 + +Refs https://chromium-review.googlesource.com/c/v8/v8/+/6495189 + +diff --git a/nan.h b/nan.h +index f0bfc0c6cc01b97156cb900615ec2df4b70ef5e8..0f120365630e7e2a37964f09cc129d05c6648c90 100644 +--- a/nan.h ++++ b/nan.h +@@ -427,12 +427,18 @@ template<typename P> class WeakCallbackInfo; + + namespace imp { + static const size_t kMaxLength = 0x3fffffff; +- // v8::String::REPLACE_INVALID_UTF8 was introduced +- // in node.js v0.10.29 and v0.8.27. +-#if NODE_MAJOR_VERSION > 0 || \ ++#if V8_MAJOR_VERSION > 13 || \ ++ V8_MAJOR_VERSION == 13 && V8_MINOR_VERSION > 3 || \ ++ V8_MAJOR_VERSION == 13 && V8_MINOR_VERSION == 3 && V8_BUILD_NUMBER >= 16 ++ // v8::String::WriteFlags::kReplaceInvalidUtf8 was introduced in ++ // v8 13.3.16 ++ static const unsigned kReplaceInvalidUtf8 = v8::String::WriteFlags::kReplaceInvalidUtf8; ++#elif NODE_MAJOR_VERSION > 0 || \ + NODE_MINOR_VERSION > 10 || \ + NODE_MINOR_VERSION == 10 && NODE_PATCH_VERSION >= 29 || \ + NODE_MINOR_VERSION == 8 && NODE_PATCH_VERSION >= 27 ++ // v8::String::REPLACE_INVALID_UTF8 was introduced ++ // in node.js v0.10.29 and v0.8.27. + static const unsigned kReplaceInvalidUtf8 = v8::String::REPLACE_INVALID_UTF8; + #else + static const unsigned kReplaceInvalidUtf8 = 0; +@@ -1167,11 +1173,11 @@ class Utf8String { + str_ = static_cast<char*>(malloc(len)); + assert(str_ != 0); + } +- const int flags = +- v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8; + #if NODE_MAJOR_VERSION >= 11 +- length_ = string->WriteUtf8(v8::Isolate::GetCurrent(), str_, +- static_cast<int>(len), 0, flags); ++ length_ = string->WriteUtf8V2(v8::Isolate::GetCurrent(), ++ str_, ++ len, ++ imp::kReplaceInvalidUtf8); + #else + // See https://github.com/nodejs/nan/issues/832. + // Disable the warning as there is no way around it. +@@ -1183,6 +1189,8 @@ class Utf8String { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #endif ++ const int flags = ++ v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8; + length_ = string->WriteUtf8(str_, static_cast<int>(len), 0, flags); + #ifdef __GNUC__ + #pragma GCC diagnostic pop +@@ -1509,9 +1517,10 @@ class Utf8String { + str_ = static_cast<char*>(malloc(len)); + assert(str_ != 0); + } +- const int flags = +- v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8; +- length_ = string->WriteUtf8(str_, static_cast<int>(len), 0, flags); ++ length_ = string->WriteUtf8V2(v8::Isolate::GetCurrent(), ++ str_, ++ len, ++ imp::kReplaceInvalidUtf8); + str_[length_] = '\0'; + } + } diff --git a/patches/nan/fix_support_new_variant_of_namedpropertyhandlerconfiguration_and.patch b/patches/nan/fix_support_new_variant_of_namedpropertyhandlerconfiguration_and.patch deleted file mode 100644 index 688b76a5bf8da..0000000000000 --- a/patches/nan/fix_support_new_variant_of_namedpropertyhandlerconfiguration_and.patch +++ /dev/null @@ -1,220 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard <marshallofsound@electronjs.org> -Date: Fri, 28 Jun 2024 11:45:44 -0700 -Subject: fix: support new variant of NamedPropertyHandlerConfiguration and - IndexedPropertyHandlerConfiguration - -Ref: https://chromium-review.googlesource.com/c/v8/v8/+/5630388 - -This should be upstreamed, the reinterpret_cast is funky but works, but require more review when upstreaming. - -diff --git a/nan_callbacks_12_inl.h b/nan_callbacks_12_inl.h -index bbcde4d65dec73139fee53339f154babd8f83b28..1af2459efcf54fa97ff24aaa221892eede6eb0d3 100644 ---- a/nan_callbacks_12_inl.h -+++ b/nan_callbacks_12_inl.h -@@ -255,7 +255,98 @@ typedef void (*NativeSetter)( - , const v8::PropertyCallbackInfo<void> &); - #endif - --#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION -+#if NODE_MODULE_VERSION > NODE_21_0_MODULE_VERSION -+static -+v8::Intercepted PropertyGetterCallbackWrapper( -+ v8::Local<v8::Name> property -+ , const v8::PropertyCallbackInfo<v8::Value> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Value> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ PropertyGetterCallback callback = reinterpret_cast<PropertyGetterCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kPropertyGetterIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(property.As<v8::String>(), cbinfo); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativePropertyGetter) -+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value> &); -+ -+static -+v8::Intercepted PropertySetterCallbackWrapper( -+ v8::Local<v8::Name> property -+ , v8::Local<v8::Value> value -+ , const v8::PropertyCallbackInfo<void> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<void> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ PropertySetterCallback callback = reinterpret_cast<PropertySetterCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kPropertySetterIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(property.As<v8::String>(), value, *reinterpret_cast<PropertyCallbackInfo<v8::Value>*>(&cbinfo)); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativePropertySetter)( -+ v8::Local<v8::Name> -+ , v8::Local<v8::Value> -+ , const v8::PropertyCallbackInfo<void> &); -+ -+static -+void PropertyEnumeratorCallbackWrapper( -+ const v8::PropertyCallbackInfo<v8::Array> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Array> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ PropertyEnumeratorCallback callback = -+ reinterpret_cast<PropertyEnumeratorCallback>(reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kPropertyEnumeratorIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(cbinfo); -+} -+ -+typedef void (*NativePropertyEnumerator) -+ (const v8::PropertyCallbackInfo<v8::Array> &); -+ -+static -+v8::Intercepted PropertyDeleterCallbackWrapper( -+ v8::Local<v8::Name> property -+ , const v8::PropertyCallbackInfo<v8::Boolean> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Boolean> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ PropertyDeleterCallback callback = reinterpret_cast<PropertyDeleterCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kPropertyDeleterIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(property.As<v8::String>(), cbinfo); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (NativePropertyDeleter) -+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Boolean> &); -+ -+static -+v8::Intercepted PropertyQueryCallbackWrapper( -+ v8::Local<v8::Name> property -+ , const v8::PropertyCallbackInfo<v8::Integer> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Integer> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ PropertyQueryCallback callback = reinterpret_cast<PropertyQueryCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kPropertyQueryIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(property.As<v8::String>(), cbinfo); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativePropertyQuery) -+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Integer> &); -+#elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION - static - void PropertyGetterCallbackWrapper( - v8::Local<v8::Name> property -@@ -431,6 +522,96 @@ typedef void (*NativePropertyQuery) - (v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Integer> &); - #endif - -+#if NODE_MODULE_VERSION > NODE_21_0_MODULE_VERSION -+static -+v8::Intercepted IndexGetterCallbackWrapper( -+ uint32_t index, const v8::PropertyCallbackInfo<v8::Value> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Value> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ IndexGetterCallback callback = reinterpret_cast<IndexGetterCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kIndexPropertyGetterIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(index, cbinfo); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativeIndexGetter) -+ (uint32_t, const v8::PropertyCallbackInfo<v8::Value> &); -+ -+static -+v8::Intercepted IndexSetterCallbackWrapper( -+ uint32_t index -+ , v8::Local<v8::Value> value -+ , const v8::PropertyCallbackInfo<void> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<void> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ IndexSetterCallback callback = reinterpret_cast<IndexSetterCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kIndexPropertySetterIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(index, value, *reinterpret_cast<PropertyCallbackInfo<v8::Value>*>(&cbinfo)); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativeIndexSetter)( -+ uint32_t -+ , v8::Local<v8::Value> -+ , const v8::PropertyCallbackInfo<void> &); -+ -+static -+void IndexEnumeratorCallbackWrapper( -+ const v8::PropertyCallbackInfo<v8::Array> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Array> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ IndexEnumeratorCallback callback = reinterpret_cast<IndexEnumeratorCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField( -+ kIndexPropertyEnumeratorIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(cbinfo); -+} -+ -+typedef void (*NativeIndexEnumerator) -+ (const v8::PropertyCallbackInfo<v8::Array> &); -+ -+static -+v8::Intercepted IndexDeleterCallbackWrapper( -+ uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Boolean> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ IndexDeleterCallback callback = reinterpret_cast<IndexDeleterCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kIndexPropertyDeleterIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(index, cbinfo); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativeIndexDeleter) -+ (uint32_t, const v8::PropertyCallbackInfo<v8::Boolean> &); -+ -+static -+v8::Intercepted IndexQueryCallbackWrapper( -+ uint32_t index, const v8::PropertyCallbackInfo<v8::Integer> &info) { -+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>(); -+ PropertyCallbackInfo<v8::Integer> -+ cbinfo(info, obj->GetInternalField(kDataIndex).As<v8::Value>()); -+ IndexQueryCallback callback = reinterpret_cast<IndexQueryCallback>( -+ reinterpret_cast<intptr_t>( -+ obj->GetInternalField(kIndexPropertyQueryIndex) -+ .As<v8::Value>().As<v8::External>()->Value())); -+ callback(index, cbinfo); -+ return v8::Intercepted::kYes; -+} -+ -+typedef v8::Intercepted (*NativeIndexQuery) -+ (uint32_t, const v8::PropertyCallbackInfo<v8::Integer> &); -+#else - static - void IndexGetterCallbackWrapper( - uint32_t index, const v8::PropertyCallbackInfo<v8::Value> &info) { -@@ -515,6 +696,8 @@ void IndexQueryCallbackWrapper( - - typedef void (*NativeIndexQuery) - (uint32_t, const v8::PropertyCallbackInfo<v8::Integer> &); -+#endif -+ - } // end of namespace imp - - #endif // NAN_CALLBACKS_12_INL_H_ diff --git a/patches/nan/remove_accesscontrol_enum_for_v8_14_4_59.patch b/patches/nan/remove_accesscontrol_enum_for_v8_14_4_59.patch new file mode 100644 index 0000000000000..b03769225ccea --- /dev/null +++ b/patches/nan/remove_accesscontrol_enum_for_v8_14_4_59.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt <jkleinsc@electronjs.org> +Date: Thu, 6 Nov 2025 15:17:50 -0500 +Subject: Remove AccessControl enum for v8 14.4.59 + +xref: [api] Remove deprecated interceptor callback types +and AccessControl enum. + +https://chromium-review.googlesource.com/c/v8/v8/+/7112747 + +diff --git a/nan.h b/nan.h +index 20ec9daca6befd0ff2bf7eff6a164d4e47a545aa..c6187a9e428e744baa2941f4f5a0ed589cdd3440 100644 +--- a/nan.h ++++ b/nan.h +@@ -2596,7 +2596,11 @@ NAN_DEPRECATED inline void SetAccessor( + , GetterCallback getter + , SetterCallback setter + , v8::Local<v8::Value> data ++#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 14 || \ ++ (V8_MAJOR_VERSION == 14 && (!defined(V8_MINOR_VERSION) || V8_MINOR_VERSION < 4)) || \ ++ (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 4 && (!defined(V8_BUILD_NUMBER) || V8_BUILD_NUMBER < 59)) + , v8::AccessControl settings ++#endif + , v8::PropertyAttribute attribute + , imp::Sig signature) { + HandleScope scope; +@@ -2651,7 +2655,11 @@ inline void SetAccessor( + , GetterCallback getter + , SetterCallback setter = 0 + , v8::Local<v8::Value> data = v8::Local<v8::Value>() ++#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 14 || \ ++ (V8_MAJOR_VERSION == 14 && (!defined(V8_MINOR_VERSION) || V8_MINOR_VERSION < 4)) || \ ++ (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 4 && (!defined(V8_BUILD_NUMBER) || V8_BUILD_NUMBER < 59)) + , v8::AccessControl settings = v8::DEFAULT ++#endif + , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + +@@ -2702,7 +2710,11 @@ inline bool SetAccessor( + , GetterCallback getter + , SetterCallback setter = 0 + , v8::Local<v8::Value> data = v8::Local<v8::Value>() ++#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 14 || \ ++ (V8_MAJOR_VERSION == 14 && (!defined(V8_MINOR_VERSION) || V8_MINOR_VERSION < 4)) || \ ++ (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 4 && (!defined(V8_BUILD_NUMBER) || V8_BUILD_NUMBER < 59)) + , v8::AccessControl settings = v8::DEFAULT ++#endif + , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + diff --git a/patches/nan/remove_deprecated_v8_isolate_idlenotificationdeadline.patch b/patches/nan/remove_deprecated_v8_isolate_idlenotificationdeadline.patch deleted file mode 100644 index e8faa2277cf9c..0000000000000 --- a/patches/nan/remove_deprecated_v8_isolate_idlenotificationdeadline.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: John Kleinschmidt <jkleinsc@electronjs.org> -Date: Thu, 6 Jun 2024 15:16:49 -0400 -Subject: Remove deprecated v8::Isolate::IdleNotificationDeadline - -See https://chromium-review.googlesource.com/c/v8/v8/+/5539852 - -Also https://github.com/nodejs/nan/issues/953#issuecomment-1791163429 - -diff --git a/nan.h b/nan.h -index 42285328055ddb7c76548258f3c4847d2c278ad6..9a9112afe0cc94ce58ed3cce9763ace7c160a932 100644 ---- a/nan.h -+++ b/nan.h -@@ -684,7 +684,13 @@ inline uv_loop_t* GetCurrentEventLoop() { - v8::Isolate::GetCurrent()->SetAddHistogramSampleFunction(cb); - } - --#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ -+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 11 || \ -+ (V8_MAJOR_VERSION == 11 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) -+ inline bool IdleNotification(int idle_time_in_ms) { -+ v8::Isolate::GetCurrent()->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate); -+ return true; -+ } -+#elif defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ - (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) - inline bool IdleNotification(int idle_time_in_ms) { - return v8::Isolate::GetCurrent()->IdleNotificationDeadline( diff --git a/patches/nan/remove_several_apis_deprecated_in_version_12_6.patch b/patches/nan/remove_several_apis_deprecated_in_version_12_6.patch deleted file mode 100644 index eb9d213975b94..0000000000000 --- a/patches/nan/remove_several_apis_deprecated_in_version_12_6.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: John Kleinschmidt <jkleinsc@electronjs.org> -Date: Thu, 6 Jun 2024 15:17:39 -0400 -Subject: Remove several APIs deprecated in version 12.6 - -See https://chromium-review.googlesource.com/c/v8/v8/+/5539888 - -ScriptOrigin constructor with isolate has been removed; -Deprecation instructions were to "Use constructor without the isolate." - -diff --git a/nan_scriptorigin.h b/nan_scriptorigin.h -index ce79cdf8dc931d61633c74079a4c38efd3c785ed..85202aaba148540644d39ea2cdf88de0dd101fe4 100644 ---- a/nan_scriptorigin.h -+++ b/nan_scriptorigin.h -@@ -11,7 +11,25 @@ - - class ScriptOrigin : public v8::ScriptOrigin { - public: --#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 9 || \ -+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ -+ (V8_MAJOR_VERSION == 12 && (defined(V8_MINOR_VERSION) && (V8_MINOR_VERSION > 6\ -+ || (V8_MINOR_VERSION == 7 && defined(V8_BUILD_NUMBER) \ -+ && V8_BUILD_NUMBER >= 1))))) -+ explicit ScriptOrigin(v8::Local<v8::Value> name) : -+ v8::ScriptOrigin(name) {} -+ -+ ScriptOrigin(v8::Local<v8::Value> name -+ , v8::Local<v8::Integer> line) : -+ v8::ScriptOrigin(name -+ , To<int32_t>(line).FromMaybe(0)) {} -+ -+ ScriptOrigin(v8::Local<v8::Value> name -+ , v8::Local<v8::Integer> line -+ , v8::Local<v8::Integer> column) : -+ v8::ScriptOrigin(name -+ , To<int32_t>(line).FromMaybe(0) -+ , To<int32_t>(column).FromMaybe(0)) {} -+#elif defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 9 || \ - (V8_MAJOR_VERSION == 9 && (defined(V8_MINOR_VERSION) && (V8_MINOR_VERSION > 0\ - || (V8_MINOR_VERSION == 0 && defined(V8_BUILD_NUMBER) \ - && V8_BUILD_NUMBER >= 1))))) diff --git a/patches/nan/test_use_v8_version_check_instead_of_node_version_check.patch b/patches/nan/test_use_v8_version_check_instead_of_node_version_check.patch new file mode 100644 index 0000000000000..63eea29e2a52a --- /dev/null +++ b/patches/nan/test_use_v8_version_check_instead_of_node_version_check.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Calvin Watford <clavin@electronjs.org> +Date: Mon, 20 Oct 2025 10:04:13 -0600 +Subject: test: use v8 version check instead of node version check + +A few tests use a Node.js version check to determine expected V8 +behavior, but since Electron ships with a different V8 version than +Node.js, this can lead to incorrect test expectations. This change +updates the tests to use the V8 version directly for more accurate +results. + +The existing check was for Node.js version > 22. Node.js v22 ships with +V8 v12.4, and Node.js v23 ships with V8 v12.9. So, the new check uses +V8 version >= 12.9 to match the previous behavior. The actual V8 +behavior change may have occurred somewhere between those versions, so +further work should verify the exact cutoff. + +This patch should be upstreamed. The only additional work is to verify +the V8 version to check against. + +diff --git a/test/js/accessors-test.js b/test/js/accessors-test.js +index 85ff490c0a23277f54ceaeae2f98ceb24f4d5727..21064e1eae8d64c79a0e77a3785945a9b49e60c4 100644 +--- a/test/js/accessors-test.js ++++ b/test/js/accessors-test.js +@@ -9,12 +9,12 @@ + const test = require('tap').test + , testRoot = require('path').resolve(__dirname, '..') + , bindings = require('bindings')({ module_root: testRoot, bindings: 'accessors' }); +-const nodeVersion = parseInt(process.versions.node.split('.')[0]); ++const v8Version = process.versions.v8.split('.').map(parseInt); + + test('accessors', function (t) { + var settergetter = bindings.create() + var derived = Object.create(settergetter) +- if(nodeVersion > 22){ ++ if(v8Version[0] > 12 || (v8Version[0] === 12 && v8Version[1] >= 9)) { + t.plan(9) + t.equal(settergetter.prop1, 'this is property 1') + t.ok(settergetter.prop2 === '') +diff --git a/test/js/methodswithdata-test.js b/test/js/methodswithdata-test.js +index dec024a3d8b6a117d0d0a20ffa13e25088938dc9..8458272def0739c3edc111e6122f676b44e04fd7 100644 +--- a/test/js/methodswithdata-test.js ++++ b/test/js/methodswithdata-test.js +@@ -9,7 +9,7 @@ + const test = require('tap').test + , testRoot = require('path').resolve(__dirname, '..') + , bindings = require('bindings')({ module_root: testRoot, bindings: 'methodswithdata' }) +-const nodeVersion = parseInt(process.versions.node.split('.')[0]); ++const v8Version = process.versions.v8.split('.').map(parseInt); + + test('SetMethod with data', function (t) { + t.plan(1); +@@ -19,7 +19,7 @@ test('SetMethod with data', function (t) { + test('accessors with data', function (t) { + var settergetter = bindings.create() + var derived = Object.create(settergetter) +- if (nodeVersion > 22) { ++ if(v8Version[0] > 12 || (v8Version[0] === 12 && v8Version[1] >= 9)) { + t.plan(9) + t.equal(settergetter.prop1, 'this is property 1') + t.ok(settergetter.prop2 === '') diff --git a/patches/nan/use_new_constructor_for_scriptorigin_when_17_x.patch b/patches/nan/use_new_constructor_for_scriptorigin_when_17_x.patch deleted file mode 100644 index da73959ba262e..0000000000000 --- a/patches/nan/use_new_constructor_for_scriptorigin_when_17_x.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Rose <japthorp@slack-corp.com> -Date: Thu, 5 May 2022 14:14:36 -0700 -Subject: use new constructor for ScriptOrigin when >= 17.x - -https://chromium-review.googlesource.com/c/v8/v8/+/3395880 - -Also -See https://chromium-review.googlesource.com/c/v8/v8/+/5539888 -ScriptOrigin constructor with isolate has been removed; - -diff --git a/test/cpp/news.cpp b/test/cpp/news.cpp -index a218167c7e3a5ec90c6668943cb395dba2bbe3a7..b1fa6e2a77e926e38006bf47ffcda2ae86555d17 100644 ---- a/test/cpp/news.cpp -+++ b/test/cpp/news.cpp -@@ -115,7 +115,7 @@ NAN_METHOD(NewScript) { - - NAN_METHOD(NewScript2) { - v8::ScriptOrigin origin( --#if NODE_MODULE_VERSION >= NODE_18_0_MODULE_VERSION -+#if NODE_MODULE_VERSION >= NODE_17_0_MODULE_VERSION && NODE_MODULE_VERSION < NODE_20_0_MODULE_VERSION - info.GetIsolate(), - #endif - New<v8::String>("x").ToLocalChecked()); -@@ -136,7 +136,7 @@ NAN_METHOD(CompileScript) { - - NAN_METHOD(CompileScript2) { - v8::ScriptOrigin origin( --#if NODE_MODULE_VERSION >= NODE_18_0_MODULE_VERSION -+#if NODE_MODULE_VERSION >= NODE_17_0_MODULE_VERSION && NODE_MODULE_VERSION < NODE_20_0_MODULE_VERSION - info.GetIsolate(), - #endif - New<v8::String>("x").ToLocalChecked()); diff --git a/patches/node/.patches b/patches/node/.patches index 1f05d709754ec..619b6affec393 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -17,34 +17,29 @@ chore_expose_importmoduledynamically_and.patch test_formally_mark_some_tests_as_flaky.patch fix_do_not_resolve_electron_entrypoints.patch ci_ensure_node_tests_set_electron_run_as_node.patch -fix_assert_module_in_the_renderer_process.patch fix_allow_passing_fileexists_fn_to_legacymainresolve.patch fix_remove_deprecated_errno_constants.patch build_enable_perfetto.patch -fix_add_source_location_for_v8_task_runner.patch -src_remove_dependency_on_wrapper-descriptor-based_cppheap.patch -test_update_v8-stats_test_for_v8_12_6.patch -src_do_not_use_soon-to-be-deprecated_v8_api.patch -src_stop_using_deprecated_fields_of_fastapicallbackoptions.patch -build_compile_with_c_20_support.patch -add_v8_taskpirority_to_foreground_task_runner_signature.patch -cli_remove_deprecated_v8_flag.patch build_restore_clang_as_default_compiler_on_macos.patch -fix_remove_harmony-import-assertions_from_node_cc.patch chore_disable_deprecation_ftbfs_in_simdjson_header.patch build_allow_unbundling_of_node_js_dependencies.patch -test_use_static_method_names_in_call_stacks.patch -fix_remove_fastapitypedarray_usage.patch -test_handle_explicit_resource_management_globals.patch build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch -chore_add_createexternalizabletwobytestring_to_globals.patch refactor_attach_cppgc_heap_on_v8_isolate_creation.patch -fix_ensure_traverseparent_bails_on_resource_path_exit.patch -cli_move_--trace-atomics-wait_to_eol.patch fix_cppgc_initializing_twice.patch -fix_task_starvation_in_inspector_context_test.patch fix_expose_readfilesync_override_for_modules.patch fix_array_out-of-bounds_read_in_boyer-moore_search.patch -chore_add_missing_include_of_iterator.patch test_accomodate_v8_thenable_stack_trace_change_in_snapshot.patch +chore_exclude_electron_node_folder_from_exit-time-destructors.patch +api_remove_deprecated_getisolate.patch +fix_redefined_macos_sdk_header_symbols.patch +fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch +feat_disable_js_source_phase_imports_by_default.patch +fix_avoid_external_memory_leak_on_invalid_tls_protocol_versions.patch +lib_check_sharedarraybuffer_existence_in_fast-utf8-stream.patch +chore_handle_support_for_import_defer_as_ns_and_import_defer.patch +api_delete_deprecated_fields_on_v8_isolate.patch +api_promote_deprecation_of_v8_context_and_v8_object_api_methods.patch +src_use_cp_utf8_for_wide_file_names_on_win32.patch +fix_ensure_traverseparent_bails_on_resource_path_exit.patch +reland_temporal_unflag_temporal.patch diff --git a/patches/node/add_v8_taskpirority_to_foreground_task_runner_signature.patch b/patches/node/add_v8_taskpirority_to_foreground_task_runner_signature.patch deleted file mode 100644 index e1497804ce738..0000000000000 --- a/patches/node/add_v8_taskpirority_to_foreground_task_runner_signature.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Calvin Watford <cwatford@slack-corp.com> -Date: Wed, 18 Sep 2024 16:25:05 -0600 -Subject: add v8::TaskPirority to foreground task runner signature - -For now, we ignore the priority parameter. We expect this will be fixed -naturally upstream, and we will be able to remove this patch in a future -Node.js upgrade. - -diff --git a/src/node_platform.cc b/src/node_platform.cc -index b438b3774d0aa7680fdbc6c6bf39a87893d221b2..ec355061825fb861c17fa2e6cc967b4c7b8d4586 100644 ---- a/src/node_platform.cc -+++ b/src/node_platform.cc -@@ -687,8 +687,8 @@ bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { - return ForIsolate(isolate)->IdleTasksEnabled(); - } - --std::shared_ptr<v8::TaskRunner> --NodePlatform::GetForegroundTaskRunner(Isolate* isolate) { -+std::shared_ptr<v8::TaskRunner> NodePlatform::GetForegroundTaskRunner( -+ Isolate* isolate, v8::TaskPriority priority) { - return ForIsolate(isolate)->GetForegroundTaskRunner(); - } - -diff --git a/src/node_platform.h b/src/node_platform.h -index a0222b4a1b074c6708e390d58d04221717069ac1..8015ca1801573c3a7c4a5db6d0f10b4016a9267c 100644 ---- a/src/node_platform.h -+++ b/src/node_platform.h -@@ -213,7 +213,7 @@ class NodePlatform : public MultiIsolatePlatform { - void (*callback)(void*), void* data) override; - - std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner( -- v8::Isolate* isolate) override; -+ v8::Isolate* isolate, v8::TaskPriority priority) override; - - Platform::StackTracePrinter GetStackTracePrinter() override; - v8::PageAllocator* GetPageAllocator() override; diff --git a/patches/node/api_delete_deprecated_fields_on_v8_isolate.patch b/patches/node/api_delete_deprecated_fields_on_v8_isolate.patch new file mode 100644 index 0000000000000..c8896e87c5305 --- /dev/null +++ b/patches/node/api_delete_deprecated_fields_on_v8_isolate.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt <jkleinsc@electronjs.org> +Date: Wed, 5 Nov 2025 12:50:16 -0500 +Subject: Delete deprecated fields on v8::Isolate + +https://chromium-review.googlesource.com/c/v8/v8/+/7081397 + +diff --git a/src/api/environment.cc b/src/api/environment.cc +index 14be033113bfb13c64e5f99446afaf0cb2aa16a9..3eccf4ce7fcd13091186086456e60334f95f643e 100644 +--- a/src/api/environment.cc ++++ b/src/api/environment.cc +@@ -225,8 +225,6 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) { + // heap based on the actual physical memory. + params->constraints.ConfigureDefaults(total_memory, 0); + } +- params->embedder_wrapper_object_index = BaseObject::InternalFields::kSlot; +- params->embedder_wrapper_type_index = std::numeric_limits<int>::max(); + + #ifdef NODE_ENABLE_VTUNE_PROFILING + params->code_event_handler = vTune::GetVtuneCodeEventHandler(); diff --git a/patches/node/api_promote_deprecation_of_v8_context_and_v8_object_api_methods.patch b/patches/node/api_promote_deprecation_of_v8_context_and_v8_object_api_methods.patch new file mode 100644 index 0000000000000..f66e6a80385db --- /dev/null +++ b/patches/node/api_promote_deprecation_of_v8_context_and_v8_object_api_methods.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt <jkleinsc@electronjs.org> +Date: Wed, 5 Nov 2025 16:41:23 -0500 +Subject: Promote deprecation of v8::Context and v8::Object API methods + +https://chromium-review.googlesource.com/c/v8/v8/+/7087956 + +diff --git a/src/base_object-inl.h b/src/base_object-inl.h +index 37d83e41b618a07aca98118260abe9618f11256d..26d5c1bd3c8191fce1d22b969996b6bf35ef6d3b 100644 +--- a/src/base_object-inl.h ++++ b/src/base_object-inl.h +@@ -75,7 +75,7 @@ bool BaseObject::IsBaseObject(IsolateData* isolate_data, + } + + uint16_t* ptr = static_cast<uint16_t*>( +- obj->GetAlignedPointerFromInternalField(BaseObject::kEmbedderType)); ++ obj->GetAlignedPointerFromInternalField(BaseObject::kEmbedderType, v8::kEmbedderDataTypeTagDefault)); + return ptr == isolate_data->embedder_id_for_non_cppgc(); + } + +@@ -83,21 +83,21 @@ void BaseObject::TagBaseObject(IsolateData* isolate_data, + v8::Local<v8::Object> object) { + DCHECK_GE(object->InternalFieldCount(), BaseObject::kInternalFieldCount); + object->SetAlignedPointerInInternalField( +- BaseObject::kEmbedderType, isolate_data->embedder_id_for_non_cppgc()); ++ BaseObject::kEmbedderType, isolate_data->embedder_id_for_non_cppgc(), v8::kEmbedderDataTypeTagDefault); + } + + void BaseObject::SetInternalFields(IsolateData* isolate_data, + v8::Local<v8::Object> object, + void* slot) { + TagBaseObject(isolate_data, object); +- object->SetAlignedPointerInInternalField(BaseObject::kSlot, slot); ++ object->SetAlignedPointerInInternalField(BaseObject::kSlot, slot, v8::kEmbedderDataTypeTagDefault); + } + + BaseObject* BaseObject::FromJSObject(v8::Local<v8::Value> value) { + v8::Local<v8::Object> obj = value.As<v8::Object>(); + DCHECK_GE(obj->InternalFieldCount(), BaseObject::kInternalFieldCount); + return static_cast<BaseObject*>( +- obj->GetAlignedPointerFromInternalField(BaseObject::kSlot)); ++ obj->GetAlignedPointerFromInternalField(BaseObject::kSlot, v8::kEmbedderDataTypeTagDefault)); + } + + template <typename T> +diff --git a/src/env-inl.h b/src/env-inl.h +index 5dfbd564d5bbd22ebf3b529a07b73e85cbe51986..b0c3c52cab63c6ae67079aa752bd58dd4f162451 100644 +--- a/src/env-inl.h ++++ b/src/env-inl.h +@@ -199,7 +199,8 @@ inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) { + } + return static_cast<Environment*>( + context->GetAlignedPointerFromEmbedderData( +- ContextEmbedderIndex::kEnvironment)); ++ ContextEmbedderIndex::kEnvironment, ++ v8::kEmbedderDataTypeTagDefault)); + } + + inline Environment* Environment::GetCurrent( +diff --git a/src/node_context_data.h b/src/node_context_data.h +index d81c75daaae47b8b0b489cf357a32e437e7a6cf7..b0aab2f7b2538b6e2cacc9ffd52473b7b4ffff38 100644 +--- a/src/node_context_data.h ++++ b/src/node_context_data.h +@@ -135,7 +135,8 @@ class ContextEmbedderTag { + // context. + context->SetAlignedPointerInEmbedderData( + ContextEmbedderIndex::kContextTag, +- ContextEmbedderTag::kNodeContextTagPtr); ++ ContextEmbedderTag::kNodeContextTagPtr, ++ v8::kEmbedderDataTypeTagDefault); + } + + static inline bool IsNodeContext(v8::Local<v8::Context> context) { +@@ -147,7 +148,8 @@ class ContextEmbedderTag { + return false; + } + if (context->GetAlignedPointerFromEmbedderData( +- ContextEmbedderIndex::kContextTag) != ++ ContextEmbedderIndex::kContextTag, ++ v8::kEmbedderDataTypeTagDefault) != + ContextEmbedderTag::kNodeContextTagPtr) [[unlikely]] { + return false; + } +diff --git a/src/node_object_wrap.h b/src/node_object_wrap.h +index cb13d84388bcc6806d3b038a51e1cc2d1feccda1..687b2cf3e63b2a3306e2cbac67e3e216dac49aa6 100644 +--- a/src/node_object_wrap.h ++++ b/src/node_object_wrap.h +@@ -49,7 +49,7 @@ class ObjectWrap { + assert(handle->InternalFieldCount() > 0); + // Cast to ObjectWrap before casting to T. A direct cast from void + // to T won't work right when T has more than one base class. +- void* ptr = handle->GetAlignedPointerFromInternalField(0); ++ void* ptr = handle->GetAlignedPointerFromInternalField(0, v8::kEmbedderDataTypeTagDefault); + ObjectWrap* wrap = static_cast<ObjectWrap*>(ptr); + return static_cast<T*>(wrap); + } +@@ -75,7 +75,7 @@ class ObjectWrap { + inline void Wrap(v8::Local<v8::Object> handle) { + assert(persistent().IsEmpty()); + assert(handle->InternalFieldCount() > 0); +- handle->SetAlignedPointerInInternalField(0, this); ++ handle->SetAlignedPointerInInternalField(0, this, v8::kEmbedderDataTypeTagDefault); + persistent().Reset(v8::Isolate::GetCurrent(), handle); + MakeWeak(); + } +diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h +index f162d1506c990a5fe578be6f1324427e3f9023f4..b57bb0b42e98b954c0c8662c667e589d6c68a5d3 100644 +--- a/src/node_realm-inl.h ++++ b/src/node_realm-inl.h +@@ -21,7 +21,8 @@ inline Realm* Realm::GetCurrent(v8::Local<v8::Context> context) { + return nullptr; + } + return static_cast<Realm*>( +- context->GetAlignedPointerFromEmbedderData(ContextEmbedderIndex::kRealm)); ++ context->GetAlignedPointerFromEmbedderData(ContextEmbedderIndex::kRealm, ++ v8::kEmbedderDataTypeTagDefault)); + } + + inline Realm* Realm::GetCurrent( diff --git a/patches/node/api_remove_deprecated_getisolate.patch b/patches/node/api_remove_deprecated_getisolate.patch new file mode 100644 index 0000000000000..8b381856d140c --- /dev/null +++ b/patches/node/api_remove_deprecated_getisolate.patch @@ -0,0 +1,940 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 <hop2deep@gmail.com> +Date: Mon, 1 Sep 2025 03:13:53 +0900 +Subject: Remove deprecated `GetIsolate` + +https://chromium-review.googlesource.com/c/v8/v8/+/6905244 + +diff --git a/src/api/environment.cc b/src/api/environment.cc +index 072deb1fa70313e33397f6ff994e3f3548e86092..14be033113bfb13c64e5f99446afaf0cb2aa16a9 100644 +--- a/src/api/environment.cc ++++ b/src/api/environment.cc +@@ -669,7 +669,7 @@ std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create( + + MaybeLocal<Object> GetPerContextExports(Local<Context> context, + IsolateData* isolate_data) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + EscapableHandleScope handle_scope(isolate); + + Local<Object> global = context->Global(); +@@ -715,7 +715,7 @@ void ProtoThrower(const FunctionCallbackInfo<Value>& info) { + // This runs at runtime, regardless of whether the context + // is created from a snapshot. + Maybe<void> InitializeContextRuntime(Local<Context> context) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + HandleScope handle_scope(isolate); + + // When `IsCodeGenerationFromStringsAllowed` is true, V8 takes the fast path +@@ -794,7 +794,7 @@ Maybe<void> InitializeContextRuntime(Local<Context> context) { + } + + Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + HandleScope handle_scope(isolate); + + // Delete `Intl.v8BreakIterator` +@@ -819,7 +819,7 @@ Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) { + } + + Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + HandleScope handle_scope(isolate); + + // Initialize the default values. +@@ -837,7 +837,7 @@ Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) { + MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context, + IsolateData* isolate_data) { + CHECK(isolate_data); +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + EscapableHandleScope scope(isolate); + Context::Scope context_scope(context); + +@@ -861,7 +861,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context, + MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context, + IsolateData* isolate_data) { + CHECK(isolate_data); +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + EscapableHandleScope scope(isolate); + Context::Scope context_scope(context); + +@@ -887,7 +887,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context, + Maybe<void> InitializePrimordials(Local<Context> context, + IsolateData* isolate_data) { + // Run per-context JS files. +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Context::Scope context_scope(context); + Local<Object> exports; + +diff --git a/src/base_object-inl.h b/src/base_object-inl.h +index cc60ddddb037e0279615bbe24821eb20fd8da677..37d83e41b618a07aca98118260abe9618f11256d 100644 +--- a/src/base_object-inl.h ++++ b/src/base_object-inl.h +@@ -55,7 +55,6 @@ v8::Local<v8::Object> BaseObject::object() const { + v8::Local<v8::Object> BaseObject::object(v8::Isolate* isolate) const { + v8::Local<v8::Object> handle = object(); + +- DCHECK_EQ(handle->GetCreationContextChecked()->GetIsolate(), isolate); + DCHECK_EQ(env()->isolate(), isolate); + + return handle; +diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc +index 20d3c1d9d17fde18fc09b6ee219137831eb08a45..8fbf4f25a91b953f3d2868889c7ee06932ee3c5f 100644 +--- a/src/crypto/crypto_context.cc ++++ b/src/crypto/crypto_context.cc +@@ -1022,7 +1022,7 @@ bool ArrayOfStringsToX509s(Local<Context> context, + Local<Array> cert_array, + std::vector<X509*>* certs) { + ClearErrorOnReturn clear_error_on_return; +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Environment* env = Environment::GetCurrent(context); + uint32_t array_length = cert_array->Length(); + +diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc +index 4c5427596d1c90d3a413cdd9ff4f1151e657073d..70135a6be65e41fcb3564ddf6d1e8083a59ef8bb 100644 +--- a/src/crypto/crypto_x509.cc ++++ b/src/crypto/crypto_x509.cc +@@ -107,7 +107,7 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, BIOPointer&& bio) { + return {}; + BUF_MEM* mem = bio; + Local<Value> ret; +- if (!String::NewFromUtf8(context->GetIsolate(), ++ if (!String::NewFromUtf8(Isolate::GetCurrent(), + mem->data, + NewStringType::kNormal, + mem->length) +@@ -121,7 +121,7 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) { + return {}; + BUF_MEM* mem = bio; + Local<Value> ret; +- if (!String::NewFromUtf8(context->GetIsolate(), ++ if (!String::NewFromUtf8(Isolate::GetCurrent(), + mem->data, + NewStringType::kNormal, + mem->length) +diff --git a/src/encoding_binding.cc b/src/encoding_binding.cc +index 266f640fb1c6503a424e77cc41fc15bc658bb6a5..877ae8a18f6b8f2c7e3474dfba060d99db88e6b9 100644 +--- a/src/encoding_binding.cc ++++ b/src/encoding_binding.cc +@@ -76,7 +76,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + // Recreate the buffer in the constructor. + InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); +diff --git a/src/env.cc b/src/env.cc +index a78817467518245c4a190e870e0eb30658eafcdb..13dcf0e9c2c86486d1e43763033f43ac4e6b6feb 100644 +--- a/src/env.cc ++++ b/src/env.cc +@@ -1753,10 +1753,10 @@ void AsyncHooks::Deserialize(Local<Context> context) { + context->GetDataFromSnapshotOnce<Array>( + info_->js_execution_async_resources).ToLocalChecked(); + } else { +- js_execution_async_resources = Array::New(context->GetIsolate()); ++ js_execution_async_resources = Array::New(Isolate::GetCurrent()); + } + js_execution_async_resources_.Reset( +- context->GetIsolate(), js_execution_async_resources); ++ Isolate::GetCurrent(), js_execution_async_resources); + + // The native_execution_async_resources_ field requires v8::Local<> instances + // for async calls whose resources were on the stack as JS objects when they +@@ -1796,7 +1796,7 @@ AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context, + info.async_id_fields = async_id_fields_.Serialize(context, creator); + if (!js_execution_async_resources_.IsEmpty()) { + info.js_execution_async_resources = creator->AddData( +- context, js_execution_async_resources_.Get(context->GetIsolate())); ++ context, js_execution_async_resources_.Get(Isolate::GetCurrent())); + CHECK_NE(info.js_execution_async_resources, 0); + } else { + info.js_execution_async_resources = 0; +diff --git a/src/inspector/network_agent.cc b/src/inspector/network_agent.cc +index d136b72e598d07f3c2fcc9c2c8ba84f5ff1aaad7..649008aafc8d68cfecb02c28ad1e26a9b749f7bd 100644 +--- a/src/inspector/network_agent.cc ++++ b/src/inspector/network_agent.cc +@@ -29,31 +29,31 @@ using v8::Value; + Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context, + Local<Object> object, + Local<v8::String> property) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + Local<Value> value; + if (!object->Get(context, property).ToLocal(&value) || !value->IsString()) { + return Nothing<protocol::String>(); + } + Local<v8::String> str = value.As<v8::String>(); +- return Just(ToProtocolString(context->GetIsolate(), str)); ++ return Just(ToProtocolString(v8::Isolate::GetCurrent(), str)); + } + + // Get a protocol string property from the object. + Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context, + Local<Object> object, + const char* property) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + return ObjectGetProtocolString( +- context, object, OneByteString(context->GetIsolate(), property)); ++ context, object, OneByteString(v8::Isolate::GetCurrent(), property)); + } + + // Get a protocol double property from the object. + Maybe<double> ObjectGetDouble(v8::Local<v8::Context> context, + Local<Object> object, + const char* property) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + Local<Value> value; +- if (!object->Get(context, OneByteString(context->GetIsolate(), property)) ++ if (!object->Get(context, OneByteString(v8::Isolate::GetCurrent(), property)) + .ToLocal(&value) || + !value->IsNumber()) { + return Nothing<double>(); +@@ -65,9 +65,9 @@ Maybe<double> ObjectGetDouble(v8::Local<v8::Context> context, + Maybe<int> ObjectGetInt(v8::Local<v8::Context> context, + Local<Object> object, + const char* property) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + Local<Value> value; +- if (!object->Get(context, OneByteString(context->GetIsolate(), property)) ++ if (!object->Get(context, OneByteString(v8::Isolate::GetCurrent(), property)) + .ToLocal(&value) || + !value->IsInt32()) { + return Nothing<int>(); +@@ -79,9 +79,9 @@ Maybe<int> ObjectGetInt(v8::Local<v8::Context> context, + Maybe<bool> ObjectGetBool(v8::Local<v8::Context> context, + Local<Object> object, + const char* property) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + Local<Value> value; +- if (!object->Get(context, OneByteString(context->GetIsolate(), property)) ++ if (!object->Get(context, OneByteString(v8::Isolate::GetCurrent(), property)) + .ToLocal(&value) || + !value->IsBoolean()) { + return Nothing<bool>(); +@@ -93,9 +93,9 @@ Maybe<bool> ObjectGetBool(v8::Local<v8::Context> context, + MaybeLocal<v8::Object> ObjectGetObject(v8::Local<v8::Context> context, + Local<Object> object, + const char* property) { +- EscapableHandleScope handle_scope(context->GetIsolate()); ++ EscapableHandleScope handle_scope(v8::Isolate::GetCurrent()); + Local<Value> value; +- if (!object->Get(context, OneByteString(context->GetIsolate(), property)) ++ if (!object->Get(context, OneByteString(v8::Isolate::GetCurrent(), property)) + .ToLocal(&value) || + !value->IsObject()) { + return {}; +@@ -106,7 +106,7 @@ MaybeLocal<v8::Object> ObjectGetObject(v8::Local<v8::Context> context, + // Create a protocol::Network::Headers from the v8 object. + std::unique_ptr<protocol::Network::Headers> createHeadersFromObject( + v8::Local<v8::Context> context, Local<Object> headers_obj) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + + std::unique_ptr<protocol::DictionaryValue> dict = + protocol::DictionaryValue::create(); +@@ -127,7 +127,7 @@ std::unique_ptr<protocol::Network::Headers> createHeadersFromObject( + .To(&property_value)) { + return {}; + } +- dict->setString(ToProtocolString(context->GetIsolate(), property_name), ++ dict->setString(ToProtocolString(v8::Isolate::GetCurrent(), property_name), + property_value); + } + +@@ -137,7 +137,7 @@ std::unique_ptr<protocol::Network::Headers> createHeadersFromObject( + // Create a protocol::Network::Request from the v8 object. + std::unique_ptr<protocol::Network::Request> createRequestFromObject( + v8::Local<v8::Context> context, Local<Object> request) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + protocol::String url; + if (!ObjectGetProtocolString(context, request, "url").To(&url)) { + return {}; +@@ -169,7 +169,7 @@ std::unique_ptr<protocol::Network::Request> createRequestFromObject( + // Create a protocol::Network::Response from the v8 object. + std::unique_ptr<protocol::Network::Response> createResponseFromObject( + v8::Local<v8::Context> context, Local<Object> response) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + protocol::String url; + if (!ObjectGetProtocolString(context, response, "url").To(&url)) { + return {}; +@@ -210,7 +210,7 @@ std::unique_ptr<protocol::Network::Response> createResponseFromObject( + + std::unique_ptr<protocol::Network::WebSocketResponse> createWebSocketResponse( + v8::Local<v8::Context> context, Local<Object> response) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(v8::Isolate::GetCurrent()); + int status; + if (!ObjectGetInt(context, response, "status").To(&status)) { + return {}; +diff --git a/src/js_native_api_v8.h b/src/js_native_api_v8.h +index 27aeac589b19cd681923fb848ce5f36c66fc05e2..5f2900869763f40cac54e3cb3fe2e24eda615410 100644 +--- a/src/js_native_api_v8.h ++++ b/src/js_native_api_v8.h +@@ -53,7 +53,7 @@ class RefTracker { + struct napi_env__ { + explicit napi_env__(v8::Local<v8::Context> context, + int32_t module_api_version) +- : isolate(context->GetIsolate()), ++ : isolate(v8::Isolate::GetCurrent()), + context_persistent(isolate, context), + module_api_version(module_api_version) { + napi_clear_last_error(this); +diff --git a/src/module_wrap.cc b/src/module_wrap.cc +index 8fed194cbae9ce75bd0805b4df30b4de64fbbefa..a584e3a80adb69d2028dc79450349823ab973a58 100644 +--- a/src/module_wrap.cc ++++ b/src/module_wrap.cc +@@ -99,7 +99,7 @@ ModuleCacheKey ModuleCacheKey::From(Local<Context> context, + Local<String> specifier, + Local<FixedArray> import_attributes) { + CHECK_EQ(import_attributes->Length() % elements_per_attribute, 0); +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + std::size_t h1 = specifier->GetIdentityHash(); + size_t num_attributes = import_attributes->Length() / elements_per_attribute; + ImportAttributeVector attributes; +@@ -1022,7 +1022,7 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( + return {}; + } + DCHECK_NOT_NULL(resolved_module); +- return resolved_module->module_.Get(context->GetIsolate()); ++ return resolved_module->module_.Get(Isolate::GetCurrent()); + } + + // static +@@ -1046,7 +1046,7 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback( + Local<String> url = resolved_module->object() + ->GetInternalField(ModuleWrap::kURLSlot) + .As<String>(); +- THROW_ERR_SOURCE_PHASE_NOT_DEFINED(context->GetIsolate(), url); ++ THROW_ERR_SOURCE_PHASE_NOT_DEFINED(Isolate::GetCurrent(), url); + return {}; + } + CHECK(module_source_object->IsObject()); +@@ -1059,7 +1059,7 @@ Maybe<ModuleWrap*> ModuleWrap::ResolveModule( + Local<String> specifier, + Local<FixedArray> import_attributes, + Local<Module> referrer) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Environment* env = Environment::GetCurrent(context); + if (env == nullptr) { + THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); +@@ -1104,7 +1104,7 @@ MaybeLocal<Promise> ImportModuleDynamicallyWithPhase( + Local<String> specifier, + ModuleImportPhase phase, + Local<FixedArray> import_attributes) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Environment* env = Environment::GetCurrent(context); + if (env == nullptr) { + THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); +@@ -1346,7 +1346,7 @@ MaybeLocal<Module> LinkRequireFacadeWithOriginal( + Local<FixedArray> import_attributes, + Local<Module> referrer) { + Environment* env = Environment::GetCurrent(context); +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + CHECK(specifier->Equals(context, env->original_string()).ToChecked()); + CHECK(!env->temporary_required_module_facade_original.IsEmpty()); + return env->temporary_required_module_facade_original.Get(isolate); +diff --git a/src/node.h b/src/node.h +index 7fae281a6e0f3c1a9f0eb97536883bb26c16d94d..fb37310f44c8d06d1ab2697ed64a0b539776a411 100644 +--- a/src/node.h ++++ b/src/node.h +@@ -1064,7 +1064,7 @@ NODE_DEPRECATED("Use v8::Date::ValueOf() directly", + + #define NODE_DEFINE_CONSTANT(target, constant) \ + do { \ +- v8::Isolate* isolate = target->GetIsolate(); \ ++ v8::Isolate* isolate = v8::Isolate::GetCurrent(); \ + v8::Local<v8::Context> context = isolate->GetCurrentContext(); \ + v8::Local<v8::String> constant_name = v8::String::NewFromUtf8Literal( \ + isolate, #constant, v8::NewStringType::kInternalized); \ +@@ -1080,7 +1080,7 @@ NODE_DEPRECATED("Use v8::Date::ValueOf() directly", + + #define NODE_DEFINE_HIDDEN_CONSTANT(target, constant) \ + do { \ +- v8::Isolate* isolate = target->GetIsolate(); \ ++ v8::Isolate* isolate = v8::Isolate::GetCurrent(); \ + v8::Local<v8::Context> context = isolate->GetCurrentContext(); \ + v8::Local<v8::String> constant_name = v8::String::NewFromUtf8Literal( \ + isolate, #constant, v8::NewStringType::kInternalized); \ +diff --git a/src/node_blob.cc b/src/node_blob.cc +index d278a32c9934c15bc721da164efccca7bc7e7111..ab862bf93a411e6ae6da7c9f9706cee279a0ad70 100644 +--- a/src/node_blob.cc ++++ b/src/node_blob.cc +@@ -554,7 +554,7 @@ void BlobBindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + BlobBindingData* binding = realm->AddBindingData<BlobBindingData>(holder); + CHECK_NOT_NULL(binding); +diff --git a/src/node_builtins.cc b/src/node_builtins.cc +index e69eb280050cae0c0f394b2f956eef947e628904..9bb4576fcf4f07550e7d6f4ff2310cedc8093c5f 100644 +--- a/src/node_builtins.cc ++++ b/src/node_builtins.cc +@@ -274,7 +274,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompileInternal( + const char* id, + LocalVector<String>* parameters, + Realm* optional_realm) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + EscapableHandleScope scope(isolate); + + Local<String> source; +@@ -396,7 +396,7 @@ void BuiltinLoader::SaveCodeCache(const char* id, Local<Function> fun) { + MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context, + const char* id, + Realm* optional_realm) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + LocalVector<String> parameters(isolate); + // Detects parameters of the scripts based on module ids. + // internal/bootstrap/realm: process, getLinkedBinding, +@@ -450,7 +450,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context, + MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context, + const char* id, + Realm* realm) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + // Detects parameters of the scripts based on module ids. + // internal/bootstrap/realm: process, getLinkedBinding, + // getInternalBinding, primordials +@@ -506,7 +506,7 @@ MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context, + if (!maybe_fn.ToLocal(&fn)) { + return MaybeLocal<Value>(); + } +- Local<Value> undefined = Undefined(context->GetIsolate()); ++ Local<Value> undefined = Undefined(Isolate::GetCurrent()); + return fn->Call(context, undefined, argc, argv); + } + +@@ -544,14 +544,14 @@ bool BuiltinLoader::CompileAllBuiltinsAndCopyCodeCache( + to_eager_compile_.emplace(id); + } + +- TryCatch bootstrapCatch(context->GetIsolate()); ++ TryCatch bootstrapCatch(Isolate::GetCurrent()); + auto fn = LookupAndCompile(context, id.data(), nullptr); + if (bootstrapCatch.HasCaught()) { + per_process::Debug(DebugCategory::CODE_CACHE, + "Failed to compile code cache for %s\n", + id.data()); + all_succeeded = false; +- PrintCaughtException(context->GetIsolate(), context, bootstrapCatch); ++ PrintCaughtException(Isolate::GetCurrent(), context, bootstrapCatch); + } else { + // This is used by the snapshot builder, so save the code cache + // unconditionally. +diff --git a/src/node_constants.cc b/src/node_constants.cc +index fea0426496978c0003fe1481afcf93fc9c23edca..c9588880d05435ab9f4e23fcff74c93309664270 100644 +--- a/src/node_constants.cc ++++ b/src/node_constants.cc +@@ -1265,7 +1265,7 @@ void CreatePerContextProperties(Local<Object> target, + Local<Value> unused, + Local<Context> context, + void* priv) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Environment* env = Environment::GetCurrent(context); + + CHECK( +diff --git a/src/node_contextify.cc b/src/node_contextify.cc +index 3c234205e89be7e976dae5c3fcc73ca67953e034..e66d4fcb0c064f96cdb819c783027d864fe88d12 100644 +--- a/src/node_contextify.cc ++++ b/src/node_contextify.cc +@@ -113,7 +113,7 @@ namespace { + + // Convert an int to a V8 Name (String or Symbol). + MaybeLocal<String> Uint32ToName(Local<Context> context, uint32_t index) { +- return Uint32::New(context->GetIsolate(), index)->ToString(context); ++ return Uint32::New(Isolate::GetCurrent(), index)->ToString(context); + } + + } // anonymous namespace +@@ -677,7 +677,7 @@ Intercepted ContextifyContext::PropertyDefinerCallback( + } + + Local<Context> context = ctx->context(); +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + + PropertyAttribute attributes = PropertyAttribute::None; + bool is_declared = +@@ -1666,7 +1666,7 @@ static MaybeLocal<Function> CompileFunctionForCJSLoader( + bool* cache_rejected, + bool is_cjs_scope, + ScriptCompiler::CachedData* cached_data) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + EscapableHandleScope scope(isolate); + + Local<Symbol> symbol = env->vm_dynamic_import_default_internal(); +diff --git a/src/node_env_var.cc b/src/node_env_var.cc +index 6aad252eb5681bb9ab9890812602b43c418e7a7f..5f7ef8cc58f589ba30a44abaaaaaf1514458c3f0 100644 +--- a/src/node_env_var.cc ++++ b/src/node_env_var.cc +@@ -311,7 +311,7 @@ std::shared_ptr<KVStore> KVStore::CreateMapKVStore() { + + Maybe<void> KVStore::AssignFromObject(Local<Context> context, + Local<Object> entries) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + HandleScope handle_scope(isolate); + Local<Array> keys; + if (!entries->GetOwnPropertyNames(context).ToLocal(&keys)) +diff --git a/src/node_errors.cc b/src/node_errors.cc +index 4386a1bc5678e351ce084cd2c47202561619b164..8d51201ad24999ed8f54e16c7878432d41841cf2 100644 +--- a/src/node_errors.cc ++++ b/src/node_errors.cc +@@ -633,7 +633,7 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings( + v8::Local<v8::Context> context, + v8::Local<v8::Value> source, + bool is_code_like) { +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + + if (context->GetNumberOfEmbedderDataFields() <= + ContextEmbedderIndex::kAllowCodeGenerationFromStrings) { +@@ -1000,7 +1000,7 @@ const char* errno_string(int errorno) { + } + + void PerIsolateMessageListener(Local<Message> message, Local<Value> error) { +- Isolate* isolate = message->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + switch (message->ErrorLevel()) { + case Isolate::MessageErrorLevel::kMessageWarning: { + Environment* env = Environment::GetCurrent(isolate); +@@ -1161,7 +1161,7 @@ void Initialize(Local<Object> target, + SetMethod( + context, target, "getErrorSourcePositions", GetErrorSourcePositions); + +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<Object> exit_codes = Object::New(isolate); + READONLY_PROPERTY(target, "exitCodes", exit_codes); + +diff --git a/src/node_file.cc b/src/node_file.cc +index d73dac2ee3f1cf1cac6845fae0f702c9fba8fcef..969e7d08086f8442bed476feaf15599b8c79db7c 100644 +--- a/src/node_file.cc ++++ b/src/node_file.cc +@@ -3874,7 +3874,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); + BindingData* binding = +diff --git a/src/node_messaging.cc b/src/node_messaging.cc +index 57e068ae249d618c2658638f9f3b03e1fedb6524..8c51ae4e0a435971c6d0288af87810877dd31a49 100644 +--- a/src/node_messaging.cc ++++ b/src/node_messaging.cc +@@ -254,7 +254,7 @@ namespace { + + MaybeLocal<Function> GetEmitMessageFunction(Local<Context> context, + IsolateData* isolate_data) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<Object> per_context_bindings; + Local<Value> emit_message_val; + if (!GetPerContextExports(context, isolate_data) +@@ -269,7 +269,7 @@ MaybeLocal<Function> GetEmitMessageFunction(Local<Context> context, + } + + MaybeLocal<Function> GetDOMException(Local<Context> context) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<Object> per_context_bindings; + Local<Value> domexception_ctor_val; + if (!GetPerContextExports(context).ToLocal(&per_context_bindings) || +@@ -284,7 +284,7 @@ MaybeLocal<Function> GetDOMException(Local<Context> context) { + } + + void ThrowDataCloneException(Local<Context> context, Local<String> message) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<Value> argv[] = {message, + FIXED_ONE_BYTE_STRING(isolate, "DataCloneError")}; + Local<Value> exception; +@@ -1477,7 +1477,7 @@ BaseObjectPtr<BaseObject> JSTransferable::Data::Deserialize( + + Maybe<bool> JSTransferable::Data::FinalizeTransferWrite( + Local<Context> context, ValueSerializer* serializer) { +- HandleScope handle_scope(context->GetIsolate()); ++ HandleScope handle_scope(Isolate::GetCurrent()); + auto ret = serializer->WriteValue(context, PersistentToLocal::Strong(data_)); + data_.Reset(); + return ret; +diff --git a/src/node_modules.cc b/src/node_modules.cc +index eea4ba313d8dbcf7b88b79f5a3e9ba2eb39d7c3e..529b7cfc15536c3fe5e7798c0f82698121751f2a 100644 +--- a/src/node_modules.cc ++++ b/src/node_modules.cc +@@ -69,7 +69,7 @@ void BindingData::Deserialize(v8::Local<v8::Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + BindingData* binding = realm->AddBindingData<BindingData>(holder); + CHECK_NOT_NULL(binding); +@@ -696,7 +696,7 @@ void BindingData::CreatePerContextProperties(Local<Object> target, + Realm* realm = Realm::GetCurrent(context); + realm->AddBindingData<BindingData>(target); + +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + LocalVector<Value> compile_cache_status_values(isolate); + + #define V(status) \ +diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc +index e453bacc3e5247493a3582c24174bfe6e590825d..fe4aad63bc877be105830a80aa6be10ce3f8fda4 100644 +--- a/src/node_process_methods.cc ++++ b/src/node_process_methods.cc +@@ -737,7 +737,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- v8::HandleScope scope(context->GetIsolate()); ++ v8::HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + // Recreate the buffer in the constructor. + InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); +diff --git a/src/node_realm.cc b/src/node_realm.cc +index 2a5fe9fe501d1fd9356eeb7d044a872fa5a55f38..39f6f142044c42904d234da20a266315346c135a 100644 +--- a/src/node_realm.cc ++++ b/src/node_realm.cc +@@ -22,7 +22,7 @@ using v8::String; + using v8::Value; + + Realm::Realm(Environment* env, v8::Local<v8::Context> context, Kind kind) +- : env_(env), isolate_(context->GetIsolate()), kind_(kind) { ++ : env_(env), isolate_(v8::Isolate::GetCurrent()), kind_(kind) { + context_.Reset(isolate_, context); + env->AssignToContext(context, this, ContextInfo("")); + // The environment can also purge empty wrappers in the check callback, +diff --git a/src/node_report.cc b/src/node_report.cc +index c82c6bcc083ba60137e83b3c291130636db3162f..0d06f61d7fb2472a3d7a66854040dc493406b79e 100644 +--- a/src/node_report.cc ++++ b/src/node_report.cc +@@ -400,7 +400,7 @@ static void PrintJavaScriptErrorProperties(JSONWriter* writer, + if (!error.IsEmpty() && error->IsObject()) { + TryCatch try_catch(isolate); + Local<Object> error_obj = error.As<Object>(); +- Local<Context> context = error_obj->GetIsolate()->GetCurrentContext(); ++ Local<Context> context = Isolate::GetCurrent()->GetCurrentContext(); + Local<Array> keys; + if (!error_obj->GetOwnPropertyNames(context).ToLocal(&keys)) { + return writer->json_objectend(); // the end of 'errorProperties' +diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc +index c2e24b4645e7903e08c80aead1c18c7bcff1bd89..e34d24d51d5c090b560d06f727043f20924e6f46 100644 +--- a/src/node_snapshotable.cc ++++ b/src/node_snapshotable.cc +@@ -1614,7 +1614,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- v8::HandleScope scope(context->GetIsolate()); ++ v8::HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + // Recreate the buffer in the constructor. + InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); +diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc +index 7bb4d4108c8326d69da5236c7ea7f00ddb68cea9..cf9ce6686cffca7e700a0e20cb9f776a5f0f7c4a 100644 +--- a/src/node_sqlite.cc ++++ b/src/node_sqlite.cc +@@ -2020,7 +2020,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) { + + if (args[0]->IsObject() && !args[0]->IsArrayBufferView()) { + Local<Object> obj = args[0].As<Object>(); +- Local<Context> context = obj->GetIsolate()->GetCurrentContext(); ++ Local<Context> context = Isolate::GetCurrent()->GetCurrentContext(); + Local<Array> keys; + if (!obj->GetOwnPropertyNames(context).ToLocal(&keys)) { + return false; +diff --git a/src/node_task_queue.cc b/src/node_task_queue.cc +index d33ee3c26c111e53edf27e6368ca8f64ff30a349..f1c53c44f201b295888e7932c5e3e2b19cb9c319 100644 +--- a/src/node_task_queue.cc ++++ b/src/node_task_queue.cc +@@ -48,7 +48,7 @@ void PromiseRejectCallback(PromiseRejectMessage message) { + static std::atomic<uint64_t> rejectionsHandledAfter{0}; + + Local<Promise> promise = message.GetPromise(); +- Isolate* isolate = promise->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + PromiseRejectEvent event = message.GetEvent(); + + Environment* env = Environment::GetCurrent(isolate); +diff --git a/src/node_url.cc b/src/node_url.cc +index 9d1e8ec05161570db11f7b662395509774668d78..9b91f83d879ea02fd3d61913c8dfd35b3bf1ac31 100644 +--- a/src/node_url.cc ++++ b/src/node_url.cc +@@ -70,7 +70,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + BindingData* binding = realm->AddBindingData<BindingData>(holder); + CHECK_NOT_NULL(binding); +diff --git a/src/node_v8.cc b/src/node_v8.cc +index 98e392f6d7118bee8a3d0bce4de1ded76a293001..152b030198c6b36efd2be6c06f5c6e8bbc7cfadb 100644 +--- a/src/node_v8.cc ++++ b/src/node_v8.cc +@@ -158,7 +158,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- HandleScope scope(context->GetIsolate()); ++ HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + // Recreate the buffer in the constructor. + InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); +diff --git a/src/node_wasi.cc b/src/node_wasi.cc +index 370221d3cddc201180260ecb3a222bc831c91093..f5aff2f65fe6b9f48cf970ab3e7c57cfe4885f85 100644 +--- a/src/node_wasi.cc ++++ b/src/node_wasi.cc +@@ -50,7 +50,7 @@ using v8::WasmMemoryObject; + static MaybeLocal<Value> WASIException(Local<Context> context, + int errorno, + const char* syscall) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Environment* env = Environment::GetCurrent(context); + CHECK_NOT_NULL(env); + const char* err_name = uvwasi_embedder_err_code_to_string(errorno); +@@ -275,8 +275,8 @@ R WASI::WasiFunction<FT, F, R, Args...>::FastCallback( + return EinvalError<R>(); + } + +- Isolate* isolate = receiver->GetIsolate(); +- HandleScope scope(isolate); ++ Isolate* isolate = Isolate::GetCurrent(); ++ HandleScope handle_scope(isolate); + if (wasi->memory_.IsEmpty()) { + THROW_ERR_WASI_NOT_STARTED(isolate); + return EinvalError<R>(); +diff --git a/src/node_webstorage.cc b/src/node_webstorage.cc +index cc90af827a3fbd14fb4cbfbfd39cc661f22cf6e1..5819d9bca845e0eed6d4d93564469d8f3c36200b 100644 +--- a/src/node_webstorage.cc ++++ b/src/node_webstorage.cc +@@ -57,7 +57,7 @@ using v8::Value; + } while (0) + + static void ThrowQuotaExceededException(Local<Context> context) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + auto dom_exception_str = FIXED_ONE_BYTE_STRING(isolate, "DOMException"); + auto err_name = FIXED_ONE_BYTE_STRING(isolate, "QuotaExceededError"); + auto err_message = +@@ -433,7 +433,7 @@ Maybe<void> Storage::Store(Local<Name> key, Local<Value> value) { + } + + static MaybeLocal<String> Uint32ToName(Local<Context> context, uint32_t index) { +- return Uint32::New(context->GetIsolate(), index)->ToString(context); ++ return Uint32::New(Isolate::GetCurrent(), index)->ToString(context); + } + + static void Clear(const FunctionCallbackInfo<Value>& info) { +diff --git a/src/node_worker.cc b/src/node_worker.cc +index 62c53368d1173edb7eb42e3337049c46fd7cdda9..7d08d8af7f6d99f7bd41cb7eb91063c630b3f87b 100644 +--- a/src/node_worker.cc ++++ b/src/node_worker.cc +@@ -1466,8 +1466,6 @@ void GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) { + Local<Object> port = env->message_port(); + CHECK_IMPLIES(!env->is_main_thread(), !port.IsEmpty()); + if (!port.IsEmpty()) { +- CHECK_EQ(port->GetCreationContextChecked()->GetIsolate(), +- args.GetIsolate()); + args.GetReturnValue().Set(port); + } + } +diff --git a/src/timers.cc b/src/timers.cc +index da4206187f7c7d2becb8a101c1ff5346a10e13f4..03f0910926f3d403121e227cee32a546b2394e04 100644 +--- a/src/timers.cc ++++ b/src/timers.cc +@@ -114,7 +114,7 @@ void BindingData::Deserialize(Local<Context> context, + int index, + InternalFieldInfoBase* info) { + DCHECK_IS_SNAPSHOT_SLOT(index); +- v8::HandleScope scope(context->GetIsolate()); ++ v8::HandleScope scope(Isolate::GetCurrent()); + Realm* realm = Realm::GetCurrent(context); + // Recreate the buffer in the constructor. + BindingData* binding = realm->AddBindingData<BindingData>(holder); +diff --git a/src/util-inl.h b/src/util-inl.h +index 9d4db311024c5f526fc3c00764fff686af044026..da9268dcf2ff432ddeec7c0f61a147b73f3130e2 100644 +--- a/src/util-inl.h ++++ b/src/util-inl.h +@@ -336,14 +336,14 @@ v8::Maybe<void> FromV8Array(v8::Local<v8::Context> context, + std::vector<v8::Global<v8::Value>>* out) { + uint32_t count = js_array->Length(); + out->reserve(count); +- ArrayIterationData data{out, context->GetIsolate()}; ++ ArrayIterationData data{out, v8::Isolate::GetCurrent()}; + return js_array->Iterate(context, PushItemToVector, &data); + } + + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + std::string_view str, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + if (str.size() >= static_cast<size_t>(v8::String::kMaxLength)) [[unlikely]] { + // V8 only has a TODO comment about adding an exception when the maximum + // string size is exceeded. +@@ -359,7 +359,7 @@ v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + v8_inspector::StringView str, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + if (str.length() >= static_cast<size_t>(v8::String::kMaxLength)) + [[unlikely]] { + // V8 only has a TODO comment about adding an exception when the maximum +@@ -386,7 +386,7 @@ template <typename T> + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + const std::vector<T>& vec, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + + MaybeStackBuffer<v8::Local<v8::Value>, 128> arr(vec.size()); +@@ -403,7 +403,7 @@ template <typename T> + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + const std::set<T>& set, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + v8::Local<v8::Set> set_js = v8::Set::New(isolate); + v8::HandleScope handle_scope(isolate); + +@@ -422,7 +422,7 @@ template <typename T, std::size_t U> + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + const std::ranges::elements_view<T, U>& vec, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + + MaybeStackBuffer<v8::Local<v8::Value>, 128> arr(vec.size()); +@@ -441,7 +441,7 @@ template <typename T, typename U> + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + const std::unordered_map<T, U>& map, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + + v8::Local<v8::Map> ret = v8::Map::New(isolate); +@@ -484,7 +484,7 @@ template <typename T, typename> + v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, + const T& number, + v8::Isolate* isolate) { +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + return ConvertNumberToV8Value(isolate, number); + } + +@@ -497,7 +497,7 @@ v8::Local<v8::Array> ToV8ValuePrimitiveArray(v8::Local<v8::Context> context, + std::is_floating_point_v<T>, + "Only primitive types (bool, integral, floating-point) are supported."); + +- if (isolate == nullptr) isolate = context->GetIsolate(); ++ if (isolate == nullptr) isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); + + v8::LocalVector<v8::Value> elements(isolate); +@@ -731,7 +731,7 @@ inline v8::MaybeLocal<v8::Object> NewDictionaryInstanceNullProto( + if (value.IsEmpty()) return v8::MaybeLocal<v8::Object>(); + } + v8::Local<v8::Object> obj = tmpl->NewInstance(context, property_values); +- if (obj->SetPrototypeV2(context, v8::Null(context->GetIsolate())) ++ if (obj->SetPrototypeV2(context, v8::Null(v8::Isolate::GetCurrent())) + .IsNothing()) { + return v8::MaybeLocal<v8::Object>(); + } +diff --git a/src/util.cc b/src/util.cc +index 660cfff6b8a0c583be843e555e7a06cd09e0d279..c4b39450c5b7f91c46f7027db367c30db34927bb 100644 +--- a/src/util.cc ++++ b/src/util.cc +@@ -391,7 +391,7 @@ void SetMethod(Local<v8::Context> context, + Local<v8::Object> that, + const std::string_view name, + v8::FunctionCallback callback) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<v8::Function> function = + NewFunctionTemplate(isolate, + callback, +@@ -452,7 +452,7 @@ void SetFastMethod(Local<v8::Context> context, + const std::string_view name, + v8::FunctionCallback slow_callback, + const v8::CFunction* c_function) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<v8::Function> function = + NewFunctionTemplate(isolate, + slow_callback, +@@ -474,7 +474,7 @@ void SetFastMethodNoSideEffect(Local<v8::Context> context, + const std::string_view name, + v8::FunctionCallback slow_callback, + const v8::CFunction* c_function) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<v8::Function> function = + NewFunctionTemplate(isolate, + slow_callback, +@@ -562,7 +562,7 @@ void SetMethodNoSideEffect(Local<v8::Context> context, + Local<v8::Object> that, + const std::string_view name, + v8::FunctionCallback callback) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + Local<v8::Function> function = + NewFunctionTemplate(isolate, + callback, +@@ -689,7 +689,7 @@ void SetConstructorFunction(Local<v8::Context> context, + const char* name, + Local<v8::FunctionTemplate> tmpl, + SetConstructorFunctionFlag flag) { +- Isolate* isolate = context->GetIsolate(); ++ Isolate* isolate = Isolate::GetCurrent(); + SetConstructorFunction( + context, that, OneByteString(isolate, name), tmpl, flag); + } +diff --git a/src/util.h b/src/util.h +index 2b351235cf7f32c9fad25367cc912d187466f1e0..6da57f95165bbdedb65dab6eaae8c39b815ee4e5 100644 +--- a/src/util.h ++++ b/src/util.h +@@ -739,7 +739,7 @@ inline v8::MaybeLocal<v8::Value> ToV8Value( + // Variation on NODE_DEFINE_CONSTANT that sets a String value. + #define NODE_DEFINE_STRING_CONSTANT(target, name, constant) \ + do { \ +- v8::Isolate* isolate = target->GetIsolate(); \ ++ v8::Isolate* isolate = v8::Isolate::GetCurrent(); \ + v8::Local<v8::String> constant_name = \ + v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \ + v8::Local<v8::String> constant_value = \ diff --git a/patches/node/build_add_gn_build_files.patch b/patches/node/build_add_gn_build_files.patch index 5e0111ef8ca4d..8524c800567e0 100644 --- a/patches/node/build_add_gn_build_files.patch +++ b/patches/node/build_add_gn_build_files.patch @@ -11,10 +11,10 @@ really in 20/21. We have to wait until 22 is released to be able to build with upstream GN files. diff --git a/configure.py b/configure.py -index 2415940835036226799a7ea14c6687cc0d56c523..0feb07afbccad97a92cee00954443407eb20ac67 100755 +index 7f73f084ef1a8336089e6a16423c2eb310c0b9f2..96eedd5d9ae05ee6704724290973251059d5dd78 100755 --- a/configure.py +++ b/configure.py -@@ -1722,7 +1722,7 @@ def configure_v8(o, configs): +@@ -1730,7 +1730,7 @@ def configure_v8(o, configs): # Until we manage to get rid of all those, v8_enable_sandbox cannot be used. # Note that enabling pointer compression without enabling sandbox is unsupported by V8, # so this can be broken at any time. @@ -24,7 +24,7 @@ index 2415940835036226799a7ea14c6687cc0d56c523..0feb07afbccad97a92cee00954443407 o['variables']['v8_enable_external_code_space'] = 1 if options.enable_pointer_compression else 0 o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0 diff --git a/node.gni b/node.gni -index b049f0692980c3e26771c3209c3bdd2e9a4d637b..e2407027ab05e59b2f0f1c213b98ea469db7a91b 100644 +index d4438f7fd61598afac2c1e3184721a759d22b10c..e2407027ab05e59b2f0f1c213b98ea469db7a91b 100644 --- a/node.gni +++ b/node.gni @@ -5,10 +5,10 @@ @@ -40,15 +40,7 @@ index b049f0692980c3e26771c3209c3bdd2e9a4d637b..e2407027ab05e59b2f0f1c213b98ea46 # The location of OpenSSL - use the one from node's deps by default. node_openssl_path = "$node_path/deps/openssl" -@@ -42,12 +42,15 @@ declare_args() { - # The variable is called "openssl" for parity with node's GYP build. - node_use_openssl = true - -+ # Build node with SQLite support. -+ node_use_sqlite = true -+ - # Use the specified path to system CA (PEM format) in addition to - # the BoringSSL supplied CA store or compiled-in Mozilla CA copy. +@@ -50,7 +50,7 @@ declare_args() { node_openssl_system_ca_path = "" # Initialize v8 platform during node.js startup. @@ -57,7 +49,7 @@ index b049f0692980c3e26771c3209c3bdd2e9a4d637b..e2407027ab05e59b2f0f1c213b98ea46 # Custom build tag. node_tag = "" -@@ -67,10 +70,16 @@ declare_args() { +@@ -70,10 +70,16 @@ declare_args() { # TODO(zcbenz): There are few broken things for now: # 1. cross-os compilation is not supported. # 2. node_mksnapshot crashes when cross-compiling for x64 from arm64. @@ -76,10 +68,10 @@ index b049f0692980c3e26771c3209c3bdd2e9a4d637b..e2407027ab05e59b2f0f1c213b98ea46 assert(!node_enable_inspector || node_use_openssl, diff --git a/src/node_builtins.cc b/src/node_builtins.cc -index abf1583cdac9f139056cf4809f14e28e62f6d24c..8b104e175ccf8de90c138337f83f8f6ce1348ac7 100644 +index 581b9886ded52f294b7cc6b080b2269b7617c85e..e43e2559aaf48add88aad342b1c96fd34f26c87f 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc -@@ -789,6 +789,7 @@ void BuiltinLoader::RegisterExternalReferences( +@@ -774,6 +774,7 @@ void BuiltinLoader::RegisterExternalReferences( registry->Register(GetNatives); RegisterExternalReferencesForInternalizedBuiltinCode(registry); @@ -88,10 +80,10 @@ index abf1583cdac9f139056cf4809f14e28e62f6d24c..8b104e175ccf8de90c138337f83f8f6c } // namespace builtins diff --git a/src/node_builtins.h b/src/node_builtins.h -index f9426599f2d5dc6ad061407f0c4eb2c9203a4433..302030f610965f07dd6998d282275c1bdf738009 100644 +index 7a7b84337feb67960819472e43192dbdc151e299..bcdd50f635757f41287c87df1db9cd3b55c4b6b9 100644 --- a/src/node_builtins.h +++ b/src/node_builtins.h -@@ -74,6 +74,8 @@ using BuiltinCodeCacheMap = +@@ -75,6 +75,8 @@ using BuiltinCodeCacheMap = // Generated by tools/js2c.cc as node_javascript.cc void RegisterExternalReferencesForInternalizedBuiltinCode( ExternalReferenceRegistry* registry); @@ -100,26 +92,6 @@ index f9426599f2d5dc6ad061407f0c4eb2c9203a4433..302030f610965f07dd6998d282275c1b // Handles compilation and caching of built-in JavaScript modules and // bootstrap scripts, whose source are bundled into the binary as static data. -diff --git a/tools/install.py b/tools/install.py -index 8797b59e59c85a8877b977fa3281e50165e6f6b2..0af01e075616195f38fb242626dcab770ec1eb57 100755 ---- a/tools/install.py -+++ b/tools/install.py -@@ -222,6 +222,7 @@ def headers(options, action): - 'include/cppgc/internal/caged-heap-local-data.h', - 'include/cppgc/internal/caged-heap.h', - 'include/cppgc/internal/compiler-specific.h', -+ 'include/cppgc/internal/conditional-stack-allocated.h', - 'include/cppgc/internal/finalizer-trait.h', - 'include/cppgc/internal/gc-info.h', - 'include/cppgc/internal/logging.h', -@@ -301,6 +302,7 @@ def headers(options, action): - 'include/v8-promise.h', - 'include/v8-proxy.h', - 'include/v8-regexp.h', -+ 'include/v8-sandbox.h', - 'include/v8-script.h', - 'include/v8-snapshot.h', - 'include/v8-source-location.h', diff --git a/tools/js2c.cc b/tools/js2c.cc old mode 100644 new mode 100755 @@ -279,22 +251,10 @@ index 856878c33681a73d41016729dabe48b0a6a80589..91a11852d206b65485fe90fd037a0bd1 if sys.platform == 'win32': files = [ x.replace('\\', '/') for x in files ] diff --git a/unofficial.gni b/unofficial.gni -index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f5294aab9d37 100644 +index c742b62c484e9dd205eff63dcffad78c76828375..20d2483bb16e297ab5b12aab6f56948d6d25cb03 100644 --- a/unofficial.gni +++ b/unofficial.gni -@@ -22,6 +22,11 @@ template("node_gn_build") { - } else { - defines += [ "HAVE_OPENSSL=0" ] - } -+ if (node_use_sqlite) { -+ defines += [ "HAVE_SQLITE=1" ] -+ } else { -+ defines += [ "HAVE_SQLITE=0" ] -+ } - if (node_use_amaro) { - defines += [ "HAVE_AMARO=1" ] - } else { -@@ -142,32 +147,41 @@ template("node_gn_build") { +@@ -147,31 +147,41 @@ template("node_gn_build") { public_configs = [ ":node_external_config", "deps/googletest:googletest_config", @@ -317,7 +277,6 @@ index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f529 "deps/nghttp2", - "deps/ngtcp2", "deps/postject", -- "deps/sqlite", "deps/uvwasi", - "deps/zstd", "//third_party/zlib", @@ -340,7 +299,7 @@ index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f529 "$target_gen_dir/node_javascript.cc", ] + gypi_values.node_sources -@@ -190,9 +204,13 @@ template("node_gn_build") { +@@ -194,7 +204,7 @@ template("node_gn_build") { } if (node_use_openssl) { deps += [ "deps/ncrypto" ] @@ -348,14 +307,8 @@ index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f529 + public_deps += [ "//third_party/boringssl" ] sources += gypi_values.node_crypto_sources } -+ if (node_use_sqlite) { -+ deps += [ "deps/sqlite" ] -+ sources += gypi_values.node_sqlite_sources -+ } - if (node_enable_inspector) { - deps += [ - "$node_inspector_protocol_path:crdtp", -@@ -215,6 +233,10 @@ template("node_gn_build") { + if (node_use_sqlite) { +@@ -223,6 +233,10 @@ template("node_gn_build") { } } @@ -366,7 +319,7 @@ index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f529 executable(target_name) { forward_variables_from(invoker, "*") -@@ -289,6 +311,7 @@ template("node_gn_build") { +@@ -314,6 +328,7 @@ template("node_gn_build") { } executable("node_js2c") { @@ -374,7 +327,7 @@ index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f529 deps = [ "deps/uv", "$node_simdutf_path", -@@ -299,26 +322,75 @@ template("node_gn_build") { +@@ -324,26 +339,75 @@ template("node_gn_build") { "src/embedded_data.cc", "src/embedded_data.h", ] @@ -460,7 +413,7 @@ index da565473f1ae96b4d009935f7733e6ab15ea9de2..26ebc811272ef2990f8d090c54e7f529 outputs = [ "$target_gen_dir/node_javascript.cc" ] # Get the path to node_js2c executable of the host toolchain. -@@ -332,11 +404,11 @@ template("node_gn_build") { +@@ -357,11 +421,11 @@ template("node_gn_build") { get_label_info(":node_js2c($host_toolchain)", "name") + host_executable_suffix diff --git a/patches/node/build_allow_unbundling_of_node_js_dependencies.patch b/patches/node/build_allow_unbundling_of_node_js_dependencies.patch index 48d4362fb6792..1ce105ad3eb80 100644 --- a/patches/node/build_allow_unbundling_of_node_js_dependencies.patch +++ b/patches/node/build_allow_unbundling_of_node_js_dependencies.patch @@ -14,7 +14,7 @@ We don't need to do this for zlib, as the existing gn workflow uses the same Upstreamed at https://github.com/nodejs/node/pull/55903 diff --git a/unofficial.gni b/unofficial.gni -index 26ebc811272ef2990f8d090c54e7f5294aab9d37..8886f2a79ae77614789d6ae0defd4f18fc756456 100644 +index 20d2483bb16e297ab5b12aab6f56948d6d25cb03..253226009faf563f6db285d4b2908f308c1f96ea 100644 --- a/unofficial.gni +++ b/unofficial.gni @@ -160,7 +160,6 @@ template("node_gn_build") { diff --git a/patches/node/build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch b/patches/node/build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch index 7f669c5b0bd7d..927fd478912ad 100644 --- a/patches/node/build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch +++ b/patches/node/build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch @@ -14,7 +14,7 @@ error: duplicate symbol: crdtp::ProtocolTypeTraits<std::__Cr::basic_string<char, Some distinguishing change should be upstreamed to Node.js. diff --git a/src/inspector/node_string.cc b/src/inspector/node_string.cc -index 8521730bd03cdfce47e9b5d0f5d68a568bc3de8c..28f4598aa7ea0e93350f79566c06d0f08313be9f 100644 +index e2148e954217b9b999e9713e95f1a115ccf7d657..7ec7464cdc0ef00e6600fb897ae99e44ed0f4ad8 100644 --- a/src/inspector/node_string.cc +++ b/src/inspector/node_string.cc @@ -7,7 +7,8 @@ diff --git a/patches/node/build_compile_with_c_20_support.patch b/patches/node/build_compile_with_c_20_support.patch deleted file mode 100644 index 52a25cc54cd5c..0000000000000 --- a/patches/node/build_compile_with_c_20_support.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr <shelley.vohr@gmail.com> -Date: Wed, 4 Sep 2024 16:39:23 +0200 -Subject: build: compile with C++20 support - -Refs https://github.com/nodejs/node/pull/45427 - -V8 requires C++20 support as of https://chromium-review.googlesource.com/c/v8/v8/+/5587859. - -This can be removed when Electron upgrades to a version of Node.js containing the required V8 version. - -diff --git a/common.gypi b/common.gypi -index 679633dc6b4ce2a1f5f88e93d1a1c1feb4bbadb4..2caa183213d5632be81b763e894e37c09384391f 100644 ---- a/common.gypi -+++ b/common.gypi -@@ -539,7 +539,7 @@ - '-fno-rtti', - '-fno-exceptions', - '-fno-strict-aliasing', -- '-std=gnu++17', -+ '-std=gnu++20', - ], - 'defines': [ '__STDC_FORMAT_MACROS' ], - 'ldflags': [ '-rdynamic' ], -@@ -709,7 +709,7 @@ - ['clang==1', { - 'xcode_settings': { - 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', -- 'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++17', # -std=gnu++17 -+ 'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++20', # -std=gnu++20 - 'CLANG_CXX_LIBRARY': 'libc++', - }, - }], diff --git a/patches/node/build_enable_perfetto.patch b/patches/node/build_enable_perfetto.patch index 1bb292dd46878..34af611eae14d 100644 --- a/patches/node/build_enable_perfetto.patch +++ b/patches/node/build_enable_perfetto.patch @@ -33,10 +33,10 @@ index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b // Non-alphabetic chars. diff --git a/lib/internal/http.js b/lib/internal/http.js -index 251f51ec454f9cba4023b8b6729241ee753aac13..1de8cac6e3953ce9cab9db03530da327199acfd5 100644 +index 9bf929f7f3360f13058d3f446c18a36cd15bea58..abf9a06d891488288bccd98c437746c1ce48bf83 100644 --- a/lib/internal/http.js +++ b/lib/internal/http.js -@@ -8,8 +8,8 @@ const { +@@ -11,8 +11,8 @@ const { const { setUnrefTimeout } = require('internal/timers'); const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events'); const { @@ -46,8 +46,8 @@ index 251f51ec454f9cba4023b8b6729241ee753aac13..1de8cac6e3953ce9cab9db03530da327 + CHAR_UPPERCASE_E, } = require('internal/constants'); - let utcCache; -@@ -44,11 +44,13 @@ function isTraceHTTPEnabled() { + const { URL } = require('internal/url'); +@@ -51,11 +51,13 @@ function isTraceHTTPEnabled() { const traceEventCategory = 'node,node.http'; function traceBegin(...args) { @@ -62,9 +62,9 @@ index 251f51ec454f9cba4023b8b6729241ee753aac13..1de8cac6e3953ce9cab9db03530da327 + trace(CHAR_UPPERCASE_E, traceEventCategory, ...args); } - module.exports = { + function ipToInt(ip) { diff --git a/node.gyp b/node.gyp -index 442c1e7a6ddafbb7a7ec7a42a97ec04b28ea4d93..3a66c11d39dd2fd129c8f54098a9607e080ecca0 100644 +index 420d57135f48df59b2cbd33497ef90b6148017e6..eefb1e0577b881da7a1570fd7ac465fe8b06747c 100644 --- a/node.gyp +++ b/node.gyp @@ -176,7 +176,6 @@ @@ -75,7 +75,7 @@ index 442c1e7a6ddafbb7a7ec7a42a97ec04b28ea4d93..3a66c11d39dd2fd129c8f54098a9607e 'src/tracing/node_trace_writer.cc', 'src/tracing/trace_event.cc', 'src/tracing/traced_value.cc', -@@ -304,7 +303,6 @@ +@@ -308,7 +307,6 @@ 'src/tcp_wrap.h', 'src/timers.h', 'src/tracing/agent.h', @@ -105,7 +105,7 @@ index 40c8aea35c931c46fc62b717c978eab0659645fd..348cdfb0b42aa18f352c220cea0b896c if (!json_writer_) return; diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc -index 7ce59674356f9743438350949be42fa7ead2afbe..30bff4272ed8eb5146e3b73a4849c187177fc3bd 100644 +index eddcf6c3bf91b730d6ca72960e3048ceed7e7844..184e8647b2148bc597d9d3eb63f86ae99917c642 100644 --- a/src/tracing/agent.cc +++ b/src/tracing/agent.cc @@ -2,7 +2,9 @@ @@ -144,7 +144,7 @@ index 7ce59674356f9743438350949be42fa7ead2afbe..30bff4272ed8eb5146e3b73a4849c187 // This thread should be created *after* async handles are created // (within NodeTraceWriter and NodeTraceBuffer constructors). -@@ -143,8 +151,10 @@ void Agent::StopTracing() { +@@ -148,8 +156,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. @@ -156,7 +156,7 @@ index 7ce59674356f9743438350949be42fa7ead2afbe..30bff4272ed8eb5146e3b73a4849c187 started_ = false; // Thread should finish when the tracing loop is stopped. -@@ -202,6 +212,7 @@ std::string Agent::GetEnabledCategories() const { +@@ -207,6 +217,7 @@ std::string Agent::GetEnabledCategories() const { return categories; } @@ -164,7 +164,7 @@ index 7ce59674356f9743438350949be42fa7ead2afbe..30bff4272ed8eb5146e3b73a4849c187 void Agent::AppendTraceEvent(TraceObject* trace_event) { for (const auto& id_writer : writers_) id_writer.second->AppendTraceEvent(trace_event); -@@ -211,18 +222,21 @@ void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) { +@@ -216,18 +227,21 @@ void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) { Mutex::ScopedLock lock(metadata_events_mutex_); metadata_events_.push_back(std::move(event)); } @@ -187,7 +187,7 @@ index 7ce59674356f9743438350949be42fa7ead2afbe..30bff4272ed8eb5146e3b73a4849c187 void TracingController::AddMetadataEvent( const unsigned char* category_group_enabled, const char* name, -@@ -246,6 +260,6 @@ void TracingController::AddMetadataEvent( +@@ -251,6 +265,6 @@ void TracingController::AddMetadataEvent( if (node_agent != nullptr) node_agent->AddMetadataEvent(std::move(trace_event)); } diff --git a/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch b/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch index 3f5e9b39ae14b..f0ca785e2804c 100644 --- a/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch +++ b/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch @@ -7,7 +7,7 @@ Subject: build: ensure native module compilation fails if not using a new This should not be upstreamed, it is a quality-of-life patch for downstream module builders. diff --git a/common.gypi b/common.gypi -index 33af43cd768c24b26d523f3db66eb8b9eb26859a..679633dc6b4ce2a1f5f88e93d1a1c1feb4bbadb4 100644 +index 29a912f58e7b522ae21fddac510946cbcbaaa4cc..aea3a882c338eb757bef9e85fabab3fc7e7495f7 100644 --- a/common.gypi +++ b/common.gypi @@ -89,6 +89,8 @@ @@ -42,10 +42,10 @@ index 33af43cd768c24b26d523f3db66eb8b9eb26859a..679633dc6b4ce2a1f5f88e93d1a1c1fe # list in v8/BUILD.gn. ['v8_enable_v8_checks == 1', { diff --git a/configure.py b/configure.py -index 0feb07afbccad97a92cee00954443407eb20ac67..5eccced7cf0212f229db68c76cc824a37e4a29bc 100755 +index 96eedd5d9ae05ee6704724290973251059d5dd78..52060f9c6dc1bcec67a0fd4710e01e73a6cf276c 100755 --- a/configure.py +++ b/configure.py -@@ -1704,6 +1704,7 @@ def configure_library(lib, output, pkgname=None): +@@ -1711,6 +1711,7 @@ def configure_library(lib, output, pkgname=None): def configure_v8(o, configs): set_configuration_variable(configs, 'v8_enable_v8_checks', release=1, debug=0) @@ -54,7 +54,7 @@ index 0feb07afbccad97a92cee00954443407eb20ac67..5eccced7cf0212f229db68c76cc824a3 o['variables']['v8_enable_javascript_promise_hooks'] = 1 o['variables']['v8_enable_lite_mode'] = 1 if options.v8_lite_mode else 0 diff --git a/src/node.h b/src/node.h -index 835c78145956de3d8c52b6cc0581bcfef600f90b..174fd4d1af4c8cd75aec09f4548a674fd5539fb2 100644 +index c5ade4bd30456cde33379c6202b65709650d3ec0..f7b3f90b0c2cfbeacc5bc50112dd711df8d3c364 100644 --- a/src/node.h +++ b/src/node.h @@ -22,6 +22,12 @@ diff --git a/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch b/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch index 8b7051b7f036c..57afd30f2c38f 100644 --- a/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch +++ b/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch @@ -10,7 +10,7 @@ JS errors and ensures embedder JS is loaded via LoadEmbedderJavaScriptSource. That method is generated by our modifications to js2c.cc in the BUILD.gn patch diff --git a/lib/internal/fs/watchers.js b/lib/internal/fs/watchers.js -index 0244a214b187e67e0cb89f26cd019855963ec93a..b65a3be6bcb0e28f7f43367d0fa9da533db9d0d1 100644 +index 605dee28cace56f2366fec9d7f18894559044ae4..15dcabb3b1682438eb6d5a681363b7ea8602b9e7 100644 --- a/lib/internal/fs/watchers.js +++ b/lib/internal/fs/watchers.js @@ -299,12 +299,13 @@ function emitCloseNT(self) { @@ -34,10 +34,10 @@ index 0244a214b187e67e0cb89f26cd019855963ec93a..b65a3be6bcb0e28f7f43367d0fa9da53 let kResistStopPropagation; diff --git a/src/node_builtins.cc b/src/node_builtins.cc -index 8b104e175ccf8de90c138337f83f8f6ce1348ac7..35cf42a5e533cb799bf129df0c8370bfe8310233 100644 +index e43e2559aaf48add88aad342b1c96fd34f26c87f..e69eb280050cae0c0f394b2f956eef947e628904 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc -@@ -35,6 +35,7 @@ using v8::Value; +@@ -39,6 +39,7 @@ using v8::Value; BuiltinLoader::BuiltinLoader() : config_(GetConfig()), code_cache_(std::make_shared<BuiltinCodeCache>()) { LoadJavaScriptSource(); @@ -46,10 +46,10 @@ index 8b104e175ccf8de90c138337f83f8f6ce1348ac7..35cf42a5e533cb799bf129df0c8370bf AddExternalizedBuiltin( "internal/deps/cjs-module-lexer/lexer", diff --git a/src/node_builtins.h b/src/node_builtins.h -index 302030f610965f07dd6998d282275c1bdf738009..35cb7766eeccc62dd2f0ce9484a2f1ec7beccc05 100644 +index bcdd50f635757f41287c87df1db9cd3b55c4b6b9..e908f3c0e314b90ff7b6c599940ea8f4e657c709 100644 --- a/src/node_builtins.h +++ b/src/node_builtins.h -@@ -138,6 +138,7 @@ class NODE_EXTERN_PRIVATE BuiltinLoader { +@@ -141,6 +141,7 @@ class NODE_EXTERN_PRIVATE BuiltinLoader { // Generated by tools/js2c.cc as node_javascript.cc void LoadJavaScriptSource(); // Loads data into source_ diff --git a/patches/node/build_restore_clang_as_default_compiler_on_macos.patch b/patches/node/build_restore_clang_as_default_compiler_on_macos.patch index 88f7586d58c69..a1f987b2b7105 100644 --- a/patches/node/build_restore_clang_as_default_compiler_on_macos.patch +++ b/patches/node/build_restore_clang_as_default_compiler_on_macos.patch @@ -11,7 +11,7 @@ node-gyp will use the result of `process.config` that reflects the environment in which the binary got built. diff --git a/common.gypi b/common.gypi -index 2caa183213d5632be81b763e894e37c09384391f..2cce436c4a9e3d942f957f6c94a4ef9e3db391ce 100644 +index aea3a882c338eb757bef9e85fabab3fc7e7495f7..9303217fb05190c734e410a524a6921723d665d5 100644 --- a/common.gypi +++ b/common.gypi @@ -128,6 +128,7 @@ diff --git a/patches/node/chore_add_createexternalizabletwobytestring_to_globals.patch b/patches/node/chore_add_createexternalizabletwobytestring_to_globals.patch deleted file mode 100644 index d9578359a44e9..0000000000000 --- a/patches/node/chore_add_createexternalizabletwobytestring_to_globals.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: John Kleinschmidt <jkleinsc@electronjs.org> -Date: Fri, 28 Feb 2025 11:24:53 -0500 -Subject: chore: add createExternalizableTwoByteString to globals - -https://chromium-review.googlesource.com/c/v8/v8/+/6304942 added -createExternalizableTwoByteString, so make sure it is handled -as a global in the parallel/test-fs-write test. - -diff --git a/test/parallel/test-fs-write.js b/test/parallel/test-fs-write.js -index 82f3425de2aa162aa97047098806a08d0f8be4bd..31ab5b833db94fec6f2e976f53f650bc6318e794 100644 ---- a/test/parallel/test-fs-write.js -+++ b/test/parallel/test-fs-write.js -@@ -48,6 +48,7 @@ assert.notStrictEqual(isOneByteString, undefined); - // Account for extra globals exposed by --expose_externalize_string. - common.allowGlobals( - createExternalizableString, -+ createExternalizableTwoByteString, - externalizeString, - isOneByteString, - globalThis.x, diff --git a/patches/node/chore_add_missing_include_of_iterator.patch b/patches/node/chore_add_missing_include_of_iterator.patch deleted file mode 100644 index c04928baba59d..0000000000000 --- a/patches/node/chore_add_missing_include_of_iterator.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Sanders <dsanders11@ucsbalum.com> -Date: Mon, 21 Jul 2025 16:58:56 -0700 -Subject: chore: add missing include of <iterator> - -This has been upstreamed at https://github.com/ada-url/ada/pull/982 - -diff --git a/deps/ada/ada.cpp b/deps/ada/ada.cpp -index d7f9b3a92c5330dad1cbd9f6f0bdd96908a4ad13..68fe0701bced5db86834ebd8232d4fe5ae7ed308 100644 ---- a/deps/ada/ada.cpp -+++ b/deps/ada/ada.cpp -@@ -11217,6 +11217,7 @@ ada_warn_unused std::string to_string(ada::state state) { - - #include <numeric> - #include <algorithm> -+#include <iterator> - #include <string> - - namespace ada { -@@ -13067,6 +13068,7 @@ template url_aggregator parse_url<url_aggregator>( - /* end file src/parser.cpp */ - /* begin file src/url_components.cpp */ - -+#include <iterator> - #include <numeric> - #include <string> - -@@ -13192,6 +13194,7 @@ namespace ada { - /* end file src/url_components.cpp */ - /* begin file src/url_aggregator.cpp */ - -+#include <iterator> - #include <string> - #include <string_view> - diff --git a/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch b/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch index a2901455347a2..2c56c247edae8 100644 --- a/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch +++ b/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch @@ -8,10 +8,10 @@ they use themselves as the entry point. We should try to upstream some form of this. diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js -index 0cda54fd85e1e0bff13d4718a269eb3e7c60312a..6b165062a5eaa40f6e5614bca50bc33ccbdb85cc 100644 +index c7f86098bdb00b6be84d547a0ac41919fa1bbb0f..35b43990c8f24f0888f89173f5662050a11b26ed 100644 --- a/lib/internal/process/pre_execution.js +++ b/lib/internal/process/pre_execution.js -@@ -245,12 +245,14 @@ function patchProcessObject(expandArgv1) { +@@ -243,12 +243,14 @@ function patchProcessObject(expandArgv1) { // the entry point. if (expandArgv1 && process.argv[1] && process.argv[1][0] !== '-') { // Expand process.argv[1] into a full path. diff --git a/patches/node/chore_exclude_electron_node_folder_from_exit-time-destructors.patch b/patches/node/chore_exclude_electron_node_folder_from_exit-time-destructors.patch new file mode 100644 index 0000000000000..b044a2d5f9df9 --- /dev/null +++ b/patches/node/chore_exclude_electron_node_folder_from_exit-time-destructors.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 <hop2deep@gmail.com> +Date: Mon, 1 Sep 2025 03:12:06 +0900 +Subject: chore: exclude electron_node folder from exit-time-destructors + +Refs https://issues.chromium.org/issues/430332953 +It contains multiple third_party dependencies that doesn't +align with the chromium style guide. + +diff --git a/deps/ada/unofficial.gni b/deps/ada/unofficial.gni +index ab7dc27de3e304f6d912d5834da47e3b4eb25495..b6c0fd4ceee989dac55c7d54e52fef183ab4621c 100644 +--- a/deps/ada/unofficial.gni ++++ b/deps/ada/unofficial.gni +@@ -20,6 +20,7 @@ template("ada_gn_build") { + source_set(target_name) { + forward_variables_from(invoker, "*") + public_configs = [ ":ada_config" ] ++ configs += [ "//build/config/compiler:no_exit_time_destructors" ] + sources = gypi_values.ada_sources + } + } +diff --git a/unofficial.gni b/unofficial.gni +index 253226009faf563f6db285d4b2908f308c1f96ea..dd686d2f7c8d2f6e8d6bd13a7bf2b4b140556ba9 100644 +--- a/unofficial.gni ++++ b/unofficial.gni +@@ -143,7 +143,10 @@ template("node_gn_build") { + [ "node.gyp" ]) + + source_set("libnode") { +- configs += [ ":node_internal_config" ] ++ configs += [ ++ ":node_internal_config", ++ "//build/config/compiler:no_exit_time_destructors" ++ ] + public_configs = [ + ":node_external_config", + "deps/googletest:googletest_config", +@@ -362,6 +365,7 @@ template("node_gn_build") { + "src/embedded_data.h", + ] + include_dirs = [ "src", "tools" ] ++ configs += [ "//build/config/compiler:no_exit_time_destructors" ] + + if (!is_win) { + defines += [ "NODE_JS2C_USE_STRING_LITERALS" ] diff --git a/patches/node/chore_expose_importmoduledynamically_and.patch b/patches/node/chore_expose_importmoduledynamically_and.patch index 3f44ec26449ef..4a0b9dff2e174 100644 --- a/patches/node/chore_expose_importmoduledynamically_and.patch +++ b/patches/node/chore_expose_importmoduledynamically_and.patch @@ -11,10 +11,10 @@ its own blended handler between Node and Blink. Not upstreamable. diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js -index 9b41db8b0714b7408f79cbd5b4c460d9bc08f239..35ecfb9bbaf2c8e7351e1c69da84c82a4a7cb049 100644 +index 4a4279459341e87784ee8efa832dc74371c4a708..88d84786e72cf8712e0b9bda16c418d4087fe549 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js -@@ -30,7 +30,7 @@ const { +@@ -34,7 +34,7 @@ const { ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING, ERR_INVALID_ARG_VALUE, } = require('internal/errors').codes; @@ -23,8 +23,8 @@ index 9b41db8b0714b7408f79cbd5b4c460d9bc08f239..35ecfb9bbaf2c8e7351e1c69da84c82a const { loadPreloadModules, initializeFrozenIntrinsics, -@@ -281,12 +281,13 @@ let _forceDefaultLoader = false; - * @param {boolean} [forceDefaultLoader=false] - A boolean indicating disabling custom loaders. +@@ -291,12 +291,13 @@ let _forceDefaultLoader = false; + * @param {boolean} [forceDefaultLoader] - A boolean indicating disabling custom loaders. */ function initializeESM(forceDefaultLoader = false) { + const shouldSetOnIsolate = !getEmbedderOptions().shouldNotRegisterESMLoader; @@ -40,19 +40,19 @@ index 9b41db8b0714b7408f79cbd5b4c460d9bc08f239..35ecfb9bbaf2c8e7351e1c69da84c82a /** diff --git a/src/module_wrap.cc b/src/module_wrap.cc -index e317a84e55714af0a93719336d02ac26410ad724..e3880111172363feafb53b51deb08c93596cd4f4 100644 +index 5783728da2894270f902f47b210008df0e911bde..8fed194cbae9ce75bd0805b4df30b4de64fbbefa 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc -@@ -895,7 +895,7 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( - return module->module_.Get(isolate); +@@ -1097,7 +1097,7 @@ Maybe<ModuleWrap*> ModuleWrap::ResolveModule( + return Just(module_wrap); } --static MaybeLocal<Promise> ImportModuleDynamically( -+MaybeLocal<Promise> ImportModuleDynamically( +-static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase( ++MaybeLocal<Promise> ImportModuleDynamicallyWithPhase( Local<Context> context, Local<Data> host_defined_options, Local<Value> resource_name, -@@ -967,12 +967,13 @@ void ModuleWrap::SetImportModuleDynamicallyCallback( +@@ -1185,14 +1185,16 @@ void ModuleWrap::SetImportModuleDynamicallyCallback( Realm* realm = Realm::GetCurrent(args); HandleScope handle_scope(isolate); @@ -63,12 +63,16 @@ index e317a84e55714af0a93719336d02ac26410ad724..e3880111172363feafb53b51deb08c93 realm->set_host_import_module_dynamically_callback(import_callback); - isolate->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically); -+ if (args[1]->IsBoolean() && args[1]->BooleanValue(isolate)) +- isolate->SetHostImportModuleWithPhaseDynamicallyCallback( ++ if (args[1]->IsBoolean() && args[1]->BooleanValue(isolate)) { + isolate->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically); ++ isolate->SetHostImportModuleWithPhaseDynamicallyCallback( + ImportModuleDynamicallyWithPhase); ++ } } void ModuleWrap::HostInitializeImportMetaObjectCallback( -@@ -1014,13 +1015,14 @@ void ModuleWrap::SetInitializeImportMetaObjectCallback( +@@ -1234,13 +1236,14 @@ void ModuleWrap::SetInitializeImportMetaObjectCallback( Realm* realm = Realm::GetCurrent(args); Isolate* isolate = realm->isolate(); @@ -87,7 +91,7 @@ index e317a84e55714af0a93719336d02ac26410ad724..e3880111172363feafb53b51deb08c93 MaybeLocal<Value> ModuleWrap::SyntheticModuleEvaluationStepsCallback( diff --git a/src/module_wrap.h b/src/module_wrap.h -index 9363ce73e51cde3d3a94f9912f072d532d0f8560..c0e972ed293157726efc5fa76dfa62d3da51c22a 100644 +index 03cf8d0e91d795aad6db9b11956d296ff4999f7e..45264c2ad58e37a73fd62addac7fb671eed6d502 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -8,6 +8,7 @@ @@ -98,23 +102,24 @@ index 9363ce73e51cde3d3a94f9912f072d532d0f8560..c0e972ed293157726efc5fa76dfa62d3 #include "v8-script.h" namespace node { -@@ -33,7 +34,14 @@ enum HostDefinedOptions : int { - kLength = 9, +@@ -92,7 +93,15 @@ struct ModuleCacheKey : public MemoryRetainer { + hash(hash) {} }; -class ModuleWrap : public BaseObject { -+NODE_EXTERN v8::MaybeLocal<v8::Promise> ImportModuleDynamically( ++NODE_EXTERN v8::MaybeLocal<v8::Promise> ImportModuleDynamicallyWithPhase( + v8::Local<v8::Context> context, + v8::Local<v8::Data> host_defined_options, + v8::Local<v8::Value> resource_name, + v8::Local<v8::String> specifier, -+ v8::Local<v8::FixedArray> import_assertions); ++ v8::ModuleImportPhase phase, ++ v8::Local<v8::FixedArray> import_attributes); + +class NODE_EXTERN ModuleWrap : public BaseObject { - public: - enum InternalFields { - kModuleSlot = BaseObject::kInternalFieldCount, -@@ -92,6 +100,8 @@ class ModuleWrap : public BaseObject { + using ResolveCache = + std::unordered_map<ModuleCacheKey, uint32_t, ModuleCacheKey::Hash>; + +@@ -157,6 +166,8 @@ class ModuleWrap : public BaseObject { static void CreateRequiredModuleFacade( const v8::FunctionCallbackInfo<v8::Value>& args); @@ -123,11 +128,11 @@ index 9363ce73e51cde3d3a94f9912f072d532d0f8560..c0e972ed293157726efc5fa76dfa62d3 private: ModuleWrap(Realm* realm, v8::Local<v8::Object> object, -@@ -131,7 +141,6 @@ class ModuleWrap : public BaseObject { +@@ -205,7 +216,6 @@ class ModuleWrap : public BaseObject { v8::Local<v8::String> specifier, v8::Local<v8::FixedArray> import_attributes, v8::Local<v8::Module> referrer); - static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>); - v8::Global<v8::Module> module_; - std::unordered_map<std::string, v8::Global<v8::Object>> resolve_cache_; + // This method may throw a JavaScript exception, so the return type is + // wrapped in a Maybe. diff --git a/patches/node/chore_handle_support_for_import_defer_as_ns_and_import_defer.patch b/patches/node/chore_handle_support_for_import_defer_as_ns_and_import_defer.patch new file mode 100644 index 0000000000000..dffa0560f0f09 --- /dev/null +++ b/patches/node/chore_handle_support_for_import_defer_as_ns_and_import_defer.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr <shelley.vohr@gmail.com> +Date: Wed, 29 Oct 2025 11:45:23 +0000 +Subject: chore: handle support for `import defer * as ns` and `import.defer` + syntax + +V8 added support for the above syntax https://chromium-review.googlesource.com/c/v8/v8/+/7017517 +by adding a new `ModuleImportPhase::kDefer` phase. + +This patch can be removed when Electron updates to a version of Node.js containing +the above CL. + +diff --git a/src/module_wrap.cc b/src/module_wrap.cc +index a584e3a80adb69d2028dc79450349823ab973a58..6f010fa2e014b2d13b1f89a691d09e2ffdf690b6 100644 +--- a/src/module_wrap.cc ++++ b/src/module_wrap.cc +@@ -563,8 +563,10 @@ ModulePhase to_phase_constant(ModuleImportPhase phase) { + return kEvaluationPhase; + case ModuleImportPhase::kSource: + return kSourcePhase; ++ case ModuleImportPhase::kDefer: ++ default: ++ UNREACHABLE(); + } +- UNREACHABLE(); + } + + static Local<Object> createImportAttributesContainer( +@@ -1471,6 +1473,7 @@ void ModuleWrap::CreatePerContextProperties(Local<Object> target, + + V(ModulePhase, kEvaluationPhase); + V(ModulePhase, kSourcePhase); ++ V(ModulePhase, kDeferPhase); + #undef V + } + +diff --git a/src/module_wrap.h b/src/module_wrap.h +index 45264c2ad58e37a73fd62addac7fb671eed6d502..fb32fbc5c1cfa4aef4a7822dbc6195429299da3e 100644 +--- a/src/module_wrap.h ++++ b/src/module_wrap.h +@@ -37,6 +37,7 @@ enum HostDefinedOptions : int { + enum ModulePhase : int { + kSourcePhase = 1, + kEvaluationPhase = 2, ++ kDeferPhase = 3, + }; + + /** diff --git a/patches/node/cli_move_--trace-atomics-wait_to_eol.patch b/patches/node/cli_move_--trace-atomics-wait_to_eol.patch deleted file mode 100644 index dae7ed917b98d..0000000000000 --- a/patches/node/cli_move_--trace-atomics-wait_to_eol.patch +++ /dev/null @@ -1,305 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Marco Ippolito <marcoippolito54@gmail.com> -Date: Wed, 1 May 2024 14:24:48 +0200 -Subject: cli: move --trace-atomics-wait to eol -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -PR-URL: https://github.com/nodejs/node/pull/52747 -Fixes: https://github.com/nodejs/node/issues/42982 -Reviewed-By: Matteo Collina <matteo.collina@gmail.com> -Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> -Reviewed-By: Michaël Zasso <targos@protonmail.com> -Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> -Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io> - -diff --git a/doc/api/cli.md b/doc/api/cli.md -index 404e87e6d1237b5ee79cafd8a959c1b6d9d23fe5..7deda572c940f7b2e8c6813f1826796a13e4db38 100644 ---- a/doc/api/cli.md -+++ b/doc/api/cli.md -@@ -2709,39 +2709,6 @@ added: v12.0.0 - Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1.3'. Use to disable support - for TLSv1.2, which is not as secure as TLSv1.3. - --### `--trace-atomics-wait` -- --<!-- YAML --added: v14.3.0 --deprecated: -- - v18.8.0 -- - v16.18.0 ----> -- --> Stability: 0 - Deprecated -- --Print short summaries of calls to [`Atomics.wait()`][] to stderr. --The output could look like this: -- --```text --(node:15701) [Thread 0] Atomics.wait(<address> + 0, 1, inf) started --(node:15701) [Thread 0] Atomics.wait(<address> + 0, 1, inf) did not wait because the values mismatched --(node:15701) [Thread 0] Atomics.wait(<address> + 0, 0, 10) started --(node:15701) [Thread 0] Atomics.wait(<address> + 0, 0, 10) timed out --(node:15701) [Thread 0] Atomics.wait(<address> + 4, 0, inf) started --(node:15701) [Thread 1] Atomics.wait(<address> + 4, -1, inf) started --(node:15701) [Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --(node:15701) [Thread 1] Atomics.wait(<address> + 4, -1, inf) was woken up by another thread --``` -- --The fields here correspond to: -- --* The thread id as given by [`worker_threads.threadId`][] --* The base address of the `SharedArrayBuffer` in question, as well as the -- byte offset corresponding to the index passed to `Atomics.wait()` --* The expected value that was passed to `Atomics.wait()` --* The timeout passed to `Atomics.wait` -- - ### `--trace-deprecation` - - <!-- YAML -@@ -3423,7 +3390,6 @@ one is included in the list below. - * `--tls-min-v1.1` - * `--tls-min-v1.2` - * `--tls-min-v1.3` --* `--trace-atomics-wait` - * `--trace-deprecation` - * `--trace-env-js-stack` - * `--trace-env-native-stack` -diff --git a/doc/node.1 b/doc/node.1 -index f41323c799ad34c8e17a36d81e4cc2b16e50e9ee..a9ff54edfad1d053ec1ac544f28e14a1898ac177 100644 ---- a/doc/node.1 -+++ b/doc/node.1 -@@ -539,11 +539,6 @@ but the option is supported for compatibility with older Node.js versions. - Set default minVersion to 'TLSv1.3'. Use to disable support for TLSv1.2 in - favour of TLSv1.3, which is more secure. - . --.It Fl -trace-atomics-wait --Print short summaries of calls to --.Sy Atomics.wait() . --. --This flag is deprecated. - .It Fl -trace-deprecation - Print stack traces for deprecations. - . -diff --git a/src/node.cc b/src/node.cc -index 0c2a4d344c991c2ca0d9d90934cf7921abf2a629..19d9fb77f1aaf003e43b7d7016f45e6c35df06b3 100644 ---- a/src/node.cc -+++ b/src/node.cc -@@ -232,44 +232,6 @@ void Environment::WaitForInspectorFrontendByOptions() { - } - #endif // HAVE_INSPECTOR - --#define ATOMIC_WAIT_EVENTS(V) \ -- V(kStartWait, "started") \ -- V(kWokenUp, "was woken up by another thread") \ -- V(kTimedOut, "timed out") \ -- V(kTerminatedExecution, "was stopped by terminated execution") \ -- V(kAPIStopped, "was stopped through the embedder API") \ -- V(kNotEqual, "did not wait because the values mismatched") \ -- --static void AtomicsWaitCallback(Isolate::AtomicsWaitEvent event, -- Local<v8::SharedArrayBuffer> array_buffer, -- size_t offset_in_bytes, int64_t value, -- double timeout_in_ms, -- Isolate::AtomicsWaitWakeHandle* stop_handle, -- void* data) { -- Environment* env = static_cast<Environment*>(data); -- -- const char* message = "(unknown event)"; -- switch (event) { --#define V(key, msg) \ -- case Isolate::AtomicsWaitEvent::key: \ -- message = msg; \ -- break; -- ATOMIC_WAIT_EVENTS(V) --#undef V -- } -- -- fprintf(stderr, -- "(node:%d) [Thread %" PRIu64 "] Atomics.wait(%p + %zx, %" PRId64 -- ", %.f) %s\n", -- static_cast<int>(uv_os_getpid()), -- env->thread_id(), -- array_buffer->Data(), -- offset_in_bytes, -- value, -- timeout_in_ms, -- message); --} -- - void Environment::InitializeDiagnostics() { - isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback( - Environment::BuildEmbedderGraph, this); -@@ -278,17 +240,6 @@ void Environment::InitializeDiagnostics() { - } - if (options_->trace_uncaught) - isolate_->SetCaptureStackTraceForUncaughtExceptions(true); -- if (options_->trace_atomics_wait) { -- ProcessEmitDeprecationWarning( -- Environment::GetCurrent(isolate_), -- "The flag --trace-atomics-wait is deprecated.", -- "DEP0165"); -- isolate_->SetAtomicsWaitCallback(AtomicsWaitCallback, this); -- AddCleanupHook([](void* data) { -- Environment* env = static_cast<Environment*>(data); -- env->isolate()->SetAtomicsWaitCallback(nullptr, nullptr); -- }, this); -- } - if (options_->trace_promises) { - isolate_->SetPromiseHook(TracePromises); - } -diff --git a/src/node_options.cc b/src/node_options.cc -index d6988a5a8c068022d10607c32e57ac667f821337..4deaa52a8a4688bca32d41b74124604b6e33c80b 100644 ---- a/src/node_options.cc -+++ b/src/node_options.cc -@@ -773,10 +773,6 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { - "throw an exception on deprecations", - &EnvironmentOptions::throw_deprecation, - kAllowedInEnvvar); -- AddOption("--trace-atomics-wait", -- "(deprecated) trace Atomics.wait() operations", -- &EnvironmentOptions::trace_atomics_wait, -- kAllowedInEnvvar); - AddOption("--trace-deprecation", - "show stack traces on deprecations", - &EnvironmentOptions::trace_deprecation, -diff --git a/src/node_options.h b/src/node_options.h -index 2b7df46312b8be58d6062b6a2f6084247e075c37..2d52cde518926577834f77424fa5b2231ca3374e 100644 ---- a/src/node_options.h -+++ b/src/node_options.h -@@ -204,7 +204,6 @@ class EnvironmentOptions : public Options { - std::vector<std::string> coverage_include_pattern; - std::vector<std::string> coverage_exclude_pattern; - bool throw_deprecation = false; -- bool trace_atomics_wait = false; - bool trace_deprecation = false; - bool trace_exit = false; - bool trace_sync_io = false; -diff --git a/test/parallel/test-trace-atomic-deprecation.js b/test/parallel/test-trace-atomic-deprecation.js -deleted file mode 100644 -index 8aeddb28e938d23e646d882cfe24b2e2311f9ab2..0000000000000000000000000000000000000000 ---- a/test/parallel/test-trace-atomic-deprecation.js -+++ /dev/null -@@ -1,14 +0,0 @@ --'use strict'; -- --const common = require('../common'); --const assert = require('node:assert'); --const { test } = require('node:test'); -- --test('should emit deprecation warning DEP0165', async () => { -- const { code, stdout, stderr } = await common.spawnPromisified( -- process.execPath, ['--trace-atomics-wait', '-e', '{}'] -- ); -- assert.match(stderr, /\[DEP0165\] DeprecationWarning:/); -- assert.strictEqual(stdout, ''); -- assert.strictEqual(code, 0); --}); -diff --git a/test/parallel/test-trace-atomics-wait.js b/test/parallel/test-trace-atomics-wait.js -deleted file mode 100644 -index 6449a2be2b47e0758090dc13d136877b1874c635..0000000000000000000000000000000000000000 ---- a/test/parallel/test-trace-atomics-wait.js -+++ /dev/null -@@ -1,101 +0,0 @@ --'use strict'; --require('../common'); --const assert = require('assert'); --const child_process = require('child_process'); --const { Worker } = require('worker_threads'); -- --if (process.argv[2] === 'child') { -- const i32arr = new Int32Array(new SharedArrayBuffer(8)); -- assert.strictEqual(Atomics.wait(i32arr, 0, 1), 'not-equal'); -- assert.strictEqual(Atomics.wait(i32arr, 0, 0, 10), 'timed-out'); -- -- new Worker(` -- const i32arr = require('worker_threads').workerData; -- Atomics.store(i32arr, 1, -1); -- Atomics.notify(i32arr, 1); -- Atomics.wait(i32arr, 1, -1); -- `, { eval: true, workerData: i32arr }); -- -- Atomics.wait(i32arr, 1, 0); -- assert.strictEqual(Atomics.load(i32arr, 1), -1); -- Atomics.store(i32arr, 1, 0); -- Atomics.notify(i32arr, 1); -- return; --} -- --const proc = child_process.spawnSync( -- process.execPath, -- [ '--disable-warning=DEP0165', '--trace-atomics-wait', __filename, 'child' ], -- { encoding: 'utf8', stdio: [ 'inherit', 'inherit', 'pipe' ] }); -- --if (proc.status !== 0) console.log(proc); --assert.strictEqual(proc.status, 0); -- --const SABAddress = proc.stderr.match(/Atomics\.wait\((?<SAB>.+) \+/).groups.SAB; --const actualTimeline = proc.stderr -- .replace(new RegExp(SABAddress, 'g'), '<address>') -- .replace(new RegExp(`\\(node:${proc.pid}\\) `, 'g'), '') -- .replace(/\binf(inity)?\b/gi, 'inf') -- .replace(/\r/g, '') -- .trim(); --console.log('+++ normalized stdout +++'); --console.log(actualTimeline); --console.log('--- normalized stdout ---'); -- --const begin = --`[Thread 0] Atomics.wait(<address> + 0, 1, inf) started --[Thread 0] Atomics.wait(<address> + 0, 1, inf) did not wait because the \ --values mismatched --[Thread 0] Atomics.wait(<address> + 0, 0, 10) started --[Thread 0] Atomics.wait(<address> + 0, 0, 10) timed out`; -- --const expectedTimelines = [ -- `${begin} --[Thread 0] Atomics.wait(<address> + 4, 0, inf) started --[Thread 1] Atomics.wait(<address> + 4, -1, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --[Thread 1] Atomics.wait(<address> + 4, -1, inf) was woken up by another thread`, -- `${begin} --[Thread 1] Atomics.wait(<address> + 4, 0, inf) started --[Thread 0] Atomics.wait(<address> + 4, -1, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --[Thread 1] Atomics.wait(<address> + 4, -1, inf) was woken up by another thread`, -- `${begin} --[Thread 0] Atomics.wait(<address> + 4, 0, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --[Thread 1] Atomics.wait(<address> + 4, -1, inf) started --[Thread 1] Atomics.wait(<address> + 4, -1, inf) was woken up by another thread`, -- `${begin} --[Thread 0] Atomics.wait(<address> + 4, 0, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --[Thread 1] Atomics.wait(<address> + 4, -1, inf) started --[Thread 1] Atomics.wait(<address> + 4, -1, inf) did not wait because the \ --values mismatched`, -- `${begin} --[Thread 0] Atomics.wait(<address> + 4, 0, inf) started --[Thread 1] Atomics.wait(<address> + 4, -1, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --[Thread 1] Atomics.wait(<address> + 4, -1, inf) did not wait because the \ --values mismatched`, -- `${begin} --[Thread 1] Atomics.wait(<address> + 4, 0, inf) started --[Thread 0] Atomics.wait(<address> + 4, -1, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) was woken up by another thread --[Thread 1] Atomics.wait(<address> + 4, -1, inf) did not wait because the \ --values mismatched`, -- `${begin} --[Thread 0] Atomics.wait(<address> + 4, 0, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) did not wait because the \ --values mismatched --[Thread 1] Atomics.wait(<address> + 4, -1, inf) started --[Thread 1] Atomics.wait(<address> + 4, -1, inf) did not wait because the \ --values mismatched`, -- `${begin} --[Thread 1] Atomics.wait(<address> + 4, -1, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) started --[Thread 0] Atomics.wait(<address> + 4, 0, inf) did not wait because the \ --values mismatched --[Thread 1] Atomics.wait(<address> + 4, -1, inf) was woken up by another thread`, --]; -- --assert(expectedTimelines.includes(actualTimeline)); diff --git a/patches/node/cli_remove_deprecated_v8_flag.patch b/patches/node/cli_remove_deprecated_v8_flag.patch deleted file mode 100644 index f1d7fb80b0b5a..0000000000000 --- a/patches/node/cli_remove_deprecated_v8_flag.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Omer Katz <omerkatz@chromium.org> -Date: Thu, 19 Sep 2024 10:50:09 +0200 -Subject: cli: remove deprecated V8 flag -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Remove the `--huge-max-old-generation-size` V8 flag from the -`NODE_OPTIONS` allowlist. That flag was recently deprecated (it -currently remains as nop, see crrev.com/c/5831467) and will soon be -completely removed. - -PR-URL: https://github.com/nodejs/node/pull/54761 -Reviewed-By: Richard Lau <rlau@redhat.com> -Reviewed-By: Luigi Pinca <luigipinca@gmail.com> -Reviewed-By: Michaël Zasso <targos@protonmail.com> -Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> - -diff --git a/doc/api/cli.md b/doc/api/cli.md -index 78c0794a57fd4fdcdd8a64fe98a6b13f9ef3f23a..404e87e6d1237b5ee79cafd8a959c1b6d9d23fe5 100644 ---- a/doc/api/cli.md -+++ b/doc/api/cli.md -@@ -3461,7 +3461,6 @@ V8 options that are allowed are: - * `--disallow-code-generation-from-strings` - * `--enable-etw-stack-walking` - * `--expose-gc` --* `--huge-max-old-generation-size` - * `--interpreted-frames-native-stack` - * `--jitless` - * `--max-old-space-size` -diff --git a/src/node_options.cc b/src/node_options.cc -index 367f7d9b1450e4d9e6d8fef36a2234e7d1344804..d6988a5a8c068022d10607c32e57ac667f821337 100644 ---- a/src/node_options.cc -+++ b/src/node_options.cc -@@ -1001,11 +1001,6 @@ PerIsolateOptionsParser::PerIsolateOptionsParser( - "disallow eval and friends", - V8Option{}, - kAllowedInEnvvar); -- AddOption("--huge-max-old-generation-size", -- "increase default maximum heap size on machines with 16GB memory " -- "or more", -- V8Option{}, -- kAllowedInEnvvar); - AddOption("--jitless", - "disable runtime allocation of executable memory", - V8Option{}, -diff --git a/test/parallel/test-cli-node-options.js b/test/parallel/test-cli-node-options.js -index c5d74f40e7894980b45713c77cc36f836be73528..53bca572c3405c0357f868aae71fc2c82d973c04 100644 ---- a/test/parallel/test-cli-node-options.js -+++ b/test/parallel/test-cli-node-options.js -@@ -76,7 +76,6 @@ if (common.hasCrypto) { - expect('--abort_on-uncaught_exception', 'B\n'); - expect('--disallow-code-generation-from-strings', 'B\n'); - expect('--expose-gc', 'B\n'); --expect('--huge-max-old-generation-size', 'B\n'); - expect('--jitless', 'B\n'); - expect('--max-old-space-size=0', 'B\n'); - expect('--max-semi-space-size=0', 'B\n'); diff --git a/patches/node/enable_crashpad_linux_node_processes.patch b/patches/node/enable_crashpad_linux_node_processes.patch index b874729cbe31e..f4cf91f463086 100644 --- a/patches/node/enable_crashpad_linux_node_processes.patch +++ b/patches/node/enable_crashpad_linux_node_processes.patch @@ -8,7 +8,7 @@ to child processes spawned with `ELECTRON_RUN_AS_NODE` which is used by the crashpad client to connect with the handler process. diff --git a/lib/child_process.js b/lib/child_process.js -index 655349b6fa17217a9202616224032a36fd01e284..bf62c5adf0e0d75cb50636f365f71db82c29ba29 100644 +index 17c6b69c118a759f9fcf254a035f1a07fcc4059f..c8576fbf889d13f951a9ad2ffeb93389cfe2445b 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -62,6 +62,7 @@ let debug = require('internal/util/debuglog').debuglog( @@ -27,7 +27,7 @@ index 655349b6fa17217a9202616224032a36fd01e284..bf62c5adf0e0d75cb50636f365f71db8 args = [...execArgv, modulePath, ...args]; if (typeof options.stdio === 'string') { -@@ -637,6 +637,22 @@ function normalizeSpawnArguments(file, args, options) { +@@ -638,6 +638,22 @@ function normalizeSpawnArguments(file, args, options) { 'options.windowsVerbatimArguments'); } @@ -49,8 +49,8 @@ index 655349b6fa17217a9202616224032a36fd01e284..bf62c5adf0e0d75cb50636f365f71db8 + if (options.shell) { validateArgumentNullCheck(options.shell, 'options.shell'); - const command = ArrayPrototypeJoin([file, ...args], ' '); -@@ -670,8 +686,6 @@ function normalizeSpawnArguments(file, args, options) { + if (args.length > 0 && !emittedDEP0190Already) { +@@ -680,8 +696,6 @@ function normalizeSpawnArguments(file, args, options) { ArrayPrototypeUnshift(args, file); } diff --git a/patches/node/expose_get_builtin_module_function.patch b/patches/node/expose_get_builtin_module_function.patch index 8b95ccbe3290c..eb7db1059f544 100644 --- a/patches/node/expose_get_builtin_module_function.patch +++ b/patches/node/expose_get_builtin_module_function.patch @@ -9,10 +9,10 @@ modules to sandboxed renderers. TODO(codebytere): remove and replace with a public facing API. diff --git a/src/node_binding.cc b/src/node_binding.cc -index aa4213c3622eab077fa8d764775c1f95c6313e34..11f722d2d7c21079cbc65033429086231a786ca7 100644 +index 5bd07e5253ae64b02ae1874226ab70c1972cf9e0..768d81a63a42d9016a42b7cdce7b6be86c59afdf 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc -@@ -652,6 +652,10 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) { +@@ -655,6 +655,10 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) { args.GetReturnValue().Set(exports); } @@ -24,10 +24,10 @@ index aa4213c3622eab077fa8d764775c1f95c6313e34..11f722d2d7c21079cbc6503342908623 Environment* env = Environment::GetCurrent(args); diff --git a/src/node_binding.h b/src/node_binding.h -index 611f38ef5e21cc303127326d50c648fbb557b4da..3d95ad2733dc83d0b7d37d57c337732c8a0e83d7 100644 +index 813204dc473960e63896b6d3609a882b52ac59fa..2fe91a28460973b543f5dde7a78fdedb05ac98b3 100644 --- a/src/node_binding.h +++ b/src/node_binding.h -@@ -154,6 +154,8 @@ void GetInternalBinding(const v8::FunctionCallbackInfo<v8::Value>& args); +@@ -155,6 +155,8 @@ void GetInternalBinding(const v8::FunctionCallbackInfo<v8::Value>& args); void GetLinkedBinding(const v8::FunctionCallbackInfo<v8::Value>& args); void DLOpen(const v8::FunctionCallbackInfo<v8::Value>& args); diff --git a/patches/node/feat_disable_js_source_phase_imports_by_default.patch b/patches/node/feat_disable_js_source_phase_imports_by_default.patch new file mode 100644 index 0000000000000..a1de4431ef2df --- /dev/null +++ b/patches/node/feat_disable_js_source_phase_imports_by_default.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr <shelley.vohr@gmail.com> +Date: Wed, 22 Oct 2025 11:03:57 +0200 +Subject: feat: disable js source phase imports by default. + +Refs: +- https://chromium-review.googlesource.com/c/v8/v8/+/7003082 +- https://chromium-review.googlesource.com/c/chromium/src/+/6336964 +- https://github.com/nodejs/node/pull/56919 + +We need to disable source phase imports in renderer and worker processes - Chromium +disables them in content/renderer/render_process_impl.cc via and the process will +hard crash otherwise. + +They shouldn't be enabled by default in Node.js either as they are still not yet +Stage 3. + +Upstreamed in https://github.com/nodejs/node/pull/60364 + +diff --git a/src/node.cc b/src/node.cc +index 5713d49d859e1161e1d6703c0b6f3d717a5a9a34..829634c084cb91eb7f488dbdd48175a093dd6e12 100644 +--- a/src/node.cc ++++ b/src/node.cc +@@ -780,7 +780,7 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args, + env_opts->abort_on_uncaught_exception = true; + } + +- v8_args.emplace_back("--js-source-phase-imports"); ++ // v8_args.emplace_back("--js-source-phase-imports"); + + #ifdef __POSIX__ + // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the diff --git a/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch b/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch index 54cd7b6f5c2bb..37e9f425260c3 100644 --- a/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch +++ b/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch @@ -7,7 +7,7 @@ common.gypi is a file that's included in the node header bundle, despite the fact that we do not build node with gyp. diff --git a/common.gypi b/common.gypi -index 20135003dd040ebfb3661c81c89fde93ce00fbfb..33af43cd768c24b26d523f3db66eb8b9eb26859a 100644 +index 7727dfc4c62100cbd873ee4b34c6089ab4b638b1..29a912f58e7b522ae21fddac510946cbcbaaa4cc 100644 --- a/common.gypi +++ b/common.gypi @@ -91,6 +91,23 @@ diff --git a/patches/node/fix_add_source_location_for_v8_task_runner.patch b/patches/node/fix_add_source_location_for_v8_task_runner.patch deleted file mode 100644 index 43896b7b67e60..0000000000000 --- a/patches/node/fix_add_source_location_for_v8_task_runner.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: VerteDinde <vertedinde@electronjs.org> -Date: Mon, 29 Apr 2024 02:56:27 -0700 -Subject: fix: add source location for v8::Task Runner - -This patch corresponds with an upstream change which adds -Post*TaskImpl variants of v8::TaskRunner::Post*Task methods, -which take a v8::SourceLocation argument, and makes Post*Task -methods non-virtual. In the original CL, embedders are asked -to override the Post*TaskImpl methods. - -This patch can be removed when node's upstream makes a -corresponding change. - -CL: https://chromium-review.googlesource.com/c/v8/v8/+/5300826 - -diff --git a/src/node_platform.cc b/src/node_platform.cc -index 9c4c1e1db5fa7c0ca791e01d9be331e0957e9699..b438b3774d0aa7680fdbc6c6bf39a87893d221b2 100644 ---- a/src/node_platform.cc -+++ b/src/node_platform.cc -@@ -307,11 +307,13 @@ void PerIsolatePlatformData::FlushTasks(uv_async_t* handle) { - platform_data->FlushForegroundTasksInternal(); - } - --void PerIsolatePlatformData::PostIdleTask(std::unique_ptr<v8::IdleTask> task) { -+void PerIsolatePlatformData::PostIdleTaskImpl(std::unique_ptr<v8::IdleTask> task, -+ const v8::SourceLocation& location) { - UNREACHABLE(); - } - --void PerIsolatePlatformData::PostTask(std::unique_ptr<Task> task) { -+void PerIsolatePlatformData::PostTaskImpl(std::unique_ptr<Task> task, -+ const v8::SourceLocation& location) { - // The task can be posted from any V8 background worker thread, even when - // the foreground task runner is being cleaned up by Shutdown(). In that - // case, make sure we wait until the shutdown is completed (which leads -@@ -330,8 +332,10 @@ void PerIsolatePlatformData::PostTask(std::unique_ptr<Task> task) { - uv_async_send(flush_tasks_); - } - --void PerIsolatePlatformData::PostDelayedTask( -- std::unique_ptr<Task> task, double delay_in_seconds) { -+void PerIsolatePlatformData::PostDelayedTaskImpl( -+ std::unique_ptr<Task> task, -+ double delay_in_seconds, -+ const v8::SourceLocation& location) { - if (debug_log_level_ != PlatformDebugLogLevel::kNone) { - fprintf(stderr, - "\nPerIsolatePlatformData::PostDelayedTaskImpl %p %f", -@@ -353,13 +357,15 @@ void PerIsolatePlatformData::PostDelayedTask( - uv_async_send(flush_tasks_); - } - --void PerIsolatePlatformData::PostNonNestableTask(std::unique_ptr<Task> task) { -+void PerIsolatePlatformData::PostNonNestableTaskImpl(std::unique_ptr<Task> task, -+ const v8::SourceLocation& location) { - PostTask(std::move(task)); - } - --void PerIsolatePlatformData::PostNonNestableDelayedTask( -+void PerIsolatePlatformData::PostNonNestableDelayedTaskImpl( - std::unique_ptr<Task> task, -- double delay_in_seconds) { -+ double delay_in_seconds, -+ const v8::SourceLocation& location) { - PostDelayedTask(std::move(task), delay_in_seconds); - } - -diff --git a/src/node_platform.h b/src/node_platform.h -index af30ebeb0c8629ab86d1a55fd63610165abfbabf..a0222b4a1b074c6708e390d58d04221717069ac1 100644 ---- a/src/node_platform.h -+++ b/src/node_platform.h -@@ -80,18 +80,21 @@ class PerIsolatePlatformData : - ~PerIsolatePlatformData() override; - - std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner() override; -- void PostTask(std::unique_ptr<v8::Task> task) override; -- void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override; -- void PostDelayedTask(std::unique_ptr<v8::Task> task, -- double delay_in_seconds) override; -+ void PostTaskImpl(std::unique_ptr<v8::Task> task, const v8::SourceLocation&) override; -+ void PostIdleTaskImpl(std::unique_ptr<v8::IdleTask> task, const v8::SourceLocation&) override; -+ void PostDelayedTaskImpl(std::unique_ptr<v8::Task> task, -+ double delay_in_seconds, -+ const v8::SourceLocation&) override; - bool IdleTasksEnabled() override { return false; } - - // Non-nestable tasks are treated like regular tasks. - bool NonNestableTasksEnabled() const override { return true; } - bool NonNestableDelayedTasksEnabled() const override { return true; } -- void PostNonNestableTask(std::unique_ptr<v8::Task> task) override; -- void PostNonNestableDelayedTask(std::unique_ptr<v8::Task> task, -- double delay_in_seconds) override; -+ void PostNonNestableTaskImpl(std::unique_ptr<v8::Task> task, -+ const v8::SourceLocation&) override; -+ void PostNonNestableDelayedTaskImpl(std::unique_ptr<v8::Task> task, -+ double delay_in_seconds, -+ const v8::SourceLocation&) override; - - void AddShutdownCallback(void (*callback)(void*), void* data); - void Shutdown(); diff --git a/patches/node/fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch b/patches/node/fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch index c74ee34466051..a8c8f1b057183 100644 --- a/patches/node/fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch +++ b/patches/node/fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch @@ -11,31 +11,14 @@ Node.js upgrades to a version of V8 that has Float16Array enabled by default. diff --git a/test/common/globals.js b/test/common/globals.js -index 2c1dac019ba2aa0a23c2434997e2007dd2eacde8..152d9afa8f8ef6b76fceb0ac4481d1df719b872b 100644 +index 1641c4df36b92dbe29b06817d87130a94ae1b22f..34563b304f0e708ae066f8303a09e37b6bf123d6 100644 --- a/test/common/globals.js +++ b/test/common/globals.js -@@ -35,6 +35,7 @@ const intrinsics = new Set([ - 'Int16Array', +@@ -36,6 +36,7 @@ const intrinsics = new Set([ + 'Float16Array', 'Uint32Array', 'Int32Array', + 'Float16Array', 'Float32Array', 'Float64Array', 'Uint8ClampedArray', -diff --git a/test/wpt/status/encoding.json b/test/wpt/status/encoding.json -index f9378d7195a2a77eb89ae696ab26747fd8bf65b8..c258031e48556480d500a02925a8d9c29dfb2a18 100644 ---- a/test/wpt/status/encoding.json -+++ b/test/wpt/status/encoding.json -@@ -70,12 +70,6 @@ - "requires": ["full-icu"] - }, - "encodeInto.any.js": { -- "fail": { -- "expected": [ -- "Invalid encodeInto() destination: Float16Array, backed by: ArrayBuffer", -- "Invalid encodeInto() destination: Float16Array, backed by: SharedArrayBuffer" -- ] -- }, - "requires": ["small-icu"] - }, - "textdecoder-copy.any.js": { diff --git a/patches/node/fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch b/patches/node/fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch new file mode 100644 index 0000000000000..23e5b493cc36e --- /dev/null +++ b/patches/node/fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr <shelley.vohr@gmail.com> +Date: Tue, 21 Oct 2025 20:00:06 +0200 +Subject: fix: allow disabling fetch in renderer and worker processes + +We need to disable Node.js' fetch implementation to prevent +conflict with Blink's in renderer and worker processes. + +We should try to upstream some version of this. + +diff --git a/doc/api/cli.md b/doc/api/cli.md +index cc990c01704484cbaa314320b3b3b72acffb6940..6b985c9fce6ec607df0e04f93b3cd5b84233d0b9 100644 +--- a/doc/api/cli.md ++++ b/doc/api/cli.md +@@ -1767,6 +1767,14 @@ changes: + + Disable using [syntax detection][] to determine module type. + ++### `--no-experimental-fetch` ++ ++<!-- YAML ++added: v18.0.0 ++--> ++ ++Disable exposition of Fetch API on the global scope. ++ + ### `--no-experimental-global-navigator` + + <!-- YAML +@@ -3436,6 +3444,7 @@ one is included in the list below. + * `--no-addons` + * `--no-async-context-frame` + * `--no-deprecation` ++* `--no-experimental-fetch` + * `--no-experimental-global-navigator` + * `--no-experimental-repl-await` + * `--no-experimental-sqlite` +diff --git a/doc/node.1 b/doc/node.1 +index 6210cbf42b26d4673f67aac43874ea28c8955fd5..565068cc3aca0eb03642e1160b814b48cb0c3c45 100644 +--- a/doc/node.1 ++++ b/doc/node.1 +@@ -198,6 +198,9 @@ Enable transformation of TypeScript-only syntax into JavaScript code. + .It Fl -experimental-eventsource + Enable experimental support for the EventSource Web API. + . ++.It Fl -no-experimental-fetch ++Disable experimental support for the Fetch API. ++. + .It Fl -no-experimental-websocket + Disable experimental support for the WebSocket API. + . +diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js +index 35b43990c8f24f0888f89173f5662050a11b26ed..2c0d12c0fa9c85ac7ffb41dabda83760ed1ae3ee 100644 +--- a/lib/internal/process/pre_execution.js ++++ b/lib/internal/process/pre_execution.js +@@ -110,6 +110,7 @@ function prepareExecution(options) { + setupSQLite(); + setupQuic(); + setupWebStorage(); ++ setupFetch(); + setupWebsocket(); + setupEventsource(); + setupCodeCoverage(); +@@ -312,6 +313,16 @@ function setupWarningHandler() { + } + } + ++function setupFetch() { ++ if (getOptionValue('--no-experimental-fetch')) { ++ delete globalThis.fetch; ++ delete globalThis.FormData; ++ delete globalThis.Headers; ++ delete globalThis.Request; ++ delete globalThis.Response; ++ } ++} ++ + // https://websockets.spec.whatwg.org/ + function setupWebsocket() { + if (getOptionValue('--no-experimental-websocket')) { +diff --git a/src/node_options.cc b/src/node_options.cc +index 2a3ab5e73cdb98bde9df1465d5fb5e40ad7799f7..9317191d22f51fd75157e849eb67678d1ee6a2a1 100644 +--- a/src/node_options.cc ++++ b/src/node_options.cc +@@ -537,7 +537,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { + &EnvironmentOptions::experimental_eventsource, + kAllowedInEnvvar, + false); +- AddOption("--experimental-fetch", "", NoOp{}, kAllowedInEnvvar); ++ AddOption("--experimental-fetch", ++ "experimental Fetch API", ++ &EnvironmentOptions::experimental_fetch, ++ kAllowedInEnvvar, ++ true); + AddOption("--experimental-websocket", + "experimental WebSocket API", + &EnvironmentOptions::experimental_websocket, +diff --git a/test/parallel/test-process-env-allowed-flags-are-documented.js b/test/parallel/test-process-env-allowed-flags-are-documented.js +index f09bf0940dad2068f0aa5dce783dd422773d4bbb..ccf4ffcacf9bd9965978738656b8fe091fee4d6a 100644 +--- a/test/parallel/test-process-env-allowed-flags-are-documented.js ++++ b/test/parallel/test-process-env-allowed-flags-are-documented.js +@@ -122,7 +122,6 @@ const undocumented = difference(process.allowedNodeEnvironmentFlags, + assert(undocumented.delete('--debug-arraybuffer-allocations')); + assert(undocumented.delete('--no-debug-arraybuffer-allocations')); + assert(undocumented.delete('--es-module-specifier-resolution')); +-assert(undocumented.delete('--experimental-fetch')); + assert(undocumented.delete('--experimental-wasm-modules')); + assert(undocumented.delete('--experimental-global-customevent')); + assert(undocumented.delete('--experimental-global-webcrypto')); diff --git a/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch b/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch index 47b72be018a34..5c4c34c59f50a 100644 --- a/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch +++ b/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch @@ -11,7 +11,7 @@ We can fix this by allowing the C++ implementation of legacyMainResolve to use a fileExists function that does take Asar into account. diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js -index e3afd30ba1f591d0298793bc42fd7166a4219bce..408dc96307d7f52f92db41004b358051a81c627c 100644 +index 72cc9444ca93ef7a1526e23314693aeaf5f173b0..79684dd7e8d1629b19be01ebf97e43e503dec581 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -28,14 +28,13 @@ const { BuiltinModule } = require('internal/bootstrap/realm'); @@ -53,10 +53,10 @@ index e3afd30ba1f591d0298793bc42fd7166a4219bce..408dc96307d7f52f92db41004b358051 const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ? packageConfig.main || './' : ''; diff --git a/src/node_file.cc b/src/node_file.cc -index 7d174113a22cb26e767f8756ce0f0cdedd68d7d7..f3142dab526064114771af154c3389961771b5dc 100644 +index 00f369e9691e184f9e5f226ce4216bd5b1d353ae..d73dac2ee3f1cf1cac6845fae0f702c9fba8fcef 100644 --- a/src/node_file.cc +++ b/src/node_file.cc -@@ -3482,13 +3482,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) { +@@ -3623,13 +3623,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) { } BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile( @@ -83,7 +83,7 @@ index 7d174113a22cb26e767f8756ce0f0cdedd68d7d7..f3142dab526064114771af154c338996 uv_fs_t req; int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr); -@@ -3546,6 +3558,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) { +@@ -3687,6 +3699,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) { std::optional<std::string> initial_file_path; std::string file_path; @@ -95,7 +95,7 @@ index 7d174113a22cb26e767f8756ce0f0cdedd68d7d7..f3142dab526064114771af154c338996 if (args.Length() >= 2 && args[1]->IsString()) { auto package_config_main = Utf8Value(isolate, args[1]).ToString(); -@@ -3566,7 +3583,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) { +@@ -3707,7 +3724,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) { BufferValue buff_file_path(isolate, local_file_path); ToNamespacedPath(env, &buff_file_path); @@ -104,7 +104,7 @@ index 7d174113a22cb26e767f8756ce0f0cdedd68d7d7..f3142dab526064114771af154c338996 case BindingData::FilePathIsFileReturnType::kIsFile: return args.GetReturnValue().Set(i); case BindingData::FilePathIsFileReturnType::kIsNotFile: -@@ -3603,7 +3620,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) { +@@ -3744,7 +3761,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) { BufferValue buff_file_path(isolate, local_file_path); ToNamespacedPath(env, &buff_file_path); @@ -114,7 +114,7 @@ index 7d174113a22cb26e767f8756ce0f0cdedd68d7d7..f3142dab526064114771af154c338996 return args.GetReturnValue().Set(i); case BindingData::FilePathIsFileReturnType::kIsNotFile: diff --git a/src/node_file.h b/src/node_file.h -index bdad1ae25f4892cbbfd8cc30c4d8b4a6f600edbc..099488319f53bc7718313d6e30df2237cad6771d 100644 +index 224fa6f7ade375cb673c8adcc95927fa04f9c248..343c6bec67e6cf70ffb91b87e7837dbaf6071cee 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -101,7 +101,8 @@ class BindingData : public SnapshotableObject { diff --git a/patches/node/fix_assert_module_in_the_renderer_process.patch b/patches/node/fix_assert_module_in_the_renderer_process.patch deleted file mode 100644 index 6b733d340fea7..0000000000000 --- a/patches/node/fix_assert_module_in_the_renderer_process.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr <shelley.vohr@gmail.com> -Date: Wed, 16 Aug 2023 19:15:29 +0200 -Subject: fix: assert module in the renderer process - -When creating a Node.js Environment, embedders have the option to disable Node.js' -default overriding of Error.prepareStackTrace. However, the assert module depends on -a WeakMap that is populated with the error stacktraces in the overridden function. - -This adds handling to fall back to the default implementation if Error.prepareStackTrace -if the override has been disabled. - -This will be upstreamed. - -diff --git a/lib/internal/assert/utils.js b/lib/internal/assert/utils.js -index d059fa89baf7d4f7d921d00871a97494be4a166a..a0f7fd2e4512e9b4196bbf5fe4390b00e5e2d9a8 100644 ---- a/lib/internal/assert/utils.js -+++ b/lib/internal/assert/utils.js -@@ -24,6 +24,7 @@ const AssertionError = require('internal/assert/assertion_error'); - const { openSync, closeSync, readSync } = require('fs'); - const { EOL } = require('internal/constants'); - const { BuiltinModule } = require('internal/bootstrap/realm'); -+const { getEmbedderOptions } = require('internal/options'); - const { isError } = require('internal/util'); - - const errorCache = new SafeMap(); -@@ -166,8 +167,16 @@ function getErrMessage(message, fn) { - ErrorCaptureStackTrace(err, fn); - if (errorStackTraceLimitIsWritable) Error.stackTraceLimit = tmpLimit; - -- overrideStackTrace.set(err, (_, stack) => stack); -- const call = err.stack[0]; -+ let call; -+ if (getEmbedderOptions().hasPrepareStackTraceCallback) { -+ overrideStackTrace.set(err, (_, stack) => stack); -+ call = err.stack[0]; -+ } else { -+ const tmpPrepare = Error.prepareStackTrace; -+ Error.prepareStackTrace = (_, stack) => stack; -+ call = err.stack[0]; -+ Error.prepareStackTrace = tmpPrepare; -+ } - - let filename = call.getFileName(); - const line = call.getLineNumber() - 1; -diff --git a/src/node_options.cc b/src/node_options.cc -index 9cf107b1048208ffcb69ff91e0d36ffacc741805..367f7d9b1450e4d9e6d8fef36a2234e7d1344804 100644 ---- a/src/node_options.cc -+++ b/src/node_options.cc -@@ -1566,14 +1566,16 @@ void GetEmbedderOptions(const FunctionCallbackInfo<Value>& args) { - } - Isolate* isolate = args.GetIsolate(); - -- constexpr size_t kOptionsSize = 4; -+ constexpr size_t kOptionsSize = 5; - std::array<Local<Name>, kOptionsSize> names = { -+ FIXED_ONE_BYTE_STRING(env->isolate(), "hasPrepareStackTraceCallback"), - FIXED_ONE_BYTE_STRING(env->isolate(), "shouldNotRegisterESMLoader"), - FIXED_ONE_BYTE_STRING(env->isolate(), "noGlobalSearchPaths"), - FIXED_ONE_BYTE_STRING(env->isolate(), "noBrowserGlobals"), - FIXED_ONE_BYTE_STRING(env->isolate(), "hasEmbedderPreload")}; - - std::array<Local<Value>, kOptionsSize> values = { -+ Boolean::New(isolate, env->prepare_stack_trace_callback().IsEmpty()), - Boolean::New(isolate, env->should_not_register_esm_loader()), - Boolean::New(isolate, env->no_global_search_paths()), - Boolean::New(isolate, env->no_browser_globals()), diff --git a/patches/node/fix_avoid_external_memory_leak_on_invalid_tls_protocol_versions.patch b/patches/node/fix_avoid_external_memory_leak_on_invalid_tls_protocol_versions.patch new file mode 100644 index 0000000000000..d5cad3cb529b4 --- /dev/null +++ b/patches/node/fix_avoid_external_memory_leak_on_invalid_tls_protocol_versions.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr <shelley.vohr@gmail.com> +Date: Fri, 24 Oct 2025 15:32:50 +0200 +Subject: fix: avoid external memory leak on invalid TLS protocol versions + +Fixes a crash caused by unbalanced external memory accounting when +tls.createSecureContext() is called with invalid minVersion/maxVersion values: + +Prior to this change, _tls_common.js instantiated a native SecureContext +which incremented V8 external memory via +env->external_memory_accounter()->Increase(kExternalSize) in crypto_context.cc +before protocol version validation ran in toV(), so an early +ERR_TLS_INVALID_PROTOCOL_VERSION throw left the +1024 bytes un-decremented +and V8 asserted in ExternalMemoryAccounter::~ExternalMemoryAccounter +during Environment teardown. + +Fix this by reordering the constructor to validate minVersion/maxVersion first and +only allocate the native SecureContext on success. + +This should be upstreamed to Node.js. + +diff --git a/lib/_tls_common.js b/lib/_tls_common.js +index 66331d2d9999e93e59cbce9e153affb942b79946..0f7fd0747ea779f76a9e64ed37d195bd735ea2a8 100644 +--- a/lib/_tls_common.js ++++ b/lib/_tls_common.js +@@ -82,10 +82,11 @@ function SecureContext(secureProtocol, secureOptions, minVersion, maxVersion) { + throw new ERR_TLS_PROTOCOL_VERSION_CONFLICT(maxVersion, secureProtocol); + } + ++ const minV = toV('minimum', minVersion, tls.DEFAULT_MIN_VERSION); ++ const maxV = toV('maximum', maxVersion, tls.DEFAULT_MAX_VERSION); ++ + this.context = new NativeSecureContext(); +- this.context.init(secureProtocol, +- toV('minimum', minVersion, tls.DEFAULT_MIN_VERSION), +- toV('maximum', maxVersion, tls.DEFAULT_MAX_VERSION)); ++ this.context.init(secureProtocol, minV, maxV); + + if (secureOptions) { + validateInteger(secureOptions, 'secureOptions'); +diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc +index 8fbf4f25a91b953f3d2868889c7ee06932ee3c5f..96f6ea29525bc2c60297e7be5bc1d0b74cd568e1 100644 +--- a/src/crypto/crypto_context.cc ++++ b/src/crypto/crypto_context.cc +@@ -1355,10 +1355,8 @@ SecureContext::SecureContext(Environment* env, Local<Object> wrap) + } + + inline void SecureContext::Reset() { +- if (ctx_ != nullptr) { +- env()->external_memory_accounter()->Decrease(env()->isolate(), +- kExternalSize); +- } ++ env()->external_memory_accounter()->Decrease(env()->isolate(), ++ kExternalSize); + ctx_.reset(); + cert_.reset(); + issuer_.reset(); diff --git a/patches/node/fix_cppgc_initializing_twice.patch b/patches/node/fix_cppgc_initializing_twice.patch index 475bd2830be6a..b3909737236af 100644 --- a/patches/node/fix_cppgc_initializing_twice.patch +++ b/patches/node/fix_cppgc_initializing_twice.patch @@ -12,10 +12,10 @@ This can be removed/refactored once Node.js upgrades to a version of V8 containing the above CL. diff --git a/src/node.cc b/src/node.cc -index 19d9fb77f1aaf003e43b7d7016f45e6c35df06b3..9fad3198757ce639eb491eb628c6264a17002bf2 100644 +index c70bec82a28b166afa785d458d3f6c820d7b8565..5713d49d859e1161e1d6703c0b6f3d717a5a9a34 100644 --- a/src/node.cc +++ b/src/node.cc -@@ -1208,7 +1208,7 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args, +@@ -1245,7 +1245,7 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args, result->platform_ = per_process::v8_platform.Platform(); } diff --git a/patches/node/fix_crypto_tests_to_run_with_bssl.patch b/patches/node/fix_crypto_tests_to_run_with_bssl.patch index 40564e4046eb7..14871fd9456bb 100644 --- a/patches/node/fix_crypto_tests_to_run_with_bssl.patch +++ b/patches/node/fix_crypto_tests_to_run_with_bssl.patch @@ -10,8 +10,541 @@ This should be upstreamed in some form, though it may need to be tweaked before it's acceptable to upstream, as this patch comments out a couple of tests that upstream probably cares about. +diff --git a/test/fixtures/crypto/ecdsa.js b/test/fixtures/crypto/ecdsa.js +index b8827b24d41965b355c6e8bbf33ebc2c034a9035..c3545fb20ec7df3e6c3d8e7c3396030af85637c0 100644 +--- a/test/fixtures/crypto/ecdsa.js ++++ b/test/fixtures/crypto/ecdsa.js +@@ -72,18 +72,20 @@ module.exports = function() { + 'b6a0a14d7e4bc6dd2eda82c9234f174b670b60c8f7d101f68fdf5889e02373b025' + + 'dcbc4c82f2929b8e06c68535da98e38fe399c53a814b097935581ef21535eb', + 'hex'), +- 'SHA3-256': Buffer.from( +- 'f6a48eb5557f484ed0c3e4b5c78a3cf497cbd346db06a4165d429248aa2cc51a69' + +- '747d09f57af145469a8b607a9b8b9709629d74e8f5ca337c6ddc581b6f6103', +- 'hex'), +- 'SHA3-384': Buffer.from( +- '777785978eb59da32888554dc7fd62d1ba1a3033cddaa8c36b8f3dcea8f85e1c8e' + +- '6db26f509747bd144dfa9436784bf4abbcaa6abcf1ecc09cea3b921d46738c', +- 'hex'), +- 'SHA3-512': Buffer.from( +- '0f01c2083b5dd7fccb2784563f88cd9a815d570a1690695e426643ab725780760d' + +- 'e972e26e18d67f5557be89f17b4cd0065ce2937de299bdb2e972ebf7635084', +- 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': Buffer.from( ++ 'f6a48eb5557f484ed0c3e4b5c78a3cf497cbd346db06a4165d429248aa2cc51a69' + ++ '747d09f57af145469a8b607a9b8b9709629d74e8f5ca337c6ddc581b6f6103', ++ 'hex'), ++ 'SHA3-384': Buffer.from( ++ '777785978eb59da32888554dc7fd62d1ba1a3033cddaa8c36b8f3dcea8f85e1c8e' + ++ '6db26f509747bd144dfa9436784bf4abbcaa6abcf1ecc09cea3b921d46738c', ++ 'hex'), ++ 'SHA3-512': Buffer.from( ++ '0f01c2083b5dd7fccb2784563f88cd9a815d570a1690695e426643ab725780760d' + ++ 'e972e26e18d67f5557be89f17b4cd0065ce2937de299bdb2e972ebf7635084', ++ 'hex') ++ } : {}) + }, + 'P-384': { + 'SHA-1': Buffer.from( +@@ -102,18 +104,20 @@ module.exports = function() { + '72fbdb369fd34c1c54264d07f4facd69b02e4206f8a8bb259b882a305c56fde2d3' + + '5107e493c53cd6b4af0b31306f4d03fd43cfc762a1030e17a3d775453a1212b142' + + '9f7b3d93066a5f42a10b138cd177dc09616e827d598822d78d4627b754e6', 'hex'), +- 'SHA3-256': Buffer.from( +- '0b07c078be30fa5925a307d6fc559c5f398e63fb5d007d6b24a834847f2d3d18d5' + +- 'b5e840711c52a7bc6626c3ced93301e873c013a706f6b297c12cc6d47a71e0529e' + +- '719f43957de9995621d3cb0217469adaa6fd3135470771d0aa9d05d7a9c6', 'hex'), +- 'SHA3-384': Buffer.from( +- '2f36e8b04af46f68ef900c2720e3518b06f5440865d44072bbad5d62288c575042' + +- 'b183a372acd70328c738668dcecb9866801462d62df3c35450fdc6c95433103fcd' + +- 'c77999b640e3f92bd4e9be6e27ab129d1bc4f0b2a4c829388666920892d3', 'hex'), +- 'SHA3-512': Buffer.from( +- '32a951e886c33ac57a008efe9643bc92aa3ece9521d115e0c7240caecf124d1f7c' + +- 'dcba7fabb9ad5202e04f7aa591ab01ed3f060f04f493e4f24430fe8159200612f0' + +- '2849108b8be6edc8494c328097ad9265928efe5cb9d91be2f013ee17ee4e', 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': Buffer.from( ++ '0b07c078be30fa5925a307d6fc559c5f398e63fb5d007d6b24a834847f2d3d18d5' + ++ 'b5e840711c52a7bc6626c3ced93301e873c013a706f6b297c12cc6d47a71e0529e' + ++ '719f43957de9995621d3cb0217469adaa6fd3135470771d0aa9d05d7a9c6', 'hex'), ++ 'SHA3-384': Buffer.from( ++ '2f36e8b04af46f68ef900c2720e3518b06f5440865d44072bbad5d62288c575042' + ++ 'b183a372acd70328c738668dcecb9866801462d62df3c35450fdc6c95433103fcd' + ++ 'c77999b640e3f92bd4e9be6e27ab129d1bc4f0b2a4c829388666920892d3', 'hex'), ++ 'SHA3-512': Buffer.from( ++ '32a951e886c33ac57a008efe9643bc92aa3ece9521d115e0c7240caecf124d1f7c' + ++ 'dcba7fabb9ad5202e04f7aa591ab01ed3f060f04f493e4f24430fe8159200612f0' + ++ '2849108b8be6edc8494c328097ad9265928efe5cb9d91be2f013ee17ee4e', 'hex') ++ } : {}) + }, + 'P-521': { + 'SHA-1': Buffer.from( +@@ -140,29 +144,35 @@ module.exports = function() { + '01f0071e6a32867fa70f695cd39c4e87e142b9e4134d38740bd6fee354a575167e' + + '13524e94832637910fe11e53a85fb21b91adb81bb1779c4e2b8bc87c717dc35084', + 'hex'), +- 'SHA3-256': Buffer.from( +- '00463679f47a4c705e03447360dcf34d1743e0d4b2591cc66832a6bc80d92e538c' + +- '169a1fd330f98e7235ca7fec7e16ac44fb13095b8edf2c76b75c4845177d59e425' + +- '0127c4359f6a4c9ccb63e7a9ff8122c0b4a8b7408e28c96817ecc3baf8c559c413' + +- 'c3bb580447dec9f52139b2afde369cd51730f050bc94137556ae137f0509464219', +- 'hex'), +- 'SHA3-384': Buffer.from( +- '01969a4db0888bc067a68a31fe5d0fc97e0b701f570565f7b25cb27707c6f020ff' + +- '680f8553ec5c2d6885e9e91b39262ed1bde375525eb13fdf12089b7939c7689735' + +- '0101c8b8d1129a217e8e956bef78cf7b9a0458523b04ac8e0b84ce73d54326f7a8' + +- '704ee42fe183f3ef79d83e676f34dc5476e2342641a5b973d3d94e8503676fbbc5', +- 'hex'), +- 'SHA3-512': Buffer.from( +- '000f362e914ee0136663cf57bf4085c25604af6dc198b4818751e1195ee7e41a16' + +- '91be909dcbc2bae00b8917f6bb918eae3740ac1b76e0913137c2da1171d6400b55' + +- '01ec6e1dc5987a27fe16fc2ce5c8e954088f898a9bbefb176eaa8bbd9ccc264c4c' + +- 'cc38c83ac8b5a168f90228daf8405a2b9bf7829c263a646b4e1098e2ace38deec7', +- 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': Buffer.from( ++ '00463679f47a4c705e03447360dcf34d1743e0d4b2591cc66832a6bc80d92e538c' + ++ '169a1fd330f98e7235ca7fec7e16ac44fb13095b8edf2c76b75c4845177d59e425' + ++ '0127c4359f6a4c9ccb63e7a9ff8122c0b4a8b7408e28c96817ecc3baf8c559c413' + ++ 'c3bb580447dec9f52139b2afde369cd51730f050bc94137556ae137f0509464219', ++ 'hex'), ++ 'SHA3-384': Buffer.from( ++ '01969a4db0888bc067a68a31fe5d0fc97e0b701f570565f7b25cb27707c6f020ff' + ++ '680f8553ec5c2d6885e9e91b39262ed1bde375525eb13fdf12089b7939c7689735' + ++ '0101c8b8d1129a217e8e956bef78cf7b9a0458523b04ac8e0b84ce73d54326f7a8' + ++ '704ee42fe183f3ef79d83e676f34dc5476e2342641a5b973d3d94e8503676fbbc5', ++ 'hex'), ++ 'SHA3-512': Buffer.from( ++ '000f362e914ee0136663cf57bf4085c25604af6dc198b4818751e1195ee7e41a16' + ++ '91be909dcbc2bae00b8917f6bb918eae3740ac1b76e0913137c2da1171d6400b55' + ++ '01ec6e1dc5987a27fe16fc2ce5c8e954088f898a9bbefb176eaa8bbd9ccc264c4c' + ++ 'cc38c83ac8b5a168f90228daf8405a2b9bf7829c263a646b4e1098e2ace38deec7', ++ 'hex') ++ } : {}) + } + } + + const curves = ['P-256', 'P-384', 'P-521']; +- const hashes = ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512', 'SHA3-256', 'SHA3-384', 'SHA3-512']; ++ const hashes = ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']; ++ ++ if (!process.features.openssl_is_boringssl) { ++ hashes.push('SHA3-256', 'SHA3-384', 'SHA3-512'); ++ } + + const vectors = []; + curves.forEach((namedCurve) => { +diff --git a/test/fixtures/crypto/hmac.js b/test/fixtures/crypto/hmac.js +index 6505c6e2ae55b55b2474f1b9c53f2da1e66c852e..acdf3229a4bc7cfc45c664718e7396f71025624a 100644 +--- a/test/fixtures/crypto/hmac.js ++++ b/test/fixtures/crypto/hmac.js +@@ -22,16 +22,18 @@ module.exports = function () { + '5dcc359443aaf652fa1375d6b3e61fdcf29bb4a28bd5d3dcfa40f82f906bb280' + + '0455db03b5d31fb972a15a6d0103a24e56d156a119c0e5a1e92a44c3c5657cf9', + 'hex'), +- 'SHA3-256': Buffer.from( +- 'e588ec0811463d767241df1074b47ae4071b51f2ce36537ba69ccdc3fdc2b7a8', +- 'hex'), +- 'SHA3-384': Buffer.from( +- '6b1da28eab1f582ad9718effe05e23d5fd2c9877a2d9443f90bec093bece2ea7' + +- 'd2354cd0bdc5e147d2e9009373494488', 'hex'), +- 'SHA3-512': Buffer.from( +- '5dcc359443aaf652fa1375d6b3e61fdcf29bb4a28bd5d3dcfa40f82f906bb280' + +- '0455db03b5d31fb972a15a6d0103a24e56d156a119c0e5a1e92a44c3c5657cf9', +- 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': Buffer.from( ++ 'e588ec0811463d767241df1074b47ae4071b51f2ce36537ba69ccdc3fdc2b7a8', ++ 'hex'), ++ 'SHA3-384': Buffer.from( ++ '6b1da28eab1f582ad9718effe05e23d5fd2c9877a2d9443f90bec093bece2ea7' + ++ 'd2354cd0bdc5e147d2e9009373494488', 'hex'), ++ 'SHA3-512': Buffer.from( ++ '5dcc359443aaf652fa1375d6b3e61fdcf29bb4a28bd5d3dcfa40f82f906bb280' + ++ '0455db03b5d31fb972a15a6d0103a24e56d156a119c0e5a1e92a44c3c5657cf9', ++ 'hex') ++ } : {}) + } + + const signatures = { +@@ -46,16 +48,18 @@ module.exports = function () { + '61fb278c3ffb0cce2bf1cf723ddfd8ef1f931c0c618c25907324605939e3f9a2' + + 'c6f4af690bda3407dc2f5770f6a0a44b954d64a332e3ee0821abf82b7f3e99c1', + 'hex'), +- 'SHA3-256': Buffer.from( +- 'c1ac5e11fcd50c48bf567f6e296632f5801c4eb07a8a47579b41dee971a3099b', +- 'hex'), +- 'SHA3-384': Buffer.from( +- 'ac8c97f6dd8d9e16101063077c16b23fe291a5e6d149653e9ac7002365159317' + +- 'adcfad511996578b0053a5c14b75f16c', 'hex'), +- 'SHA3-512': Buffer.from( +- '2162c2a8907e6b2f68599a69e81a464d8f076b5eeb555d98b4d20330034df3c7' + +- 'cf35b1fa958a074ca12f0d242df39f0da3d4f1dbfb3629057798fe1f883974ee', +- 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': Buffer.from( ++ 'c1ac5e11fcd50c48bf567f6e296632f5801c4eb07a8a47579b41dee971a3099b', ++ 'hex'), ++ 'SHA3-384': Buffer.from( ++ 'ac8c97f6dd8d9e16101063077c16b23fe291a5e6d149653e9ac7002365159317' + ++ 'adcfad511996578b0053a5c14b75f16c', 'hex'), ++ 'SHA3-512': Buffer.from( ++ '2162c2a8907e6b2f68599a69e81a464d8f076b5eeb555d98b4d20330034df3c7' + ++ 'cf35b1fa958a074ca12f0d242df39f0da3d4f1dbfb3629057798fe1f883974ee', ++ 'hex') ++ } : {}) + } + + const vectors = []; +diff --git a/test/fixtures/crypto/rsa_pkcs.js b/test/fixtures/crypto/rsa_pkcs.js +index 4630e4af9135800ad0fc604f99ac578d36984ca2..d54c44b6d820d83f997cc5e1b94fe5b5f151c013 100644 +--- a/test/fixtures/crypto/rsa_pkcs.js ++++ b/test/fixtures/crypto/rsa_pkcs.js +@@ -97,33 +97,35 @@ module.exports = function () { + '7a6335c70e193235dcda48add6858626bd96311e60f7e5ea4491b6c1e6248afe12b' + + 'bbd54f8869b043a5b0444562813f0a98b300356f306e6b783a29f3bec97ca40ea20' + + '062cab8926ec5d96aa387cc84821a6d72b8ea126e7d', 'hex'), +- 'sha3-256': Buffer.from( +- 'be1b476c1911a01d71710fd8a2f3158d6f7839e91443b01bed30dfdd04336d80c6b' + +- 'f692c06fad254877901c10a73853e8fb202a29cddefdf16c3adcda1fc123625897d' + +- '1b81b32a9dec38957e023be221d8f31e7470ad32e761edce9170eefa37ec19bd0c3' + +- 'e0b0ad2a244e98f54a08f873efb63c6fad14d7322b50eb05b6bae767305da92a90a' + +- '53cdae52b0d81e158a00003ec626e50423b7377a34a7b28cc7483b55bfde05bd431' + +- 'cfa436c38c285531e0d476ee13f151c8ae832ffd51ba00f2ab06f1844e73c0fe0f6' + +- 'ce17d966b1e07727af4161368aa0a74a594a6fdb782b46a9ae6098799c366fc0d71' + +- '1b2d965cf5eeeed9175b39b1d0bcefdd7df376e8ac9', 'hex'), +- 'sha3-384': Buffer.from( +- '002eaf5837443f1a33dc03729a308c503888d7a8cc013be424a91bce18105f7334a' + +- '499a5eddc5f4fab2fdf80f52988d53bf8bd5e78c3ce1a43abaf3b8146c260b6ce8b' + +- 'ffc9857f4b35c190cea85921c46d3ab573113744472d1afb637a0e9ab5021bcb355' + +- '7f5b52faf89fa864a7d3bf5799096c54ee53fa139e1bc13842a2a5bf0f1d85f041d' + +- 'a4e0e87425b421f22f0240ad62ef77ba6f090e0d48e17c07fd1e477c7e16a3196f5' + +- '0142d0f0c5e525a10325569e5a1f50cb4577e782a643972857cc918ae5409587d9e' + +- '44e1c1e89540e87deed7dda5005ac63ba609f522fdd92c81d95c1ffa383558a10f3' + +- '064f59ca0534bfad31acbf3e2807cb7d3147c59ee4d', 'hex'), +- 'sha3-512': Buffer.from( +- '561585b621c916453762285c8bb6ede3f303074ad6f2826ca15b3900e49c4d94c07' + +- 'aab0b875eaa79049ba2ed97e9a87c44fff9bffe638a1bf8c4db69c627b6adbe8fca' + +- '2b38cb8b4c2810a16286bef498327b9db4b53043ed5012c7c58f037edf669baf772' + +- '9b58e413e133ebb90a5fcb6dc3936f4f87971c0e85f362189b4279bbb2d9293a427' + +- '5653068c1bc8772cebc4733a5d1df0b454d4f628c645c22bb1c8cc601fbc92dc091' + +- 'db38fad4a36289ae9ed424c46643a8161a102ae511877d25f2eab7342dff6b92bf3' + +- '65951e76ee84c2bd84a595f63d7cc04d00e1589870956491e518b3ba245efc37a28' + +- 'ec018d8788a92ab93a90bb314f9ab0788a0b5b50489', 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'sha3-256': Buffer.from( ++ 'be1b476c1911a01d71710fd8a2f3158d6f7839e91443b01bed30dfdd04336d80c6b' + ++ 'f692c06fad254877901c10a73853e8fb202a29cddefdf16c3adcda1fc123625897d' + ++ '1b81b32a9dec38957e023be221d8f31e7470ad32e761edce9170eefa37ec19bd0c3' + ++ 'e0b0ad2a244e98f54a08f873efb63c6fad14d7322b50eb05b6bae767305da92a90a' + ++ '53cdae52b0d81e158a00003ec626e50423b7377a34a7b28cc7483b55bfde05bd431' + ++ 'cfa436c38c285531e0d476ee13f151c8ae832ffd51ba00f2ab06f1844e73c0fe0f6' + ++ 'ce17d966b1e07727af4161368aa0a74a594a6fdb782b46a9ae6098799c366fc0d71' + ++ '1b2d965cf5eeeed9175b39b1d0bcefdd7df376e8ac9', 'hex'), ++ 'sha3-384': Buffer.from( ++ '002eaf5837443f1a33dc03729a308c503888d7a8cc013be424a91bce18105f7334a' + ++ '499a5eddc5f4fab2fdf80f52988d53bf8bd5e78c3ce1a43abaf3b8146c260b6ce8b' + ++ 'ffc9857f4b35c190cea85921c46d3ab573113744472d1afb637a0e9ab5021bcb355' + ++ '7f5b52faf89fa864a7d3bf5799096c54ee53fa139e1bc13842a2a5bf0f1d85f041d' + ++ 'a4e0e87425b421f22f0240ad62ef77ba6f090e0d48e17c07fd1e477c7e16a3196f5' + ++ '0142d0f0c5e525a10325569e5a1f50cb4577e782a643972857cc918ae5409587d9e' + ++ '44e1c1e89540e87deed7dda5005ac63ba609f522fdd92c81d95c1ffa383558a10f3' + ++ '064f59ca0534bfad31acbf3e2807cb7d3147c59ee4d', 'hex'), ++ 'sha3-512': Buffer.from( ++ '561585b621c916453762285c8bb6ede3f303074ad6f2826ca15b3900e49c4d94c07' + ++ 'aab0b875eaa79049ba2ed97e9a87c44fff9bffe638a1bf8c4db69c627b6adbe8fca' + ++ '2b38cb8b4c2810a16286bef498327b9db4b53043ed5012c7c58f037edf669baf772' + ++ '9b58e413e133ebb90a5fcb6dc3936f4f87971c0e85f362189b4279bbb2d9293a427' + ++ '5653068c1bc8772cebc4733a5d1df0b454d4f628c645c22bb1c8cc601fbc92dc091' + ++ 'db38fad4a36289ae9ed424c46643a8161a102ae511877d25f2eab7342dff6b92bf3' + ++ '65951e76ee84c2bd84a595f63d7cc04d00e1589870956491e518b3ba245efc37a28' + ++ 'ec018d8788a92ab93a90bb314f9ab0788a0b5b50489', 'hex') ++ } : {}) + } + + const vectors = [ +@@ -159,30 +161,32 @@ module.exports = function () { + plaintext, + signature: signatures['sha-512'] + }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSASSA-PKCS1-v1_5' }, +- hash: 'SHA3-256', +- plaintext, +- signature: signatures['sha3-256'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSASSA-PKCS1-v1_5' }, +- hash: 'SHA3-384', +- plaintext, +- signature: signatures['sha3-384'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSASSA-PKCS1-v1_5' }, +- hash: 'SHA3-512', +- plaintext, +- signature: signatures['sha3-512'] +- }, ++ ...(!process.features.openssl_is_boringssl ? [ ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSASSA-PKCS1-v1_5' }, ++ hash: 'SHA3-256', ++ plaintext, ++ signature: signatures['sha3-256'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSASSA-PKCS1-v1_5' }, ++ hash: 'SHA3-384', ++ plaintext, ++ signature: signatures['sha3-384'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSASSA-PKCS1-v1_5' }, ++ hash: 'SHA3-512', ++ plaintext, ++ signature: signatures['sha3-512'] ++ }, ++ ] : []), + ]; + + return vectors; +diff --git a/test/fixtures/crypto/rsa_pss.js b/test/fixtures/crypto/rsa_pss.js +index 101122b2ffe31c8dc903ff8852212d9f55c0badd..fa0bcceb5697486930a9530732f9a9ab6e1bb5b0 100644 +--- a/test/fixtures/crypto/rsa_pss.js ++++ b/test/fixtures/crypto/rsa_pss.js +@@ -1,6 +1,6 @@ + 'use strict'; + +-module.exports = function() { ++module.exports = function () { + const pkcs8 = Buffer.from( + '308204bf020100300d06092a864886f70d0101010500048204a9308204a5020100028' + + '2010100d3576092e62957364544e7e4233b7bdb293db2085122c479328546f9f0f712' + +@@ -150,42 +150,44 @@ module.exports = function() { + 'b68c04bfe452c3adc6c10066a915231b7b404727eb6201b4921eb96d9407de2b963' + + '3879ceb71d759d9828d7b4d062f6ef100757d8328187caf57dfb859d1555345207c' + + '1cce7905c3564c08fec78867a53d5a2cf84810e1ffa', 'hex'), +- 'sha3-512, no salt': Buffer.from( +- 'd2430dc87abeaa7d13f7cec8510f1a296e1c608f44b1696829c59a99e8eefe9b2ee' + +- '6ee8ad6fdc93c24fcba2f04d1da195924b6209717e1992c10ed9f4783478765fe34' + +- '3e761203bff9d326bb6dc2061b0a7554c8ce0814b29249136c20c8e30054df0c6bc' + +- '656509a82845149368896690e32ff5dd32ef01543686f01d6a69bb438b049e66a8b' + +- 'df485a13edcd7dc482da4cc57d0b740aca3e56f0da247794e600afd27b22b6da13b' + +- 'cc15dd2059b525f8cb6bcd07540aa843f0ae51d4b0eea27045485914b908bdd01d0' + +- 'a9d42379f9f7180f4ad162ff73df5fed0200eb02ad01473975d54a77c15a9c61a3c' + +- 'b5e27de5d1eecc363d45506f7123a5ddd115c5e4c9e', 'hex'), +- 'sha3-256, salted': Buffer.from( +- '59cb9cce6ae838eb20d38d6af4acb9b866b0753bb7df9e441037d788512c03279e8' + +- '3d9a9cf5c0921fe1c0b6e8e895a8c0ad24a18b123f809b34ef2a3a1f05974030320' + +- '435692ef5d378cef4368c3658c098a25371dfaf1c0b6910f653a4ec15f2c08956c1' + +- '405136c2aba7f25a808fa7dbf57a4cb2978bd91af710b27ee239d955c8cac7a76ae' + +- '9085cefeda2a585a99cc948f064b5da66a9c4aa4f3f767ac905a9f314b47038e05c' + +- '3608fbb7e67a278e4f009a62c3cd3fdf43692e759d9361be1217999a76a69d4d119' + +- 'f8791a90e207e46b3f6125721f56fd819292d06a3cdae2c62c9a1dc0d964a06036c' + +- '8c18661cc6c873532a3536ab51e1ce210926db299e2', 'hex'), +- 'sha3-384, salted': Buffer.from( +- '8d1f9297c8169f27f0c58827dba991d862de58c1155f612ad2995d2bf862d051c4a' + +- '91b48571849b0412384382e5b77990de6a3c84010046b35c4a504f175a3479483d9' + +- '5c58f86bb96d53a27e59d6f67fddaae295ce90610f5086acc711557c2c85aac32d3' + +- '24199cff2367ae44e1d91307a98c8cbfb085a8bce6b1c20714711bc15b0eddb7881' + +- '823227d4be477ffdad8093663a6a1fc62eb39c49c2c3a821c2b202cf7904b49ca92' + +- '3c83819602bb13931577354a80f99309030044935b1cd41f0513160e661db1959fb' + +- '1ec15f087f3d288e875d54cbf070ec860b0aeecc951ea65e97cd5460750d4b7de52' + +- '22cb9e7466b1f506ecf6a81fc399dfd8334160f9084', 'hex'), +- 'sha3-512, salted': Buffer.from( +- '7b6d7be418c5d37cc8070698b8b03d818ecd8b673d047d34921913f6d59c69cb496' + +- '172d6118207d9ff92b8e1246acf0e03a845d935a70f8a82c3d5d6db6a1a0e337269' + +- '4b904372413dcbaa7ac5486bc8ccaf70d7e9470be82b928a90017e272cf9761ed26' + +- 'c160fe874a2675a4fb2acad72c50fbfffdd70b5a6f2919553d7ea1829934670f8de' + +- 'f2a5c2816404b1aa153323c92c58400622f184b9b0463fa48d6b27091f68c287e3f' + +- '6d9ab9eb451711a5d984c547f3d56f14a686a89ddf36c47ce25092b8c6530904de9' + +- '5df7fc602fe9394315f1b1847aae304cb5ad71e2cb78acfbc997a87a9d62a6898bb' + +- '6d84a81bb89b50186265f4be171a93d837a4bf777c8', 'hex') ++ ...(!process.features.openssl_is_boringssl ? { ++ 'sha3-512, no salt': Buffer.from( ++ 'd2430dc87abeaa7d13f7cec8510f1a296e1c608f44b1696829c59a99e8eefe9b2ee' + ++ '6ee8ad6fdc93c24fcba2f04d1da195924b6209717e1992c10ed9f4783478765fe34' + ++ '3e761203bff9d326bb6dc2061b0a7554c8ce0814b29249136c20c8e30054df0c6bc' + ++ '656509a82845149368896690e32ff5dd32ef01543686f01d6a69bb438b049e66a8b' + ++ 'df485a13edcd7dc482da4cc57d0b740aca3e56f0da247794e600afd27b22b6da13b' + ++ 'cc15dd2059b525f8cb6bcd07540aa843f0ae51d4b0eea27045485914b908bdd01d0' + ++ 'a9d42379f9f7180f4ad162ff73df5fed0200eb02ad01473975d54a77c15a9c61a3c' + ++ 'b5e27de5d1eecc363d45506f7123a5ddd115c5e4c9e', 'hex'), ++ 'sha3-256, salted': Buffer.from( ++ '59cb9cce6ae838eb20d38d6af4acb9b866b0753bb7df9e441037d788512c03279e8' + ++ '3d9a9cf5c0921fe1c0b6e8e895a8c0ad24a18b123f809b34ef2a3a1f05974030320' + ++ '435692ef5d378cef4368c3658c098a25371dfaf1c0b6910f653a4ec15f2c08956c1' + ++ '405136c2aba7f25a808fa7dbf57a4cb2978bd91af710b27ee239d955c8cac7a76ae' + ++ '9085cefeda2a585a99cc948f064b5da66a9c4aa4f3f767ac905a9f314b47038e05c' + ++ '3608fbb7e67a278e4f009a62c3cd3fdf43692e759d9361be1217999a76a69d4d119' + ++ 'f8791a90e207e46b3f6125721f56fd819292d06a3cdae2c62c9a1dc0d964a06036c' + ++ '8c18661cc6c873532a3536ab51e1ce210926db299e2', 'hex'), ++ 'sha3-384, salted': Buffer.from( ++ '8d1f9297c8169f27f0c58827dba991d862de58c1155f612ad2995d2bf862d051c4a' + ++ '91b48571849b0412384382e5b77990de6a3c84010046b35c4a504f175a3479483d9' + ++ '5c58f86bb96d53a27e59d6f67fddaae295ce90610f5086acc711557c2c85aac32d3' + ++ '24199cff2367ae44e1d91307a98c8cbfb085a8bce6b1c20714711bc15b0eddb7881' + ++ '823227d4be477ffdad8093663a6a1fc62eb39c49c2c3a821c2b202cf7904b49ca92' + ++ '3c83819602bb13931577354a80f99309030044935b1cd41f0513160e661db1959fb' + ++ '1ec15f087f3d288e875d54cbf070ec860b0aeecc951ea65e97cd5460750d4b7de52' + ++ '22cb9e7466b1f506ecf6a81fc399dfd8334160f9084', 'hex'), ++ 'sha3-512, salted': Buffer.from( ++ '7b6d7be418c5d37cc8070698b8b03d818ecd8b673d047d34921913f6d59c69cb496' + ++ '172d6118207d9ff92b8e1246acf0e03a845d935a70f8a82c3d5d6db6a1a0e337269' + ++ '4b904372413dcbaa7ac5486bc8ccaf70d7e9470be82b928a90017e272cf9761ed26' + ++ 'c160fe874a2675a4fb2acad72c50fbfffdd70b5a6f2919553d7ea1829934670f8de' + ++ 'f2a5c2816404b1aa153323c92c58400622f184b9b0463fa48d6b27091f68c287e3f' + ++ '6d9ab9eb451711a5d984c547f3d56f14a686a89ddf36c47ce25092b8c6530904de9' + ++ '5df7fc602fe9394315f1b1847aae304cb5ad71e2cb78acfbc997a87a9d62a6898bb' + ++ '6d84a81bb89b50186265f4be171a93d837a4bf777c8', 'hex') ++ } : {}) + } + + const vectors = [ +@@ -253,54 +255,56 @@ module.exports = function() { + plaintext, + signature: signatures['sha-512, salted'] + }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSA-PSS', saltLength: 0 }, +- hash: 'SHA3-256', +- plaintext, +- signature: signatures['sha3-256, no salt'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSA-PSS', saltLength: 0 }, +- hash: 'SHA3-384', +- plaintext, +- signature: signatures['sha3-384, no salt'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSA-PSS', saltLength: 0 }, +- hash: 'SHA3-512', +- plaintext, +- signature: signatures['sha3-512, no salt'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSA-PSS', saltLength: 32 }, +- hash: 'SHA3-256', +- plaintext, +- signature: signatures['sha3-256, salted'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSA-PSS', saltLength: 48 }, +- hash: 'SHA3-384', +- plaintext, +- signature: signatures['sha3-384, salted'] +- }, +- { +- publicKeyBuffer: spki, +- privateKeyBuffer: pkcs8, +- algorithm: { name: 'RSA-PSS', saltLength: 64 }, +- hash: 'SHA3-512', +- plaintext, +- signature: signatures['sha3-512, salted'] +- } ++ ...(!process.features.openssl_is_boringssl ? [ ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSA-PSS', saltLength: 0 }, ++ hash: 'SHA3-256', ++ plaintext, ++ signature: signatures['sha3-256, no salt'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSA-PSS', saltLength: 0 }, ++ hash: 'SHA3-384', ++ plaintext, ++ signature: signatures['sha3-384, no salt'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSA-PSS', saltLength: 0 }, ++ hash: 'SHA3-512', ++ plaintext, ++ signature: signatures['sha3-512, no salt'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSA-PSS', saltLength: 32 }, ++ hash: 'SHA3-256', ++ plaintext, ++ signature: signatures['sha3-256, salted'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSA-PSS', saltLength: 48 }, ++ hash: 'SHA3-384', ++ plaintext, ++ signature: signatures['sha3-384, salted'] ++ }, ++ { ++ publicKeyBuffer: spki, ++ privateKeyBuffer: pkcs8, ++ algorithm: { name: 'RSA-PSS', saltLength: 64 }, ++ hash: 'SHA3-512', ++ plaintext, ++ signature: signatures['sha3-512, salted'] ++ } ++ ] : []), + ]; + + return vectors; +diff --git a/test/fixtures/webcrypto/supports-modern-algorithms.mjs b/test/fixtures/webcrypto/supports-modern-algorithms.mjs +index 337ed577b143062d41e378cc1f820945e76cea08..76d5e805cbc0e756aef0013373baec31bd320f44 100644 +--- a/test/fixtures/webcrypto/supports-modern-algorithms.mjs ++++ b/test/fixtures/webcrypto/supports-modern-algorithms.mjs +@@ -9,6 +9,7 @@ const shake256 = crypto.getHashes().includes('shake256'); + const chacha = crypto.getCiphers().includes('chacha20-poly1305'); + const ocb = hasOpenSSL(3); + const kmac = hasOpenSSL(3); ++const boringSSL = process.features.openssl_is_boringssl; + + const { subtle } = globalThis.crypto; + const X25519 = await subtle.generateKey('X25519', false, ['deriveBits', 'deriveKey']); +@@ -108,9 +109,9 @@ export const vectors = { + [true, 'RSA-PSS'], + [true, 'RSASSA-PKCS1-v1_5'], + [true, 'X25519'], +- [true, 'X448'], ++ [!boringSSL, 'X448'], + [true, 'Ed25519'], +- [true, 'Ed448'], ++ [!boringSSL, 'Ed448'], + [true, 'ECDH'], + [true, 'ECDSA'], + [pqc, 'ML-DSA-44'], diff --git a/test/parallel/test-crypto-async-sign-verify.js b/test/parallel/test-crypto-async-sign-verify.js -index b35dd08e6c49796418cd9d10eb5cc9d02b39961e..97bcd79b331db140d157e6b1faf92625597edc98 100644 +index d385926e9943052bbe1793d4b1e39846e1a69562..dbf7b04afa77f132aaa466c9ee02c5ffad0296bc 100644 --- a/test/parallel/test-crypto-async-sign-verify.js +++ b/test/parallel/test-crypto-async-sign-verify.js @@ -89,6 +89,7 @@ test('rsa_public.pem', 'rsa_private.pem', 'sha256', false, @@ -30,20 +563,19 @@ index b35dd08e6c49796418cd9d10eb5cc9d02b39961e..97bcd79b331db140d157e6b1faf92625 // Test Parallel Execution w/ KeyObject is threadsafe in openssl3 { -@@ -150,8 +152,10 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc= +@@ -150,7 +152,10 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc= const data = crypto.randomBytes(32); const signature = crypto.randomBytes(16); -- const expected = hasOpenSSL3 ? -- /operation not supported for this keytype/ : /no default digest/; -+ let expected = /no default digest/; +- const expected = hasOpenSSL3 ? /operation not supported for this keytype/ : /no default digest/; ++ let expected = hasOpenSSL3 ? /operation not supported for this keytype/ : /no default digest/; + if (hasOpenSSL3 || process.features.openssl_is_boringssl) { + expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i; + } crypto.verify(undefined, data, untrustedKey, signature, common.mustCall((err) => { assert.ok(err); -@@ -165,6 +169,6 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc= +@@ -164,6 +169,6 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc= }); crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => { assert.ok(err); @@ -81,7 +613,7 @@ index 4a5f1f149fe6c739f7f1d2ee17df6e61a942d621..b3287f428ce6b3fde11d449c601a57ff { diff --git a/test/parallel/test-crypto-cipheriv-decipheriv.js b/test/parallel/test-crypto-cipheriv-decipheriv.js -index 88d07c3b957f57b85861542d174a0fd0ba8ceb66..1f430197579ff5f31322bfa0fa5e92e4c58588e2 100644 +index 6742722f9e90914b4dc8c079426d10040d476f72..8801ddfe7023fd0f7d5657b86a9164d75765322e 100644 --- a/test/parallel/test-crypto-cipheriv-decipheriv.js +++ b/test/parallel/test-crypto-cipheriv-decipheriv.js @@ -62,6 +62,10 @@ function testCipher2(key, iv) { @@ -222,6 +754,21 @@ index 929dd36c669239804f2cfc5168bd3bf6e15855e6..8ebe599bbd21ad30e5041e0eab1e5898 // Default outputLengths. assert.strictEqual(crypto.createHash('shake128').digest('hex'), '7f9c2ba4e88f827d616045507605853e'); +diff --git a/test/parallel/test-crypto-oneshot-hash-xof.js b/test/parallel/test-crypto-oneshot-hash-xof.js +index 75cb4800ff1bd51fedd7bc4e2d7e6af6f4f48346..b4363c31592763235116d970a5f45d4cf63de373 100644 +--- a/test/parallel/test-crypto-oneshot-hash-xof.js ++++ b/test/parallel/test-crypto-oneshot-hash-xof.js +@@ -7,6 +7,10 @@ if (!common.hasCrypto) common.skip('missing crypto'); + const assert = require('assert'); + const crypto = require('crypto'); + ++if (process.features.openssl_is_boringssl) { ++ common.skip('BoringSSL does not support XOF hash functions'); ++} ++ + // Test XOF hash functions and the outputLength option. + { + // Default outputLengths. diff --git a/test/parallel/test-crypto-padding.js b/test/parallel/test-crypto-padding.js index 48cd1ed4df61aaddeee8785cb90f83bdd9628187..d09e01712c617597833bb1320a32a967bcf1d318 100644 --- a/test/parallel/test-crypto-padding.js @@ -268,7 +815,7 @@ index 48cd1ed4df61aaddeee8785cb90f83bdd9628187..d09e01712c617597833bb1320a32a967 // No-pad encrypted string should return the same: diff --git a/test/parallel/test-crypto-rsa-dsa.js b/test/parallel/test-crypto-rsa-dsa.js -index dcd5045daaf58c60e27c1e2f7941033302241339..b52ec0e2cd5d6b1c9a0fee3064f2f8ff3b6e4308 100644 +index 119bc3c2d20ea7d681f0b579f9d91ad46cdc3634..8d13b105fa426015a873c411ad1d7f64b3d9580e 100644 --- a/test/parallel/test-crypto-rsa-dsa.js +++ b/test/parallel/test-crypto-rsa-dsa.js @@ -29,12 +29,11 @@ const dsaPkcs8KeyPem = fixtures.readKey('dsa_private_pkcs8.pem'); @@ -296,9 +843,9 @@ index dcd5045daaf58c60e27c1e2f7941033302241339..b52ec0e2cd5d6b1c9a0fee3064f2f8ff - if (padding === constants.RSA_PKCS1_PADDING) { + if (!process.features.openssl_is_boringssl) { if (!process.config.variables.node_shared_openssl) { - assert.throws(() => { - crypto.privateDecrypt({ -@@ -471,7 +470,7 @@ assert.throws(() => { + // TODO(richardlau) remove check and else branch after deps/openssl + // is upgraded. +@@ -489,7 +488,7 @@ assert.throws(() => { // // Test DSA signing and verification // @@ -308,10 +855,10 @@ index dcd5045daaf58c60e27c1e2f7941033302241339..b52ec0e2cd5d6b1c9a0fee3064f2f8ff // DSA signatures vary across runs so there is no static string to verify diff --git a/test/parallel/test-crypto-scrypt.js b/test/parallel/test-crypto-scrypt.js -index 03a18c7522531c7317f12705550117dc389a0245..2f0f46f2c6ddc62de89877cfa0ca80949a0f4c5e 100644 +index eafdfe392bde8eb1fde1dc7e7e9ae51682c74b87..2907e0175379266c90acb9df829d10283bd46652 100644 --- a/test/parallel/test-crypto-scrypt.js +++ b/test/parallel/test-crypto-scrypt.js -@@ -176,7 +176,7 @@ for (const options of bad) { +@@ -192,7 +192,7 @@ for (const options of incompatibleOptions) { for (const options of toobig) { const expected = { @@ -321,7 +868,7 @@ index 03a18c7522531c7317f12705550117dc389a0245..2f0f46f2c6ddc62de89877cfa0ca8094 }; assert.throws(() => crypto.scrypt('pass', 'salt', 1, options, () => {}), diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js -index 0589d60736e377f24dc8550f87a6b7624173fc44..113003826fc47a589cf2334f7345e33d3e189d0a 100644 +index a66f0a94efd7c952c1d2320fbc7a39fe3a88a8a1..dc5846db0e3dcf8f7cb5f7efcdbc81c1d767ab88 100644 --- a/test/parallel/test-crypto-sign-verify.js +++ b/test/parallel/test-crypto-sign-verify.js @@ -33,7 +33,7 @@ const keySize = 2048; @@ -336,7 +883,7 @@ index 0589d60736e377f24dc8550f87a6b7624173fc44..113003826fc47a589cf2334f7345e33d @@ -345,15 +345,15 @@ assert.throws( padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }); - }, hasOpenSSL3 ? { + }, hasOpenSSL(3) ? { - code: 'ERR_OSSL_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE', - message: /illegal or unsupported padding mode/, + code: /^ERR_OSSL_(RSA|EVP)_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE$/, @@ -355,7 +902,7 @@ index 0589d60736e377f24dc8550f87a6b7624173fc44..113003826fc47a589cf2334f7345e33d }); } -@@ -423,10 +423,12 @@ assert.throws( +@@ -423,11 +423,13 @@ assert.throws( public: fixtures.readKey('ed25519_public.pem', 'ascii'), algo: null, sigLen: 64 }, @@ -363,12 +910,13 @@ index 0589d60736e377f24dc8550f87a6b7624173fc44..113003826fc47a589cf2334f7345e33d { private: fixtures.readKey('ed448_private.pem', 'ascii'), public: fixtures.readKey('ed448_public.pem', 'ascii'), algo: null, + supportsContext: true, sigLen: 114 }, + */ { private: fixtures.readKey('rsa_private_2048.pem', 'ascii'), public: fixtures.readKey('rsa_public_2048.pem', 'ascii'), algo: 'sha1', -@@ -497,7 +499,7 @@ assert.throws( +@@ -547,7 +549,7 @@ assert.throws( { const data = Buffer.from('Hello world'); @@ -474,11 +1022,387 @@ index 7bd42bbe721c4c9442410d524c5ca740078fc72c..de49dbdc2b75517f497af353a6b24b1b assert.strictEqual(err.function, 'ssl3_read_bytes'); assert.match(err.reason, expectedErrorReason); })); +diff --git a/test/parallel/test-webcrypto-derivebits-hkdf.js b/test/parallel/test-webcrypto-derivebits-hkdf.js +index 0629f85b0fb538cabf77479132f8c3e4ea958b19..2759223e76a0609d0ff98da73f8f6e67b325d8f3 100644 +--- a/test/parallel/test-webcrypto-derivebits-hkdf.js ++++ b/test/parallel/test-webcrypto-derivebits-hkdf.js +@@ -91,18 +91,20 @@ const kDerivations = { + empty: '9e4b719033742101e90f1ad61e2ff3b4' + + '256863667296d74389f1f02af2c4e6a6' + }, +- 'SHA3-256': { +- normal: '386b0693d7a58c4ddf01b49bfbbd2fa87c6f911991543995170ba20ed28df599', +- empty: 'd029bc828b6c6c8bb16ce3d25f5058f19c7d2517745e11c5d65c6d242e82e47f', +- }, +- 'SHA3-384': { +- normal: '8c3b72e659bad40bcd14bdc1f7c3836059d24253795ab046a272973fd0456508', +- empty: '3211ff4c676f761494c1ca2683d2d4662fe1d770ae5c58ebf6af6acb181c7d71', +- }, +- 'SHA3-512': { +- normal: '5588c5c70cb3dd2f95323da2e9d5f299ca99c301d920a499330c449d21c645cd', +- empty: '2c944b916c2751a71a1b5e57fcb487939c624335683995770b9f7cc7cbbb21f0', +- }, ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': { ++ normal: '386b0693d7a58c4ddf01b49bfbbd2fa87c6f911991543995170ba20ed28df599', ++ empty: 'd029bc828b6c6c8bb16ce3d25f5058f19c7d2517745e11c5d65c6d242e82e47f', ++ }, ++ 'SHA3-384': { ++ normal: '8c3b72e659bad40bcd14bdc1f7c3836059d24253795ab046a272973fd0456508', ++ empty: '3211ff4c676f761494c1ca2683d2d4662fe1d770ae5c58ebf6af6acb181c7d71', ++ }, ++ 'SHA3-512': { ++ normal: '5588c5c70cb3dd2f95323da2e9d5f299ca99c301d920a499330c449d21c645cd', ++ empty: '2c944b916c2751a71a1b5e57fcb487939c624335683995770b9f7cc7cbbb21f0', ++ }, ++ } : {}), + }, + empty: { + 'SHA-384': { +@@ -129,18 +131,20 @@ const kDerivations = { + empty: 'c8e12774135305c9147f2cc4766e5ead' + + '25d8f457b9a1953d52677361ced558fb' + }, +- 'SHA3-256': { +- normal: '9befc557f5baf4075b5fb38c014b41b92ab7534150baf64201069e8807d0e83d', +- empty: '54d1fa1aa7cad99dab0622b772170e775c103756183bac36a228fd817a98a3f6', +- }, +- 'SHA3-384': { +- normal: '46b54c015e368677edf7ac16963bccd9d2ba8246eef0e8beb04d8d188774b91b', +- empty: '46eb0b2649bb0f605d70e4818ffc8176ee1be9782396e69fb4d0fd7cfe902b55', +- }, +- 'SHA3-512': { +- normal: 'aa4375c82b5d7a3cac88a0423250b3882f140c253e98e8e7a0f6055b0908e4c2', +- empty: '6613003f98602ddb53ac35f5aa256c9f5279d50ee65bb08fdf2ecf65cc5df27f', +- }, ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': { ++ normal: '9befc557f5baf4075b5fb38c014b41b92ab7534150baf64201069e8807d0e83d', ++ empty: '54d1fa1aa7cad99dab0622b772170e775c103756183bac36a228fd817a98a3f6', ++ }, ++ 'SHA3-384': { ++ normal: '46b54c015e368677edf7ac16963bccd9d2ba8246eef0e8beb04d8d188774b91b', ++ empty: '46eb0b2649bb0f605d70e4818ffc8176ee1be9782396e69fb4d0fd7cfe902b55', ++ }, ++ 'SHA3-512': { ++ normal: 'aa4375c82b5d7a3cac88a0423250b3882f140c253e98e8e7a0f6055b0908e4c2', ++ empty: '6613003f98602ddb53ac35f5aa256c9f5279d50ee65bb08fdf2ecf65cc5df27f', ++ }, ++ } : {}), + } + }, + long: { +@@ -169,18 +173,20 @@ const kDerivations = { + empty: 'e579d1f9e7f08e6f990ffcfcce1ed201' + + 'c5e37e62cdf606f0ba4aca80427fbc44' + }, +- 'SHA3-256': { +- normal: '24f38fd1905554b7cbf8395cc3976292d11ce24a0b3131da0fd4b109832d27e3', +- empty: '33d0a5151c0f52e4bb7fb67cf7a17063127624dc3e685903f49ebb07872084d1', +- }, +- 'SHA3-384': { +- normal: '15777581a1ea81ad0baac8a97d954df4142f7260d9e8351aa7f6ef6de2d04632', +- empty: 'ada4da4e28dc971633a8760b265b3019db57baf17e7bf7e13cf78b1a676f6d44', +- }, +- 'SHA3-512': { +- normal: '621e4602b07fcba55ed6b976a8bef513b0f7c4ad0c546e0f852993051d887408', +- empty: 'f1292af65b05c86cf7146b739bc65785c707450316f3207ee54a3f596a7d0f7b', +- }, ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': { ++ normal: '24f38fd1905554b7cbf8395cc3976292d11ce24a0b3131da0fd4b109832d27e3', ++ empty: '33d0a5151c0f52e4bb7fb67cf7a17063127624dc3e685903f49ebb07872084d1', ++ }, ++ 'SHA3-384': { ++ normal: '15777581a1ea81ad0baac8a97d954df4142f7260d9e8351aa7f6ef6de2d04632', ++ empty: 'ada4da4e28dc971633a8760b265b3019db57baf17e7bf7e13cf78b1a676f6d44', ++ }, ++ 'SHA3-512': { ++ normal: '621e4602b07fcba55ed6b976a8bef513b0f7c4ad0c546e0f852993051d887408', ++ empty: 'f1292af65b05c86cf7146b739bc65785c707450316f3207ee54a3f596a7d0f7b', ++ }, ++ } : {}), + }, + empty: { + 'SHA-384': { +@@ -207,18 +213,20 @@ const kDerivations = { + empty: 'b4f7e7557674d501cbfbc0148ad800c0' + + '750189fe295a2aca5e1bf4122c85edf9' + }, +- 'SHA3-256': { +- normal: 'fe32459f7339dd2e8df6c6fc874ed9e81e3b7aad669edad9b71196f53ed95b12', +- empty: '04519be1eb94079c91306cc5b21946b3de6a78ad35ec83d4f4a37bafbda678d7', +- }, +- 'SHA3-384': { +- normal: 'a474e8289cb4a0511e90b87eaf9ec29cadd74d4c1f2ee1fb8cb5f7d08f91a379', +- empty: '726c8c4b39083a7d5755604d3a67e9aa6139db00c08028ac9e69f7fb1525bf1d', +- }, +- 'SHA3-512': { +- normal: 'c7a7f5004d1d595c6896498c169642ac24b946e13296ff53e12b534962a88675', +- empty: '7b543480b5696932551abb3100d72e05c18f57fbb63aa44fe020bef1eec3555c', +- }, ++ ...(!process.features.openssl_is_boringssl ? { ++ 'SHA3-256': { ++ normal: 'fe32459f7339dd2e8df6c6fc874ed9e81e3b7aad669edad9b71196f53ed95b12', ++ empty: '04519be1eb94079c91306cc5b21946b3de6a78ad35ec83d4f4a37bafbda678d7', ++ }, ++ 'SHA3-384': { ++ normal: 'a474e8289cb4a0511e90b87eaf9ec29cadd74d4c1f2ee1fb8cb5f7d08f91a379', ++ empty: '726c8c4b39083a7d5755604d3a67e9aa6139db00c08028ac9e69f7fb1525bf1d', ++ }, ++ 'SHA3-512': { ++ normal: 'c7a7f5004d1d595c6896498c169642ac24b946e13296ff53e12b534962a88675', ++ empty: '7b543480b5696932551abb3100d72e05c18f57fbb63aa44fe020bef1eec3555c', ++ }, ++ } : {}), + } + }, + }; +diff --git a/test/parallel/test-webcrypto-derivekey.js b/test/parallel/test-webcrypto-derivekey.js +index 422384f4447bda80c3137ea8784c1bd70c3c285f..c7c6343194a29f14d80db44cf6574e4cd6f34786 100644 +--- a/test/parallel/test-webcrypto-derivekey.js ++++ b/test/parallel/test-webcrypto-derivekey.js +@@ -135,14 +135,21 @@ const { KeyObject } = require('crypto'); + '201509b012c9cd2fbe7ea938f0c509b36ecb140f38bf9130e96923f55f46756d'], + ['hello', 'there', 5, 'SHA-512', + '2e8d981741f98193e0af9c79870af0e985089341221edad9a130d297eae1984b'], +- ['hello', 'there', 5, 'SHA3-256', +- '0aed29b61b3ca3978aea34a9793276574ea997b69e8d03727438199f90571649'], +- ['hello', 'there', 5, 'SHA3-384', +- '7aa4a274aa19b4623c5d3091c4b06355de85ff6f25e53a83e3126cbb86ae68df'], +- ['hello', 'there', 5, 'SHA3-512', +- '4d909c47a81c625f866d1f9406248e6bc3c7ea89225fbccf1f08820254c9ef56'], + ]; + ++ if (!process.features.openssl_is_boringssl) { ++ kTests.push( ++ ['hello', 'there', 5, 'SHA3-256', ++ '0aed29b61b3ca3978aea34a9793276574ea997b69e8d03727438199f90571649'], ++ ['hello', 'there', 5, 'SHA3-384', ++ '7aa4a274aa19b4623c5d3091c4b06355de85ff6f25e53a83e3126cbb86ae68df'], ++ ['hello', 'there', 5, 'SHA3-512', ++ '4d909c47a81c625f866d1f9406248e6bc3c7ea89225fbccf1f08820254c9ef56'] ++ ); ++ } else { ++ common.printSkipMessage('Skipping unsupported SHA-3 test cases'); ++ } ++ + const tests = Promise.all(kTests.map((args) => test(...args))); + + tests.then(common.mustCall()); +@@ -158,16 +165,23 @@ const { KeyObject } = require('crypto'); + // Not long enough secret generated by ECDH + [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024], + [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024], +- [{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256], +- [{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384], +- [{ name: 'HMAC', hash: 'SHA3-512', length: 512 }, 'sign', 512], +- // This interaction is not defined for now. +- // https://github.com/WICG/webcrypto-modern-algos/issues/23 +- // [{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 256], +- // [{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 384], +- // [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512], + ]; + ++ if (!process.features.openssl_is_boringssl) { ++ vectors.push( ++ [{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256], ++ [{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384], ++ [{ name: 'HMAC', hash: 'SHA3-512', length: 512 }, 'sign', 512] ++ // This interaction is not defined for now. ++ // https://github.com/WICG/webcrypto-modern-algos/issues/23 ++ // [{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 256], ++ // [{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 384], ++ // [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512], ++ ); ++ } else { ++ common.printSkipMessage('Skipping unsupported SHA-3 test cases'); ++ } ++ + if (hasOpenSSL(3)) { + vectors.push( + ['KMAC128', 'sign', 128], +@@ -211,16 +225,23 @@ const { KeyObject } = require('crypto'); + [{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 512], + [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024], + [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024], +- [{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256], +- [{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384], +- [{ name: 'HMAC', hash: 'SHA3-512', length: 512 }, 'sign', 512], +- // This interaction is not defined for now. +- // https://github.com/WICG/webcrypto-modern-algos/issues/23 +- // [{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 256], +- // [{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 384], +- // [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512], + ]; + ++ if (!process.features.openssl_is_boringssl) { ++ vectors.push( ++ [{ name: 'HMAC', hash: 'SHA3-256', length: 256 }, 'sign', 256], ++ [{ name: 'HMAC', hash: 'SHA3-384', length: 384 }, 'sign', 384], ++ [{ name: 'HMAC', hash: 'SHA3-512', length: 512 }, 'sign', 512], ++ // This interaction is not defined for now. ++ // https://github.com/WICG/webcrypto-modern-algos/issues/23 ++ // [{ name: 'HMAC', hash: 'SHA3-256' }, 'sign', 256], ++ // [{ name: 'HMAC', hash: 'SHA3-384' }, 'sign', 384], ++ // [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512], ++ ); ++ } else { ++ common.printSkipMessage('Skipping unsupported SHA-3 test cases'); ++ } ++ + if (hasOpenSSL(3)) { + vectors.push( + ['KMAC128', 'sign', 128], +diff --git a/test/parallel/test-webcrypto-digest.js b/test/parallel/test-webcrypto-digest.js +index 04507d77b59142be9c9fe81c746f1c0003429262..e91214047dea431913c1a3d47ed55dd573888daf 100644 +--- a/test/parallel/test-webcrypto-digest.js ++++ b/test/parallel/test-webcrypto-digest.js +@@ -148,65 +148,67 @@ const kDigestedData = { + '60b22aab8d36a4c2a3affdb71234f49276737c575ddf7' + + '4d14054cbd6fdb98fd0ddcbcb46f91ad76b6ee' + }, +- 'cshake128': { +- empty: '7f9c2ba4e88f827d616045507605853ed73b8093f6e' + +- 'fbc88eb1a6eacfa66ef26', +- short: 'dea62d73e6b59cf725d0320d660089a4475cbbd3b85' + +- '39e36691f150d47556794', +- medium: 'b1acd53a03e76a221e52ea578e042f686a68c3d1c9' + +- '832ab18285cf4f304ca32d', +- long: '3a5bf5676955e5dec87d430e526925558971ca14c370' + +- 'ee5d7cf572b94c7c63d7' +- }, +- 'cshake256': { +- empty: '46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b' + +- '81b82b50c27646ed5762fd75dc4ddd8c0f200cb0501' + +- '9d67b592f6fc821c49479ab48640292eacb3b7c4be', +- short: '1738113f5abb3ee5320ee18aa266c3617a7475dbd8e' + +- 'd9a985994fddd6112ad999ec8e2ebdfeafb96e76f6b' + +- 'b3a3adba43da60f00cd12496df5af3e28ae6d3de42', +- medium: '4146c13d86d9bc186b0b309ab6a124ee0c74ba26b8' + +- 'c60dcc7b3ed505969aa8d19028c6317999a085b1e6' + +- 'b6a785ce4ff632aeb27493227e44232fb7b3952141' + +- '7b', +- long: '0c42bfd1e282622fd8144aa29b072fd09fc2bae70885' + +- 'd5290933492f9d17411926a613dd0611668c2ac999e8' + +- 'c011aabaa9004323425fbad75b0f58ee6e777a94' +- }, +- 'sha3-256': { +- empty: 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a', +- short: '3059af7aa33b517084e8ad7bbc4fb208a44c28ef32b4698d103dd540e4f91aa1', +- medium: '1fa7cd1da74cd8046417508c8314e74a9a4a9d38f9f18e6cb215b8c891a0a80e', +- long: 'b2cfc61e0386cdaef5e10a2be189891f5ef52a7624bfcd8edc893acc64fec600' +- }, +- 'sha3-384': { +- empty: '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa9' + +- '4fc61995e71bbee983a2ac3713831264adb47fb6bd1' + +- 'e058d5f004', +- short: '54b8f0e4cf4974de740098f66b3024479b01631315a' + +- '6773606c33eadc32556a6e778e08f0225ae79265aec' + +- '666cb2390b', +- medium: '437b7d8b68b250b5c1739ea4cc86db2033879dfb18' + +- 'de292c9c50d9c193a4c79a08a6cae3f4e483c2795e' + +- 'a5d1ef7e69d2', +- long: '3b39c4c97ad87613305d0ccc987181713e2d5e84b1f9' + +- '760011bcce0c297499005bdce8a3d2409b5ad0164f32' + +- 'bb8778d0' +- }, +- 'sha3-512': { +- empty: 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe' + +- '25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9' + +- '402c3ac558f500199d95b6d3e301758586281dcd26', +- short: '2dd2e07a62e6ad0498ba84f313c4d4024cb46001f78' + +- 'f75db336b0d4d8bd2a9ec152c4ad20878735d82ba08' + +- '72ecf59608ef3ced2b2a8669427e7da31e362333d8', +- medium: 'e640a21909536640369e9b0a48931c5cb2efcbc91f' + +- 'ecf247306bc96a0e4ca33307cb8e1b9af367946dd01' + +- 'c243f3907508d04f1692a3161df1f898de8ee25febe', +- long: 'bd262cecf565c338032de5ba0138f0aacfe7dde83d27' + +- '2d0d37d952829ed25de1a1342d98659ef7d2fa4aca7c' + +- 'e2b1aa0784d8fc1dcbf81bcec7a7431a3da36bf7' +- } ++ ...(!process.features.openssl_is_boringssl ? { ++ 'cshake128': { ++ empty: '7f9c2ba4e88f827d616045507605853ed73b8093f6e' + ++ 'fbc88eb1a6eacfa66ef26', ++ short: 'dea62d73e6b59cf725d0320d660089a4475cbbd3b85' + ++ '39e36691f150d47556794', ++ medium: 'b1acd53a03e76a221e52ea578e042f686a68c3d1c9' + ++ '832ab18285cf4f304ca32d', ++ long: '3a5bf5676955e5dec87d430e526925558971ca14c370' + ++ 'ee5d7cf572b94c7c63d7' ++ }, ++ 'cshake256': { ++ empty: '46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b' + ++ '81b82b50c27646ed5762fd75dc4ddd8c0f200cb0501' + ++ '9d67b592f6fc821c49479ab48640292eacb3b7c4be', ++ short: '1738113f5abb3ee5320ee18aa266c3617a7475dbd8e' + ++ 'd9a985994fddd6112ad999ec8e2ebdfeafb96e76f6b' + ++ 'b3a3adba43da60f00cd12496df5af3e28ae6d3de42', ++ medium: '4146c13d86d9bc186b0b309ab6a124ee0c74ba26b8' + ++ 'c60dcc7b3ed505969aa8d19028c6317999a085b1e6' + ++ 'b6a785ce4ff632aeb27493227e44232fb7b3952141' + ++ '7b', ++ long: '0c42bfd1e282622fd8144aa29b072fd09fc2bae70885' + ++ 'd5290933492f9d17411926a613dd0611668c2ac999e8' + ++ 'c011aabaa9004323425fbad75b0f58ee6e777a94' ++ }, ++ 'sha3-256': { ++ empty: 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a', ++ short: '3059af7aa33b517084e8ad7bbc4fb208a44c28ef32b4698d103dd540e4f91aa1', ++ medium: '1fa7cd1da74cd8046417508c8314e74a9a4a9d38f9f18e6cb215b8c891a0a80e', ++ long: 'b2cfc61e0386cdaef5e10a2be189891f5ef52a7624bfcd8edc893acc64fec600' ++ }, ++ 'sha3-384': { ++ empty: '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa9' + ++ '4fc61995e71bbee983a2ac3713831264adb47fb6bd1' + ++ 'e058d5f004', ++ short: '54b8f0e4cf4974de740098f66b3024479b01631315a' + ++ '6773606c33eadc32556a6e778e08f0225ae79265aec' + ++ '666cb2390b', ++ medium: '437b7d8b68b250b5c1739ea4cc86db2033879dfb18' + ++ 'de292c9c50d9c193a4c79a08a6cae3f4e483c2795e' + ++ 'a5d1ef7e69d2', ++ long: '3b39c4c97ad87613305d0ccc987181713e2d5e84b1f9' + ++ '760011bcce0c297499005bdce8a3d2409b5ad0164f32' + ++ 'bb8778d0' ++ }, ++ 'sha3-512': { ++ empty: 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe' + ++ '25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9' + ++ '402c3ac558f500199d95b6d3e301758586281dcd26', ++ short: '2dd2e07a62e6ad0498ba84f313c4d4024cb46001f78' + ++ 'f75db336b0d4d8bd2a9ec152c4ad20878735d82ba08' + ++ '72ecf59608ef3ced2b2a8669427e7da31e362333d8', ++ medium: 'e640a21909536640369e9b0a48931c5cb2efcbc91f' + ++ 'ecf247306bc96a0e4ca33307cb8e1b9af367946dd01' + ++ 'c243f3907508d04f1692a3161df1f898de8ee25febe', ++ long: 'bd262cecf565c338032de5ba0138f0aacfe7dde83d27' + ++ '2d0d37d952829ed25de1a1342d98659ef7d2fa4aca7c' + ++ 'e2b1aa0784d8fc1dcbf81bcec7a7431a3da36bf7' ++ } ++ } : {}), + }; + + async function testDigest(size, alg) { +diff --git a/test/parallel/test-webcrypto-sign-verify-rsa.js b/test/parallel/test-webcrypto-sign-verify-rsa.js +index 7e90388cc4c270200ecfbda541828c5b237e0d69..ca99ad79fea59f583726f96a58271e86d5c7b5d7 100644 +--- a/test/parallel/test-webcrypto-sign-verify-rsa.js ++++ b/test/parallel/test-webcrypto-sign-verify-rsa.js +@@ -245,7 +245,7 @@ async function testSaltLength(keyLength, hash, hLen) { + ['SHA3-384', 48], + ['SHA3-512', 64], + ]) { +- if (hash.startsWith('SHA-3') && !process.features.openssl_is_boringssl) { ++ if (hash.startsWith('SHA3') && !process.features.openssl_is_boringssl) { + variations.push(testSaltLength(keyLength, hash, hLen)); + } + } diff --git a/test/parallel/test-webcrypto-wrap-unwrap.js b/test/parallel/test-webcrypto-wrap-unwrap.js -index d1ca571af4be713082d32093bfb8a65f2aef9800..57b8df2ce18df58ff54b2d828af67e3c2e082fe0 100644 +index bd788ec4ed88289d35798b8af8c9490a68e081a2..1a5477ba928bce93320f8056db02e1a7b8ddcdf3 100644 --- a/test/parallel/test-webcrypto-wrap-unwrap.js +++ b/test/parallel/test-webcrypto-wrap-unwrap.js -@@ -18,14 +18,15 @@ const kWrappingData = { +@@ -20,14 +20,15 @@ const kWrappingData = { wrap: { label: new Uint8Array(8) }, pair: true }, @@ -498,14 +1422,40 @@ index d1ca571af4be713082d32093bfb8a65f2aef9800..57b8df2ce18df58ff54b2d828af67e3c pair: false }, 'AES-GCM': { -@@ -42,6 +43,7 @@ const kWrappingData = { +@@ -46,30 +47,9 @@ if (!process.features.openssl_is_boringssl) { + generate: { length: 128 }, wrap: { }, pair: false - } +- }; +- kWrappingData['ChaCha20-Poly1305'] = { +- wrap: { +- iv: new Uint8Array(12), +- additionalData: new Uint8Array(16), +- tagLength: 128 +- }, +- pair: false +- }; +-} else { +- common.printSkipMessage('Skipping unsupported AES-KW test case'); +-} +- +-if (hasOpenSSL(3)) { +- kWrappingData['AES-OCB'] = { +- generate: { length: 128 }, +- wrap: { +- iv: new Uint8Array(15), +- additionalData: new Uint8Array(16), +- tagLength: 128 +- }, +- pair: false +- }; +-} ++ } + */ - }; ++}; function generateWrappingKeys() { + return Promise.all(Object.keys(kWrappingData).map(async (name) => { diff --git a/test/parallel/test-x509-escaping.js b/test/parallel/test-x509-escaping.js index b507af88e1f7f3424b7b5d6d683a295b9d208e5e..825ba4c8dce775f401080a0522565bb7a087bcc3 100644 --- a/test/parallel/test-x509-escaping.js diff --git a/patches/node/fix_do_not_resolve_electron_entrypoints.patch b/patches/node/fix_do_not_resolve_electron_entrypoints.patch index e481b7a973137..03664584dcbdc 100644 --- a/patches/node/fix_do_not_resolve_electron_entrypoints.patch +++ b/patches/node/fix_do_not_resolve_electron_entrypoints.patch @@ -6,21 +6,22 @@ Subject: fix: do not resolve electron entrypoints This wastes fs cycles and can result in strange behavior if this path actually exists on disk diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js -index 8b55082d2bb0ce743b190a601aff0651095049cd..eb71a78c91b277157980aa1359578390c9fd1ae3 100644 +index 1f967df42128a05e49acfa6d409737c06a3372e3..c9b0dae3378f556c453f4fa31208eb6f57c433a9 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js -@@ -293,6 +293,9 @@ function cjsPreparseModuleExports(filename, source, isMain, format) { - if (module && module[kModuleExportNames] !== undefined) { +@@ -408,6 +408,10 @@ function cjsPreparseModuleExports(filename, source, format) { return { module, exportNames: module[kModuleExportNames] }; } + + if (filename === 'electron') { + return { module, exportNames: new SafeSet(['default', ...Object.keys(module.exports)]) }; + } - const loaded = Boolean(module); - if (!loaded) { - module = new CJSModule(filename); ++ + if (source === undefined) { + ({ source } = loadSourceForCJSWithHooks(module, filename, format)); + } diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js -index 02ba43adc2c8e92a78942bbb04023a16f5870ee9..bbf1ab69b884a9325bebdd07b2c4fd354eee946b 100644 +index 2a9ef56d1568080d19d4b6e68a14c752e48c3822..fb45f3dc66a49a554df1c06431197392c0a199b7 100644 --- a/lib/internal/modules/run_main.js +++ b/lib/internal/modules/run_main.js @@ -2,6 +2,7 @@ @@ -31,8 +32,8 @@ index 02ba43adc2c8e92a78942bbb04023a16f5870ee9..bbf1ab69b884a9325bebdd07b2c4fd35 globalThis, } = primordials; -@@ -26,6 +27,13 @@ const { - * @param {string} main - Entry point path +@@ -27,6 +28,13 @@ const { + * @returns {string|undefined} */ function resolveMainPath(main) { + // For built-in modules used as the main entry point we _never_ @@ -42,11 +43,11 @@ index 02ba43adc2c8e92a78942bbb04023a16f5870ee9..bbf1ab69b884a9325bebdd07b2c4fd35 + return main; + } + - const defaultType = getOptionValue('--experimental-default-type'); /** @type {string} */ let mainPath; -@@ -62,6 +70,13 @@ function resolveMainPath(main) { - * @param {string} mainPath - Absolute path to the main entry point + // Extension searching for the main entry point is supported for backward compatibility. +@@ -50,6 +58,13 @@ function resolveMainPath(main) { + * @returns {boolean} */ function shouldUseESMLoader(mainPath) { + // For built-in modules used as the main entry point we _never_ @@ -56,6 +57,6 @@ index 02ba43adc2c8e92a78942bbb04023a16f5870ee9..bbf1ab69b884a9325bebdd07b2c4fd35 + return false; + } + - if (getOptionValue('--experimental-default-type') === 'module') { return true; } - /** + * @type {string[]} userLoaders A list of custom loaders registered by the user + * (or an empty list when none have been registered). diff --git a/patches/node/fix_ensure_traverseparent_bails_on_resource_path_exit.patch b/patches/node/fix_ensure_traverseparent_bails_on_resource_path_exit.patch index 2a3a90362897e..2b8b182e909f6 100644 --- a/patches/node/fix_ensure_traverseparent_bails_on_resource_path_exit.patch +++ b/patches/node/fix_ensure_traverseparent_bails_on_resource_path_exit.patch @@ -8,10 +8,10 @@ resource path. This commit ensures that the TraverseParent function bails out if the parent path is outside of the resource path. diff --git a/src/node_modules.cc b/src/node_modules.cc -index 55d628f0c5e7f330e548878807de26d51ef025b5..c06779dea471b6f6a8dd29d4657162ef0faec043 100644 +index cbc3283fc2d511cce2eae0048cc9bf0fa917d38a..3b4d82da2ad30cafa96611eaa2d68ddf1badeac0 100644 --- a/src/node_modules.cc +++ b/src/node_modules.cc -@@ -291,8 +291,41 @@ const BindingData::PackageConfig* BindingData::TraverseParent( +@@ -320,8 +320,41 @@ const BindingData::PackageConfig* BindingData::TraverseParent( Realm* realm, const std::filesystem::path& check_path) { std::filesystem::path current_path = check_path; auto env = realm->env(); @@ -47,22 +47,22 @@ index 55d628f0c5e7f330e548878807de26d51ef025b5..c06779dea471b6f6a8dd29d4657162ef + }); + }; + -+ bool did_original_path_start_with_resources_path = starts_with(check_path. -+ generic_string(), resources_path); ++ bool did_original_path_start_with_resources_path = starts_with( ++ ConvertGenericPathToUTF8(check_path), resources_path); + do { current_path = current_path.parent_path(); -@@ -311,6 +344,12 @@ const BindingData::PackageConfig* BindingData::TraverseParent( - return nullptr; +@@ -341,6 +374,12 @@ const BindingData::PackageConfig* BindingData::TraverseParent( + } } + // If current path is outside the resources path, bail. + if (did_original_path_start_with_resources_path && -+ !starts_with(current_path.generic_string(), resources_path)) { ++ !starts_with(ConvertGenericPathToUTF8(current_path), resources_path)) { + return nullptr; + } + // Check if the path ends with `/node_modules` - if (current_path.generic_string().ends_with("/node_modules")) { + if (current_path.filename() == "node_modules") { return nullptr; diff --git a/patches/node/fix_expose_readfilesync_override_for_modules.patch b/patches/node/fix_expose_readfilesync_override_for_modules.patch index 3feb62a0ed205..62b99c918f08e 100644 --- a/patches/node/fix_expose_readfilesync_override_for_modules.patch +++ b/patches/node/fix_expose_readfilesync_override_for_modules.patch @@ -8,10 +8,10 @@ an API override to replace the native `ReadFileSync` in the `modules` binding. diff --git a/src/env_properties.h b/src/env_properties.h -index d4961ac90fbc7fffe44f7d494bfae37ba0fa07e0..7b414e6733adff5740bd8e661846824962048c3e 100644 +index 2884149d82d180e0d2ecfa7ac8fd92f201f1cb55..dded4bf3d7106d127efbad81087f0c375b2b2c95 100644 --- a/src/env_properties.h +++ b/src/env_properties.h -@@ -505,6 +505,7 @@ +@@ -490,6 +490,7 @@ V(maybe_cache_generated_source_map, v8::Function) \ V(messaging_deserialize_create_object, v8::Function) \ V(message_port, v8::Object) \ @@ -20,18 +20,18 @@ index d4961ac90fbc7fffe44f7d494bfae37ba0fa07e0..7b414e6733adff5740bd8e6618468249 V(performance_entry_callback, v8::Function) \ V(prepare_stack_trace_callback, v8::Function) \ diff --git a/src/node_modules.cc b/src/node_modules.cc -index c06779dea471b6f6a8dd29d4657162ef0faec043..6204986dc97686a248d6ae483f3a413ee5c51e47 100644 +index 9eec93f52f0d0b2e45ae04ff357b4ced0770782f..eea4ba313d8dbcf7b88b79f5a3e9ba2eb39d7c3e 100644 --- a/src/node_modules.cc +++ b/src/node_modules.cc -@@ -21,6 +21,7 @@ namespace modules { - +@@ -23,6 +23,7 @@ namespace modules { using v8::Array; using v8::Context; + using v8::External; +using v8::Function; using v8::FunctionCallbackInfo; using v8::HandleScope; - using v8::Isolate; -@@ -89,6 +90,7 @@ Local<Array> BindingData::PackageConfig::Serialize(Realm* realm) const { + using v8::Integer; +@@ -94,6 +95,7 @@ Local<Array> BindingData::PackageConfig::Serialize(Realm* realm) const { const BindingData::PackageConfig* BindingData::GetPackageJSON( Realm* realm, std::string_view path, ErrorContext* error_context) { @@ -39,7 +39,7 @@ index c06779dea471b6f6a8dd29d4657162ef0faec043..6204986dc97686a248d6ae483f3a413e auto binding_data = realm->GetBindingData<BindingData>(); auto cache_entry = binding_data->package_configs_.find(path.data()); -@@ -98,8 +100,36 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( +@@ -103,8 +105,36 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( PackageConfig package_config{}; package_config.file_path = path; @@ -76,8 +76,8 @@ index c06779dea471b6f6a8dd29d4657162ef0faec043..6204986dc97686a248d6ae483f3a413e + if (read_err < 0) { return nullptr; } - // In some systems, std::string is annotated to generate an -@@ -249,6 +279,12 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( + simdjson::ondemand::document document; +@@ -242,6 +272,12 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON( return &cached.first->second; } @@ -90,7 +90,7 @@ index c06779dea471b6f6a8dd29d4657162ef0faec043..6204986dc97686a248d6ae483f3a413e void BindingData::ReadPackageJSON(const FunctionCallbackInfo<Value>& args) { CHECK_GE(args.Length(), 1); // path, [is_esm, base, specifier] CHECK(args[0]->IsString()); // path -@@ -643,6 +679,8 @@ void InitImportMetaPathHelpers(const FunctionCallbackInfo<Value>& args) { +@@ -635,6 +671,8 @@ void SaveCompileCacheEntry(const FunctionCallbackInfo<Value>& args) { void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data, Local<ObjectTemplate> target) { Isolate* isolate = isolate_data->isolate(); @@ -99,7 +99,7 @@ index c06779dea471b6f6a8dd29d4657162ef0faec043..6204986dc97686a248d6ae483f3a413e SetMethod(isolate, target, "readPackageJSON", ReadPackageJSON); SetMethod(isolate, target, -@@ -685,6 +723,8 @@ void BindingData::CreatePerContextProperties(Local<Object> target, +@@ -694,6 +732,8 @@ void BindingData::CreatePerContextProperties(Local<Object> target, void BindingData::RegisterExternalReferences( ExternalReferenceRegistry* registry) { @@ -107,9 +107,9 @@ index c06779dea471b6f6a8dd29d4657162ef0faec043..6204986dc97686a248d6ae483f3a413e + registry->Register(ReadPackageJSON); registry->Register(GetNearestParentPackageJSONType); - registry->Register(GetNearestParentPackageJSON); + registry->Register(GetPackageScopeConfig<false>); diff --git a/src/node_modules.h b/src/node_modules.h -index eb2900d8f8385238f89a6dcc972a28e5fcb1d288..e28f38d98f4f8749048af135f0dcbe55aa69c4fe 100644 +index e4ba6b75bc86d14deada835903ba68a4cb0eccc5..ae77f9ec81b358bd356993617cd07671d382e8ca 100644 --- a/src/node_modules.h +++ b/src/node_modules.h @@ -54,6 +54,8 @@ class BindingData : public SnapshotableObject { @@ -119,5 +119,5 @@ index eb2900d8f8385238f89a6dcc972a28e5fcb1d288..e28f38d98f4f8749048af135f0dcbe55 + static void OverrideReadFileSync( + const v8::FunctionCallbackInfo<v8::Value>& args); static void ReadPackageJSON(const v8::FunctionCallbackInfo<v8::Value>& args); - static void GetNearestParentPackageJSON( + static void GetNearestParentPackageJSONType( const v8::FunctionCallbackInfo<v8::Value>& args); diff --git a/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch index e6cbd4f2f6d9f..9abfc8d1c74b2 100644 --- a/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch +++ b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch @@ -6,7 +6,7 @@ Subject: fix: expose the built-in electron module via the ESM loader This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js -index 9519f947b8dfdc69808839948c9cb8434a0acf0e..23ce72d479f638c33edffcea7c35f5da6cab7cae 100644 +index 01584983c16a2ab6eec2fbb01208504f2771148b..6afbbca6c95103f3ecad29485581c94735bac0d3 100644 --- a/lib/internal/modules/esm/get_format.js +++ b/lib/internal/modules/esm/get_format.js @@ -26,6 +26,7 @@ const protocolHandlers = { @@ -18,10 +18,10 @@ index 9519f947b8dfdc69808839948c9cb8434a0acf0e..23ce72d479f638c33edffcea7c35f5da /** diff --git a/lib/internal/modules/esm/load.js b/lib/internal/modules/esm/load.js -index e718d7b3e7c11addc78cf7af33c93f63a9cb247b..3334818153068468967baa5adc1ed2382592ec76 100644 +index 8414d303c078d51a93c9127a1fd8d6f24961b104..e8a2326e158550786620439fa4039c2b449624cc 100644 --- a/lib/internal/modules/esm/load.js +++ b/lib/internal/modules/esm/load.js -@@ -81,7 +81,7 @@ function defaultLoad(url, context = kEmptyObject) { +@@ -77,7 +77,7 @@ function defaultLoad(url, context = kEmptyObject) { throwIfUnsupportedURLScheme(urlInstance); @@ -29,8 +29,8 @@ index e718d7b3e7c11addc78cf7af33c93f63a9cb247b..3334818153068468967baa5adc1ed238 + if (urlInstance.protocol === 'node:' || format === 'electron') { source = null; format ??= 'builtin'; - } else if (format !== 'commonjs' || defaultType === 'module') { -@@ -94,7 +94,7 @@ function defaultLoad(url, context = kEmptyObject) { + } else if (format === 'addon') { +@@ -93,7 +93,7 @@ function defaultLoad(url, context = kEmptyObject) { // Now that we have the source for the module, run `defaultGetFormat` to detect its format. format = defaultGetFormat(urlInstance, context); @@ -39,7 +39,7 @@ index e718d7b3e7c11addc78cf7af33c93f63a9cb247b..3334818153068468967baa5adc1ed238 // For backward compatibility reasons, we need to discard the source in // order for the CJS loader to re-fetch it. source = null; -@@ -142,7 +142,7 @@ function defaultLoadSync(url, context = kEmptyObject) { +@@ -141,7 +141,7 @@ function defaultLoadSync(url, context = kEmptyObject) { throwIfUnsupportedURLScheme(urlInstance, false); @@ -48,7 +48,7 @@ index e718d7b3e7c11addc78cf7af33c93f63a9cb247b..3334818153068468967baa5adc1ed238 source = null; } else if (source == null) { ({ responseURL, source } = getSourceSync(urlInstance, context)); -@@ -175,12 +175,13 @@ function throwIfUnsupportedURLScheme(parsed) { +@@ -174,12 +174,13 @@ function throwIfUnsupportedURLScheme(parsed) { protocol !== 'file:' && protocol !== 'data:' && protocol !== 'node:' && @@ -64,10 +64,10 @@ index e718d7b3e7c11addc78cf7af33c93f63a9cb247b..3334818153068468967baa5adc1ed238 } } diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js -index 8d98d50395cf7fbbaf9ae30387727bff5c6cd550..ed3b3c02bbdac78c163d589557651618814685a5 100644 +index 300da51afe6185f5f9799a88fc75ba3b8f0cf5fb..4c7e2dc8c00c7a38a27169d1cc08e27f89e74fbb 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js -@@ -494,7 +494,7 @@ class ModuleLoader { +@@ -522,7 +522,7 @@ class ModuleLoader { } const cjsModule = wrap[imported_cjs_symbol]; @@ -77,10 +77,10 @@ index 8d98d50395cf7fbbaf9ae30387727bff5c6cd550..ed3b3c02bbdac78c163d589557651618 // Check if the ESM initiating import CJS is being required by the same CJS module. if (cjsModule?.[kIsExecuting]) { diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js -index 859b6bfedac4bbee2df054f9ebca7cbaaed45f18..5aa946f66c71beff0b7a43c30638ab28a1a5dfc0 100644 +index c27ee4c6612c6a7ea0b6355f03563e8724fd0e40..5f03cf14e948d449d303b22ab6710b5508fb83b2 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js -@@ -750,6 +750,9 @@ function packageImportsResolve(name, base, conditions) { +@@ -751,6 +751,9 @@ function packageImportsResolve(name, base, conditions) { throw importNotDefined(name, packageJSONUrl, base); } @@ -90,7 +90,7 @@ index 859b6bfedac4bbee2df054f9ebca7cbaaed45f18..5aa946f66c71beff0b7a43c30638ab28 /** * Resolves a package specifier to a URL. -@@ -764,6 +767,11 @@ function packageResolve(specifier, base, conditions) { +@@ -765,6 +768,11 @@ function packageResolve(specifier, base, conditions) { return new URL('node:' + specifier); } @@ -103,30 +103,21 @@ index 859b6bfedac4bbee2df054f9ebca7cbaaed45f18..5aa946f66c71beff0b7a43c30638ab28 const packageConfig = packageJsonReader.read(packageJSONPath, { __proto__: null, specifier, base, isESM: true }); diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js -index 3a69558d7a3dba5bfcb7d3c13299f698fe6c18a1..de1539cebeb1874cbafbe76a4f03217693db2aa1 100644 +index 147d96bda8098fe16e5d0053e36eab05fb489c22..3c82913ca381eba30596f22a734b49dcba9b6f5b 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js -@@ -188,7 +188,7 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul - - const { exportNames, module } = cjsPreparseModuleExports(filename, source, isMain, format); +@@ -215,7 +215,9 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul + const { exportNames, module } = cjsPreparseModuleExports(filename, source, format); cjsCache.set(url, module); -- const namesWithDefault = exportNames.has('default') ? -+ const namesWithDefault = filename === 'electron' ? ['default', ...Object.keys(module.exports)] : exportNames.has('default') ? - [...exportNames] : ['default', ...exportNames]; - if (isMain) { -@@ -210,8 +210,8 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul - ({ exports } = module); - } - for (const exportName of exportNames) { -- if (!ObjectPrototypeHasOwnProperty(exports, exportName) || -- exportName === 'default') { -+ if (exportName === 'default' || -+ !ObjectPrototypeHasOwnProperty(exports, exportName)) { - continue; - } - // We might trigger a getter -> dont fail. -@@ -245,6 +245,10 @@ translators.set('require-commonjs', (url, source, isMain) => { +- const wrapperNames = [...exportNames]; ++ const wrapperNames = filename === 'electron' ? ++ ['default', ...Object.keys(module.exports)] : ++ [...exportNames]; + if (!exportNames.has('default')) { + ArrayPrototypePush(wrapperNames, 'default'); + } +@@ -319,6 +321,10 @@ translators.set('require-commonjs', (url, source, isMain) => { return createCJSModuleWrap(url, source, isMain, 'commonjs'); }); @@ -138,10 +129,10 @@ index 3a69558d7a3dba5bfcb7d3c13299f698fe6c18a1..de1539cebeb1874cbafbe76a4f032176 // This translator function must be sync, as `require` is sync. translators.set('require-commonjs-typescript', (url, source, isMain) => { diff --git a/lib/internal/url.js b/lib/internal/url.js -index b6057ae6656e03d98ea40c018369419749409c6d..9bd9abd49523406fd9ac77f2b5efe311da1fa9aa 100644 +index a1473fdac8aba3be541df3b6688a05c0dfbe403f..0a87d997856ea227f8f21393909ffc4634043f24 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js -@@ -1604,6 +1604,8 @@ function fileURLToPath(path, options = kEmptyObject) { +@@ -1609,6 +1609,8 @@ function fileURLToPath(path, options = kEmptyObject) { path = new URL(path); else if (!isURL(path)) throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path); diff --git a/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch b/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch index 689fe6d14fb64..aec3faa38e0ea 100644 --- a/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch +++ b/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch @@ -17,160 +17,82 @@ Upstreams: - https://github.com/nodejs/node/pull/39136 diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc -index 6f9406eecacb7411a2e84a7b51e60b726d1961f3..a0cfb0bc3776dc3682cdb332ed418286d3243bd1 100644 +index e1c2da6969a1ce937d397735e844930f3234bba7..0bed152014949c22b6c610198df39a2522890279 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc -@@ -786,7 +786,7 @@ bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) { - - bool ok = true; - -- for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) { -+ for (size_t i = 0; i < sk_GENERAL_NAME_num(names); i++) { - GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i); - - if (i != 0) BIO_write(out.get(), ", ", 2); -@@ -810,7 +810,7 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) { - - bool ok = true; - -- for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) { -+ for (size_t i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) { - ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i); - - if (i != 0) BIO_write(out.get(), "\n", 1); -@@ -952,13 +952,17 @@ BIOPointer X509View::getValidTo() const { - - int64_t X509View::getValidToTime() const { +@@ -11,6 +11,7 @@ + #include <array> + #include <cstring> + #include <string_view> ++#include <vector> + #if OPENSSL_VERSION_MAJOR >= 3 + #include <openssl/core_names.h> + #include <openssl/params.h> +@@ -1130,7 +1131,9 @@ int64_t X509View::getValidToTime() const { + return tp; + #else struct tm tp; - ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp); +#ifndef OPENSSL_IS_BORINGSSL + ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp); +#endif return PortableTimeGM(&tp); + #endif } - - int64_t X509View::getValidFromTime() const { +@@ -1142,7 +1145,9 @@ int64_t X509View::getValidFromTime() const { + return tp; + #else struct tm tp; +#ifndef OPENSSL_IS_BORINGSSL ASN1_TIME_to_tm(X509_get0_notBefore(cert_), &tp); +#endif return PortableTimeGM(&tp); + #endif } - -@@ -1233,7 +1237,11 @@ BIOPointer BIOPointer::NewMem() { - } - - BIOPointer BIOPointer::NewSecMem() { -- return BIOPointer(BIO_new(BIO_s_secmem())); -+#ifdef OPENSSL_IS_BORINGSSL -+ return BIOPointer(BIO_new(BIO_s_mem())); -+#else -+ return BIOPointer(BIO_new(BIO_s_secmem())); -+#endif - } - - BIOPointer BIOPointer::New(const BIO_METHOD* method) { -@@ -1303,8 +1311,10 @@ BignumPointer DHPointer::FindGroup(const std::string_view name, - #define V(n, p) \ - if (EqualNoCase(name, n)) return BignumPointer(p(nullptr)); - if (option != FindGroupOption::NO_SMALL_PRIMES) { -+#ifndef OPENSSL_IS_BORINGSSL - V("modp1", BN_get_rfc2409_prime_768); - V("modp2", BN_get_rfc2409_prime_1024); -+#endif - V("modp5", BN_get_rfc3526_prime_1536); - } - V("modp14", BN_get_rfc3526_prime_2048); -@@ -1380,11 +1390,13 @@ DHPointer::CheckPublicKeyResult DHPointer::checkPublicKey( - int codes = 0; - if (DH_check_pub_key(dh_.get(), pub_key.get(), &codes) != 1) - return DHPointer::CheckPublicKeyResult::CHECK_FAILED; -+#ifndef OPENSSL_IS_BORINGSSL - if (codes & DH_CHECK_PUBKEY_TOO_SMALL) { - return DHPointer::CheckPublicKeyResult::TOO_SMALL; - } else if (codes & DH_CHECK_PUBKEY_TOO_SMALL) { - return DHPointer::CheckPublicKeyResult::TOO_LARGE; -- } else if (codes != 0) { -+#endif -+ if (codes != 0) { - return DHPointer::CheckPublicKeyResult::INVALID; - } - return CheckPublicKeyResult::NONE; -@@ -2327,7 +2339,7 @@ const std::string_view SSLPointer::getClientHelloAlpn() const { - const unsigned char* buf; - size_t len; - size_t rem; +@@ -2886,10 +2891,6 @@ std::optional<uint32_t> SSLPointer::verifyPeerCertificate() const { + const char* SSLPointer::getClientHelloAlpn() const { + if (ssl_ == nullptr) return {}; + #ifndef OPENSSL_IS_BORINGSSL +- const unsigned char* buf; +- size_t len; +- size_t rem; - -+#ifndef OPENSSL_IS_BORINGSSL if (!SSL_client_hello_get0_ext( get(), TLSEXT_TYPE_application_layer_protocol_negotiation, -@@ -2340,6 +2352,8 @@ const std::string_view SSLPointer::getClientHelloAlpn() const { - len = (buf[0] << 8) | buf[1]; - if (len + 2 != rem) return {}; - return reinterpret_cast<const char*>(buf + 3); -+#endif -+ return {}; - } - - const std::string_view SSLPointer::getClientHelloServerName() const { -@@ -2347,7 +2361,7 @@ const std::string_view SSLPointer::getClientHelloServerName() const { - const unsigned char* buf; - size_t len; - size_t rem; -- +@@ -3090,9 +3091,11 @@ const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm); + const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap); + const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap); + const Cipher Cipher::AES_256_KW = Cipher::FromNid(NID_id_aes256_wrap); +#ifndef OPENSSL_IS_BORINGSSL - if (!SSL_client_hello_get0_ext(get(), TLSEXT_TYPE_server_name, &buf, &rem) || - rem <= 2) { - return {}; -@@ -2363,6 +2377,8 @@ const std::string_view SSLPointer::getClientHelloServerName() const { - len = (*(buf + 3) << 8) | *(buf + 4); - if (len + 2 > rem) return {}; - return reinterpret_cast<const char*>(buf + 5); + const Cipher Cipher::AES_128_OCB = Cipher::FromNid(NID_aes_128_ocb); + const Cipher Cipher::AES_192_OCB = Cipher::FromNid(NID_aes_192_ocb); + const Cipher Cipher::AES_256_OCB = Cipher::FromNid(NID_aes_256_ocb); +#endif -+ return {}; - } + const Cipher Cipher::CHACHA20_POLY1305 = Cipher::FromNid(NID_chacha20_poly1305); - std::optional<const std::string_view> SSLPointer::GetServerName( -@@ -2396,8 +2412,11 @@ bool SSLPointer::isServer() const { - EVPKeyPointer SSLPointer::getPeerTempKey() const { - if (!ssl_) return {}; - EVP_PKEY* raw_key = nullptr; -+#ifndef OPENSSL_IS_BORINGSSL - if (!SSL_get_peer_tmp_key(get(), &raw_key)) return {}; - return EVPKeyPointer(raw_key); -+#endif -+ return {}; - } - - SSLCtxPointer::SSLCtxPointer(SSL_CTX* ctx) : ctx_(ctx) {} + bool Cipher::isGcmMode() const { diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h -index e5bf2b529bf23914677e25d7468aad58a4684557..9a3c6029ff3319cce58c79782a7bd5d1fcd467f9 100644 +index 175ec8ba0f2a908ffad2ce48434aeed573b09c90..3218590ddce1e92c2a9d776f20f9fb016612061d 100644 --- a/deps/ncrypto/ncrypto.h +++ b/deps/ncrypto/ncrypto.h -@@ -623,17 +623,21 @@ class DHPointer final { - UNABLE_TO_CHECK_GENERATOR = DH_UNABLE_TO_CHECK_GENERATOR, - NOT_SUITABLE_GENERATOR = DH_NOT_SUITABLE_GENERATOR, - Q_NOT_PRIME = DH_CHECK_Q_NOT_PRIME, +@@ -306,9 +306,13 @@ class Cipher final { + #else + static constexpr size_t MAX_AUTH_TAG_LENGTH = 16; + #endif +- static_assert(EVP_GCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH && +- EVP_CCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH && +- EVP_CHACHAPOLY_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH); ++ static_assert(EVP_GCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH +#ifndef OPENSSL_IS_BORINGSSL - INVALID_Q = DH_CHECK_INVALID_Q_VALUE, - INVALID_J = DH_CHECK_INVALID_J_VALUE, ++ && EVP_CCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH ++ && EVP_CHACHAPOLY_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH); ++#else ++ ); +#endif - CHECK_FAILED = 512, - }; - CheckResult check(); - enum class CheckPublicKeyResult { - NONE, -+#ifndef OPENSSL_IS_BORINGSSL - TOO_SMALL = DH_R_CHECK_PUBKEY_TOO_SMALL, - TOO_LARGE = DH_R_CHECK_PUBKEY_TOO_LARGE, -- INVALID = DH_R_CHECK_PUBKEY_INVALID, -+#endif -+ INVALID = DH_R_INVALID_PUBKEY, - CHECK_FAILED = 512, - }; - // Check to see if the given public key is suitable for this DH instance. + Cipher() = default; + Cipher(const EVP_CIPHER* cipher) : cipher_(cipher) {} diff --git a/node.gni b/node.gni index e2407027ab05e59b2f0f1c213b98ea469db7a91b..c64761b730e61edcdc0e46a48699f2fd5bb1c0a6 100644 --- a/node.gni @@ -185,31 +107,32 @@ index e2407027ab05e59b2f0f1c213b98ea469db7a91b..c64761b730e61edcdc0e46a48699f2fd # The location of simdutf - use the one from node's deps by default. node_simdutf_path = "//third_party/simdutf" diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc -index 2176fb6982484e2c42538478eeb4dd81c9d50ee1..c00d3616e08b00b1e0a3a29b2dbb5278e1e14fcc 100644 +index 5ed2f8b35a1e2f8348a0f3891f37944f49371256..bd453ae633b2833cc3c6e3e415b43792dc5bf2e5 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc -@@ -1027,7 +1027,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) { - if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) { - return ThrowCryptoError(env, ERR_get_error()); +@@ -447,6 +447,7 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, } -- + } else { + if (auth_tag_len == kNoAuthTagLength) { +#ifndef OPENSSL_IS_BORINGSSL - int rsa_pkcs1_implicit_rejection = - EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pkcs1_implicit_rejection", "1"); - // From the doc -2 means that the option is not supported. -@@ -1042,6 +1042,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) { - env, - "RSA_PKCS1_PADDING is no longer supported for private decryption"); - } + // We treat ChaCha20-Poly1305 specially. Like GCM, the authentication tag + // length defaults to 16 bytes when encrypting. Unlike GCM, the + // authentication tag length also defaults to 16 bytes when decrypting, +@@ -458,6 +459,9 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, + env(), "authTagLength required for %s", cipher_type); + return false; + } ++#else ++ return false; +#endif - } + } - const EVP_MD* digest = nullptr; + // TODO(tniessen) Support CCM decryption in FIPS mode diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc -index d94f6e1c82c4a62547b3b395f375c86ce4deb5de..b81b9005365272217c77e2b9289bd9f877c0e77c 100644 +index d005bf0ffb93445fa6611a1beb1b465764271ede..01770687bd191c61af02e76d7de24bbac5c47b8f 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc -@@ -124,7 +124,7 @@ StackOfX509 CloneSSLCerts(X509Pointer&& cert, +@@ -90,7 +90,7 @@ StackOfX509 CloneSSLCerts(X509Pointer&& cert, if (!peer_certs) return StackOfX509(); if (cert && !sk_X509_push(peer_certs.get(), cert.release())) return StackOfX509(); @@ -218,7 +141,7 @@ index d94f6e1c82c4a62547b3b395f375c86ce4deb5de..b81b9005365272217c77e2b9289bd9f8 X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i))); if (!cert || !sk_X509_push(peer_certs.get(), cert.get())) return StackOfX509(); -@@ -140,7 +140,7 @@ MaybeLocal<Object> AddIssuerChainToObject(X509Pointer* cert, +@@ -106,7 +106,7 @@ MaybeLocal<Object> AddIssuerChainToObject(X509Pointer* cert, Environment* const env) { cert->reset(sk_X509_delete(peer_certs.get(), 0)); for (;;) { @@ -228,10 +151,10 @@ index d94f6e1c82c4a62547b3b395f375c86ce4deb5de..b81b9005365272217c77e2b9289bd9f8 X509View ca(sk_X509_value(peer_certs.get(), i)); if (!cert->view().isIssuedBy(ca)) continue; diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc -index 64b850089ec837915910a243b1d5e4ed68655f63..508f7c1a49a0812583363c9e35244c3f5fbf5f89 100644 +index 6482bd58bb6a95cfa4074ea9535e1443aea66bb5..20d3c1d9d17fde18fc09b6ee219137831eb08a45 100644 --- a/src/crypto/crypto_context.cc +++ b/src/crypto/crypto_context.cc -@@ -121,7 +121,7 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, +@@ -143,7 +143,7 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, // the CA certificates. SSL_CTX_clear_extra_chain_certs(ctx); @@ -240,7 +163,7 @@ index 64b850089ec837915910a243b1d5e4ed68655f63..508f7c1a49a0812583363c9e35244c3f X509* ca = sk_X509_value(extra_certs, i); // NOTE: Increments reference count on `ca` -@@ -1584,11 +1584,12 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) { +@@ -1831,11 +1831,12 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) { // If the user specified "auto" for dhparams, the JavaScript layer will pass // true to this function instead of the original string. Any other string // value will be interpreted as custom DH parameters below. @@ -254,7 +177,7 @@ index 64b850089ec837915910a243b1d5e4ed68655f63..508f7c1a49a0812583363c9e35244c3f DHPointer dh; { BIOPointer bio(LoadBIO(env, args[0])); -@@ -1814,7 +1815,7 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { +@@ -2061,7 +2062,7 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { } // Add CA certs too @@ -264,71 +187,10 @@ index 64b850089ec837915910a243b1d5e4ed68655f63..508f7c1a49a0812583363c9e35244c3f X509_STORE_add_cert(sc->GetCertStoreOwnedByThisSecureContext(), ca); diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc -index c26a88b395abfc645da56231635b36fb23c8fa09..f23cedf4f2449d8edc9a8de1b70332e75d693cdd 100644 +index e35fda9ad2e8c52c75492d66566dc6e6c57dd2ae..46a7d1396dc1a175ae99f4e403721f1730fdd320 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc -@@ -7,7 +7,9 @@ - #include "memory_tracker-inl.h" - #include "ncrypto.h" - #include "node_errors.h" -+#ifndef OPENSSL_IS_BORINGSSL - #include "openssl/bnerr.h" -+#endif - #include "openssl/dh.h" - #include "threadpoolwork-inl.h" - #include "v8.h" -@@ -88,11 +90,7 @@ void New(const FunctionCallbackInfo<Value>& args) { - if (args[0]->IsInt32()) { - int32_t bits = args[0].As<Int32>()->Value(); - if (bits < 2) { --#if OPENSSL_VERSION_MAJOR >= 3 -- ERR_put_error(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_SMALL, __FILE__, __LINE__); --#else -- ERR_put_error(ERR_LIB_BN, 0, BN_R_BITS_TOO_SMALL, __FILE__, __LINE__); --#endif -+ OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); - return ThrowCryptoError(env, ERR_get_error(), "Invalid prime length"); - } - -@@ -105,7 +103,7 @@ void New(const FunctionCallbackInfo<Value>& args) { - } - int32_t generator = args[1].As<Int32>()->Value(); - if (generator < 2) { -- ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__); -+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); - return ThrowCryptoError(env, ERR_get_error(), "Invalid generator"); - } - -@@ -134,12 +132,12 @@ void New(const FunctionCallbackInfo<Value>& args) { - if (args[1]->IsInt32()) { - int32_t generator = args[1].As<Int32>()->Value(); - if (generator < 2) { -- ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__); -+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); - return ThrowCryptoError(env, ERR_get_error(), "Invalid generator"); - } - bn_g = BignumPointer::New(); - if (!bn_g.setWord(generator)) { -- ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__); -+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); - return ThrowCryptoError(env, ERR_get_error(), "Invalid generator"); - } - } else { -@@ -148,11 +146,11 @@ void New(const FunctionCallbackInfo<Value>& args) { - return THROW_ERR_OUT_OF_RANGE(env, "generator is too big"); - bn_g = BignumPointer(reinterpret_cast<uint8_t*>(arg1.data()), arg1.size()); - if (!bn_g) { -- ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__); -+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); - return ThrowCryptoError(env, ERR_get_error(), "Invalid generator"); - } - if (bn_g.getWord() < 2) { -- ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__); -+ OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); - return ThrowCryptoError(env, ERR_get_error(), "Invalid generator"); - } - } -@@ -260,15 +258,17 @@ void ComputeSecret(const FunctionCallbackInfo<Value>& args) { +@@ -309,15 +309,17 @@ void ComputeSecret(const FunctionCallbackInfo<Value>& args) { BignumPointer key(key_buf.data(), key_buf.size()); switch (dh.checkPublicKey(key)) { @@ -348,58 +210,24 @@ index c26a88b395abfc645da56231635b36fb23c8fa09..f23cedf4f2449d8edc9a8de1b70332e7 case DHPointer::CheckPublicKeyResult::NONE: break; } -@@ -400,9 +400,11 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { - key_params = EVPKeyPointer::New(); - CHECK(key_params); - CHECK_EQ(EVP_PKEY_assign_DH(key_params.get(), dh.release()), 1); -- } else if (int* prime_size = std::get_if<int>(¶ms->params.prime)) { -+ } else if (std::get_if<int>(¶ms->params.prime)) { - EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr)); - EVP_PKEY* raw_params = nullptr; -+#ifndef OPENSSL_IS_BORINGSSL -+ int* prime_size = std::get_if<int>(¶ms->params.prime); - if (!param_ctx || - EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 || - EVP_PKEY_CTX_set_dh_paramgen_prime_len( -@@ -416,6 +418,9 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { - } - - key_params = EVPKeyPointer(raw_params); -+#else -+ return EVPKeyCtxPointer(); -+#endif - } else { - UNREACHABLE(); - } -diff --git a/src/crypto/crypto_dsa.cc b/src/crypto/crypto_dsa.cc -index 471fee77531139ce988292470dff443fdfb05b07..931f7c2ae3d7e12afce471545d610d22f63412d7 100644 ---- a/src/crypto/crypto_dsa.cc -+++ b/src/crypto/crypto_dsa.cc -@@ -43,7 +43,7 @@ namespace crypto { - EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) { - EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr)); - EVP_PKEY* raw_params = nullptr; -- -+#ifndef OPENSSL_IS_BORINGSSL - if (!param_ctx || - EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 || - EVP_PKEY_CTX_set_dsa_paramgen_bits( -@@ -58,7 +58,9 @@ EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) { - return EVPKeyCtxPointer(); - } - } -- -+#else -+ return EVPKeyCtxPointer(); -+#endif - if (EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) - return EVPKeyCtxPointer(); - +diff --git a/src/crypto/crypto_hash.cc b/src/crypto/crypto_hash.cc +index 33cde71b105c7cf22b559583d2e46bfb50016f6d..659910992dff7c05bb7e367e1cba14256b46dea4 100644 +--- a/src/crypto/crypto_hash.cc ++++ b/src/crypto/crypto_hash.cc +@@ -232,7 +232,7 @@ void Hash::OneShotDigest(const FunctionCallbackInfo<Value>& args) { + enum encoding output_enc = ParseEncoding(isolate, args[4], args[5], HEX); + + bool is_xof = (EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0; +- int output_length = EVP_MD_size(md); ++ size_t output_length = EVP_MD_size(md); + + // This is to cause hash() to fail when an incorrect + // outputLength option was passed for a non-XOF hash function. diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc -index 7238cda445fd663e6b45fa134f31d017bb267dfc..522655555cdb2ab2083797f736bf167d1f42c15e 100644 +index e805a984322c8348ceba950fe6f45e002ade10b3..bb9b1f8e1b3c6dd8479ee463e303088e3240d6be 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc -@@ -949,6 +949,7 @@ void KeyObjectHandle::GetAsymmetricKeyType( +@@ -1034,6 +1034,7 @@ void KeyObjectHandle::GetAsymmetricKeyType( } bool KeyObjectHandle::CheckEcKeyData() const { @@ -407,62 +235,21 @@ index 7238cda445fd663e6b45fa134f31d017bb267dfc..522655555cdb2ab2083797f736bf167d MarkPopErrorOnReturn mark_pop_error_on_return; const auto& key = data_.GetAsymmetricKey(); -@@ -965,6 +966,9 @@ bool KeyObjectHandle::CheckEcKeyData() const { - #else - return EVP_PKEY_public_check(ctx.get()) == 1; - #endif +@@ -1043,6 +1044,9 @@ bool KeyObjectHandle::CheckEcKeyData() const { + + return data_.GetKeyType() == kKeyTypePrivate ? ctx.privateCheck() + : ctx.publicCheck(); +#else + return true; +#endif } void KeyObjectHandle::CheckEcKeyData(const FunctionCallbackInfo<Value>& args) { -diff --git a/src/crypto/crypto_random.cc b/src/crypto/crypto_random.cc -index 78f2093d1d010be6f9c492662f4f582657ff6a13..b6aef7fd27cd974697bcee05955bfd9ccf4d5837 100644 ---- a/src/crypto/crypto_random.cc -+++ b/src/crypto/crypto_random.cc -@@ -143,7 +143,7 @@ Maybe<void> RandomPrimeTraits::AdditionalConfig( - - params->bits = bits; - params->safe = safe; -- params->prime = BignumPointer::NewSecure(); -+ params->prime = BignumPointer::New(); - if (!params->prime) { - THROW_ERR_CRYPTO_OPERATION_FAILED(env, "could not generate prime"); - return Nothing<void>(); -diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc -index 05a3882c7e17d78e27aabb29891aa250789a47c0..1f2fccce6ed8f14525557644e0bdd130eedf3337 100644 ---- a/src/crypto/crypto_rsa.cc -+++ b/src/crypto/crypto_rsa.cc -@@ -612,10 +612,13 @@ Maybe<void> GetRsaKeyDetail(Environment* env, - } - - if (params->saltLength != nullptr) { -+#ifndef OPENSSL_IS_BORINGSSL -+ // TODO(codebytere): Upstream a shim to BoringSSL? - if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) { - ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error"); - return Nothing<void>(); - } -+#endif - } - - if (target diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc -index 7c548d32b40365343f0e208c3aa856a1c847f4c3..6346f8f7199cf7b7d3736c59571606fff102fbb6 100644 +index 205e248e0f20f019e189a6c69d3c011a616b3939..12b0d804c6f1d4998b85160b0aac8eb7a3b5576b 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc -@@ -207,7 +207,8 @@ void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) { - - void GetOpenSSLSecLevelCrypto(const FunctionCallbackInfo<Value>& args) { - // for BoringSSL assume the same as the default -- int sec_level = OPENSSL_TLS_SECURITY_LEVEL; -+ // value of OPENSSL_TLS_SECURITY_LEVEL. -+ int sec_level = 1; - #ifndef OPENSSL_IS_BORINGSSL - Environment* env = Environment::GetCurrent(args); - -@@ -527,24 +528,15 @@ Maybe<void> Decorate(Environment* env, +@@ -533,24 +533,15 @@ Maybe<void> Decorate(Environment* env, V(BIO) \ V(PKCS7) \ V(X509V3) \ @@ -488,43 +275,12 @@ index 7c548d32b40365343f0e208c3aa856a1c847f4c3..6346f8f7199cf7b7d3736c59571606ff V(USER) \ #define V(name) case ERR_LIB_##name: lib = #name "_"; break; -@@ -686,7 +678,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) { - CHECK(args[0]->IsUint32()); - Environment* env = Environment::GetCurrent(args); - uint32_t len = args[0].As<Uint32>()->Value(); -- void* data = OPENSSL_secure_zalloc(len); -+ void* data = OPENSSL_malloc(len); - if (data == nullptr) { - // There's no memory available for the allocation. - // Return nothing. -@@ -697,7 +689,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) { - data, - len, - [](void* data, size_t len, void* deleter_data) { -- OPENSSL_secure_clear_free(data, len); -+ OPENSSL_clear_free(data, len); - }, - data); - Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store); -@@ -705,10 +697,12 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) { - } - - void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) { -+#ifndef OPENSSL_IS_BORINGSSL - Environment* env = Environment::GetCurrent(args); - if (CRYPTO_secure_malloc_initialized()) - args.GetReturnValue().Set( - BigInt::New(env->isolate(), CRYPTO_secure_used())); -+#endif - } - } // namespace - diff --git a/src/env.h b/src/env.h -index c42493ad958508f650917bf5ca92088714a5056c..07accfbcca491966c6c8ad9c20e146dbd22347f0 100644 +index f3a2d221f4bb52987e1bdacdadf19aacfcf65ec3..d34aec43630b3cf53004d8180446d7136b59ceac 100644 --- a/src/env.h +++ b/src/env.h -@@ -50,7 +50,7 @@ - #include "uv.h" +@@ -52,7 +52,7 @@ + #include "v8-profiler.h" #include "v8.h" -#if HAVE_OPENSSL @@ -532,7 +288,7 @@ index c42493ad958508f650917bf5ca92088714a5056c..07accfbcca491966c6c8ad9c20e146db #include <openssl/evp.h> #endif -@@ -1076,7 +1076,7 @@ class Environment final : public MemoryRetainer { +@@ -1058,7 +1058,7 @@ class Environment final : public MemoryRetainer { kExitInfoFieldCount }; @@ -542,11 +298,11 @@ index c42493ad958508f650917bf5ca92088714a5056c..07accfbcca491966c6c8ad9c20e146db // We declare another alias here to avoid having to include crypto_util.h using EVPMDPointer = DeleteFnPtr<EVP_MD, EVP_MD_free>; diff --git a/src/node_metadata.h b/src/node_metadata.h -index 7b2072ad39c3f1a7c73101b25b69beb781141e26..d23536d88d21255d348175425a59e2424332cd19 100644 +index d9c533f100d25aeab1fe8589932a8ddead431258..2acab8786a8a752b17961445edeb872c2b08fdeb 100644 --- a/src/node_metadata.h +++ b/src/node_metadata.h -@@ -6,7 +6,7 @@ - #include <string> +@@ -8,7 +8,7 @@ + #include <utility> #include "node_version.h" -#if HAVE_OPENSSL @@ -554,21 +310,8 @@ index 7b2072ad39c3f1a7c73101b25b69beb781141e26..d23536d88d21255d348175425a59e242 #include <openssl/crypto.h> #if NODE_OPENSSL_HAS_QUIC #include <openssl/quic.h> -diff --git a/src/node_options.cc b/src/node_options.cc -index 228fbe645587ab2d36574b46f1a4f6668bd56177..9cf107b1048208ffcb69ff91e0d36ffacc741805 100644 ---- a/src/node_options.cc -+++ b/src/node_options.cc -@@ -7,7 +7,7 @@ - #include "node_external_reference.h" - #include "node_internals.h" - #include "node_sea.h" --#if HAVE_OPENSSL -+#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL) - #include "openssl/opensslv.h" - #endif - diff --git a/src/node_options.h b/src/node_options.h -index 0b75516eb426929dc95b7531a00bdb01d1c39185..2b7df46312b8be58d6062b6a2f6084247e075c37 100644 +index 3a1503a035e12b5dce75c77c327607c857a8a367..941ae4f15c42fb8016d03c786973fd4709ac1a0d 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -11,7 +11,7 @@ diff --git a/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch b/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch index 046340baebd65..bcd9a4b156e60 100644 --- a/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch +++ b/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch @@ -6,19 +6,19 @@ Subject: fix: lazyload fs in esm loaders to apply asar patches Changes { foo } from fs to just "fs.foo" so that our patching of fs is applied to esm loaders diff --git a/lib/internal/modules/esm/load.js b/lib/internal/modules/esm/load.js -index 3334818153068468967baa5adc1ed2382592ec76..ab4c8a4d00f1813e72f1ea8349850b40f55a393e 100644 +index e8a2326e158550786620439fa4039c2b449624cc..c17867136a07022a740d6bf957fe7a8138a48c11 100644 --- a/lib/internal/modules/esm/load.js +++ b/lib/internal/modules/esm/load.js -@@ -10,7 +10,7 @@ const { +@@ -9,7 +9,7 @@ const { + const { defaultGetFormat } = require('internal/modules/esm/get_format'); const { validateAttributes, emitImportAssertionWarning } = require('internal/modules/esm/assert'); - const { getOptionValue } = require('internal/options'); -const { readFileSync } = require('fs'); +const fs = require('fs'); - const defaultType = - getOptionValue('--experimental-default-type'); -@@ -38,7 +38,7 @@ function getSourceSync(url, context) { + const { Buffer: { from: BufferFrom } } = require('buffer'); + +@@ -34,7 +34,7 @@ function getSourceSync(url, context) { const responseURL = href; let source; if (protocol === 'file:') { @@ -28,7 +28,7 @@ index 3334818153068468967baa5adc1ed2382592ec76..ab4c8a4d00f1813e72f1ea8349850b40 const result = dataURLProcessor(url); if (result === 'failure') { diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js -index 5aa946f66c71beff0b7a43c30638ab28a1a5dfc0..e3afd30ba1f591d0298793bc42fd7166a4219bce 100644 +index 5f03cf14e948d449d303b22ab6710b5508fb83b2..72cc9444ca93ef7a1526e23314693aeaf5f173b0 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -25,7 +25,7 @@ const { @@ -50,10 +50,10 @@ index 5aa946f66c71beff0b7a43c30638ab28a1a5dfc0..e3afd30ba1f591d0298793bc42fd7166 }); const { search, hash } = resolved; diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js -index de1539cebeb1874cbafbe76a4f03217693db2aa1..8b55082d2bb0ce743b190a601aff0651095049cd 100644 +index 3c82913ca381eba30596f22a734b49dcba9b6f5b..1f967df42128a05e49acfa6d409737c06a3372e3 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js -@@ -25,7 +25,7 @@ const { +@@ -24,7 +24,7 @@ const { const { BuiltinModule } = require('internal/bootstrap/realm'); const assert = require('internal/assert'); @@ -62,7 +62,7 @@ index de1539cebeb1874cbafbe76a4f03217693db2aa1..8b55082d2bb0ce743b190a601aff0651 const { dirname, extname } = require('path'); const { assertBufferSource, -@@ -274,7 +274,7 @@ translators.set('commonjs', function commonjsStrategy(url, source, isMain) { +@@ -350,7 +350,7 @@ translators.set('commonjs', function commonjsStrategy(url, source, isMain) { try { // We still need to read the FS to detect the exports. diff --git a/patches/node/fix_redefined_macos_sdk_header_symbols.patch b/patches/node/fix_redefined_macos_sdk_header_symbols.patch new file mode 100644 index 0000000000000..0b183cd513365 --- /dev/null +++ b/patches/node/fix_redefined_macos_sdk_header_symbols.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Maddock <smaddock@slack-corp.com> +Date: Wed, 8 Oct 2025 10:50:03 -0400 +Subject: fix: redefined macos sdk header symbols + +https://chromium-review.googlesource.com/c/chromium/src/+/6950738 + +Chromium has set the minimum MacOS SDK version to 26. With this +change, it seems to introduce an incompatibility when compiling +using clang modules. Disabling them resolves the issue. + +diff --git a/unofficial.gni b/unofficial.gni +index dd686d2f7c8d2f6e8d6bd13a7bf2b4b140556ba9..97e4bcfaa8aa42a5fc2b68ccdd8128eac8886532 100644 +--- a/unofficial.gni ++++ b/unofficial.gni +@@ -195,6 +195,10 @@ template("node_gn_build") { + "CoreFoundation.framework", + "Security.framework", + ] ++ ++ # Fix for MacOSX26 SDK headers included twice due to usage of clang ++ # modules. Included once as a C header and again as C++. ++ use_libcxx_modules = false + } + if (is_posix) { + configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] +@@ -367,6 +371,12 @@ template("node_gn_build") { + include_dirs = [ "src", "tools" ] + configs += [ "//build/config/compiler:no_exit_time_destructors" ] + ++ # Fix for MacOSX26 SDK headers included twice due to usage of clang modules. ++ # Included once as a C header and again as C++. ++ if (is_mac) { ++ use_libcxx_modules = false ++ } ++ + if (!is_win) { + defines += [ "NODE_JS2C_USE_STRING_LITERALS" ] + } diff --git a/patches/node/fix_remove_deprecated_errno_constants.patch b/patches/node/fix_remove_deprecated_errno_constants.patch index 55ac88fa57cd0..3722644054fef 100644 --- a/patches/node/fix_remove_deprecated_errno_constants.patch +++ b/patches/node/fix_remove_deprecated_errno_constants.patch @@ -45,10 +45,10 @@ index ac00778cfc59fb55e361b24fc81a965a5e8f97e7..f0c4d6dfc9f03bee59e656b2da9ac325 # define UV__EUNATCH UV__ERR(EUNATCH) #else diff --git a/src/node_constants.cc b/src/node_constants.cc -index 8c44e32381a44675792ca0922e47df1adda48e41..d193725ea9a3270ed9affea12d11467fb14efdf8 100644 +index fd28e0904d05e24e8eeb74fa36abd9727699a649..fea0426496978c0003fe1481afcf93fc9c23edca 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc -@@ -241,10 +241,6 @@ void DefineErrnoConstants(Local<Object> target) { +@@ -242,10 +242,6 @@ void DefineErrnoConstants(Local<Object> target) { NODE_DEFINE_CONSTANT(target, ENOBUFS); #endif @@ -59,7 +59,7 @@ index 8c44e32381a44675792ca0922e47df1adda48e41..d193725ea9a3270ed9affea12d11467f #ifdef ENODEV NODE_DEFINE_CONSTANT(target, ENODEV); #endif -@@ -281,14 +277,6 @@ void DefineErrnoConstants(Local<Object> target) { +@@ -282,14 +278,6 @@ void DefineErrnoConstants(Local<Object> target) { NODE_DEFINE_CONSTANT(target, ENOSPC); #endif @@ -74,7 +74,7 @@ index 8c44e32381a44675792ca0922e47df1adda48e41..d193725ea9a3270ed9affea12d11467f #ifdef ENOSYS NODE_DEFINE_CONSTANT(target, ENOSYS); #endif -@@ -369,10 +357,6 @@ void DefineErrnoConstants(Local<Object> target) { +@@ -370,10 +358,6 @@ void DefineErrnoConstants(Local<Object> target) { NODE_DEFINE_CONSTANT(target, ESTALE); #endif @@ -86,7 +86,7 @@ index 8c44e32381a44675792ca0922e47df1adda48e41..d193725ea9a3270ed9affea12d11467f NODE_DEFINE_CONSTANT(target, ETIMEDOUT); #endif diff --git a/src/node_errors.cc b/src/node_errors.cc -index 5f51add4cdf68a9487edfc9382f586cc94539571..befb642f1effa3c4139e4cd99ff64d9c5175fd72 100644 +index ae8553ee2022d60fea4572976b14ba9cd253aa45..4386a1bc5678e351ce084cd2c47202561619b164 100644 --- a/src/node_errors.cc +++ b/src/node_errors.cc @@ -862,10 +862,6 @@ const char* errno_string(int errorno) { diff --git a/patches/node/fix_remove_fastapitypedarray_usage.patch b/patches/node/fix_remove_fastapitypedarray_usage.patch deleted file mode 100644 index dd7b160fd3556..0000000000000 --- a/patches/node/fix_remove_fastapitypedarray_usage.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: deepak1556 <hop2deep@gmail.com> -Date: Sun, 29 Dec 2024 04:01:32 +0900 -Subject: fix: remove FastApiTypedArray usage - -Refs https://github.com/electron/electron/pull/45055#issuecomment-2559095439 -Can be removed when upstream adopts relevant V8 version. - -diff --git a/src/crypto/crypto_timing.cc b/src/crypto/crypto_timing.cc -index fe669d40c31a29334b047b9cfee3067f64ef0a7b..9e5de7bbe574add017cd12ee091304d01e6458d6 100644 ---- a/src/crypto/crypto_timing.cc -+++ b/src/crypto/crypto_timing.cc -@@ -12,7 +12,6 @@ namespace node { - - using v8::CFunction; - using v8::FastApiCallbackOptions; --using v8::FastApiTypedArray; - using v8::FunctionCallbackInfo; - using v8::Local; - using v8::Object; -@@ -51,14 +50,13 @@ void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) { - } - - bool FastTimingSafeEqual(Local<Value> receiver, -- const FastApiTypedArray<uint8_t>& a, -- const FastApiTypedArray<uint8_t>& b, -+ Local<Value> a, -+ Local<Value> b, - // NOLINTNEXTLINE(runtime/references) - FastApiCallbackOptions& options) { -- uint8_t* data_a; -- uint8_t* data_b; -- if (a.length() != b.length() || !a.getStorageIfAligned(&data_a) || -- !b.getStorageIfAligned(&data_b)) { -+ FAST_SPREAD_BUFFER_ARG(a, a_buffer); -+ FAST_SPREAD_BUFFER_ARG(b, b_buffer); -+ if (a_buffer_length != b_buffer_length) { - TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.error"); - v8::HandleScope scope(options.isolate); - THROW_ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH(options.isolate); -@@ -66,7 +64,7 @@ bool FastTimingSafeEqual(Local<Value> receiver, - } - - TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.ok"); -- return CRYPTO_memcmp(data_a, data_b, a.length()) == 0; -+ return CRYPTO_memcmp(a_buffer_data, b_buffer_data, a_buffer_length) == 0; - } - - static CFunction fast_timing_safe_equal(CFunction::Make(FastTimingSafeEqual)); -diff --git a/src/node_buffer.cc b/src/node_buffer.cc -index d0338b8a2d9cd3fd9f6db1f0f16f83b198ce0e7e..c4a87539dab49ff40e0951616777b132d4059e01 100644 ---- a/src/node_buffer.cc -+++ b/src/node_buffer.cc -@@ -44,6 +44,14 @@ - #define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \ - THROW_AND_RETURN_IF_NOT_BUFFER(env, obj, "argument") \ - -+#define THROW_AND_RETURN_VAL_UNLESS_BUFFER(isolate, val, prefix, retval) \ -+ do { \ -+ if (!Buffer::HasInstance(val)) { \ -+ node::THROW_ERR_INVALID_ARG_TYPE(isolate, prefix " must be a buffer"); \ -+ return retval; \ -+ } \ -+ } while (0) -+ - #define THROW_AND_RETURN_IF_OOB(r) \ - do { \ - Maybe<bool> m = (r); \ -@@ -60,7 +68,6 @@ using v8::ArrayBufferView; - using v8::BackingStore; - using v8::Context; - using v8::EscapableHandleScope; --using v8::FastApiTypedArray; - using v8::FunctionCallbackInfo; - using v8::Global; - using v8::HandleScope; -@@ -584,19 +591,24 @@ void SlowCopy(const FunctionCallbackInfo<Value>& args) { - - // Assume caller has properly validated args. - uint32_t FastCopy(Local<Value> receiver, -- const v8::FastApiTypedArray<uint8_t>& source, -- const v8::FastApiTypedArray<uint8_t>& target, -+ Local<Value> source_obj, -+ Local<Value> target_obj, - uint32_t target_start, - uint32_t source_start, -- uint32_t to_copy) { -- uint8_t* source_data; -- CHECK(source.getStorageIfAligned(&source_data)); -- -+ uint32_t to_copy, -+ v8::FastApiCallbackOptions& options) { -+ FAST_SPREAD_BUFFER_ARG(source_obj, source); - uint8_t* target_data; -- CHECK(target.getStorageIfAligned(&target_data)); -+ FAST_SPREAD_BUFFER_ARG(target_obj, target_buffer); -+ if (target_buffer_length <= kMaxSizeInHeap) { -+ HandleScope handle_scope(options.isolate); -+ SPREAD_BUFFER_ARG(target_obj, target_buffer); -+ target_data = reinterpret_cast<uint8_t*>(target_buffer_data); -+ } else { -+ target_data = target_buffer_data; -+ } - - memmove(target_data + target_start, source_data + source_start, to_copy); -- - return to_copy; - } - -@@ -865,19 +877,17 @@ void Compare(const FunctionCallbackInfo<Value> &args) { - } - - int32_t FastCompare(v8::Local<v8::Value>, -- const FastApiTypedArray<uint8_t>& a, -- const FastApiTypedArray<uint8_t>& b) { -- uint8_t* data_a; -- uint8_t* data_b; -- CHECK(a.getStorageIfAligned(&data_a)); -- CHECK(b.getStorageIfAligned(&data_b)); -+ v8::Local<v8::Value> a, -+ v8::Local<v8::Value> b) { -+ FAST_SPREAD_BUFFER_ARG(a, a_buffer); -+ FAST_SPREAD_BUFFER_ARG(b, b_buffer); - -- size_t cmp_length = std::min(a.length(), b.length()); -+ size_t cmp_length = std::min(a_buffer_length, b_buffer_length); - - return normalizeCompareVal( -- cmp_length > 0 ? memcmp(data_a, data_b, cmp_length) : 0, -- a.length(), -- b.length()); -+ cmp_length > 0 ? memcmp(a_buffer_data, b_buffer_data, cmp_length) : 0, -+ a_buffer_length, -+ b_buffer_length); - } - - static v8::CFunction fast_compare(v8::CFunction::Make(FastCompare)); -@@ -1148,14 +1158,13 @@ void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) { - } - - int32_t FastIndexOfNumber(v8::Local<v8::Value>, -- const FastApiTypedArray<uint8_t>& buffer, -+ v8::Local<v8::Value> source_obj, - uint32_t needle, - int64_t offset_i64, - bool is_forward) { -- uint8_t* buffer_data; -- CHECK(buffer.getStorageIfAligned(&buffer_data)); -+ FAST_SPREAD_BUFFER_ARG(source_obj, buffer); - return IndexOfNumber( -- buffer_data, buffer.length(), needle, offset_i64, is_forward); -+ buffer_data, buffer_length, needle, offset_i64, is_forward); - } - - static v8::CFunction fast_index_of_number( -@@ -1495,21 +1504,31 @@ void SlowWriteString(const FunctionCallbackInfo<Value>& args) { - - template <encoding encoding> - uint32_t FastWriteString(Local<Value> receiver, -- const v8::FastApiTypedArray<uint8_t>& dst, -+ Local<v8::Value> dst, - const v8::FastOneByteString& src, - uint32_t offset, -- uint32_t max_length) { -- uint8_t* dst_data; -- CHECK(dst.getStorageIfAligned(&dst_data)); -- CHECK(offset <= dst.length()); -- CHECK(dst.length() - offset <= std::numeric_limits<uint32_t>::max()); -+ uint32_t max_length, -+ v8::FastApiCallbackOptions& options) { -+ THROW_AND_RETURN_VAL_UNLESS_BUFFER(options.isolate, dst, "dst", 0); -+ uint8_t* dst_buffer_data; -+ FAST_SPREAD_BUFFER_ARG(dst, dst_fast_buffer); -+ if (dst_fast_buffer_length <= kMaxSizeInHeap) { -+ HandleScope handle_scope(options.isolate); -+ SPREAD_BUFFER_ARG(dst, dst_slow_buffer); -+ dst_buffer_data = reinterpret_cast<uint8_t*>(dst_slow_buffer_data); -+ } else { -+ dst_buffer_data = dst_fast_buffer_data; -+ }; -+ -+ CHECK(dst_fast_buffer_length <= std::numeric_limits<uint32_t>::max()); -+ uint32_t dst_size = static_cast<uint32_t>(dst_fast_buffer_length); - TRACK_V8_FAST_API_CALL("buffer.writeString"); - - return WriteOneByteString<encoding>( - src.data, - src.length, -- reinterpret_cast<char*>(dst_data + offset), -- std::min<uint32_t>(dst.length() - offset, max_length)); -+ reinterpret_cast<char*>(dst_buffer_data + offset), -+ std::min<uint32_t>(dst_size - offset, max_length)); - } - - static const v8::CFunction fast_write_string_ascii( -diff --git a/src/util.h b/src/util.h -index 6376cf4f81113cdb2e3c179b800f1c79b51ab762..cc7ad99f981f564fba0395159d9d8b39901050ff 100644 ---- a/src/util.h -+++ b/src/util.h -@@ -60,6 +60,7 @@ - namespace node { - - constexpr char kPathSeparator = std::filesystem::path::preferred_separator; -+static constexpr size_t kMaxSizeInHeap = 64; - - #ifdef _WIN32 - /* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */ -@@ -585,6 +586,16 @@ class BufferValue : public MaybeStackBuffer<char> { - static_cast<char*>(name->Buffer()->Data()) + name##_offset; \ - if (name##_length > 0) CHECK_NE(name##_data, nullptr); - -+#define FAST_SPREAD_BUFFER_ARG(val, name) \ -+ CHECK((val)->IsArrayBufferView()); \ -+ v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \ -+ uint8_t name##_buffer[kMaxSizeInHeap]; \ -+ v8::MemorySpan<uint8_t> name##_storage(name##_buffer); \ -+ name##_storage = name->GetContents(name##_storage); \ -+ const size_t name##_length = name##_storage.size(); \ -+ uint8_t* name##_data = name##_storage.data(); \ -+ if (name##_length > 0) CHECK_NE(name##_data, nullptr); -+ - // Use this when a variable or parameter is unused in order to explicitly - // silence a compiler warning about that. - template <typename T> inline void USE(T&&) {} diff --git a/patches/node/fix_remove_harmony-import-assertions_from_node_cc.patch b/patches/node/fix_remove_harmony-import-assertions_from_node_cc.patch deleted file mode 100644 index eb48a5a18140f..0000000000000 --- a/patches/node/fix_remove_harmony-import-assertions_from_node_cc.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr <shelley.vohr@gmail.com> -Date: Fri, 18 Oct 2024 17:01:06 +0200 -Subject: fix: remove harmony-import-assertions from node.cc - -harmony-import-assertions has been removed from V8 as of -https://chromium-review.googlesource.com/c/v8/v8/+/5507047, -so we should remove it from node.cc as well. - -This patch can be removed when we upgrade to a V8 version that -contains the above CL. - -diff --git a/src/node.cc b/src/node.cc -index c0d0b734edfa729c91a8112189c480e3f2382988..a43d36c731693b9d2ed1ba13f6b4bb33bf6c4ca4 100644 ---- a/src/node.cc -+++ b/src/node.cc -@@ -816,7 +816,7 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args, - } - // TODO(nicolo-ribaudo): remove this once V8 doesn't enable it by default - // anymore. -- v8_args.emplace_back("--no-harmony-import-assertions"); -+ // v8_args.emplace_back("--no-harmony-import-assertions"); - - auto env_opts = per_process::cli_options->per_isolate->per_env; - if (std::find(v8_args.begin(), v8_args.end(), diff --git a/patches/node/fix_task_starvation_in_inspector_context_test.patch b/patches/node/fix_task_starvation_in_inspector_context_test.patch deleted file mode 100644 index 9e3438d72c40b..0000000000000 --- a/patches/node/fix_task_starvation_in_inspector_context_test.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Calvin Watford <cwatford@slack-corp.com> -Date: Thu, 3 Apr 2025 10:59:30 -0600 -Subject: Fix task starvation in inspector context test - -A V8 change makes these contexts get collected in a task that is posted -and run asynchronously. The tests were synchronously GC'ing in an -infinite loop, preventing the task loop from running the task that would -GC these contexts. - -This change should be upstreamed in some way. - -Ref: https://chromium-review.googlesource.com/c/v8/v8/+/4733273 - -diff --git a/test/parallel/test-inspector-contexts.js b/test/parallel/test-inspector-contexts.js -index e7bdc53f8cd5763572798cbd9ef07c902e3fc335..8b7a1f1aaf648efe10761af205ac561952a06980 100644 ---- a/test/parallel/test-inspector-contexts.js -+++ b/test/parallel/test-inspector-contexts.js -@@ -17,6 +17,13 @@ function notificationPromise(method) { - return new Promise((resolve) => session.once(method, resolve)); - } - -+function gcImmediate() { -+ return new Promise((resolve) => { -+ global.gc(); -+ setImmediate(resolve); -+ }); -+} -+ - async function testContextCreatedAndDestroyed() { - console.log('Testing context created/destroyed notifications'); - { -@@ -68,7 +75,7 @@ async function testContextCreatedAndDestroyed() { - // GC is unpredictable... - console.log('Checking/waiting for GC.'); - while (!contextDestroyed) -- global.gc(); -+ await gcImmediate(); - console.log('Context destroyed.'); - - assert.strictEqual(contextDestroyed.params.executionContextId, id, -@@ -100,7 +107,7 @@ async function testContextCreatedAndDestroyed() { - // GC is unpredictable... - console.log('Checking/waiting for GC again.'); - while (!contextDestroyed) -- global.gc(); -+ await gcImmediate(); - console.log('Other context destroyed.'); - } - -@@ -126,7 +133,7 @@ async function testContextCreatedAndDestroyed() { - // GC is unpredictable... - console.log('Checking/waiting for GC a third time.'); - while (!contextDestroyed) -- global.gc(); -+ await gcImmediate(); - console.log('Context destroyed once again.'); - } - -@@ -150,7 +157,7 @@ async function testContextCreatedAndDestroyed() { - // GC is unpredictable... - console.log('Checking/waiting for GC a fourth time.'); - while (!contextDestroyed) -- global.gc(); -+ await gcImmediate(); - console.log('Context destroyed a fourth time.'); - } - } diff --git a/patches/node/lib_check_sharedarraybuffer_existence_in_fast-utf8-stream.patch b/patches/node/lib_check_sharedarraybuffer_existence_in_fast-utf8-stream.patch new file mode 100644 index 0000000000000..6379c9643b511 --- /dev/null +++ b/patches/node/lib_check_sharedarraybuffer_existence_in_fast-utf8-stream.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr <shelley.vohr@gmail.com> +Date: Sat, 25 Oct 2025 11:06:10 +0200 +Subject: lib: check SharedArrayBuffer existence in fast-utf8-stream + +After https://github.com/nodejs/node/pull/58897 calling +Object.entries on fs will lazy-load fast-utf8-stream, which uses +SharedArrayBuffer without checking for its existence first. It +won't exist in the renderer process and will throw +'SharedArrayBuffer is not a constructor'. Refactor to check +for SharedArrayBuffer first. + +This should be upstreamed to Node.js + +diff --git a/lib/internal/streams/fast-utf8-stream.js b/lib/internal/streams/fast-utf8-stream.js +index 3bfcc494d17b5cc4c9f494fab4aff4f0d68d2287..241a6b05e84f8e79b8c9b93abfda5562c2e35e9e 100644 +--- a/lib/internal/streams/fast-utf8-stream.js ++++ b/lib/internal/streams/fast-utf8-stream.js +@@ -49,7 +49,8 @@ const { + const BUSY_WRITE_TIMEOUT = 100; + const kEmptyBuffer = Buffer.allocUnsafe(0); + +-const kNil = new Int32Array(new SharedArrayBuffer(4)); ++const haveSAB = typeof SharedArrayBuffer !== 'undefined'; ++const kNil = haveSAB ? new Int32Array(new SharedArrayBuffer(4)) : null; + + function sleep(ms) { + // Also filters out NaN, non-number types, including empty strings, but allows bigints +@@ -59,10 +60,14 @@ function sleep(ms) { + throw new ERR_INVALID_ARG_TYPE('ms', ['number', 'bigint'], ms); + } + throw new ERR_INVALID_ARG_VALUE.RangeError('ms', ms, +- 'must be a number greater than 0 and less than Infinity'); ++ 'must be a number greater than 0 and less than Infinity'); ++ } ++ if (haveSAB) { ++ AtomicsWait(kNil, 0, 0, Number(ms)); ++ } else { ++ const { sleep: _sleep } = internalBinding('util'); ++ _sleep(ms); + } +- +- AtomicsWait(kNil, 0, 0, Number(ms)); + } + + // 16 KB. Don't write more than docker buffer size. diff --git a/patches/node/pass_all_globals_through_require.patch b/patches/node/pass_all_globals_through_require.patch index 1f02e81bce378..c121874bbeeb1 100644 --- a/patches/node/pass_all_globals_through_require.patch +++ b/patches/node/pass_all_globals_through_require.patch @@ -6,10 +6,10 @@ Subject: Pass all globals through "require" (cherry picked from commit 7d015419cb7a0ecfe6728431a4ed2056cd411d62) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js -index 9b51e5bf4cdfbc8127efc7d5882581daa1cbd81f..aca7c36e9b566847228bd4f13f2c8237509207db 100644 +index 8a28cd0e497911550cb0fa889c4f2f780d86c24b..811a2961834b9648f5f6b51c3bda570541413818 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js -@@ -200,6 +200,13 @@ const { +@@ -208,6 +208,13 @@ const { CHAR_FORWARD_SLASH, } = require('internal/constants'); @@ -23,7 +23,7 @@ index 9b51e5bf4cdfbc8127efc7d5882581daa1cbd81f..aca7c36e9b566847228bd4f13f2c8237 const { isProxy, } = require('internal/util/types'); -@@ -1683,10 +1690,12 @@ Module.prototype._compile = function(content, filename, format) { +@@ -1755,10 +1762,12 @@ Module.prototype._compile = function(content, filename, format) { if (this[kIsMainSymbol] && getOptionValue('--inspect-brk')) { const { callAndPauseOnStart } = internalBinding('inspector'); result = callAndPauseOnStart(compiledWrapper, thisValue, exports, diff --git a/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch b/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch index dbbf389088cd5..a192468d4cf7e 100644 --- a/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch +++ b/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch @@ -7,10 +7,10 @@ We use this to allow node's 'fs' module to read from ASAR files as if they were a real filesystem. diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js -index dd9e3e58d72fb9ada1528212f80e0e911292a266..5758c74f6139dbe4fbeeae9d1e9b078688261257 100644 +index 963fe2ab11927a6802d2b1c0f653b5b1032d4243..0a531f216bd64477b800a169e91d859844161f16 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js -@@ -132,6 +132,10 @@ process.domain = null; +@@ -129,6 +129,10 @@ process.domain = null; } process._exiting = false; diff --git a/patches/node/refactor_attach_cppgc_heap_on_v8_isolate_creation.patch b/patches/node/refactor_attach_cppgc_heap_on_v8_isolate_creation.patch index 1a5b2c83760c5..734d31ac7bb2c 100644 --- a/patches/node/refactor_attach_cppgc_heap_on_v8_isolate_creation.patch +++ b/patches/node/refactor_attach_cppgc_heap_on_v8_isolate_creation.patch @@ -18,10 +18,10 @@ This can be removed when Node.js upgrades to a version of V8 containing CLs from the above issue. diff --git a/src/api/environment.cc b/src/api/environment.cc -index 9e1b8d147a99fda962d75c343d0687ffea3c9c69..244d747f010c51366e44dec705ae304423038a85 100644 +index a869bc0a145009b57db3f37208e405d9356cc20f..072deb1fa70313e33397f6ff994e3f3548e86092 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc -@@ -313,6 +313,10 @@ Isolate* NewIsolate(Isolate::CreateParams* params, +@@ -319,6 +319,10 @@ Isolate* NewIsolate(Isolate::CreateParams* params, MultiIsolatePlatform* platform, const SnapshotData* snapshot_data, const IsolateSettings& settings) { @@ -32,7 +32,7 @@ index 9e1b8d147a99fda962d75c343d0687ffea3c9c69..244d747f010c51366e44dec705ae3044 Isolate* isolate = Isolate::Allocate(); if (isolate == nullptr) return nullptr; -@@ -356,9 +360,12 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator, +@@ -374,9 +378,12 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop, MultiIsolatePlatform* platform, const EmbedderSnapshotData* snapshot_data, @@ -46,100 +46,66 @@ index 9e1b8d147a99fda962d75c343d0687ffea3c9c69..244d747f010c51366e44dec705ae3044 return NewIsolate(¶ms, event_loop, platform, -diff --git a/src/env.cc b/src/env.cc -index 56eb42643f26f3ebb447cb625d5422dcfa872189..8cdfbac602796cabbd8a2f673385b93bea9bd7cc 100644 ---- a/src/env.cc -+++ b/src/env.cc -@@ -577,14 +577,6 @@ IsolateData::IsolateData(Isolate* isolate, - // We do not care about overflow since we just want this to be different - // from the cppgc id. - uint16_t non_cppgc_id = cppgc_id + 1; -- if (cpp_heap == nullptr) { -- cpp_heap_ = CppHeap::Create(platform, v8::CppHeapCreateParams{{}}); -- // TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8 -- // own it when we can keep the isolate registered/task runner discoverable -- // during isolate disposal. -- isolate->AttachCppHeap(cpp_heap_.get()); -- } -- - { - // GC could still be run after the IsolateData is destroyed, so we store - // the ids in a static map to ensure pointers to them are still valid -@@ -607,15 +599,6 @@ IsolateData::IsolateData(Isolate* isolate, - } +diff --git a/src/cppgc_helpers-inl.h b/src/cppgc_helpers-inl.h +index 745ecab746f7c7540733d31a94f52809dcddd5be..0e52bf5a6f4837d0f4bfed83987c6903796fda55 100644 +--- a/src/cppgc_helpers-inl.h ++++ b/src/cppgc_helpers-inl.h +@@ -15,11 +15,12 @@ void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) { + v8::Isolate* isolate = realm->isolate(); + ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj); + // Note that ptr must be of concrete type T in Wrap. +- v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(isolate, obj, ptr); ++ auto* wrappable = static_cast<v8::Object::Wrappable*>(ptr); ++ v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(isolate, obj, wrappable); + // Keep the layout consistent with BaseObjects. + obj->SetAlignedPointerInInternalField( +- kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc()); +- obj->SetAlignedPointerInInternalField(kSlot, ptr); ++ kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc(), 0); ++ obj->SetAlignedPointerInInternalField(kSlot, ptr, 0); + realm->TrackCppgcWrapper(ptr); } --IsolateData::~IsolateData() { -- if (cpp_heap_ != nullptr) { -- v8::Locker locker(isolate_); -- // The CppHeap must be detached before being terminated. -- isolate_->DetachCppHeap(); -- cpp_heap_->Terminate(); -- } --} -- - // Deprecated API, embedders should use v8::Object::Wrap() directly instead. - void SetCppgcReference(Isolate* isolate, - Local<Object> object, -diff --git a/src/env.h b/src/env.h -index 1079e3beb02e5f5d71a15fd2db65cb93ebd175d6..a7be609c3ab9093cec5145367b95ae6859936a24 100644 ---- a/src/env.h -+++ b/src/env.h -@@ -155,7 +155,6 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { - ArrayBufferAllocator* node_allocator = nullptr, - const EmbedderSnapshotData* embedder_snapshot_data = nullptr, - std::shared_ptr<PerIsolateOptions> options = nullptr); -- ~IsolateData(); - - SET_MEMORY_INFO_NAME(IsolateData) - SET_SELF_SIZE(IsolateData) -@@ -258,7 +257,6 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { - const SnapshotData* snapshot_data_; - std::optional<SnapshotConfig> snapshot_config_; - -- std::unique_ptr<v8::CppHeap> cpp_heap_; - std::shared_ptr<PerIsolateOptions> options_; - worker::Worker* worker_context_ = nullptr; - PerIsolateWrapperData* wrapper_data_; -diff --git a/src/node.cc b/src/node.cc -index a43d36c731693b9d2ed1ba13f6b4bb33bf6c4ca4..0c2a4d344c991c2ca0d9d90934cf7921abf2a629 100644 ---- a/src/node.cc -+++ b/src/node.cc -@@ -1257,6 +1257,14 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args, - result->platform_ = per_process::v8_platform.Platform(); +@@ -40,7 +41,7 @@ T* CppgcMixin::Unwrap(v8::Local<v8::Object> obj) { + if (obj->InternalFieldCount() != T::kInternalFieldCount) { + return nullptr; } +- T* ptr = static_cast<T*>(obj->GetAlignedPointerFromInternalField(T::kSlot)); ++ T* ptr = static_cast<T*>(obj->GetAlignedPointerFromInternalField(T::kSlot, 0)); + return ptr; + } -+ if (!(flags & ProcessInitializationFlags::kNoInitializeCppgc)) { -+ v8::PageAllocator* allocator = nullptr; -+ if (result->platform_ != nullptr) { -+ allocator = result->platform_->GetPageAllocator(); -+ } -+ cppgc::InitializeProcess(allocator); -+ } -+ - if (!(flags & ProcessInitializationFlags::kNoInitializeV8)) { - V8::Initialize(); +diff --git a/src/cppgc_helpers.h b/src/cppgc_helpers.h +index fb2af584a4ae777022c9ef8c20ada1edcbbbefdc..fe6300a5d5d2d6602a84cbd33736c2133041d1b0 100644 +--- a/src/cppgc_helpers.h ++++ b/src/cppgc_helpers.h +@@ -155,7 +155,7 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer { + */ + #define CPPGC_MIXIN(Klass) \ + public /* NOLINT(whitespace/indent) */ \ +- cppgc::GarbageCollected<Klass>, public cppgc::NameProvider, public CppgcMixin ++ v8::Object::Wrappable, public CppgcMixin -@@ -1266,14 +1274,6 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args, - absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore); - } + #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -- if (!(flags & ProcessInitializationFlags::kNoInitializeCppgc)) { -- v8::PageAllocator* allocator = nullptr; -- if (result->platform_ != nullptr) { -- allocator = result->platform_->GetPageAllocator(); -- } -- cppgc::InitializeProcess(allocator); -- } -- - #if NODE_USE_V8_WASM_TRAP_HANDLER - bool use_wasm_trap_handler = - !per_process::cli_options->disable_wasm_trap_handler; +diff --git a/src/env.cc b/src/env.cc +index 53f0bf7fc1e5c85fa9a5a323e998f04310f4f75e..a78817467518245c4a190e870e0eb30658eafcdb 100644 +--- a/src/env.cc ++++ b/src/env.cc +@@ -611,7 +611,7 @@ IsolateData::~IsolateData() {} + // Deprecated API, embedders should use v8::Object::Wrap() directly instead. + void SetCppgcReference(Isolate* isolate, + Local<Object> object, +- void* wrappable) { ++ v8::Object::Wrappable* wrappable) { + v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>( + isolate, object, wrappable); + } diff --git a/src/node.h b/src/node.h -index 42d55d24bd0770795ae0c0e19241d25a6350ae08..4335c7cf53b7e08c95dcee3461384ac12c8ebe41 100644 +index f7b3f90b0c2cfbeacc5bc50112dd711df8d3c364..7fae281a6e0f3c1a9f0eb97536883bb26c16d94d 100644 --- a/src/node.h +++ b/src/node.h -@@ -590,7 +590,8 @@ NODE_EXTERN v8::Isolate* NewIsolate( +@@ -604,7 +604,8 @@ NODE_EXTERN v8::Isolate* NewIsolate( struct uv_loop_s* event_loop, MultiIsolatePlatform* platform, const EmbedderSnapshotData* snapshot_data = nullptr, @@ -149,8 +115,22 @@ index 42d55d24bd0770795ae0c0e19241d25a6350ae08..4335c7cf53b7e08c95dcee3461384ac1 NODE_EXTERN v8::Isolate* NewIsolate( std::shared_ptr<ArrayBufferAllocator> allocator, struct uv_loop_s* event_loop, +@@ -1617,9 +1618,10 @@ void RegisterSignalHandler(int signal, + // work with only Node.js versions with v8::Object::Wrap() should use that + // instead. + NODE_DEPRECATED("Use v8::Object::Wrap()", +- NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate, +- v8::Local<v8::Object> object, +- void* wrappable)); ++ NODE_EXTERN void SetCppgcReference( ++ v8::Isolate* isolate, ++ v8::Local<v8::Object> object, ++ v8::Object::Wrappable* wrappable)); + + } // namespace node + diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc -index 4119ac1b002681d39711eac810ca2fcc2702ffc7..790347056cde949ffe6cf8498a7eca0c4864c997 100644 +index dd6ecd1f9d82f6661b2480c0195e33515633429f..334d5cb7df7a763e0929468392dad83421cad606 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -44,6 +44,8 @@ NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data, @@ -162,22 +142,11 @@ index 4119ac1b002681d39711eac810ca2fcc2702ffc7..790347056cde949ffe6cf8498a7eca0c isolate_ = NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data); -@@ -81,9 +83,9 @@ NodeMainInstance::~NodeMainInstance() { - // This should only be done on a main instance that owns its isolate. - // IsolateData must be freed before UnregisterIsolate() is called. - isolate_data_.reset(); -- platform_->UnregisterIsolate(isolate_); - } - isolate_->Dispose(); -+ platform_->UnregisterIsolate(isolate_); - } - - ExitCode NodeMainInstance::Run() { diff --git a/src/node_worker.cc b/src/node_worker.cc -index 9d56d8f793ef48a79867f465530554ae0226f2cd..842eb999c6ef0cb877cc2ee4acf75bb597a117da 100644 +index 7bae29747d8cd8e83973d105099f9111fc185fe1..62c53368d1173edb7eb42e3337049c46fd7cdda9 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc -@@ -162,6 +162,9 @@ class WorkerThreadData { +@@ -181,6 +181,9 @@ class WorkerThreadData { SetIsolateCreateParamsForNode(¶ms); w->UpdateResourceConstraints(¶ms.constraints); params.array_buffer_allocator_shared = allocator; @@ -187,153 +156,3 @@ index 9d56d8f793ef48a79867f465530554ae0226f2cd..842eb999c6ef0cb877cc2ee4acf75bb5 Isolate* isolate = NewIsolate(¶ms, &loop_, w->platform_, w->snapshot_data()); if (isolate == nullptr) { -@@ -230,13 +233,8 @@ class WorkerThreadData { - *static_cast<bool*>(data) = true; - }, &platform_finished); - -- // The order of these calls is important; if the Isolate is first disposed -- // and then unregistered, there is a race condition window in which no -- // new Isolate at the same address can successfully be registered with -- // the platform. -- // (Refs: https://github.com/nodejs/node/issues/30846) -- w_->platform_->UnregisterIsolate(isolate); - isolate->Dispose(); -+ w_->platform_->UnregisterIsolate(isolate); - - // Wait until the platform has cleaned up all relevant resources. - while (!platform_finished) { -diff --git a/src/util.cc b/src/util.cc -index 0c01d338b9d1ced7f173ac862239315f91326791..5ca32f026f9f001ddadc14965705fe005600eddd 100644 ---- a/src/util.cc -+++ b/src/util.cc -@@ -726,8 +726,8 @@ RAIIIsolateWithoutEntering::RAIIIsolateWithoutEntering(const SnapshotData* data) - } - - RAIIIsolateWithoutEntering::~RAIIIsolateWithoutEntering() { -- per_process::v8_platform.Platform()->UnregisterIsolate(isolate_); - isolate_->Dispose(); -+ per_process::v8_platform.Platform()->UnregisterIsolate(isolate_); - } - - RAIIIsolate::RAIIIsolate(const SnapshotData* data) -diff --git a/test/cctest/node_test_fixture.h b/test/cctest/node_test_fixture.h -index 3414c0be8ad777f0b9836323150071b688831a38..82013ffe7667d53248bd616efb79b294e4ae47dd 100644 ---- a/test/cctest/node_test_fixture.h -+++ b/test/cctest/node_test_fixture.h -@@ -123,8 +123,8 @@ class NodeTestFixture : public NodeZeroIsolateTestFixture { - void TearDown() override { - platform->DrainTasks(isolate_); - isolate_->Exit(); -- platform->UnregisterIsolate(isolate_); - isolate_->Dispose(); -+ platform->UnregisterIsolate(isolate_); - isolate_ = nullptr; - NodeZeroIsolateTestFixture::TearDown(); - } -diff --git a/test/cctest/test_cppgc.cc b/test/cctest/test_cppgc.cc -index edd413ae9b956b2e59e8166785adef6a8ff06d51..d1c1549efcb0320bc0f7d354db2101acc0930005 100644 ---- a/test/cctest/test_cppgc.cc -+++ b/test/cctest/test_cppgc.cc -@@ -46,18 +46,15 @@ int CppGCed::kDestructCount = 0; - int CppGCed::kTraceCount = 0; - - TEST_F(NodeZeroIsolateTestFixture, ExistingCppHeapTest) { -- v8::Isolate* isolate = -- node::NewIsolate(allocator.get(), ¤t_loop, platform.get()); - - // Create and attach the CppHeap before we set up the IsolateData so that - // it recognizes the existing heap. - std::unique_ptr<v8::CppHeap> cpp_heap = - v8::CppHeap::Create(platform.get(), v8::CppHeapCreateParams{{}}); - -- // TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8 -- // own it when we can keep the isolate registered/task runner discoverable -- // during isolate disposal. -- isolate->AttachCppHeap(cpp_heap.get()); -+ v8::Isolate* isolate = -+ node::NewIsolate(allocator.get(), ¤t_loop, platform.get(), -+ nullptr, {}, std::move(cpp_heap)); - - // Try creating Context + IsolateData + Environment. - { -@@ -102,13 +99,11 @@ TEST_F(NodeZeroIsolateTestFixture, ExistingCppHeapTest) { - platform->DrainTasks(isolate); - - // Cleanup. -- isolate->DetachCppHeap(); -- cpp_heap->Terminate(); - platform->DrainTasks(isolate); - } - -- platform->UnregisterIsolate(isolate); - isolate->Dispose(); -+ platform->UnregisterIsolate(isolate); - - // Check that all the objects are created and destroyed properly. - EXPECT_EQ(CppGCed::kConstructCount, 100); -diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc -index 008cda77b650dc2d904ae00e7629b5ad05d297ad..103931516cea9beb7f25c53526928e67b3c90d2d 100644 ---- a/test/cctest/test_environment.cc -+++ b/test/cctest/test_environment.cc -@@ -625,6 +625,9 @@ TEST_F(NodeZeroIsolateTestFixture, CtrlCWithOnlySafeTerminationTest) { - // Allocate and initialize Isolate. - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = allocator.get(); -+ create_params.cpp_heap = -+ v8::CppHeap::Create(platform.get(), v8::CppHeapCreateParams{{}}) -+ .release(); - v8::Isolate* isolate = v8::Isolate::Allocate(); - CHECK_NOT_NULL(isolate); - platform->RegisterIsolate(isolate, ¤t_loop); -@@ -675,8 +678,8 @@ TEST_F(NodeZeroIsolateTestFixture, CtrlCWithOnlySafeTerminationTest) { - } - - // Cleanup. -- platform->UnregisterIsolate(isolate); - isolate->Dispose(); -+ platform->UnregisterIsolate(isolate); - } - #endif // _WIN32 - -diff --git a/test/cctest/test_platform.cc b/test/cctest/test_platform.cc -index 53644accf29749bf8fc18b641ae1eaef93cd6f98..7e5b143fb4b633e18a4b2d7440cba7e077c50950 100644 ---- a/test/cctest/test_platform.cc -+++ b/test/cctest/test_platform.cc -@@ -102,8 +102,8 @@ TEST_F(NodeZeroIsolateTestFixture, IsolatePlatformDelegateTest) { - - // Graceful shutdown - delegate->Shutdown(); -- platform->UnregisterIsolate(isolate); - isolate->Dispose(); -+ platform->UnregisterIsolate(isolate); - } - - TEST_F(PlatformTest, TracingControllerNullptr) { -diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc -index bace3051f8cecd5050d4707f2431973752a22188..5ca295848a974c70ff1a9094eb288ef7e658d8e5 100644 ---- a/test/fuzzers/fuzz_env.cc -+++ b/test/fuzzers/fuzz_env.cc -@@ -65,8 +65,8 @@ public: - void Teardown() { - platform->DrainTasks(isolate_); - isolate_->Exit(); -- platform->UnregisterIsolate(isolate_); - isolate_->Dispose(); -+ platform->UnregisterIsolate(isolate_); - isolate_ = nullptr; - } - }; -diff --git a/test/fuzzers/fuzz_strings.cc b/test/fuzzers/fuzz_strings.cc -index 8f5e1a473e3148e0bcdcc3c2fd582685665ce461..936876cdae20d29618d3789a5ab46a1b3101a79d 100644 ---- a/test/fuzzers/fuzz_strings.cc -+++ b/test/fuzzers/fuzz_strings.cc -@@ -72,8 +72,8 @@ public: - void Teardown() { - platform->DrainTasks(isolate_); - isolate_->Exit(); -- platform->UnregisterIsolate(isolate_); - isolate_->Dispose(); -+ platform->UnregisterIsolate(isolate_); - isolate_ = nullptr; - } - }; diff --git a/patches/node/reland_temporal_unflag_temporal.patch b/patches/node/reland_temporal_unflag_temporal.patch new file mode 100644 index 0000000000000..46f666064a170 --- /dev/null +++ b/patches/node/reland_temporal_unflag_temporal.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt <jkleinsc@electronjs.org> +Date: Fri, 7 Nov 2025 16:36:35 -0500 +Subject: Reland "[temporal] Unflag Temporal" + +https://chromium-review.googlesource.com/c/v8/v8/+/7123876 + +diff --git a/test/common/globals.js b/test/common/globals.js +index 34563b304f0e708ae066f8303a09e37b6bf123d6..cffba7d5f1936c4459b5afd91b8bc45b9038436d 100644 +--- a/test/common/globals.js ++++ b/test/common/globals.js +@@ -69,6 +69,7 @@ const intrinsics = new Set([ + 'SuppressedError', + 'DisposableStack', + 'AsyncDisposableStack', ++ 'Temporal' + ]); + + if (global.gc) { diff --git a/patches/node/src_do_not_use_soon-to-be-deprecated_v8_api.patch b/patches/node/src_do_not_use_soon-to-be-deprecated_v8_api.patch deleted file mode 100644 index c866e376873fc..0000000000000 --- a/patches/node/src_do_not_use_soon-to-be-deprecated_v8_api.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Igor Sheludko <ishell@chromium.org> -Date: Fri, 19 Apr 2024 12:29:53 +0200 -Subject: src: do not use soon-to-be-deprecated V8 API - -V8 announced deprecation of the following methods: - - v8::Object::SetAccessor(...) in favor of - v8::Object::SetNativeDataProperty(...), - - v8::ObjectTemplate::SetNativeDataProperty(...) with AccessControl - parameter in favor of - v8::ObjectTemplate::SetNativeDataProperty(...) without AccessControl - parameter. - -See https://crrev.com/c/5006387. - -This slightly changes behavior of the following properties: - - process.debugPort (for worker processes), - - process.title (for worker processes), - - process.ppid. - -The difference is that they will now behave like a regular writable -JavaScript data properties - in case setter callback is not provided -they will be be reconfigured from a native data property (the one -that calls C++ callbacks upon get/set operations) to a real data -property (so subsequent reads will no longer trigger C++ getter -callbacks). - -PR-URL: https://github.com/nodejs/node/pull/53174 -Reviewed-By: Michael Dawson <midawson@redhat.com> -Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> -Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> -Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> -Reviewed-By: James M Snell <jasnell@gmail.com> - -diff --git a/src/node_process_object.cc b/src/node_process_object.cc -index 7dd24545fee674b25503b0fcff9b9af0d5c6a26a..5de8be7f8ed97e6b110e397fc4cacb9a246892b6 100644 ---- a/src/node_process_object.cc -+++ b/src/node_process_object.cc -@@ -13,7 +13,6 @@ - - namespace node { - using v8::Context; --using v8::DEFAULT; - using v8::EscapableHandleScope; - using v8::Function; - using v8::FunctionCallbackInfo; -@@ -186,13 +185,12 @@ void PatchProcessObject(const FunctionCallbackInfo<Value>& args) { - - // process.title - CHECK(process -- ->SetAccessor( -+ ->SetNativeDataProperty( - context, - FIXED_ONE_BYTE_STRING(isolate, "title"), - ProcessTitleGetter, - env->owns_process_state() ? ProcessTitleSetter : nullptr, - Local<Value>(), -- DEFAULT, - None, - SideEffectType::kHasNoSideEffect) - .FromJust()); -@@ -211,9 +209,15 @@ void PatchProcessObject(const FunctionCallbackInfo<Value>& args) { - READONLY_PROPERTY(process, "pid", - Integer::New(isolate, uv_os_getpid())); - -- CHECK(process->SetAccessor(context, -- FIXED_ONE_BYTE_STRING(isolate, "ppid"), -- GetParentProcessId).FromJust()); -+ CHECK(process -+ ->SetNativeDataProperty(context, -+ FIXED_ONE_BYTE_STRING(isolate, "ppid"), -+ GetParentProcessId, -+ nullptr, -+ Local<Value>(), -+ None, -+ SideEffectType::kHasNoSideEffect) -+ .FromJust()); - - // --security-revert flags - #define V(code, _, __) \ -@@ -238,12 +242,15 @@ void PatchProcessObject(const FunctionCallbackInfo<Value>& args) { - - // process.debugPort - CHECK(process -- ->SetAccessor(context, -- FIXED_ONE_BYTE_STRING(isolate, "debugPort"), -- DebugPortGetter, -- env->owns_process_state() ? DebugPortSetter : nullptr, -- Local<Value>()) -- .FromJust()); -+ ->SetNativeDataProperty( -+ context, -+ FIXED_ONE_BYTE_STRING(isolate, "debugPort"), -+ DebugPortGetter, -+ env->owns_process_state() ? DebugPortSetter : nullptr, -+ Local<Value>(), -+ None, -+ SideEffectType::kHasNoSideEffect) -+ .FromJust()); - - // process.versions - Local<Object> versions = Object::New(isolate); -diff --git a/test/parallel/test-worker-unsupported-things.js b/test/parallel/test-worker-unsupported-things.js -index 18c1617c3cde5ef12f9c97828840c39e0be3dc2c..95d93d24dec9f1944091a97574f01c94d617cc49 100644 ---- a/test/parallel/test-worker-unsupported-things.js -+++ b/test/parallel/test-worker-unsupported-things.js -@@ -14,14 +14,16 @@ if (!process.env.HAS_STARTED_WORKER) { - } else { - { - const before = process.title; -- process.title += ' in worker'; -- assert.strictEqual(process.title, before); -+ const after = before + ' in worker'; -+ process.title = after; -+ assert.strictEqual(process.title, after); - } - - { - const before = process.debugPort; -- process.debugPort++; -- assert.strictEqual(process.debugPort, before); -+ const after = before + 1; -+ process.debugPort = after; -+ assert.strictEqual(process.debugPort, after); - } - - { diff --git a/patches/node/src_remove_dependency_on_wrapper-descriptor-based_cppheap.patch b/patches/node/src_remove_dependency_on_wrapper-descriptor-based_cppheap.patch deleted file mode 100644 index f6d219887d84a..0000000000000 --- a/patches/node/src_remove_dependency_on_wrapper-descriptor-based_cppheap.patch +++ /dev/null @@ -1,308 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Joyee Cheung <joyeec9h3@gmail.com> -Date: Wed, 29 May 2024 19:59:19 +0200 -Subject: src: remove dependency on wrapper-descriptor-based CppHeap - -As V8 has moved away from wrapper-descriptor-based CppHeap, this -patch: - -1. Create the CppHeap without using wrapper descirptors. -2. Deprecates node::SetCppgcReference() in favor of - v8::Object::Wrap() since the wrapper descriptor is no longer - relevant. It is still kept as a compatibility layer for addons - that need to also work on Node.js versions without - v8::Object::Wrap(). - -(cherry picked from commit 30329d06235a9f9733b1d4da479b403462d1b326) - -diff --git a/src/env-inl.h b/src/env-inl.h -index 0d32d9f5a55da257a5e5a895a2ff002b780f96fe..9567d9499c62ea44cca651e87ab912ad55e2d90b 100644 ---- a/src/env-inl.h -+++ b/src/env-inl.h -@@ -62,31 +62,6 @@ inline uv_loop_t* IsolateData::event_loop() const { - return event_loop_; - } - --inline void IsolateData::SetCppgcReference(v8::Isolate* isolate, -- v8::Local<v8::Object> object, -- void* wrappable) { -- v8::CppHeap* heap = isolate->GetCppHeap(); -- CHECK_NOT_NULL(heap); -- v8::WrapperDescriptor descriptor = heap->wrapper_descriptor(); -- uint16_t required_size = std::max(descriptor.wrappable_instance_index, -- descriptor.wrappable_type_index); -- CHECK_GT(object->InternalFieldCount(), required_size); -- -- uint16_t* id_ptr = nullptr; -- { -- Mutex::ScopedLock lock(isolate_data_mutex_); -- auto it = -- wrapper_data_map_.find(descriptor.embedder_id_for_garbage_collected); -- CHECK_NE(it, wrapper_data_map_.end()); -- id_ptr = &(it->second->cppgc_id); -- } -- -- object->SetAlignedPointerInInternalField(descriptor.wrappable_type_index, -- id_ptr); -- object->SetAlignedPointerInInternalField(descriptor.wrappable_instance_index, -- wrappable); --} -- - inline uint16_t* IsolateData::embedder_id_for_cppgc() const { - return &(wrapper_data_->cppgc_id); - } -diff --git a/src/env.cc b/src/env.cc -index 63fdeeb26ba89284e74ca37050dfd170e7963331..56eb42643f26f3ebb447cb625d5422dcfa872189 100644 ---- a/src/env.cc -+++ b/src/env.cc -@@ -23,6 +23,7 @@ - #include "util-inl.h" - #include "v8-cppgc.h" - #include "v8-profiler.h" -+#include "v8-sandbox.h" // v8::Object::Wrap(), v8::Object::Unwrap() - - #include <algorithm> - #include <atomic> -@@ -72,7 +73,6 @@ using v8::TryCatch; - using v8::Uint32; - using v8::Undefined; - using v8::Value; --using v8::WrapperDescriptor; - using worker::Worker; - - int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64; -@@ -529,6 +529,14 @@ void IsolateData::CreateProperties() { - CreateEnvProxyTemplate(this); - } - -+// Previously, the general convention of the wrappable layout for cppgc in -+// the ecosystem is: -+// [ 0 ] -> embedder id -+// [ 1 ] -> wrappable instance -+// Now V8 has deprecated this layout-based tracing enablement, embedders -+// should simply use v8::Object::Wrap() and v8::Object::Unwrap(). We preserve -+// this layout only to distinguish internally how the memory of a Node.js -+// wrapper is managed or whether a wrapper is managed by Node.js. - constexpr uint16_t kDefaultCppGCEmbedderID = 0x90de; - Mutex IsolateData::isolate_data_mutex_; - std::unordered_map<uint16_t, std::unique_ptr<PerIsolateWrapperData>> -@@ -566,36 +574,16 @@ IsolateData::IsolateData(Isolate* isolate, - v8::CppHeap* cpp_heap = isolate->GetCppHeap(); - - uint16_t cppgc_id = kDefaultCppGCEmbedderID; -- if (cpp_heap != nullptr) { -- // The general convention of the wrappable layout for cppgc in the -- // ecosystem is: -- // [ 0 ] -> embedder id -- // [ 1 ] -> wrappable instance -- // If the Isolate includes a CppHeap attached by another embedder, -- // And if they also use the field 0 for the ID, we DCHECK that -- // the layout matches our layout, and record the embedder ID for cppgc -- // to avoid accidentally enabling cppgc on non-cppgc-managed wrappers . -- v8::WrapperDescriptor descriptor = cpp_heap->wrapper_descriptor(); -- if (descriptor.wrappable_type_index == BaseObject::kEmbedderType) { -- cppgc_id = descriptor.embedder_id_for_garbage_collected; -- DCHECK_EQ(descriptor.wrappable_instance_index, BaseObject::kSlot); -- } -- // If the CppHeap uses the slot we use to put non-cppgc-traced BaseObject -- // for embedder ID, V8 could accidentally enable cppgc on them. So -- // safe guard against this. -- DCHECK_NE(descriptor.wrappable_type_index, BaseObject::kSlot); -- } else { -- cpp_heap_ = CppHeap::Create( -- platform, -- CppHeapCreateParams{ -- {}, -- WrapperDescriptor( -- BaseObject::kEmbedderType, BaseObject::kSlot, cppgc_id)}); -- isolate->AttachCppHeap(cpp_heap_.get()); -- } - // We do not care about overflow since we just want this to be different - // from the cppgc id. - uint16_t non_cppgc_id = cppgc_id + 1; -+ if (cpp_heap == nullptr) { -+ cpp_heap_ = CppHeap::Create(platform, v8::CppHeapCreateParams{{}}); -+ // TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8 -+ // own it when we can keep the isolate registered/task runner discoverable -+ // during isolate disposal. -+ isolate->AttachCppHeap(cpp_heap_.get()); -+ } - - { - // GC could still be run after the IsolateData is destroyed, so we store -@@ -628,11 +616,12 @@ IsolateData::~IsolateData() { - } - } - --// Public API -+// Deprecated API, embedders should use v8::Object::Wrap() directly instead. - void SetCppgcReference(Isolate* isolate, - Local<Object> object, - void* wrappable) { -- IsolateData::SetCppgcReference(isolate, object, wrappable); -+ v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>( -+ isolate, object, static_cast<v8::Object::Wrappable*>(wrappable)); - } - - void IsolateData::MemoryInfo(MemoryTracker* tracker) const { -diff --git a/src/env.h b/src/env.h -index 07accfbcca491966c6c8ad9c20e146dbd22347f0..1079e3beb02e5f5d71a15fd2db65cb93ebd175d6 100644 ---- a/src/env.h -+++ b/src/env.h -@@ -175,10 +175,6 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { - uint16_t* embedder_id_for_cppgc() const; - uint16_t* embedder_id_for_non_cppgc() const; - -- static inline void SetCppgcReference(v8::Isolate* isolate, -- v8::Local<v8::Object> object, -- void* wrappable); -- - inline uv_loop_t* event_loop() const; - inline MultiIsolatePlatform* platform() const; - inline const SnapshotData* snapshot_data() const; -diff --git a/src/node.h b/src/node.h -index 174fd4d1af4c8cd75aec09f4548a674fd5539fb2..42d55d24bd0770795ae0c0e19241d25a6350ae08 100644 ---- a/src/node.h -+++ b/src/node.h -@@ -1560,24 +1560,14 @@ void RegisterSignalHandler(int signal, - bool reset_handler = false); - #endif // _WIN32 - --// Configure the layout of the JavaScript object with a cppgc::GarbageCollected --// instance so that when the JavaScript object is reachable, the garbage --// collected instance would have its Trace() method invoked per the cppgc --// contract. To make it work, the process must have called --// cppgc::InitializeProcess() before, which is usually the case for addons --// loaded by the stand-alone Node.js executable. Embedders of Node.js can use --// either need to call it themselves or make sure that --// ProcessInitializationFlags::kNoInitializeCppgc is *not* set for cppgc to --// work. --// If the CppHeap is owned by Node.js, which is usually the case for addon, --// the object must be created with at least two internal fields available, --// and the first two internal fields would be configured by Node.js. --// This may be superseded by a V8 API in the future, see --// https://bugs.chromium.org/p/v8/issues/detail?id=13960. Until then this --// serves as a helper for Node.js isolates. --NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate, -- v8::Local<v8::Object> object, -- void* wrappable); -+// This is kept as a compatibility layer for addons to wrap cppgc-managed -+// objects on Node.js versions without v8::Object::Wrap(). Addons created to -+// work with only Node.js versions with v8::Object::Wrap() should use that -+// instead. -+NODE_DEPRECATED("Use v8::Object::Wrap()", -+ NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate, -+ v8::Local<v8::Object> object, -+ void* wrappable)); - - } // namespace node - -diff --git a/test/addons/cppgc-object/binding.cc b/test/addons/cppgc-object/binding.cc -index 1b70ff11dc561abdc5ac794f6280557d5c428239..7fc16a87b843ce0626ee137a07c3ccb7f4cc6493 100644 ---- a/test/addons/cppgc-object/binding.cc -+++ b/test/addons/cppgc-object/binding.cc -@@ -1,8 +1,10 @@ -+#include <assert.h> - #include <cppgc/allocation.h> - #include <cppgc/garbage-collected.h> - #include <cppgc/heap.h> - #include <node.h> - #include <v8-cppgc.h> -+#include <v8-sandbox.h> - #include <v8.h> - #include <algorithm> - -@@ -15,8 +17,10 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> { - static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Isolate* isolate = args.GetIsolate(); - v8::Local<v8::Object> js_object = args.This(); -- CppGCed* gc_object = cppgc::MakeGarbageCollected<CppGCed>( -- isolate->GetCppHeap()->GetAllocationHandle()); -+ auto* heap = isolate->GetCppHeap(); -+ assert(heap != nullptr); -+ CppGCed* gc_object = -+ cppgc::MakeGarbageCollected<CppGCed>(heap->GetAllocationHandle()); - node::SetCppgcReference(isolate, js_object, gc_object); - args.GetReturnValue().Set(js_object); - } -@@ -24,12 +28,6 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> { - static v8::Local<v8::Function> GetConstructor( - v8::Local<v8::Context> context) { - auto ft = v8::FunctionTemplate::New(context->GetIsolate(), New); -- auto ot = ft->InstanceTemplate(); -- v8::WrapperDescriptor descriptor = -- context->GetIsolate()->GetCppHeap()->wrapper_descriptor(); -- uint16_t required_size = std::max(descriptor.wrappable_instance_index, -- descriptor.wrappable_type_index); -- ot->SetInternalFieldCount(required_size + 1); - return ft->GetFunction(context).ToLocalChecked(); - } - -diff --git a/test/cctest/test_cppgc.cc b/test/cctest/test_cppgc.cc -index 49665174615870b4f70529b1d548e593846140a1..edd413ae9b956b2e59e8166785adef6a8ff06d51 100644 ---- a/test/cctest/test_cppgc.cc -+++ b/test/cctest/test_cppgc.cc -@@ -3,16 +3,12 @@ - #include <cppgc/heap.h> - #include <node.h> - #include <v8-cppgc.h> -+#include <v8-sandbox.h> - #include <v8.h> - #include "node_test_fixture.h" - - // This tests that Node.js can work with an existing CppHeap. - --// Mimic the Blink layout. --static int kWrappableTypeIndex = 0; --static int kWrappableInstanceIndex = 1; --static uint16_t kEmbedderID = 0x1; -- - // Mimic a class that does not know about Node.js. - class CppGCed : public cppgc::GarbageCollected<CppGCed> { - public: -@@ -23,12 +19,11 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> { - static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Isolate* isolate = args.GetIsolate(); - v8::Local<v8::Object> js_object = args.This(); -- CppGCed* gc_object = cppgc::MakeGarbageCollected<CppGCed>( -- isolate->GetCppHeap()->GetAllocationHandle()); -- js_object->SetAlignedPointerInInternalField(kWrappableTypeIndex, -- &kEmbedderID); -- js_object->SetAlignedPointerInInternalField(kWrappableInstanceIndex, -- gc_object); -+ auto* heap = isolate->GetCppHeap(); -+ CHECK_NOT_NULL(heap); -+ CppGCed* gc_object = -+ cppgc::MakeGarbageCollected<CppGCed>(heap->GetAllocationHandle()); -+ node::SetCppgcReference(isolate, js_object, gc_object); - kConstructCount++; - args.GetReturnValue().Set(js_object); - } -@@ -36,8 +31,6 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> { - static v8::Local<v8::Function> GetConstructor( - v8::Local<v8::Context> context) { - auto ft = v8::FunctionTemplate::New(context->GetIsolate(), New); -- auto ot = ft->InstanceTemplate(); -- ot->SetInternalFieldCount(2); - return ft->GetFunction(context).ToLocalChecked(); - } - -@@ -58,12 +51,12 @@ TEST_F(NodeZeroIsolateTestFixture, ExistingCppHeapTest) { - - // Create and attach the CppHeap before we set up the IsolateData so that - // it recognizes the existing heap. -- std::unique_ptr<v8::CppHeap> cpp_heap = v8::CppHeap::Create( -- platform.get(), -- v8::CppHeapCreateParams( -- {}, -- v8::WrapperDescriptor( -- kWrappableTypeIndex, kWrappableInstanceIndex, kEmbedderID))); -+ std::unique_ptr<v8::CppHeap> cpp_heap = -+ v8::CppHeap::Create(platform.get(), v8::CppHeapCreateParams{{}}); -+ -+ // TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8 -+ // own it when we can keep the isolate registered/task runner discoverable -+ // during isolate disposal. - isolate->AttachCppHeap(cpp_heap.get()); - - // Try creating Context + IsolateData + Environment. diff --git a/patches/node/src_stop_using_deprecated_fields_of_fastapicallbackoptions.patch b/patches/node/src_stop_using_deprecated_fields_of_fastapicallbackoptions.patch deleted file mode 100644 index b798ee11d432d..0000000000000 --- a/patches/node/src_stop_using_deprecated_fields_of_fastapicallbackoptions.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andreas Haas <ahaas@chromium.org> -Date: Sun, 28 Jul 2024 09:20:12 +0200 -Subject: src: stop using deprecated fields of `v8::FastApiCallbackOptions` - -Two fields on the `v8::FastApiCallbackOptions` struct were deprecated -recently: `fallback` and `wasm_memory`. This PR removes uses of these -two fields in node.js. - -(This is a subset of upstream commit d0000b118 from the `canary-base` -branch of Node.js. This patch can be removed when Electron upgrades to -a stable Node release that contains the change. -- Charles) - -diff --git a/src/crypto/crypto_timing.cc b/src/crypto/crypto_timing.cc -index dbc46400501b61814d5be0ec1cb01b0dcd94e1d0..fe669d40c31a29334b047b9cfee3067f64ef0a7b 100644 ---- a/src/crypto/crypto_timing.cc -+++ b/src/crypto/crypto_timing.cc -@@ -60,7 +60,8 @@ bool FastTimingSafeEqual(Local<Value> receiver, - if (a.length() != b.length() || !a.getStorageIfAligned(&data_a) || - !b.getStorageIfAligned(&data_b)) { - TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.error"); -- options.fallback = true; -+ v8::HandleScope scope(options.isolate); -+ THROW_ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH(options.isolate); - return false; - } - -diff --git a/src/histogram.cc b/src/histogram.cc -index b655808e43d7c700ddeab7690e287bdbc9bfa50a..b0f7ae4e3af652c6dfe09f66d88485c5783f4037 100644 ---- a/src/histogram.cc -+++ b/src/histogram.cc -@@ -187,7 +187,8 @@ void HistogramBase::FastRecord(Local<Value> unused, - const int64_t value, - FastApiCallbackOptions& options) { - if (value < 1) { -- options.fallback = true; -+ Environment* env = Environment::GetCurrent(options.isolate); -+ THROW_ERR_OUT_OF_RANGE(env, "value is out of range"); - return; - } - HistogramBase* histogram; -diff --git a/src/node_wasi.cc b/src/node_wasi.cc -index 090866960beb8f1759c99e95536924b8b61fb723..3f91b651b83a20e70d5b368e012f5ee4b9d16092 100644 ---- a/src/node_wasi.cc -+++ b/src/node_wasi.cc -@@ -275,17 +275,19 @@ R WASI::WasiFunction<FT, F, R, Args...>::FastCallback( - return EinvalError<R>(); - } - -- if (options.wasm_memory == nullptr || wasi->memory_.IsEmpty()) [[unlikely]] { -- // fallback to slow path which to throw an error about missing memory. -- options.fallback = true; -+ v8::Isolate* isolate = receiver->GetIsolate(); -+ v8::HandleScope handle_scope(isolate); -+ if (wasi->memory_.IsEmpty()) { -+ THROW_ERR_WASI_NOT_STARTED(isolate); - return EinvalError<R>(); - } -- uint8_t* memory = nullptr; -- CHECK(options.wasm_memory->getStorageIfAligned(&memory)); - -- return F(*wasi, -- {reinterpret_cast<char*>(memory), options.wasm_memory->length()}, -- args...); -+ Local<ArrayBuffer> ab = wasi->memory_.Get(isolate)->Buffer(); -+ size_t mem_size = ab->ByteLength(); -+ char* mem_data = static_cast<char*>(ab->Data()); -+ CHECK_NOT_NULL(mem_data); -+ -+ return F(*wasi, {mem_data, mem_size}, args...); - } - - namespace { diff --git a/patches/node/src_use_cp_utf8_for_wide_file_names_on_win32.patch b/patches/node/src_use_cp_utf8_for_wide_file_names_on_win32.patch new file mode 100644 index 0000000000000..d1207f12b1317 --- /dev/null +++ b/patches/node/src_use_cp_utf8_for_wide_file_names_on_win32.patch @@ -0,0 +1,308 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fedor Indutny <indutny@signal.org> +Date: Tue, 11 Nov 2025 13:43:01 -0800 +Subject: src: use CP_UTF8 for wide file names on win32 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +`src/node_modules.cc` needs to be consistent with `src/node_file.cc` in +how it translates the utf8 strings to `std::wstring` otherwise we might +end up in situation where we can read the source code of imported +package from disk, but fail to recognize that it is an ESM (or CJS) and +cause runtime errors. This type of error is possible on Windows when the +path contains unicode characters and "Language for non-Unicode programs" +is set to "Chinese (Traditional, Taiwan)". + +See: #58768 +PR-URL: https://github.com/nodejs/node/pull/60575 +Reviewed-By: Anna Henningsen <anna@addaleax.net> +Reviewed-By: Darshan Sen <raisinten@gmail.com> +Reviewed-By: Stefan Stojanovic <stefan.stojanovic@janeasystems.com> +Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> +Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> +Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> + +diff --git a/src/node_file.cc b/src/node_file.cc +index 969e7d08086f8442bed476feaf15599b8c79db7c..e7459654401c275dfb86207831016ed71060bcc9 100644 +--- a/src/node_file.cc ++++ b/src/node_file.cc +@@ -3175,42 +3175,6 @@ static void GetFormatOfExtensionlessFile( + return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT); + } + +-#ifdef _WIN32 +-#define BufferValueToPath(str) \ +- std::filesystem::path(ConvertToWideString(str.ToString(), CP_UTF8)) +- +-std::string ConvertWideToUTF8(const std::wstring& wstr) { +- if (wstr.empty()) return std::string(); +- +- int size_needed = WideCharToMultiByte(CP_UTF8, +- 0, +- &wstr[0], +- static_cast<int>(wstr.size()), +- nullptr, +- 0, +- nullptr, +- nullptr); +- std::string strTo(size_needed, 0); +- WideCharToMultiByte(CP_UTF8, +- 0, +- &wstr[0], +- static_cast<int>(wstr.size()), +- &strTo[0], +- size_needed, +- nullptr, +- nullptr); +- return strTo; +-} +- +-#define PathToString(path) ConvertWideToUTF8(path.wstring()); +- +-#else // _WIN32 +- +-#define BufferValueToPath(str) std::filesystem::path(str.ToStringView()); +-#define PathToString(path) path.native(); +- +-#endif // _WIN32 +- + static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); +@@ -3223,7 +3187,7 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) { + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemRead, src.ToStringView()); + +- auto src_path = BufferValueToPath(src); ++ auto src_path = src.ToPath(); + + BufferValue dest(isolate, args[1]); + CHECK_NOT_NULL(*dest); +@@ -3231,7 +3195,7 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) { + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView()); + +- auto dest_path = BufferValueToPath(dest); ++ auto dest_path = dest.ToPath(); + bool dereference = args[2]->IsTrue(); + bool recursive = args[3]->IsTrue(); + +@@ -3260,8 +3224,8 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) { + (src_status.type() == std::filesystem::file_type::directory) || + (dereference && src_status.type() == std::filesystem::file_type::symlink); + +- auto src_path_str = PathToString(src_path); +- auto dest_path_str = PathToString(dest_path); ++ auto src_path_str = ConvertPathToUTF8(src_path); ++ auto dest_path_str = ConvertPathToUTF8(dest_path); + + if (!error_code) { + // Check if src and dest are identical. +@@ -3356,7 +3320,7 @@ static bool CopyUtimes(const std::filesystem::path& src, + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + +- auto src_path_str = PathToString(src); ++ auto src_path_str = ConvertPathToUTF8(src); + int result = uv_fs_stat(nullptr, &req, src_path_str.c_str(), nullptr); + if (is_uv_error(result)) { + env->ThrowUVException(result, "stat", nullptr, src_path_str.c_str()); +@@ -3367,7 +3331,7 @@ static bool CopyUtimes(const std::filesystem::path& src, + const double source_atime = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + const double source_mtime = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + +- auto dest_file_path_str = PathToString(dest); ++ auto dest_file_path_str = ConvertPathToUTF8(dest); + int utime_result = uv_fs_utime(nullptr, + &req, + dest_file_path_str.c_str(), +@@ -3502,7 +3466,7 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) { + std::error_code error; + for (auto dir_entry : std::filesystem::directory_iterator(src)) { + auto dest_file_path = dest / dir_entry.path().filename(); +- auto dest_str = PathToString(dest); ++ auto dest_str = ConvertPathToUTF8(dest); + + if (dir_entry.is_symlink()) { + if (verbatim_symlinks) { +@@ -3565,7 +3529,7 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) { + } + } else if (std::filesystem::is_regular_file(dest_file_path)) { + if (!dereference || (!force && error_on_exist)) { +- auto dest_file_path_str = PathToString(dest_file_path); ++ auto dest_file_path_str = ConvertPathToUTF8(dest_file_path); + env->ThrowStdErrException( + std::make_error_code(std::errc::file_exists), + "cp", +diff --git a/src/node_modules.cc b/src/node_modules.cc +index 529b7cfc15536c3fe5e7798c0f82698121751f2a..cbc3283fc2d511cce2eae0048cc9bf0fa917d38a 100644 +--- a/src/node_modules.cc ++++ b/src/node_modules.cc +@@ -332,22 +332,24 @@ const BindingData::PackageConfig* BindingData::TraverseParent( + + // Stop the search when the process doesn't have permissions + // to walk upwards +- if (is_permissions_enabled && +- !env->permission()->is_granted( +- env, +- permission::PermissionScope::kFileSystemRead, +- current_path.generic_string())) [[unlikely]] { +- return nullptr; ++ if (is_permissions_enabled) { ++ if (!env->permission()->is_granted( ++ env, ++ permission::PermissionScope::kFileSystemRead, ++ ConvertGenericPathToUTF8(current_path))) [[unlikely]] { ++ return nullptr; ++ } + } + + // Check if the path ends with `/node_modules` +- if (current_path.generic_string().ends_with("/node_modules")) { ++ if (current_path.filename() == "node_modules") { + return nullptr; + } + + auto package_json_path = current_path / "package.json"; ++ + auto package_json = +- GetPackageJSON(realm, package_json_path.string(), nullptr); ++ GetPackageJSON(realm, ConvertPathToUTF8(package_json_path), nullptr); + if (package_json != nullptr) { + return package_json; + } +@@ -369,20 +371,12 @@ void BindingData::GetNearestParentPackageJSONType( + + ToNamespacedPath(realm->env(), &path_value); + +- std::string path_value_str = path_value.ToString(); ++ auto path = path_value.ToPath(); ++ + if (slashCheck) { +- path_value_str.push_back(kPathSeparator); ++ path /= ""; + } + +- std::filesystem::path path; +- +-#ifdef _WIN32 +- std::wstring wide_path = ConvertToWideString(path_value_str, GetACP()); +- path = std::filesystem::path(wide_path); +-#else +- path = std::filesystem::path(path_value_str); +-#endif +- + auto package_json = TraverseParent(realm, path); + + if (package_json == nullptr) { +diff --git a/src/util-inl.h b/src/util-inl.h +index da9268dcf2ff432ddeec7c0f61a147b73f3130e2..82b2760f535345d126bc3dcf3890573d36dbb497 100644 +--- a/src/util-inl.h ++++ b/src/util-inl.h +@@ -698,12 +698,11 @@ inline bool IsWindowsBatchFile(const char* filename) { + return !extension.empty() && (extension == "cmd" || extension == "bat"); + } + +-inline std::wstring ConvertToWideString(const std::string& str, +- UINT code_page) { ++inline std::wstring ConvertUTF8ToWideString(const std::string& str) { + int size_needed = MultiByteToWideChar( +- code_page, 0, &str[0], static_cast<int>(str.size()), nullptr, 0); ++ CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0); + std::wstring wstrTo(size_needed, 0); +- MultiByteToWideChar(code_page, ++ MultiByteToWideChar(CP_UTF8, + 0, + &str[0], + static_cast<int>(str.size()), +@@ -711,6 +710,59 @@ inline std::wstring ConvertToWideString(const std::string& str, + size_needed); + return wstrTo; + } ++ ++std::string ConvertWideStringToUTF8(const std::wstring& wstr) { ++ if (wstr.empty()) return std::string(); ++ ++ int size_needed = WideCharToMultiByte(CP_UTF8, ++ 0, ++ &wstr[0], ++ static_cast<int>(wstr.size()), ++ nullptr, ++ 0, ++ nullptr, ++ nullptr); ++ std::string strTo(size_needed, 0); ++ WideCharToMultiByte(CP_UTF8, ++ 0, ++ &wstr[0], ++ static_cast<int>(wstr.size()), ++ &strTo[0], ++ size_needed, ++ nullptr, ++ nullptr); ++ return strTo; ++} ++ ++template <typename T, size_t kStackStorageSize> ++std::filesystem::path MaybeStackBuffer<T, kStackStorageSize>::ToPath() const { ++ std::wstring wide_path = ConvertUTF8ToWideString(ToString()); ++ return std::filesystem::path(wide_path); ++} ++ ++std::string ConvertPathToUTF8(const std::filesystem::path& path) { ++ return ConvertWideStringToUTF8(path.wstring()); ++} ++ ++std::string ConvertGenericPathToUTF8(const std::filesystem::path& path) { ++ return ConvertWideStringToUTF8(path.generic_wstring()); ++} ++ ++#else // _WIN32 ++ ++template <typename T, size_t kStackStorageSize> ++std::filesystem::path MaybeStackBuffer<T, kStackStorageSize>::ToPath() const { ++ return std::filesystem::path(ToStringView()); ++} ++ ++std::string ConvertPathToUTF8(const std::filesystem::path& path) { ++ return path.native(); ++} ++ ++std::string ConvertGenericPathToUTF8(const std::filesystem::path& path) { ++ return path.generic_string(); ++} ++ + #endif // _WIN32 + + inline v8::MaybeLocal<v8::Object> NewDictionaryInstance( +diff --git a/src/util.h b/src/util.h +index 6da57f95165bbdedb65dab6eaae8c39b815ee4e5..e65d6dbf359f61d051efe4e129c9035ed90cc8f6 100644 +--- a/src/util.h ++++ b/src/util.h +@@ -507,6 +507,8 @@ class MaybeStackBuffer { + inline std::basic_string_view<T> ToStringView() const { + return {out(), length()}; + } ++ // This can only be used if the buffer contains path data in UTF8 ++ inline std::filesystem::path ToPath() const; + + private: + size_t length_; +@@ -1026,9 +1028,15 @@ class JSONOutputStream final : public v8::OutputStream { + // Returns true if OS==Windows and filename ends in .bat or .cmd, + // case insensitive. + inline bool IsWindowsBatchFile(const char* filename); +-inline std::wstring ConvertToWideString(const std::string& str, UINT code_page); ++inline std::wstring ConvertUTF8ToWideString(const std::string& str); ++inline std::string ConvertWideStringToUTF8(const std::wstring& wstr); ++ + #endif // _WIN32 + ++inline std::filesystem::path ConvertUTF8ToPath(const std::string& str); ++inline std::string ConvertPathToUTF8(const std::filesystem::path& path); ++inline std::string ConvertGenericPathToUTF8(const std::filesystem::path& path); ++ + // A helper to create a new instance of the dictionary template. + // Unlike v8::DictionaryTemplate::NewInstance, this method will + // check that all properties have been set (are not empty MaybeLocals) diff --git a/patches/node/support_v8_sandboxed_pointers.patch b/patches/node/support_v8_sandboxed_pointers.patch index 18508387fe1a7..b035c26d399b2 100644 --- a/patches/node/support_v8_sandboxed_pointers.patch +++ b/patches/node/support_v8_sandboxed_pointers.patch @@ -7,10 +7,10 @@ This refactors several allocators to allocate within the V8 memory cage, allowing them to be compatible with the V8_SANDBOXED_POINTERS feature. diff --git a/src/api/environment.cc b/src/api/environment.cc -index 50accbf4052da11d47a5200997f1098ed9d85354..9e1b8d147a99fda962d75c343d0687ffea3c9c69 100644 +index d10f861c96931d06fb50dcdb66f2e79b0dee55a7..a869bc0a145009b57db3f37208e405d9356cc20f 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc -@@ -103,6 +103,14 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context, +@@ -109,6 +109,14 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context, return result; } @@ -25,17 +25,39 @@ index 50accbf4052da11d47a5200997f1098ed9d85354..9e1b8d147a99fda962d75c343d0687ff void* NodeArrayBufferAllocator::Allocate(size_t size) { void* ret; if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers) +@@ -324,6 +332,12 @@ Isolate* NewIsolate(Isolate::CreateParams* params, + // but also otherwise just doesn't work, and the only real alternative + // is disabling shared-readonly-heap mode altogether. + static Isolate::CreateParams first_params = *params; ++ // Clear allocator pointers to prevent use-after-free during static ++ // destruction. The static first_params can outlive V8's internal ++ // allocator systems, causing crashes when its destructor tries to ++ // free resources after V8 has shut down. ++ first_params.array_buffer_allocator = nullptr; ++ first_params.array_buffer_allocator_shared.reset(); + params->snapshot_blob = first_params.snapshot_blob; + params->external_references = first_params.external_references; + } diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc -index f23cedf4f2449d8edc9a8de1b70332e75d693cdd..976653dd1e9363e046788fc3419a9b649ceb2ea4 100644 +index 46a7d1396dc1a175ae99f4e403721f1730fdd320..bbb0abb3b9563074d350578e0f5a8fa211046b17 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc -@@ -55,13 +55,32 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const { - - namespace { - MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) { -+#if defined(V8_ENABLE_SANDBOX) +@@ -61,17 +61,22 @@ MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) { + bool secure; + }; + #ifdef V8_ENABLE_SANDBOX +- auto backing = ArrayBuffer::NewBackingStore( +- env->isolate(), +- data.size(), +- BackingStoreInitializationMode::kUninitialized, +- BackingStoreOnFailureMode::kReturnNull); +- if (!backing) { +- THROW_ERR_MEMORY_ALLOCATION_FAILED(env); +- return MaybeLocal<Value>(); +- } + std::unique_ptr<v8::BackingStore> backing; -+ if (data.size() > 0) { + if (data.size() > 0) { +- memcpy(backing->Data(), data.get(), data.size()); + std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator()); + void* v8_data = allocator->Allocate(data.size()); + CHECK(v8_data); @@ -50,32 +72,24 @@ index f23cedf4f2449d8edc9a8de1b70332e75d693cdd..976653dd1e9363e046788fc3419a9b64 + } else { + NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data()); + backing = v8::ArrayBuffer::NewBackingStore(env->isolate(), data.size()); -+ } -+#else + } + #else auto backing = ArrayBuffer::NewBackingStore( - data.get(), - data.size(), - [](void* data, size_t len, void* ptr) { DataPointer free_me(data, len); }, - nullptr); - data.release(); -- -+#endif - auto ab = ArrayBuffer::New(env->isolate(), std::move(backing)); - return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()); - } diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc -index 6346f8f7199cf7b7d3736c59571606fff102fbb6..7eea2eaefcad5780663a6b87985925ae5d70a5f9 100644 +index 12b0d804c6f1d4998b85160b0aac8eb7a3b5576b..27bd93769233dc65a064710db4095d9cdc3a8b1a 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc -@@ -359,10 +359,35 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept { - return *this; - } - --std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() { -+std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(Environment* env) { +@@ -346,24 +346,30 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore( // It's ok for allocated_data_ to be nullptr but // only if size_ is zero. CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr); +-#ifdef V8_ENABLE_SANDBOX +- // If the v8 sandbox is enabled, then all array buffers must be allocated +- // via the isolate. External buffers are not allowed. So, instead of wrapping +- // the allocated data we'll copy it instead. +- +- // TODO(@jasnell): It would be nice to use an abstracted utility to do this +- // branch instead of duplicating the V8_ENABLE_SANDBOX check each time. +#if defined(V8_ENABLE_SANDBOX) + // When V8 sandboxed pointers are enabled, we have to copy into the memory + // cage. We still want to ensure we erase the data on free though, so @@ -87,9 +101,18 @@ index 6346f8f7199cf7b7d3736c59571606fff102fbb6..7eea2eaefcad5780663a6b87985925ae + CHECK(v8_data); + memcpy(v8_data, allocated_data_, size()); + OPENSSL_clear_free(allocated_data_, size()); -+ std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore( + std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore( +- env->isolate(), + v8_data, -+ size(), + size(), +- BackingStoreInitializationMode::kUninitialized, +- BackingStoreOnFailureMode::kReturnNull); +- if (!ptr) { +- THROW_ERR_MEMORY_ALLOCATION_FAILED(env); +- return nullptr; +- } +- memcpy(ptr->Data(), allocated_data_, size()); +- OPENSSL_clear_free(allocated_data_, size_); + [](void* data, size_t length, void*) { + OPENSSL_cleanse(data, length); + std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator()); @@ -100,108 +123,131 @@ index 6346f8f7199cf7b7d3736c59571606fff102fbb6..7eea2eaefcad5780663a6b87985925ae + data_ = nullptr; + size_ = 0; + return ptr; -+#else + #else std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore( allocated_data_, - size(), -@@ -374,10 +399,11 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() { - data_ = nullptr; - size_ = 0; - return ptr; -+#endif // defined(V8_ENABLE_SANDBOX) - } - - Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) { -- std::unique_ptr<BackingStore> store = ReleaseToBackingStore(); -+ std::unique_ptr<BackingStore> store = ReleaseToBackingStore(env); - return ArrayBuffer::New(env->isolate(), std::move(store)); - } - -@@ -674,6 +700,16 @@ namespace { - // in which case this has the same semantics as +@@ -662,23 +668,16 @@ namespace { // using OPENSSL_malloc. However, if the secure heap is // initialized, SecureBuffer will automatically use it. -+#if defined(V8_ENABLE_SANDBOX) -+// When V8 sandboxed pointers are enabled, the secure heap cannot be used as -+// all ArrayBuffers must be allocated inside the V8 memory cage. -+void SecureBuffer(const FunctionCallbackInfo<Value>& args) { -+ CHECK(args[0]->IsUint32()); -+ uint32_t len = args[0].As<Uint32>()->Value(); -+ Local<ArrayBuffer> buffer = ArrayBuffer::New(args.GetIsolate(), len); -+ args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); -+} -+#else void SecureBuffer(const FunctionCallbackInfo<Value>& args) { - CHECK(args[0]->IsUint32()); - Environment* env = Environment::GetCurrent(args); -@@ -695,6 +731,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) { - Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store); - args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); - } -+#endif // defined(V8_ENABLE_SANDBOX) - - void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) { - #ifndef OPENSSL_IS_BORINGSSL -diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h -index 1592134716da2de40de4ba028ee937b765423e37..8f3ba65f1fef2c066d6df6087a08ba71100d1090 100644 ---- a/src/crypto/crypto_util.h -+++ b/src/crypto/crypto_util.h -@@ -242,7 +242,7 @@ class ByteSource { - // Creates a v8::BackingStore that takes over responsibility for - // any allocated data. The ByteSource will be reset with size = 0 - // after being called. -- std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(); -+ std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(Environment* env); - - v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env); +- Environment* env = Environment::GetCurrent(args); ++ CHECK(args[0]->IsUint32()); + #ifdef V8_ENABLE_SANDBOX +- // The v8 sandbox is enabled, so we cannot use the secure heap because +- // the sandbox requires that all array buffers be allocated via the isolate. +- // That is fundamentally incompatible with the secure heap which allocates +- // in openssl's secure heap area. Instead we'll just throw an error here. +- // +- // That said, we really shouldn't get here in the first place since the +- // option to enable the secure heap is only available when the sandbox +- // is disabled. +- UNREACHABLE(); ++ uint32_t len = args[0].As<Uint32>()->Value(); ++ Local<ArrayBuffer> buffer = ArrayBuffer::New(args.GetIsolate(), len); ++ args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); + #else +- CHECK(args[0]->IsUint32()); ++ Environment* env = Environment::GetCurrent(args); + uint32_t len = args[0].As<Uint32>()->Value(); + auto data = DataPointer::SecureAlloc(len); +- CHECK(data.isSecure()); + if (!data) { + return THROW_ERR_OPERATION_FAILED(env, "Allocation failed"); + } diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc -index f616223cfb0f6e10f7cf57ada9704316bde2797e..eb6dad44a49d997097c8fb5009eeb60a7305da27 100644 +index b30297eac08ad9587642b723f91d7e3b954294d4..4c5427596d1c90d3a413cdd9ff4f1151e657073d 100644 --- a/src/crypto/crypto_x509.cc +++ b/src/crypto/crypto_x509.cc -@@ -167,6 +167,19 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) { - MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) { - if (bio == nullptr || !*bio) return {}; +@@ -135,19 +135,17 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) { + return {}; BUF_MEM* mem = *bio; -+#if defined(V8_ENABLE_SANDBOX) + #ifdef V8_ENABLE_SANDBOX +- // If the v8 sandbox is enabled, then all array buffers must be allocated +- // via the isolate. External buffers are not allowed. So, instead of wrapping +- // the BIOPointer we'll copy it instead. +- auto backing = ArrayBuffer::NewBackingStore( +- env->isolate(), + std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator()); + void* v8_data = allocator->Allocate(mem->length); + CHECK(v8_data); + memcpy(v8_data, mem->data, mem->length); + std::unique_ptr<v8::BackingStore> backing = ArrayBuffer::NewBackingStore( + v8_data, -+ mem->length, + mem->length, +- BackingStoreInitializationMode::kUninitialized, +- BackingStoreOnFailureMode::kReturnNull); +- if (!backing) { +- THROW_ERR_MEMORY_ALLOCATION_FAILED(env); +- return MaybeLocal<Value>(); +- } +- memcpy(backing->Data(), mem->data, mem->length); + [](void* data, size_t length, void*) { + std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator()); + allocator->Free(data, length); + }, nullptr); -+#else + #else auto backing = ArrayBuffer::NewBackingStore( mem->data, - mem->length, -@@ -174,6 +187,8 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) { - BIOPointer free_me(static_cast<BIO*>(data)); - }, - bio->release()); -+#endif +diff --git a/src/env-inl.h b/src/env-inl.h +index 97c43afb487b58c0c77bd59b4a6b6d7a13690053..5dfbd564d5bbd22ebf3b529a07b73e85cbe51986 100644 +--- a/src/env-inl.h ++++ b/src/env-inl.h +@@ -44,6 +44,16 @@ + + namespace node { + ++NoArrayBufferZeroFillScope::NoArrayBufferZeroFillScope( ++ IsolateData* isolate_data) ++ : node_allocator_(isolate_data->node_allocator()) { ++ if (node_allocator_ != nullptr) node_allocator_->zero_fill_field()[0] = 0; ++} + - auto ab = ArrayBuffer::New(env->isolate(), std::move(backing)); - Local<Value> ret; - if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {}; ++NoArrayBufferZeroFillScope::~NoArrayBufferZeroFillScope() { ++ if (node_allocator_ != nullptr) node_allocator_->zero_fill_field()[0] = 1; ++} ++ + inline v8::Isolate* IsolateData::isolate() const { + return isolate_; + } +diff --git a/src/env.h b/src/env.h +index d34aec43630b3cf53004d8180446d7136b59ceac..b30314d7773742e2332ff47f84bc326151563690 100644 +--- a/src/env.h ++++ b/src/env.h +@@ -111,6 +111,19 @@ class ModuleWrap; + class Environment; + class Realm; + ++// Disables zero-filling for ArrayBuffer allocations in this scope. This is ++// similar to how we implement Buffer.allocUnsafe() in JS land. ++class NoArrayBufferZeroFillScope { ++ public: ++ inline explicit NoArrayBufferZeroFillScope(IsolateData* isolate_data); ++ inline ~NoArrayBufferZeroFillScope(); ++ ++ private: ++ NodeArrayBufferAllocator* node_allocator_; ++ ++ friend class Environment; ++}; ++ + struct IsolateDataSerializeInfo { + std::vector<SnapshotIndex> primitive_values; + std::vector<PropInfo> template_values; diff --git a/src/node_i18n.cc b/src/node_i18n.cc -index 61b6ecd240c9500f21f683065a2f920af3afb502..ad2b1c76325cb5c8f18a618c5a85ae87b6a7bbe7 100644 +index 3c4f419aa29470b3280174b58680b9421b0340b5..3b24ad2a2316f89d98b067e2c13988f87a9a00d2 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc -@@ -104,7 +104,7 @@ namespace { - +@@ -105,7 +105,7 @@ namespace { template <typename T> MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) { -- MaybeLocal<Object> ret = Buffer::New(env, buf); -+ MaybeLocal<Object> ret = Buffer::Copy(env, reinterpret_cast<char*>(buf->out()), buf->length() * sizeof(T)); - if (ret.IsEmpty()) - return ret; + Local<Object> ret; +- if (!Buffer::New(env, buf).ToLocal(&ret)) { ++ if (!Buffer::Copy(env, reinterpret_cast<char*>(buf->out()), buf->length() * sizeof(T)).ToLocal(&ret)) { + return {}; + } -@@ -181,7 +181,7 @@ MaybeLocal<Object> TranscodeLatin1ToUcs2(Environment* env, +@@ -182,7 +182,7 @@ MaybeLocal<Object> TranscodeLatin1ToUcs2(Environment* env, return {}; } @@ -210,7 +256,7 @@ index 61b6ecd240c9500f21f683065a2f920af3afb502..ad2b1c76325cb5c8f18a618c5a85ae87 } MaybeLocal<Object> TranscodeFromUcs2(Environment* env, -@@ -226,7 +226,7 @@ MaybeLocal<Object> TranscodeUcs2FromUtf8(Environment* env, +@@ -227,7 +227,7 @@ MaybeLocal<Object> TranscodeUcs2FromUtf8(Environment* env, return {}; } @@ -219,7 +265,7 @@ index 61b6ecd240c9500f21f683065a2f920af3afb502..ad2b1c76325cb5c8f18a618c5a85ae87 } MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env, -@@ -250,7 +250,7 @@ MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env, +@@ -251,7 +251,7 @@ MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env, return {}; } @@ -229,10 +275,10 @@ index 61b6ecd240c9500f21f683065a2f920af3afb502..ad2b1c76325cb5c8f18a618c5a85ae87 constexpr const char* EncodingName(const enum encoding encoding) { diff --git a/src/node_internals.h b/src/node_internals.h -index 275534285ec28f02b46639142ab4195b24267476..5f9d123f9d4b9feb7bc0b627b1e6309fdbd6e30d 100644 +index 12ea72b61b0a5e194207bb369dfed4b8667107cb..64442215714a98f648971e517ddd9c77e38fe3f2 100644 --- a/src/node_internals.h +++ b/src/node_internals.h -@@ -120,7 +120,9 @@ v8::MaybeLocal<v8::Object> InitializePrivateSymbols( +@@ -121,7 +121,9 @@ v8::MaybeLocal<v8::Object> InitializePrivateSymbols( class NodeArrayBufferAllocator : public ArrayBufferAllocator { public: @@ -243,7 +289,7 @@ index 275534285ec28f02b46639142ab4195b24267476..5f9d123f9d4b9feb7bc0b627b1e6309f void* Allocate(size_t size) override; // Defined in src/node.cc void* AllocateUninitialized(size_t size) override; -@@ -138,7 +140,7 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator { +@@ -139,7 +141,7 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator { } private: @@ -253,7 +299,7 @@ index 275534285ec28f02b46639142ab4195b24267476..5f9d123f9d4b9feb7bc0b627b1e6309f // Delegate to V8's allocator for compatibility with the V8 memory cage. diff --git a/src/node_serdes.cc b/src/node_serdes.cc -index c55a2e28066147ae5ca5def10ec76ccc03c634b4..c54183c72944989219b6437c9e571a3f7f3f8dd5 100644 +index 00fcd4b6afccce47ff21c4447d9cd60f25c11835..5f96ee2051e5339456185efddb149c4d43093f31 100644 --- a/src/node_serdes.cc +++ b/src/node_serdes.cc @@ -29,6 +29,26 @@ using v8::ValueSerializer; @@ -307,8 +353,8 @@ index c55a2e28066147ae5ca5def10ec76ccc03c634b4..c54183c72944989219b6437c9e571a3f }; class DeserializerContext : public BaseObject, -@@ -144,6 +170,24 @@ Maybe<uint32_t> SerializerContext::GetSharedArrayBufferId( - return id.ToLocalChecked()->Uint32Value(env()->context()); +@@ -145,6 +171,24 @@ Maybe<uint32_t> SerializerContext::GetSharedArrayBufferId( + return id->Uint32Value(env()->context()); } +void* SerializerContext::ReallocateBufferMemory(void* old_buffer, @@ -331,14 +377,15 @@ index c55a2e28066147ae5ca5def10ec76ccc03c634b4..c54183c72944989219b6437c9e571a3f + Maybe<bool> SerializerContext::WriteHostObject(Isolate* isolate, Local<Object> input) { - MaybeLocal<Value> ret; -@@ -209,9 +253,14 @@ void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) { + Local<Value> args[1] = { input }; +@@ -211,10 +255,17 @@ void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) { // Note: Both ValueSerializer and this Buffer::New() variant use malloc() // as the underlying allocator. std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release(); -- auto buf = Buffer::New(ctx->env(), -- reinterpret_cast<char*>(ret.first), -- ret.second); +- Local<Object> buf; +- if (Buffer::New(ctx->env(), reinterpret_cast<char*>(ret.first), ret.second) +- .ToLocal(&buf)) { +- args.GetReturnValue().Set(buf); + std::unique_ptr<v8::BackingStore> bs = + v8::ArrayBuffer::NewBackingStore(reinterpret_cast<char*>(ret.first), ret.second, + [](void* data, size_t length, void* deleter_data) { @@ -347,14 +394,17 @@ index c55a2e28066147ae5ca5def10ec76ccc03c634b4..c54183c72944989219b6437c9e571a3f + Local<ArrayBuffer> ab = v8::ArrayBuffer::New(ctx->env()->isolate(), std::move(bs)); + + auto buf = Buffer::New(ctx->env(), ab, 0, ret.second); ++ ++ if (!buf.IsEmpty()) { ++ args.GetReturnValue().Set(buf.ToLocalChecked()); + } + } - if (!buf.IsEmpty()) { - args.GetReturnValue().Set(buf.ToLocalChecked()); diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc -index 9787b14352753c5e0f8dc2b90093680e7cd10f1a..31af9e62396368af1b81f8841a705fd313df2b9f 100644 +index ef659f1c39f7ee958879bf395377bc99911fc346..225b1465b7c97d972a38968faf6d685017a80bf0 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc -@@ -132,12 +132,28 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) { +@@ -129,12 +129,28 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) { const uint8_t* enabled_pointer = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_name.out()); uint8_t* enabled_pointer_cast = const_cast<uint8_t*>(enabled_pointer); @@ -384,3 +434,26 @@ index 9787b14352753c5e0f8dc2b90093680e7cd10f1a..31af9e62396368af1b81f8841a705fd3 auto ab = ArrayBuffer::New(isolate, std::move(bs)); v8::Local<Uint8Array> u8 = v8::Uint8Array::New(ab, 0, 1); +diff --git a/test/parallel/test-process-env-allowed-flags-are-documented.js b/test/parallel/test-process-env-allowed-flags-are-documented.js +index 07e38748b07ddd32a6e3caa3c34183387e1cae18..f09bf0940dad2068f0aa5dce783dd422773d4bbb 100644 +--- a/test/parallel/test-process-env-allowed-flags-are-documented.js ++++ b/test/parallel/test-process-env-allowed-flags-are-documented.js +@@ -49,6 +49,8 @@ if (!hasOpenSSL3) { + documented.delete('--openssl-shared-config'); + } + ++const isV8Sandboxed = process.config.variables.v8_enable_sandbox; ++ + // Filter out options that are conditionally present. + const conditionalOpts = [ + { +@@ -74,6 +76,9 @@ const conditionalOpts = [ + }, { + include: process.features.inspector, + filter: (opt) => opt.startsWith('--inspect') || opt === '--debug-port' ++ }, { ++ include: !isV8Sandboxed, ++ filter: (opt) => ['--secure-heap', '--secure-heap-min'].includes(opt) + }, + ]; + documented.forEach((opt) => { diff --git a/patches/node/test_accomodate_v8_thenable_stack_trace_change_in_snapshot.patch b/patches/node/test_accomodate_v8_thenable_stack_trace_change_in_snapshot.patch index 5024caa3376d5..20dd33ff91c3e 100644 --- a/patches/node/test_accomodate_v8_thenable_stack_trace_change_in_snapshot.patch +++ b/patches/node/test_accomodate_v8_thenable_stack_trace_change_in_snapshot.patch @@ -12,7 +12,7 @@ See: https://chromium-review.googlesource.com/c/v8/v8/+/6826001 diff --git a/test/fixtures/test-runner/output/describe_it.snapshot b/test/fixtures/test-runner/output/describe_it.snapshot -index 347f3789693ddae7e7f9bd4125d8b19a31c1e764..35913d7f487dbd56eb8015e20f14a447de1db9bc 100644 +index 67d4af7f1b9f45d48b35c930cb1490ee019d0bdf..21d8744340c5a4c002d8c91266f46c2b66591b6e 100644 --- a/test/fixtures/test-runner/output/describe_it.snapshot +++ b/test/fixtures/test-runner/output/describe_it.snapshot @@ -690,6 +690,8 @@ not ok 54 - timeouts diff --git a/patches/node/test_formally_mark_some_tests_as_flaky.patch b/patches/node/test_formally_mark_some_tests_as_flaky.patch index 595f85a075db7..cf2948d7df336 100644 --- a/patches/node/test_formally_mark_some_tests_as_flaky.patch +++ b/patches/node/test_formally_mark_some_tests_as_flaky.patch @@ -7,7 +7,7 @@ Instead of disabling the tests, flag them as flaky so they still run but don't cause CI failures on flakes. diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status -index 6303908ce180db4d409707ae1f049319358642fb..d487497417e20c778dde57197dc18373799df36a 100644 +index 0036beb318df2241d49201dc9d0679763e551e7b..5713f13de818f84b1c598b73024773c1bbf936c6 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -5,6 +5,16 @@ prefix parallel @@ -25,10 +25,10 @@ index 6303908ce180db4d409707ae1f049319358642fb..d487497417e20c778dde57197dc18373 +test-cluster-shared-handle-bind-privileged-port: PASS, FLAKY +test-debugger-random-port-with-inspect-port: PASS, FLAKY # https://github.com/nodejs/node/issues/52273 - test-net-write-fully-async-hex-string: PASS, FLAKY - # https://github.com/nodejs/node/issues/52273 + test-shadow-realm-gc: SKIP + test-shadow-realm-gc-module: SKIP diff --git a/test/sequential/sequential.status b/test/sequential/sequential.status -index 6893abfe6e1c03d455099099f0d7e6b6930372a6..24aab3bad500ce4b9d43bf693c5efa6d563fe858 100644 +index c36eac6302d43a6b80ed0bc77db2c628bb66169c..627c4d576787e4363736615d08eebe481800909e 100644 --- a/test/sequential/sequential.status +++ b/test/sequential/sequential.status @@ -7,6 +7,18 @@ prefix sequential diff --git a/patches/node/test_handle_explicit_resource_management_globals.patch b/patches/node/test_handle_explicit_resource_management_globals.patch deleted file mode 100644 index f1f83f9037dc3..0000000000000 --- a/patches/node/test_handle_explicit_resource_management_globals.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= <targos@protonmail.com> -Date: Sat, 21 Dec 2024 09:25:55 +0100 -Subject: test: handle explicit resource management globals - -https://chromium-review.googlesource.com/c/chromium/src/+/6174695 - -diff --git a/test/common/globals.js b/test/common/globals.js -index 5d1c4415eeb09e92d062330afc0aecb1d297b6d3..2c1dac019ba2aa0a23c2434997e2007dd2eacde8 100644 ---- a/test/common/globals.js -+++ b/test/common/globals.js -@@ -64,6 +64,9 @@ const intrinsics = new Set([ - 'Atomics', - 'WebAssembly', - 'Iterator', -+ 'SuppressedError', -+ 'DisposableStack', -+ 'AsyncDisposableStack', - ]); - - if (global.gc) { diff --git a/patches/node/test_update_v8-stats_test_for_v8_12_6.patch b/patches/node/test_update_v8-stats_test_for_v8_12_6.patch deleted file mode 100644 index 671fcb14ed845..0000000000000 --- a/patches/node/test_update_v8-stats_test_for_v8_12_6.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "targos@protonmail.com" <targos@protonmail.com> -Date: Thu, 9 May 2024 12:00:39 +0200 -Subject: test: update v8-stats test for V8 12.6 - -Refs: https://github.com/v8/v8/commit/e30e228ee6e034de49a40af0173113198a19b497 - -diff --git a/test/parallel/test-v8-stats.js b/test/parallel/test-v8-stats.js -index bb954165f42c9de3db66bc5fdcac647654ad71ea..07be833e6e749a2bb68490c935c6791c178d126f 100644 ---- a/test/parallel/test-v8-stats.js -+++ b/test/parallel/test-v8-stats.js -@@ -48,6 +48,8 @@ const expectedHeapSpaces = [ - 'read_only_space', - 'shared_large_object_space', - 'shared_space', -+ 'shared_trusted_large_object_space', -+ 'shared_trusted_space', - 'trusted_large_object_space', - 'trusted_space', - ]; diff --git a/patches/node/test_use_static_method_names_in_call_stacks.patch b/patches/node/test_use_static_method_names_in_call_stacks.patch deleted file mode 100644 index 5fdb4a1fe55d3..0000000000000 --- a/patches/node/test_use_static_method_names_in_call_stacks.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Maddock <smaddock@slack-corp.com> -Date: Fri, 22 Nov 2024 15:18:05 -0500 -Subject: test: use static method names in call stacks - -Refs: https://chromium-review.googlesource.com/c/v8/v8/+/5907815 - -diff --git a/test/message/assert_throws_stack.out b/test/message/assert_throws_stack.out -index b1f3ea2108ba9c1a4f98928062b44b927eea31f2..897ddf36a04eb03edd01dd6b9a6fb4394cbdf114 100644 ---- a/test/message/assert_throws_stack.out -+++ b/test/message/assert_throws_stack.out -@@ -23,7 +23,7 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: - actual: Error: foo - at assert.throws.bar (*assert_throws_stack.js:*) - at getActual (node:assert:*) -- at Function.throws (node:assert:*) -+ at strict.throws (node:assert:*) - at Object.<anonymous> (*assert_throws_stack.js:*:*) - at * - at * -diff --git a/test/message/internal_assert_fail.out b/test/message/internal_assert_fail.out -index 9fc86673262dbacb45e544340c81b4d14ee3f845..5f1026791f323d6a5965810917c0ef33ae4bfd53 100644 ---- a/test/message/internal_assert_fail.out -+++ b/test/message/internal_assert_fail.out -@@ -6,7 +6,7 @@ Error [ERR_INTERNAL_ASSERTION]: Unreachable! - This is caused by either a bug in Node.js or incorrect usage of Node.js internals. - Please open an issue with this stack trace at https://github.com/nodejs/node/issues - -- at Function.fail (node:internal/assert:*:*) -+ at assert.fail (node:internal/assert:*:*) - at * (*test*message*internal_assert_fail.js:7:8) - at * - at * -diff --git a/test/parallel/test-fs-promises.js b/test/parallel/test-fs-promises.js -index d28af0f4833c4901e8542c8938cbcf51ff22464d..796ad3224c4dba06b53b2da14fc8469b158f206d 100644 ---- a/test/parallel/test-fs-promises.js -+++ b/test/parallel/test-fs-promises.js -@@ -58,7 +58,7 @@ assert.strictEqual( - code: 'ENOENT', - name: 'Error', - message: /^ENOENT: no such file or directory, access/, -- stack: /at async Function\.rejects/ -+ stack: /at async ok\.rejects/ - } - ).then(common.mustCall()); - diff --git a/patches/sqlite/fix_rename_sqlite_win32_exports_to_avoid_conflicts_with_node_js.patch b/patches/sqlite/fix_rename_sqlite_win32_exports_to_avoid_conflicts_with_node_js.patch index 75eb0d2cd3cbf..d539776faa397 100644 --- a/patches/sqlite/fix_rename_sqlite_win32_exports_to_avoid_conflicts_with_node_js.patch +++ b/patches/sqlite/fix_rename_sqlite_win32_exports_to_avoid_conflicts_with_node_js.patch @@ -10,13 +10,13 @@ the exported symbols in SQLite to avoid conflicts with Node.js. This should be upstreamed to SQLite. diff --git a/amalgamation/rename_exports.h b/amalgamation/rename_exports.h -index 1d45c732431e1031b7431ade967f0cfb66e500ea..be03b5b7e09108ba1e8ad4ff408b013c3ece90e3 100644 +index f61b7c38dcfa3a69ccc392c3e808fc8c2622773f..f4d5bb88a176ccb28c37420d30ac88c690486f96 100644 --- a/amalgamation/rename_exports.h +++ b/amalgamation/rename_exports.h @@ -367,6 +367,15 @@ - #define sqlite3session_patchset chrome_sqlite3session_patchset // Lines 11680-11684 - #define sqlite3session_patchset_strm chrome_sqlite3session_patchset_strm // Lines 12946-12950 - #define sqlite3session_table_filter chrome_sqlite3session_table_filter // Lines 11448-11455 + #define sqlite3session_patchset chrome_sqlite3session_patchset // Lines 11682-11686 + #define sqlite3session_patchset_strm chrome_sqlite3session_patchset_strm // Lines 12948-12952 + #define sqlite3session_table_filter chrome_sqlite3session_table_filter // Lines 11450-11457 +#define sqlite3_win32_write_debug chrome_sqlite3_win32_write_debug +#define sqlite3_win32_sleep chrome_sqlite3_win32_sleep +#define sqlite3_win32_is_nt chrome_sqlite3_win32_is_nt diff --git a/patches/squirrel.mac/build_add_gn_config.patch b/patches/squirrel.mac/build_add_gn_config.patch index d2c9ef6b4d975..afe5a0285c893 100644 --- a/patches/squirrel.mac/build_add_gn_config.patch +++ b/patches/squirrel.mac/build_add_gn_config.patch @@ -23,10 +23,10 @@ index 89c499e451ecb48655cfd42b01ffa1da56998c2e..98f80aad43a87ed75ca1660ad6a178db +vendor diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 -index 0000000000000000000000000000000000000000..68beb3d10580cdb747a78407c7f5bbb205825c4b +index 0000000000000000000000000000000000000000..a02e5f54d923513fd0676e91a99b8913bad6a57e --- /dev/null +++ b/BUILD.gn -@@ -0,0 +1,242 @@ +@@ -0,0 +1,250 @@ +assert(is_mac) + +import("//build/config/mac/rules.gni") @@ -48,12 +48,16 @@ index 0000000000000000000000000000000000000000..68beb3d10580cdb747a78407c7f5bbb2 + "Resources", + ] + info_plist = "vendor/Mantle/Mantle/Info.plist" -+ extra_substitutions = [ "CURRENT_PROJECT_VERSION=0.0.0" ] ++ extra_substitutions = [ ++ "CURRENT_PROJECT_VERSION=0.0.0", ++ "PRODUCT_BUNDLE_IDENTIFIER=com.electron.mantle", ++ ] + + configs -= [ + "//build/config/compiler:chromium_code", + "//build/config/gcc:symbol_visibility_hidden", + ] ++ + configs += [ "//build/config/compiler:no_chromium_code" ] + public_deps = [ ":mantle_headers" ] + deps = [] @@ -66,6 +70,8 @@ index 0000000000000000000000000000000000000000..68beb3d10580cdb747a78407c7f5bbb2 + include_dirs = [ + "vendor/Mantle/Mantle", + "vendor/Mantle/Mantle/extobjc", ++ "vendor/Mantle/Mantle/extobjc/include", ++ "vendor/Mantle/Mantle/include", + ] + + cflags_objc = [ @@ -196,6 +202,7 @@ index 0000000000000000000000000000000000000000..68beb3d10580cdb747a78407c7f5bbb2 + cflags_objc = [ + "-fobjc-weak", + "-Wno-unknown-warning-option", ++ "-Wno-deprecated-declarations", + "-Wno-block-capture-autoreleasing", + "-fobjc-arc", + ] @@ -262,6 +269,7 @@ index 0000000000000000000000000000000000000000..68beb3d10580cdb747a78407c7f5bbb2 + cflags_objc = [ + "-fobjc-weak", + "-fobjc-arc", ++ "-Wno-deprecated-declarations", + "-Wno-block-capture-autoreleasing", + ] + @@ -534,10 +542,10 @@ index 0000000000000000000000000000000000000000..a7aeeb7d3e187bd91ef12ed860d1e37e + sys.exit(e.returncode) diff --git a/filenames.gni b/filenames.gni new file mode 100644 -index 0000000000000000000000000000000000000000..3672153140b74fe948e7102b5e1ffad49341163d +index 0000000000000000000000000000000000000000..cee305c80588ffe2234bfadd5c211a9c301fe589 --- /dev/null +++ b/filenames.gni -@@ -0,0 +1,243 @@ +@@ -0,0 +1,249 @@ +squirrel_filenames = { + headers = [ + "Squirrel/NSBundle+SQRLVersionExtensions.h", @@ -582,22 +590,25 @@ index 0000000000000000000000000000000000000000..3672153140b74fe948e7102b5e1ffad4 + +mantle_filenames = { + headers = [ -+ "vendor/Mantle/Mantle/MTLJSONAdapter.h", -+ "vendor/Mantle/Mantle/MTLModel+NSCoding.h", -+ "vendor/Mantle/Mantle/MTLModel.h", + "vendor/Mantle/Mantle/MTLReflection.h", -+ "vendor/Mantle/Mantle/MTLValueTransformer.h", -+ "vendor/Mantle/Mantle/Mantle.h", -+ "vendor/Mantle/Mantle/NSArray+MTLManipulationAdditions.h", -+ "vendor/Mantle/Mantle/NSDictionary+MTLManipulationAdditions.h", + "vendor/Mantle/Mantle/NSError+MTLModelException.h", -+ "vendor/Mantle/Mantle/NSObject+MTLComparisonAdditions.h", -+ "vendor/Mantle/Mantle/NSValueTransformer+MTLInversionAdditions.h", -+ "vendor/Mantle/Mantle/NSValueTransformer+MTLPredefinedTransformerAdditions.h", -+ "vendor/Mantle/Mantle/extobjc/MTLEXTKeyPathCoding.h", -+ "vendor/Mantle/Mantle/extobjc/MTLEXTRuntimeExtensions.h", -+ "vendor/Mantle/Mantle/extobjc/MTLEXTScope.h", -+ "vendor/Mantle/Mantle/extobjc/metamacros.h", ++ "vendor/Mantle/Mantle/NSDictionary+MTLJSONKeyPath.h", ++ "vendor/Mantle/Mantle/include/MTLJSONAdapter.h", ++ "vendor/Mantle/Mantle/include/MTLModel+NSCoding.h", ++ "vendor/Mantle/Mantle/include/MTLModel.h", ++ "vendor/Mantle/Mantle/include/MTLTransformerErrorHandling.h", ++ "vendor/Mantle/Mantle/include/MTLValueTransformer.h", ++ "vendor/Mantle/Mantle/include/Mantle.h", ++ "vendor/Mantle/Mantle/include/NSArray+MTLManipulationAdditions.h", ++ "vendor/Mantle/Mantle/include/NSDictionary+MTLMappingAdditions.h", ++ "vendor/Mantle/Mantle/include/NSDictionary+MTLManipulationAdditions.h", ++ "vendor/Mantle/Mantle/include/NSObject+MTLComparisonAdditions.h", ++ "vendor/Mantle/Mantle/include/NSValueTransformer+MTLInversionAdditions.h", ++ "vendor/Mantle/Mantle/include/NSValueTransformer+MTLPredefinedTransformerAdditions.h", ++ "vendor/Mantle/Mantle/extobjc/include/MTLEXTKeyPathCoding.h", ++ "vendor/Mantle/Mantle/extobjc/include/MTLEXTRuntimeExtensions.h", ++ "vendor/Mantle/Mantle/extobjc/include/MTLEXTScope.h", ++ "vendor/Mantle/Mantle/extobjc/include/MTLMetamacros.h", + ] + + sources = [ @@ -605,9 +616,12 @@ index 0000000000000000000000000000000000000000..3672153140b74fe948e7102b5e1ffad4 + "vendor/Mantle/Mantle/MTLModel+NSCoding.m", + "vendor/Mantle/Mantle/MTLModel.m", + "vendor/Mantle/Mantle/MTLReflection.m", ++ "vendor/Mantle/Mantle/MTLTransformerErrorHandling.m", + "vendor/Mantle/Mantle/MTLValueTransformer.m", + "vendor/Mantle/Mantle/NSArray+MTLManipulationAdditions.m", ++ "vendor/Mantle/Mantle/NSDictionary+MTLJSONKeyPath.m", + "vendor/Mantle/Mantle/NSDictionary+MTLManipulationAdditions.m", ++ "vendor/Mantle/Mantle/NSDictionary+MTLMappingAdditions.m", + "vendor/Mantle/Mantle/NSError+MTLModelException.m", + "vendor/Mantle/Mantle/NSObject+MTLComparisonAdditions.m", + "vendor/Mantle/Mantle/NSValueTransformer+MTLInversionAdditions.m", diff --git a/patches/squirrel.mac/use_uttype_class_instead_of_deprecated_uttypeconformsto.patch b/patches/squirrel.mac/use_uttype_class_instead_of_deprecated_uttypeconformsto.patch index c1966fc3370b5..6fda441fe344b 100644 --- a/patches/squirrel.mac/use_uttype_class_instead_of_deprecated_uttypeconformsto.patch +++ b/patches/squirrel.mac/use_uttype_class_instead_of_deprecated_uttypeconformsto.patch @@ -6,10 +6,10 @@ Subject: Use UTType class instead of deprecated UTTypeConformsTo macOS 12 removed support for the deprecated UTTypeConformsTo function. Its replacement is the dedicated UTType class in the Uniform Type Identifiers framework. diff --git a/BUILD.gn b/BUILD.gn -index 68beb3d10580cdb747a78407c7f5bbb205825c4b..b9e871a0292eeda1f0e738329d0b510bdc3e34a0 100644 +index a02e5f54d923513fd0676e91a99b8913bad6a57e..6f32c4b203a0efa2ccd515e3754494deef5b39f0 100644 --- a/BUILD.gn +++ b/BUILD.gn -@@ -227,6 +227,7 @@ mac_framework_bundle("squirrel_framework") { +@@ -234,6 +234,7 @@ mac_framework_bundle("squirrel_framework") { "IOKit.framework", "Security.framework", "ServiceManagement.framework", diff --git a/patches/webrtc/fix_handle_pipewire_capturer_initialization_and_management.patch b/patches/webrtc/fix_handle_pipewire_capturer_initialization_and_management.patch index 231491f4167bb..4ea2687bb14a8 100644 --- a/patches/webrtc/fix_handle_pipewire_capturer_initialization_and_management.patch +++ b/patches/webrtc/fix_handle_pipewire_capturer_initialization_and_management.patch @@ -36,10 +36,10 @@ for desktop capturer. This change re-enables that fallback, which was previously default behavior. diff --git a/modules/desktop_capture/desktop_capturer.cc b/modules/desktop_capture/desktop_capturer.cc -index ae9aba26ee56e8a0d48f81994f964b278c9019d3..758f1b44e01adb6807bc7c5f673d06fffbac5865 100644 +index bf63f73178688e49286bb6686d5a42ce040c663e..f5f62a2b7865d8415ec08242312df006bcb2edf5 100644 --- a/modules/desktop_capture/desktop_capturer.cc +++ b/modules/desktop_capture/desktop_capturer.cc -@@ -123,7 +123,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateGenericCapturer( +@@ -138,7 +138,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateGenericCapturer( std::unique_ptr<DesktopCapturer> capturer; #if defined(WEBRTC_USE_PIPEWIRE) @@ -61,10 +61,10 @@ index 361b465dad2a53f4dac774fa2d6d6d9e3fc5fc31..ef05a35bc4f2c2352b12c0af0b09193b capturer_failed_ = true; } diff --git a/modules/desktop_capture/screen_capturer_linux.cc b/modules/desktop_capture/screen_capturer_linux.cc -index 94726750c5762e22b517445b23254513eb207aae..85946a6c7eef56a66c0ee2ec06bdc5f2ba49c53c 100644 +index f25e08fb594c563b1f8ca0fd1c4383ed39df5149..8ce6a9d82d808c1618b857ac83af85ac38a43a2a 100644 --- a/modules/desktop_capture/screen_capturer_linux.cc +++ b/modules/desktop_capture/screen_capturer_linux.cc -@@ -35,11 +35,10 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer( +@@ -39,11 +39,10 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer( #endif // defined(WEBRTC_USE_PIPEWIRE) #if defined(WEBRTC_USE_X11) @@ -80,10 +80,10 @@ index 94726750c5762e22b517445b23254513eb207aae..85946a6c7eef56a66c0ee2ec06bdc5f2 } // namespace webrtc diff --git a/modules/desktop_capture/window_capturer_linux.cc b/modules/desktop_capture/window_capturer_linux.cc -index f621a63e72131fd8426361a078a55d1e07c0e436..91394503da5e7f6d090e2eaede02316cf51ad7b2 100644 +index 87ea3d57212c5f62194f206787756b7f3fb63e90..3f565ab13a033dc29d55f819da7de464b6e19885 100644 --- a/modules/desktop_capture/window_capturer_linux.cc +++ b/modules/desktop_capture/window_capturer_linux.cc -@@ -35,11 +35,10 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer( +@@ -39,11 +39,10 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer( #endif // defined(WEBRTC_USE_PIPEWIRE) #if defined(WEBRTC_USE_X11) diff --git a/script/actions/screencapture-nag-remover.sh b/script/actions/screencapture-nag-remover.sh new file mode 100755 index 0000000000000..b62024fb2a345 --- /dev/null +++ b/script/actions/screencapture-nag-remover.sh @@ -0,0 +1,297 @@ +#!/bin/bash +# From https://github.com/luckman212/screencapture-nag-remover + +SELF='screencapture-nag-remover' +FQPN=$(realpath "$0") +PLIST="$HOME/Library/Group Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist" +AGENT_PLIST="$HOME/Library/LaunchAgents/$SELF.plist" +MDM_PROFILE="$HOME/Downloads/macOS_15.1_DisableScreenCaptureAlerts.mobileconfig" +TCC_DB='/Library/Application Support/com.apple.TCC/TCC.db' +FUTURE=$(/bin/date -j -v+100y +"%Y-%m-%d %H:%M:%S +0000") +INTERVAL=86400 #run every 24h + +IFS='.' read -r MAJ MIN _ < <(/usr/bin/sw_vers --productVersion) +if (( MAJ < 15 )); then + echo >&2 "this tool requires macOS 15 (Sequoia)" + exit +fi + +_os_is_151_or_higher() { + (( MAJ >= 15 )) && (( MIN > 0 )) +} + +_fda_settings() { + /usr/bin/open 'x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles' +} + +_open_device_management() { + /usr/bin/open 'x-apple.systempreferences:com.apple.preferences.configurationprofiles' +} + +_bundleid_to_name() { + local APP_NAME + APP_NAME=$(/usr/bin/mdfind kMDItemCFBundleIdentifier == "$1" 2>/dev/null) + echo "${APP_NAME##*/}" +} + +_create_plist() { + cat <<-EOF 2>/dev/null >"$PLIST" + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> + <plist version="1.0"> + <dict> + </dict> + </plist> + EOF +} + +_bounce_daemons() { + /usr/bin/killall -HUP replayd + /usr/bin/killall -u "$USER" cfprefsd +} + +_nagblock() { + local APP_NAME + if _os_is_151_or_higher; then + if [[ -z $1 ]]; then + echo >&2 "supply the bundle ID of the app" + return 1 + fi + APP_NAME=$(_bundleid_to_name "$1") + echo "disabling nag for $1${APP_NAME:+ ($APP_NAME)}" + /usr/bin/defaults write "$PLIST" "$1" -dict \ + kScreenCaptureApprovalLastAlerted -date "$FUTURE" \ + kScreenCaptureApprovalLastUsed -date "$FUTURE" + (( c++ )) + else + if [[ -z $1 ]]; then + echo >&2 "supply complete pathname to the binary inside the app bundle" + return 1 + fi + [[ -e $1 ]] || { echo >&2 "$1 does not exist"; return 1; } + IFS='/' read -ra PARTS <<< "$1" + for p in "${PARTS[@]}"; do + if [[ $p == *.app ]]; then + APP_NAME=$p + break + fi + done + echo "disabling nag for ${APP_NAME:-$1}" + /usr/bin/defaults write "$PLIST" "$1" -date "$FUTURE" + (( c++ )) + return 0 + fi +} + +_enum_apps() { + [[ -e $PLIST ]] || return 1 + if _os_is_151_or_higher; then + /usr/bin/plutil -convert raw -o - -- "$PLIST" + else + /usr/bin/plutil -convert xml1 -o - -- "$PLIST" | + /usr/bin/sed -n "s/.*<key>\(.*\)<\/key>.*/\1/p" + fi +} + +_generate_mdm_profile() { +UUID1=$(/usr/bin/uuidgen) +UUID2=$(/usr/bin/uuidgen) +/bin/cat <<EOF >"$MDM_PROFILE" +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>PayloadContent</key> + <array> + <dict> + <key>PayloadDisplayName</key> + <string>Restrictions</string> + <key>PayloadIdentifier</key> + <string>com.apple.applicationaccess.${UUID2}</string> + <key>PayloadType</key> + <string>com.apple.applicationaccess</string> + <key>PayloadUUID</key> + <string>${UUID2}</string> + <key>PayloadVersion</key> + <integer>1</integer> + <key>forceBypassScreenCaptureAlert</key> + <true/> + </dict> + </array> + <key>PayloadDescription</key> + <string>Disables additional screen capture alerts on macOS 15.1 or higher</string> + <key>PayloadDisplayName</key> + <string>DisableScreenCaptureAlert</string> + <key>PayloadIdentifier</key> + <string>com.apple.applicationaccess.forceBypassScreenCaptureAlert</string> + <key>PayloadScope</key> + <string>System</string> + <key>PayloadType</key> + <string>Configuration</string> + <key>PayloadUUID</key> + <string>${UUID1}</string> + <key>PayloadVersion</key> + <integer>1</integer> + <key>TargetDeviceType</key> + <integer>5</integer> +</dict> +</plist> +EOF +#Apple prohibits self-installing TCC profiles, they can only be pushed via MDM +#/usr/bin/open "$MDM_PROFILE" +#_open_device_management +echo "import ${MDM_PROFILE##*/} into your MDM to provision it" +/usr/bin/open -R "$MDM_PROFILE" +} + +_uninstall_launchagent() { + /bin/launchctl bootout gui/$UID "$AGENT_PLIST" 2>/dev/null + /bin/rm 2>/dev/null "$AGENT_PLIST" + echo "uninstalled $SELF LaunchAgent" +} + +_install_launchagent() { + _uninstall_launchagent &>/dev/null + read -r FDA_TEST < <(/usr/bin/sqlite3 "$TCC_DB" <<-EOS + SELECT COUNT(client) + FROM access + WHERE + client = '/bin/bash' AND + service = 'kTCCServiceSystemPolicyAllFiles' AND + auth_value = 2 + EOS + ) + if (( FDA_TEST == 0 )); then + /bin/cat <<-EOF >&2 + ┌──────────────────────────────────────────────────────────────────────────────────────┐ + │ For the LaunchAgent to work properly, you must grant Full Disk Access to /bin/bash │ + │ │ + │ The Full Disk Access settings panel will now be opened. Press the (+) button near │ + │ the bottom of the window, then press [⌘cmd + ⇧shift + g] and type '/bin/bash' and │ + │ click Open to get it to appear in the app list. │ + │ │ + │ Once that's all done, run the --install command again. │ + └──────────────────────────────────────────────────────────────────────────────────────┘ + EOF + sleep 3 + _fda_settings + return 1 + fi + /bin/cat >"$AGENT_PLIST" <<-EOF + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> + <plist version="1.0"> + <dict> + <key>Label</key> + <string>$SELF.agent</string> + <key>ProgramArguments</key> + <array> + <string>/bin/bash</string> + <string>--norc</string> + <string>--noprofile</string> + <string>$FQPN</string> + </array> + <key>StandardErrorPath</key> + <string>/private/tmp/$SELF.stderr</string> + <key>StandardOutPath</key> + <string>/private/tmp/$SELF.stdout</string> + <key>StartInterval</key> + <integer>$INTERVAL</integer> + <key>WorkingDirectory</key> + <string>/private/tmp</string> + </dict> + </plist> + EOF + /bin/chmod 644 "$PLIST" + if /bin/launchctl bootstrap gui/$UID "$AGENT_PLIST"; then + echo "installed $SELF LaunchAgent" + fi +} + +_manual_add_desc() { + if _os_is_151_or_higher ; then + echo "-a,--add <bundle_id> manually create an entry" + else + echo "-a,--add <path> manually create an entry (supply full path to binary)" + fi +} + +case $1 in + -h|--help) + /bin/cat <<-EOF + + a tool to help suppress macOS Sequoia's persistent ScreenCapture alerts + usage: ${0##*/} [args] + -r,--reveal show ${PLIST##*/} in Finder + -p,--print print current values + $(_manual_add_desc) + --reset initialize empty ${PLIST##*/} + --generate_profile generate configuration profile for use with your MDM server + --profiles opens Device Management in System Settings + --install install LaunchAgent to ensure alerts continue to be silenced + --uninstall remove LaunchAgent + EOF + if _os_is_151_or_higher; then /bin/cat <<-EOF + + ┌────────────────────────────────────────────────────────────────────────────────────┐ + │ macOS 15.1 introduced an official method for suppressing ScreenCapture alerts │ + │ for ALL apps on Macs enrolled in an MDM server (Jamf, Addigy, Mosyle etc). │ + │ │ + │ A configuration profile to enable this can be generated using --generate_profile │ + └────────────────────────────────────────────────────────────────────────────────────┘ + + EOF + fi + exit + ;; + -r|--reveal) + if [[ -e $PLIST ]]; then + /usr/bin/open -R "$PLIST" + else + /usr/bin/open "$(/usr/bin/dirname "$PLIST")" + fi + exit + ;; + -p|--print) + if [[ -e $PLIST ]]; then + /usr/bin/plutil -p "$PLIST" + else + echo >&2 "${PLIST##*/} does not exist" + fi + exit + ;; + --reset) _create_plist || echo >&2 "error, could not create ${PLIST##*/}"; exit;; + --generate_profile) _generate_mdm_profile; exit;; + --profiles) _open_device_management; exit;; + --install) _install_launchagent; exit;; + --uninstall) _uninstall_launchagent; exit;; +esac + +[[ -e $PLIST ]] || _create_plist +if ! /usr/bin/touch "$PLIST" 2>/dev/null; then + if [[ -n $__CFBundleIdentifier ]]; then + TERMINAL_NAME=$(_bundleid_to_name "$__CFBundleIdentifier") + fi + echo >&2 "Full Disk Access permissions are missing${TERMINAL_NAME:+ for $TERMINAL_NAME}" + exit 1 +fi + +case $1 in + -a|--add) + _nagblock "$2" + _bounce_daemons + exit + ;; + -*) echo >&2 "invalid arg: $1"; exit 1;; +esac + +c=0 +while read -r APP_PATH ; do + [[ -n $APP_PATH ]] || continue + _nagblock "$APP_PATH" +done < <(_enum_apps) + +#bounce daemons if any changes were made so the new settings take effect +(( c > 0 )) && _bounce_daemons + +exit 0 diff --git a/script/build-stats.mjs b/script/build-stats.mjs new file mode 100644 index 0000000000000..8079f3456bf93 --- /dev/null +++ b/script/build-stats.mjs @@ -0,0 +1,96 @@ +import * as fs from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; +import { parseArgs } from 'node:util'; + +async function main () { + const { positionals: [filename], values: { 'upload-stats': uploadStats } } = parseArgs({ + allowPositionals: true, + options: { + 'upload-stats': { + type: 'boolean', + default: false + } + } + }); + + if (!filename) { + throw new Error('filename is required (should be a siso.INFO file)'); + } + + const log = await fs.readFile(filename, 'utf-8'); + + // We expect to find a line which looks like stats=build.Stats{..., CacheHit:39008, Local:4778, Remote:0, LocalFallback:0, ...} + const match = log.match(/stats=build\.Stats{(.*)}/); + + if (!match) { + throw new Error('could not find stats=build.Stats in log'); + } + + const stats = Object.fromEntries(match[1].split(',').map(part => { + const [key, value] = part.trim().split(':'); + return [key, parseInt(value)]; + })); + const hitRate = stats.CacheHit / (stats.Remote + stats.CacheHit + stats.LocalFallback); + + console.log(`Effective cache hit rate: ${(hitRate * 100).toFixed(2)}%`); + + if (uploadStats) { + if (!process.env.DD_API_KEY) { + throw new Error('DD_API_KEY is not set'); + } + + const timestamp = Math.round(new Date().getTime() / 1000); + + const tags = []; + + if (process.env.TARGET_ARCH) tags.push(`target-arch:${process.env.TARGET_ARCH}`); + if (process.env.TARGET_PLATFORM) tags.push(`target-platform:${process.env.TARGET_PLATFORM}`); + if (process.env.GITHUB_HEAD_REF) { + // Will be set in pull requests + tags.push(`branch:${process.env.GITHUB_HEAD_REF}`); + } else if (process.env.GITHUB_REF_NAME) { + // Will be set for release branches + tags.push(`branch:${process.env.GITHUB_REF_NAME}`); + } + + const series = [ + { + metric: 'electron.build.effective-cache-hit-rate', + points: [{ timestamp, value: (hitRate * 100).toFixed(2) }], + type: 3, // GAUGE + unit: 'percent', + tags + } + ]; + + // Add all raw stats as individual metrics + for (const [key, value] of Object.entries(stats)) { + series.push({ + metric: `electron.build.stats.${key.toLowerCase()}`, + points: [{ timestamp, value }], + type: 1, // COUNT + tags + }); + } + + await fetch('https://api.datadoghq.com/api/v2/series', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'DD-API-KEY': process.env.DD_API_KEY + }, + body: JSON.stringify({ series }) + }); + } +} + +if ((await fs.realpath(process.argv[1])) === fileURLToPath(import.meta.url)) { + main() + .then(() => { + process.exit(0); + }) + .catch((err) => { + console.error(`ERROR: ${err.message}`); + process.exit(1); + }); +} diff --git a/script/gn-check.js b/script/gn-check.js index 542b1fbdeb734..13776019a6ed1 100644 --- a/script/gn-check.js +++ b/script/gn-check.js @@ -33,7 +33,9 @@ const gnCheckDirs = [ '//electron:electron_lib', '//electron:electron_app', '//electron/shell/common:mojo', - '//electron/shell/common:plugin' + '//electron/shell/common:plugin', + '//electron:testing_build', + '//electron:release_build' ]; for (const dir of gnCheckDirs) { diff --git a/script/lib/config.py b/script/lib/config.py index 6d60db6a214e4..d2076fbd94563 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -51,3 +51,12 @@ def get_zip_name(name, version, suffix=''): if suffix: zip_name += '-' + suffix return zip_name + '.zip' + +def get_tar_name(name, version, suffix=''): + arch = get_target_arch() + if arch == 'arm': + arch += 'v7l' + zip_name = f'{name}-{version}-{get_platform_key()}-{arch}' + if suffix: + zip_name += '-' + suffix + return zip_name + '.tar.xz' diff --git a/script/lib/git.py b/script/lib/git.py index 68789d8add0c8..55a3a560bebb3 100644 --- a/script/lib/git.py +++ b/script/lib/git.py @@ -52,7 +52,8 @@ def get_repo_root(path): def am(repo, patch_data, threeway=False, directory=None, exclude=None, committer_name=None, committer_email=None, keep_cr=True): - args = [] + # --keep-non-patch prevents stripping leading bracketed strings on the subject line + args = ['--keep-non-patch'] if threeway: args += ['--3way'] if directory is not None: diff --git a/script/lib/util.py b/script/lib/util.py index 38bb70cc8d029..040a144c444fe 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -70,20 +70,26 @@ def make_zip(zip_file_path, files, dirs): safe_unlink(zip_file_path) if sys.platform == 'darwin': allfiles = files + dirs - execute(['zip', '-r', '-y', zip_file_path] + allfiles) + execute(['zip', '-r', '-y', '-9', zip_file_path] + allfiles) else: with zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED, allowZip64=True) as zip_file: for filename in files: - zip_file.write(filename, filename) + zip_file.write(filename, filename, compress_type=zipfile.ZIP_DEFLATED, compresslevel=9) for dirname in dirs: for root, _, filenames in os.walk(dirname): for f in filenames: - zip_file.write(os.path.join(root, f)) + zip_file.write(os.path.join(root, f), compress_type=zipfile.ZIP_DEFLATED, compresslevel=9) zip_file.close() +def make_tar_xz(tar_file_path, files, dirs): + safe_unlink(tar_file_path) + allfiles = files + dirs + execute(['tar', '-cJf', tar_file_path] + allfiles) + + def rm_rf(path): try: shutil.rmtree(path) diff --git a/script/nan-spec-runner.js b/script/nan-spec-runner.js index e4675cb8981f2..b8259c7f753b3 100644 --- a/script/nan-spec-runner.js +++ b/script/nan-spec-runner.js @@ -65,6 +65,12 @@ async function main () { platformFlags.push(`-isysroot ${path.resolve(sdkPath, sdkToUse)}`); } + const cflags = [ + '-Wno-trigraphs', + '-fPIC', + ...platformFlags + ].join(' '); + const cxxflags = [ '-std=c++20', '-Wno-trigraphs', @@ -92,10 +98,10 @@ async function main () { if (process.platform !== 'win32') { env.CC = cc; - env.CFLAGS = cxxflags; + env.CFLAGS = cflags; env.CXX = cxx; - env.LD = ld; env.CXXFLAGS = cxxflags; + env.LD = ld; env.LDFLAGS = ldflags; } @@ -112,16 +118,16 @@ async function main () { return process.exit(buildStatus !== 0 ? buildStatus : signal); } - const { status: installStatus } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], { + const { status: installStatus, signal: installSignal } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], { env, cwd: NAN_DIR, stdio: 'inherit', shell: process.platform === 'win32' }); - if (installStatus !== 0 || signal != null) { + if (installStatus !== 0 || installSignal != null) { console.error('Failed to install nan node_modules'); - return process.exit(installStatus !== 0 ? installStatus : signal); + return process.exit(installStatus !== 0 ? installStatus : installSignal); } const onlyTests = args.only?.split(','); @@ -129,9 +135,9 @@ async function main () { const DISABLED_TESTS = new Set([ 'nannew-test.js', 'buffer-test.js', - // we can't patch this test because it uses CRLF line endings - 'methodswithdata-test.js', - // these two are incompatible with crrev.com/c/4733273 + // These two are incompatible with crrev.com/c/4733273 + // They are disabled upstream starting in "Node.js 24" (note: the incompatible change above + // landed in V8 v13.7), so we can remove them from this list once we upgrade Node.js to 24. 'weak-test.js', 'weak2-test.js' ]); diff --git a/script/node-disabled-tests.json b/script/node-disabled-tests.json index 1ffa363aaf799..4d3fbe7da1ef1 100644 --- a/script/node-disabled-tests.json +++ b/script/node-disabled-tests.json @@ -1,7 +1,7 @@ [ "abort/test-abort-backtrace", + "es-module/test-esm-wasm", "es-module/test-vm-compile-function-lineoffset", - "parallel/test-async-context-frame", "parallel/test-bootstrap-modules", "parallel/test-child-process-fork-exec-path", "parallel/test-code-cache", @@ -41,11 +41,11 @@ "parallel/test-module-loading-globalpaths", "parallel/test-module-print-timing", "parallel/test-openssl-ca-options", + "parallel/test-os-checked-function", "parallel/test-process-versions", "parallel/test-process-get-builtin", "parallel/test-repl", "parallel/test-repl-underscore", - "parallel/test-tls-securepair-leak", "parallel/test-single-executable-blob-config", "parallel/test-single-executable-blob-config-errors", "parallel/test-shadow-realm-custom-loaders", @@ -76,6 +76,7 @@ "parallel/test-snapshot-worker", "parallel/test-strace-openat-openssl", "parallel/test-sqlite-backup", + "parallel/test-max-old-space-size-percentage", "parallel/test-tls-alpn-server-client", "parallel/test-tls-cli-min-version-1.0", "parallel/test-tls-cli-max-version-1.2", @@ -118,6 +119,7 @@ "parallel/test-tls-server-failed-handshake-emits-clienterror", "parallel/test-tls-set-ciphers", "parallel/test-tls-set-ciphers-error", + "parallel/test-tls-set-default-ca-certificates-recovery", "parallel/test-tls-set-sigalgs", "parallel/test-tls-socket-allow-half-open-option", "parallel/test-tls-socket-failed-handshake-emits-error", diff --git a/script/release/notes/notes.ts b/script/release/notes/notes.ts index 2c5e97f3334ab..04a2030bd1467 100644 --- a/script/release/notes/notes.ts +++ b/script/release/notes/notes.ts @@ -684,7 +684,7 @@ function renderTrops (commit: Commit, excludeBranch: string) { .map(([branch, key]) => renderTrop(branch, key)) .join(', '); return body - ? `<span style="font-size:small;">(Also in ${body})</span>` + ? `<sup>(Also in ${body})</sup>` : body; } diff --git a/script/release/release.ts b/script/release/release.ts index 1438577fae8db..63f73126dd7ae 100755 --- a/script/release/release.ts +++ b/script/release/release.ts @@ -137,11 +137,11 @@ function assetsForVersion (version: string, validatingRelease: boolean) { `chromedriver-${version}-win32-ia32.zip`, `chromedriver-${version}-win32-x64.zip`, `chromedriver-${version}-win32-arm64.zip`, - `electron-${version}-darwin-x64-dsym.zip`, + `electron-${version}-darwin-x64-dsym.tar.xz`, `electron-${version}-darwin-x64-dsym-snapshot.zip`, `electron-${version}-darwin-x64-symbols.zip`, `electron-${version}-darwin-x64.zip`, - `electron-${version}-darwin-arm64-dsym.zip`, + `electron-${version}-darwin-arm64-dsym.tar.xz`, `electron-${version}-darwin-arm64-dsym-snapshot.zip`, `electron-${version}-darwin-arm64-symbols.zip`, `electron-${version}-darwin-arm64.zip`, @@ -152,11 +152,11 @@ function assetsForVersion (version: string, validatingRelease: boolean) { `electron-${version}-linux-x64-debug.zip`, `electron-${version}-linux-x64-symbols.zip`, `electron-${version}-linux-x64.zip`, - `electron-${version}-mas-x64-dsym.zip`, + `electron-${version}-mas-x64-dsym.tar.xz`, `electron-${version}-mas-x64-dsym-snapshot.zip`, `electron-${version}-mas-x64-symbols.zip`, `electron-${version}-mas-x64.zip`, - `electron-${version}-mas-arm64-dsym.zip`, + `electron-${version}-mas-arm64-dsym.tar.xz`, `electron-${version}-mas-arm64-dsym-snapshot.zip`, `electron-${version}-mas-arm64-symbols.zip`, `electron-${version}-mas-arm64.zip`, @@ -210,8 +210,10 @@ function assetsForVersion (version: string, validatingRelease: boolean) { const cloudStoreFilePaths = (version: string) => [ `iojs-${version}-headers.tar.gz`, `iojs-${version}.tar.gz`, + `node-${version}-headers.tar.gz`, `node-${version}.tar.gz`, 'node.lib', + 'arm64/node.lib', 'x64/node.lib', 'win-x64/iojs.lib', 'win-x86/iojs.lib', @@ -219,7 +221,6 @@ const cloudStoreFilePaths = (version: string) => [ 'win-x64/node.lib', 'win-x86/node.lib', 'win-arm64/node.lib', - 'arm64/node.lib', 'SHASUMS.txt', 'SHASUMS256.txt' ]; diff --git a/script/release/uploaders/upload-to-github.ts b/script/release/uploaders/upload-to-github.ts index b801ded782a7d..6be8147736f4c 100644 --- a/script/release/uploaders/upload-to-github.ts +++ b/script/release/uploaders/upload-to-github.ts @@ -48,7 +48,7 @@ const targetRepo = getRepo(); const uploadUrl = `https://uploads.github.com/repos/electron/${targetRepo}/releases/${releaseId}/assets{?name,label}`; let retry = 0; -const octokit = new Octokit({ +let octokit = new Octokit({ authStrategy: createGitHubTokenStrategy(targetRepo), log: console }); @@ -73,6 +73,12 @@ function uploadToGitHub () { console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err); retry++; + // Reset octokit in case it cached an auth error somehow + octokit = new Octokit({ + authStrategy: createGitHubTokenStrategy(targetRepo), + log: console + }); + octokit.repos.listReleaseAssets({ owner: ELECTRON_ORG, repo: targetRepo, @@ -98,6 +104,7 @@ function uploadToGitHub () { } }).catch((getReleaseErr) => { console.log('Fatal: Unable to get current release assets via getRelease! Error was:', getReleaseErr); + process.exitCode = 1; }); } else { console.log(`Error retrying uploading ${fileName} to GitHub:`, err); diff --git a/script/release/uploaders/upload.py b/script/release/uploaders/upload.py index c5fa934b01cd6..36b5a3dd7f670 100755 --- a/script/release/uploaders/upload.py +++ b/script/release/uploaders/upload.py @@ -16,7 +16,7 @@ from zipfile import ZipFile from lib.config import PLATFORM, get_target_arch, \ - get_zip_name, set_verbose_mode, \ + get_zip_name, get_tar_name, set_verbose_mode, \ is_verbose_mode, get_platform_key, \ verbose_mode_print from lib.util import get_electron_branding, execute, get_electron_version, \ @@ -33,7 +33,8 @@ DIST_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION) SYMBOLS_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'symbols') -DSYM_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'dsym') +# Use tar.xz compression for dsym files due to size +DSYM_NAME = get_tar_name(PROJECT_NAME, ELECTRON_VERSION, 'dsym') DSYM_SNAPSHOT_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'dsym-snapshot') PDB_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'pdb') @@ -88,7 +89,7 @@ def main(): upload_electron(release, ts_defs_path, args) dsym_zip = os.path.join(OUT_DIR, DSYM_NAME) - shutil.copy2(os.path.join(OUT_DIR, 'dsym.zip'), dsym_zip) + shutil.copy2(os.path.join(OUT_DIR, 'dsym.tar.xz'), dsym_zip) upload_electron(release, dsym_zip, args) dsym_snapshot_zip = os.path.join(OUT_DIR, DSYM_SNAPSHOT_NAME) diff --git a/script/spec-runner.js b/script/spec-runner.js index 3457fdb34a9f1..4c5e72acac0c5 100755 --- a/script/spec-runner.js +++ b/script/spec-runner.js @@ -2,6 +2,7 @@ const { ElectronVersions, Installer } = require('@electron/fiddle-core'); +const { DOMParser } = require('@xmldom/xmldom'); const chalk = require('chalk'); const { hashElement } = require('folder-hash'); const minimist = require('minimist'); @@ -21,6 +22,7 @@ const FAILURE_STATUS_KEY = 'Electron_Spec_Runner_Failures'; const args = minimist(process.argv, { string: ['runners', 'target', 'electronVersion'], + number: ['enableRerun'], unknown: arg => unknownFlags.push(arg) }); @@ -191,7 +193,160 @@ async function asyncSpawn (exe, runnerArgs) { }); } -async function runTestUsingElectron (specDir, testName) { +function parseJUnitXML (specDir) { + if (!fs.existsSync(process.env.MOCHA_FILE)) { + console.error('JUnit XML file not found:', process.env.MOCHA_FILE); + return []; + } + + const xmlContent = fs.readFileSync(process.env.MOCHA_FILE, 'utf8'); + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(xmlContent, 'text/xml'); + + const failedTests = []; + // find failed tests by looking for all testsuite nodes with failure > 0 + const testSuites = xmlDoc.getElementsByTagName('testsuite'); + for (let i = 0; i < testSuites.length; i++) { + const testSuite = testSuites[i]; + const failures = testSuite.getAttribute('failures'); + if (failures > 0) { + const testcases = testSuite.getElementsByTagName('testcase'); + + for (let i = 0; i < testcases.length; i++) { + const testcase = testcases[i]; + const failures = testcase.getElementsByTagName('failure'); + const errors = testcase.getElementsByTagName('error'); + + if (failures.length > 0 || errors.length > 0) { + const testName = testcase.getAttribute('name'); + const filePath = testSuite.getAttribute('file'); + const fileName = filePath ? path.relative(specDir, filePath) : 'unknown file'; + const failureInfo = { + name: testName, + file: fileName, + filePath + }; + if (failures.length > 0) { + failureInfo.failure = failures[0].textContent || failures[0].nodeValue || 'No failure message'; + } + + if (errors.length > 0) { + failureInfo.error = errors[0].textContent || errors[0].nodeValue || 'No error message'; + } + + failedTests.push(failureInfo); + } + } + } + } + + return failedTests; +} + +async function rerunFailedTest (specDir, testName, testInfo) { + console.log('\n========================================'); + console.log(`Rerunning failed test: ${testInfo.name} (${testInfo.file})`); + console.log('========================================'); + + let grepPattern = testInfo.name; + + // Escape special regex characters in test name + grepPattern = grepPattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + const args = []; + if (testInfo.filePath) { + args.push('--files', testInfo.filePath); + } + args.push('-g', grepPattern); + + const success = await runTestUsingElectron(specDir, testName, false, args); + + if (success) { + console.log(`✅ Test passed: ${testInfo.name}`); + return true; + } else { + console.log(`❌ Test failed again: ${testInfo.name}`); + return false; + } +} + +async function rerunFailedTests (specDir, testName) { + console.log('\n📋 Parsing JUnit XML for failed tests...'); + const failedTests = parseJUnitXML(specDir); + + if (failedTests.length === 0) { + console.log('No failed tests could be found.'); + process.exit(1); + return; + } + + // Save off the original junit xml file + if (fs.existsSync(process.env.MOCHA_FILE)) { + fs.copyFileSync(process.env.MOCHA_FILE, `${process.env.MOCHA_FILE}.save`); + } + + console.log(`\n📊 Found ${failedTests.length} failed test(s):`); + failedTests.forEach((test, index) => { + console.log(` ${index + 1}. ${test.name} (${test.file})`); + }); + + // Step 3: Rerun each failed test individually + console.log('\n🔄 Rerunning failed tests individually...\n'); + + const results = { + total: failedTests.length, + passed: 0, + failed: 0 + }; + + let index = 0; + for (const testInfo of failedTests) { + let runCount = 0; + let success = false; + let retryTest = false; + while (!success && (runCount < args.enableRerun)) { + success = await rerunFailedTest(specDir, testName, testInfo); + if (success) { + results.passed++; + } else { + if (runCount === args.enableRerun - 1) { + results.failed++; + } else { + retryTest = true; + console.log(`Retrying test (${runCount + 1}/${args.enableRerun})...`); + } + } + + // Add a small delay between tests + if (retryTest || index < failedTests.length - 1) { + console.log('\nWaiting 2 seconds before next test...'); + await new Promise(resolve => setTimeout(resolve, 2000)); + } + runCount++; + } + index++; + }; + + // Step 4: Summary + console.log('\n📈 Summary:'); + console.log(`Total failed tests: ${results.total}`); + console.log(`Passed on rerun: ${results.passed}`); + console.log(`Still failing: ${results.failed}`); + + // Restore the original junit xml file + if (fs.existsSync(`${process.env.MOCHA_FILE}.save`)) { + fs.renameSync(`${process.env.MOCHA_FILE}.save`, process.env.MOCHA_FILE); + } + + if (results.failed === 0) { + console.log('🎉 All previously failed tests now pass!'); + } else { + console.log(`⚠️ ${results.failed} test(s) are still failing`); + process.exit(1); + } +} + +async function runTestUsingElectron (specDir, testName, shouldRerun, additionalArgs = []) { let exe; if (args.electronVersion) { const installer = new Installer(); @@ -199,11 +354,16 @@ async function runTestUsingElectron (specDir, testName) { } else { exe = path.resolve(BASE, utils.getElectronExec()); } - const runnerArgs = [`electron/${specDir}`, ...unknownArgs.slice(2)]; + let argsToPass = unknownArgs.slice(2); + if (additionalArgs.includes('--files')) { + argsToPass = argsToPass.filter(arg => (arg.toString().indexOf('--files') === -1 && arg.toString().indexOf('spec/') === -1)); + } + const runnerArgs = [`electron/${specDir}`, ...argsToPass, ...additionalArgs]; if (process.platform === 'linux') { runnerArgs.unshift(path.resolve(__dirname, 'dbus_mock.py'), exe); exe = 'python3'; } + console.log(`Running: ${exe} ${runnerArgs.join(' ')}`); const { status, signal } = await asyncSpawn(exe, runnerArgs); if (status !== 0) { if (status) { @@ -212,13 +372,22 @@ async function runTestUsingElectron (specDir, testName) { } else { console.log(`${fail} Electron tests failed with kill signal ${signal}.`); } - process.exit(1); + if (shouldRerun) { + await rerunFailedTests(specDir, testName); + } else { + return false; + } } console.log(`${pass} Electron ${testName} process tests passed.`); + return true; } async function runMainProcessElectronTests () { - await runTestUsingElectron('spec', 'main'); + let shouldRerun = false; + if (args.enableRerun && args.enableRerun > 0) { + shouldRerun = true; + } + await runTestUsingElectron('spec', 'main', shouldRerun); } async function installSpecModules (dir) { diff --git a/script/start.js b/script/start.js index 4f158e3f931f2..b4c5b127a29aa 100644 --- a/script/start.js +++ b/script/start.js @@ -5,11 +5,15 @@ const utils = require('./lib/utils'); const electronPath = utils.getAbsoluteElectronExec(); const child = cp.spawn(electronPath, process.argv.slice(2), { stdio: 'inherit' }); -child.on('close', (code) => process.exit(code)); +let childClosed = false; +child.on('close', (code) => { + childClosed = true; + process.exit(code); +}); const handleTerminationSignal = (signal) => process.on(signal, () => { - if (!child.killed) { + if (!childClosed) { child.kill(signal); } }); diff --git a/script/zip-symbols.py b/script/zip-symbols.py index 2b365566b386c..45635a1fdcdbf 100755 --- a/script/zip-symbols.py +++ b/script/zip-symbols.py @@ -6,7 +6,7 @@ import sys from lib.config import PLATFORM -from lib.util import scoped_cwd, get_electron_version, make_zip, \ +from lib.util import scoped_cwd, get_electron_version, make_zip, make_tar_xz, \ get_electron_branding, get_out_dir, execute ELECTRON_VERSION = get_electron_version() @@ -27,16 +27,15 @@ def main(): make_zip(zip_file, licenses, dirs) if PLATFORM == 'darwin': - dsym_name = 'dsym.zip' + dsym_name = 'dsym.tar.xz' with scoped_cwd(args.build_dir): dsyms = glob.glob('*.dSYM') snapshot_dsyms = ['v8_context_snapshot_generator.dSYM'] for dsym in snapshot_dsyms: if (dsym in dsyms): dsyms.remove(dsym) - dsym_zip_file = os.path.join(args.build_dir, dsym_name) - print('Making dsym zip: ' + dsym_zip_file) - make_zip(dsym_zip_file, licenses, dsyms) + dsym_tar_file = os.path.join(args.build_dir, dsym_name) + make_tar_xz(dsym_tar_file, licenses, dsyms) dsym_snapshot_name = 'dsym-snapshot.zip' dsym_snapshot_zip_file = os.path.join(args.build_dir, dsym_snapshot_name) print('Making dsym snapshot zip: ' + dsym_snapshot_zip_file) diff --git a/script/zip_manifests/dist_zip.win.arm64.manifest b/script/zip_manifests/dist_zip.win.arm64.manifest index 5d8deb41a53b8..fc2445e8885c9 100644 --- a/script/zip_manifests/dist_zip.win.arm64.manifest +++ b/script/zip_manifests/dist_zip.win.arm64.manifest @@ -8,6 +8,8 @@ ffmpeg.dll icudtl.dat libEGL.dll libGLESv2.dll +dxil.dll +dxcompiler.dll locales/af.pak locales/am.pak locales/ar.pak diff --git a/script/zip_manifests/dist_zip.win.x64.manifest b/script/zip_manifests/dist_zip.win.x64.manifest index 5d8deb41a53b8..fc2445e8885c9 100644 --- a/script/zip_manifests/dist_zip.win.x64.manifest +++ b/script/zip_manifests/dist_zip.win.x64.manifest @@ -8,6 +8,8 @@ ffmpeg.dll icudtl.dat libEGL.dll libGLESv2.dll +dxil.dll +dxcompiler.dll locales/af.pak locales/am.pak locales/ar.pak diff --git a/shell/app/electron_content_client.cc b/shell/app/electron_content_client.cc index c5740f769b353..e6fb2f3f7b315 100644 --- a/shell/app/electron_content_client.cc +++ b/shell/app/electron_content_client.cc @@ -13,7 +13,6 @@ #include "base/files/file_util.h" #include "base/strings/string_split.h" #include "content/public/common/buildflags.h" -#include "content/public/common/content_constants.h" #include "electron/buildflags/buildflags.h" #include "electron/fuses.h" #include "extensions/common/constants.h" @@ -37,7 +36,7 @@ #endif // BUILDFLAG(ENABLE_PDF_VIEWER) #if BUILDFLAG(ENABLE_PLUGINS) -#include "content/public/common/content_plugin_info.h" +#include "content/public/common/webplugininfo.h" #endif // BUILDFLAG(ENABLE_PLUGINS) namespace electron { @@ -162,21 +161,25 @@ void ElectronContentClient::AddAdditionalSchemes(Schemes* schemes) { } void ElectronContentClient::AddPlugins( - std::vector<content::ContentPluginInfo>* plugins) { + std::vector<content::WebPluginInfo>* plugins) { #if BUILDFLAG(ENABLE_PDF_VIEWER) + static constexpr char16_t kPDFPluginName[] = u"Chromium PDF Plugin"; + static constexpr char16_t kPDFPluginDescription[] = u"Built-in PDF viewer"; static constexpr char kPDFPluginExtension[] = "pdf"; - static constexpr char kPDFPluginDescription[] = "Portable Document Format"; + static constexpr char kPDFPluginExtensionDescription[] = + "Portable Document Format"; - content::ContentPluginInfo pdf_info; - pdf_info.is_internal = true; - pdf_info.name = kPDFInternalPluginName; - pdf_info.description = kPDFPluginDescription; + content::WebPluginInfo pdf_info; + pdf_info.name = kPDFPluginName; // This isn't a real file path; it's just used as a unique identifier. static constexpr std::string_view kPdfPluginPath = "internal-pdf-viewer"; pdf_info.path = base::FilePath::FromASCII(kPdfPluginPath); - content::WebPluginMimeType pdf_mime_type( - pdf::kInternalPluginMimeType, kPDFPluginExtension, kPDFPluginDescription); + pdf_info.desc = kPDFPluginDescription; + content::WebPluginMimeType pdf_mime_type(pdf::kInternalPluginMimeType, + kPDFPluginExtension, + kPDFPluginExtensionDescription); pdf_info.mime_types.push_back(pdf_mime_type); + pdf_info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_INTERNAL_PLUGIN; plugins->push_back(pdf_info); #endif // BUILDFLAG(ENABLE_PDF_VIEWER) } diff --git a/shell/app/electron_content_client.h b/shell/app/electron_content_client.h index ffaab188bcfcf..f833881b77b86 100644 --- a/shell/app/electron_content_client.h +++ b/shell/app/electron_content_client.h @@ -29,7 +29,7 @@ class ElectronContentClient : public content::ContentClient { gfx::Image& GetNativeImageNamed(int resource_id) override; base::RefCountedMemory* GetDataResourceBytes(int resource_id) override; void AddAdditionalSchemes(Schemes* schemes) override; - void AddPlugins(std::vector<content::ContentPluginInfo>* plugins) override; + void AddPlugins(std::vector<content::WebPluginInfo>* plugins) override; void AddContentDecryptionModules( std::vector<content::CdmInfo>* cdms, std::vector<media::CdmHostFilePath>* cdm_host_file_paths) override; diff --git a/shell/app/electron_main_delegate.cc b/shell/app/electron_main_delegate.cc index e4ba443e43b46..2339136712a35 100644 --- a/shell/app/electron_main_delegate.cc +++ b/shell/app/electron_main_delegate.cc @@ -13,10 +13,12 @@ #include "base/apple/bundle_locations.h" #include "base/base_switches.h" #include "base/command_line.h" +#include "base/debug/leak_annotations.h" #include "base/debug/stack_trace.h" #include "base/environment.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/metrics/field_trial.h" #include "base/path_service.h" #include "base/strings/cstring_view.h" #include "base/strings/string_number_conversions.cc" @@ -419,6 +421,11 @@ std::optional<int> ElectronMainDelegate::PreBrowserMain() { // This is initialized early because the service manager reads some feature // flags and we need to make sure the feature list is initialized before the // service manager reads the features. + if (!base::FieldTrialList::GetInstance()) { + base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList(); + ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); + std::ignore = leaked_field_trial_list; + } InitializeFeatureList(); // Initialize mojo core as soon as we have a valid feature list content::InitializeMojoCore(); diff --git a/shell/app/node_main.cc b/shell/app/node_main.cc index ddc61c0257631..7cd0a71eea8e8 100644 --- a/shell/app/node_main.cc +++ b/shell/app/node_main.cc @@ -35,6 +35,8 @@ #include "shell/common/node_bindings.h" #include "shell/common/node_includes.h" #include "shell/common/node_util.h" +#include "shell/common/options_switches.h" +#include "shell/common/platform_util.h" #if BUILDFLAG(IS_WIN) #include "chrome/child/v8_crashpad_support_win.h" @@ -153,9 +155,10 @@ int NodeMain() { v8_crashpad_support::SetUp(); #endif + auto* command_line = base::CommandLine::ForCurrentProcess(); + #if BUILDFLAG(IS_LINUX) int pid = -1; - auto* command_line = base::CommandLine::ForCurrentProcess(); std::optional<std::string> fd_string = os_env->GetVar("CRASHDUMP_SIGNAL_FD"); std::optional<std::string> pid_string = os_env->GetVar("CRASHPAD_HANDLER_PID"); @@ -189,14 +192,32 @@ int NodeMain() { NodeBindings::RegisterBuiltinBindings(); // Parse Node.js cli flags and strip out disallowed options. - const std::vector<std::string> args = ElectronCommandLine::AsUtf8(); + std::vector<std::string> args = ElectronCommandLine::AsUtf8(); ExitIfContainsDisallowedFlags(args); + uint64_t process_flags = + node::ProcessInitializationFlags::kNoInitializeV8 | + node::ProcessInitializationFlags::kNoInitializeNodeV8Platform; + + if (command_line->HasSwitch(switches::kNoStdioInit)) { + process_flags |= node::ProcessInitializationFlags::kNoStdioInitialization; + // remove the option to avoid node error "bad option: --no-stdio-init" + std::string option = std::string("--") + switches::kNoStdioInit; + std::erase(args, option); + } else { +#if BUILDFLAG(IS_WIN) + if (!platform_util::IsNulDeviceEnabled()) { + LOG(FATAL) << "Unable to open nul device needed for initialization," + "aborting startup. As a workaround, try starting with --" + << switches::kNoStdioInit; + } +#endif + } + std::shared_ptr<node::InitializationResult> result = node::InitializeOncePerProcess( - args, - {node::ProcessInitializationFlags::kNoInitializeV8, - node::ProcessInitializationFlags::kNoInitializeNodeV8Platform}); + args, static_cast<node::ProcessInitializationFlags::Flags>( + process_flags)); for (const std::string& error : result->errors()) std::cerr << args[0] << ": " << error << '\n'; diff --git a/shell/browser/api/electron_api_app.cc b/shell/browser/api/electron_api_app.cc index 2db351326ab68..b5cfbd2368178 100644 --- a/shell/browser/api/electron_api_app.cc +++ b/shell/browser/api/electron_api_app.cc @@ -62,6 +62,7 @@ #include "shell/browser/net/resolve_proxy_helper.h" #include "shell/browser/relauncher.h" #include "shell/common/application_info.h" +#include "shell/common/callback_util.h" #include "shell/common/electron_command_line.h" #include "shell/common/electron_paths.h" #include "shell/common/gin_converters/base_converter.h" @@ -369,9 +370,6 @@ namespace electron::api { gin::WrapperInfo App::kWrapperInfo = {{gin::kEmbedderNativeGin}, gin::kElectronApp}; -// static -cppgc::Persistent<App> App::instance_; - namespace { IconLoader::IconSize GetIconSizeByString(const std::string& size) { @@ -458,10 +456,10 @@ void GotPrivateKey(std::shared_ptr<content::ClientCertificateDelegate> delegate, } void OnClientCertificateSelected( - v8::Isolate* isolate, + v8::Isolate* const isolate, std::shared_ptr<content::ClientCertificateDelegate> delegate, std::shared_ptr<net::ClientCertIdentityList> identities, - gin::Arguments* args) { + gin::Arguments* const args) { if (args->Length() == 2) { delegate->ContinueWithCertificate(nullptr, nullptr); return; @@ -476,8 +474,7 @@ void OnClientCertificateSelected( gin_helper::Dictionary cert_data; if (!gin::ConvertFromV8(isolate, val, &cert_data)) { - gin_helper::ErrorThrower(isolate).ThrowError( - "Must pass valid certificate object."); + args->ThrowTypeError("Must pass valid certificate object."); return; } @@ -739,7 +736,8 @@ void App::AllowCertificateError( bool is_main_frame_request, bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> callback) { - auto adapted_callback = base::AdaptCallbackForRepeating(std::move(callback)); + auto adapted_callback = + electron::AdaptCallbackForRepeating(std::move(callback)); v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); v8::HandleScope handle_scope(isolate); bool prevent_default = Emit( @@ -874,28 +872,33 @@ void App::SetAppPath(const base::FilePath& app_path) { app_path_ = app_path; } +void App::SetAppLogsPath(gin::Arguments* const args) { + base::FilePath path; + + // if caller provided a path, it must be absolute + if (args->GetNext(&path) && !path.IsAbsolute()) { + args->ThrowTypeError("Path must be absolute"); + return; + } + + // if caller did not provide a path, then use a default one + if (path.empty()) { + path = GetDefaultAppLogPath(); + } + + ScopedAllowBlockingForElectron allow_blocking; + base::PathService::Override(DIR_APP_LOGS, path); +} + #if !BUILDFLAG(IS_MAC) -void App::SetAppLogsPath(gin_helper::ErrorThrower thrower, - std::optional<base::FilePath> custom_path) { - if (custom_path.has_value()) { - if (!custom_path->IsAbsolute()) { - thrower.ThrowError("Path must be absolute"); - return; - } - { - ScopedAllowBlockingForElectron allow_blocking; - base::PathService::Override(DIR_APP_LOGS, custom_path.value()); - } - } else { - base::FilePath path; - if (base::PathService::Get(chrome::DIR_USER_DATA, &path)) { - path = path.Append(base::FilePath::FromUTF8Unsafe("logs")); - { - ScopedAllowBlockingForElectron allow_blocking; - base::PathService::Override(DIR_APP_LOGS, path); - } - } +// static +// default to `${DIR_USER_DATA}/logs` +base::FilePath App::GetDefaultAppLogPath() { + base::FilePath path; + if (base::PathService::Get(chrome::DIR_USER_DATA, &path)) { + path = path.Append(base::FilePath::FromUTF8Unsafe("logs")); } + return path; } #endif @@ -1139,6 +1142,10 @@ void App::DisableHardwareAcceleration(gin_helper::ErrorThrower thrower) { "before app is ready"); return; } + + // If the GpuDataManager is already initialized, disable hardware + // acceleration immediately. Otherwise, set a flag to disable it in + // OnPreCreateThreads(). if (content::GpuDataManager::Initialized()) { content::GpuDataManager::GetInstance()->DisableHardwareAcceleration(); } else { @@ -1146,6 +1153,13 @@ void App::DisableHardwareAcceleration(gin_helper::ErrorThrower thrower) { } } +bool App::IsHardwareAccelerationEnabled() { + if (content::GpuDataManager::Initialized()) + return content::GpuDataManager::GetInstance() + ->HardwareAccelerationEnabled(); + return !disable_hw_acceleration_; +} + void App::DisableDomainBlockingFor3DAPIs(gin_helper::ErrorThrower thrower) { if (Browser::Get()->is_ready()) { thrower.ThrowError( @@ -1167,6 +1181,86 @@ bool App::IsAccessibilitySupportEnabled() { return mode.has_mode(ui::kAXModeComplete.flags()); } +v8::Local<v8::Value> App::GetAccessibilitySupportFeatures() { + v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); + v8::EscapableHandleScope handle_scope(isolate); + auto* ax_state = content::BrowserAccessibilityState::GetInstance(); + ui::AXMode mode = ax_state->GetAccessibilityMode(); + + std::vector<v8::Local<v8::Value>> features; + auto push = [&](const char* name) { + features.push_back(v8::String::NewFromUtf8(isolate, name).ToLocalChecked()); + }; + + if (mode.has_mode(ui::AXMode::kNativeAPIs)) + push("nativeAPIs"); + if (mode.has_mode(ui::AXMode::kWebContents)) + push("webContents"); + if (mode.has_mode(ui::AXMode::kInlineTextBoxes)) + push("inlineTextBoxes"); + if (mode.has_mode(ui::AXMode::kExtendedProperties)) + push("extendedProperties"); + if (mode.has_mode(ui::AXMode::kHTML)) + push("html"); + if (mode.has_mode(ui::AXMode::kLabelImages)) + push("labelImages"); + if (mode.has_mode(ui::AXMode::kPDFPrinting)) + push("pdfPrinting"); + if (mode.has_mode(ui::AXMode::kScreenReader)) + push("screenReader"); + + v8::Local<v8::Array> arr = v8::Array::New(isolate, features.size()); + for (uint32_t i = 0; i < features.size(); ++i) { + arr->Set(isolate->GetCurrentContext(), i, features[i]).Check(); + } + return handle_scope.Escape(arr); +} + +void App::SetAccessibilitySupportFeatures( + gin_helper::ErrorThrower thrower, + const std::vector<std::string>& features) { + if (!Browser::Get()->is_ready()) { + thrower.ThrowError( + "app.setAccessibilitySupportFeatures() can only be called after app " + "is ready"); + return; + } + + ui::AXMode mode; + for (const auto& f : features) { + if (f == "nativeAPIs") { + mode.set_mode(ui::AXMode::kNativeAPIs, true); + } else if (f == "webContents") { + mode.set_mode(ui::AXMode::kWebContents, true); + } else if (f == "inlineTextBoxes") { + mode.set_mode(ui::AXMode::kInlineTextBoxes, true); + } else if (f == "extendedProperties") { + mode.set_mode(ui::AXMode::kExtendedProperties, true); + } else if (f == "screenReader") { + mode.set_mode(ui::AXMode::kScreenReader, true); + } else if (f == "html") { + mode.set_mode(ui::AXMode::kHTML, true); + } else if (f == "labelImages") { + mode.set_mode(ui::AXMode::kLabelImages, true); + } else if (f == "pdfPrinting") { + mode.set_mode(ui::AXMode::kPDFPrinting, true); + } else { + thrower.ThrowError("Unknown accessibility feature: " + f); + return; + } + } + + if (mode.is_mode_off()) { + scoped_accessibility_mode_.reset(); + } else { + scoped_accessibility_mode_ = + content::BrowserAccessibilityState::GetInstance() + ->CreateScopedModeForProcess(mode); + } + + Browser::Get()->OnAccessibilitySupportChanged(); +} + void App::SetAccessibilitySupportEnabled(gin_helper::ErrorThrower thrower, bool enabled) { if (!Browser::Get()->is_ready()) { @@ -1244,14 +1338,13 @@ v8::Local<v8::Value> App::GetJumpListSettings() { return dict.GetHandle(); } -JumpListResult App::SetJumpList(v8::Local<v8::Value> val, - gin::Arguments* args) { +JumpListResult App::SetJumpList(v8::Isolate* const isolate, + v8::Local<v8::Value> val) { std::vector<JumpListCategory> categories; bool delete_jump_list = val->IsNull(); - if (!delete_jump_list && - !gin::ConvertFromV8(args->isolate(), val, &categories)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError("Argument must be null or an array of categories"); + if (!delete_jump_list && !gin::ConvertFromV8(isolate, val, &categories)) { + gin_helper::ErrorThrower{isolate}.ThrowTypeError( + "Argument must be null or an array of categories"); return JumpListResult::kArgumentError; } @@ -1696,22 +1789,21 @@ void ConfigureHostResolver(v8::Isolate* isolate, // NetworkContext is created, but before anything has the chance to use it. content::GetNetworkService()->ConfigureStubHostResolver( enable_built_in_resolver, enable_happy_eyeballs_v3, secure_dns_mode, - doh_config, additional_dns_query_types_enabled); + doh_config, additional_dns_query_types_enabled, + {} /*fallback_doh_nameservers*/); } // static App* App::Get() { - CHECK_NE(instance_, nullptr); - return instance_.Get(); + return Create(nullptr); } // static App* App::Create(v8::Isolate* isolate) { - if (!instance_) { - instance_ = cppgc::MakeGarbageCollected<App>( - isolate->GetCppHeap()->GetAllocationHandle()); - } - return instance_.Get(); + static base::NoDestructor<cppgc::Persistent<App>> instance( + cppgc::MakeGarbageCollected<App>( + isolate->GetCppHeap()->GetAllocationHandle())); + return instance->Get(); } const gin::WrapperInfo* App::wrapper_info() const { @@ -1840,10 +1932,16 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) { .SetMethod("relaunch", &App::Relaunch) .SetMethod("isAccessibilitySupportEnabled", &App::IsAccessibilitySupportEnabled) + .SetMethod("getAccessibilitySupportFeatures", + &App::GetAccessibilitySupportFeatures) + .SetMethod("setAccessibilitySupportFeatures", + &App::SetAccessibilitySupportFeatures) .SetMethod("setAccessibilitySupportEnabled", &App::SetAccessibilitySupportEnabled) .SetMethod("disableHardwareAcceleration", &App::DisableHardwareAcceleration) + .SetMethod("isHardwareAccelerationEnabled", + &App::IsHardwareAccelerationEnabled) .SetMethod("disableDomainBlockingFor3DAPIs", &App::DisableDomainBlockingFor3DAPIs) .SetMethod("getFileIcon", &App::GetFileIcon) diff --git a/shell/browser/api/electron_api_app.h b/shell/browser/api/electron_api_app.h index dad2ed76a81ac..fd0565b51c9d3 100644 --- a/shell/browser/api/electron_api_app.h +++ b/shell/browser/api/electron_api_app.h @@ -178,6 +178,8 @@ class App final : public gin::Wrappable<App>, const content::ChildProcessTerminationInfo& info) override; private: + [[nodiscard]] static base::FilePath GetDefaultAppLogPath(); + void BrowserChildProcessCrashedOrKilled( const content::ChildProcessData& data, const content::ChildProcessTerminationInfo& info); @@ -190,8 +192,7 @@ class App final : public gin::Wrappable<App>, const std::string& name = std::string()); void ChildProcessDisconnected(content::ChildProcessId pid); - void SetAppLogsPath(gin_helper::ErrorThrower thrower, - std::optional<base::FilePath> custom_path); + void SetAppLogsPath(gin::Arguments* args); // Get/Set the pre-defined path in PathService. base::FilePath GetPath(gin_helper::ErrorThrower thrower, @@ -212,8 +213,13 @@ class App final : public gin::Wrappable<App>, void ReleaseSingleInstanceLock(); bool Relaunch(gin::Arguments* args); void DisableHardwareAcceleration(gin_helper::ErrorThrower thrower); + bool IsHardwareAccelerationEnabled(); void DisableDomainBlockingFor3DAPIs(gin_helper::ErrorThrower thrower); bool IsAccessibilitySupportEnabled(); + v8::Local<v8::Value> GetAccessibilitySupportFeatures(); + void SetAccessibilitySupportFeatures( + gin_helper::ErrorThrower thrower, + const std::vector<std::string>& features); void SetAccessibilitySupportEnabled(gin_helper::ErrorThrower thrower, bool enabled); v8::Local<v8::Value> GetLoginItemSettings(gin::Arguments* args); @@ -258,7 +264,7 @@ class App final : public gin::Wrappable<App>, v8::Local<v8::Value> GetJumpListSettings(); // Set or remove a custom Jump List for the application. - JumpListResult SetJumpList(v8::Local<v8::Value> val, gin::Arguments* args); + JumpListResult SetJumpList(v8::Isolate* isolate, v8::Local<v8::Value> val); #endif // BUILDFLAG(IS_WIN) std::unique_ptr<ProcessSingleton> process_singleton_; @@ -282,8 +288,6 @@ class App final : public gin::Wrappable<App>, bool watch_singleton_socket_on_ready_ = false; std::unique_ptr<content::ScopedAccessibilityMode> scoped_accessibility_mode_; - - static cppgc::Persistent<App> instance_; }; } // namespace api diff --git a/shell/browser/api/electron_api_app_mac.mm b/shell/browser/api/electron_api_app_mac.mm index 37bf73426a542..b7d9228a121d2 100644 --- a/shell/browser/api/electron_api_app_mac.mm +++ b/shell/browser/api/electron_api_app_mac.mm @@ -17,30 +17,14 @@ namespace electron::api { -void App::SetAppLogsPath(gin_helper::ErrorThrower thrower, - std::optional<base::FilePath> custom_path) { - if (custom_path.has_value()) { - if (!custom_path->IsAbsolute()) { - thrower.ThrowError("Path must be absolute"); - return; - } - { - ScopedAllowBlockingForElectron allow_blocking; - base::PathService::Override(DIR_APP_LOGS, custom_path.value()); - } - } else { - NSString* bundle_name = - [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - NSString* logs_path = - [NSString stringWithFormat:@"Library/Logs/%@", bundle_name]; - NSString* library_path = - [NSHomeDirectory() stringByAppendingPathComponent:logs_path]; - { - ScopedAllowBlockingForElectron allow_blocking; - base::PathService::Override(DIR_APP_LOGS, - base::FilePath([library_path UTF8String])); - } - } +base::FilePath App::GetDefaultAppLogPath() { + NSString* bundle_name = + [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + NSString* logs_path = + [NSString stringWithFormat:@"Library/Logs/%@", bundle_name]; + NSString* library_path = + [NSHomeDirectory() stringByAppendingPathComponent:logs_path]; + return base::FilePath{[library_path UTF8String]}; } void App::SetActivationPolicy(gin_helper::ErrorThrower thrower, diff --git a/shell/browser/api/electron_api_base_window.cc b/shell/browser/api/electron_api_base_window.cc index b362c47a221c3..9441ecffc2671 100644 --- a/shell/browser/api/electron_api_base_window.cc +++ b/shell/browser/api/electron_api_base_window.cc @@ -10,15 +10,20 @@ #include <vector> #include "base/task/single_thread_task_runner.h" +#include "components/prefs/scoped_user_pref_update.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" #include "shell/browser/api/electron_api_view.h" #include "shell/browser/api/electron_api_web_contents.h" +#include "shell/browser/browser_process_impl.h" +#include "shell/browser/electron_browser_main_parts.h" #include "shell/browser/javascript_environment.h" #include "shell/browser/native_window.h" +#include "shell/browser/window_list.h" #include "shell/common/color_util.h" +#include "shell/common/electron_constants.h" #include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_converters/gfx_converter.h" @@ -39,11 +44,13 @@ #endif #if BUILDFLAG(IS_WIN) +#include <variant> #include "shell/browser/ui/views/win_frame_view.h" #include "shell/browser/ui/win/taskbar_host.h" #include "ui/base/win/shell.h" #elif BUILDFLAG(IS_LINUX) #include "shell/browser/ui/views/opaque_frame_view.h" +#include "ui/gfx/image/image_skia.h" #endif #if BUILDFLAG(IS_WIN) @@ -123,7 +130,7 @@ BaseWindow::BaseWindow(v8::Isolate* isolate, #endif } -BaseWindow::BaseWindow(gin_helper::Arguments* args, +BaseWindow::BaseWindow(gin::Arguments* args, const gin_helper::Dictionary& options) : BaseWindow(args->isolate(), options) { InitWithArgs(args); @@ -178,7 +185,7 @@ void BaseWindow::OnWindowClosed() { // We can not call Destroy here because we need to call Emit first, but we // also do not want any method to be used, so just mark as destroyed here. MarkDestroyed(); - + window_->FlushWindowState(); Emit("closed"); RemoveFromParentChildWindows(); @@ -269,6 +276,7 @@ void BaseWindow::OnWindowWillResize(const gfx::Rect& new_bounds, } void BaseWindow::OnWindowResize() { + window_->DebouncedSaveWindowState(); Emit("resize"); } @@ -284,6 +292,7 @@ void BaseWindow::OnWindowWillMove(const gfx::Rect& new_bounds, } void BaseWindow::OnWindowMove() { + window_->DebouncedSaveWindowState(); Emit("move"); } @@ -346,6 +355,10 @@ void BaseWindow::OnSystemContextMenu(int x, int y, bool* prevent_default) { } } +void BaseWindow::OnWindowStateRestored() { + EmitEventSoon("restored-persisted-state"); +} + #if BUILDFLAG(IS_WIN) void BaseWindow::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { if (IsWindowMessageHooked(message)) { @@ -444,7 +457,7 @@ bool BaseWindow::IsFullscreen() const { } void BaseWindow::SetBounds(const gfx::Rect& bounds, - gin_helper::Arguments* args) { + gin::Arguments* const args) { bool animate = false; args->GetNext(&animate); window_->SetBounds(bounds, animate); @@ -463,7 +476,7 @@ gfx::Rect BaseWindow::GetNormalBounds() const { } void BaseWindow::SetContentBounds(const gfx::Rect& bounds, - gin_helper::Arguments* args) { + gin::Arguments* const args) { bool animate = false; args->GetNext(&animate); window_->SetContentBounds(bounds, animate); @@ -473,7 +486,7 @@ gfx::Rect BaseWindow::GetContentBounds() const { return window_->GetContentBounds(); } -void BaseWindow::SetSize(int width, int height, gin_helper::Arguments* args) { +void BaseWindow::SetSize(int width, int height, gin::Arguments* args) { bool animate = false; gfx::Size size = window_->GetMinimumSize(); size.SetToMax(gfx::Size(width, height)); @@ -485,12 +498,12 @@ std::array<int, 2U> BaseWindow::GetSize() const { return ToArray(window_->GetSize()); } -void BaseWindow::SetContentSize(int width, - int height, - gin_helper::Arguments* args) { +void BaseWindow::SetContentSize(const int width, + const int height, + gin::Arguments* const args) { bool animate = false; args->GetNext(&animate); - window_->SetContentSize(gfx::Size(width, height), animate); + window_->SetContentSize(gfx::Size{width, height}, animate); } std::array<int, 2U> BaseWindow::GetContentSize() const { @@ -513,7 +526,8 @@ std::array<int, 2U> BaseWindow::GetMaximumSize() const { return ToArray(window_->GetMaximumSize()); } -void BaseWindow::SetSheetOffset(double offsetY, gin_helper::Arguments* args) { +void BaseWindow::SetSheetOffset(const double offsetY, + gin::Arguments* const args) { double offsetX = 0.0; args->GetNext(&offsetX); window_->SetSheetOffset(offsetX, offsetY); @@ -567,7 +581,7 @@ bool BaseWindow::IsClosable() const { return window_->IsClosable(); } -void BaseWindow::SetAlwaysOnTop(bool top, gin_helper::Arguments* args) { +void BaseWindow::SetAlwaysOnTop(bool top, gin::Arguments* args) { std::string level = "floating"; int relative_level = 0; args->GetNext(&level); @@ -586,19 +600,21 @@ void BaseWindow::Center() { window_->Center(); } -void BaseWindow::SetPosition(int x, int y, gin_helper::Arguments* args) { +void BaseWindow::SetPosition(const int x, + const int y, + gin::Arguments* const args) { bool animate = false; args->GetNext(&animate); - window_->SetPosition(gfx::Point(x, y), animate); + window_->SetPosition(gfx::Point{x, y}, animate); } std::array<int, 2U> BaseWindow::GetPosition() const { return ToArray(window_->GetPosition()); } void BaseWindow::MoveAbove(const std::string& sourceId, - gin_helper::Arguments* args) { + gin::Arguments* const args) { if (!window_->MoveAbove(sourceId)) - args->ThrowError("Invalid media source id"); + args->ThrowTypeError("Invalid media source id"); } void BaseWindow::MoveTop() { @@ -706,8 +722,7 @@ bool BaseWindow::IsDocumentEdited() const { return window_->IsDocumentEdited(); } -void BaseWindow::SetIgnoreMouseEvents(bool ignore, - gin_helper::Arguments* args) { +void BaseWindow::SetIgnoreMouseEvents(bool ignore, gin::Arguments* const args) { gin_helper::Dictionary options; bool forward = false; args->GetNext(&options) && options.Get("forward", &forward); @@ -759,9 +774,9 @@ void BaseWindow::RemoveMenu() { } void BaseWindow::SetParentWindow(v8::Local<v8::Value> value, - gin_helper::Arguments* args) { + gin::Arguments* const args) { if (IsModal()) { - args->ThrowError("Can not be called for modal window"); + args->ThrowTypeError("Can not be called for modal window"); return; } @@ -776,7 +791,7 @@ void BaseWindow::SetParentWindow(v8::Local<v8::Value> value, window_->SetParentWindow(parent->window_.get()); parent->child_windows_.Set(isolate(), weak_map_id(), GetWrapper()); } else { - args->ThrowError("Must pass BaseWindow instance or null"); + args->ThrowTypeError("Must pass BaseWindow instance or null"); } } @@ -794,7 +809,7 @@ v8::Local<v8::Value> BaseWindow::GetNativeWindowHandle() { } #endif -void BaseWindow::SetProgressBar(double progress, gin_helper::Arguments* args) { +void BaseWindow::SetProgressBar(double progress, gin::Arguments* args) { gin_helper::Dictionary options; std::string mode; args->GetNext(&options) && options.Get("mode", &mode); @@ -818,7 +833,7 @@ void BaseWindow::SetOverlayIcon(const gfx::Image& overlay, } void BaseWindow::SetVisibleOnAllWorkspaces(bool visible, - gin_helper::Arguments* args) { + gin::Arguments* const args) { gin_helper::Dictionary options; bool visibleOnFullScreen = false; bool skipTransformProcessType = false; @@ -838,9 +853,9 @@ void BaseWindow::SetAutoHideCursor(bool auto_hide) { window_->SetAutoHideCursor(auto_hide); } -void BaseWindow::SetVibrancy(v8::Isolate* isolate, +void BaseWindow::SetVibrancy(v8::Isolate* const isolate, v8::Local<v8::Value> value, - gin_helper::Arguments* args) { + gin::Arguments* const args) { std::string type = gin::V8ToString(isolate, value); gin_helper::Dictionary options; int animation_duration_ms = 0; @@ -925,10 +940,11 @@ void BaseWindow::ToggleTabBar() { window_->ToggleTabBar(); } -void BaseWindow::AddTabbedWindow(NativeWindow* window, - gin_helper::Arguments* args) { +void BaseWindow::AddTabbedWindow(NativeWindow* const window, + gin::Arguments* const args) { if (!window_->AddTabbedWindow(window)) - args->ThrowError("AddTabbedWindow cannot be called by a window on itself."); + args->ThrowTypeError( + "AddTabbedWindow cannot be called by a window on itself."); } v8::Local<v8::Value> BaseWindow::GetTabbingIdentifier() { @@ -955,15 +971,15 @@ bool BaseWindow::IsMenuBarVisible() const { return window_->IsMenuBarVisible(); } -void BaseWindow::SetAspectRatio(double aspect_ratio, - gin_helper::Arguments* args) { +void BaseWindow::SetAspectRatio(const double aspect_ratio, + gin::Arguments* const args) { gfx::Size extra_size; args->GetNext(&extra_size); window_->SetAspectRatio(aspect_ratio, extra_size); } void BaseWindow::PreviewFile(const std::string& path, - gin_helper::Arguments* args) { + gin::Arguments* const args) { std::string display_name; if (!args->GetNext(&display_name)) display_name = path; @@ -1000,7 +1016,7 @@ bool BaseWindow::IsModal() const { return window_->is_modal(); } -bool BaseWindow::SetThumbarButtons(gin_helper::Arguments* args) { +bool BaseWindow::SetThumbarButtons(gin::Arguments* args) { #if BUILDFLAG(IS_WIN) std::vector<TaskbarHost::ThumbarButton> buttons; if (!args->GetNext(&buttons)) { @@ -1092,22 +1108,35 @@ bool BaseWindow::IsSnapped() const { return window_->IsSnapped(); } -void BaseWindow::SetAccentColor(gin_helper::Arguments* args) { - bool accent_color = false; - std::string accent_color_string; - if (args->GetNext(&accent_color_string)) { - std::optional<SkColor> maybe_color = ParseCSSColor(accent_color_string); - if (maybe_color.has_value()) { - window_->SetAccentColor(maybe_color.value()); +void BaseWindow::SetAccentColor(gin::Arguments* const args) { + v8::Local<v8::Value> ac_val; + args->GetNext(&ac_val); + + if (!ac_val.IsEmpty() && ac_val->IsNull()) { + window_->SetAccentColor(std::monostate{}); + window_->UpdateWindowAccentColor(window_->IsActive()); + return; + } + + if (!ac_val.IsEmpty() && ac_val->IsBoolean()) { + const bool ac_flag = ac_val->BooleanValue(args->isolate()); + window_->SetAccentColor(ac_flag); + window_->UpdateWindowAccentColor(window_->IsActive()); + return; + } + + if (!ac_val.IsEmpty() && ac_val->IsString()) { + std::string ac_str; + gin::ConvertFromV8(args->isolate(), ac_val, &ac_str); + if (const std::optional<SkColor> ac_color = ParseCSSColor(ac_str)) { + window_->SetAccentColor(*ac_color); window_->UpdateWindowAccentColor(window_->IsActive()); } - } else if (args->GetNext(&accent_color)) { - window_->SetAccentColor(accent_color); - window_->UpdateWindowAccentColor(window_->IsActive()); - } else { - args->ThrowError( - "Invalid accent color value - must be a string or boolean"); + return; } + + args->ThrowTypeError( + "Invalid accent color value - must be null, hex string, or boolean"); } v8::Local<v8::Value> BaseWindow::GetAccentColor() const { @@ -1122,7 +1151,7 @@ v8::Local<v8::Value> BaseWindow::GetAccentColor() const { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) void BaseWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options, - gin_helper::Arguments* args) { + gin::Arguments* args) { static_cast<NativeWindowViews*>(window_.get()) ->SetTitleBarOverlay(options, args); } @@ -1144,13 +1173,63 @@ void BaseWindow::RemoveFromParentChildWindows() { } // static -gin_helper::WrappableBase* BaseWindow::New(gin_helper::Arguments* args) { +void BaseWindow::ClearPersistedState(const std::string& window_name) { + if (window_name.empty()) { + LOG(WARNING) << "Cannot clear persisted window state: window name is empty"; + return; + } + + if (auto* browser_process = + electron::ElectronBrowserMainParts::Get()->browser_process()) { + DCHECK(browser_process); + if (auto* prefs = browser_process->local_state()) { + ScopedDictPrefUpdate update(prefs, electron::kWindowStates); + + if (!update->Remove(window_name)) { + LOG(WARNING) << "Window state '" << window_name + << "' not found, nothing to clear"; + } + } + } +} + +// static +gin_helper::WrappableBase* BaseWindow::New(gin::Arguments* const args) { auto options = gin_helper::Dictionary::CreateEmpty(args->isolate()); args->GetNext(&options); + std::string error_message; + if (!IsWindowNameValid(options, &error_message)) { + // Window name is already in use throw an error and do not create the window + args->ThrowTypeError(error_message); + return nullptr; + } + return new BaseWindow(args, options); } +// static +bool BaseWindow::IsWindowNameValid(const gin_helper::Dictionary& options, + std::string* error_message) { + std::string window_name; + if (options.Get(options::kName, &window_name) && !window_name.empty()) { + // Check if window name is already in use by another window + // Window names must be unique for state persistence to work correctly + const auto& windows = electron::WindowList::GetWindows(); + bool name_in_use = std::any_of(windows.begin(), windows.end(), + [&window_name](const auto* const window) { + return window->GetName() == window_name; + }); + + if (name_in_use) { + *error_message = "Window name '" + window_name + + "' is already in use. Window names must be unique."; + return false; + } + } + return true; +} + // static void BaseWindow::BuildPrototype(v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype) { @@ -1342,6 +1421,8 @@ void Initialize(v8::Local<v8::Object> exports, .ToLocalChecked()); constructor.SetMethod("fromId", &BaseWindow::FromWeakMapID); constructor.SetMethod("getAllWindows", &BaseWindow::GetAll); + constructor.SetMethod("clearPersistedState", + &BaseWindow::ClearPersistedState); gin_helper::Dictionary dict(isolate, exports); dict.Set("BaseWindow", constructor); diff --git a/shell/browser/api/electron_api_base_window.h b/shell/browser/api/electron_api_base_window.h index 53ddd8cee191f..5a744da4de57b 100644 --- a/shell/browser/api/electron_api_base_window.h +++ b/shell/browser/api/electron_api_base_window.h @@ -19,8 +19,11 @@ #include "shell/common/api/electron_api_native_image.h" #include "shell/common/gin_helper/trackable_object.h" -namespace gin_helper { +namespace gin { class Arguments; +} // namespace gin + +namespace gin_helper { class PersistentDictionary; template <typename T> class Handle; @@ -37,11 +40,18 @@ class View; class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, private NativeWindowObserver { public: - static gin_helper::WrappableBase* New(gin_helper::Arguments* args); + static gin_helper::WrappableBase* New(gin::Arguments* args); static void BuildPrototype(v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype); + // Clears window state from the Local State JSON file in + // app.getPath('userData') via PrefService. + static void ClearPersistedState(const std::string& window_name); + + static bool IsWindowNameValid(const gin_helper::Dictionary& options, + std::string* error_message); + const NativeWindow* window() const { return window_.get(); } NativeWindow* window() { return window_.get(); } @@ -49,8 +59,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, // Common constructor. BaseWindow(v8::Isolate* isolate, const gin_helper::Dictionary& options); // Creating independent BaseWindow instance. - BaseWindow(gin_helper::Arguments* args, - const gin_helper::Dictionary& options); + BaseWindow(gin::Arguments* args, const gin_helper::Dictionary& options); ~BaseWindow() override; // TrackableObject: @@ -93,6 +102,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, const base::Value::Dict& details) override; void OnNewWindowForTab() override; void OnSystemContextMenu(int x, int y, bool* prevent_default) override; + void OnWindowStateRestored() override; #if BUILDFLAG(IS_WIN) void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; #endif @@ -104,8 +114,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, virtual void Focus(); virtual void Blur(); bool IsFocused() const; - void Show(); - void ShowInactive(); + virtual void Show(); + virtual void ShowInactive(); void Hide(); bool IsVisible() const; bool IsEnabled() const; @@ -118,13 +128,13 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, bool IsMinimized() const; void SetFullScreen(bool fullscreen); bool IsFullscreen() const; - void SetBounds(const gfx::Rect& bounds, gin_helper::Arguments* args); + void SetBounds(const gfx::Rect& bounds, gin::Arguments* args); gfx::Rect GetBounds() const; - void SetSize(int width, int height, gin_helper::Arguments* args); + void SetSize(int width, int height, gin::Arguments* args); std::array<int, 2U> GetSize() const; - void SetContentSize(int width, int height, gin_helper::Arguments* args); + void SetContentSize(int width, int height, gin::Arguments* args); std::array<int, 2U> GetContentSize() const; - void SetContentBounds(const gfx::Rect& bounds, gin_helper::Arguments* args); + void SetContentBounds(const gfx::Rect& bounds, gin::Arguments* args); gfx::Rect GetContentBounds() const; bool IsNormal() const; gfx::Rect GetNormalBounds() const; @@ -132,11 +142,11 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, std::array<int, 2U> GetMinimumSize() const; void SetMaximumSize(int width, int height); std::array<int, 2U> GetMaximumSize() const; - void SetSheetOffset(double offsetY, gin_helper::Arguments* args); + void SetSheetOffset(double offsetY, gin::Arguments* args); void SetResizable(bool resizable); bool IsResizable() const; void SetMovable(bool movable); - void MoveAbove(const std::string& sourceId, gin_helper::Arguments* args); + void MoveAbove(const std::string& sourceId, gin::Arguments* args); void MoveTop(); bool IsMovable() const; void SetMinimizable(bool minimizable); @@ -147,10 +157,10 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, bool IsFullScreenable() const; void SetClosable(bool closable); bool IsClosable() const; - void SetAlwaysOnTop(bool top, gin_helper::Arguments* args); + void SetAlwaysOnTop(bool top, gin::Arguments* args); bool IsAlwaysOnTop() const; void Center(); - void SetPosition(int x, int y, gin_helper::Arguments* args); + void SetPosition(int x, int y, gin::Arguments* args); std::array<int, 2U> GetPosition() const; void SetTitle(const std::string& title); std::string GetTitle() const; @@ -177,25 +187,25 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, std::string GetRepresentedFilename() const; void SetDocumentEdited(bool edited); bool IsDocumentEdited() const; - void SetIgnoreMouseEvents(bool ignore, gin_helper::Arguments* args); + void SetIgnoreMouseEvents(bool ignore, gin::Arguments* args); void SetContentProtection(bool enable); bool IsContentProtected() const; void SetFocusable(bool focusable); bool IsFocusable() const; void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu); void RemoveMenu(); - void SetParentWindow(v8::Local<v8::Value> value, gin_helper::Arguments* args); + void SetParentWindow(v8::Local<v8::Value> value, gin::Arguments* args); std::string GetMediaSourceId() const; v8::Local<v8::Value> GetNativeWindowHandle(); - void SetProgressBar(double progress, gin_helper::Arguments* args); + void SetProgressBar(double progress, gin::Arguments* args); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); - void SetVisibleOnAllWorkspaces(bool visible, gin_helper::Arguments* args); + void SetVisibleOnAllWorkspaces(bool visible, gin::Arguments* args); bool IsVisibleOnAllWorkspaces() const; void SetAutoHideCursor(bool auto_hide); virtual void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value, - gin_helper::Arguments* args); + gin::Arguments* args); virtual void SetBackgroundMaterial(const std::string& material); #if BUILDFLAG(IS_MAC) @@ -218,14 +228,14 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, void MergeAllWindows(); void MoveTabToNewWindow(); void ToggleTabBar(); - void AddTabbedWindow(NativeWindow* window, gin_helper::Arguments* args); + void AddTabbedWindow(NativeWindow* window, gin::Arguments* args); v8::Local<v8::Value> GetTabbingIdentifier(); void SetAutoHideMenuBar(bool auto_hide); bool IsMenuBarAutoHide() const; void SetMenuBarVisibility(bool visible); bool IsMenuBarVisible() const; - void SetAspectRatio(double aspect_ratio, gin_helper::Arguments* args); - void PreviewFile(const std::string& path, gin_helper::Arguments* args); + void SetAspectRatio(double aspect_ratio, gin::Arguments* args); + void PreviewFile(const std::string& path, gin::Arguments* args); void CloseFilePreview(); void SetGTKDarkThemeEnabled(bool use_dark_theme); @@ -236,7 +246,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, bool IsModal() const; // Extra APIs added in JS. - bool SetThumbarButtons(gin_helper::Arguments* args); + bool SetThumbarButtons(gin::Arguments* args); #if defined(TOOLKIT_VIEWS) void SetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon); void SetIconImpl(v8::Isolate* isolate, @@ -255,13 +265,13 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>, bool SetThumbnailToolTip(const std::string& tooltip); void SetAppDetails(const gin_helper::Dictionary& options); bool IsSnapped() const; - void SetAccentColor(gin_helper::Arguments* args); + void SetAccentColor(gin::Arguments* args); v8::Local<v8::Value> GetAccentColor() const; #endif #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) void SetTitleBarOverlay(const gin_helper::Dictionary& options, - gin_helper::Arguments* args); + gin::Arguments* args); #endif [[nodiscard]] constexpr int32_t GetID() const { return weak_map_id(); } diff --git a/shell/browser/api/electron_api_browser_window.cc b/shell/browser/api/electron_api_browser_window.cc index 943530e697e41..5d065765cecaf 100644 --- a/shell/browser/api/electron_api_browser_window.cc +++ b/shell/browser/api/electron_api_browser_window.cc @@ -280,7 +280,6 @@ v8::Local<v8::Value> BrowserWindow::GetWebContents(v8::Isolate* isolate) { } void BrowserWindow::OnWindowShow() { - web_contents()->WasShown(); BaseWindow::OnWindowShow(); } @@ -289,6 +288,19 @@ void BrowserWindow::OnWindowHide() { BaseWindow::OnWindowHide(); } +void BrowserWindow::Show() { + web_contents()->WasShown(); + BaseWindow::Show(); +} + +void BrowserWindow::ShowInactive() { + // This method doesn't make sense for modal window. + if (IsModal()) + return; + web_contents()->WasShown(); + BaseWindow::ShowInactive(); +} + // static gin_helper::WrappableBase* BrowserWindow::New(gin_helper::ErrorThrower thrower, gin::Arguments* args) { @@ -307,6 +319,13 @@ gin_helper::WrappableBase* BrowserWindow::New(gin_helper::ErrorThrower thrower, options = gin::Dictionary::CreateEmpty(args->isolate()); } + std::string error_message; + if (!IsWindowNameValid(options, &error_message)) { + // Window name is already in use throw an error and do not create the window + thrower.ThrowError(error_message); + return nullptr; + } + return new BrowserWindow(args, options); } diff --git a/shell/browser/api/electron_api_browser_window.h b/shell/browser/api/electron_api_browser_window.h index b13ffda8f8a18..02684f23b5c53 100644 --- a/shell/browser/api/electron_api_browser_window.h +++ b/shell/browser/api/electron_api_browser_window.h @@ -67,6 +67,8 @@ class BrowserWindow : public BaseWindow, void SetBackgroundMaterial(const std::string& material) override; void OnWindowShow() override; void OnWindowHide() override; + void Show() override; + void ShowInactive() override; // BrowserWindow APIs. void FocusOnWebView(); diff --git a/shell/browser/api/electron_api_content_tracing.cc b/shell/browser/api/electron_api_content_tracing.cc index 278ec587df985..90652c0de5881 100644 --- a/shell/browser/api/electron_api_content_tracing.cc +++ b/shell/browser/api/electron_api_content_tracing.cc @@ -98,8 +98,8 @@ void StopTracing(gin_helper::Promise<base::FilePath> promise, } } -v8::Local<v8::Promise> StopRecording(gin_helper::Arguments* args) { - gin_helper::Promise<base::FilePath> promise(args->isolate()); +v8::Local<v8::Promise> StopRecording(gin::Arguments* const args) { + gin_helper::Promise<base::FilePath> promise{args->isolate()}; v8::Local<v8::Promise> handle = promise.GetHandle(); base::FilePath path; diff --git a/shell/browser/api/electron_api_debugger.cc b/shell/browser/api/electron_api_debugger.cc index b760639166276..29f496c746fa8 100644 --- a/shell/browser/api/electron_api_debugger.cc +++ b/shell/browser/api/electron_api_debugger.cc @@ -19,15 +19,18 @@ #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/handle.h" #include "shell/common/gin_helper/promise.h" +#include "v8/include/cppgc/allocation.h" +#include "v8/include/v8-cppgc.h" using content::DevToolsAgentHost; namespace electron::api { -gin::DeprecatedWrapperInfo Debugger::kWrapperInfo = {gin::kEmbedderNativeGin}; +gin::WrapperInfo Debugger::kWrapperInfo = {{gin::kEmbedderNativeGin}, + gin::kElectronDebugger}; -Debugger::Debugger(v8::Isolate* isolate, content::WebContents* web_contents) - : content::WebContentsObserver(web_contents), web_contents_(web_contents) {} +Debugger::Debugger(content::WebContents* web_contents) + : content::WebContentsObserver{web_contents}, web_contents_{web_contents} {} Debugger::~Debugger() = default; @@ -178,10 +181,10 @@ void Debugger::ClearPendingRequests() { } // static -gin_helper::Handle<Debugger> Debugger::Create( - v8::Isolate* isolate, - content::WebContents* web_contents) { - return gin_helper::CreateHandle(isolate, new Debugger(isolate, web_contents)); +Debugger* Debugger::Create(v8::Isolate* isolate, + content::WebContents* web_contents) { + return cppgc::MakeGarbageCollected<Debugger>( + isolate->GetCppHeap()->GetAllocationHandle(), web_contents); } gin::ObjectTemplateBuilder Debugger::GetObjectTemplateBuilder( @@ -194,8 +197,12 @@ gin::ObjectTemplateBuilder Debugger::GetObjectTemplateBuilder( .SetMethod("sendCommand", &Debugger::SendCommand); } -const char* Debugger::GetTypeName() { - return "Debugger"; +const gin::WrapperInfo* Debugger::wrapper_info() const { + return &kWrapperInfo; +} + +const char* Debugger::GetHumanReadableName() const { + return "Electron / Debugger"; } } // namespace electron::api diff --git a/shell/browser/api/electron_api_debugger.h b/shell/browser/api/electron_api_debugger.h index 4a017244d3614..1d40c4f16ee00 100644 --- a/shell/browser/api/electron_api_debugger.h +++ b/shell/browser/api/electron_api_debugger.h @@ -11,8 +11,8 @@ #include "base/values.h" #include "content/public/browser/devtools_agent_host_client.h" #include "content/public/browser/web_contents_observer.h" +#include "gin/wrappable.h" #include "shell/browser/event_emitter_mixin.h" -#include "shell/common/gin_helper/wrappable.h" namespace content { class DevToolsAgentHost; @@ -32,29 +32,32 @@ class Promise; namespace electron::api { -class Debugger final : public gin_helper::DeprecatedWrappable<Debugger>, +class Debugger final : public gin::Wrappable<Debugger>, public gin_helper::EventEmitterMixin<Debugger>, public content::DevToolsAgentHostClient, private content::WebContentsObserver { public: - static gin_helper::Handle<Debugger> Create( - v8::Isolate* isolate, - content::WebContents* web_contents); + static Debugger* Create(v8::Isolate* isolate, + content::WebContents* web_contents); + + // Make public for cppgc::MakeGarbageCollected. + explicit Debugger(content::WebContents* web_contents); + ~Debugger() override; // gin_helper::Wrappable - static gin::DeprecatedWrapperInfo kWrapperInfo; + static gin::WrapperInfo kWrapperInfo; gin::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; - const char* GetTypeName() override; + const gin::WrapperInfo* wrapper_info() const override; + const char* GetHumanReadableName() const override; + + const char* GetClassName() const { return "Debugger"; } // disable copy Debugger(const Debugger&) = delete; Debugger& operator=(const Debugger&) = delete; protected: - Debugger(v8::Isolate* isolate, content::WebContents* web_contents); - ~Debugger() override; - // content::DevToolsAgentHostClient: void AgentHostClosed(content::DevToolsAgentHost* agent_host) override; void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host, diff --git a/shell/browser/api/electron_api_dialog.cc b/shell/browser/api/electron_api_dialog.cc index 9311c26e4d478..89b8ab09b597e 100644 --- a/shell/browser/api/electron_api_dialog.cc +++ b/shell/browser/api/electron_api_dialog.cc @@ -42,9 +42,8 @@ void ResolvePromiseObject(gin_helper::Promise<gin_helper::Dictionary> promise, } v8::Local<v8::Promise> ShowMessageBox( - const electron::MessageBoxSettings& settings, - gin::Arguments* args) { - v8::Isolate* isolate = args->isolate(); + v8::Isolate* const isolate, + const electron::MessageBoxSettings& settings) { gin_helper::Promise<gin_helper::Dictionary> promise(isolate); v8::Local<v8::Promise> handle = promise.GetHandle(); @@ -62,9 +61,9 @@ void ShowOpenDialogSync(const file_dialog::DialogSettings& settings, } v8::Local<v8::Promise> ShowOpenDialog( - const file_dialog::DialogSettings& settings, - gin::Arguments* args) { - gin_helper::Promise<gin_helper::Dictionary> promise(args->isolate()); + v8::Isolate* const isolate, + const file_dialog::DialogSettings& settings) { + gin_helper::Promise<gin_helper::Dictionary> promise{isolate}; v8::Local<v8::Promise> handle = promise.GetHandle(); file_dialog::ShowOpenDialog(settings, std::move(promise)); return handle; diff --git a/shell/browser/api/electron_api_menu.cc b/shell/browser/api/electron_api_menu.cc index 817fa2ac7f97a..269080dba7a16 100644 --- a/shell/browser/api/electron_api_menu.cc +++ b/shell/browser/api/electron_api_menu.cc @@ -50,7 +50,8 @@ struct Converter<SharingItem> { namespace electron::api { -gin::DeprecatedWrapperInfo Menu::kWrapperInfo = {gin::kEmbedderNativeGin}; +const gin::WrapperInfo Menu::kWrapperInfo = {{gin::kEmbedderNativeGin}, + gin::kElectronMenu}; Menu::Menu(gin::Arguments* args) : model_(std::make_unique<ElectronMenuModel>(this)) { @@ -268,12 +269,11 @@ bool Menu::WorksWhenHiddenAt(int index) const { } void Menu::OnMenuWillClose() { - Unpin(); + keep_alive_.Clear(); Emit("menu-will-close"); } void Menu::OnMenuWillShow() { - Pin(JavascriptEnvironment::GetIsolate()); Emit("menu-will-show"); } @@ -311,8 +311,12 @@ void Menu::FillObjectTemplate(v8::Isolate* isolate, .Build(); } -const char* Menu::GetTypeName() { - return GetClassName(); +const gin::WrapperInfo* Menu::wrapper_info() const { + return &kWrapperInfo; +} + +const char* Menu::GetHumanReadableName() const { + return "Electron / Menu"; } } // namespace electron::api @@ -327,7 +331,7 @@ void Initialize(v8::Local<v8::Object> exports, void* priv) { v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate(); gin_helper::Dictionary dict{isolate, exports}; - dict.Set("Menu", Menu::GetConstructor(isolate, context)); + dict.Set("Menu", Menu::GetConstructor(isolate, context, &Menu::kWrapperInfo)); #if BUILDFLAG(IS_MAC) dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu); dict.SetMethod("sendActionToFirstResponder", diff --git a/shell/browser/api/electron_api_menu.h b/shell/browser/api/electron_api_menu.h index ba92e230e3f4c..fc76a0c3df5ae 100644 --- a/shell/browser/api/electron_api_menu.h +++ b/shell/browser/api/electron_api_menu.h @@ -9,11 +9,11 @@ #include <string> #include "base/memory/raw_ptr.h" +#include "gin/wrappable.h" #include "shell/browser/event_emitter_mixin.h" #include "shell/browser/ui/electron_menu_model.h" #include "shell/common/gin_helper/constructible.h" -#include "shell/common/gin_helper/pinnable.h" -#include "shell/common/gin_helper/wrappable.h" +#include "shell/common/gin_helper/self_keep_alive.h" #include "ui/base/mojom/menu_source_type.mojom-forward.h" namespace gin { @@ -25,22 +25,31 @@ namespace electron::api { class BaseWindow; class WebFrameMain; -class Menu : public gin_helper::DeprecatedWrappable<Menu>, +class Menu : public gin::Wrappable<Menu>, public gin_helper::EventEmitterMixin<Menu>, public gin_helper::Constructible<Menu>, - public gin_helper::Pinnable<Menu>, public ElectronMenuModel::Delegate, private ElectronMenuModel::Observer { public: + static Menu* New(gin::Arguments* args); + + // Make public for cppgc::MakeGarbageCollected. + explicit Menu(gin::Arguments* args); + ~Menu() override; + + // disable copy + Menu(const Menu&) = delete; + Menu& operator=(const Menu&) = delete; + + // gin::Wrappable + static const gin::WrapperInfo kWrapperInfo; + const gin::WrapperInfo* wrapper_info() const override; + const char* GetHumanReadableName() const override; + // gin_helper::Constructible - static gin_helper::Handle<Menu> New(gin::Arguments* args); static void FillObjectTemplate(v8::Isolate*, v8::Local<v8::ObjectTemplate>); static const char* GetClassName() { return "Menu"; } - // gin_helper::Wrappable - static gin::DeprecatedWrapperInfo kWrapperInfo; - const char* GetTypeName() override; - #if BUILDFLAG(IS_MAC) // Set the global menubar. static void SetApplicationMenu(Menu* menu); @@ -51,14 +60,7 @@ class Menu : public gin_helper::DeprecatedWrappable<Menu>, ElectronMenuModel* model() const { return model_.get(); } - // disable copy - Menu(const Menu&) = delete; - Menu& operator=(const Menu&) = delete; - protected: - explicit Menu(gin::Arguments* args); - ~Menu() override; - // Returns a new callback which keeps references of the JS wrapper until the // passed |callback| is called. base::OnceClosure BindSelfToClosure(base::OnceClosure callback); @@ -129,6 +131,8 @@ class Menu : public gin_helper::DeprecatedWrappable<Menu>, bool IsEnabledAt(int index) const; bool IsVisibleAt(int index) const; bool WorksWhenHiddenAt(int index) const; + + gin_helper::SelfKeepAlive<Menu> keep_alive_{this}; }; } // namespace electron::api diff --git a/shell/browser/api/electron_api_menu_mac.h b/shell/browser/api/electron_api_menu_mac.h index f4d92f0840693..750f2a01a258a 100644 --- a/shell/browser/api/electron_api_menu_mac.h +++ b/shell/browser/api/electron_api_menu_mac.h @@ -18,10 +18,12 @@ class WebFrameMain; namespace api { class MenuMac : public Menu { - protected: + public: + // Make public for cppgc::MakeGarbageCollected. explicit MenuMac(gin::Arguments* args); ~MenuMac() override; + protected: // Menu void PopupAt(BaseWindow* window, std::optional<WebFrameMain*> frame, diff --git a/shell/browser/api/electron_api_menu_mac.mm b/shell/browser/api/electron_api_menu_mac.mm index a70725d983d9b..b5c60b3eb5d7c 100644 --- a/shell/browser/api/electron_api_menu_mac.mm +++ b/shell/browser/api/electron_api_menu_mac.mm @@ -20,6 +20,8 @@ #include "shell/common/keyboard_util.h" #include "shell/common/node_includes.h" #include "ui/base/cocoa/menu_utils.h" +#include "v8/include/cppgc/allocation.h" +#include "v8/include/v8-cppgc.h" namespace { @@ -47,7 +49,7 @@ namespace electron::api { -MenuMac::MenuMac(gin::Arguments* args) : Menu(args) {} +MenuMac::MenuMac(gin::Arguments* args) : Menu{args} {} MenuMac::~MenuMac() = default; @@ -288,11 +290,12 @@ } // static -gin_helper::Handle<Menu> Menu::New(gin::Arguments* args) { - auto handle = gin_helper::CreateHandle(args->isolate(), - static_cast<Menu*>(new MenuMac(args))); - gin_helper::CallMethod(args->isolate(), handle.get(), "_init"); - return handle; +Menu* Menu::New(gin::Arguments* args) { + v8::Isolate* const isolate = args->isolate(); + Menu* const menu = cppgc::MakeGarbageCollected<MenuMac>( + isolate->GetCppHeap()->GetAllocationHandle(), args); + gin_helper::CallMethod(isolate, menu, "_init"); + return menu; } } // namespace electron::api diff --git a/shell/browser/api/electron_api_menu_views.cc b/shell/browser/api/electron_api_menu_views.cc index 8a496f9f85874..2003ae4e59a39 100644 --- a/shell/browser/api/electron_api_menu_views.cc +++ b/shell/browser/api/electron_api_menu_views.cc @@ -10,7 +10,10 @@ #include "shell/browser/api/electron_api_base_window.h" #include "shell/browser/api/electron_api_web_frame_main.h" #include "shell/browser/native_window_views.h" +#include "shell/common/callback_util.h" #include "ui/display/screen.h" +#include "v8/include/cppgc/allocation.h" +#include "v8/include/v8-cppgc.h" using views::MenuRunner; @@ -34,7 +37,7 @@ void MenuViews::PopupAt(BaseWindow* window, // (-1, -1) means showing on mouse location. gfx::Point location; if (x == -1 || y == -1) { - location = display::Screen::GetScreen()->GetCursorScreenPoint(); + location = display::Screen::Get()->GetCursorScreenPoint(); } else { gfx::Point origin = native_window->GetContentBounds().origin(); location = gfx::Point(origin.x() + x, origin.y() + y); @@ -52,7 +55,7 @@ void MenuViews::PopupAt(BaseWindow* window, // callback, it is fine passing OnceCallback to it because we reset the // menu runner immediately when the menu is closed. int32_t window_id = window->weak_map_id(); - auto close_callback = base::AdaptCallbackForRepeating( + auto close_callback = electron::AdaptCallbackForRepeating( base::BindOnce(&MenuViews::OnClosed, weak_factory_.GetWeakPtr(), window_id, std::move(callback_with_ref))); auto& runner = menu_runners_[window_id] = @@ -84,11 +87,12 @@ void MenuViews::OnClosed(int32_t window_id, base::OnceClosure callback) { } // static -gin_helper::Handle<Menu> Menu::New(gin::Arguments* args) { - auto handle = gin_helper::CreateHandle( - args->isolate(), static_cast<Menu*>(new MenuViews(args))); - gin_helper::CallMethod(args->isolate(), handle.get(), "_init"); - return handle; +Menu* Menu::New(gin::Arguments* args) { + v8::Isolate* const isolate = args->isolate(); + Menu* menu = cppgc::MakeGarbageCollected<MenuViews>( + isolate->GetCppHeap()->GetAllocationHandle(), args); + gin_helper::CallMethod(isolate, menu, "_init"); + return menu; } } // namespace electron::api diff --git a/shell/browser/api/electron_api_native_theme.cc b/shell/browser/api/electron_api_native_theme.cc index adccf5f8e50b8..fa7f9fbbeff9f 100644 --- a/shell/browser/api/electron_api_native_theme.cc +++ b/shell/browser/api/electron_api_native_theme.cc @@ -25,6 +25,12 @@ NativeTheme::NativeTheme(v8::Isolate* isolate, ui::NativeTheme* web_theme) : ui_theme_(ui_theme), web_theme_(web_theme) { ui_theme_->AddObserver(this); +#if BUILDFLAG(IS_WIN) + std::ignore = hkcu_themes_regkey_.Open(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\" + L"CurrentVersion\\Themes\\Personalize", + KEY_READ); +#endif } NativeTheme::~NativeTheme() { @@ -32,6 +38,16 @@ NativeTheme::~NativeTheme() { } void NativeTheme::OnNativeThemeUpdatedOnUI() { +#if BUILDFLAG(IS_WIN) + if (hkcu_themes_regkey_.Valid()) { + DWORD system_uses_light_theme = 1; + hkcu_themes_regkey_.ReadValueDW(L"SystemUsesLightTheme", + &system_uses_light_theme); + bool system_dark_mode_enabled = (system_uses_light_theme == 0); + should_use_dark_colors_for_system_integrated_ui_ = + std::make_optional<bool>(system_dark_mode_enabled); + } +#endif Emit("updated"); } @@ -57,23 +73,32 @@ ui::NativeTheme::ThemeSource NativeTheme::GetThemeSource() const { } bool NativeTheme::ShouldUseDarkColors() { - return ui_theme_->ShouldUseDarkColors(); + auto theme_source = GetThemeSource(); + if (theme_source == ui::NativeTheme::ThemeSource::kForcedLight) + return false; + if (theme_source == ui::NativeTheme::ThemeSource::kForcedDark) + return true; + return ui_theme_->preferred_color_scheme() == + ui::NativeTheme::PreferredColorScheme::kDark; } bool NativeTheme::ShouldUseHighContrastColors() { - return ui_theme_->UserHasContrastPreference(); + return ui_theme_->preferred_contrast() == + ui::NativeTheme::PreferredContrast::kMore; } bool NativeTheme::ShouldUseDarkColorsForSystemIntegratedUI() { - return ui_theme_->ShouldUseDarkColorsForSystemIntegratedUI(); + return should_use_dark_colors_for_system_integrated_ui_.value_or( + ShouldUseDarkColors()); } bool NativeTheme::InForcedColorsMode() { - return ui_theme_->InForcedColorsMode(); + return ui_theme_->forced_colors() != + ui::ColorProviderKey::ForcedColors::kNone; } bool NativeTheme::GetPrefersReducedTransparency() { - return ui_theme_->GetPrefersReducedTransparency(); + return ui_theme_->prefers_reduced_transparency(); } #if BUILDFLAG(IS_MAC) @@ -92,8 +117,10 @@ bool NativeTheme::ShouldUseInvertedColorScheme() { return false; return is_inverted; #else - return ui_theme_->GetPlatformHighContrastColorScheme() == - ui::NativeTheme::PlatformHighContrastColorScheme::kDark; + return ui_theme_->forced_colors() != + ui::ColorProviderKey::ForcedColors::kNone && + ui_theme_->preferred_color_scheme() == + ui::NativeTheme::PreferredColorScheme::kDark; #endif } diff --git a/shell/browser/api/electron_api_native_theme.h b/shell/browser/api/electron_api_native_theme.h index 04351ffb944a0..7a4b7b4eecc07 100644 --- a/shell/browser/api/electron_api_native_theme.h +++ b/shell/browser/api/electron_api_native_theme.h @@ -11,6 +11,10 @@ #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_observer.h" +#if BUILDFLAG(IS_WIN) +#include "base/win/registry.h" +#endif + namespace gin_helper { template <typename T> class Handle; @@ -58,6 +62,11 @@ class NativeTheme final : public gin_helper::DeprecatedWrappable<NativeTheme>, void OnNativeThemeUpdatedOnUI(); private: +#if BUILDFLAG(IS_WIN) + base::win::RegKey hkcu_themes_regkey_; +#endif + std::optional<bool> should_use_dark_colors_for_system_integrated_ui_ = + std::nullopt; raw_ptr<ui::NativeTheme> ui_theme_; raw_ptr<ui::NativeTheme> web_theme_; }; diff --git a/shell/browser/api/electron_api_net_log.cc b/shell/browser/api/electron_api_net_log.cc index 29c04d585ea29..5d91452046581 100644 --- a/shell/browser/api/electron_api_net_log.cc +++ b/shell/browser/api/electron_api_net_log.cc @@ -22,6 +22,8 @@ #include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/handle.h" +#include "v8/include/cppgc/allocation.h" +#include "v8/include/v8-cppgc.h" namespace gin { @@ -79,9 +81,10 @@ void ResolvePromiseWithNetError(gin_helper::Promise<void> promise, namespace api { -gin::DeprecatedWrapperInfo NetLog::kWrapperInfo = {gin::kEmbedderNativeGin}; +gin::WrapperInfo NetLog::kWrapperInfo = {{gin::kEmbedderNativeGin}, + gin::kElectronNetLog}; -NetLog::NetLog(v8::Isolate* isolate, ElectronBrowserContext* browser_context) +NetLog::NetLog(ElectronBrowserContext* const browser_context) : browser_context_(browser_context) { file_task_runner_ = CreateFileTaskRunner(); } @@ -194,8 +197,8 @@ bool NetLog::IsCurrentlyLogging() const { return !!net_log_exporter_; } -v8::Local<v8::Promise> NetLog::StopLogging(gin::Arguments* args) { - gin_helper::Promise<void> promise(args->isolate()); +v8::Local<v8::Promise> NetLog::StopLogging(v8::Isolate* const isolate) { + gin_helper::Promise<void> promise{isolate}; v8::Local<v8::Promise> handle = promise.GetHandle(); if (net_log_exporter_) { @@ -219,23 +222,25 @@ v8::Local<v8::Promise> NetLog::StopLogging(gin::Arguments* args) { gin::ObjectTemplateBuilder NetLog::GetObjectTemplateBuilder( v8::Isolate* isolate) { - return gin_helper::DeprecatedWrappable<NetLog>::GetObjectTemplateBuilder( - isolate) + return gin::Wrappable<NetLog>::GetObjectTemplateBuilder(isolate) .SetProperty("currentlyLogging", &NetLog::IsCurrentlyLogging) .SetMethod("startLogging", &NetLog::StartLogging) .SetMethod("stopLogging", &NetLog::StopLogging); } -const char* NetLog::GetTypeName() { - return "NetLog"; +const gin::WrapperInfo* NetLog::wrapper_info() const { + return &kWrapperInfo; +} + +const char* NetLog::GetHumanReadableName() const { + return "Electron / NetLog"; } // static -gin_helper::Handle<NetLog> NetLog::Create( - v8::Isolate* isolate, - ElectronBrowserContext* browser_context) { - return gin_helper::CreateHandle(isolate, - new NetLog(isolate, browser_context)); +NetLog* NetLog::Create(v8::Isolate* isolate, + ElectronBrowserContext* browser_context) { + return cppgc::MakeGarbageCollected<NetLog>( + isolate->GetCppHeap()->GetAllocationHandle(), browser_context); } } // namespace api diff --git a/shell/browser/api/electron_api_net_log.h b/shell/browser/api/electron_api_net_log.h index d056ad3062e38..108a867982ca9 100644 --- a/shell/browser/api/electron_api_net_log.h +++ b/shell/browser/api/electron_api_net_log.h @@ -10,11 +10,11 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/values.h" +#include "gin/wrappable.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/log/net_log_capture_mode.h" #include "services/network/public/mojom/net_log.mojom.h" #include "shell/common/gin_helper/promise.h" -#include "shell/common/gin_helper/wrappable.h" namespace base { class FilePath; @@ -37,32 +37,32 @@ class ElectronBrowserContext; namespace api { // The code is referenced from the net_log::NetExportFileWriter class. -class NetLog final : public gin_helper::DeprecatedWrappable<NetLog> { +class NetLog final : public gin::Wrappable<NetLog> { public: - static gin_helper::Handle<NetLog> Create( - v8::Isolate* isolate, - ElectronBrowserContext* browser_context); + static NetLog* Create(v8::Isolate* isolate, + ElectronBrowserContext* browser_context); - v8::Local<v8::Promise> StartLogging(base::FilePath log_path, - gin::Arguments* args); - v8::Local<v8::Promise> StopLogging(gin::Arguments* args); - bool IsCurrentlyLogging() const; + // Make public for cppgc::MakeGarbageCollected. + explicit NetLog(ElectronBrowserContext* browser_context); + ~NetLog() override; + + // disable copy + NetLog(const NetLog&) = delete; + NetLog& operator=(const NetLog&) = delete; // gin_helper::Wrappable - static gin::DeprecatedWrapperInfo kWrapperInfo; + static gin::WrapperInfo kWrapperInfo; gin::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; - const char* GetTypeName() override; + const gin::WrapperInfo* wrapper_info() const override; + const char* GetHumanReadableName() const override; - // disable copy - NetLog(const NetLog&) = delete; - NetLog& operator=(const NetLog&) = delete; + v8::Local<v8::Promise> StartLogging(base::FilePath log_path, + gin::Arguments* args); + v8::Local<v8::Promise> StopLogging(v8::Isolate* isolate); + bool IsCurrentlyLogging() const; protected: - explicit NetLog(v8::Isolate* isolate, - ElectronBrowserContext* browser_context); - ~NetLog() override; - void OnConnectionError(); void StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode, diff --git a/shell/browser/api/electron_api_protocol.cc b/shell/browser/api/electron_api_protocol.cc index 1d1f1a209ec89..cb7093c43f34b 100644 --- a/shell/browser/api/electron_api_protocol.cc +++ b/shell/browser/api/electron_api_protocol.cc @@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/containers/contains.h" +#include "base/no_destructor.h" #include "content/common/url_schemes.h" #include "content/public/browser/child_process_security_policy.h" #include "gin/object_template_builder.h" @@ -28,15 +29,6 @@ namespace { -// List of registered custom standard schemes. -std::vector<std::string> g_standard_schemes; - -// List of registered custom streaming schemes. -std::vector<std::string> g_streaming_schemes; - -// Schemes that support V8 code cache. -std::vector<std::string> g_code_cache_schemes; - struct SchemeOptions { bool standard = false; bool secure = false; @@ -89,12 +81,19 @@ namespace electron::api { gin::DeprecatedWrapperInfo Protocol::kWrapperInfo = {gin::kEmbedderNativeGin}; -const std::vector<std::string>& GetStandardSchemes() { - return g_standard_schemes; +std::vector<std::string>& GetStandardSchemes() { + static base::NoDestructor<std::vector<std::string>> g_standard_schemes; + return *g_standard_schemes; } -const std::vector<std::string>& GetCodeCacheSchemes() { - return g_code_cache_schemes; +std::vector<std::string>& GetCodeCacheSchemes() { + static base::NoDestructor<std::vector<std::string>> g_code_cache_schemes; + return *g_code_cache_schemes; +} + +std::vector<std::string>& GetStreamingSchemes() { + static base::NoDestructor<std::vector<std::string>> g_streaming_schemes; + return *g_streaming_schemes; } void AddServiceWorkerScheme(const std::string& scheme) { @@ -132,7 +131,7 @@ void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower, auto* policy = content::ChildProcessSecurityPolicy::GetInstance(); url::AddStandardScheme(custom_scheme.scheme.c_str(), url::SCHEME_WITH_HOST); - g_standard_schemes.push_back(custom_scheme.scheme); + GetStandardSchemes().push_back(custom_scheme.scheme); policy->RegisterWebSafeScheme(custom_scheme.scheme); } if (custom_scheme.options.secure) { @@ -155,10 +154,10 @@ void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower, AddServiceWorkerScheme(custom_scheme.scheme); } if (custom_scheme.options.stream) { - g_streaming_schemes.push_back(custom_scheme.scheme); + GetStreamingSchemes().push_back(custom_scheme.scheme); } if (custom_scheme.options.codeCache) { - g_code_cache_schemes.push_back(custom_scheme.scheme); + GetCodeCacheSchemes().push_back(custom_scheme.scheme); url::AddCodeCacheScheme(custom_scheme.scheme.c_str()); } } @@ -181,11 +180,11 @@ void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower, AppendSchemesToCmdLine(electron::switches::kServiceWorkerSchemes, service_worker_schemes); AppendSchemesToCmdLine(electron::switches::kStandardSchemes, - g_standard_schemes); + GetStandardSchemes()); AppendSchemesToCmdLine(electron::switches::kStreamingSchemes, - g_streaming_schemes); + GetStreamingSchemes()); AppendSchemesToCmdLine(electron::switches::kCodeCacheSchemes, - g_code_cache_schemes); + GetCodeCacheSchemes()); } namespace { @@ -199,6 +198,8 @@ const char* const kBuiltinSchemes[] = { Protocol::Protocol(ProtocolRegistry* protocol_registry) : protocol_registry_{protocol_registry} {} +Protocol::~Protocol() = default; + // Convert error code to string. // static std::string_view Protocol::ErrorCodeToString(Error error) { @@ -252,24 +253,23 @@ bool Protocol::IsProtocolIntercepted(const std::string& scheme) { return protocol_registry_->FindIntercepted(scheme) != nullptr; } -v8::Local<v8::Promise> Protocol::IsProtocolHandled(const std::string& scheme, - gin::Arguments* args) { - util::EmitWarning(args->isolate(), +v8::Local<v8::Promise> Protocol::IsProtocolHandled(v8::Isolate* const isolate, + const std::string& scheme) { + util::EmitWarning(isolate, "The protocol.isProtocolHandled API is deprecated, " "use protocol.isProtocolRegistered " "or protocol.isProtocolIntercepted instead.", "ProtocolDeprecateIsProtocolHandled"); return gin_helper::Promise<bool>::ResolvedPromise( - args->isolate(), - IsProtocolRegistered(scheme) || IsProtocolIntercepted(scheme) || - // The |isProtocolHandled| should return true for builtin - // schemes, however with NetworkService it is impossible to - // know which schemes are registered until a real network - // request is sent. - // So we have to test against a hard-coded builtin schemes - // list make it work with old code. We should deprecate - // this API with the new |isProtocolRegistered| API. - base::Contains(kBuiltinSchemes, scheme)); + isolate, IsProtocolRegistered(scheme) || IsProtocolIntercepted(scheme) || + // The |isProtocolHandled| should return true for builtin + // schemes, however with NetworkService it is impossible to + // know which schemes are registered until a real network + // request is sent. + // So we have to test against a hard-coded builtin schemes + // list make it work with old code. We should deprecate + // this API with the new |isProtocolRegistered| API. + base::Contains(kBuiltinSchemes, scheme)); } void Protocol::HandleOptionalCallback(gin::Arguments* args, Error error) { diff --git a/shell/browser/api/electron_api_protocol.h b/shell/browser/api/electron_api_protocol.h index dfb935c175630..79013260ebe9c 100644 --- a/shell/browser/api/electron_api_protocol.h +++ b/shell/browser/api/electron_api_protocol.h @@ -29,8 +29,8 @@ class ProtocolRegistry; namespace api { -const std::vector<std::string>& GetStandardSchemes(); -const std::vector<std::string>& GetCodeCacheSchemes(); +std::vector<std::string>& GetStandardSchemes(); +std::vector<std::string>& GetCodeCacheSchemes(); void AddServiceWorkerScheme(const std::string& scheme); @@ -71,7 +71,7 @@ class Protocol final : public gin_helper::DeprecatedWrappable<Protocol>, base::RepeatingCallback<void(v8::Local<v8::Value>)>; explicit Protocol(ProtocolRegistry* protocol_registry); - ~Protocol() override = default; + ~Protocol() override; [[nodiscard]] static std::string_view ErrorCodeToString(Error error); @@ -89,8 +89,8 @@ class Protocol final : public gin_helper::DeprecatedWrappable<Protocol>, bool IsProtocolIntercepted(const std::string& scheme); // Old async version of IsProtocolRegistered. - v8::Local<v8::Promise> IsProtocolHandled(const std::string& scheme, - gin::Arguments* args); + v8::Local<v8::Promise> IsProtocolHandled(v8::Isolate* isolate, + const std::string& scheme); // Helper for converting old registration APIs to new RegisterProtocol API. template <ProtocolType type> diff --git a/shell/browser/api/electron_api_screen.cc b/shell/browser/api/electron_api_screen.cc index 5dc8389480ea7..3b4cb6f7df41e 100644 --- a/shell/browser/api/electron_api_screen.cc +++ b/shell/browser/api/electron_api_screen.cc @@ -179,7 +179,7 @@ v8::Local<v8::Value> Screen::Create(gin_helper::ErrorThrower error_thrower) { return v8::Null(error_thrower.isolate()); } - display::Screen* screen = display::Screen::GetScreen(); + display::Screen* screen = display::Screen::Get(); if (!screen) { error_thrower.ThrowError("Failed to get screen information"); return v8::Null(error_thrower.isolate()); diff --git a/shell/browser/api/electron_api_service_worker_main.cc b/shell/browser/api/electron_api_service_worker_main.cc index c6cc18a7cf1a2..a0e6978803837 100644 --- a/shell/browser/api/electron_api_service_worker_main.cc +++ b/shell/browser/api/electron_api_service_worker_main.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/no_destructor.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" // nogncheck +#include "content/browser/service_worker/service_worker_info.h" // nogncheck #include "content/browser/service_worker/service_worker_version.h" // nogncheck #include "gin/object_template_builder.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -21,7 +22,6 @@ #include "shell/common/gin_converters/gurl_converter.h" #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" -#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/handle.h" #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/gin_helper/promise.h" diff --git a/shell/browser/api/electron_api_service_worker_main.h b/shell/browser/api/electron_api_service_worker_main.h index 9cd79653ecb85..c8e4ed59f8836 100644 --- a/shell/browser/api/electron_api_service_worker_main.h +++ b/shell/browser/api/electron_api_service_worker_main.h @@ -16,7 +16,6 @@ #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/remote.h" -#include "shell/browser/event_emitter_mixin.h" #include "shell/common/api/api.mojom.h" #include "shell/common/gin_helper/constructible.h" #include "shell/common/gin_helper/pinnable.h" @@ -80,7 +79,6 @@ struct ServiceWorkerKey { // the default StoragePartition for the associated BrowserContext. class ServiceWorkerMain final : public gin_helper::DeprecatedWrappable<ServiceWorkerMain>, - public gin_helper::EventEmitterMixin<ServiceWorkerMain>, public gin_helper::Pinnable<ServiceWorkerMain>, public gin_helper::Constructible<ServiceWorkerMain> { public: diff --git a/shell/browser/api/electron_api_session.cc b/shell/browser/api/electron_api_session.cc index 2bb6795d66d49..7514a8eca1f8a 100644 --- a/shell/browser/api/electron_api_session.cc +++ b/shell/browser/api/electron_api_session.cc @@ -19,6 +19,7 @@ #include "base/files/file_util.h" #include "base/scoped_observation.h" #include "base/strings/string_util.h" +#include "base/types/pass_key.h" #include "base/uuid.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/predictors/predictors_traffic_annotations.h" // nogncheck @@ -586,6 +587,7 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context) if (auto* service = SpellcheckServiceFactory::GetForContext(browser_context)) { service->SetHunspellObserver(this); + service->InitializeDictionaries(base::DoNothing()); } #endif } @@ -815,27 +817,33 @@ void Session::SetDownloadPath(const base::FilePath& path) { } void Session::EnableNetworkEmulation(const gin_helper::Dictionary& options) { - auto conditions = network::mojom::NetworkConditions::New(); - - options.Get("offline", &conditions->offline); - options.Get("downloadThroughput", &conditions->download_throughput); - options.Get("uploadThroughput", &conditions->upload_throughput); + std::vector<network::mojom::MatchedNetworkConditionsPtr> matched_conditions; + network::mojom::MatchedNetworkConditionsPtr network_conditions = + network::mojom::MatchedNetworkConditions::New(); + network_conditions->conditions = network::mojom::NetworkConditions::New(); + options.Get("offline", &network_conditions->conditions->offline); + options.Get("downloadThroughput", + &network_conditions->conditions->download_throughput); + options.Get("uploadThroughput", + &network_conditions->conditions->upload_throughput); double latency = 0.0; if (options.Get("latency", &latency) && latency) { - conditions->latency = base::Milliseconds(latency); + network_conditions->conditions->latency = base::Milliseconds(latency); } + matched_conditions.emplace_back(std::move(network_conditions)); auto* network_context = browser_context_->GetDefaultStoragePartition()->GetNetworkContext(); network_context->SetNetworkConditions(network_emulation_token_, - std::move(conditions)); + std::move(matched_conditions)); } void Session::DisableNetworkEmulation() { auto* network_context = browser_context_->GetDefaultStoragePartition()->GetNetworkContext(); - network_context->SetNetworkConditions( - network_emulation_token_, network::mojom::NetworkConditions::New()); + std::vector<network::mojom::MatchedNetworkConditionsPtr> network_conditions; + network_context->SetNetworkConditions(network_emulation_token_, + std::move(network_conditions)); } void Session::SetCertVerifyProc(v8::Local<v8::Value> val, @@ -878,6 +886,24 @@ void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val, blink::PermissionType permission_type, ElectronPermissionManager::StatusCallback callback, const base::Value& details) { +#if (BUILDFLAG(IS_MAC)) + if (permission_type == blink::PermissionType::GEOLOCATION) { + if (ElectronPermissionManager:: + IsGeolocationDisabledViaCommandLine()) { + auto original_callback = std::move(callback); + callback = base::BindOnce( + [](ElectronPermissionManager::StatusCallback callback, + content::PermissionResult /*ignored_result*/) { + // Always deny regardless of what + // content::PermissionResult is passed here + std::move(callback).Run(content::PermissionResult( + blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED)); + }, + std::move(original_callback)); + } + } +#endif handler->Run(web_contents, permission_type, std::move(callback), details); }, @@ -1352,20 +1378,17 @@ v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) { return service_worker_context_.Get(isolate); } -v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) { - if (web_request_.IsEmptyThreadSafe()) { - auto handle = WebRequest::Create(isolate, browser_context()); - web_request_.Reset(isolate, handle.ToV8()); - } - return web_request_.Get(isolate); +WebRequest* Session::WebRequest(v8::Isolate* isolate) { + if (!web_request_) + web_request_ = WebRequest::Create(isolate, base::PassKey<Session>{}); + return web_request_; } -v8::Local<v8::Value> Session::NetLog(v8::Isolate* isolate) { - if (net_log_.IsEmptyThreadSafe()) { - auto handle = NetLog::Create(isolate, browser_context()); - net_log_.Reset(isolate, handle.ToV8()); +NetLog* Session::NetLog(v8::Isolate* isolate) { + if (!net_log_) { + net_log_ = NetLog::Create(isolate, browser_context()); } - return net_log_.Get(isolate); + return net_log_; } static void StartPreconnectOnUI(ElectronBrowserContext* browser_context, @@ -1466,9 +1489,8 @@ v8::Local<v8::Promise> Session::ClearCodeCaches( return handle; } -v8::Local<v8::Value> Session::ClearData(gin_helper::ErrorThrower thrower, - gin::Arguments* args) { - auto* isolate = JavascriptEnvironment::GetIsolate(); +v8::Local<v8::Value> Session::ClearData(gin::Arguments* const args) { + v8::Isolate* const isolate = JavascriptEnvironment::GetIsolate(); BrowsingDataRemover::DataType data_type_mask = kClearDataTypeAll; std::vector<url::Origin> origins; @@ -1498,7 +1520,7 @@ v8::Local<v8::Value> Session::ClearData(gin_helper::ErrorThrower thrower, options.Get("excludeOrigins", &exclude_origin_urls); if (has_origins_key && has_exclude_origins_key) { - thrower.ThrowError( + args->ThrowTypeError( "Cannot provide both 'origins' and 'excludeOrigins'"); return v8::Undefined(isolate); } @@ -1517,7 +1539,7 @@ v8::Local<v8::Value> Session::ClearData(gin_helper::ErrorThrower thrower, // Opaque origins cannot be used with this API if (origin.opaque()) { - thrower.ThrowError(absl::StrFormat( + args->ThrowTypeError(absl::StrFormat( "Invalid origin: '%s'", origin_url.possibly_invalid_spec())); return v8::Undefined(isolate); } @@ -1680,8 +1702,17 @@ gin::WeakCell<Session>* Session::FromBrowserContext( } // static -Session* Session::CreateFrom(v8::Isolate* isolate, - ElectronBrowserContext* browser_context) { +Session* Session::FromOrCreate(v8::Isolate* isolate, + content::BrowserContext* context) { + if (ElectronBrowserContext::IsValidContext(context)) + return FromOrCreate(isolate, static_cast<ElectronBrowserContext*>(context)); + DCHECK(false); + return {}; +} + +// static +Session* Session::FromOrCreate(v8::Isolate* isolate, + ElectronBrowserContext* browser_context) { gin::WeakCell<Session>* existing = FromBrowserContext(browser_context); if (existing && existing->Get()) { return existing->Get(); @@ -1697,14 +1728,11 @@ Session* Session::CreateFrom(v8::Isolate* isolate, return nullptr; } - { - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Object> wrapper; - if (!session->GetWrapper(isolate).ToLocal(&wrapper)) { - return nullptr; - } - App::Get()->EmitWithoutEvent("session-created", wrapper); + v8::Local<v8::Object> wrapper; + if (!session->GetWrapper(isolate).ToLocal(&wrapper)) { + return nullptr; } + App::Get()->EmitWithoutEvent("session-created", wrapper); return session; } @@ -1725,7 +1753,7 @@ Session* Session::FromPartition(v8::Isolate* isolate, browser_context = ElectronBrowserContext::From(partition, true, std::move(options)); } - return CreateFrom(isolate, browser_context); + return FromOrCreate(isolate, browser_context); } // static @@ -1746,7 +1774,7 @@ Session* Session::FromPath(gin::Arguments* args, browser_context = ElectronBrowserContext::FromPath(std::move(path), std::move(options)); - return CreateFrom(args->isolate(), browser_context); + return FromOrCreate(args->isolate(), browser_context); } // static @@ -1871,49 +1899,24 @@ namespace { using electron::api::Session; -v8::Local<v8::Value> FromPartition(const std::string& partition, - gin::Arguments* args) { +Session* FromPartition(const std::string& partition, gin::Arguments* args) { if (!electron::Browser::Get()->is_ready()) { args->ThrowTypeError("Session can only be received when app is ready"); - return v8::Null(args->isolate()); + return {}; } base::Value::Dict options; args->GetNext(&options); - Session* session = - Session::FromPartition(args->isolate(), partition, std::move(options)); - - if (session) { - v8::HandleScope handle_scope(args->isolate()); - v8::Local<v8::Object> wrapper; - if (!session->GetWrapper(args->isolate()).ToLocal(&wrapper)) { - return v8::Null(args->isolate()); - } - return wrapper; - } else { - return v8::Null(args->isolate()); - } + return Session::FromPartition(args->isolate(), partition, std::move(options)); } -v8::Local<v8::Value> FromPath(const base::FilePath& path, - gin::Arguments* args) { +Session* FromPath(const base::FilePath& path, gin::Arguments* args) { if (!electron::Browser::Get()->is_ready()) { args->ThrowTypeError("Session can only be received when app is ready"); - return v8::Null(args->isolate()); + return {}; } base::Value::Dict options; args->GetNext(&options); - Session* session = Session::FromPath(args, path, std::move(options)); - - if (session) { - v8::HandleScope handle_scope(args->isolate()); - v8::Local<v8::Object> wrapper; - if (!session->GetWrapper(args->isolate()).ToLocal(&wrapper)) { - return v8::Null(args->isolate()); - } - return wrapper; - } else { - return v8::Null(args->isolate()); - } + return Session::FromPath(args, path, std::move(options)); } void Initialize(v8::Local<v8::Object> exports, diff --git a/shell/browser/api/electron_api_session.h b/shell/browser/api/electron_api_session.h index 822603fa14ce6..58c28b9dab1e0 100644 --- a/shell/browser/api/electron_api_session.h +++ b/shell/browser/api/electron_api_session.h @@ -60,6 +60,9 @@ struct PreloadScript; namespace api { +class NetLog; +class WebRequest; + class Session final : public gin::Wrappable<Session>, public gin_helper::Constructible<Session>, public gin_helper::EventEmitterMixin<Session>, @@ -71,8 +74,14 @@ class Session final : public gin::Wrappable<Session>, private content::DownloadManager::Observer { public: // Gets or creates Session from the |browser_context|. - static Session* CreateFrom(v8::Isolate* isolate, - ElectronBrowserContext* browser_context); + static Session* FromOrCreate(v8::Isolate* isolate, + ElectronBrowserContext* browser_context); + + // Convenience wrapper around the previous method: Checks that + // |browser_context| is an ElectronBrowserContext before downcasting. + static Session* FromOrCreate(v8::Isolate* isolate, + content::BrowserContext* browser_context); + static void New(); // Dummy, do not use! static gin::WeakCell<Session>* FromBrowserContext( @@ -161,15 +170,14 @@ class Session final : public gin::Wrappable<Session>, v8::Local<v8::Value> Extensions(v8::Isolate* isolate); v8::Local<v8::Value> Protocol(v8::Isolate* isolate); v8::Local<v8::Value> ServiceWorkerContext(v8::Isolate* isolate); - v8::Local<v8::Value> WebRequest(v8::Isolate* isolate); - v8::Local<v8::Value> NetLog(v8::Isolate* isolate); + WebRequest* WebRequest(v8::Isolate* isolate); + api::NetLog* NetLog(v8::Isolate* isolate); void Preconnect(const gin_helper::Dictionary& options, gin::Arguments* args); v8::Local<v8::Promise> CloseAllConnections(); v8::Local<v8::Value> GetPath(v8::Isolate* isolate); void SetCodeCachePath(gin::Arguments* args); v8::Local<v8::Promise> ClearCodeCaches(const gin_helper::Dictionary& options); - v8::Local<v8::Value> ClearData(gin_helper::ErrorThrower thrower, - gin::Arguments* args); + v8::Local<v8::Value> ClearData(gin::Arguments* args); #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) base::Value GetSpellCheckerLanguages(); void SetSpellCheckerLanguages(gin_helper::ErrorThrower thrower, @@ -208,9 +216,9 @@ class Session final : public gin::Wrappable<Session>, v8::TracedReference<v8::Value> cookies_; v8::TracedReference<v8::Value> extensions_; v8::TracedReference<v8::Value> protocol_; - v8::TracedReference<v8::Value> net_log_; + cppgc::Member<api::NetLog> net_log_; v8::TracedReference<v8::Value> service_worker_context_; - v8::TracedReference<v8::Value> web_request_; + cppgc::Member<api::WebRequest> web_request_; raw_ptr<v8::Isolate> isolate_; diff --git a/shell/browser/api/electron_api_system_preferences.cc b/shell/browser/api/electron_api_system_preferences.cc index ca3c95775973a..52ac57acd0ab8 100644 --- a/shell/browser/api/electron_api_system_preferences.cc +++ b/shell/browser/api/electron_api_system_preferences.cc @@ -7,10 +7,15 @@ #include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" -#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/handle.h" #include "shell/common/node_includes.h" #include "ui/gfx/animation/animation.h" +#if BUILDFLAG(IS_LINUX) +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "shell/browser/api/electron_api_system_preferences.h" +#include "shell/common/color_util.h" +#endif namespace electron::api { @@ -21,6 +26,11 @@ gin::DeprecatedWrapperInfo SystemPreferences::kWrapperInfo = { SystemPreferences::SystemPreferences() { InitializeWindow(); } +#elif BUILDFLAG(IS_LINUX) +SystemPreferences::SystemPreferences() + : ui_theme_(ui::NativeTheme::GetInstanceForNativeUi()) { + ui_theme_->AddObserver(this); +} #else SystemPreferences::SystemPreferences() = default; #endif @@ -45,6 +55,29 @@ v8::Local<v8::Value> SystemPreferences::GetAnimationSettings( return dict.GetHandle(); } +#if BUILDFLAG(IS_LINUX) +std::string SystemPreferences::GetAccentColor() { + auto const color = ui_theme_->user_color(); + if (!color.has_value()) + return ""; + return ToRGBAHex(*color); +} + +void SystemPreferences::OnNativeThemeUpdatedOnUI() { + auto const new_accent_color = GetAccentColor(); + if (current_accent_color_ == new_accent_color) + return; + Emit("accent-color-changed", new_accent_color); + current_accent_color_ = new_accent_color; +} + +void SystemPreferences::OnNativeThemeUpdated(ui::NativeTheme* theme) { + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&SystemPreferences::OnNativeThemeUpdatedOnUI, + base::Unretained(this))); +} +#endif + // static gin_helper::Handle<SystemPreferences> SystemPreferences::Create( v8::Isolate* isolate) { @@ -55,9 +88,9 @@ gin::ObjectTemplateBuilder SystemPreferences::GetObjectTemplateBuilder( v8::Isolate* isolate) { return gin_helper::EventEmitterMixin< SystemPreferences>::GetObjectTemplateBuilder(isolate) + .SetMethod("getAccentColor", &SystemPreferences::GetAccentColor) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) .SetMethod("getColor", &SystemPreferences::GetColor) - .SetMethod("getAccentColor", &SystemPreferences::GetAccentColor) .SetMethod("getMediaAccessStatus", &SystemPreferences::GetMediaAccessStatus) #endif diff --git a/shell/browser/api/electron_api_system_preferences.h b/shell/browser/api/electron_api_system_preferences.h index 7582a68faec12..442f2e2c1100f 100644 --- a/shell/browser/api/electron_api_system_preferences.h +++ b/shell/browser/api/electron_api_system_preferences.h @@ -8,14 +8,20 @@ #include <memory> #include <string> +#include "base/functional/bind.h" #include "base/values.h" #include "shell/browser/event_emitter_mixin.h" #include "shell/common/gin_helper/wrappable.h" #if BUILDFLAG(IS_WIN) +#include "base/callback_list.h" #include "shell/browser/browser.h" #include "shell/browser/browser_observer.h" -#include "ui/gfx/sys_color_change_listener.h" +#endif +#if BUILDFLAG(IS_LINUX) +#include "base/memory/raw_ptr.h" +#include "ui/native_theme/native_theme.h" +#include "ui/native_theme/native_theme_observer.h" #endif namespace gin_helper { @@ -42,8 +48,10 @@ class SystemPreferences final public gin_helper::EventEmitterMixin<SystemPreferences> #if BUILDFLAG(IS_WIN) , - public BrowserObserver, - public gfx::SysColorChangeListener + public BrowserObserver +#elif BUILDFLAG(IS_LINUX) + , + public ui::NativeThemeObserver #endif { public: @@ -55,8 +63,8 @@ class SystemPreferences final v8::Isolate* isolate) override; const char* GetTypeName() override; + std::string GetAccentColor(); #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - static std::string GetAccentColor(); std::string GetColor(gin_helper::ErrorThrower thrower, const std::string& color); std::string GetMediaAccessStatus(gin_helper::ErrorThrower thrower, @@ -65,8 +73,8 @@ class SystemPreferences final #if BUILDFLAG(IS_WIN) void InitializeWindow(); - // gfx::SysColorChangeListener: - void OnSysColorChange() override; + // Called by `hwnd_subscription_`. + void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); // BrowserObserver: void OnFinishLaunching(base::Value::Dict launch_info) override; @@ -117,6 +125,10 @@ class SystemPreferences final // TODO(MarshallOfSound): Write tests for these methods once we // are running tests on a Mojave machine v8::Local<v8::Value> GetEffectiveAppearance(v8::Isolate* isolate); + +#elif BUILDFLAG(IS_LINUX) + // ui::NativeThemeObserver: + void OnNativeThemeUpdated(ui::NativeTheme* theme) override; #endif v8::Local<v8::Value> GetAnimationSettings(v8::Isolate* isolate); @@ -159,7 +171,14 @@ class SystemPreferences final std::string current_color_; - std::unique_ptr<gfx::ScopedSysColorChangeListener> color_change_listener_; + // Color/high contrast mode change observer. + base::CallbackListSubscription hwnd_subscription_; +#endif +#if BUILDFLAG(IS_LINUX) + void OnNativeThemeUpdatedOnUI(); + + raw_ptr<ui::NativeTheme> ui_theme_; + std::string current_accent_color_; #endif }; diff --git a/shell/browser/api/electron_api_system_preferences_mac.mm b/shell/browser/api/electron_api_system_preferences_mac.mm index 582b7bc74fc0d..f0f39f43b91fb 100644 --- a/shell/browser/api/electron_api_system_preferences_mac.mm +++ b/shell/browser/api/electron_api_system_preferences_mac.mm @@ -14,6 +14,7 @@ #include "base/apple/scoped_cftyperef.h" #include "base/containers/flat_map.h" +#include "base/no_destructor.h" #include "base/strings/sys_string_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" @@ -80,7 +81,10 @@ static bool FromV8(v8::Isolate* isolate, int g_next_id = 0; // The map to convert |id| to |int|. -base::flat_map<int, id> g_id_map; +auto& GetIdMap() { + static base::NoDestructor<base::flat_map<int, id>> g_id_map; + return *g_id_map; +} AVMediaType ParseMediaType(const std::string& media_type) { if (media_type == "camera") { @@ -214,7 +218,7 @@ AVMediaType ParseMediaType(const std::string& media_type) { auto* name = maybe_name->IsNull() ? nil : base::SysUTF8ToNSString(name_str); - g_id_map[request_id] = [GetNotificationCenter(kind) + GetIdMap()[request_id] = [GetNotificationCenter(kind) addObserverForName:name object:nil queue:nil @@ -240,11 +244,11 @@ AVMediaType ParseMediaType(const std::string& media_type) { void SystemPreferences::DoUnsubscribeNotification(int request_id, NotificationCenterKind kind) { - auto iter = g_id_map.find(request_id); - if (iter != g_id_map.end()) { + auto iter = GetIdMap().find(request_id); + if (iter != GetIdMap().end()) { id observer = iter->second; [GetNotificationCenter(kind) removeObserver:observer]; - g_id_map.erase(iter); + GetIdMap().erase(iter); } } @@ -363,13 +367,11 @@ AVMediaType ParseMediaType(const std::string& media_type) { } } } else { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError("Invalid type: " + type); + args->ThrowTypeError("Invalid type: " + type); return; } - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError("Unable to convert value to: " + type); + args->ThrowTypeError("Unable to convert value to: " + type); } std::string SystemPreferences::GetAccentColor() { diff --git a/shell/browser/api/electron_api_system_preferences_win.cc b/shell/browser/api/electron_api_system_preferences_win.cc index d03f0f0c3e1ba..46cac9af30517 100644 --- a/shell/browser/api/electron_api_system_preferences_win.cc +++ b/shell/browser/api/electron_api_system_preferences_win.cc @@ -16,8 +16,9 @@ #include "base/win/wrapped_window_proc.h" #include "shell/common/color_util.h" #include "shell/common/process_util.h" -#include "ui/gfx/color_utils.h" +#include "skia/ext/skia_utils_win.h" #include "ui/gfx/win/hwnd_util.h" +#include "ui/gfx/win/singleton_hwnd.h" namespace electron { @@ -88,7 +89,7 @@ std::string SystemPreferences::GetAccentColor() { if (!color.has_value()) return ""; - return hexColorDWORDToRGBA(color.value()); + return ToRGBAHex(skia::COLORREFToSkColor(color.value()), false); } std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower, @@ -127,7 +128,7 @@ std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower, }); if (auto iter = Lookup.find(color); iter != Lookup.end()) - return ToRGBAHex(color_utils::GetSysSkColor(iter->second)); + return ToRGBAHex(GetSysSkColor(iter->second)); thrower.ThrowError("Unknown color: " + color); return ""; @@ -158,8 +159,9 @@ void SystemPreferences::InitializeWindow() { // Creating this listener before the app is ready causes global shortcuts // to not fire if (Browser::Get()->is_ready()) - color_change_listener_ = - std::make_unique<gfx::ScopedSysColorChangeListener>(this); + hwnd_subscription_ = + gfx::SingletonHwnd::GetInstance()->RegisterCallback(base::BindRepeating( + &SystemPreferences::OnWndProc, base::Unretained(this))); else Browser::Get()->AddObserver(this); @@ -208,13 +210,21 @@ LRESULT CALLBACK SystemPreferences::WndProc(HWND hwnd, return ::DefWindowProc(hwnd, message, wparam, lparam); } -void SystemPreferences::OnSysColorChange() { +void SystemPreferences::OnWndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + if (message != WM_SYSCOLORCHANGE && + (message != WM_SETTINGCHANGE || wparam != SPI_SETHIGHCONTRAST)) { + return; + } Emit("color-changed"); } void SystemPreferences::OnFinishLaunching(base::Value::Dict launch_info) { - color_change_listener_ = - std::make_unique<gfx::ScopedSysColorChangeListener>(this); + hwnd_subscription_ = + gfx::SingletonHwnd::GetInstance()->RegisterCallback(base::BindRepeating( + &SystemPreferences::OnWndProc, base::Unretained(this))); } } // namespace api diff --git a/shell/browser/api/electron_api_utility_process.cc b/shell/browser/api/electron_api_utility_process.cc index fe6bde85eecc3..2fa5bb17503a4 100644 --- a/shell/browser/api/electron_api_utility_process.cc +++ b/shell/browser/api/electron_api_utility_process.cc @@ -26,7 +26,6 @@ #include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_helper/dictionary.h" -#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/handle.h" #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" @@ -133,6 +132,7 @@ UtilityProcessWrapper::UtilityProcessWrapper( OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { PLOG(ERROR) << "Failed to create null handle"; + Emit("error", "Failed to create null handle for ignoring stdio"); return; } if (io_handle == IOHandle::STDOUT) { @@ -329,17 +329,17 @@ void UtilityProcessWrapper::Shutdown(uint64_t exit_code) { HandleTermination(exit_code); } -void UtilityProcessWrapper::PostMessage(gin::Arguments* args) { +void UtilityProcessWrapper::PostMessage(gin::Arguments* const args) { if (!node_service_remote_.is_connected()) return; blink::TransferableMessage transferable_message; - gin_helper::ErrorThrower thrower(args->isolate()); + v8::Isolate* const isolate = args->isolate(); // |message| is any value that can be serialized to StructuredClone. v8::Local<v8::Value> message_value; if (args->GetNext(&message_value)) { - if (!electron::SerializeV8Value(args->isolate(), message_value, + if (!electron::SerializeV8Value(isolate, message_value, &transferable_message)) { // SerializeV8Value sets an exception. return; @@ -350,31 +350,30 @@ void UtilityProcessWrapper::PostMessage(gin::Arguments* args) { std::vector<gin_helper::Handle<MessagePort>> wrapped_ports; if (args->GetNext(&transferables)) { std::vector<v8::Local<v8::Value>> wrapped_port_values; - if (!gin::ConvertFromV8(args->isolate(), transferables, - &wrapped_port_values)) { - thrower.ThrowTypeError("transferables must be an array of MessagePorts"); + if (!gin::ConvertFromV8(isolate, transferables, &wrapped_port_values)) { + args->ThrowTypeError("transferables must be an array of MessagePorts"); return; } for (size_t i = 0; i < wrapped_port_values.size(); ++i) { if (!gin_helper::IsValidWrappable(wrapped_port_values[i], &MessagePort::kWrapperInfo)) { - thrower.ThrowTypeError( + args->ThrowTypeError( base::StrCat({"Port at index ", base::NumberToString(i), " is not a valid port"})); return; } } - if (!gin::ConvertFromV8(args->isolate(), transferables, &wrapped_ports)) { - thrower.ThrowTypeError("Passed an invalid MessagePort"); + if (!gin::ConvertFromV8(isolate, transferables, &wrapped_ports)) { + args->ThrowTypeError("Passed an invalid MessagePort"); return; } } bool threw_exception = false; - transferable_message.ports = MessagePort::DisentanglePorts( - args->isolate(), wrapped_ports, &threw_exception); + transferable_message.ports = + MessagePort::DisentanglePorts(isolate, wrapped_ports, &threw_exception); if (threw_exception) return; @@ -436,11 +435,10 @@ raw_ptr<UtilityProcessWrapper> UtilityProcessWrapper::FromProcessId( // static gin_helper::Handle<UtilityProcessWrapper> UtilityProcessWrapper::Create( - gin::Arguments* args) { + gin::Arguments* const args) { if (!Browser::Get()->is_ready()) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError( - "utilityProcess cannot be created before app is ready."); + args->ThrowTypeError( + "utilityProcess cannot be created before app is ready."); return {}; } diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index a0cba67673ef6..d886665a51c3a 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -551,17 +551,17 @@ base::IDMap<WebContents*>& GetAllWebContents() { void OnCapturePageDone(gin_helper::Promise<gfx::Image> promise, base::ScopedClosureRunner capture_handle, - const SkBitmap& bitmap) { + const viz::CopyOutputBitmapWithMetadata& result) { auto ui_task_runner = content::GetUIThreadTaskRunner({}); if (!ui_task_runner->RunsTasksInCurrentSequence()) { ui_task_runner->PostTask( FROM_HERE, base::BindOnce(&OnCapturePageDone, std::move(promise), - std::move(capture_handle), bitmap)); + std::move(capture_handle), result)); return; } // Hack to enable transparency in captured image - promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap)); + promise.Resolve(gfx::Image::CreateFrom1xBitmap(result.bitmap)); capture_handle.RunAndReset(); } @@ -572,8 +572,8 @@ std::optional<base::TimeDelta> GetCursorBlinkInterval() { if (system_value) return *system_value; #elif BUILDFLAG(IS_LINUX) - if (auto* linux_ui = ui::LinuxUi::instance()) - return linux_ui->GetCursorBlinkInterval(); + if (auto* native_theme = ui::NativeTheme::GetInstanceForNativeUi()) + return native_theme->caret_blink_interval(); #elif BUILDFLAG(IS_WIN) const auto system_msec = ::GetCaretBlinkTime(); if (system_msec != 0) { @@ -754,7 +754,7 @@ WebContents::WebContents(v8::Isolate* isolate, script_executor_ = std::make_unique<extensions::ScriptExecutor>(web_contents); #endif - session_ = Session::CreateFrom(isolate, GetBrowserContext()); + session_ = Session::FromOrCreate(isolate, GetBrowserContext()); SetUserAgent(GetBrowserContext()->GetUserAgent()); @@ -776,7 +776,7 @@ WebContents::WebContents(v8::Isolate* isolate, { DCHECK(type != Type::kRemote) << "Can't take ownership of a remote WebContents"; - session_ = Session::CreateFrom(isolate, GetBrowserContext()); + session_ = Session::FromOrCreate(isolate, GetBrowserContext()); InitWithSessionAndOptions(isolate, std::move(web_contents), session_->browser_context(), gin::Dictionary::CreateEmpty(isolate)); @@ -814,6 +814,8 @@ WebContents::WebContents(v8::Isolate* isolate, options.Get(options::kOffscreen, &use_offscreen_dict); use_offscreen_dict.Get(options::kUseSharedTexture, &offscreen_use_shared_texture_); + use_offscreen_dict.Get(options::kSharedTexturePixelFormat, + &offscreen_shared_texture_pixel_format_); } } @@ -851,6 +853,7 @@ WebContents::WebContents(v8::Isolate* isolate, if (embedder_ && embedder_->IsOffScreen()) { auto* view = new OffScreenWebContentsView( false, offscreen_use_shared_texture_, + offscreen_shared_texture_pixel_format_, base::BindRepeating(&WebContents::OnPaint, base::Unretained(this))); params.view = view; params.delegate_view = view; @@ -872,6 +875,7 @@ WebContents::WebContents(v8::Isolate* isolate, content::WebContents::CreateParams params(session->browser_context()); auto* view = new OffScreenWebContentsView( transparent, offscreen_use_shared_texture_, + offscreen_shared_texture_pixel_format_, base::BindRepeating(&WebContents::OnPaint, base::Unretained(this))); params.view = view; params.delegate_view = view; @@ -1229,6 +1233,7 @@ void WebContents::MaybeOverrideCreateParamsForNewWindow( if (is_offscreen) { auto* view = new OffScreenWebContentsView( false, offscreen_use_shared_texture_, + offscreen_shared_texture_pixel_format_, base::BindRepeating(&WebContents::OnPaint, base::Unretained(this))); create_params->view = view; create_params->delegate_view = view; @@ -1434,7 +1439,7 @@ bool WebContents::IsFullscreen() const { void WebContents::EnterFullscreen(const url::Origin& origin, ExclusiveAccessBubbleType bubble_type, - const int64_t display_id) {} + FullscreenTabParams fullscreen_tab_params) {} content::WebContents* WebContents::GetWebContentsForExclusiveAccess() { return web_contents(); @@ -1480,7 +1485,7 @@ void WebContents::OnEnterFullscreenModeForTab( owner_window()->set_fullscreen_transition_type( NativeWindow::FullScreenTransitionType::kHTML); exclusive_access_manager_.fullscreen_controller()->EnterFullscreenModeForTab( - requesting_frame, options.display_id); + requesting_frame, FullscreenTabParams{options.display_id}); SetHtmlApiFullscreen(true); @@ -1765,14 +1770,15 @@ void WebContents::RenderFrameCreated( return; } - content::RenderFrameHost::LifecycleState lifecycle_state = - render_frame_host->GetLifecycleState(); - if (lifecycle_state == content::RenderFrameHost::LifecycleState::kActive) { + if (render_frame_host->GetLifecycleState() == + content::RenderFrameHost::LifecycleState::kActive) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::HandleScope handle_scope(isolate); + v8::HandleScope handle_scope{isolate}; auto details = gin_helper::Dictionary::CreateEmpty(isolate); details.SetGetter("frame", render_frame_host); Emit("frame-created", details); + content::WebContents::FromRenderFrameHost(render_frame_host) + ->SetSupportsDraggableRegions(true); } } @@ -2255,7 +2261,8 @@ void WebContents::WebContentsDestroyed() { v8::Local<v8::Object> wrapper; if (!GetWrapper(isolate).ToLocal(&wrapper)) return; - wrapper->SetAlignedPointerInInternalField(0, nullptr); + wrapper->SetAlignedPointerInInternalField(0, nullptr, + v8::kEmbedderDataTypeTagDefault); // Tell WebViewGuestDelegate that the WebContents has been destroyed. if (guest_delegate_) @@ -2298,7 +2305,7 @@ void WebContents::SetBackgroundThrottling(bool allowed) { rwh_impl->disable_hidden_ = !background_throttling_; web_contents()->GetRenderViewHost()->SetSchedulerThrottling(allowed); - if (rwh_impl->is_hidden()) { + if (rwh_impl->IsHidden()) { rwh_impl->WasShown({}); } } @@ -2835,7 +2842,8 @@ void WebContents::EnableDeviceEmulation( frame_host->GetView()->GetRenderWidgetHost()); if (widget_host_impl) { auto& frame_widget = widget_host_impl->GetAssociatedFrameWidget(); - frame_widget->EnableDeviceEmulation(params); + frame_widget->EnableDeviceEmulation( + params, blink::mojom::DeviceEmulationCacheBehavior::kClearCache); } } } @@ -3031,23 +3039,24 @@ void OnPDFCreated(gin_helper::Promise<v8::Local<v8::Value>> promise, } } // namespace -void WebContents::Print(gin::Arguments* args) { - auto options = gin_helper::Dictionary::CreateEmpty(args->isolate()); - base::Value::Dict settings; +void WebContents::Print(gin::Arguments* const args) { + v8::Isolate* const isolate = args->isolate(); + auto options = gin_helper::Dictionary::CreateEmpty(isolate); if (args->Length() >= 1 && !args->GetNext(&options)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("webContents.print(): Invalid print settings specified."); + args->ThrowTypeError( + "webContents.print(): Invalid print settings specified."); return; } printing::CompletionCallback callback; if (args->Length() == 2 && !args->GetNext(&callback)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("webContents.print(): Invalid optional callback provided."); + args->ThrowTypeError( + "webContents.print(): Invalid optional callback provided."); return; } + base::Value::Dict settings; if (options.IsEmptyObject()) { content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents()); if (!rfh) @@ -3069,7 +3078,7 @@ void WebContents::Print(gin::Arguments* args) { options.ValueOrDefault("printBackground", false)); // Set custom margin settings - auto margins = gin_helper::Dictionary::CreateEmpty(args->isolate()); + auto margins = gin_helper::Dictionary::CreateEmpty(isolate); if (options.Get("margins", &margins)) { printing::mojom::MarginType margin_type = printing::mojom::MarginType::kDefaultMargins; @@ -3259,21 +3268,19 @@ v8::Local<v8::Promise> WebContents::PrintToPDF(const base::Value& settings) { } #endif -void WebContents::AddWorkSpace(gin::Arguments* args, +void WebContents::AddWorkSpace(v8::Isolate* const isolate, const base::FilePath& path) { if (path.empty()) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("path cannot be empty"); + gin_helper::ErrorThrower{isolate}.ThrowError("path cannot be empty"); return; } DevToolsAddFileSystem(std::string(), path); } -void WebContents::RemoveWorkSpace(gin::Arguments* args, +void WebContents::RemoveWorkSpace(v8::Isolate* const isolate, const base::FilePath& path) { if (path.empty()) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("path cannot be empty"); + gin_helper::ErrorThrower{isolate}.ThrowError("path cannot be empty"); return; } DevToolsRemoveFileSystem(path); @@ -3351,11 +3358,10 @@ void WebContents::ReplaceMisspelling(const std::u16string& word) { web_contents()->ReplaceMisspelling(word); } -uint32_t WebContents::FindInPage(gin::Arguments* args) { +uint32_t WebContents::FindInPage(gin::Arguments* const args) { std::u16string search_text; if (!args->GetNext(&search_text) || search_text.empty()) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("Must provide a non-empty search content"); + args->ThrowTypeError("Must provide a non-empty search content"); return 0; } @@ -3508,8 +3514,8 @@ void WebContents::EndFrameSubscription() { frame_subscriber_.reset(); } -void WebContents::StartDrag(const gin_helper::Dictionary& item, - gin::Arguments* args) { +void WebContents::StartDrag(v8::Isolate* const isolate, + const gin_helper::Dictionary& item) { base::FilePath file; std::vector<base::FilePath> files; if (!item.Get("files", &files) && item.Get("file", &file)) { @@ -3518,13 +3524,13 @@ void WebContents::StartDrag(const gin_helper::Dictionary& item, v8::Local<v8::Value> icon_value; if (!item.Get("icon", &icon_value)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("'icon' parameter is required"); + gin_helper::ErrorThrower{isolate}.ThrowError( + "'icon' parameter is required"); return; } NativeImage* icon = nullptr; - if (!NativeImage::TryConvertNativeImage(args->isolate(), icon_value, &icon) || + if (!NativeImage::TryConvertNativeImage(isolate, icon_value, &icon) || icon->image().IsEmpty()) { return; } @@ -3534,8 +3540,8 @@ void WebContents::StartDrag(const gin_helper::Dictionary& item, base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow; DragFileItems(files, icon->image(), web_contents()->GetNativeView()); } else { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("Must specify either 'file' or 'files' option"); + gin_helper::ErrorThrower{isolate}.ThrowError( + "Must specify either 'file' or 'files' option"); } } @@ -3580,7 +3586,7 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) { // current system, increase the requested bitmap size to capture it all. gfx::Size bitmap_size = view_size; const gfx::NativeView native_view = view->GetNativeView(); - const float scale = display::Screen::GetScreen() + const float scale = display::Screen::Get() ->GetDisplayNearestView(native_view) .device_scale_factor(); if (scale > 1.0f) @@ -3758,7 +3764,6 @@ v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow( } v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) { - v8::HandleScope handle_scope(isolate); v8::Local<v8::Object> wrapper; if (!session_->GetWrapper(isolate).ToLocal(&wrapper)) { return v8::Null(isolate); @@ -3804,11 +3809,15 @@ v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) { } v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) { - if (debugger_.IsEmpty()) { - auto handle = electron::api::Debugger::Create(isolate, web_contents()); - debugger_.Reset(isolate, handle.ToV8()); + if (!debugger_) { + debugger_ = electron::api::Debugger::Create(isolate, web_contents()); } - return v8::Local<v8::Value>::New(isolate, debugger_); + + v8::Local<v8::Object> wrapper; + if (!debugger_->GetWrapper(isolate).ToLocal(&wrapper)) { + return v8::Null(isolate); + } + return v8::Local<v8::Value>::New(isolate, wrapper); } content::RenderFrameHost* WebContents::MainFrame() { @@ -4196,8 +4205,8 @@ void WebContents::DevToolsIndexPath( return; std::vector<std::string> excluded_folders; - std::optional<base::Value> parsed_excluded_folders = - base::JSONReader::Read(excluded_folders_message); + std::optional<base::Value> parsed_excluded_folders = base::JSONReader::Read( + excluded_folders_message, base::JSON_PARSE_CHROMIUM_EXTENSIONS); if (parsed_excluded_folders && parsed_excluded_folders->is_list()) { for (const base::Value& folder_path : parsed_excluded_folders->GetList()) { if (folder_path.is_string()) diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index 9deb95e341d29..ae22cbbf29708 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -31,6 +31,7 @@ #include "content/public/common/stop_find_action.h" #include "electron/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h" +#include "shell/browser/api/electron_api_debugger.h" #include "shell/browser/api/electron_api_session.h" #include "shell/browser/api/save_page_handler.h" #include "shell/browser/background_throttling_source.h" @@ -266,8 +267,8 @@ class WebContents final : public ExclusiveAccessContext, void SetNextChildWebPreferences(const gin_helper::Dictionary); // DevTools workspace api. - void AddWorkSpace(gin::Arguments* args, const base::FilePath& path); - void RemoveWorkSpace(gin::Arguments* args, const base::FilePath& path); + void AddWorkSpace(v8::Isolate* isolate, const base::FilePath& path); + void RemoveWorkSpace(v8::Isolate* isolate, const base::FilePath& path); // Editing commands. void Undo(); @@ -302,7 +303,7 @@ class WebContents final : public ExclusiveAccessContext, void EndFrameSubscription(); // Dragging native items. - void StartDrag(const gin_helper::Dictionary& item, gin::Arguments* args); + void StartDrag(v8::Isolate* isolate, const gin_helper::Dictionary& item); // Captures the page with |rect|, |callback| would be called when capturing is // done. @@ -697,7 +698,7 @@ class WebContents final : public ExclusiveAccessContext, bool IsFullscreen() const override; void EnterFullscreen(const url::Origin& origin, ExclusiveAccessBubbleType bubble_type, - const int64_t display_id) override; + FullscreenTabParams fullscreen_tab_params) override; void ExitFullscreen() override {} void UpdateExclusiveAccessBubble( const ExclusiveAccessBubbleParams& params, @@ -772,7 +773,7 @@ class WebContents final : public ExclusiveAccessContext, cppgc::Persistent<api::Session> session_; v8::Global<v8::Value> devtools_web_contents_; - v8::Global<v8::Value> debugger_; + cppgc::Persistent<api::Debugger> debugger_; std::unique_ptr<WebViewGuestDelegate> guest_delegate_; std::unique_ptr<FrameSubscriber> frame_subscriber_; @@ -816,6 +817,7 @@ class WebContents final : public ExclusiveAccessContext, // Whether offscreen rendering use gpu shared texture bool offscreen_use_shared_texture_ = false; + std::string offscreen_shared_texture_pixel_format_ = "argb"; // Whether window is fullscreened by HTML5 api. bool html_fullscreen_ = false; diff --git a/shell/browser/api/electron_api_web_contents_view.cc b/shell/browser/api/electron_api_web_contents_view.cc index 0b9be9bd55dc9..360d03d050817 100644 --- a/shell/browser/api/electron_api_web_contents_view.cc +++ b/shell/browser/api/electron_api_web_contents_view.cc @@ -153,36 +153,37 @@ v8::Local<v8::Function> WebContentsView::GetConstructor(v8::Isolate* isolate) { } // static -gin_helper::WrappableBase* WebContentsView::New(gin_helper::Arguments* args) { +gin_helper::WrappableBase* WebContentsView::New(gin::Arguments* const args) { + v8::Isolate* const isolate = args->isolate(); gin_helper::Dictionary web_preferences; v8::Local<v8::Value> existing_web_contents_value; { v8::Local<v8::Value> options_value; if (args->GetNext(&options_value)) { gin_helper::Dictionary options; - if (!gin::ConvertFromV8(args->isolate(), options_value, &options)) { - args->ThrowError("options must be an object"); + if (!gin::ConvertFromV8(isolate, options_value, &options)) { + args->ThrowTypeError("options must be an object"); return nullptr; } v8::Local<v8::Value> web_preferences_value; if (options.Get("webPreferences", &web_preferences_value)) { - if (!gin::ConvertFromV8(args->isolate(), web_preferences_value, + if (!gin::ConvertFromV8(isolate, web_preferences_value, &web_preferences)) { - args->ThrowError("options.webPreferences must be an object"); + args->ThrowTypeError("options.webPreferences must be an object"); return nullptr; } } if (options.Get("webContents", &existing_web_contents_value)) { gin_helper::Handle<WebContents> existing_web_contents; - if (!gin::ConvertFromV8(args->isolate(), existing_web_contents_value, + if (!gin::ConvertFromV8(isolate, existing_web_contents_value, &existing_web_contents)) { - args->ThrowError("options.webContents must be a WebContents"); + args->ThrowTypeError("options.webContents must be a WebContents"); return nullptr; } if (existing_web_contents->owner_window() != nullptr) { - args->ThrowError( + args->ThrowTypeError( "options.webContents is already attached to a window"); return nullptr; } @@ -191,7 +192,7 @@ gin_helper::WrappableBase* WebContentsView::New(gin_helper::Arguments* args) { } if (web_preferences.IsEmpty()) - web_preferences = gin_helper::Dictionary::CreateEmpty(args->isolate()); + web_preferences = gin_helper::Dictionary::CreateEmpty(isolate); if (!web_preferences.Has(options::kShow)) web_preferences.Set(options::kShow, false); @@ -200,10 +201,10 @@ gin_helper::WrappableBase* WebContentsView::New(gin_helper::Arguments* args) { } auto web_contents = - WebContents::CreateFromWebPreferences(args->isolate(), web_preferences); + WebContents::CreateFromWebPreferences(isolate, web_preferences); // Constructor call. - auto* view = new WebContentsView(args->isolate(), web_contents); + auto* view = new WebContentsView{isolate, web_contents}; view->InitWithArgs(args); return view; } diff --git a/shell/browser/api/electron_api_web_contents_view.h b/shell/browser/api/electron_api_web_contents_view.h index 51c67231e1176..f04254d30bd04 100644 --- a/shell/browser/api/electron_api_web_contents_view.h +++ b/shell/browser/api/electron_api_web_contents_view.h @@ -57,7 +57,7 @@ class WebContentsView : public View, void OnViewRemovedFromWidget(views::View* view) override; private: - static gin_helper::WrappableBase* New(gin_helper::Arguments* args); + static gin_helper::WrappableBase* New(gin::Arguments* args); void ApplyBorderRadius(); diff --git a/shell/browser/api/electron_api_web_request.cc b/shell/browser/api/electron_api_web_request.cc index b2b0a7f405aa9..814ed1e9b45e9 100644 --- a/shell/browser/api/electron_api_web_request.cc +++ b/shell/browser/api/electron_api_web_request.cc @@ -5,12 +5,14 @@ #include "shell/browser/api/electron_api_web_request.h" #include <memory> +#include <optional> #include <string> #include <string_view> #include <utility> #include "base/containers/fixed_flat_map.h" #include "base/memory/raw_ptr.h" +#include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/values.h" #include "content/public/browser/web_contents.h" @@ -20,11 +22,13 @@ #include "gin/converter.h" #include "gin/dictionary.h" #include "gin/object_template_builder.h" +#include "gin/persistent.h" #include "shell/browser/api/electron_api_session.h" #include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/api/electron_api_web_frame_main.h" #include "shell/browser/electron_browser_context.h" #include "shell/browser/javascript_environment.h" +#include "shell/browser/login_handler.h" #include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/frame_converter.h" #include "shell/common/gin_converters/gurl_converter.h" @@ -72,14 +76,6 @@ namespace electron::api { namespace { -const char kUserDataKey[] = "WebRequest"; - -// BrowserContext <=> WebRequest relationship. -struct UserData : public base::SupportsUserData::Data { - explicit UserData(WebRequest* data) : data(data) {} - raw_ptr<WebRequest> data; -}; - extensions::WebRequestResourceType ParseResourceType(std::string_view value) { if (auto iter = ResourceTypes.find(value); iter != ResourceTypes.end()) return iter->second; @@ -108,7 +104,7 @@ v8::Local<v8::Value> HttpResponseHeadersToV8( // Overloaded by multiple types to fill the |details| object. void ToDictionary(gin_helper::Dictionary* details, - extensions::WebRequestInfo* info) { + const extensions::WebRequestInfo* info) { details->Set("id", info->id); details->Set("url", info->url); details->Set("method", info->method); @@ -209,7 +205,8 @@ CalculateOnBeforeSendHeadersDelta(const net::HttpRequestHeaders* old_headers, } // namespace -gin::DeprecatedWrapperInfo WebRequest::kWrapperInfo = {gin::kEmbedderNativeGin}; +const gin::WrapperInfo WebRequest::kWrapperInfo = {{gin::kEmbedderNativeGin}, + gin::kElectronWebRequest}; WebRequest::RequestFilter::RequestFilter( std::set<URLPattern> include_url_patterns, @@ -255,7 +252,7 @@ bool WebRequest::RequestFilter::MatchesType( } bool WebRequest::RequestFilter::MatchesRequest( - extensions::WebRequestInfo* info) const { + const extensions::WebRequestInfo* info) const { // Matches URL and type, and does not match exclude URL. return MatchesURL(info->url, include_url_patterns_) && !MatchesURL(info->url, exclude_url_patterns_) && @@ -287,6 +284,10 @@ struct WebRequest::BlockedRequest { net::CompletionOnceCallback callback; // Only used for onBeforeSendHeaders. BeforeSendHeadersCallback before_send_headers_callback; + // The callback to invoke for auth. If |auth_callback.is_null()| is false, + // |callback| must be NULL. + // Only valid for OnAuthRequired. + AuthCallback auth_callback; // Only used for onBeforeSendHeaders. raw_ptr<net::HttpRequestHeaders> request_headers = nullptr; // Only used for onHeadersReceived. @@ -297,6 +298,8 @@ struct WebRequest::BlockedRequest { std::string status_line; // Only used for onBeforeRequest. raw_ptr<GURL> new_url = nullptr; + // Owns the LoginHandler while waiting for auth credentials. + std::unique_ptr<LoginHandler> login_handler; }; WebRequest::SimpleListenerInfo::SimpleListenerInfo(RequestFilter filter_, @@ -312,20 +315,12 @@ WebRequest::ResponseListenerInfo::ResponseListenerInfo( WebRequest::ResponseListenerInfo::ResponseListenerInfo() = default; WebRequest::ResponseListenerInfo::~ResponseListenerInfo() = default; -WebRequest::WebRequest(v8::Isolate* isolate, - content::BrowserContext* browser_context) - : browser_context_(browser_context) { - browser_context_->SetUserData(kUserDataKey, std::make_unique<UserData>(this)); -} - -WebRequest::~WebRequest() { - browser_context_->RemoveUserData(kUserDataKey); -} +WebRequest::WebRequest(base::PassKey<Session>) {} +WebRequest::~WebRequest() = default; gin::ObjectTemplateBuilder WebRequest::GetObjectTemplateBuilder( v8::Isolate* isolate) { - return gin_helper::DeprecatedWrappable<WebRequest>::GetObjectTemplateBuilder( - isolate) + return gin::Wrappable<WebRequest>::GetObjectTemplateBuilder(isolate) .SetMethod( "onBeforeRequest", &WebRequest::SetResponseListener<ResponseEvent::kOnBeforeRequest>) @@ -348,8 +343,17 @@ gin::ObjectTemplateBuilder WebRequest::GetObjectTemplateBuilder( &WebRequest::SetSimpleListener<SimpleEvent::kOnCompleted>); } -const char* WebRequest::GetTypeName() { - return GetClassName(); +const gin::WrapperInfo* WebRequest::wrapper_info() const { + return &kWrapperInfo; +} + +const char* WebRequest::GetHumanReadableName() const { + return "Electron / WebRequest"; +} + +void WebRequest::Trace(cppgc::Visitor* visitor) const { + gin::Wrappable<WebRequest>::Trace(visitor); + visitor->Trace(weak_factory_); } bool WebRequest::HasListener() const { @@ -387,20 +391,22 @@ int WebRequest::HandleOnBeforeRequestResponseEvent( gin_helper::Dictionary details(isolate, v8::Object::New(isolate)); FillDetails(&details, request_info, request, *new_url); - ResponseCallback response = - base::BindOnce(&WebRequest::OnBeforeRequestListenerResult, - base::Unretained(this), request_info->id); + auto& allocation_handle = isolate->GetCppHeap()->GetAllocationHandle(); + ResponseCallback response = base::BindOnce( + &WebRequest::OnBeforeRequestListenerResult, + gin::WrapPersistent(weak_factory_.GetWeakCell(allocation_handle)), + request_info->id); info.listener.Run(gin::ConvertToV8(isolate, details), std::move(response)); return net::ERR_IO_PENDING; } void WebRequest::OnBeforeRequestListenerResult(uint64_t id, v8::Local<v8::Value> response) { - const auto iter = blocked_requests_.find(id); - if (iter == std::end(blocked_requests_)) + auto nh = blocked_requests_.extract(id); + if (!nh) return; - auto& request = iter->second; + auto& request = nh.mapped(); int result = net::OK; if (response->IsObject()) { @@ -418,7 +424,6 @@ void WebRequest::OnBeforeRequestListenerResult(uint64_t id, base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(std::move(request.callback), result)); - blocked_requests_.erase(iter); } int WebRequest::OnBeforeSendHeaders(extensions::WebRequestInfo* info, @@ -463,11 +468,11 @@ int WebRequest::HandleOnBeforeSendHeadersResponseEvent( void WebRequest::OnBeforeSendHeadersListenerResult( uint64_t id, v8::Local<v8::Value> response) { - const auto iter = blocked_requests_.find(id); - if (iter == std::end(blocked_requests_)) + auto nh = blocked_requests_.extract(id); + if (!nh) return; - auto& request = iter->second; + auto& request = nh.mapped(); net::HttpRequestHeaders* old_headers = request.request_headers; net::HttpRequestHeaders new_headers; @@ -505,7 +510,6 @@ void WebRequest::OnBeforeSendHeadersListenerResult( FROM_HERE, base::BindOnce(std::move(request.before_send_headers_callback), updated_headers.first, updated_headers.second, result)); - blocked_requests_.erase(iter); } int WebRequest::OnHeadersReceived( @@ -557,11 +561,11 @@ int WebRequest::HandleOnHeadersReceivedResponseEvent( void WebRequest::OnHeadersReceivedListenerResult( uint64_t id, v8::Local<v8::Value> response) { - const auto iter = blocked_requests_.find(id); - if (iter == std::end(blocked_requests_)) + auto nh = blocked_requests_.extract(id); + if (!nh) return; - auto& request = iter->second; + auto& request = nh.mapped(); int result = net::OK; bool user_modified_headers = false; @@ -594,7 +598,6 @@ void WebRequest::OnHeadersReceivedListenerResult( base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(std::move(request.callback), result)); - blocked_requests_.erase(iter); } void WebRequest::OnSendHeaders(extensions::WebRequestInfo* info, @@ -603,6 +606,36 @@ void WebRequest::OnSendHeaders(extensions::WebRequestInfo* info, HandleSimpleEvent(SimpleEvent::kOnSendHeaders, info, request, headers); } +WebRequest::AuthRequiredResponse WebRequest::OnAuthRequired( + const extensions::WebRequestInfo* request_info, + const net::AuthChallengeInfo& auth_info, + WebRequest::AuthCallback callback, + net::AuthCredentials* credentials) { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( + request_info->render_process_id, request_info->frame_routing_id); + content::WebContents* web_contents = nullptr; + if (rfh) + web_contents = content::WebContents::FromRenderFrameHost(rfh); + + BlockedRequest blocked_request; + blocked_request.auth_callback = std::move(callback); + blocked_requests_[request_info->id] = std::move(blocked_request); + + auto login_callback = + base::BindOnce(&WebRequest::OnLoginAuthResult, base::Unretained(this), + request_info->id, credentials); + + scoped_refptr<net::HttpResponseHeaders> response_headers = + request_info->response_headers; + blocked_requests_[request_info->id].login_handler = + std::make_unique<LoginHandler>( + auth_info, web_contents, + static_cast<base::ProcessId>(request_info->render_process_id), + request_info->url, response_headers, std::move(login_callback)); + + return AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_IO_PENDING; +} + void WebRequest::OnBeforeRedirect(extensions::WebRequestInfo* info, const network::ResourceRequest& request, const GURL& new_location) { @@ -732,44 +765,35 @@ void WebRequest::HandleSimpleEvent(SimpleEvent event, info.listener.Run(gin::ConvertToV8(isolate, details)); } -// static -gin_helper::Handle<WebRequest> WebRequest::FromOrCreate( - v8::Isolate* isolate, - content::BrowserContext* browser_context) { - gin_helper::Handle<WebRequest> handle = From(isolate, browser_context); - if (handle.IsEmpty()) { - // Make sure the |Session| object has the |webRequest| property created. - v8::Local<v8::Value> web_request = - Session::CreateFrom( - isolate, static_cast<ElectronBrowserContext*>(browser_context)) - ->WebRequest(isolate); - gin::ConvertFromV8(isolate, web_request, &handle); +void WebRequest::OnLoginAuthResult( + uint64_t id, + net::AuthCredentials* credentials, + const std::optional<net::AuthCredentials>& maybe_creds) { + auto nh = blocked_requests_.extract(id); + CHECK(nh); + + AuthRequiredResponse action = + AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_NO_ACTION; + if (maybe_creds.has_value()) { + *credentials = maybe_creds.value(); + action = AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_SET_AUTH; } - DCHECK(!handle.IsEmpty()); - return handle; + + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(std::move(nh.mapped().auth_callback), action)); } // static -gin_helper::Handle<WebRequest> WebRequest::Create( - v8::Isolate* isolate, - content::BrowserContext* browser_context) { - DCHECK(From(isolate, browser_context).IsEmpty()) - << "WebRequest already created"; - return gin_helper::CreateHandle(isolate, - new WebRequest(isolate, browser_context)); +WebRequest* WebRequest::FromOrCreate(v8::Isolate* isolate, + content::BrowserContext* browser_context) { + return Session::FromOrCreate(isolate, browser_context)->WebRequest(isolate); } // static -gin_helper::Handle<WebRequest> WebRequest::From( - v8::Isolate* isolate, - content::BrowserContext* browser_context) { - if (!browser_context) - return {}; - auto* user_data = - static_cast<UserData*>(browser_context->GetUserData(kUserDataKey)); - if (!user_data) - return {}; - return gin_helper::CreateHandle(isolate, user_data->data.get()); +WebRequest* WebRequest::Create(v8::Isolate* isolate, + base::PassKey<Session> passkey) { + return cppgc::MakeGarbageCollected<WebRequest>( + isolate->GetCppHeap()->GetAllocationHandle(), std::move(passkey)); } } // namespace electron::api diff --git a/shell/browser/api/electron_api_web_request.h b/shell/browser/api/electron_api_web_request.h index c2e97e6dc6d02..dba78e2d7821d 100644 --- a/shell/browser/api/electron_api_web_request.h +++ b/shell/browser/api/electron_api_web_request.h @@ -7,10 +7,13 @@ #include <map> #include <set> +#include <string> -#include "base/memory/raw_ptr.h" -#include "shell/browser/net/web_request_api_interface.h" -#include "shell/common/gin_helper/wrappable.h" +#include "base/types/pass_key.h" +#include "gin/weak_cell.h" +#include "gin/wrappable.h" +#include "net/base/completion_once_callback.h" +#include "services/network/public/cpp/resource_request.h" class URLPattern; @@ -19,6 +22,7 @@ class BrowserContext; } namespace extensions { +struct WebRequestInfo; enum class WebRequestResourceType : uint8_t; } // namespace extensions @@ -33,72 +37,96 @@ class Handle; namespace electron::api { -class WebRequest final : public gin_helper::DeprecatedWrappable<WebRequest>, - public WebRequestAPI { +class Session; + +class WebRequest final : public gin::Wrappable<WebRequest> { public: - // Return the WebRequest object attached to |browser_context|, create if there - // is no one. - // Note that the lifetime of WebRequest object is managed by Session, instead - // of the caller. - static gin_helper::Handle<WebRequest> FromOrCreate( - v8::Isolate* isolate, - content::BrowserContext* browser_context); - - // Return a new WebRequest object, this should only be called by Session. - static gin_helper::Handle<WebRequest> Create( - v8::Isolate* isolate, - content::BrowserContext* browser_context); - - // Find the WebRequest object attached to |browser_context|. - static gin_helper::Handle<WebRequest> From( - v8::Isolate* isolate, - content::BrowserContext* browser_context); + using BeforeSendHeadersCallback = + base::OnceCallback<void(const std::set<std::string>& removed_headers, + const std::set<std::string>& set_headers, + int error_code)>; + + // AuthRequiredResponse indicates how an OnAuthRequired call is handled. + enum class AuthRequiredResponse { + // No credentials were provided. + AUTH_REQUIRED_RESPONSE_NO_ACTION, + // AuthCredentials is filled in with a username and password, which should + // be used in a response to the provided auth challenge. + AUTH_REQUIRED_RESPONSE_SET_AUTH, + // The request should be canceled. + AUTH_REQUIRED_RESPONSE_CANCEL_AUTH, + // The action will be decided asynchronously. |callback| will be invoked + // when the decision is made, and one of the other AuthRequiredResponse + // values will be passed in with the same semantics as described above. + AUTH_REQUIRED_RESPONSE_IO_PENDING, + }; + + using AuthCallback = base::OnceCallback<void(AuthRequiredResponse)>; + + // Convenience wrapper around api::Session::FromOrCreate()->WebRequest(). + // Creates the Session and WebRequest if they don't already exist. + // Note that the WebRequest is owned by the session, not by the caller. + static WebRequest* FromOrCreate(v8::Isolate* isolate, + content::BrowserContext* browser_context); + + // Return a new WebRequest object. This can only be called by api::Session. + static WebRequest* Create(v8::Isolate* isolate, base::PassKey<Session>); + + // Make public for cppgc::MakeGarbageCollected. + explicit WebRequest(base::PassKey<Session>); + ~WebRequest() override; + + // disable copy + WebRequest(const WebRequest&) = delete; + WebRequest& operator=(const WebRequest&) = delete; static const char* GetClassName() { return "WebRequest"; } - // gin_helper::Wrappable: - static gin::DeprecatedWrapperInfo kWrapperInfo; + // gin::Wrappable: + static const gin::WrapperInfo kWrapperInfo; + void Trace(cppgc::Visitor*) const override; + const gin::WrapperInfo* wrapper_info() const override; + const char* GetHumanReadableName() const override; gin::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; - const char* GetTypeName() override; - // WebRequestAPI: - bool HasListener() const override; + bool HasListener() const; int OnBeforeRequest(extensions::WebRequestInfo* info, const network::ResourceRequest& request, net::CompletionOnceCallback callback, - GURL* new_url) override; + GURL* new_url); int OnBeforeSendHeaders(extensions::WebRequestInfo* info, const network::ResourceRequest& request, BeforeSendHeadersCallback callback, - net::HttpRequestHeaders* headers) override; + net::HttpRequestHeaders* headers); int OnHeadersReceived( extensions::WebRequestInfo* info, const network::ResourceRequest& request, net::CompletionOnceCallback callback, const net::HttpResponseHeaders* original_response_headers, scoped_refptr<net::HttpResponseHeaders>* override_response_headers, - GURL* allowed_unsafe_redirect_url) override; + GURL* allowed_unsafe_redirect_url); void OnSendHeaders(extensions::WebRequestInfo* info, const network::ResourceRequest& request, - const net::HttpRequestHeaders& headers) override; + const net::HttpRequestHeaders& headers); + AuthRequiredResponse OnAuthRequired(const extensions::WebRequestInfo* info, + const net::AuthChallengeInfo& auth_info, + AuthCallback callback, + net::AuthCredentials* credentials); void OnBeforeRedirect(extensions::WebRequestInfo* info, const network::ResourceRequest& request, - const GURL& new_location) override; + const GURL& new_location); void OnResponseStarted(extensions::WebRequestInfo* info, - const network::ResourceRequest& request) override; + const network::ResourceRequest& request); void OnErrorOccurred(extensions::WebRequestInfo* info, const network::ResourceRequest& request, - int net_error) override; + int net_error); void OnCompleted(extensions::WebRequestInfo* info, const network::ResourceRequest& request, - int net_error) override; - void OnRequestWillBeDestroyed(extensions::WebRequestInfo* info) override; + int net_error); + void OnRequestWillBeDestroyed(extensions::WebRequestInfo* info); private: - WebRequest(v8::Isolate* isolate, content::BrowserContext* browser_context); - ~WebRequest() override; - // Contains info about requests that are blocked waiting for a response from // the user. struct BlockedRequest; @@ -157,6 +185,12 @@ class WebRequest final : public gin_helper::DeprecatedWrappable<WebRequest>, v8::Local<v8::Value> response); void OnHeadersReceivedListenerResult(uint64_t id, v8::Local<v8::Value> response); + // Callback invoked by LoginHandler when auth credentials are supplied via + // the unified 'login' event. Bridges back into WebRequest's AuthCallback. + void OnLoginAuthResult( + uint64_t id, + net::AuthCredentials* credentials, + const std::optional<net::AuthCredentials>& maybe_creds); class RequestFilter { public: @@ -174,7 +208,7 @@ class WebRequest final : public gin_helper::DeprecatedWrappable<WebRequest>, bool is_match_pattern = true); void AddType(extensions::WebRequestResourceType type); - bool MatchesRequest(extensions::WebRequestInfo* info) const; + bool MatchesRequest(const extensions::WebRequestInfo* info) const; private: bool MatchesURL(const GURL& url, @@ -208,8 +242,7 @@ class WebRequest final : public gin_helper::DeprecatedWrappable<WebRequest>, std::map<ResponseEvent, ResponseListenerInfo> response_listeners_; std::map<uint64_t, BlockedRequest> blocked_requests_; - // Weak-ref, it manages us. - raw_ptr<content::BrowserContext> browser_context_; + gin::WeakCellFactory<WebRequest> weak_factory_{this}; }; } // namespace electron::api diff --git a/shell/browser/api/electron_api_web_view_manager.cc b/shell/browser/api/electron_api_web_view_manager.cc index 03938517bf28b..32bf53cb5b566 100644 --- a/shell/browser/api/electron_api_web_view_manager.cc +++ b/shell/browser/api/electron_api_web_view_manager.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. +#include "base/callback_list.h" #include "content/public/browser/browser_context.h" #include "shell/browser/javascript_environment.h" #include "shell/browser/web_contents_preferences.h" diff --git a/shell/browser/api/frame_subscriber.cc b/shell/browser/api/frame_subscriber.cc index cef2e20b0ad0b..b3171c433991b 100644 --- a/shell/browser/api/frame_subscriber.cc +++ b/shell/browser/api/frame_subscriber.cc @@ -6,6 +6,7 @@ #include <utility> +#include "content/public/browser/page.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" diff --git a/shell/browser/api/frame_subscriber.h b/shell/browser/api/frame_subscriber.h index c6c3300374d9e..61196270015bc 100644 --- a/shell/browser/api/frame_subscriber.h +++ b/shell/browser/api/frame_subscriber.h @@ -61,7 +61,8 @@ class FrameSubscriber : private content::WebContentsObserver, const gfx::Rect& content_rect, mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks) override; - void OnNewSubCaptureTargetVersion(uint32_t crop_version) override {} + void OnNewCaptureVersion( + const media::CaptureVersion& capture_version) override {} void OnFrameWithEmptyRegionCapture() override {} void OnStopped() override {} void OnLog(const std::string& message) override {} diff --git a/shell/browser/api/gpu_info_enumerator.cc b/shell/browser/api/gpu_info_enumerator.cc index caf458f4a9a72..da6b215750ab8 100644 --- a/shell/browser/api/gpu_info_enumerator.cc +++ b/shell/browser/api/gpu_info_enumerator.cc @@ -80,19 +80,6 @@ void GPUInfoEnumerator::EndVideoEncodeAcceleratorSupportedProfile() { value_stack_.pop(); } -void GPUInfoEnumerator::BeginImageDecodeAcceleratorSupportedProfile() { - value_stack_.push(std::move(current_)); - current_ = {}; -} - -void GPUInfoEnumerator::EndImageDecodeAcceleratorSupportedProfile() { - auto& top_value = value_stack_.top(); - top_value.Set(kImageDecodeAcceleratorSupportedProfileKey, - std::move(current_)); - current_ = std::move(top_value); - value_stack_.pop(); -} - void GPUInfoEnumerator::BeginAuxAttributes() { value_stack_.push(std::move(current_)); current_ = {}; diff --git a/shell/browser/api/gpu_info_enumerator.h b/shell/browser/api/gpu_info_enumerator.h index c6fb3d5820989..87c68e6786947 100644 --- a/shell/browser/api/gpu_info_enumerator.h +++ b/shell/browser/api/gpu_info_enumerator.h @@ -21,8 +21,6 @@ class GPUInfoEnumerator final : public gpu::GPUInfo::Enumerator { "videoDecodeAcceleratorSupportedProfile"; const char* const kVideoEncodeAcceleratorSupportedProfileKey = "videoEncodeAcceleratorSupportedProfile"; - const char* const kImageDecodeAcceleratorSupportedProfileKey = - "imageDecodeAcceleratorSupportedProfile"; const char* const kAuxAttributesKey = "auxAttributes"; const char* const kOverlayInfo = "overlayInfo"; @@ -45,8 +43,6 @@ class GPUInfoEnumerator final : public gpu::GPUInfo::Enumerator { void EndVideoDecodeAcceleratorSupportedProfile() override; void BeginVideoEncodeAcceleratorSupportedProfile() override; void EndVideoEncodeAcceleratorSupportedProfile() override; - void BeginImageDecodeAcceleratorSupportedProfile() override; - void EndImageDecodeAcceleratorSupportedProfile() override; void BeginAuxAttributes() override; void EndAuxAttributes() override; void BeginOverlayInfo() override; diff --git a/shell/browser/api/views/electron_api_image_view.cc b/shell/browser/api/views/electron_api_image_view.cc index c0578c7777615..3dbc56f226c24 100644 --- a/shell/browser/api/views/electron_api_image_view.cc +++ b/shell/browser/api/views/electron_api_image_view.cc @@ -25,7 +25,7 @@ void ImageView::SetImage(const gfx::Image& image) { } // static -gin_helper::WrappableBase* ImageView::New(gin_helper::Arguments* args) { +gin_helper::WrappableBase* ImageView::New(gin::Arguments* const args) { // Constructor call. auto* view = new ImageView(); view->InitWithArgs(args); diff --git a/shell/browser/api/views/electron_api_image_view.h b/shell/browser/api/views/electron_api_image_view.h index 78d913c046b13..156d256771dea 100644 --- a/shell/browser/api/views/electron_api_image_view.h +++ b/shell/browser/api/views/electron_api_image_view.h @@ -13,8 +13,11 @@ namespace gfx { class Image; } -namespace gin_helper { +namespace gin { class Arguments; +} // namespace gin + +namespace gin_helper { class WrappableBase; } // namespace gin_helper @@ -22,7 +25,7 @@ namespace electron::api { class ImageView : public View { public: - static gin_helper::WrappableBase* New(gin_helper::Arguments* args); + static gin_helper::WrappableBase* New(gin::Arguments* args); static void BuildPrototype(v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype); diff --git a/shell/browser/auto_updater.cc b/shell/browser/auto_updater.cc index e3fbf865c95fb..54ca9ab1ab59e 100644 --- a/shell/browser/auto_updater.cc +++ b/shell/browser/auto_updater.cc @@ -4,6 +4,7 @@ #include "shell/browser/auto_updater.h" +#include "base/no_destructor.h" #include "build/build_config.h" #include "electron/mas.h" @@ -19,11 +20,12 @@ void AutoUpdater::SetDelegate(Delegate* delegate) { delegate_ = delegate; } -#if !BUILDFLAG(IS_MAC) || IS_MAS_BUILD() -std::string AutoUpdater::GetFeedURL() { - return ""; +std::string& AutoUpdater::GetFeedURL() { + static base::NoDestructor<std::string> feed_url; + return *feed_url; } +#if !BUILDFLAG(IS_MAC) || IS_MAS_BUILD() void AutoUpdater::SetFeedURL(gin::Arguments* args) {} void AutoUpdater::CheckForUpdates() {} diff --git a/shell/browser/auto_updater.h b/shell/browser/auto_updater.h index 8b8cd48f1d9bd..1c145b00e37b2 100644 --- a/shell/browser/auto_updater.h +++ b/shell/browser/auto_updater.h @@ -60,7 +60,7 @@ class AutoUpdater { static Delegate* GetDelegate(); static void SetDelegate(Delegate* delegate); - static std::string GetFeedURL(); + static std::string& GetFeedURL(); // FIXME(zcbenz): We should not do V8 in this file, this method should only // accept C++ struct as parameter, and atom_api_auto_updater.cc is responsible // for parsing the parameter from JavaScript. diff --git a/shell/browser/auto_updater_mac.mm b/shell/browser/auto_updater_mac.mm index 50b9f645b9c68..cfc0755cdf9ed 100644 --- a/shell/browser/auto_updater_mac.mm +++ b/shell/browser/auto_updater_mac.mm @@ -18,7 +18,6 @@ #include "shell/browser/browser.h" #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" -#include "shell/common/gin_helper/error_thrower.h" namespace auto_updater { @@ -26,23 +25,12 @@ // The global SQRLUpdater object. SQRLUpdater* __strong g_updater = nil; - -} // namespace - -namespace { - bool g_update_available = false; -std::string update_url_ = ""; // NOLINT(runtime/string) } // namespace -std::string AutoUpdater::GetFeedURL() { - return update_url_; -} - // static -void AutoUpdater::SetFeedURL(gin::Arguments* args) { - gin_helper::ErrorThrower thrower(args->isolate()); +void AutoUpdater::SetFeedURL(gin::Arguments* const args) { gin_helper::Dictionary opts; std::string feed; @@ -55,7 +43,7 @@ } } else if (args->GetNext(&opts)) { if (!opts.Get("url", &feed)) { - thrower.ThrowError( + args->ThrowTypeError( "Expected options object to contain a 'url' string property in " "setFeedUrl call"); return; @@ -63,11 +51,11 @@ opts.Get("headers", &requestHeaders); opts.Get("serverType", &serverType); if (serverType != "default" && serverType != "json") { - thrower.ThrowError("Expected serverType to be 'default' or 'json'"); + args->ThrowTypeError("Expected serverType to be 'default' or 'json'"); return; } } else { - thrower.ThrowError( + args->ThrowTypeError( "Expected an options object with a 'url' property to be provided"); return; } @@ -76,7 +64,7 @@ if (!delegate) return; - update_url_ = feed; + GetFeedURL() = feed; NSURL* url = [NSURL URLWithString:base::SysUTF8ToNSString(feed)]; NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url]; diff --git a/shell/browser/browser.cc b/shell/browser/browser.cc index 0c0e7c8c5076f..ca23057de9784 100644 --- a/shell/browser/browser.cc +++ b/shell/browser/browser.cc @@ -13,13 +13,13 @@ #include "base/task/single_thread_task_runner.h" #include "base/threading/thread_restrictions.h" #include "chrome/common/chrome_paths.h" +#include "gin/arguments.h" #include "shell/browser/browser_observer.h" #include "shell/browser/electron_browser_main_parts.h" #include "shell/browser/native_window.h" #include "shell/browser/window_list.h" #include "shell/common/application_info.h" #include "shell/common/gin_converters/login_item_settings_converter.h" -#include "shell/common/gin_helper/arguments.h" #include "shell/common/thread_restrictions.h" namespace electron { diff --git a/shell/browser/browser_linux.cc b/shell/browser/browser_linux.cc index 03e1a9521c11d..56503dfe755ed 100644 --- a/shell/browser/browser_linux.cc +++ b/shell/browser/browser_linux.cc @@ -134,7 +134,7 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol, std::u16string Browser::GetApplicationNameForProtocol(const GURL& url) { const std::vector<std::string> argv = { "xdg-mime", "query", "default", - base::StrCat({"x-scheme-handler/", url.scheme_piece()})}; + base::StrCat({"x-scheme-handler/", url.scheme()})}; return base::ASCIIToUTF16(GetXdgAppOutput(argv).value_or(std::string())); } diff --git a/shell/browser/browser_mac.mm b/shell/browser/browser_mac.mm index e7a4468649df6..4c5156ae21201 100644 --- a/shell/browser/browser_mac.mm +++ b/shell/browser/browser_mac.mm @@ -137,13 +137,10 @@ LoginItemSettings GetLoginItemSettingsDeprecated() { gin_helper::Dictionary opts; bool steal_focus = false; - if (args->GetNext(&opts)) { - gin_helper::ErrorThrower thrower(args->isolate()); - if (!opts.Get("steal", &steal_focus)) { - thrower.ThrowError( - "Expected options object to contain a 'steal' boolean property"); - return; - } + if (args->GetNext(&opts) && !opts.Get("steal", &steal_focus)) { + args->ThrowTypeError( + "Expected options object to contain a 'steal' boolean property"); + return; } [[AtomApplication sharedApplication] activateIgnoringOtherApps:steal_focus]; @@ -546,6 +543,9 @@ LoginItemSettings GetLoginItemSettingsDeprecated() { gin_helper::Promise<void> promise(isolate); v8::Local<v8::Promise> handle = promise.GetHandle(); + for (auto* const& window : WindowList::GetWindows()) + [window->GetNativeWindow().GetNativeNSWindow() setCanHide:YES]; + BOOL active = [[NSRunningApplication currentApplication] isActive]; ProcessSerialNumber psn = {0, kCurrentProcess}; if (active) { diff --git a/shell/browser/browser_process_impl.cc b/shell/browser/browser_process_impl.cc index 7c6cc917ed9a8..013f317993758 100644 --- a/shell/browser/browser_process_impl.cc +++ b/shell/browser/browser_process_impl.cc @@ -38,6 +38,7 @@ #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h" #include "services/network/public/cpp/network_switches.h" #include "shell/browser/net/resolve_proxy_helper.h" +#include "shell/common/electron_constants.h" #include "shell/common/electron_paths.h" #include "shell/common/thread_restrictions.h" @@ -106,12 +107,12 @@ void BrowserProcessImpl::PostEarlyInitialization() { OSCrypt::RegisterLocalPrefs(pref_registry.get()); #endif + pref_registry->RegisterDictionaryPref(electron::kWindowStates); + in_memory_pref_store_ = base::MakeRefCounted<ValueMapPrefStore>(); ApplyProxyModeFromCommandLine(in_memory_pref_store()); prefs_factory.set_command_line_prefs(in_memory_pref_store()); - // Only use a persistent prefs store when cookie encryption is enabled as that - // is the only key that needs it base::FilePath prefs_path; CHECK(base::PathService::Get(electron::DIR_SESSION_DATA, &prefs_path)); prefs_path = prefs_path.Append(FILE_PATH_LITERAL("Local State")); diff --git a/shell/browser/browser_win.cc b/shell/browser/browser_win.cc index bd9f5ea24e064..d640283b4b2ad 100644 --- a/shell/browser/browser_win.cc +++ b/shell/browser/browser_win.cc @@ -106,7 +106,7 @@ bool IsValidCustomProtocol(const std::wstring& scheme) { // (https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/ne-shlwapi-assocstr) // and returns the application name, icon and path that handles the protocol. std::wstring GetAppInfoHelperForProtocol(ASSOCSTR assoc_str, const GURL& url) { - const std::wstring url_scheme = base::ASCIIToWide(url.scheme_piece()); + const std::wstring url_scheme = base::ASCIIToWide(url.scheme()); if (!IsValidCustomProtocol(url_scheme)) return {}; diff --git a/shell/browser/child_web_contents_tracker.cc b/shell/browser/child_web_contents_tracker.cc index b72eabda6c0f9..6a03b51b56ffd 100644 --- a/shell/browser/child_web_contents_tracker.cc +++ b/shell/browser/child_web_contents_tracker.cc @@ -3,7 +3,12 @@ // found in the LICENSE file. #include "shell/browser/child_web_contents_tracker.h" + +#include "base/memory/scoped_refptr.h" #include "content/public/browser/web_contents_user_data.h" +#include "content/public/common/referrer.h" +#include "services/network/public/cpp/resource_request_body.h" +#include "url/gurl.h" namespace electron { diff --git a/shell/browser/child_web_contents_tracker.h b/shell/browser/child_web_contents_tracker.h index c16113af7274f..e944e10c130d2 100644 --- a/shell/browser/child_web_contents_tracker.h +++ b/shell/browser/child_web_contents_tracker.h @@ -7,7 +7,14 @@ #include <string> +#include "base/memory/scoped_refptr.h" #include "content/public/browser/web_contents_user_data.h" +#include "content/public/common/referrer.h" +#include "url/gurl.h" + +namespace network { +class ResourceRequestBody; +} // namespace network namespace electron { diff --git a/shell/browser/electron_browser_client.cc b/shell/browser/electron_browser_client.cc index 627b8f18b974c..9fea5d0e060d2 100644 --- a/shell/browser/electron_browser_client.cc +++ b/shell/browser/electron_browser_client.cc @@ -56,6 +56,7 @@ #include "electron/fuses.h" #include "extensions/browser/extension_navigation_ui_data.h" #include "extensions/common/extension_id.h" +#include "ipc/constants.mojom.h" #include "mojo/public/cpp/bindings/binder_map.h" #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" #include "net/ssl/ssl_cert_request_info.h" @@ -215,12 +216,14 @@ #if BUILDFLAG(ENABLE_PDF_VIEWER) #include "chrome/browser/pdf/chrome_pdf_stream_delegate.h" +#include "chrome/browser/pdf/pdf_help_bubble_handler_factory.h" #include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h" // nogncheck #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" // nogncheck #include "shell/browser/electron_pdf_document_helper_client.h" +#include "ui/webui/resources/cr_components/help_bubble/help_bubble.mojom.h" // nogncheck #endif using content::BrowserThread; @@ -305,7 +308,7 @@ const extensions::Extension* GetEnabledExtensionFromEffectiveURL( if (!registry) return nullptr; - return registry->enabled_extensions().GetByID(effective_url.host()); + return registry->enabled_extensions().GetByID(effective_url.GetHost()); } #endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) @@ -427,9 +430,11 @@ void ElectronBrowserClient::OverrideWebPreferences( renderer_prefs->can_accept_load_drops = false; ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); - prefs->in_forced_colors = native_theme->InForcedColorsMode(); + prefs->in_forced_colors = native_theme->forced_colors() != + ui::ColorProviderKey::ForcedColors::kNone; prefs->preferred_color_scheme = - native_theme->ShouldUseDarkColors() + native_theme->preferred_color_scheme() == + ui::NativeTheme::PreferredColorScheme::kDark ? blink::mojom::PreferredColorScheme::kDark : blink::mojom::PreferredColorScheme::kLight; @@ -441,6 +446,22 @@ void ElectronBrowserClient::OverrideWebPreferences( } } +bool ElectronBrowserClient::WebPreferencesNeedUpdateForColorRelatedStateChanges( + content::WebContents& web_contents, + const content::SiteInstance& main_frame_site) const { + const auto& prefs = web_contents.GetOrCreateWebPreferences(); + ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); + bool in_forced_colors = native_theme->forced_colors() != + ui::ColorProviderKey::ForcedColors::kNone; + blink::mojom::PreferredColorScheme preferred_color_scheme = + native_theme->preferred_color_scheme() == + ui::NativeTheme::PreferredColorScheme::kDark + ? blink::mojom::PreferredColorScheme::kDark + : blink::mojom::PreferredColorScheme::kLight; + return prefs.in_forced_colors != in_forced_colors || + prefs.preferred_color_scheme != preferred_color_scheme; +} + void ElectronBrowserClient::RegisterPendingSiteInstance( content::RenderFrameHost* rfh, content::SiteInstance* pending_site_instance) { @@ -533,7 +554,7 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches( if (process_type == ::switches::kUtilityProcess || process_type == ::switches::kRendererProcess) { // Copy following switches to child process. - static constexpr std::array<const char*, 9U> kCommonSwitchNames = { + static constexpr std::array<const char*, 10U> kCommonSwitchNames = { switches::kStandardSchemes.c_str(), switches::kEnableSandbox.c_str(), switches::kSecureSchemes.c_str(), @@ -542,6 +563,7 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches( switches::kFetchSchemes.c_str(), switches::kServiceWorkerSchemes.c_str(), switches::kStreamingSchemes.c_str(), + switches::kNoStdioInit.c_str(), switches::kCodeCacheSchemes.c_str()}; command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(), kCommonSwitchNames); @@ -1250,11 +1272,11 @@ bool ElectronBrowserClient::WillInterceptWebSocket( v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); v8::HandleScope scope(isolate); auto* browser_context = frame->GetProcess()->GetBrowserContext(); - auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context); + auto* web_request = api::WebRequest::FromOrCreate(isolate, browser_context); // NOTE: Some unit test environments do not initialize // BrowserContextKeyedAPI factories for e.g. WebRequest. - if (!web_request.get()) + if (!web_request) return false; bool has_listener = web_request->HasListener(); @@ -1282,8 +1304,8 @@ void ElectronBrowserClient::CreateWebSocket( v8::HandleScope scope(isolate); auto* browser_context = frame->GetProcess()->GetBrowserContext(); - auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context); - DCHECK(web_request.get()); + auto* web_request = api::WebRequest::FromOrCreate(isolate, browser_context); + DCHECK(web_request); #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) if (!web_request->HasListener()) { @@ -1300,7 +1322,7 @@ void ElectronBrowserClient::CreateWebSocket( #endif ProxyingWebSocket::StartProxying( - web_request.get(), std::move(factory), url, site_for_cookies, user_agent, + web_request, std::move(factory), url, site_for_cookies, user_agent, std::move(handshake_client), true, frame->GetProcess()->GetDeprecatedID(), frame->GetRoutingID(), frame->GetLastCommittedOrigin(), browser_context, &next_id_); @@ -1324,8 +1346,9 @@ void ElectronBrowserClient::WillCreateURLLoaderFactory( scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); v8::HandleScope scope(isolate); - auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context); - DCHECK(web_request.get()); + auto* const web_request = + api::WebRequest::FromOrCreate(isolate, browser_context); + DCHECK(web_request); #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) if (!web_request->HasListener()) { @@ -1366,13 +1389,18 @@ void ElectronBrowserClient::WillCreateURLLoaderFactory( auto* protocol_registry = ProtocolRegistry::FromBrowserContext(browser_context); - new ProxyingURLLoaderFactory( - web_request.get(), protocol_registry->intercept_handlers(), + new ProxyingURLLoaderFactory{ + web_request, + protocol_registry->intercept_handlers(), render_process_id, - frame_host ? frame_host->GetRoutingID() : MSG_ROUTING_NONE, &next_id_, - std::move(navigation_ui_data), std::move(navigation_id), - std::move(proxied_receiver), std::move(target_factory_remote), - std::move(header_client_receiver), type); + frame_host ? frame_host->GetRoutingID() : IPC::mojom::kRoutingIdNone, + &next_id_, + std::move(navigation_ui_data), + std::move(navigation_id), + std::move(proxied_receiver), + std::move(target_factory_remote), + std::move(header_client_receiver), + type}; } std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> @@ -1649,13 +1677,18 @@ void ElectronBrowserClient::RegisterBrowserInterfaceBindersForFrame( render_frame_host->GetProcess()->GetBrowserContext(); auto* extension = extensions::ExtensionRegistry::Get(browser_context) ->enabled_extensions() - .GetByID(site.host()); + .GetByID(site.GetHost()); if (!extension) return; extensions::ExtensionsBrowserClient::Get() ->RegisterBrowserInterfaceBindersForFrame(map, render_frame_host, extension); #endif + +#if BUILDFLAG(ENABLE_PDF_VIEWER) + map->Add<help_bubble::mojom::PdfHelpBubbleHandlerFactory>( + &pdf::PdfHelpBubbleHandlerFactory::Create); +#endif } #if BUILDFLAG(IS_LINUX) diff --git a/shell/browser/electron_browser_client.h b/shell/browser/electron_browser_client.h index 5e2fc2ad905ad..46eb0e790ad05 100644 --- a/shell/browser/electron_browser_client.h +++ b/shell/browser/electron_browser_client.h @@ -133,6 +133,9 @@ class ElectronBrowserClient : public content::ContentBrowserClient, void OverrideWebPreferences(content::WebContents* web_contents, content::SiteInstance& main_frame_site, blink::web_pref::WebPreferences* prefs) override; + bool WebPreferencesNeedUpdateForColorRelatedStateChanges( + content::WebContents& web_contents, + const content::SiteInstance& main_frame_site) const override; void RegisterPendingSiteInstance( content::RenderFrameHost* render_frame_host, content::SiteInstance* pending_site_instance) override; diff --git a/shell/browser/electron_browser_context.cc b/shell/browser/electron_browser_context.cc index 9a86b3040be28..f33da024719b8 100644 --- a/shell/browser/electron_browser_context.cc +++ b/shell/browser/electron_browser_context.cc @@ -66,7 +66,6 @@ #include "shell/common/electron_paths.h" #include "shell/common/gin_converters/frame_converter.h" #include "shell/common/gin_helper/dictionary.h" -#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/options_switches.h" #include "shell/common/thread_restrictions.h" #include "third_party/blink/public/common/page/page_zoom.h" @@ -499,7 +498,7 @@ void ElectronBrowserContext::SetUserAgent(const std::string& user_agent) { user_agent_ = user_agent; } -base::FilePath ElectronBrowserContext::GetPath() { +base::FilePath ElectronBrowserContext::GetPath() const { return path_; } @@ -681,7 +680,7 @@ void ElectronBrowserContext::SetDisplayMediaRequestHandler( void ElectronBrowserContext::DisplayMediaDeviceChosen( const content::MediaStreamRequest& request, content::MediaResponseCallback callback, - gin::Arguments* args) { + gin::Arguments* const args) { blink::mojom::StreamDevicesSetPtr stream_devices_set = blink::mojom::StreamDevicesSet::New(); v8::Local<v8::Value> result; @@ -693,10 +692,9 @@ void ElectronBrowserContext::DisplayMediaDeviceChosen( } gin_helper::Dictionary result_dict; if (!gin::ConvertFromV8(args->isolate(), result, &result_dict)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError( - "Display Media Request streams callback must be called with null " - "or a valid object"); + args->ThrowTypeError( + "Display Media Request streams callback must be called with null " + "or a valid object"); std::move(callback).Run( blink::mojom::StreamDevicesSet(), blink::mojom::MediaStreamRequestResult::CAPTURE_FAILURE, nullptr); @@ -735,9 +733,8 @@ void ElectronBrowserContext::DisplayMediaDeviceChosen( content::DesktopMediaID::Parse(video_device.id)); devices.video_device = video_device; } else { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError( - "video must be a WebFrameMain or DesktopCapturerSource"); + args->ThrowTypeError( + "video must be a WebFrameMain or DesktopCapturerSource"); std::move(callback).Run( blink::mojom::StreamDevicesSet(), blink::mojom::MediaStreamRequestResult::CAPTURE_FAILURE, nullptr); @@ -784,10 +781,9 @@ void ElectronBrowserContext::DisplayMediaDeviceChosen( GetAudioDesktopMediaId(request.requested_audio_device_ids)); devices.audio_device = audio_device; } else { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError( - "audio must be a WebFrameMain, \"loopback\" or " - "\"loopbackWithMute\""); + args->ThrowTypeError( + "audio must be a WebFrameMain, \"loopback\" or " + "\"loopbackWithMute\""); std::move(callback).Run( blink::mojom::StreamDevicesSet(), blink::mojom::MediaStreamRequestResult::CAPTURE_FAILURE, nullptr); @@ -796,9 +792,8 @@ void ElectronBrowserContext::DisplayMediaDeviceChosen( } if ((video_requested && !has_video)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowTypeError( - "Video was requested, but no video stream was provided"); + args->ThrowTypeError( + "Video was requested, but no video stream was provided"); std::move(callback).Run( blink::mojom::StreamDevicesSet(), blink::mojom::MediaStreamRequestResult::CAPTURE_FAILURE, nullptr); diff --git a/shell/browser/electron_browser_context.h b/shell/browser/electron_browser_context.h index 17e5bb02dab8a..b643e75b79aa4 100644 --- a/shell/browser/electron_browser_context.h +++ b/shell/browser/electron_browser_context.h @@ -94,7 +94,7 @@ class ElectronBrowserContext : public content::BrowserContext { std::string GetMediaDeviceIDSalt(); // content::BrowserContext: - base::FilePath GetPath() override; + base::FilePath GetPath() const override; bool IsOffTheRecord() override; std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate( const base::FilePath& partition_path) override; diff --git a/shell/browser/electron_browser_main_parts.cc b/shell/browser/electron_browser_main_parts.cc index bb1cc5bd295a3..139237d3a0413 100644 --- a/shell/browser/electron_browser_main_parts.cc +++ b/shell/browser/electron_browser_main_parts.cc @@ -14,7 +14,6 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "base/i18n/rtl.h" -#include "base/metrics/field_trial.h" #include "base/nix/xdg_util.h" #include "base/path_service.h" #include "base/run_loop.h" @@ -68,6 +67,7 @@ #include "ui/base/ui_base_switches.h" #include "ui/color/color_provider_manager.h" #include "ui/display/screen.h" +#include "ui/linux/display_server_utils.h" #include "ui/views/layout/layout_provider.h" #include "url/url_util.h" @@ -101,7 +101,7 @@ #endif #if BUILDFLAG(IS_MAC) -#include "components/os_crypt/sync/keychain_password_mac.h" +#include "components/os_crypt/common/keychain_password_mac.h" #include "shell/browser/ui/cocoa/views_delegate_mac.h" #else #include "shell/browser/ui/views/electron_views_delegate.h" @@ -205,13 +205,17 @@ int ElectronBrowserMainParts::GetExitCode() const { } int ElectronBrowserMainParts::PreEarlyInitialization() { - field_trial_list_ = std::make_unique<base::FieldTrialList>(); #if BUILDFLAG(IS_POSIX) HandleSIGCHLD(); #endif +#if BUILDFLAG(IS_OZONE) + // Initialize Ozone platform and add required feature flags as per platform's + // properties. #if BUILDFLAG(IS_LINUX) - ui::OzonePlatform::PreEarlyInitialization(); + ui::SetOzonePlatformForLinuxIfNeeded(*base::CommandLine::ForCurrentProcess()); #endif + ui::OzonePlatform::PreEarlyInitialization(); +#endif // BUILDFLAG(IS_OZONE) #if BUILDFLAG(IS_MAC) screen_ = std::make_unique<display::ScopedNativeScreen>(); #endif @@ -319,7 +323,7 @@ int ElectronBrowserMainParts::PreCreateThreads() { #if defined(USE_AURA) // NB: must be called _after_ locale resource bundle is loaded, // because ui lib makes use of it in X11 - if (!display::Screen::GetScreen()) { + if (!display::Screen::Get()) { screen_ = views::CreateDesktopScreen(); } #endif diff --git a/shell/browser/electron_browser_main_parts.h b/shell/browser/electron_browser_main_parts.h index 86897fc9c780a..ccc1565822614 100644 --- a/shell/browser/electron_browser_main_parts.h +++ b/shell/browser/electron_browser_main_parts.h @@ -19,10 +19,6 @@ class BrowserProcessImpl; class IconManager; -namespace base { -class FieldTrialList; -} - namespace display { class Screen; class ScopedNativeScreen; @@ -171,7 +167,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts { std::unique_ptr<Browser> browser_; std::unique_ptr<IconManager> icon_manager_; - std::unique_ptr<base::FieldTrialList> field_trial_list_; #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) std::unique_ptr<ElectronExtensionsClient> extensions_client_; diff --git a/shell/browser/electron_browser_main_parts_mac.mm b/shell/browser/electron_browser_main_parts_mac.mm index c7c093010ef0b..2a4238dec285c 100644 --- a/shell/browser/electron_browser_main_parts_mac.mm +++ b/shell/browser/electron_browser_main_parts_mac.mm @@ -11,6 +11,7 @@ #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h" #include "services/device/public/cpp/geolocation/system_geolocation_source_apple.h" #include "shell/browser/browser_process_impl.h" +#include "shell/browser/electron_permission_manager.h" #include "shell/browser/mac/electron_application.h" #include "shell/browser/mac/electron_application_delegate.h" #include "ui/base/l10n/l10n_util_mac.h" @@ -32,7 +33,13 @@ setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"]; - if (!device::GeolocationSystemPermissionManager::GetInstance()) { + const bool geolocationDisabled = + ElectronPermissionManager::IsGeolocationDisabledViaCommandLine(); + + // Check if geolocation api is NOT disabled via command line before + // CreateGeolocationSystemPermissionManager is called + if (!geolocationDisabled && + !device::GeolocationSystemPermissionManager::GetInstance()) { device::GeolocationSystemPermissionManager::SetInstance( device::SystemGeolocationSourceApple:: CreateGeolocationSystemPermissionManager()); diff --git a/shell/browser/electron_pdf_document_helper_client.h b/shell/browser/electron_pdf_document_helper_client.h index 3532e599a9995..c4f447b34a15f 100644 --- a/shell/browser/electron_pdf_document_helper_client.h +++ b/shell/browser/electron_pdf_document_helper_client.h @@ -20,7 +20,7 @@ class ElectronPDFDocumentHelperClient : public pdf::PDFDocumentHelperClient { // pdf::PDFDocumentHelperClient void UpdateContentRestrictions(content::RenderFrameHost* render_frame_host, int content_restrictions) override; - void OnSaveURL(content::WebContents* contents) override {} + void OnSaveURL() override {} void SetPluginCanSave(content::RenderFrameHost* render_frame_host, bool can_save) override; #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) diff --git a/shell/browser/electron_permission_manager.cc b/shell/browser/electron_permission_manager.cc index d947c5246b2c7..c50c76789bbc9 100644 --- a/shell/browser/electron_permission_manager.cc +++ b/shell/browser/electron_permission_manager.cc @@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/command_line.h" #include "base/containers/to_vector.h" #include "base/values.h" #include "content/browser/permissions/permission_util.h" // nogncheck @@ -46,7 +47,7 @@ bool WebContentsDestroyed(content::RenderFrameHost* rfh) { void PermissionRequestResponseCallbackWrapper( ElectronPermissionManager::StatusCallback callback, - const std::vector<blink::mojom::PermissionStatus>& vector) { + const std::vector<content::PermissionResult>& vector) { std::move(callback).Run(vector[0]); } @@ -60,7 +61,10 @@ class ElectronPermissionManager::PendingRequest { : render_frame_host_id_(render_frame_host->GetGlobalId()), callback_(std::move(callback)), permissions_(std::move(permissions)), - results_(permissions_.size(), blink::mojom::PermissionStatus::DENIED), + results_(permissions_.size(), + content::PermissionResult( + blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED)), remaining_results_(permissions_.size()) {} void SetPermissionStatus(int permission_id, @@ -80,7 +84,8 @@ class ElectronPermissionManager::PendingRequest { } } - results_[permission_id] = status; + results_[permission_id] = content::PermissionResult( + status, content::PermissionStatusSource::UNSPECIFIED); --remaining_results_; } @@ -100,7 +105,7 @@ class ElectronPermissionManager::PendingRequest { content::GlobalRenderFrameHostId render_frame_host_id_; StatusesCallback callback_; std::vector<blink::mojom::PermissionDescriptorPtr> permissions_; - std::vector<blink::mojom::PermissionStatus> results_; + std::vector<content::PermissionResult> results_; size_t remaining_results_; }; @@ -142,6 +147,25 @@ void ElectronPermissionManager::SetBluetoothPairingHandler( bluetooth_pairing_handler_ = handler; } +// static +bool ElectronPermissionManager::IsGeolocationDisabledViaCommandLine() { +// Remove platform check once flag is extended to other platforms +#if BUILDFLAG(IS_MAC) + auto* command_line = base::CommandLine::ForCurrentProcess(); + return command_line->HasSwitch("disable-geolocation"); +#else + return false; +#endif +} + +bool ElectronPermissionManager::HasPermissionRequestHandler() const { + return !request_handler_.is_null(); +} + +bool ElectronPermissionManager::HasPermissionCheckHandler() const { + return !check_handler_.is_null(); +} + void ElectronPermissionManager::RequestPermissionWithDetails( blink::mojom::PermissionDescriptorPtr permission, content::RenderFrameHost* render_frame_host, @@ -150,7 +174,10 @@ void ElectronPermissionManager::RequestPermissionWithDetails( base::Value::Dict details, StatusCallback response_callback) { if (render_frame_host->IsNestedWithinFencedFrame()) { - std::move(response_callback).Run(blink::mojom::PermissionStatus::DENIED); + std::move(response_callback) + .Run(content::PermissionResult( + blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED)); return; } @@ -168,9 +195,11 @@ void ElectronPermissionManager::RequestPermissions( const content::PermissionRequestDescription& request_description, StatusesCallback callback) { if (render_frame_host->IsNestedWithinFencedFrame()) { - std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>( + std::move(callback).Run(std::vector<content::PermissionResult>( request_description.permissions.size(), - blink::mojom::PermissionStatus::DENIED)); + content::PermissionResult( + blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED))); return; } @@ -194,7 +223,7 @@ void ElectronPermissionManager::RequestPermissionsWithDetails( }); if (request_handler_.is_null()) { - std::vector<blink::mojom::PermissionStatus> statuses; + std::vector<content::PermissionResult> results; for (const auto& permission : permissions) { const auto permission_type = blink::PermissionDescriptorToPermissionType(permission); @@ -203,13 +232,22 @@ void ElectronPermissionManager::RequestPermissionsWithDetails( ->GrantSendMidiSysExMessage( render_frame_host->GetProcess()->GetDeprecatedID()); } else if (permission_type == blink::PermissionType::GEOLOCATION) { - ElectronBrowserMainParts::Get() - ->GetGeolocationControl() - ->UserDidOptIntoLocationServices(); + if (IsGeolocationDisabledViaCommandLine()) { + results.push_back(content::PermissionResult( + blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED)); + continue; + } else { + ElectronBrowserMainParts::Get() + ->GetGeolocationControl() + ->UserDidOptIntoLocationServices(); + } } - statuses.push_back(blink::mojom::PermissionStatus::GRANTED); + results.push_back(content::PermissionResult( + blink::mojom::PermissionStatus::GRANTED, + content::PermissionStatusSource::UNSPECIFIED)); } - std::move(response_callback).Run(statuses); + std::move(response_callback).Run(results); return; } @@ -235,12 +273,12 @@ void ElectronPermissionManager::RequestPermissionsWithDetails( void ElectronPermissionManager::OnPermissionResponse( int request_id, int permission_id, - blink::mojom::PermissionStatus status) { + content::PermissionResult result) { auto* pending_request = pending_requests_.Lookup(request_id); if (!pending_request) return; - pending_request->SetPermissionStatus(permission_id, status); + pending_request->SetPermissionStatus(permission_id, result.status); if (pending_request->IsComplete()) { pending_request->RunCallback(); pending_requests_.Remove(request_id); @@ -255,12 +293,14 @@ void ElectronPermissionManager::ResetPermission( void ElectronPermissionManager::RequestPermissionsFromCurrentDocument( content::RenderFrameHost* render_frame_host, const content::PermissionRequestDescription& request_description, - base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> + base::OnceCallback<void(const std::vector<content::PermissionResult>&)> callback) { if (render_frame_host->IsNestedWithinFencedFrame()) { - std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>( + std::move(callback).Run(std::vector<content::PermissionResult>( request_description.permissions.size(), - blink::mojom::PermissionStatus::DENIED)); + content::PermissionResult( + blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED))); return; } @@ -290,7 +330,7 @@ ElectronPermissionManager::GetPermissionResultForOriginWithoutContext( blink::mojom::PermissionStatus status = GetPermissionStatus(permission_descriptor, requesting_origin.GetURL(), embedding_origin.GetURL()); - return {status, content::PermissionStatusSource::UNSPECIFIED}; + return content::PermissionResult(status); } void ElectronPermissionManager::CheckBluetoothDevicePair( @@ -310,6 +350,10 @@ bool ElectronPermissionManager::CheckPermissionWithDetails( content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, base::Value::Dict details) const { + if (permission == blink::PermissionType::GEOLOCATION && + IsGeolocationDisabledViaCommandLine()) + return false; + if (check_handler_.is_null()) { if (permission == blink::PermissionType::DEPRECATED_SYNC_CLIPBOARD_READ) { return false; @@ -347,6 +391,10 @@ bool ElectronPermissionManager::CheckDevicePermission( const url::Origin& origin, const base::Value& device, ElectronBrowserContext* browser_context) const { + if (permission == blink::PermissionType::GEOLOCATION && + IsGeolocationDisabledViaCommandLine()) + return false; + if (device_permission_handler_.is_null()) return browser_context->CheckDevicePermission(origin, device, permission); @@ -391,13 +439,13 @@ ElectronPermissionManager::CheckProtectedUSBClasses( return protected_usb_handler_.Run(details); } -blink::mojom::PermissionStatus -ElectronPermissionManager::GetPermissionStatusForCurrentDocument( +content::PermissionResult +ElectronPermissionManager::GetPermissionResultForCurrentDocument( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, content::RenderFrameHost* render_frame_host, - bool /*should_include_device_status*/) { + bool should_include_device_status) { if (render_frame_host->IsNestedWithinFencedFrame()) - return blink::mojom::PermissionStatus::DENIED; + return content::PermissionResult(blink::mojom::PermissionStatus::DENIED); const auto permission = blink::PermissionDescriptorToPermissionType(permission_descriptor); @@ -409,30 +457,34 @@ ElectronPermissionManager::GetPermissionStatusForCurrentDocument( bool granted = CheckPermissionWithDetails( permission, render_frame_host, render_frame_host->GetLastCommittedOrigin().GetURL(), std::move(details)); - return granted ? blink::mojom::PermissionStatus::GRANTED - : blink::mojom::PermissionStatus::DENIED; + return granted ? content::PermissionResult( + blink::mojom::PermissionStatus::GRANTED) + : content::PermissionResult( + blink::mojom::PermissionStatus::DENIED); } -blink::mojom::PermissionStatus -ElectronPermissionManager::GetPermissionStatusForWorker( +content::PermissionResult +ElectronPermissionManager::GetPermissionResultForWorker( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, content::RenderProcessHost* render_process_host, const GURL& worker_origin) { - return GetPermissionStatus(permission_descriptor, worker_origin, - worker_origin); + blink::mojom::PermissionStatus status = + GetPermissionStatus(permission_descriptor, worker_origin, worker_origin); + return content::PermissionResult(status); } -blink::mojom::PermissionStatus -ElectronPermissionManager::GetPermissionStatusForEmbeddedRequester( +content::PermissionResult +ElectronPermissionManager::GetPermissionResultForEmbeddedRequester( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, content::RenderFrameHost* render_frame_host, - const url::Origin& overridden_origin) { + const url::Origin& requesting_origin) { if (render_frame_host->IsNestedWithinFencedFrame()) - return blink::mojom::PermissionStatus::DENIED; + return content::PermissionResult(blink::mojom::PermissionStatus::DENIED); - return GetPermissionStatus( - permission_descriptor, overridden_origin.GetURL(), - render_frame_host->GetLastCommittedOrigin().GetURL()); + blink::mojom::PermissionStatus status = + GetPermissionStatus(permission_descriptor, requesting_origin.GetURL(), + render_frame_host->GetLastCommittedOrigin().GetURL()); + return content::PermissionResult(status); } } // namespace electron diff --git a/shell/browser/electron_permission_manager.h b/shell/browser/electron_permission_manager.h index a0e720d93203d..9a0062ef631e5 100644 --- a/shell/browser/electron_permission_manager.h +++ b/shell/browser/electron_permission_manager.h @@ -43,10 +43,9 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { using USBProtectedClasses = std::vector<uint8_t>; - using StatusCallback = - base::OnceCallback<void(blink::mojom::PermissionStatus)>; - using StatusesCallback = base::OnceCallback<void( - const std::vector<blink::mojom::PermissionStatus>&)>; + using StatusCallback = base::OnceCallback<void(content::PermissionResult)>; + using StatusesCallback = + base::OnceCallback<void(const std::vector<content::PermissionResult>&)>; using PairCallback = base::OnceCallback<void(base::Value::Dict)>; using RequestHandler = base::RepeatingCallback<void(content::WebContents*, blink::PermissionType, @@ -67,6 +66,8 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { using BluetoothPairingHandler = base::RepeatingCallback<void(gin_helper::Dictionary, PairCallback)>; + static bool IsGeolocationDisabledViaCommandLine(); + void RequestPermissionWithDetails( blink::mojom::PermissionDescriptorPtr permission, content::RenderFrameHost* render_frame_host, @@ -82,6 +83,9 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { void SetProtectedUSBHandler(const ProtectedUSBHandler& handler); void SetBluetoothPairingHandler(const BluetoothPairingHandler& handler); + bool HasPermissionRequestHandler() const; + bool HasPermissionCheckHandler() const; + void CheckBluetoothDevicePair(gin_helper::Dictionary details, PairCallback pair_callback) const; @@ -111,7 +115,7 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { protected: void OnPermissionResponse(int request_id, int permission_id, - blink::mojom::PermissionStatus status); + content::PermissionResult result); // content::PermissionControllerDelegate: void RequestPermissions( @@ -128,22 +132,21 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { void RequestPermissionsFromCurrentDocument( content::RenderFrameHost* render_frame_host, const content::PermissionRequestDescription& request_description, - base::OnceCallback< - void(const std::vector<blink::mojom::PermissionStatus>&)> callback) - override; + base::OnceCallback<void(const std::vector<content::PermissionResult>&)> + callback) override; content::PermissionResult GetPermissionResultForOriginWithoutContext( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, const url::Origin& requesting_origin, const url::Origin& embedding_origin) override; - blink::mojom::PermissionStatus GetPermissionStatusForCurrentDocument( + content::PermissionResult GetPermissionResultForCurrentDocument( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, content::RenderFrameHost* render_frame_host, bool should_include_device_status) override; - blink::mojom::PermissionStatus GetPermissionStatusForWorker( + content::PermissionResult GetPermissionResultForWorker( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, content::RenderProcessHost* render_process_host, const GURL& worker_origin) override; - blink::mojom::PermissionStatus GetPermissionStatusForEmbeddedRequester( + content::PermissionResult GetPermissionResultForEmbeddedRequester( const blink::mojom::PermissionDescriptorPtr& permission_descriptor, content::RenderFrameHost* render_frame_host, const url::Origin& requesting_origin) override; diff --git a/shell/browser/electron_plugin_info_host_impl.cc b/shell/browser/electron_plugin_info_host_impl.cc index 456be676c4414..8a09038a05a76 100644 --- a/shell/browser/electron_plugin_info_host_impl.cc +++ b/shell/browser/electron_plugin_info_host_impl.cc @@ -49,7 +49,7 @@ void ElectronPluginInfoHostImpl::PluginsLoaded( std::vector<WebPluginInfo> matching_plugins; std::vector<std::string> mime_types; PluginService::GetInstance()->GetPluginInfoArray( - params.url, params.mime_type, true, &matching_plugins, &mime_types); + params.url, params.mime_type, &matching_plugins, &mime_types); if (!matching_plugins.empty()) { output->plugin = matching_plugins[0]; output->actual_mime_type = mime_types[0]; diff --git a/shell/browser/electron_web_ui_controller_factory.cc b/shell/browser/electron_web_ui_controller_factory.cc index d4b7d022e2aa3..6b5c4ff4e21e9 100644 --- a/shell/browser/electron_web_ui_controller_factory.cc +++ b/shell/browser/electron_web_ui_controller_factory.cc @@ -25,7 +25,7 @@ ElectronWebUIControllerFactory::~ElectronWebUIControllerFactory() = default; content::WebUI::TypeID ElectronWebUIControllerFactory::GetWebUIType( content::BrowserContext* browser_context, const GURL& url) { - if (const std::string_view host = url.host_piece(); + if (const std::string_view host = url.host(); host == chrome::kChromeUIDevToolsHost || host == chrome::kChromeUIAccessibilityHost) { return this; @@ -44,7 +44,7 @@ std::unique_ptr<content::WebUIController> ElectronWebUIControllerFactory::CreateWebUIControllerForURL( content::WebUI* web_ui, const GURL& url) { - const std::string_view host = url.host_piece(); + const std::string_view host = url.host(); if (host == chrome::kChromeUIDevToolsHost) { auto* browser_context = web_ui->GetWebContents()->GetBrowserContext(); diff --git a/shell/browser/event_emitter_mixin.h b/shell/browser/event_emitter_mixin.h index 7260f93407046..33d77a1bb1358 100644 --- a/shell/browser/event_emitter_mixin.h +++ b/shell/browser/event_emitter_mixin.h @@ -6,6 +6,7 @@ #define ELECTRON_SHELL_BROWSER_EVENT_EMITTER_MIXIN_H_ #include <string_view> +#include <type_traits> #include <utility> #include "gin/object_template_builder.h" @@ -57,17 +58,37 @@ class EventEmitterMixin { gin::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) { gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); auto* wrapper_info = &(static_cast<T*>(this)->kWrapperInfo); - v8::Local<v8::FunctionTemplate> constructor = - data->DeprecatedGetFunctionTemplate(wrapper_info); + + // DeprecatedWrapperInfo support will be removed as part of + // https://github.com/electron/electron/issues/47922 + constexpr bool is_deprecated_wrapper = + std::is_same_v<decltype(wrapper_info), gin::DeprecatedWrapperInfo*>; + + v8::Local<v8::FunctionTemplate> constructor; + if constexpr (is_deprecated_wrapper) { + constructor = data->DeprecatedGetFunctionTemplate(wrapper_info); + } else { + constructor = data->GetFunctionTemplate(wrapper_info); + } + + const char* class_name = ""; + if constexpr (is_deprecated_wrapper) { + class_name = static_cast<T*>(this)->GetTypeName(); + } else { + class_name = static_cast<T*>(this)->GetClassName(); + } + if (constructor.IsEmpty()) { constructor = v8::FunctionTemplate::New(isolate); - constructor->SetClassName( - gin::StringToV8(isolate, static_cast<T*>(this)->GetTypeName())); + constructor->SetClassName(gin::StringToV8(isolate, class_name)); constructor->Inherit(internal::GetEventEmitterTemplate(isolate)); - data->DeprecatedSetFunctionTemplate(wrapper_info, constructor); + if constexpr (is_deprecated_wrapper) { + data->DeprecatedSetFunctionTemplate(wrapper_info, constructor); + } else { + data->SetFunctionTemplate(wrapper_info, constructor); + } } - return gin::ObjectTemplateBuilder(isolate, - static_cast<T*>(this)->GetTypeName(), + return gin::ObjectTemplateBuilder(isolate, class_name, constructor->InstanceTemplate()); } }; diff --git a/shell/browser/extensions/api/extension_action/extension_action_api.cc b/shell/browser/extensions/api/extension_action/extension_action_api.cc index a57fef8aee609..a28a136b2524c 100644 --- a/shell/browser/extensions/api/extension_action/extension_action_api.cc +++ b/shell/browser/extensions/api/extension_action/extension_action_api.cc @@ -33,8 +33,7 @@ void ExtensionActionAPI::Observer::OnExtensionActionAPIShuttingDown() {} // ExtensionActionAPI // -ExtensionActionAPI::ExtensionActionAPI(content::BrowserContext* context) - : browser_context_(context), extension_prefs_(nullptr) {} +ExtensionActionAPI::ExtensionActionAPI(content::BrowserContext*) {} // static BrowserContextKeyedAPIFactory<ExtensionActionAPI>* @@ -49,10 +48,6 @@ ExtensionActionAPI* ExtensionActionAPI::Get(content::BrowserContext* context) { return BrowserContextKeyedAPIFactory<ExtensionActionAPI>::Get(context); } -ExtensionPrefs* ExtensionActionAPI::GetExtensionPrefs() { - return nullptr; -} - void ExtensionActionAPI::Shutdown() {} // diff --git a/shell/browser/extensions/api/extension_action/extension_action_api.h b/shell/browser/extensions/api/extension_action/extension_action_api.h index 4f4a557de0f65..16388b79f8111 100644 --- a/shell/browser/extensions/api/extension_action/extension_action_api.h +++ b/shell/browser/extensions/api/extension_action/extension_action_api.h @@ -5,7 +5,6 @@ #ifndef SHELL_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_ #define SHELL_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_ -#include "base/memory/raw_ptr.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/extension_action.h" #include "extensions/browser/extension_function.h" @@ -70,16 +69,10 @@ class ExtensionActionAPI : public BrowserContextKeyedAPI { private: friend class BrowserContextKeyedAPIFactory<ExtensionActionAPI>; - ExtensionPrefs* GetExtensionPrefs(); - // BrowserContextKeyedAPI implementation. void Shutdown() override; static const char* service_name() { return "ExtensionActionAPI"; } static const bool kServiceRedirectedInIncognito = true; - - raw_ptr<content::BrowserContext> browser_context_; - - raw_ptr<ExtensionPrefs> extension_prefs_; }; // Implementation of the browserAction and pageAction APIs. diff --git a/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc b/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc index bab4336953758..985059a1f0c79 100644 --- a/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc +++ b/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.cc @@ -4,20 +4,31 @@ #include "shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h" +#include <cmath> +#include <memory> #include <string> #include "base/memory/weak_ptr.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "chrome/browser/pdf/pdf_pref_names.h" // nogncheck #include "chrome/browser/pdf/pdf_viewer_stream_manager.h" #include "chrome/common/extensions/api/pdf_viewer_private.h" #include "chrome/common/pref_names.h" #include "components/pdf/common/constants.h" #include "components/prefs/pref_service.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" +#include "pdf/buildflags.h" #include "url/url_constants.h" +#if BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) +#include "chrome/browser/save_to_drive/content_reader.h" +#include "chrome/browser/save_to_drive/pdf_content_reader.h" +#include "chrome/browser/save_to_drive/save_to_drive_event_dispatcher.h" +#include "chrome/browser/save_to_drive/save_to_drive_flow.h" +#endif // BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) + namespace extensions { namespace { @@ -25,6 +36,8 @@ namespace { namespace IsAllowedLocalFileAccess = api::pdf_viewer_private::IsAllowedLocalFileAccess; +namespace SaveToDrive = api::pdf_viewer_private::SaveToDrive; + namespace SetPdfPluginAttributes = api::pdf_viewer_private::SetPdfPluginAttributes; @@ -68,6 +81,27 @@ base::WeakPtr<StreamContainer> GetStreamContainer( return pdf_viewer_stream_manager->GetStreamContainer(embedder_host); } +#if BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) +// Converts the `SaveRequestType` enum from the extension API to the mojom enum. +pdf::mojom::SaveRequestType ToMojomSaveRequestType( + api::pdf_viewer_private::SaveRequestType request_type) { + switch (request_type) { + case api::pdf_viewer_private::SaveRequestType::kOriginal: + return pdf::mojom::SaveRequestType::kOriginal; + case api::pdf_viewer_private::SaveRequestType::kEdited: + return pdf::mojom::SaveRequestType::kEdited; + case api::pdf_viewer_private::SaveRequestType::kSearchified: + return pdf::mojom::SaveRequestType::kSearchified; + case api::pdf_viewer_private::SaveRequestType::kAnnotation: + return pdf::mojom::SaveRequestType::kAnnotation; + case api::pdf_viewer_private::SaveRequestType::kNone: + // It should not be called with `kNone`. + NOTREACHED(); + } + NOTREACHED(); +} +#endif // BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) + } // namespace PdfViewerPrivateGetStreamInfoFunction::PdfViewerPrivateGetStreamInfoFunction() = @@ -107,6 +141,64 @@ PdfViewerPrivateIsAllowedLocalFileAccessFunction::Run() { IsUrlAllowedToEmbedLocalFiles(GURL(params->url), base::Value::List()))); } +PdfViewerPrivateSaveToDriveFunction::PdfViewerPrivateSaveToDriveFunction() = + default; + +PdfViewerPrivateSaveToDriveFunction::~PdfViewerPrivateSaveToDriveFunction() = + default; + +ExtensionFunction::ResponseAction PdfViewerPrivateSaveToDriveFunction::Run() { +#if BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) + std::optional<SaveToDrive::Params> params = + SaveToDrive::Params::Create(args()); + EXTENSION_FUNCTION_VALIDATE(params); + if (params->save_request_type != + api::pdf_viewer_private::SaveRequestType::kNone) { + return RunSaveToDriveFlow(params->save_request_type); + } + return StopSaveToDriveFlow(); +#else + return RespondNow(Error("Not supported")); +#endif // BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) +} + +#if BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) +ExtensionFunction::ResponseAction +PdfViewerPrivateSaveToDriveFunction::RunSaveToDriveFlow( + api::pdf_viewer_private::SaveRequestType request_type) { + using SaveToDriveFlow = save_to_drive::SaveToDriveFlow; + + if (SaveToDriveFlow::GetForCurrentDocument(render_frame_host())) { + return RespondNow(Error("An upload is already in progress")); + } + auto event_dispatcher = + save_to_drive::SaveToDriveEventDispatcher::Create(render_frame_host()); + if (!event_dispatcher) { + return RespondNow(Error("Failed to create event dispatcher")); + } + auto content_reader = std::make_unique<save_to_drive::PDFContentReader>( + render_frame_host(), ToMojomSaveRequestType(request_type)); + save_to_drive::SaveToDriveFlow::CreateForCurrentDocument( + render_frame_host(), std::move(event_dispatcher), + std::move(content_reader)); + auto* flow = SaveToDriveFlow::GetForCurrentDocument(render_frame_host()); + flow->Run(); + return RespondNow(NoArguments()); +} + +ExtensionFunction::ResponseAction +PdfViewerPrivateSaveToDriveFunction::StopSaveToDriveFlow() { + using SaveToDriveFlow = save_to_drive::SaveToDriveFlow; + + auto* flow = SaveToDriveFlow::GetForCurrentDocument(render_frame_host()); + if (!flow) { + return RespondNow(Error("Failed to get SaveToDriveFlow")); + } + flow->Stop(); + return RespondNow(NoArguments()); +} +#endif // BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) + PdfViewerPrivateSetPdfDocumentTitleFunction:: PdfViewerPrivateSetPdfDocumentTitleFunction() = default; diff --git a/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h b/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h index f184924ad8db8..b42cfd3a0a1f9 100644 --- a/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h +++ b/shell/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h @@ -5,7 +5,9 @@ #ifndef ELECTRON_SHELL_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_API_H_ #define ELECTRON_SHELL_BROWSER_EXTENSIONS_API_PDF_VIEWER_PRIVATE_PDF_VIEWER_PRIVATE_API_H_ +#include "chrome/common/extensions/api/pdf_viewer_private.h" #include "extensions/browser/extension_function.h" +#include "pdf/buildflags.h" namespace extensions { @@ -46,6 +48,32 @@ class PdfViewerPrivateIsAllowedLocalFileAccessFunction ResponseAction Run() override; }; +class PdfViewerPrivateSaveToDriveFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("pdfViewerPrivate.saveToDrive", + PDFVIEWERPRIVATE_SAVETODRIVE) + + PdfViewerPrivateSaveToDriveFunction(); + PdfViewerPrivateSaveToDriveFunction( + const PdfViewerPrivateSaveToDriveFunction&) = delete; + PdfViewerPrivateSaveToDriveFunction& operator=( + const PdfViewerPrivateSaveToDriveFunction&) = delete; + + protected: + ~PdfViewerPrivateSaveToDriveFunction() override; + + // Override from ExtensionFunction: + ResponseAction Run() override; + +#if BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) + private: + ResponseAction RunSaveToDriveFlow( + api::pdf_viewer_private::SaveRequestType request_type); + + ResponseAction StopSaveToDriveFlow(); +#endif // BUILDFLAG(ENABLE_PDF_SAVE_TO_DRIVE) +}; + class PdfViewerPrivateSetPdfDocumentTitleFunction : public ExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("pdfViewerPrivate.setPdfDocumentTitle", diff --git a/shell/browser/extensions/api/resources_private/resources_private_api.cc b/shell/browser/extensions/api/resources_private/resources_private_api.cc index 61a508f409952..f1170e574ab9f 100644 --- a/shell/browser/extensions/api/resources_private/resources_private_api.cc +++ b/shell/browser/extensions/api/resources_private/resources_private_api.cc @@ -39,18 +39,15 @@ ResourcesPrivateGetStringsFunction::~ResourcesPrivateGetStringsFunction() = default; ExtensionFunction::ResponseAction ResourcesPrivateGetStringsFunction::Run() { - std::optional<get_strings::Params> params( - get_strings::Params::Create(args())); + get_strings::Params params = get_strings::Params::Create(args()).value(); base::Value::Dict dict; - api::resources_private::Component component = params->component; - - switch (component) { + switch (params.component) { case api::resources_private::Component::kPdf: #if BUILDFLAG(ENABLE_PDF_VIEWER) - pdf_extension_util::AddStrings( - pdf_extension_util::PdfViewerContext::kPdfViewer, &dict); - pdf_extension_util::AddAdditionalData(browser_context(), &dict); + dict = pdf_extension_util::GetStrings( + pdf_extension_util::PdfViewerContext::kAll); + dict.Merge(pdf_extension_util::GetAdditionalData(browser_context())); #endif break; case api::resources_private::Component::kIdentity: diff --git a/shell/browser/extensions/api/tabs/tabs_api.cc b/shell/browser/extensions/api/tabs/tabs_api.cc index 010f7ae15521e..fb6b6c37b2383 100644 --- a/shell/browser/extensions/api/tabs/tabs_api.cc +++ b/shell/browser/extensions/api/tabs/tabs_api.cc @@ -510,7 +510,7 @@ bool IsKillURL(const GURL& url) { content::kChromeUIMemoryExhaustHost, }); - return kKillHosts.contains(url.host_piece()); + return kKillHosts.contains(url.host()); } GURL ResolvePossiblyRelativeURL(const std::string& url_string, diff --git a/shell/browser/extensions/electron_component_extension_resource_manager.cc b/shell/browser/extensions/electron_component_extension_resource_manager.cc index da72977cfe051..c5b6fb8cca559 100644 --- a/shell/browser/extensions/electron_component_extension_resource_manager.cc +++ b/shell/browser/extensions/electron_component_extension_resource_manager.cc @@ -28,14 +28,12 @@ ElectronComponentExtensionResourceManager:: AddComponentResourceEntries(kPdfResources); // Register strings for the PDF viewer, so that $i18n{} replacements work. - base::Value::Dict pdf_strings; - pdf_extension_util::AddStrings( - pdf_extension_util::PdfViewerContext::kPdfViewer, &pdf_strings); + base::Value::Dict dict = pdf_extension_util::GetStrings( + pdf_extension_util::PdfViewerContext::kPdfViewer); ui::TemplateReplacements pdf_viewer_replacements; - ui::TemplateReplacementsFromDictionaryValue(pdf_strings, - &pdf_viewer_replacements); - extension_template_replacements_[extension_misc::kPdfExtensionId] = + ui::TemplateReplacementsFromDictionaryValue(dict, &pdf_viewer_replacements); + template_replacements_[extension_misc::kPdfExtensionId] = std::move(pdf_viewer_replacements); #endif } @@ -69,8 +67,8 @@ bool ElectronComponentExtensionResourceManager::IsComponentExtensionResource( const ui::TemplateReplacements* ElectronComponentExtensionResourceManager::GetTemplateReplacementsForExtension( const std::string& extension_id) const { - auto it = extension_template_replacements_.find(extension_id); - if (it == extension_template_replacements_.end()) { + auto it = template_replacements_.find(extension_id); + if (it == template_replacements_.end()) { return nullptr; } return &it->second; diff --git a/shell/browser/extensions/electron_component_extension_resource_manager.h b/shell/browser/extensions/electron_component_extension_resource_manager.h index b56d7ce1a6f31..4457b2e2e7459 100644 --- a/shell/browser/extensions/electron_component_extension_resource_manager.h +++ b/shell/browser/extensions/electron_component_extension_resource_manager.h @@ -47,8 +47,7 @@ class ElectronComponentExtensionResourceManager std::map<base::FilePath, int> path_to_resource_id_; // A map from an extension ID to its i18n template replacements. - std::map<std::string, ui::TemplateReplacements> - extension_template_replacements_; + std::map<std::string, ui::TemplateReplacements> template_replacements_; }; } // namespace extensions diff --git a/shell/browser/extensions/electron_extension_loader.cc b/shell/browser/extensions/electron_extension_loader.cc index 19bc33423abfa..26fef0216fc63 100644 --- a/shell/browser/extensions/electron_extension_loader.cc +++ b/shell/browser/extensions/electron_extension_loader.cc @@ -145,8 +145,9 @@ void ElectronExtensionLoader::FinishExtensionLoad( if (extension) { extension_registrar_->AddExtension(extension); - // Write extension install time to ExtensionPrefs. This is required by - // WebRequestAPI which calls extensions::ExtensionPrefs::GetInstallTime. + // Write extension install time to ExtensionPrefs. + // This is required by extensions::WebRequestAPI + // which calls extensions::ExtensionPrefs::GetInstallTime. // // Implementation for writing the pref was based on // PreferenceAPIBase::SetExtensionControlledPref. diff --git a/shell/browser/extensions/electron_extension_system.cc b/shell/browser/extensions/electron_extension_system.cc index 74ccee197f952..47689d290a197 100644 --- a/shell/browser/extensions/electron_extension_system.cc +++ b/shell/browser/extensions/electron_extension_system.cc @@ -108,7 +108,7 @@ std::unique_ptr<base::Value::Dict> ParseManifest( void ElectronExtensionSystem::LoadComponentExtensions() { #if BUILDFLAG(ENABLE_PDF_VIEWER) - std::string utf8_error; + std::u16string error; std::string pdf_manifest_string = pdf_extension_util::GetManifest(); std::unique_ptr<base::Value::Dict> pdf_manifest = ParseManifest(pdf_manifest_string); @@ -119,7 +119,7 @@ void ElectronExtensionSystem::LoadComponentExtensions() { scoped_refptr<const Extension> pdf_extension = extensions::Extension::Create( root_directory, extensions::mojom::ManifestLocation::kComponent, - *pdf_manifest, extensions::Extension::REQUIRE_KEY, &utf8_error); + *pdf_manifest, extensions::Extension::REQUIRE_KEY, &error); extension_loader_->registrar()->AddExtension(pdf_extension); } #endif diff --git a/shell/browser/extensions/electron_extensions_browser_client.cc b/shell/browser/extensions/electron_extensions_browser_client.cc index ec73efbc9a5b3..3e5ed3161a5c5 100644 --- a/shell/browser/extensions/electron_extensions_browser_client.cc +++ b/shell/browser/extensions/electron_extensions_browser_client.cc @@ -12,7 +12,6 @@ #include "base/path_service.h" #include "chrome/browser/extensions/chrome_url_request_util.h" #include "chrome/common/chrome_paths.h" -#include "chrome/common/extensions/chrome_manifest_url_handlers.h" #include "components/version_info/version_info.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -32,6 +31,8 @@ #include "extensions/common/features/feature_channel.h" #include "extensions/common/file_util.h" #include "extensions/common/manifest_constants.h" +#include "extensions/common/manifest_handlers/chrome_url_overrides_handler.h" +#include "extensions/common/manifest_handlers/devtools_page_handler.h" #include "extensions/common/manifest_url_handlers.h" #include "services/network/public/mojom/url_loader.mojom.h" #include "shell/browser/browser.h" diff --git a/shell/browser/extensions/electron_messaging_delegate.cc b/shell/browser/extensions/electron_messaging_delegate.cc index 0ec714a4825d3..a76c85f2b2bbc 100644 --- a/shell/browser/extensions/electron_messaging_delegate.cc +++ b/shell/browser/extensions/electron_messaging_delegate.cc @@ -22,7 +22,7 @@ #include "extensions/common/api/messaging/port_id.h" #include "extensions/common/extension.h" #include "shell/browser/api/electron_api_web_contents.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" #include "url/gurl.h" namespace extensions { diff --git a/shell/browser/feature_list.cc b/shell/browser/feature_list.cc index ae98b133ea5d2..e5c5c957f5537 100644 --- a/shell/browser/feature_list.cc +++ b/shell/browser/feature_list.cc @@ -57,13 +57,13 @@ void InitializeFeatureList() { // See https://chromium-review.googlesource.com/c/chromium/src/+/6626905 // Needed so that ElectronBrowserClient::RegisterPendingSiteInstance does // not throw a check. - std::string(", TraceSiteInstanceGetProcessCreation"); + std::string(", TraceSiteInstanceGetProcessCreation") + + // See https://chromium-review.googlesource.com/c/chromium/src/+/6910012 + // Needed until we rework some of our logic and checks to enable this + // properly. + std::string(",") + network::features::kLocalNetworkAccessChecks.name; #if BUILDFLAG(IS_WIN) - disable_features += - // Delayed spellcheck initialization is causing the - // 'custom dictionary word list API' spec to crash. - std::string(",") + spellcheck::kWinDelaySpellcheckServiceInit.name; // Refs https://issues.chromium.org/issues/401996981 // TODO(deepak1556): Remove this once test added in // https://github.com/electron/electron/pull/12904 diff --git a/shell/browser/file_system_access/file_system_access_permission_context.cc b/shell/browser/file_system_access/file_system_access_permission_context.cc index 34eb74a7f6bb2..2dcbfcb95cf93 100644 --- a/shell/browser/file_system_access/file_system_access_permission_context.cc +++ b/shell/browser/file_system_access/file_system_access_permission_context.cc @@ -257,6 +257,28 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl // FileSystemAccessPermissionGrant: PermissionStatus GetStatus() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + auto* permission_manager = + static_cast<electron::ElectronPermissionManager*>( + context_->browser_context()->GetPermissionControllerDelegate()); + if (permission_manager && permission_manager->HasPermissionCheckHandler()) { + base::Value::Dict details; + details.Set("filePath", base::FilePathToValue(path_info_.path)); + details.Set("isDirectory", handle_type_ == HandleType::kDirectory); + details.Set("fileAccessType", + type_ == GrantType::kWrite ? "writable" : "readable"); + + bool granted = permission_manager->CheckPermissionWithDetails( + blink::PermissionType::FILE_SYSTEM, nullptr, origin_.GetURL(), + std::move(details)); + return granted ? PermissionStatus::GRANTED : PermissionStatus::DENIED; + } + + return status_; + } + + PermissionStatus GetActivePermissionStatus() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return status_; } @@ -279,8 +301,8 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl // Check if a permission request has already been processed previously. This // check is done first because we don't want to reset the status of a // permission if it has already been granted. - if (GetStatus() != PermissionStatus::ASK || !context_) { - if (GetStatus() == PermissionStatus::GRANTED) { + if (GetActivePermissionStatus() != PermissionStatus::ASK || !context_) { + if (GetActivePermissionStatus() == PermissionStatus::GRANTED) { SetStatus(PermissionStatus::GRANTED); } std::move(callback).Run(PermissionRequestOutcome::kRequestAborted); @@ -294,7 +316,7 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl return; } - // Don't request permission for an inactive RenderFrameHost as the + // Don't request permission for an inactive RenderFrameHost as the // page might not distinguish properly between user denying the permission // and automatic rejection. if (rfh->IsInactiveAndDisallowActivation( @@ -347,7 +369,7 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl permission_manager->RequestPermissionWithDetails( content::PermissionDescriptorUtil:: CreatePermissionDescriptorForPermissionType(type), - rfh, origin, false, std::move(details), + rfh, origin, rfh->HasTransientUserActivation(), std::move(details), base::BindOnce(&PermissionGrantImpl::OnPermissionRequestResult, this, std::move(callback))); } @@ -394,7 +416,8 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl return; } - DCHECK_EQ(entry_it->second->GetStatus(), PermissionStatus::GRANTED); + DCHECK_EQ(entry_it->second->GetActivePermissionStatus(), + PermissionStatus::GRANTED); auto* const grant_impl = entry_it->second; grant_impl->SetPath(new_path); @@ -415,10 +438,10 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl private: void OnPermissionRequestResult( base::OnceCallback<void(PermissionRequestOutcome)> callback, - blink::mojom::PermissionStatus status) { + content::PermissionResult result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (status == blink::mojom::PermissionStatus::GRANTED) { + if (result.status == blink::mojom::PermissionStatus::GRANTED) { SetStatus(PermissionStatus::GRANTED); std::move(callback).Run(PermissionRequestOutcome::kUserGranted); } else { @@ -916,6 +939,14 @@ void FileSystemAccessPermissionContext::NotifyEntryMoved( } } +void FileSystemAccessPermissionContext::NotifyEntryModified( + const url::Origin& origin, + const content::PathInfo& path) {} + +void FileSystemAccessPermissionContext::NotifyEntryRemoved( + const url::Origin& origin, + const content::PathInfo& path) {} + void FileSystemAccessPermissionContext::OnFileCreatedFromShowSaveFilePicker( const GURL& file_picker_binding_context, const storage::FileSystemURL& url) {} @@ -965,7 +996,8 @@ bool FileSystemAccessPermissionContext::OriginHasReadAccess( auto it = active_permissions_map_.find(origin); if (it != active_permissions_map_.end()) { return std::ranges::any_of(it->second.read_grants, [&](const auto& grant) { - return grant.second->GetStatus() == PermissionStatus::GRANTED; + return grant.second->GetActivePermissionStatus() == + PermissionStatus::GRANTED; }); } @@ -979,7 +1011,8 @@ bool FileSystemAccessPermissionContext::OriginHasWriteAccess( auto it = active_permissions_map_.find(origin); if (it != active_permissions_map_.end()) { return std::ranges::any_of(it->second.write_grants, [&](const auto& grant) { - return grant.second->GetStatus() == PermissionStatus::GRANTED; + return grant.second->GetActivePermissionStatus() == + PermissionStatus::GRANTED; }); } @@ -1033,7 +1066,7 @@ bool FileSystemAccessPermissionContext::AncestorHasActivePermission( parent = parent.DirName()) { auto i = relevant_grants.find(parent); if (i != relevant_grants.end() && i->second && - i->second->GetStatus() == PermissionStatus::GRANTED) { + i->second->GetActivePermissionStatus() == PermissionStatus::GRANTED) { return true; } } @@ -1056,7 +1089,7 @@ void FileSystemAccessPermissionContext::PermissionGrantDestroyed( // be granted but won't be visible in any UI because the permission context // isn't tracking them anymore. if (grant_it == grants.end()) { - DCHECK_EQ(PermissionStatus::DENIED, grant->GetStatus()); + DCHECK_EQ(PermissionStatus::DENIED, grant->GetActivePermissionStatus()); return; } diff --git a/shell/browser/file_system_access/file_system_access_permission_context.h b/shell/browser/file_system_access/file_system_access_permission_context.h index 591c1288e2dda..2419ae536df3d 100644 --- a/shell/browser/file_system_access/file_system_access_permission_context.h +++ b/shell/browser/file_system_access/file_system_access_permission_context.h @@ -102,6 +102,10 @@ class FileSystemAccessPermissionContext void NotifyEntryMoved(const url::Origin& origin, const content::PathInfo& old_path, const content::PathInfo& new_path) override; + void NotifyEntryModified(const url::Origin& origin, + const content::PathInfo& path) override; + void NotifyEntryRemoved(const url::Origin& origin, + const content::PathInfo& path) override; void OnFileCreatedFromShowSaveFilePicker( const GURL& file_picker_binding_context, diff --git a/shell/browser/font_defaults.cc b/shell/browser/font_defaults.cc index 884021b7d55d6..5432caf584801 100644 --- a/shell/browser/font_defaults.cc +++ b/shell/browser/font_defaults.cc @@ -308,7 +308,7 @@ auto MakeDefaultFontCopier() { namespace electron { void SetFontDefaults(blink::web_pref::WebPreferences* prefs) { - static const auto copy_default_fonts_to_web_prefs = MakeDefaultFontCopier(); + static const auto& copy_default_fonts_to_web_prefs = MakeDefaultFontCopier(); copy_default_fonts_to_web_prefs(prefs); } diff --git a/shell/browser/login_handler.cc b/shell/browser/login_handler.cc index 8813b08363fd2..00ddcafc2792d 100644 --- a/shell/browser/login_handler.cc +++ b/shell/browser/login_handler.cc @@ -42,6 +42,23 @@ LoginHandler::LoginHandler( response_headers, first_auth_attempt)); } +LoginHandler::LoginHandler( + const net::AuthChallengeInfo& auth_info, + content::WebContents* web_contents, + base::ProcessId process_id, + const GURL& url, + scoped_refptr<net::HttpResponseHeaders> response_headers, + content::LoginDelegate::LoginAuthRequiredCallback auth_required_callback) + : LoginHandler(auth_info, + web_contents, + /*is_request_for_primary_main_frame=*/false, + /*is_request_for_navigation=*/false, + process_id, + url, + std::move(response_headers), + /*first_auth_attempt=*/false, + std::move(auth_required_callback)) {} + void LoginHandler::EmitEvent( net::AuthChallengeInfo auth_info, content::WebContents* web_contents, diff --git a/shell/browser/login_handler.h b/shell/browser/login_handler.h index 144b97cc00b74..ef73b259336e1 100644 --- a/shell/browser/login_handler.h +++ b/shell/browser/login_handler.h @@ -32,6 +32,13 @@ class LoginHandler : public content::LoginDelegate { scoped_refptr<net::HttpResponseHeaders> response_headers, bool first_auth_attempt, content::LoginDelegate::LoginAuthRequiredCallback auth_required_callback); + LoginHandler( + const net::AuthChallengeInfo& auth_info, + content::WebContents* web_contents, + base::ProcessId process_id, + const GURL& url, + scoped_refptr<net::HttpResponseHeaders> response_headers, + content::LoginDelegate::LoginAuthRequiredCallback auth_required_callback); ~LoginHandler() override; // disable copy diff --git a/shell/browser/native_window.cc b/shell/browser/native_window.cc index f69be2feb6051..be8e6f07dd062 100644 --- a/shell/browser/native_window.cc +++ b/shell/browser/native_window.cc @@ -10,22 +10,31 @@ #include "base/containers/contains.h" #include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" #include "content/public/browser/web_contents_user_data.h" #include "include/core/SkColor.h" #include "shell/browser/background_throttling_source.h" #include "shell/browser/browser.h" +#include "shell/browser/browser_process_impl.h" #include "shell/browser/draggable_region_provider.h" +#include "shell/browser/electron_browser_main_parts.h" #include "shell/browser/native_window_features.h" #include "shell/browser/ui/drag_util.h" #include "shell/browser/window_list.h" #include "shell/common/color_util.h" +#include "shell/common/electron_constants.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/persistent_dictionary.h" #include "shell/common/options_switches.h" #include "ui/base/hit_test.h" #include "ui/compositor/compositor.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/display/types/display_constants.h" #include "ui/views/widget/widget.h" #if !BUILDFLAG(IS_MAC) @@ -95,6 +104,12 @@ gfx::Size GetExpandedWindowSize(const NativeWindow* window, } #endif +// Check if display is fake (default display ID) or has invalid dimensions +bool hasInvalidDisplay(const display::Display& display) { + return display.id() == display::kDefaultDisplayId || + display.size().width() == 0 || display.size().height() == 0; +} + } // namespace NativeWindow::NativeWindow(const gin_helper::Dictionary& options, @@ -104,7 +119,8 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options, transparent_{options.ValueOrDefault(options::kTransparent, false)}, enable_larger_than_screen_{ options.ValueOrDefault(options::kEnableLargerThanScreen, false)}, - is_modal_{parent != nullptr && options.ValueOrDefault("modal", false)}, + is_modal_{parent != nullptr && + options.ValueOrDefault(options::kModal, false)}, has_frame_{options.ValueOrDefault(options::kFrame, true) && title_bar_style_ == TitleBarStyle::kNormal}, parent_{parent} { @@ -114,6 +130,38 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options, options.Get(options::kVibrancyType, &vibrancy_); #endif + options.Get(options::kName, &window_name_); + + if (gin_helper::Dictionary persistence_options; + options.Get(options::kWindowStatePersistence, &persistence_options)) { + // Restore bounds by default + restore_bounds_ = true; + persistence_options.Get(options::kBounds, &restore_bounds_); + // Restore display mode by default + restore_display_mode_ = true; + persistence_options.Get(options::kDisplayMode, &restore_display_mode_); + window_state_persistence_enabled_ = true; + } else if (bool flag; options.Get(options::kWindowStatePersistence, &flag)) { + restore_bounds_ = flag; + restore_display_mode_ = flag; + window_state_persistence_enabled_ = flag; + } + + // Initialize prefs_ to save/restore window bounds if we have a valid window + // name and window state persistence is enabled. + if (window_state_persistence_enabled_ && !window_name_.empty()) { + // Move this out if there's a need to initialize prefs_ for other features + if (auto* browser_process = + electron::ElectronBrowserMainParts::Get()->browser_process()) { + DCHECK(browser_process); + prefs_ = browser_process->local_state(); + } + } else if (window_state_persistence_enabled_ && window_name_.empty()) { + window_state_persistence_enabled_ = false; + LOG(WARNING) << "Window state persistence enabled but no window name " + "provided. Window state will not be persisted."; + } + if (gin_helper::Dictionary dict; options.Get(options::ktitleBarOverlay, &dict)) { titlebar_overlay_ = true; @@ -213,7 +261,14 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) { options.Get(options::kFullScreenable, &fullscreenable); SetFullScreenable(fullscreenable); - if (fullscreen) + // Restore window state (bounds and display mode) at this point in + // initialization. We deliberately restore bounds before display modes + // (fullscreen/kiosk) since the target display for these states depends on the + // window's initial bounds. Also, restoring here ensures we respect min/max + // width/height and fullscreenable constraints. + RestoreWindowState(options); + + if (fullscreen && !restore_display_mode_) SetFullScreen(true); if (bool val; options.Get(options::kResizable, &val)) @@ -222,7 +277,8 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) { if (bool val; options.Get(options::kSkipTaskbar, &val)) SetSkipTaskbar(val); - if (bool val; options.Get(options::kKiosk, &val) && val) + if (bool val; + options.Get(options::kKiosk, &val) && val && !restore_display_mode_) SetKiosk(val); #if BUILDFLAG(IS_MAC) @@ -242,7 +298,9 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) { SetBackgroundColor(background_color); SetTitle(options.ValueOrDefault(options::kTitle, Browser::Get()->GetName())); - + // Save updated window state after restoration adjustments are complete if + // any. + SaveWindowState(); // Then show it. if (options.ValueOrDefault(options::kShow, true)) Show(); @@ -655,6 +713,10 @@ void NativeWindow::NotifyLayoutWindowControlsOverlay() { *bounds); } +void NativeWindow::NotifyWindowStateRestored() { + observers_.Notify(&NativeWindowObserver::OnWindowStateRestored); +} + #if BUILDFLAG(IS_WIN) void NativeWindow::NotifyWindowMessage(UINT message, WPARAM w_param, @@ -757,10 +819,14 @@ void NativeWindow::SetAccessibleTitle(const std::string& title) { WidgetDelegate::SetAccessibleTitle(base::UTF8ToUTF16(title)); } -std::string NativeWindow::GetAccessibleTitle() { +std::string NativeWindow::GetAccessibleTitle() const { return base::UTF16ToUTF8(GetAccessibleWindowTitle()); } +std::string NativeWindow::GetName() const { + return window_name_; +} + void NativeWindow::HandlePendingFullscreenTransitions() { if (pending_transitions_.empty()) { set_fullscreen_transition_type(FullScreenTransitionType::kNone); @@ -793,6 +859,252 @@ bool NativeWindow::IsTranslucent() const { return false; } +void NativeWindow::DebouncedSaveWindowState() { + save_window_state_timer_.Start( + FROM_HERE, base::Milliseconds(200), + base::BindOnce(&NativeWindow::SaveWindowState, base::Unretained(this))); +} + +void NativeWindow::SaveWindowState() { + if (!window_state_persistence_enabled_ || is_being_restored_) + return; + + gfx::Rect bounds = GetBounds(); + + if (bounds.width() == 0 || bounds.height() == 0) { + LOG(WARNING) << "Window state not saved - window bounds are invalid"; + return; + } + + const display::Screen* screen = display::Screen::Get(); + DCHECK(screen); + // GetDisplayMatching returns a fake display with 1920x1080 resolution at + // (0,0) when no physical displays are attached. + // https://source.chromium.org/chromium/chromium/src/+/main:ui/display/display.cc;l=184;drc=e4f1aef5f3ec30a28950d766612cc2c04c822c71 + const display::Display display = screen->GetDisplayMatching(bounds); + + // Skip window state persistence when display has invalid dimensions (0x0) or + // is fake (ID 0xFF). Invalid displays could cause incorrect window bounds to + // be saved, leading to positioning issues during restoration. + // https://source.chromium.org/chromium/chromium/src/+/main:ui/display/types/display_constants.h;l=28;drc=e4f1aef5f3ec30a28950d766612cc2c04c822c71 + if (hasInvalidDisplay(display)) { + LOG(WARNING) + << "Window state not saved - no physical display attached or current " + "display has invalid bounds"; + return; + } + + ScopedDictPrefUpdate update(prefs_, electron::kWindowStates); + const base::Value::Dict* existing_prefs = update->FindDict(window_name_); + + // When the window is in a special display mode (fullscreen, kiosk, or + // maximized), save the previously stored window bounds instead of + // the current bounds. This ensures that when the window is restored, it can + // be restored to its original position and size if display mode is not + // preserved via windowStatePersistence. + if (!IsNormal() && existing_prefs) { + std::optional<int> left = existing_prefs->FindInt(electron::kLeft); + std::optional<int> top = existing_prefs->FindInt(electron::kTop); + std::optional<int> right = existing_prefs->FindInt(electron::kRight); + std::optional<int> bottom = existing_prefs->FindInt(electron::kBottom); + + if (left && top && right && bottom) { + bounds = gfx::Rect(*left, *top, *right - *left, *bottom - *top); + } + } + + base::Value::Dict window_preferences; + window_preferences.Set(electron::kLeft, bounds.x()); + window_preferences.Set(electron::kTop, bounds.y()); + window_preferences.Set(electron::kRight, bounds.right()); + window_preferences.Set(electron::kBottom, bounds.bottom()); + + window_preferences.Set(electron::kMaximized, IsMaximized()); + window_preferences.Set(electron::kFullscreen, IsFullscreen()); + window_preferences.Set(electron::kKiosk, IsKiosk()); + + gfx::Rect work_area = display.work_area(); + + window_preferences.Set(electron::kWorkAreaLeft, work_area.x()); + window_preferences.Set(electron::kWorkAreaTop, work_area.y()); + window_preferences.Set(electron::kWorkAreaRight, work_area.right()); + window_preferences.Set(electron::kWorkAreaBottom, work_area.bottom()); + + update->Set(window_name_, std::move(window_preferences)); +} + +void NativeWindow::FlushWindowState() { + if (save_window_state_timer_.IsRunning()) { + save_window_state_timer_.FireNow(); + } else { + SaveWindowState(); + } +} + +void NativeWindow::RestoreWindowState(const gin_helper::Dictionary& options) { + if (!window_state_persistence_enabled_) + return; + + const base::Value& value = prefs_->GetValue(electron::kWindowStates); + const base::Value::Dict* window_preferences = + value.is_dict() ? value.GetDict().FindDict(window_name_) : nullptr; + + if (!window_preferences) + return; + + std::optional<int> saved_left = window_preferences->FindInt(electron::kLeft); + std::optional<int> saved_top = window_preferences->FindInt(electron::kTop); + std::optional<int> saved_right = + window_preferences->FindInt(electron::kRight); + std::optional<int> saved_bottom = + window_preferences->FindInt(electron::kBottom); + + std::optional<int> work_area_left = + window_preferences->FindInt(electron::kWorkAreaLeft); + std::optional<int> work_area_top = + window_preferences->FindInt(electron::kWorkAreaTop); + std::optional<int> work_area_right = + window_preferences->FindInt(electron::kWorkAreaRight); + std::optional<int> work_area_bottom = + window_preferences->FindInt(electron::kWorkAreaBottom); + + if (!saved_left || !saved_top || !saved_right || !saved_bottom || + !work_area_left || !work_area_top || !work_area_right || + !work_area_bottom) { + LOG(WARNING) << "Window state not restored - corrupted values found"; + return; + } + + gfx::Rect saved_bounds = + gfx::Rect(*saved_left, *saved_top, *saved_right - *saved_left, + *saved_bottom - *saved_top); + + display::Screen* screen = display::Screen::Get(); + DCHECK(screen); + + // Set the primary display as the target display for restoration. + display::Display display = screen->GetPrimaryDisplay(); + + // We identify the display with the minimal Manhattan distance to the saved + // bounds and set it as the target display for restoration. + int min_displacement = std::numeric_limits<int>::max(); + + for (const auto& candidate : screen->GetAllDisplays()) { + gfx::Rect test_bounds = saved_bounds; + test_bounds.AdjustToFit(candidate.work_area()); + int displacement = std::abs(test_bounds.x() - saved_bounds.x()) + + std::abs(test_bounds.y() - saved_bounds.y()); + + if (displacement < min_displacement) { + min_displacement = displacement; + display = candidate; + } + } + + // Skip window state restoration if current display has invalid dimensions or + // is fake. Restoring from invalid displays (0x0) or fake displays (ID 0xFF) + // could cause incorrect window positioning when later moved to real displays. + // https://source.chromium.org/chromium/chromium/src/+/main:ui/display/types/display_constants.h;l=28;drc=e4f1aef5f3ec30a28950d766612cc2c04c822c71 + if (hasInvalidDisplay(display)) { + LOG(WARNING) << "Window state not restored - no physical display attached " + "or current display has invalid bounds"; + return; + } + + gfx::Rect saved_work_area = gfx::Rect(*work_area_left, *work_area_top, + *work_area_right - *work_area_left, + *work_area_bottom - *work_area_top); + + // Set this to true before RestoreBounds to prevent SaveWindowState from being + // inadvertently triggered during the restoration process. + is_being_restored_ = true; + + if (restore_bounds_) { + RestoreBounds(display, saved_work_area, saved_bounds); + } + + if (restore_display_mode_) { + restore_display_mode_callback_ = base::BindOnce( + [](NativeWindow* window, base::Value::Dict prefs) { + if (auto kiosk = prefs.FindBool(electron::kKiosk); kiosk && *kiosk) { + window->SetKiosk(true); + } else if (auto fs = prefs.FindBool(electron::kFullscreen); + fs && *fs) { + window->SetFullScreen(true); + } else if (auto max = prefs.FindBool(electron::kMaximized); + max && *max) { + window->Maximize(); + } + }, + base::Unretained(this), window_preferences->Clone()); + } + + is_being_restored_ = false; + + NotifyWindowStateRestored(); +} + +void NativeWindow::FlushPendingDisplayMode() { + if (restore_display_mode_callback_) { + std::move(restore_display_mode_callback_).Run(); + } +} + +// This function is similar to Chromium's window bounds adjustment logic +// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/window_sizer/window_sizer.cc;l=350;drc=0ec56065ba588552f21633aa47280ba02c3cd160 +void NativeWindow::RestoreBounds(const display::Display& display, + const gfx::Rect& saved_work_area, + gfx::Rect& saved_bounds) { + if (saved_bounds.width() == 0 || saved_bounds.height() == 0) { + LOG(WARNING) << "Window bounds not restored - values are invalid"; + return; + } + + // Ensure that the window is at least kMinVisibleHeight * kMinVisibleWidth. + saved_bounds.set_height(std::max(kMinVisibleHeight, saved_bounds.height())); + saved_bounds.set_width(std::max(kMinVisibleWidth, saved_bounds.width())); + + const gfx::Rect work_area = display.work_area(); + // Ensure that the title bar is not above the work area. + if (saved_bounds.y() < work_area.y()) { + saved_bounds.set_y(work_area.y()); + } + + // Reposition and resize the bounds if the saved_work_area is different from + // the current work area and the current work area doesn't completely contain + // the bounds. + if (!saved_work_area.IsEmpty() && saved_work_area != work_area && + !work_area.Contains(saved_bounds)) { + saved_bounds.AdjustToFit(work_area); + } + +#if BUILDFLAG(IS_MAC) + // On mac, we want to be aggressive about repositioning windows that are + // partially offscreen. If the window is partially offscreen horizontally, + // snap to the nearest edge of the work area. This call also adjusts the + // height, width if needed to make the window fully visible. + saved_bounds.AdjustToFit(work_area); +#else + // On non-Mac platforms, we are less aggressive about repositioning. Simply + // ensure that at least kMinVisibleWidth * kMinVisibleHeight is visible + + const int min_y = work_area.y() + kMinVisibleHeight - saved_bounds.height(); + const int min_x = work_area.x() + kMinVisibleWidth - saved_bounds.width(); + const int max_y = work_area.bottom() - kMinVisibleHeight; + const int max_x = work_area.right() - kMinVisibleWidth; + // Reposition and resize the bounds to make it fully visible inside the work + // area. `min_x >= max_x` happens when work area and bounds are both small. + if (min_x >= max_x || min_y >= max_y) { + saved_bounds.AdjustToFit(work_area); + } else { + saved_bounds.set_y(std::clamp(saved_bounds.y(), min_y, max_y)); + saved_bounds.set_x(std::clamp(saved_bounds.x(), min_x, max_x)); + } +#endif // BUILDFLAG(IS_MAC) + + SetBounds(saved_bounds); +} + // static bool NativeWindow::PlatformHasClientFrame() { #if defined(USE_OZONE) diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index 2c25fa547ab78..3e009a8b4c2ff 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -18,6 +18,7 @@ #include "base/observer_list.h" #include "base/strings/cstring_view.h" #include "base/supports_user_data.h" +#include "base/timer/timer.h" #include "content/public/browser/desktop_media_id.h" #include "content/public/browser/web_contents_user_data.h" #include "extensions/browser/app_window/size_constraints.h" @@ -27,6 +28,7 @@ class SkRegion; class DraggableRegionProvider; +class PrefService; namespace input { struct NativeWebKeyboardEvent; @@ -50,10 +52,6 @@ namespace electron { class ElectronMenuModel; class BackgroundThrottlingSource; -namespace api { -class BrowserView; -} - #if BUILDFLAG(IS_MAC) using NativeWindowHandle = gfx::NativeView; #else @@ -169,9 +167,11 @@ class NativeWindow : public base::SupportsUserData, void SetTitle(std::string_view title); [[nodiscard]] std::string GetTitle() const; + [[nodiscard]] std::string GetName() const; + // Ability to augment the window title for the screen readers. void SetAccessibleTitle(const std::string& title); - std::string GetAccessibleTitle(); + [[nodiscard]] std::string GetAccessibleTitle() const; virtual void FlashFrame(bool flash) = 0; virtual void SetSkipTaskbar(bool skip) = 0; @@ -344,6 +344,7 @@ class NativeWindow : public base::SupportsUserData, void NotifyNewWindowForTab(); void NotifyWindowSystemContextMenu(int x, int y, bool* prevent_default); void NotifyLayoutWindowControlsOverlay(); + void NotifyWindowStateRestored(); #if BUILDFLAG(IS_WIN) void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param); @@ -433,9 +434,29 @@ class NativeWindow : public base::SupportsUserData, // throttling, then throttling in the `ui::Compositor` will be disabled. void UpdateBackgroundThrottlingState(); - protected: - friend class api::BrowserView; + // Saves current window state to the Local State JSON file in + // app.getPath('userData') via PrefService. + // This does NOT immediately write to disk - it updates the in-memory + // preference store and queues an asynchronous write operation. The actual + // disk write is batched and flushed later. + void SaveWindowState(); + void DebouncedSaveWindowState(); + // Flushes save_window_state_timer_ that was queued by + // DebouncedSaveWindowState. This does NOT flush the actual disk write. + void FlushWindowState(); + + // Restores window state - bounds first and then display mode. + void RestoreWindowState(const gin_helper::Dictionary& options); + // Applies saved bounds to the window. + void RestoreBounds(const display::Display& display, + const gfx::Rect& saved_work_area, + gfx::Rect& saved_bounds); + // Flushes pending display mode restoration (fullscreen, maximized, kiosk) + // that was deferred during initialization to respect show=false. This + // consumes and clears the restore_display_mode_callback_. + void FlushPendingDisplayMode(); + protected: NativeWindow(const gin_helper::Dictionary& options, NativeWindow* parent); void set_titlebar_overlay_height(int height) { @@ -494,6 +515,10 @@ class NativeWindow : public base::SupportsUserData, static inline int32_t next_id_ = 0; const int32_t window_id_ = ++next_id_; + // Identifier for the window provided by the application. + // Used by Electron internally for features such as state persistence. + std::string window_name_; + // The "titleBarStyle" option. const TitleBarStyle title_bar_style_; @@ -552,6 +577,32 @@ class NativeWindow : public base::SupportsUserData, gfx::Rect overlay_rect_; + // Flag to prevent SaveWindowState calls during window restoration. + bool is_being_restored_ = false; + + // The boolean parsing of the "windowStatePersistence" option + bool window_state_persistence_enabled_ = false; + + // PrefService is used to persist window bounds and state. + // Only populated when windowStatePersistence is enabled and window has a + // valid name. + raw_ptr<PrefService> prefs_ = nullptr; + + // Whether to restore bounds. + bool restore_bounds_ = false; + // Whether to restore display mode. + bool restore_display_mode_ = false; + // Callback to restore display mode. + base::OnceCallback<void()> restore_display_mode_callback_; + + // Timer to debounce window state saving operations. + base::OneShotTimer save_window_state_timer_; + + // Minimum height of the visible part of a window. + const int kMinVisibleHeight = 100; + // Minimum width of the visible part of a window. + const int kMinVisibleWidth = 100; + base::WeakPtrFactory<NativeWindow> weak_factory_{this}; }; diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index 2a0192aa9e6b5..66b647ff10e2c 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -225,7 +225,7 @@ class NativeWindowMac : public NativeWindow, // views::WidgetDelegate: views::View* GetContentsView() override; bool CanMaximize() const override; - std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView( + std::unique_ptr<views::FrameView> CreateFrameView( views::Widget* widget) override; void OnWidgetInitialized() override; diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index fbb9ee8946c3f..ea1855730bcd0 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -118,7 +118,7 @@ static bool FromV8(v8::Isolate* isolate, NativeWindow* parent) : NativeWindow(options, parent), root_view_(new RootViewMac(this)) { ui::NativeTheme::GetInstanceForNativeUi()->AddObserver(this); - display::Screen::GetScreen()->AddObserver(this); + display::Screen::Get()->AddObserver(this); int width = options.ValueOrDefault(options::kWidth, 800); int height = options.ValueOrDefault(options::kHeight, 600); @@ -416,6 +416,8 @@ static bool FromV8(v8::Isolate* isolate, return; } + FlushPendingDisplayMode(); + set_wants_to_be_visible(true); // Reattach the window to the parent to actually show it. @@ -1333,7 +1335,6 @@ static bool FromV8(v8::Isolate* isolate, maskImage.capInsets = NSEdgeInsetsMake(radius, radius, radius, radius); maskImage.resizingMode = NSImageResizingModeStretch; [vibrantView setMaskImage:maskImage]; - [window_ setCornerMask:maskImage]; } } } @@ -1680,7 +1681,7 @@ static bool FromV8(v8::Isolate* isolate, void NativeWindowMac::Cleanup() { DCHECK(!IsClosed()); ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this); - display::Screen::GetScreen()->RemoveObserver(this); + display::Screen::Get()->RemoveObserver(this); [window_ cleanup]; } @@ -1719,8 +1720,8 @@ static bool FromV8(v8::Isolate* isolate, const raw_ptr<NativeWindowMac, DanglingUntriaged> native_app_window_; }; -std::unique_ptr<views::NonClientFrameView> -NativeWindowMac::CreateNonClientFrameView(views::Widget* widget) { +std::unique_ptr<views::FrameView> NativeWindowMac::CreateFrameView( + views::Widget* widget) { CHECK(!frame_view_client_); frame_view_client_ = std::make_unique<NativeAppWindowFrameViewMacClient>(widget, this); diff --git a/shell/browser/native_window_observer.h b/shell/browser/native_window_observer.h index 1adf24d474043..84925dd04f32f 100644 --- a/shell/browser/native_window_observer.h +++ b/shell/browser/native_window_observer.h @@ -110,6 +110,8 @@ class NativeWindowObserver : public base::CheckedObserver { virtual void OnExecuteAppCommand(std::string_view command_name) {} virtual void UpdateWindowControlsOverlay(const gfx::Rect& bounding_rect) {} + + virtual void OnWindowStateRestored() {} }; } // namespace electron diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index ceee28bfc7689..b37e792935f76 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -35,7 +35,6 @@ #include "shell/browser/window_list.h" #include "shell/common/electron_constants.h" #include "shell/common/gin_converters/image_converter.h" -#include "shell/common/gin_helper/arguments.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/options_switches.h" #include "ui/aura/window_tree_host.h" @@ -43,7 +42,7 @@ #include "ui/compositor/compositor.h" #include "ui/display/screen.h" #include "ui/gfx/image/image.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/views/background.h" #include "ui/views/controls/webview/webview.h" @@ -85,7 +84,6 @@ #include "shell/common/color_util.h" #include "skia/ext/skia_utils_win.h" #include "ui/display/win/screen_win.h" -#include "ui/gfx/color_utils.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/msg_util.h" #endif @@ -216,8 +214,8 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, if (transparent()) thick_frame_ = false; - overlay_button_color_ = color_utils::GetSysSkColor(COLOR_BTNFACE); - overlay_symbol_color_ = color_utils::GetSysSkColor(COLOR_BTNTEXT); + overlay_button_color_ = GetSysSkColor(COLOR_BTNFACE); + overlay_symbol_color_ = GetSysSkColor(COLOR_BTNTEXT); if (std::string str; options.Get(options::kAccentColor, &str)) { std::optional<SkColor> parsed_color = ParseCSSColor(str); @@ -268,7 +266,7 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, params.remove_standard_frame = !has_frame() || has_client_frame(); // If a client frame, we need to draw our own shadows. - if (IsTranslucent() || has_client_frame()) + if (transparent() || has_client_frame()) params.opacity = InitParams::WindowOpacity::kTranslucent; // The given window is most likely not rectangular since it is translucent and @@ -302,7 +300,7 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, widget()->Init(std::move(params)); widget()->SetNativeWindowProperty(kNativeWindowKey.c_str(), this); - SetCanResize(resizable_); + widget()->OnSizeConstraintsChanged(); const bool fullscreen = options.ValueOrDefault(options::kFullscreen, false); @@ -356,11 +354,11 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, // frameless. DWORD frame_style = WS_CAPTION | WS_OVERLAPPED; - if (resizable_) + if (CanResize()) frame_style |= WS_THICKFRAME; if (minimizable_) frame_style |= WS_MINIMIZEBOX; - if (maximizable_) + if (maximizable_ && CanResize()) frame_style |= WS_MAXIMIZEBOX; // We should not show a frame for transparent window. @@ -452,10 +450,10 @@ NativeWindowViews::~NativeWindowViews() { void NativeWindowViews::SetTitleBarOverlay( const gin_helper::Dictionary& options, - gin_helper::Arguments* args) { + gin::Arguments* args) { // Ensure WCO is already enabled on this window if (!IsWindowControlsOverlayEnabled()) { - args->ThrowError("Titlebar overlay is not enabled"); + args->ThrowTypeError("Titlebar overlay is not enabled"); return; } @@ -466,7 +464,7 @@ void NativeWindowViews::SetTitleBarOverlay( // Parse the string as a CSS color SkColor color; if (!content::ParseCssColorString(val, &color)) { - args->ThrowError("Could not parse color as CSS color"); + args->ThrowTypeError("Could not parse color as CSS color"); return; } @@ -480,7 +478,7 @@ void NativeWindowViews::SetTitleBarOverlay( // Parse the string as a CSS color SkColor color; if (!content::ParseCssColorString(val, &color)) { - args->ThrowError("Could not parse symbol color as CSS color"); + args->ThrowTypeError("Could not parse symbol color as CSS color"); return; } @@ -555,9 +553,11 @@ bool NativeWindowViews::IsFocused() const { } void NativeWindowViews::Show() { - if (is_modal() && NativeWindow::parent() && !widget()->IsVisible()) + if (is_modal() && NativeWindow::parent()) static_cast<NativeWindowViews*>(parent())->IncrementChildModals(); + FlushPendingDisplayMode(); + widget()->native_widget_private()->Show(GetRestoredState(), gfx::Rect()); // explicitly focus the window @@ -688,8 +688,8 @@ void NativeWindowViews::Maximize() { #if BUILDFLAG(IS_WIN) if (transparent()) { restore_bounds_ = GetBounds(); - auto display = display::Screen::GetScreen()->GetDisplayNearestWindow( - GetNativeWindow()); + auto display = + display::Screen::Get()->GetDisplayNearestWindow(GetNativeWindow()); SetBounds(display.work_area(), false); NotifyWindowMaximize(); return; @@ -733,8 +733,8 @@ bool NativeWindowViews::IsMaximized() const { if (transparent() && !IsMinimized()) { // If the window is the same dimensions and placement as the // display, we consider it maximized. - auto display = display::Screen::GetScreen()->GetDisplayNearestWindow( - GetNativeWindow()); + auto display = + display::Screen::Get()->GetDisplayNearestWindow(GetNativeWindow()); return GetBounds() == display.work_area(); } #endif @@ -799,7 +799,7 @@ void NativeWindowViews::SetFullScreen(bool fullscreen) { if (fullscreen) { restore_bounds_ = GetBounds(); auto display = - display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition()); + display::Screen::Get()->GetDisplayNearestPoint(GetPosition()); SetBounds(display.bounds(), false); } else { SetBounds(restore_bounds_, false); @@ -868,7 +868,7 @@ void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) // On Linux and Windows the minimum and maximum size should be updated with // window size when window is not resizable. - if (!resizable_) { + if (!CanResize()) { SetMaximumSize(bounds.size()); SetMinimumSize(bounds.size()); } @@ -949,26 +949,21 @@ extensions::SizeConstraints NativeWindowViews::GetContentSizeConstraints() void NativeWindowViews::SetResizable(bool resizable) { if (resizable != resizable_) { + resizable_ = resizable; // On Linux there is no "resizable" property of a window, we have to set // both the minimum and maximum size to the window size to achieve it. if (resizable) { SetContentSizeConstraints(old_size_constraints_); - SetMaximizable(maximizable_); } else { old_size_constraints_ = GetContentSizeConstraints(); - resizable_ = false; gfx::Size content_size = GetContentSize(); SetContentSizeConstraints( extensions::SizeConstraints(content_size, content_size)); } - } - - resizable_ = resizable; - SetCanResize(resizable_); - #if BUILDFLAG(IS_WIN) - UpdateThickFrame(); + UpdateThickFrame(); #endif + } } bool NativeWindowViews::MoveAbove(const std::string& sourceId) { @@ -1013,12 +1008,20 @@ void NativeWindowViews::MoveTop() { #endif } +bool NativeWindowViews::CanResize() const { +#if BUILDFLAG(IS_WIN) + return resizable_ && thick_frame_; +#else + return resizable_; +#endif +} + bool NativeWindowViews::IsResizable() const { #if BUILDFLAG(IS_WIN) if (has_frame()) return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME; #endif - return resizable_; + return CanResize(); } void NativeWindowViews::SetAspectRatio(double aspect_ratio, @@ -1164,7 +1167,7 @@ ui::ZOrderLevel NativeWindowViews::GetZOrderLevel() const { void NativeWindowViews::Center() { #if BUILDFLAG(IS_LINUX) auto display = - display::Screen::GetScreen()->GetDisplayNearestWindow(GetNativeWindow()); + display::Screen::Get()->GetDisplayNearestWindow(GetNativeWindow()); gfx::Rect window_bounds_in_screen = display.work_area(); window_bounds_in_screen.ClampToCenteredSize(GetSize()); widget()->SetBounds(window_bounds_in_screen); @@ -1362,7 +1365,8 @@ void NativeWindowViews::SetFocusable(bool focusable) { ex_style |= WS_EX_NOACTIVATE; ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style); SetSkipTaskbar(!focusable); - Focus(false); + if (!focusable) + Focus(false); #endif } @@ -1819,7 +1823,7 @@ views::View* NativeWindowViews::GetInitiallyFocusedView() { } bool NativeWindowViews::CanMaximize() const { - return resizable_ && maximizable_; + return CanResize() && maximizable_; } bool NativeWindowViews::CanMinimize() const { @@ -1844,8 +1848,8 @@ views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) { return new NativeWindowClientView{widget, &root_view_, this}; } -std::unique_ptr<views::NonClientFrameView> -NativeWindowViews::CreateNonClientFrameView(views::Widget* widget) { +std::unique_ptr<views::FrameView> NativeWindowViews::CreateFrameView( + views::Widget* widget) { #if BUILDFLAG(IS_WIN) auto frame_view = std::make_unique<WinFrameView>(); frame_view->Init(this, widget); @@ -1872,7 +1876,7 @@ electron::ClientFrameViewLinux* NativeWindowViews::GetClientFrameViewLinux() { // Check to make sure this window's non-client frame view is a // ClientFrameViewLinux. If either has_frame() or has_client_frame() // are false, it will be an OpaqueFrameView or NativeFrameView instead. - // See NativeWindowViews::CreateNonClientFrameView. + // See NativeWindowViews::CreateFrameView. if (!has_frame() || !has_client_frame()) return {}; return static_cast<ClientFrameViewLinux*>( diff --git a/shell/browser/native_window_views.h b/shell/browser/native_window_views.h index a4f3bb40a3747..874a9fda86610 100644 --- a/shell/browser/native_window_views.h +++ b/shell/browser/native_window_views.h @@ -12,6 +12,7 @@ #include <string> #include "base/memory/raw_ptr.h" +#include "base/no_destructor.h" #include "shell/browser/ui/views/root_view.h" #include "third_party/abseil-cpp/absl/container/flat_hash_set.h" #include "ui/base/ozone_buildflags.h" @@ -24,9 +25,9 @@ #include "shell/browser/ui/win/taskbar_host.h" #endif -namespace gin_helper { +namespace gin { class Arguments; -} // namespace gin_helper +} // namespace gin namespace electron { @@ -88,6 +89,7 @@ class NativeWindowViews : public NativeWindow, bool IsResizable() const override; void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size) override; + bool CanResize() const override; void SetMovable(bool movable) override; bool IsMovable() const override; void SetMinimizable(bool minimizable) override; @@ -157,7 +159,7 @@ class NativeWindowViews : public NativeWindow, void DecrementChildModals(); void SetTitleBarOverlay(const gin_helper::Dictionary& options, - gin_helper::Arguments* args); + gin::Arguments* args); #if BUILDFLAG(IS_WIN) // Catch-all message handling and filtering. Called before @@ -189,7 +191,7 @@ class NativeWindowViews : public NativeWindow, SkColor overlay_symbol_color() const { return overlay_symbol_color_; } #if BUILDFLAG(IS_LINUX) - // returns the ClientFrameViewLinux iff that is our NonClientFrameView type, + // returns the ClientFrameViewLinux iff that is our FrameView type, // nullptr otherwise. ClientFrameViewLinux* GetClientFrameViewLinux(); #endif @@ -218,7 +220,7 @@ class NativeWindowViews : public NativeWindow, gfx::NativeView child, const gfx::Point& location) override; views::ClientView* CreateClientView(views::Widget* widget) override; - std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView( + std::unique_ptr<views::FrameView> CreateFrameView( views::Widget* widget) override; void OnWidgetMove() override; #if BUILDFLAG(IS_WIN) @@ -302,7 +304,8 @@ class NativeWindowViews : public NativeWindow, base::win::ScopedGDIObject<HICON> app_icon_; // The set of windows currently forwarding mouse messages. - static inline absl::flat_hash_set<NativeWindowViews*> forwarding_windows_; + static inline base::NoDestructor<absl::flat_hash_set<NativeWindowViews*>> + forwarding_windows_; static HHOOK mouse_hook_; bool forwarding_mouse_messages_ = false; HWND legacy_window_ = nullptr; diff --git a/shell/browser/native_window_views_win.cc b/shell/browser/native_window_views_win.cc index f4c8c119494e4..400d140fd58f2 100644 --- a/shell/browser/native_window_views_win.cc +++ b/shell/browser/native_window_views_win.cc @@ -31,15 +31,15 @@ namespace electron { namespace { -void SetWindowBorderAndCaptionColor(HWND hwnd, COLORREF color) { - if (base::win::GetVersion() < base::win::Version::WIN11) - return; - - HRESULT result = - DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &color, sizeof(color)); - - if (FAILED(result)) - LOG(WARNING) << "Failed to set caption color"; +void SetWindowBorderAndCaptionColor(HWND hwnd, COLORREF color, bool has_frame) { + HRESULT result; + if (has_frame) { + result = + DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &color, sizeof(color)); + + if (FAILED(result)) + LOG(WARNING) << "Failed to set caption color"; + } result = DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color)); @@ -324,11 +324,6 @@ bool NativeWindowViews::PreHandleMSG(UINT message, return false; } - case WM_RBUTTONUP: { - if (!has_frame()) - electron::api::WebContents::SetDisableDraggableRegions(false); - return false; - } case WM_GETMINMAXINFO: { WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); @@ -514,7 +509,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); - if (GetWindowPlacement(GetAcceleratedWidget(), &wp)) { + if (GetWindowPlacement(GetAcceleratedWidget(), &wp) && !was_snapped_) { last_normal_placement_bounds_ = gfx::Rect(wp.rcNormalPosition); } @@ -523,11 +518,9 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { if (w_param == SIZE_MAXIMIZED && last_window_state_ != ui::mojom::WindowShowState::kMaximized) { if (last_window_state_ == ui::mojom::WindowShowState::kMinimized) { - if (was_snapped_) { - SetRoundedCorners(false); - was_snapped_ = false; - } NotifyWindowRestore(); + if (was_snapped_) + was_snapped_ = false; } last_window_state_ = ui::mojom::WindowShowState::kMaximized; NotifyWindowMaximize(); @@ -550,12 +543,10 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { last_window_state_ = ui::mojom::WindowShowState::kFullscreen; NotifyWindowEnterFullScreen(); } else { - if (was_snapped_) { - SetRoundedCorners(false); - was_snapped_ = false; - } last_window_state_ = ui::mojom::WindowShowState::kNormal; NotifyWindowRestore(); + if (was_snapped_) + was_snapped_ = false; } break; default: @@ -600,7 +591,8 @@ void NativeWindowViews::UpdateWindowAccentColor(bool active) { } COLORREF final_color = border_color.value_or(DWMWA_COLOR_DEFAULT); - SetWindowBorderAndCaptionColor(GetAcceleratedWidget(), final_color); + SetWindowBorderAndCaptionColor(GetAcceleratedWidget(), final_color, + has_frame()); } void NativeWindowViews::SetAccentColor( @@ -668,7 +660,7 @@ void NativeWindowViews::SetRoundedCorners(bool rounded) { void NativeWindowViews::SetForwardMouseMessages(bool forward) { if (forward && !forwarding_mouse_messages_) { forwarding_mouse_messages_ = true; - forwarding_windows_.insert(this); + forwarding_windows_->insert(this); // Subclassing is used to fix some issues when forwarding mouse messages; // see comments in |SubclassProc|. @@ -680,11 +672,11 @@ void NativeWindowViews::SetForwardMouseMessages(bool forward) { } } else if (!forward && forwarding_mouse_messages_) { forwarding_mouse_messages_ = false; - forwarding_windows_.erase(this); + forwarding_windows_->erase(this); RemoveWindowSubclass(legacy_window_, SubclassProc, 1); - if (forwarding_windows_.empty()) { + if (forwarding_windows_->empty()) { UnhookWindowsHookEx(mouse_hook_); mouse_hook_ = nullptr; } @@ -731,7 +723,7 @@ LRESULT CALLBACK NativeWindowViews::MouseHookProc(int n_code, // the cursor since they are in a state where they would otherwise ignore all // mouse input. if (w_param == WM_MOUSEMOVE) { - for (auto* window : forwarding_windows_) { + for (auto* window : *forwarding_windows_) { // At first I considered enumerating windows to check whether the cursor // was directly above the window, but since nothing bad seems to happen // if we post the message even if some other window occludes it I have diff --git a/shell/browser/net/proxying_url_loader_factory.cc b/shell/browser/net/proxying_url_loader_factory.cc index 1bbb15b669cfc..255687b8699e4 100644 --- a/shell/browser/net/proxying_url_loader_factory.cc +++ b/shell/browser/net/proxying_url_loader_factory.cc @@ -88,7 +88,7 @@ ProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() { // This is important to ensure that no outstanding blocking requests continue // to reference state owned by this object. if (info_) { - factory_->web_request_api()->OnRequestWillBeDestroyed(&info_.value()); + factory_->web_request_->OnRequestWillBeDestroyed(&info_.value()); } if (on_before_send_headers_callback_) { std::move(on_before_send_headers_callback_) @@ -147,7 +147,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() { weak_factory_.GetWeakPtr()); } redirect_url_ = GURL(); - int result = factory_->web_request_api()->OnBeforeRequest( + int result = factory_->web_request_->OnBeforeRequest( &info_.value(), request_, continuation, &redirect_url_); if (result == net::ERR_BLOCKED_BY_CLIENT) { // The request was cancelled synchronously. Dispatch an error notification @@ -293,8 +293,8 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnComplete( } target_client_->OnComplete(status); - factory_->web_request_api()->OnCompleted(&info_.value(), request_, - status.error_code); + factory_->web_request_->OnCompleted(&info_.value(), request_, + status.error_code); // Deletes |this|. factory_->RemoveRequest(network_service_request_id_, request_id_); @@ -343,6 +343,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnBeforeSendHeaders( void ProxyingURLLoaderFactory::InProgressRequest::OnHeadersReceived( const std::string& headers, const net::IPEndPoint& remote_endpoint, + const std::optional<net::SSLInfo>& ssl_info, OnHeadersReceivedCallback callback) { if (!current_request_uses_header_client_) { std::move(callback).Run(net::OK, std::nullopt, GURL()); @@ -441,7 +442,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeSendHeaders( auto continuation = base::BindRepeating( &InProgressRequest::ContinueToSendHeaders, weak_factory_.GetWeakPtr()); // Note: In Electron onBeforeSendHeaders is called for all protocols. - int result = factory_->web_request_api()->OnBeforeSendHeaders( + int result = factory_->web_request_->OnBeforeSendHeaders( &info_.value(), request_, continuation, &request_.headers); if (result == net::ERR_BLOCKED_BY_CLIENT) { @@ -555,8 +556,8 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToSendHeaders( proxied_client_receiver_.Resume(); // Note: In Electron onSendHeaders is called for all protocols. - factory_->web_request_api()->OnSendHeaders(&info_.value(), request_, - request_.headers); + factory_->web_request_->OnSendHeaders(&info_.value(), request_, + request_.headers); if (!current_request_uses_header_client_) ContinueToStartRequest(net::OK); @@ -598,8 +599,8 @@ void ProxyingURLLoaderFactory::InProgressRequest:: if (info_->response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) return; // We notify the completion here, and delete |this|. - factory_->web_request_api()->OnResponseStarted(&info_.value(), request_); - factory_->web_request_api()->OnCompleted(&info_.value(), request_, net::OK); + factory_->web_request_->OnResponseStarted(&info_.value(), request_); + factory_->web_request_->OnCompleted(&info_.value(), request_, net::OK); factory_->RemoveRequest(network_service_request_id_, request_id_); return; @@ -653,7 +654,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToResponseStarted( proxied_client_receiver_.Resume(); - factory_->web_request_api()->OnResponseStarted(&info_.value(), request_); + factory_->web_request_->OnResponseStarted(&info_.value(), request_); target_client_->OnReceiveResponse(current_response_.Clone(), std::move(current_body_), std::move(current_cached_metadata_)); @@ -672,8 +673,8 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeRedirect( if (proxied_client_receiver_.is_bound()) proxied_client_receiver_.Resume(); - factory_->web_request_api()->OnBeforeRedirect(&info_.value(), request_, - redirect_info.new_url); + factory_->web_request_->OnBeforeRedirect(&info_.value(), request_, + redirect_info.new_url); target_client_->OnReceiveRedirect(redirect_info, current_response_.Clone()); request_.url = redirect_info.new_url; request_.method = redirect_info.new_method; @@ -696,7 +697,7 @@ void ProxyingURLLoaderFactory::InProgressRequest:: auto callback_pair = base::SplitOnceCallback(std::move(continuation)); DCHECK(info_.has_value()); - int result = factory_->web_request_api()->OnHeadersReceived( + int result = factory_->web_request_->OnHeadersReceived( &info_.value(), request_, std::move(callback_pair.first), current_response_->headers.get(), &override_headers_, &redirect_url_); if (result == net::ERR_BLOCKED_BY_CLIENT) { @@ -724,15 +725,15 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnRequestError( const network::URLLoaderCompletionStatus& status) { if (target_client_) target_client_->OnComplete(status); - factory_->web_request_api()->OnErrorOccurred(&info_.value(), request_, - status.error_code); + factory_->web_request_->OnErrorOccurred(&info_.value(), request_, + status.error_code); // Deletes |this|. factory_->RemoveRequest(network_service_request_id_, request_id_); } ProxyingURLLoaderFactory::ProxyingURLLoaderFactory( - WebRequestAPI* web_request_api, + api::WebRequest* web_request, const HandlersMap& intercepted_handlers, int render_process_id, int frame_routing_id, @@ -744,7 +745,7 @@ ProxyingURLLoaderFactory::ProxyingURLLoaderFactory( mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver, content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type) - : web_request_api_(web_request_api), + : web_request_{web_request}, intercepted_handlers_(intercepted_handlers), render_process_id_(render_process_id), frame_routing_id_(frame_routing_id), @@ -797,7 +798,7 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart( bool bypass_custom_protocol_handlers = options & kBypassCustomProtocolHandlers; if (!bypass_custom_protocol_handlers) { - auto it = intercepted_handlers_->find(request.url.scheme_piece()); + auto it = intercepted_handlers_->find(request.url.scheme()); if (it != intercepted_handlers_->end()) { mojo::PendingRemote<network::mojom::URLLoaderFactory> loader_remote; this->Clone(loader_remote.InitWithNewPipeAndPassReceiver()); @@ -824,7 +825,7 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart( return; } - if (!web_request_api()->HasListener()) { + if (!web_request_->HasListener()) { // Pass-through to the original factory. target_factory_->CreateLoaderAndStart(std::move(loader), request_id, options, request, std::move(client), diff --git a/shell/browser/net/proxying_url_loader_factory.h b/shell/browser/net/proxying_url_loader_factory.h index d40fb14083d0f..9f488ae49afc9 100644 --- a/shell/browser/net/proxying_url_loader_factory.h +++ b/shell/browser/net/proxying_url_loader_factory.h @@ -18,10 +18,12 @@ #include "base/memory/weak_ptr.h" #include "content/public/browser/content_browser_client.h" #include "extensions/browser/api/web_request/web_request_info.h" +#include "ipc/constants.mojom.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/base/completion_once_callback.h" +#include "net/ssl/ssl_info.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/network_context.mojom.h" @@ -29,9 +31,10 @@ #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/network/public/mojom/url_response_head.mojom-forward.h" #include "services/network/url_loader_factory.h" +#include "shell/browser/api/electron_api_web_request.h" #include "shell/browser/net/electron_url_loader_factory.h" -#include "shell/browser/net/web_request_api_interface.h" #include "url/gurl.h" +#include "v8/include/cppgc/persistent.h" namespace mojo { template <typename T> @@ -114,6 +117,7 @@ class ProxyingURLLoaderFactory OnBeforeSendHeadersCallback callback) override; void OnHeadersReceived(const std::string& headers, const net::IPEndPoint& endpoint, + const std::optional<net::SSLInfo>& ssl_info, OnHeadersReceivedCallback callback) override; private: @@ -140,7 +144,7 @@ class ProxyingURLLoaderFactory const std::optional<url::Origin> original_initiator_; const uint64_t request_id_ = 0; const int32_t network_service_request_id_ = 0; - const int32_t frame_routing_id_ = MSG_ROUTING_NONE; + const int32_t frame_routing_id_ = IPC::mojom::kRoutingIdNone; const uint32_t options_ = 0; const net::MutableNetworkTrafficAnnotationTag traffic_annotation_; mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_; @@ -196,7 +200,7 @@ class ProxyingURLLoaderFactory }; ProxyingURLLoaderFactory( - WebRequestAPI* web_request_api, + api::WebRequest* web_request, const HandlersMap& intercepted_handlers, int render_process_id, int frame_routing_id, @@ -238,8 +242,6 @@ class ProxyingURLLoaderFactory mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) override; - WebRequestAPI* web_request_api() { return web_request_api_; } - bool IsForServiceWorkerScript() const; private: @@ -250,8 +252,7 @@ class ProxyingURLLoaderFactory bool ShouldIgnoreConnectionsLimit(const network::ResourceRequest& request); - // Passed from api::WebRequest. - raw_ptr<WebRequestAPI> web_request_api_; + const cppgc::WeakPersistent<api::WebRequest> web_request_; // This is passed from api::Protocol. // diff --git a/shell/browser/net/proxying_websocket.cc b/shell/browser/net/proxying_websocket.cc index 02ae781d0bb74..5a1836c427b17 100644 --- a/shell/browser/net/proxying_websocket.cc +++ b/shell/browser/net/proxying_websocket.cc @@ -17,7 +17,7 @@ namespace electron { ProxyingWebSocket::ProxyingWebSocket( - WebRequestAPI* web_request_api, + api::WebRequest* web_request, WebSocketFactory factory, const network::ResourceRequest& request, mojo::PendingRemote<network::mojom::WebSocketHandshakeClient> @@ -27,7 +27,7 @@ ProxyingWebSocket::ProxyingWebSocket( int render_frame_id, content::BrowserContext* browser_context, uint64_t* request_id_generator) - : web_request_api_(web_request_api), + : web_request_{web_request}, request_(request), factory_(std::move(factory)), forwarding_handshake_client_(std::move(handshake_client)), @@ -70,8 +70,8 @@ void ProxyingWebSocket::Start() { weak_factory_.GetWeakPtr()); } - int result = web_request_api_->OnBeforeRequest(&info_, request_, continuation, - &redirect_url_); + int result = web_request_->OnBeforeRequest(&info_, request_, continuation, + &redirect_url_); if (result == net::ERR_BLOCKED_BY_CLIENT) { OnError(result); @@ -97,7 +97,7 @@ void ProxyingWebSocket::ContinueToHeadersReceived() { base::BindRepeating(&ProxyingWebSocket::OnHeadersReceivedComplete, weak_factory_.GetWeakPtr()); info_.AddResponseInfoFromResourceResponse(*response_); - int result = web_request_api_->OnHeadersReceived( + int result = web_request_->OnHeadersReceived( &info_, request_, continuation, response_->headers.get(), &override_headers_, &redirect_url_); @@ -152,7 +152,7 @@ void ProxyingWebSocket::OnConnectionEstablished( void ProxyingWebSocket::ContinueToCompleted() { DCHECK(forwarding_handshake_client_); DCHECK(is_done_); - web_request_api_->OnCompleted(&info_, request_, net::ERR_WS_UPGRADE); + web_request_->OnCompleted(&info_, request_, net::ERR_WS_UPGRADE); forwarding_handshake_client_->OnConnectionEstablished( std::move(websocket_), std::move(client_receiver_), std::move(handshake_response_), std::move(readable_), @@ -180,7 +180,7 @@ void ProxyingWebSocket::OnAuthRequired( base::BindRepeating(&ProxyingWebSocket::OnHeadersReceivedCompleteForAuth, weak_factory_.GetWeakPtr(), auth_info); info_.AddResponseInfoFromResourceResponse(*response_); - int result = web_request_api_->OnHeadersReceived( + int result = web_request_->OnHeadersReceived( &info_, request_, continuation, response_->headers.get(), &override_headers_, &redirect_url_); @@ -207,9 +207,11 @@ void ProxyingWebSocket::OnBeforeSendHeaders( OnBeforeRequestComplete(net::OK); } -void ProxyingWebSocket::OnHeadersReceived(const std::string& headers, - const net::IPEndPoint& endpoint, - OnHeadersReceivedCallback callback) { +void ProxyingWebSocket::OnHeadersReceived( + const std::string& headers, + const net::IPEndPoint& endpoint, + const std::optional<net::SSLInfo>& ssl_info, + OnHeadersReceivedCallback callback) { DCHECK(receiver_as_header_client_.is_bound()); on_headers_received_callback_ = std::move(callback); @@ -219,7 +221,7 @@ void ProxyingWebSocket::OnHeadersReceived(const std::string& headers, } void ProxyingWebSocket::StartProxying( - WebRequestAPI* web_request_api, + api::WebRequest* web_request, WebSocketFactory factory, const GURL& url, const net::SiteForCookies& site_for_cookies, @@ -242,7 +244,7 @@ void ProxyingWebSocket::StartProxying( request.request_initiator = origin; auto* proxy = new ProxyingWebSocket( - web_request_api, std::move(factory), request, std::move(handshake_client), + web_request, std::move(factory), request, std::move(handshake_client), has_extra_headers, process_id, render_frame_id, browser_context, request_id_generator); proxy->Start(); @@ -262,8 +264,8 @@ void ProxyingWebSocket::OnBeforeRequestComplete(int error_code) { weak_factory_.GetWeakPtr()); info_.AddResponseInfoFromResourceResponse(*response_); - int result = web_request_api_->OnBeforeSendHeaders( - &info_, request_, continuation, &request_headers_); + int result = web_request_->OnBeforeSendHeaders(&info_, request_, continuation, + &request_headers_); if (result == net::ERR_BLOCKED_BY_CLIENT) { OnError(result); @@ -296,7 +298,7 @@ void ProxyingWebSocket::OnBeforeSendHeadersComplete( } info_.AddResponseInfoFromResourceResponse(*response_); - web_request_api_->OnSendHeaders(&info_, request_, request_headers_); + web_request_->OnSendHeaders(&info_, request_, request_headers_); if (!receiver_as_header_client_.is_bound()) ContinueToStartRequest(net::OK); @@ -366,25 +368,29 @@ void ProxyingWebSocket::OnHeadersReceivedComplete(int error_code) { ResumeIncomingMethodCallProcessing(); info_.AddResponseInfoFromResourceResponse(*response_); - web_request_api_->OnResponseStarted(&info_, request_); + web_request_->OnResponseStarted(&info_, request_); if (!receiver_as_header_client_.is_bound()) ContinueToCompleted(); } -void ProxyingWebSocket::OnAuthRequiredComplete(AuthRequiredResponse rv) { +void ProxyingWebSocket::OnAuthRequiredComplete( + api::WebRequest::AuthRequiredResponse rv) { CHECK(auth_required_callback_); ResumeIncomingMethodCallProcessing(); switch (rv) { - case AuthRequiredResponse::kNoAction: - case AuthRequiredResponse::kCancelAuth: + case api::WebRequest::AuthRequiredResponse:: + AUTH_REQUIRED_RESPONSE_NO_ACTION: + case api::WebRequest::AuthRequiredResponse:: + AUTH_REQUIRED_RESPONSE_CANCEL_AUTH: std::move(auth_required_callback_).Run(std::nullopt); break; - case AuthRequiredResponse::kSetAuth: + case api::WebRequest::AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_SET_AUTH: std::move(auth_required_callback_).Run(auth_credentials_); break; - case AuthRequiredResponse::kIoPending: + case api::WebRequest::AuthRequiredResponse:: + AUTH_REQUIRED_RESPONSE_IO_PENDING: NOTREACHED(); } } @@ -401,8 +407,13 @@ void ProxyingWebSocket::OnHeadersReceivedCompleteForAuth( auto continuation = base::BindRepeating( &ProxyingWebSocket::OnAuthRequiredComplete, weak_factory_.GetWeakPtr()); - auto auth_rv = AuthRequiredResponse::kIoPending; + auto auth_rv = web_request_->OnAuthRequired( + &info_, auth_info, std::move(continuation), &auth_credentials_); PauseIncomingMethodCallProcessing(); + if (auth_rv == api::WebRequest::AuthRequiredResponse:: + AUTH_REQUIRED_RESPONSE_IO_PENDING) { + return; + } OnAuthRequiredComplete(auth_rv); } @@ -424,7 +435,7 @@ void ProxyingWebSocket::ResumeIncomingMethodCallProcessing() { void ProxyingWebSocket::OnError(int error_code) { if (!is_done_) { is_done_ = true; - web_request_api_->OnErrorOccurred(&info_, request_, error_code); + web_request_->OnErrorOccurred(&info_, request_, error_code); } // Deletes |this|. diff --git a/shell/browser/net/proxying_websocket.h b/shell/browser/net/proxying_websocket.h index 8940757adaa98..1fb8bd8a9b4a4 100644 --- a/shell/browser/net/proxying_websocket.h +++ b/shell/browser/net/proxying_websocket.h @@ -16,12 +16,14 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "net/ssl/ssl_info.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/websocket.mojom.h" -#include "shell/browser/net/web_request_api_interface.h" +#include "shell/browser/api/electron_api_web_request.h" #include "url/gurl.h" #include "url/origin.h" +#include "v8/include/cppgc/persistent.h" namespace electron { @@ -36,23 +38,8 @@ class ProxyingWebSocket : public network::mojom::WebSocketHandshakeClient, public: using WebSocketFactory = content::ContentBrowserClient::WebSocketFactory; - // AuthRequiredResponse indicates how an OnAuthRequired call is handled. - enum class AuthRequiredResponse { - // No credentials were provided. - kNoAction, - // AuthCredentials is filled in with a username and password, which should - // be used in a response to the provided auth challenge. - kSetAuth, - // The request should be canceled. - kCancelAuth, - // The action will be decided asynchronously. |callback| will be invoked - // when the decision is made, and one of the other AuthRequiredResponse - // values will be passed in with the same semantics as described above. - kIoPending, - }; - ProxyingWebSocket( - WebRequestAPI* web_request_api, + api::WebRequest* web_request, WebSocketFactory factory, const network::ResourceRequest& request, mojo::PendingRemote<network::mojom::WebSocketHandshakeClient> @@ -94,10 +81,11 @@ class ProxyingWebSocket : public network::mojom::WebSocketHandshakeClient, OnBeforeSendHeadersCallback callback) override; void OnHeadersReceived(const std::string& headers, const net::IPEndPoint& endpoint, + const std::optional<net::SSLInfo>& ssl_info, OnHeadersReceivedCallback callback) override; static void StartProxying( - WebRequestAPI* web_request_api, + api::WebRequest* web_request, WebSocketFactory factory, const GURL& url, const net::SiteForCookies& site_for_cookies, @@ -119,7 +107,7 @@ class ProxyingWebSocket : public network::mojom::WebSocketHandshakeClient, void ContinueToStartRequest(int error_code); void OnHeadersReceivedComplete(int error_code); void ContinueToHeadersReceived(); - void OnAuthRequiredComplete(AuthRequiredResponse rv); + void OnAuthRequiredComplete(api::WebRequest::AuthRequiredResponse rv); void OnHeadersReceivedCompleteForAuth(const net::AuthChallengeInfo& auth_info, int rv); void ContinueToCompleted(); @@ -136,7 +124,7 @@ class ProxyingWebSocket : public network::mojom::WebSocketHandshakeClient, void OnMojoConnectionError(); // Passed from api::WebRequest. - raw_ptr<WebRequestAPI> web_request_api_; + const cppgc::WeakPersistent<api::WebRequest> web_request_; // Saved to feed the api::WebRequest. network::ResourceRequest request_; diff --git a/shell/browser/net/system_network_context_manager.cc b/shell/browser/net/system_network_context_manager.cc index 1b2819ebf441f..fe5d783c3b620 100644 --- a/shell/browser/net/system_network_context_manager.cc +++ b/shell/browser/net/system_network_context_manager.cc @@ -272,7 +272,8 @@ void SystemNetworkContextManager::OnNetworkServiceCreated( content::GetNetworkService()->ConfigureStubHostResolver( base::FeatureList::IsEnabled(net::features::kAsyncDns), base::FeatureList::IsEnabled(net::features::kHappyEyeballsV3), - default_secure_dns_mode, doh_config, additional_dns_query_types_enabled); + default_secure_dns_mode, doh_config, additional_dns_query_types_enabled, + {} /*fallback_doh_nameservers*/); // The OSCrypt keys are process bound, so if network service is out of // process, send it the required key. diff --git a/shell/browser/net/url_loader_network_observer.h b/shell/browser/net/url_loader_network_observer.h index 5b7cd43ee092f..5b3db75bd8923 100644 --- a/shell/browser/net/url_loader_network_observer.h +++ b/shell/browser/net/url_loader_network_observer.h @@ -58,6 +58,7 @@ class URLLoaderNetworkObserver int64_t recv_bytes, int64_t sent_bytes) override {} void OnWebSocketConnectedToPrivateNetwork( + const GURL& request_url, network::mojom::IPAddressSpace ip_address_space) override {} void OnCertificateRequested( const std::optional<base::UnguessableToken>& window_id, diff --git a/shell/browser/net/web_request_api_interface.h b/shell/browser/net/web_request_api_interface.h deleted file mode 100644 index d93a6aa94391e..0000000000000 --- a/shell/browser/net/web_request_api_interface.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2020 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ELECTRON_SHELL_BROWSER_NET_WEB_REQUEST_API_INTERFACE_H_ -#define ELECTRON_SHELL_BROWSER_NET_WEB_REQUEST_API_INTERFACE_H_ - -#include <set> -#include <string> - -#include "net/base/completion_once_callback.h" -#include "services/network/public/cpp/resource_request.h" - -namespace extensions { -struct WebRequestInfo; -} // namespace extensions - -namespace electron { - -// Defines the interface for WebRequest API, implemented by api::WebRequestNS. -class WebRequestAPI { - public: - virtual ~WebRequestAPI() = default; - - using BeforeSendHeadersCallback = - base::OnceCallback<void(const std::set<std::string>& removed_headers, - const std::set<std::string>& set_headers, - int error_code)>; - - virtual bool HasListener() const = 0; - virtual int OnBeforeRequest(extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - net::CompletionOnceCallback callback, - GURL* new_url) = 0; - virtual int OnBeforeSendHeaders(extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - BeforeSendHeadersCallback callback, - net::HttpRequestHeaders* headers) = 0; - virtual int OnHeadersReceived( - extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - net::CompletionOnceCallback callback, - const net::HttpResponseHeaders* original_response_headers, - scoped_refptr<net::HttpResponseHeaders>* override_response_headers, - GURL* allowed_unsafe_redirect_url) = 0; - virtual void OnSendHeaders(extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - const net::HttpRequestHeaders& headers) = 0; - virtual void OnBeforeRedirect(extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - const GURL& new_location) = 0; - virtual void OnResponseStarted(extensions::WebRequestInfo* info, - const network::ResourceRequest& request) = 0; - virtual void OnErrorOccurred(extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - int net_error) = 0; - virtual void OnCompleted(extensions::WebRequestInfo* info, - const network::ResourceRequest& request, - int net_error) = 0; - virtual void OnRequestWillBeDestroyed(extensions::WebRequestInfo* info) = 0; -}; - -} // namespace electron - -#endif // ELECTRON_SHELL_BROWSER_NET_WEB_REQUEST_API_INTERFACE_H_ diff --git a/shell/browser/notifications/linux/libnotify_notification.cc b/shell/browser/notifications/linux/libnotify_notification.cc index 231ba25485a16..5364f1d9ede47 100644 --- a/shell/browser/notifications/linux/libnotify_notification.cc +++ b/shell/browser/notifications/linux/libnotify_notification.cc @@ -10,6 +10,7 @@ #include "base/files/file_enumerator.h" #include "base/functional/bind.h" #include "base/logging.h" +#include "base/no_destructor.h" #include "base/process/process_handle.h" #include "base/strings/utf_string_conversions.h" #include "shell/browser/notifications/notification_delegate.h" @@ -22,17 +23,20 @@ namespace electron { namespace { -LibNotifyLoader libnotify_loader_; +LibNotifyLoader& GetLibNotifyLoader() { + static base::NoDestructor<LibNotifyLoader> loader; + return *loader; +} const base::flat_set<std::string>& GetServerCapabilities() { - static base::flat_set<std::string> caps; - if (caps.empty()) { - auto* capabilities = libnotify_loader_.notify_get_server_caps(); + static base::NoDestructor<base::flat_set<std::string>> caps; + if (caps->empty()) { + auto* capabilities = GetLibNotifyLoader().notify_get_server_caps(); for (auto* l = capabilities; l != nullptr; l = l->next) - caps.insert(static_cast<const char*>(l->data)); + caps->insert(static_cast<const char*>(l->data)); g_list_free_full(capabilities, g_free); } - return caps; + return *caps; } bool HasCapability(const std::string& capability) { @@ -57,15 +61,15 @@ void log_and_clear_error(GError* error, const char* context) { // static bool LibnotifyNotification::Initialize() { - if (!libnotify_loader_.Load("libnotify.so.4") && // most common one - !libnotify_loader_.Load("libnotify.so.5") && - !libnotify_loader_.Load("libnotify.so.1") && - !libnotify_loader_.Load("libnotify.so")) { + if (!GetLibNotifyLoader().Load("libnotify.so.4") && // most common one + !GetLibNotifyLoader().Load("libnotify.so.5") && + !GetLibNotifyLoader().Load("libnotify.so.1") && + !GetLibNotifyLoader().Load("libnotify.so")) { LOG(WARNING) << "Unable to find libnotify; notifications disabled"; return false; } - if (!libnotify_loader_.notify_is_initted() && - !libnotify_loader_.notify_init(GetApplicationName().c_str())) { + if (!GetLibNotifyLoader().notify_is_initted() && + !GetLibNotifyLoader().notify_init(GetApplicationName().c_str())) { LOG(WARNING) << "Unable to initialize libnotify; notifications disabled"; return false; } @@ -84,7 +88,7 @@ LibnotifyNotification::~LibnotifyNotification() { } void LibnotifyNotification::Show(const NotificationOptions& options) { - notification_ = libnotify_loader_.notify_notification_new( + notification_ = GetLibNotifyLoader().notify_notification_new( base::UTF16ToUTF8(options.title).c_str(), base::UTF16ToUTF8(options.msg).c_str(), nullptr); @@ -96,7 +100,7 @@ void LibnotifyNotification::Show(const NotificationOptions& options) { // NB: On Unity and on any other DE using Notify-OSD, adding a notification // action will cause the notification to display as a modal dialog box. if (NotifierSupportsActions()) { - libnotify_loader_.notify_notification_add_action( + GetLibNotifyLoader().notify_notification_add_action( notification_, "default", "View", OnNotificationView, this, nullptr); } @@ -108,19 +112,19 @@ void LibnotifyNotification::Show(const NotificationOptions& options) { } // Set the urgency level of the notification. - libnotify_loader_.notify_notification_set_urgency(notification_, urgency); + GetLibNotifyLoader().notify_notification_set_urgency(notification_, urgency); if (!options.icon.drawsNothing()) { GdkPixbuf* pixbuf = gtk_util::GdkPixbufFromSkBitmap(options.icon); - libnotify_loader_.notify_notification_set_image_from_pixbuf(notification_, - pixbuf); + GetLibNotifyLoader().notify_notification_set_image_from_pixbuf( + notification_, pixbuf); g_object_unref(pixbuf); } // Set the timeout duration for the notification bool neverTimeout = options.timeout_type == u"never"; int timeout = (neverTimeout) ? NOTIFY_EXPIRES_NEVER : NOTIFY_EXPIRES_DEFAULT; - libnotify_loader_.notify_notification_set_timeout(notification_, timeout); + GetLibNotifyLoader().notify_notification_set_timeout(notification_, timeout); if (!options.tag.empty()) { GQuark id = g_quark_from_string(options.tag.c_str()); @@ -130,10 +134,10 @@ void LibnotifyNotification::Show(const NotificationOptions& options) { // Always try to append notifications. // Unique tags can be used to prevent this. if (HasCapability("append")) { - libnotify_loader_.notify_notification_set_hint( + GetLibNotifyLoader().notify_notification_set_hint( notification_, "append", g_variant_new_string("true")); } else if (HasCapability("x-canonical-append")) { - libnotify_loader_.notify_notification_set_hint( + GetLibNotifyLoader().notify_notification_set_hint( notification_, "x-canonical-append", g_variant_new_string("true")); } @@ -141,17 +145,17 @@ void LibnotifyNotification::Show(const NotificationOptions& options) { // The desktop-entry is the part before the .desktop std::string desktop_id = platform_util::GetXdgAppId(); if (!desktop_id.empty()) { - libnotify_loader_.notify_notification_set_hint( + GetLibNotifyLoader().notify_notification_set_hint( notification_, "desktop-entry", g_variant_new_string(desktop_id.c_str())); } - libnotify_loader_.notify_notification_set_hint( + GetLibNotifyLoader().notify_notification_set_hint( notification_, "sender-pid", g_variant_new_int64(base::GetCurrentProcId())); GError* error = nullptr; - libnotify_loader_.notify_notification_show(notification_, &error); + GetLibNotifyLoader().notify_notification_show(notification_, &error); if (error) { log_and_clear_error(error, "notify_notification_show"); NotificationFailed(); @@ -169,7 +173,7 @@ void LibnotifyNotification::Dismiss() { GError* error = nullptr; on_dismissing_ = true; - libnotify_loader_.notify_notification_close(notification_, &error); + GetLibNotifyLoader().notify_notification_close(notification_, &error); if (error) { log_and_clear_error(error, "notify_notification_close"); } diff --git a/shell/browser/notifications/win/notification_presenter_win.cc b/shell/browser/notifications/win/notification_presenter_win.cc index 39acd451247eb..2649ce40a917a 100644 --- a/shell/browser/notifications/win/notification_presenter_win.cc +++ b/shell/browser/notifications/win/notification_presenter_win.cc @@ -11,7 +11,7 @@ #include <vector> #include "base/files/file_util.h" -#include "base/hash/md5.h" +#include "base/hash/sha1.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -30,9 +30,8 @@ namespace { bool SaveIconToPath(const SkBitmap& bitmap, const base::FilePath& path) { std::optional<std::vector<uint8_t>> png_data = gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false); - if (!png_data.has_value()) + if (!png_data.has_value() || !png_data.value().size()) return false; - return base::WriteFile(path, png_data.value()); } @@ -64,10 +63,12 @@ bool NotificationPresenterWin::Init() { std::wstring NotificationPresenterWin::SaveIconToFilesystem( const SkBitmap& icon, const GURL& origin) { - std::string filename; + if (icon.drawsNothing()) + return L""; + std::string filename; if (origin.is_valid()) { - filename = base::MD5String(origin.spec()) + ".png"; + filename = base::SHA1HashString(origin.spec()) + ".png"; } else { const int64_t now_usec = base::Time::Now().since_origin().InMicroseconds(); filename = base::NumberToString(now_usec) + ".png"; @@ -75,11 +76,11 @@ std::wstring NotificationPresenterWin::SaveIconToFilesystem( ScopedAllowBlockingForElectron allow_blocking; base::FilePath path = temp_dir_.GetPath().Append(base::UTF8ToWide(filename)); - if (base::PathExists(path)) - return path.value(); - if (SaveIconToPath(icon, path)) - return path.value(); - return base::UTF8ToWide(origin.spec()); + + if (!SaveIconToPath(icon, path)) + return L""; + + return path.value(); } Notification* NotificationPresenterWin::CreateNotificationObject( diff --git a/shell/browser/notifications/win/windows_toast_notification.cc b/shell/browser/notifications/win/windows_toast_notification.cc index a9eae96c96bc2..d377e03cf102e 100644 --- a/shell/browser/notifications/win/windows_toast_notification.cc +++ b/shell/browser/notifications/win/windows_toast_notification.cc @@ -147,12 +147,12 @@ const char* GetTemplateType(bool two_lines, bool has_icon) { } // namespace // static -ComPtr<winui::Notifications::IToastNotificationManagerStatics> - WindowsToastNotification::toast_manager_; +ComPtr<winui::Notifications::IToastNotificationManagerStatics>* + WindowsToastNotification::toast_manager_ = nullptr; // static -ComPtr<winui::Notifications::IToastNotifier> - WindowsToastNotification::toast_notifier_; +ComPtr<winui::Notifications::IToastNotifier>* + WindowsToastNotification::toast_notifier_ = nullptr; // static bool WindowsToastNotification::Initialize() { @@ -163,21 +163,35 @@ bool WindowsToastNotification::Initialize() { RuntimeClass_Windows_UI_Notifications_ToastNotificationManager); if (!toast_manager_str.success()) return false; - if (FAILED(Windows::Foundation::GetActivationFactory(toast_manager_str, - &toast_manager_))) + + if (!toast_manager_) { + toast_manager_ = new ComPtr< + ABI::Windows::UI::Notifications::IToastNotificationManagerStatics>(); + } + + if (FAILED(Windows::Foundation::GetActivationFactory( + toast_manager_str, toast_manager_->GetAddressOf()))) return false; + if (!toast_notifier_) { + toast_notifier_ = + new ComPtr<ABI::Windows::UI::Notifications::IToastNotifier>(); + } + if (IsRunningInDesktopBridge()) { // Ironically, the Desktop Bridge / UWP environment // requires us to not give Windows an appUserModelId. - return SUCCEEDED(toast_manager_->CreateToastNotifier(&toast_notifier_)); + return SUCCEEDED( + (*toast_manager_) + ->CreateToastNotifier(toast_notifier_->GetAddressOf())); } else { ScopedHString app_id; if (!GetAppUserModelID(&app_id)) return false; - return SUCCEEDED( - toast_manager_->CreateToastNotifierWithId(app_id, &toast_notifier_)); + return SUCCEEDED((*toast_manager_) + ->CreateToastNotifierWithId( + app_id, toast_notifier_->GetAddressOf())); } } @@ -207,7 +221,7 @@ void WindowsToastNotification::Remove() { ComPtr<winui::Notifications::IToastNotificationManagerStatics2> toast_manager2; - if (FAILED(toast_manager_.As(&toast_manager2))) + if (FAILED(toast_manager_->As(&toast_manager2))) return; ComPtr<winui::Notifications::IToastNotificationHistory> notification_history; @@ -226,7 +240,7 @@ void WindowsToastNotification::Remove() { void WindowsToastNotification::Dismiss() { DebugLog("Hiding notification"); - toast_notifier_->Hide(toast_notification_.Get()); + (*toast_notifier_)->Hide(toast_notification_.Get()); } HRESULT WindowsToastNotification::ShowInternal( @@ -281,8 +295,9 @@ HRESULT WindowsToastNotification::ShowInternal( REPORT_AND_RETURN_IF_FAILED(SetupCallbacks(toast_notification_.Get()), "WinAPI: SetupCallbacks failed"); - REPORT_AND_RETURN_IF_FAILED(toast_notifier_->Show(toast_notification_.Get()), - "WinAPI: Show failed"); + REPORT_AND_RETURN_IF_FAILED( + (*toast_notifier_)->Show(toast_notification_.Get()), + "WinAPI: Show failed"); return S_OK; } @@ -338,6 +353,7 @@ std::u16string WindowsToastNotification::GetToastXml( // Optional icon as app logo override (small icon). if (!icon_path.empty()) { xml_writer.StartElement(kImage); + xml_writer.AddAttribute(kID, "1"); xml_writer.AddAttribute(kPlacement, kAppLogoOverride); xml_writer.AddAttribute(kHintCrop, kHintCropNone); xml_writer.AddAttribute(kSrc, base::WideToUTF8(icon_path)); diff --git a/shell/browser/notifications/win/windows_toast_notification.h b/shell/browser/notifications/win/windows_toast_notification.h index 3065700efd0a1..da6eca87f95d9 100644 --- a/shell/browser/notifications/win/windows_toast_notification.h +++ b/shell/browser/notifications/win/windows_toast_notification.h @@ -72,9 +72,9 @@ class WindowsToastNotification : public Notification { ABI::Windows::UI::Notifications::IToastNotification* toast); static ComPtr< - ABI::Windows::UI::Notifications::IToastNotificationManagerStatics> + ABI::Windows::UI::Notifications::IToastNotificationManagerStatics>* toast_manager_; - static ComPtr<ABI::Windows::UI::Notifications::IToastNotifier> + static ComPtr<ABI::Windows::UI::Notifications::IToastNotifier>* toast_notifier_; EventRegistrationToken activated_token_; diff --git a/shell/browser/osr/osr_host_display_client.cc b/shell/browser/osr/osr_host_display_client.cc index 8f316f044919d..e2c41c8442be8 100644 --- a/shell/browser/osr/osr_host_display_client.cc +++ b/shell/browser/osr/osr_host_display_client.cc @@ -6,7 +6,7 @@ #include <utility> -#include "components/viz/common/resources/resource_sizes.h" +#include "components/viz/common/resources/shared_image_format_utils.h" #include "mojo/public/cpp/system/platform_handle.h" #include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkColor.h" @@ -39,11 +39,10 @@ void LayeredWindowUpdater::OnAllocatedSharedMemory( return; // Make sure |pixel_size| is sane. - size_t expected_bytes; - bool size_result = viz::ResourceSizes::MaybeSizeInBytes( - pixel_size, viz::SinglePlaneFormat::kRGBA_8888, &expected_bytes); - if (!size_result) + if (!SharedMemorySizeForSharedImageFormat(viz::SinglePlaneFormat::kRGBA_8888, + pixel_size)) { return; + } #if defined(WIN32) canvas_ = skia::CreatePlatformCanvasWithSharedSection( diff --git a/shell/browser/osr/osr_host_display_client.h b/shell/browser/osr/osr_host_display_client.h index e95eb43bd1ef3..fc914b52fd35a 100644 --- a/shell/browser/osr/osr_host_display_client.h +++ b/shell/browser/osr/osr_host_display_client.h @@ -14,7 +14,7 @@ #include "shell/browser/osr/osr_paint_event.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" class SkBitmap; class SkCanvas; diff --git a/shell/browser/osr/osr_paint_event.h b/shell/browser/osr/osr_paint_event.h index cd8f8710c6703..b3e37a6a16857 100644 --- a/shell/browser/osr/osr_paint_event.h +++ b/shell/browser/osr/osr_paint_event.h @@ -13,7 +13,7 @@ #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" #include <cstdint> diff --git a/shell/browser/osr/osr_render_widget_host_view.cc b/shell/browser/osr/osr_render_widget_host_view.cc index df712cefe4f48..c9fdc0a8a679b 100644 --- a/shell/browser/osr/osr_render_widget_host_view.cc +++ b/shell/browser/osr/osr_render_widget_host_view.cc @@ -45,7 +45,7 @@ #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/image/image_skia.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" #include "ui/gfx/skbitmap_operations.h" #include "ui/latency/latency_info.h" @@ -154,6 +154,7 @@ class ElectronDelegatedFrameHostClient OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( bool transparent, bool offscreen_use_shared_texture, + const std::string& offscreen_shared_texture_pixel_format, bool painting, int frame_rate, const OnPaintCallback& callback, @@ -165,6 +166,8 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( parent_host_view_(parent_host_view), transparent_(transparent), offscreen_use_shared_texture_(offscreen_use_shared_texture), + offscreen_shared_texture_pixel_format_( + offscreen_shared_texture_pixel_format), callback_(callback), frame_rate_(frame_rate), size_(initial_size), @@ -207,6 +210,15 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( compositor_->SetDelegate(this); compositor_->SetRootLayer(root_layer_.get()); + // For offscreen rendering with format rgbaf16, we need to set correct display + // color spaces to the compositor, otherwise it won't support hdr. + if (offscreen_use_shared_texture_ && + offscreen_shared_texture_pixel_format_ == "rgbaf16") { + gfx::DisplayColorSpaces hdr_display_color_spaces( + gfx::ColorSpace::CreateSRGBLinear(), viz::SinglePlaneFormat::kRGBA_F16); + compositor_->SetDisplayColorSpaces(hdr_display_color_spaces); + } + ResizeRootLayer(false); render_widget_host_->SetView(this); @@ -486,7 +498,8 @@ uint32_t OffScreenRenderWidgetHostView::GetCaptureSequenceNumber() const { void OffScreenRenderWidgetHostView::CopyFromSurface( const gfx::Rect& src_rect, const gfx::Size& output_size, - base::OnceCallback<void(const SkBitmap&)> callback) { + base::OnceCallback<void(const viz::CopyOutputBitmapWithMetadata&)> + callback) { delegated_frame_host()->CopyFromCompositingSurface(src_rect, output_size, std::move(callback)); } @@ -548,7 +561,8 @@ OffScreenRenderWidgetHostView::CreateViewForWidget( } return new OffScreenRenderWidgetHostView( - transparent_, offscreen_use_shared_texture_, true, + transparent_, offscreen_use_shared_texture_, + offscreen_shared_texture_pixel_format_, true, embedder_host_view->frame_rate(), callback_, render_widget_host, embedder_host_view, size()); } @@ -961,7 +975,7 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) { SetupFrameRate(false); display::Display display = - display::Screen::GetScreen()->GetDisplayNearestView(GetNativeView()); + display::Screen::Get()->GetDisplayNearestView(GetNativeView()); const float scaleFactor = display.device_scale_factor(); float sf = GetDeviceScaleFactor(); const bool sf_did_change = scaleFactor != sf; diff --git a/shell/browser/osr/osr_render_widget_host_view.h b/shell/browser/osr/osr_render_widget_host_view.h index 2e7738fe2faf4..2ec006889a355 100644 --- a/shell/browser/osr/osr_render_widget_host_view.h +++ b/shell/browser/osr/osr_render_widget_host_view.h @@ -69,14 +69,16 @@ class OffScreenRenderWidgetHostView public ui::CompositorDelegate, private OffscreenViewProxyObserver { public: - OffScreenRenderWidgetHostView(bool transparent, - bool offscreen_use_shared_texture, - bool painting, - int frame_rate, - const OnPaintCallback& callback, - content::RenderWidgetHost* render_widget_host, - OffScreenRenderWidgetHostView* parent_host_view, - gfx::Size initial_size); + OffScreenRenderWidgetHostView( + bool transparent, + bool offscreen_use_shared_texture, + const std::string& offscreen_shared_texture_pixel_format, + bool painting, + int frame_rate, + const OnPaintCallback& callback, + content::RenderWidgetHost* render_widget_host, + OffScreenRenderWidgetHostView* parent_host_view, + gfx::Size initial_size); ~OffScreenRenderWidgetHostView() override; // disable copy @@ -145,7 +147,8 @@ class OffScreenRenderWidgetHostView void CopyFromSurface( const gfx::Rect& src_rect, const gfx::Size& output_size, - base::OnceCallback<void(const SkBitmap&)> callback) override; + base::OnceCallback<void(const viz::CopyOutputBitmapWithMetadata&)> + callback) override; display::ScreenInfo GetScreenInfo() const override; void TransformPointToRootSurface(gfx::PointF* point) override {} gfx::Rect GetBoundsInRootWindow() override; @@ -238,6 +241,10 @@ class OffScreenRenderWidgetHostView return offscreen_use_shared_texture_; } + const std::string offscreen_shared_texture_pixel_format() const { + return offscreen_shared_texture_pixel_format_; + } + ui::Layer* root_layer() const { return root_layer_.get(); } content::DelegatedFrameHost* delegated_frame_host() const { @@ -283,6 +290,7 @@ class OffScreenRenderWidgetHostView const bool transparent_; const bool offscreen_use_shared_texture_; + const std::string offscreen_shared_texture_pixel_format_; OnPaintCallback callback_; OnPopupPaintCallback parent_callback_; diff --git a/shell/browser/osr/osr_video_consumer.cc b/shell/browser/osr/osr_video_consumer.cc index ac00b63a817e5..caedef4d2594a 100644 --- a/shell/browser/osr/osr_video_consumer.cc +++ b/shell/browser/osr/osr_video_consumer.cc @@ -16,6 +16,22 @@ #include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/skbitmap_operations.h" +namespace { + +media::VideoPixelFormat GetTargetPixelFormatFromOption( + const std::string& pixel_format_option) { + if (pixel_format_option == "argb") { + return media::PIXEL_FORMAT_ARGB; + } else if (pixel_format_option == "rgbaf16") { + return media::PIXEL_FORMAT_RGBAF16; + } + + // Use ARGB as default. + return media::PIXEL_FORMAT_ARGB; +} + +} // namespace + namespace electron { OffScreenVideoConsumer::OffScreenVideoConsumer( @@ -26,7 +42,10 @@ OffScreenVideoConsumer::OffScreenVideoConsumer( video_capturer_(view->CreateVideoCapturer()) { video_capturer_->SetAutoThrottlingEnabled(false); video_capturer_->SetMinSizeChangePeriod(base::TimeDelta()); - video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB); + + auto format = GetTargetPixelFormatFromOption( + view->offscreen_shared_texture_pixel_format()); + video_capturer_->SetFormat(format); // https://crrev.org/c/6438681 // Disable capturer's animation lock-in feature for offscreen capture to diff --git a/shell/browser/osr/osr_video_consumer.h b/shell/browser/osr/osr_video_consumer.h index 78dc1518f23ab..e97097996a193 100644 --- a/shell/browser/osr/osr_video_consumer.h +++ b/shell/browser/osr/osr_video_consumer.h @@ -41,7 +41,8 @@ class OffScreenVideoConsumer : public viz::mojom::FrameSinkVideoConsumer { const gfx::Rect& content_rect, mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks) override; - void OnNewSubCaptureTargetVersion(uint32_t crop_version) override {} + void OnNewCaptureVersion( + const media::CaptureVersion& capture_version) override {} void OnFrameWithEmptyRegionCapture() override {} void OnStopped() override {} void OnLog(const std::string& message) override {} diff --git a/shell/browser/osr/osr_web_contents_view.cc b/shell/browser/osr/osr_web_contents_view.cc index 3606e2754ce74..99991fee12cef 100644 --- a/shell/browser/osr/osr_web_contents_view.cc +++ b/shell/browser/osr/osr_web_contents_view.cc @@ -16,9 +16,12 @@ namespace electron { OffScreenWebContentsView::OffScreenWebContentsView( bool transparent, bool offscreen_use_shared_texture, + const std::string& offscreen_shared_texture_pixel_format, const OnPaintCallback& callback) : transparent_(transparent), offscreen_use_shared_texture_(offscreen_use_shared_texture), + offscreen_shared_texture_pixel_format_( + offscreen_shared_texture_pixel_format), callback_(callback) { #if BUILDFLAG(IS_MAC) PlatformCreate(); @@ -112,7 +115,8 @@ OffScreenWebContentsView::CreateViewForWidget( return static_cast<content::RenderWidgetHostViewBase*>(rwhv); return new OffScreenRenderWidgetHostView( - transparent_, offscreen_use_shared_texture_, painting_, GetFrameRate(), + transparent_, offscreen_use_shared_texture_, + offscreen_shared_texture_pixel_format_, painting_, GetFrameRate(), callback_, render_widget_host, nullptr, GetSize()); } @@ -132,7 +136,8 @@ OffScreenWebContentsView::CreateViewForChildWidget( } return new OffScreenRenderWidgetHostView( - transparent_, offscreen_use_shared_texture_, painting_, + transparent_, offscreen_use_shared_texture_, + offscreen_shared_texture_pixel_format_, painting_, embedder_host_view->frame_rate(), callback_, render_widget_host, embedder_host_view, GetSize()); } diff --git a/shell/browser/osr/osr_web_contents_view.h b/shell/browser/osr/osr_web_contents_view.h index 50f24b9033037..364fabff78dc8 100644 --- a/shell/browser/osr/osr_web_contents_view.h +++ b/shell/browser/osr/osr_web_contents_view.h @@ -34,9 +34,11 @@ class OffScreenWebContentsView : public content::WebContentsView, public content::RenderViewHostDelegateView, private NativeWindowObserver { public: - OffScreenWebContentsView(bool transparent, - bool offscreen_use_shared_texture, - const OnPaintCallback& callback); + OffScreenWebContentsView( + bool transparent, + bool offscreen_use_shared_texture, + const std::string& offscreen_shared_texture_pixel_format, + const OnPaintCallback& callback); ~OffScreenWebContentsView() override; void SetWebContents(content::WebContents*); @@ -109,6 +111,7 @@ class OffScreenWebContentsView : public content::WebContentsView, const bool transparent_; const bool offscreen_use_shared_texture_; + const std::string offscreen_shared_texture_pixel_format_; bool painting_ = true; int frame_rate_ = 60; OnPaintCallback callback_; diff --git a/shell/browser/relauncher_linux.cc b/shell/browser/relauncher_linux.cc index 7c9c1fa048407..ab9b6b62c8144 100644 --- a/shell/browser/relauncher_linux.cc +++ b/shell/browser/relauncher_linux.cc @@ -11,6 +11,7 @@ #include "base/files/scoped_file.h" #include "base/logging.h" +#include "base/no_destructor.h" #include "base/posix/eintr_wrapper.h" #include "base/process/launch.h" #include "base/synchronization/waitable_event.h" @@ -18,7 +19,10 @@ namespace relauncher::internal { // this is global to be visible to the sa_handler -base::WaitableEvent parentWaiter; +auto& GetParentWaiter() { + static base::NoDestructor<base::WaitableEvent> parentWaiter; + return *parentWaiter; +} void RelauncherSynchronizeWithParent() { base::ScopedFD relauncher_sync_fd(kRelauncherSyncFD); @@ -32,7 +36,7 @@ void RelauncherSynchronizeWithParent() { // set up a signum handler struct sigaction action = {}; - action.sa_handler = [](int /*signum*/) { parentWaiter.Signal(); }; + action.sa_handler = [](int /*signum*/) { GetParentWaiter().Signal(); }; if (sigaction(signum, &action, nullptr) != 0) { PLOG(ERROR) << "sigaction"; return; @@ -46,7 +50,7 @@ void RelauncherSynchronizeWithParent() { } // Wait for the parent to exit - parentWaiter.Wait(); + GetParentWaiter().Wait(); } int LaunchProgram(const StringVector& relauncher_args, diff --git a/shell/browser/ui/cocoa/electron_bundle_mover.h b/shell/browser/ui/cocoa/electron_bundle_mover.h index 5c944952606fe..59b48e099e203 100644 --- a/shell/browser/ui/cocoa/electron_bundle_mover.h +++ b/shell/browser/ui/cocoa/electron_bundle_mover.h @@ -26,8 +26,7 @@ class ElectronBundleMover { static bool IsCurrentAppInApplicationsFolder(); private: - static bool ShouldContinueMove(gin_helper::ErrorThrower thrower, - BundlerMoverConflictType type, + static bool ShouldContinueMove(BundlerMoverConflictType type, gin::Arguments* args); }; diff --git a/shell/browser/ui/cocoa/electron_bundle_mover.mm b/shell/browser/ui/cocoa/electron_bundle_mover.mm index 3eb2692594442..630b98c337ef7 100644 --- a/shell/browser/ui/cocoa/electron_bundle_mover.mm +++ b/shell/browser/ui/cocoa/electron_bundle_mover.mm @@ -328,9 +328,9 @@ bool IsApplicationAtPathRunning(NSString* bundlePath) { namespace electron { -bool ElectronBundleMover::ShouldContinueMove(gin_helper::ErrorThrower thrower, - BundlerMoverConflictType type, - gin::Arguments* args) { +bool ElectronBundleMover::ShouldContinueMove( + const BundlerMoverConflictType type, + gin::Arguments* const args) { gin::Dictionary options(args->isolate()); bool hasOptions = args->GetNext(&options); base::OnceCallback<v8::Local<v8::Value>(BundlerMoverConflictType)> @@ -345,7 +345,7 @@ bool IsApplicationAtPathRunning(NSString* bundlePath) { // we only want to throw an error if a user has returned a non-boolean // value; this allows for client-side error handling should something in // the handler throw - thrower.ThrowError("Invalid conflict handler return type."); + args->ThrowTypeError("Invalid conflict handler return type."); } } return true; @@ -406,8 +406,8 @@ bool IsApplicationAtPathRunning(NSString* bundlePath) { // But first, make sure that it's not running if (IsApplicationAtPathRunning(destinationPath)) { // Check for callback handler and get user choice for open/quit - if (!ShouldContinueMove( - thrower, BundlerMoverConflictType::kExistsAndRunning, args)) + if (!ShouldContinueMove(BundlerMoverConflictType::kExistsAndRunning, + args)) return false; // Unless explicitly denied, give running app focus and terminate self @@ -420,8 +420,7 @@ bool IsApplicationAtPathRunning(NSString* bundlePath) { return true; } else { // Check callback handler and get user choice for app trashing - if (!ShouldContinueMove(thrower, BundlerMoverConflictType::kExists, - args)) + if (!ShouldContinueMove(BundlerMoverConflictType::kExists, args)) return false; // Unless explicitly denied, attempt to trash old app diff --git a/shell/browser/ui/cocoa/electron_menu_controller.mm b/shell/browser/ui/cocoa/electron_menu_controller.mm index 1e78e57f01dc1..56691ec9ef90e 100644 --- a/shell/browser/ui/cocoa/electron_menu_controller.mm +++ b/shell/browser/ui/cocoa/electron_menu_controller.mm @@ -90,6 +90,7 @@ bool MenuHasVisibleItems(const electron::ElectronMenuModel* model) { // "(empty)" into the submenu. Matches Windows behavior. NSMenu* MakeEmptySubmenu() { NSMenu* submenu = [[NSMenu alloc] initWithTitle:@""]; + submenu.autoenablesItems = NO; NSString* empty_menu_title = l10n_util::GetNSString(IDS_APP_MENU_EMPTY_SUBMENU); @@ -231,6 +232,9 @@ - (void)cancel { // be invoked recursively. - (NSMenu*)menuFromModel:(electron::ElectronMenuModel*)model { NSMenu* menu = [[NSMenu alloc] initWithTitle:@""]; + // We manually manage enabled/disabled/hidden state for every item, + // including Cocoa role-based selectors. + menu.autoenablesItems = NO; const int count = model->GetItemCount(); for (int index = 0; index < count; index++) { @@ -240,6 +244,7 @@ - (NSMenu*)menuFromModel:(electron::ElectronMenuModel*)model { [self addItemToMenu:menu atIndex:index fromModel:model]; } + menu.delegate = self; return menu; } @@ -294,9 +299,11 @@ - (NSMenu*)createShareMenuForItem:(const SharingItem&)item { if ([items count] == 0) return MakeEmptySubmenu(); NSMenu* menu = [[NSMenu alloc] init]; + menu.autoenablesItems = NO; NSArray* services = [NSSharingService sharingServicesForItems:items]; for (NSSharingService* service in services) [menu addItem:[self menuItemForService:service withItems:items]]; + [menu setDelegate:self]; return menu; } @@ -353,27 +360,22 @@ - (NSMenuItem*)makeMenuItemForIndex:(NSInteger)index std::u16string title = u"Services"; NSString* sub_label = l10n_util::FixUpWindowsStyleLabel(title); - [item setTarget:nil]; - [item setAction:nil]; + item.target = nil; + item.action = nil; NSMenu* submenu = [[NSMenu alloc] initWithTitle:sub_label]; - [item setSubmenu:submenu]; + item.submenu = submenu; [NSApp setServicesMenu:submenu]; } else if (role == u"sharemenu") { SharingItem sharing_item; model->GetSharingItemAt(index, &sharing_item); - [item setTarget:nil]; - [item setAction:nil]; + item.target = nil; + item.action = nil; [item setSubmenu:[self createShareMenuForItem:sharing_item]]; } else if (type == electron::ElectronMenuModel::TYPE_SUBMENU && model->IsVisibleAt(index)) { - // We need to specifically check that the submenu top-level item has been - // enabled as it's not validated by validateUserInterfaceItem - if (!model->IsEnabledAt(index)) - [item setEnabled:NO]; - // Recursively build a submenu from the sub-model at this index. - [item setTarget:nil]; - [item setAction:nil]; + item.target = nil; + item.action = nil; electron::ElectronMenuModel* submenuModel = static_cast<electron::ElectronMenuModel*>( model->GetSubmenuModelAt(index)); @@ -388,8 +390,12 @@ - (NSMenuItem*)makeMenuItemForIndex:(NSInteger)index } } - [submenu setTitle:[item title]]; - [item setSubmenu:submenu]; + submenu.title = item.title; + item.submenu = submenu; + item.tag = index; + item.representedObject = + [WeakPtrToElectronMenuModelAsNSObject weakPtrForModel:model]; + submenu.delegate = self; // Set submenu's role. if ((role == u"window" || role == u"windowmenu") && [submenu numberOfItems]) @@ -404,9 +410,9 @@ - (NSMenuItem*)makeMenuItemForIndex:(NSInteger)index // the model so hierarchical menus check the correct index in the correct // model. Setting the target to |self| allows this class to participate // in validation of the menu items. - [item setTag:index]; - [item setRepresentedObject:[WeakPtrToElectronMenuModelAsNSObject - weakPtrForModel:model]]; + item.tag = index; + item.representedObject = + [WeakPtrToElectronMenuModelAsNSObject weakPtrForModel:model]; ui::Accelerator accelerator; if (model->GetAcceleratorAtWithParams(index, useDefaultAccelerator_, &accelerator)) { @@ -434,20 +440,20 @@ - (NSMenuItem*)makeMenuItemForIndex:(NSInteger)index ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), modifier_mask, nullptr, &character); } - [item setKeyEquivalent:[NSString stringWithFormat:@"%C", character]]; - [item setKeyEquivalentModifierMask:modifier_mask]; + item.keyEquivalent = [NSString stringWithFormat:@"%C", character]; + item.keyEquivalentModifierMask = modifier_mask; } [(id)item setAllowsKeyEquivalentWhenHidden:(model->WorksWhenHiddenAt(index))]; // Set menu item's role. - [item setTarget:self]; + item.target = self; if (!role.empty()) { for (const Role& pair : kRolesMap) { if (role == base::ASCIIToUTF16(pair.role)) { - [item setTarget:nil]; - [item setAction:pair.selector]; + item.target = nil; + item.action = pair.selector; break; } } @@ -457,6 +463,43 @@ - (NSMenuItem*)makeMenuItemForIndex:(NSInteger)index return item; } +- (void)applyStateToMenuItem:(NSMenuItem*)item { + id represented = item.representedObject; + if (!represented) + return; + + if (![represented + isKindOfClass:[WeakPtrToElectronMenuModelAsNSObject class]]) { + NSLog(@"representedObject is not a WeakPtrToElectronMenuModelAsNSObject"); + return; + } + + electron::ElectronMenuModel* model = + [WeakPtrToElectronMenuModelAsNSObject getFrom:represented]; + if (!model) + return; + + NSInteger index = item.tag; + int count = model->GetItemCount(); + if (index < 0 || index >= count) + return; + + item.hidden = !model->IsVisibleAt(index); + item.enabled = model->IsEnabledAt(index); + item.state = model->IsItemCheckedAt(index) ? NSControlStateValueOn + : NSControlStateValueOff; +} + +// Recursively refreshes the menu tree starting from |menu|, applying the +// model state to each menu item. +- (void)refreshMenuTree:(NSMenu*)menu { + for (NSMenuItem* item in menu.itemArray) { + [self applyStateToMenuItem:item]; + if (item.submenu) + [self refreshMenuTree:item.submenu]; + } +} + // Adds an item or a hierarchical menu to the item at the |index|, // associated with the entry in the model identified by |modelIndex|. - (void)addItemToMenu:(NSMenu*)menu @@ -466,32 +509,6 @@ - (void)addItemToMenu:(NSMenu*)menu atIndex:index]; } -// Called before the menu is to be displayed to update the state (enabled, -// radio, etc) of each item in the menu. -- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { - SEL action = [item action]; - if (action == @selector(performShare:)) - return YES; - if (action != @selector(itemSelected:)) - return NO; - - NSInteger modelIndex = [item tag]; - electron::ElectronMenuModel* model = [WeakPtrToElectronMenuModelAsNSObject - getFrom:[(id)item representedObject]]; - DCHECK(model); - if (model) { - BOOL checked = model->IsItemCheckedAt(modelIndex); - DCHECK([(id)item isKindOfClass:[NSMenuItem class]]); - - [(id)item - setState:(checked ? NSControlStateValueOn : NSControlStateValueOff)]; - [(id)item setHidden:(!model->IsVisibleAt(modelIndex))]; - - return model->IsEnabledAt(modelIndex); - } - return NO; -} - // Called when the user chooses a particular menu item. |sender| is the menu // item chosen. - (void)itemSelected:(id)sender { @@ -526,10 +543,11 @@ - (NSMenu*)menu { menu_ = menu; } else { menu_ = [[NSMenu alloc] initWithTitle:@""]; + menu_.autoenablesItems = NO; if (model_) [self populateWithModel:model_.get()]; } - [menu_ setDelegate:self]; + menu_.delegate = self; return menu_; } @@ -539,6 +557,7 @@ - (BOOL)isMenuOpen { - (void)menuWillOpen:(NSMenu*)menu { isMenuOpen_ = YES; + [self refreshMenuTree:menu]; if (model_) model_->MenuWillShow(); } diff --git a/shell/browser/ui/cocoa/electron_ns_window.h b/shell/browser/ui/cocoa/electron_ns_window.h index 8c026c0b0bdca..de2414e041e57 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.h +++ b/shell/browser/ui/cocoa/electron_ns_window.h @@ -40,7 +40,6 @@ class ElectronNativeWindowObserver; @property BOOL disableAutoHideCursor; @property BOOL disableKeyOrMainWindow; @property(nonatomic, retain) NSVisualEffectView* vibrantView; -@property(nonatomic, retain) NSImage* cornerMask; - (id)initWithShell:(electron::NativeWindowMac*)shell styleMask:(NSUInteger)styleMask; - (void)cleanup; @@ -48,7 +47,6 @@ class ElectronNativeWindowObserver; - (id)accessibilityFocusedUIElement; - (NSRect)originalContentRectForFrameRect:(NSRect)frameRect; - (BOOL)toggleFullScreenMode:(id)sender; -- (NSImage*)_cornerMask; - (void)disableHeadlessMode; @end diff --git a/shell/browser/ui/cocoa/electron_ns_window.mm b/shell/browser/ui/cocoa/electron_ns_window.mm index 007997838699d..7156fa986406e 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.mm +++ b/shell/browser/ui/cocoa/electron_ns_window.mm @@ -25,7 +25,6 @@ } // namespace electron @interface NSWindow (PrivateAPI) -- (NSImage*)_cornerMask; - (int64_t)_resizeDirectionForMouseLocation:(CGPoint)location; @end @@ -123,7 +122,6 @@ @implementation ElectronNSWindow @synthesize disableAutoHideCursor; @synthesize disableKeyOrMainWindow; @synthesize vibrantView; -@synthesize cornerMask; - (id)initWithShell:(electron::NativeWindowMac*)shell styleMask:(NSUInteger)styleMask { @@ -308,16 +306,6 @@ - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { return [super validateUserInterfaceItem:item]; } -// By overriding this built-in method the corners of the vibrant view (if set) -// will be smooth. -- (NSImage*)_cornerMask { - if (self.vibrantView != nil) { - return [self cornerMask]; - } else { - return [super _cornerMask]; - } -} - - (void)disableHeadlessMode { if (shell_) { // We initialize the window in headless mode to allow painting before it is diff --git a/shell/browser/ui/cocoa/window_buttons_proxy.mm b/shell/browser/ui/cocoa/window_buttons_proxy.mm index de1d6b4630310..c0dfd0ac58e72 100644 --- a/shell/browser/ui/cocoa/window_buttons_proxy.mm +++ b/shell/browser/ui/cocoa/window_buttons_proxy.mm @@ -176,6 +176,13 @@ - (void)updateButtonsVisibility { [button setHidden:hidden]; [button setNeedsDisplay:YES]; } + + // On macOS 26, toggling the hidden state of the standard window buttons can + // cause AppKit to re-layout the title bar container and reset its frame, + // which loses the custom margin adjustments. Re-apply the calculated geometry + // after visibility changes to keep the buttons at the specified margin + // instead of snapping back to the default until the next manual resize. + [self redraw]; } // Return the bounds of all 3 buttons. diff --git a/shell/browser/ui/devtools_ui_bundle_data_source.cc b/shell/browser/ui/devtools_ui_bundle_data_source.cc index 2a73bfeb6e5f4..5733a7d8a161e 100644 --- a/shell/browser/ui/devtools_ui_bundle_data_source.cc +++ b/shell/browser/ui/devtools_ui_bundle_data_source.cc @@ -32,7 +32,7 @@ std::string PathWithoutParams(const std::string& path) { url::kStandardSchemeSeparator, chrome::kChromeUIDevToolsHost})) .Resolve(path) - .path() + .GetPath() .substr(1); } diff --git a/shell/browser/ui/drag_util.h b/shell/browser/ui/drag_util.h index 55fed34ca0d6c..fb4120c4476c3 100644 --- a/shell/browser/ui/drag_util.h +++ b/shell/browser/ui/drag_util.h @@ -9,7 +9,7 @@ #include <vector> #include "third_party/blink/public/mojom/page/draggable_region.mojom-forward.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" class SkRegion; diff --git a/shell/browser/ui/drag_util_views.cc b/shell/browser/ui/drag_util_views.cc index f64f3ec54dab8..4e4aa8870eeb0 100644 --- a/shell/browser/ui/drag_util_views.cc +++ b/shell/browser/ui/drag_util_views.cc @@ -12,6 +12,7 @@ #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/display/screen.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/image/image_skia.h" #include "ui/views/button_drag_utils.h" #include "ui/views/widget/widget.h" #include "url/gurl.h" @@ -38,7 +39,7 @@ void DragFileItems(const std::vector<base::FilePath>& files, } data->SetFilenames(file_infos); - gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point location = display::Screen::Get()->GetCursorScreenPoint(); // TODO(varunjain): Properly determine and send DragEventSource below. aura::client::GetDragDropClient(root_window) ->StartDragAndDrop( diff --git a/shell/browser/ui/electron_desktop_window_tree_host_linux.cc b/shell/browser/ui/electron_desktop_window_tree_host_linux.cc index 4502f132c71f9..5e27038f7c958 100644 --- a/shell/browser/ui/electron_desktop_window_tree_host_linux.cc +++ b/shell/browser/ui/electron_desktop_window_tree_host_linux.cc @@ -100,13 +100,19 @@ void ElectronDesktopWindowTreeHostLinux::OnWindowStateChanged( void ElectronDesktopWindowTreeHostLinux::OnWindowTiledStateChanged( ui::WindowTiledEdges new_tiled_edges) { if (auto* const view = native_window_view_->GetClientFrameViewLinux()) { - bool maximized = new_tiled_edges.top && new_tiled_edges.left && - new_tiled_edges.bottom && new_tiled_edges.right; + // GNOME on Ubuntu reports all edges as tiled + // even if the window is only half-tiled so do not trust individual edge + // values. + bool maximized = native_window_view_->IsMaximized(); bool tiled = new_tiled_edges.top || new_tiled_edges.left || new_tiled_edges.bottom || new_tiled_edges.right; view->set_tiled(tiled && !maximized); } UpdateFrameHints(); + ScheduleRelayout(); + if (GetWidget()->non_client_view()) { + GetWidget()->non_client_view()->SchedulePaint(); + } } void ElectronDesktopWindowTreeHostLinux::UpdateWindowState( @@ -283,7 +289,7 @@ void ElectronDesktopWindowTreeHostLinux::DispatchEvent(ui::Event* event) { ->GetPlatformRuntimeProperties() .supports_server_window_menus) { views::DesktopWindowTreeHostLinux::ShowWindowControlsMenu( - display::Screen::GetScreen()->GetCursorScreenPoint()); + display::Screen::Get()->GetCursorScreenPoint()); } } return; diff --git a/shell/browser/ui/file_dialog.h b/shell/browser/ui/file_dialog.h index f7757da491c65..6cdfc7b667a37 100644 --- a/shell/browser/ui/file_dialog.h +++ b/shell/browser/ui/file_dialog.h @@ -13,6 +13,10 @@ #include "base/files/file_path.h" #include "base/memory/raw_ptr_exclusion.h" +#if BUILDFLAG(IS_LINUX) +#include <bits/stdint-uintn.h> +#endif + namespace electron { class NativeWindow; } diff --git a/shell/browser/ui/file_dialog_linux_portal.cc b/shell/browser/ui/file_dialog_linux_portal.cc index bd2c986fb8edb..e1bcbfafd9435 100644 --- a/shell/browser/ui/file_dialog_linux_portal.cc +++ b/shell/browser/ui/file_dialog_linux_portal.cc @@ -72,7 +72,8 @@ void CheckPortalAvailabilityOnBusThread() { options.bus_type = dbus::Bus::SESSION; options.connection_type = dbus::Bus::PRIVATE; options.dbus_task_runner = g_electron_dbus_thread_task_runner.Get(); - scoped_refptr<dbus::Bus> bus = base::MakeRefCounted<dbus::Bus>(options); + scoped_refptr<dbus::Bus> bus = + base::MakeRefCounted<dbus::Bus>(std::move(options)); dbus_utils::CheckForServiceAndStart( bus, kXdgPortalService, base::BindOnce( diff --git a/shell/browser/ui/file_dialog_win.cc b/shell/browser/ui/file_dialog_win.cc index 5ded77f646610..9a9b218644fba 100644 --- a/shell/browser/ui/file_dialog_win.cc +++ b/shell/browser/ui/file_dialog_win.cc @@ -44,8 +44,7 @@ void ConvertFilters(const Filters& filters, std::vector<std::wstring>* buffer, std::vector<COMDLG_FILTERSPEC>* filterspec) { if (filters.empty()) { - COMDLG_FILTERSPEC spec = {L"All Files (*.*)", L"*.*"}; - filterspec->push_back(spec); + filterspec->push_back({L"All Files (*.*)", L"*.*"}); return; } @@ -55,11 +54,16 @@ void ConvertFilters(const Filters& filters, buffer->push_back(base::UTF8ToWide(filter.first)); spec.pszName = buffer->back().c_str(); - std::vector<std::string> extensions(filter.second); - for (std::string& extension : extensions) - extension.insert(0, "*."); - buffer->push_back(base::UTF8ToWide(base::JoinString(extensions, ";"))); - spec.pszSpec = buffer->back().c_str(); + if (filter.second.empty()) { + buffer->push_back(L"*.*"); + spec.pszSpec = buffer->back().c_str(); + } else { + std::vector<std::string> extensions(filter.second); + for (std::string& extension : extensions) + extension.insert(0, "*."); + buffer->push_back(base::UTF8ToWide(base::JoinString(extensions, ";"))); + spec.pszSpec = buffer->back().c_str(); + } filterspec->push_back(spec); } diff --git a/shell/browser/ui/inspectable_web_contents.cc b/shell/browser/ui/inspectable_web_contents.cc index f05476527bd73..d641ce572450f 100644 --- a/shell/browser/ui/inspectable_web_contents.cc +++ b/shell/browser/ui/inspectable_web_contents.cc @@ -36,7 +36,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/browser/storage_partition.h" -#include "ipc/ipc_channel.h" +#include "ipc/constants.mojom.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "services/network/public/cpp/simple_url_loader.h" @@ -60,10 +60,11 @@ #include "v8/include/v8.h" #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) -#include "chrome/common/extensions/chrome_manifest_url_handlers.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_process_host.h" #include "extensions/browser/extension_registry.h" +#include "extensions/common/manifest_handlers/chrome_url_overrides_handler.h" +#include "extensions/common/manifest_handlers/devtools_page_handler.h" #include "extensions/common/permissions/permissions_data.h" #endif @@ -92,7 +93,7 @@ constexpr std::string_view kFrontendHostMethod = "method"; constexpr std::string_view kFrontendHostParams = "params"; constexpr std::string_view kTitleFormat = "Developer Tools - %s"; -const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4; +const size_t kMaxMessageChunkSize = IPC::mojom::kChannelMaximumMessageSize / 4; base::Value::Dict RectToDictionary(const gfx::Rect& bounds) { return base::Value::Dict{} @@ -109,7 +110,7 @@ gfx::Rect DictionaryToRect(const base::Value::Dict& dict) { } bool IsPointInScreen(const gfx::Point& point) { - return std::ranges::any_of(display::Screen::GetScreen()->GetAllDisplays(), + return std::ranges::any_of(display::Screen::Get()->GetAllDisplays(), [&point](auto const& display) { return display.bounds().Contains(point); }); @@ -325,11 +326,11 @@ InspectableWebContents::InspectableWebContents( if (!IsPointInScreen(devtools_bounds_.origin())) { gfx::Rect display; if (!is_guest && web_contents_->GetNativeView()) { - display = display::Screen::GetScreen() + display = display::Screen::Get() ->GetDisplayNearestView(web_contents_->GetNativeView()) .bounds(); } else { - display = display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); + display = display::Screen::Get()->GetPrimaryDisplay().bounds(); } devtools_bounds_.set_x(display.x() + @@ -519,6 +520,12 @@ void InspectableWebContents::UpdateDevToolsZoomLevel(double level) { } void InspectableWebContents::ActivateWindow() { + if (embedder_message_dispatcher_) { + if (managed_devtools_web_contents_ && view_) { + view_->ActivateDevTools(); + } + } + // Set the zoom level. SetZoomLevelForWebContents(GetDevToolsWebContents(), GetDevToolsZoomLevel()); } @@ -680,7 +687,7 @@ void InspectableWebContents::LoadNetworkResource(DispatchCallback callback, std::make_unique<network::WrapperPendingSharedURLLoaderFactory>( std::move(pending_remote))); } else if (const auto* const protocol_handler = - protocol_registry->FindRegistered(gurl.scheme_piece())) { + protocol_registry->FindRegistered(gurl.scheme())) { url_loader_factory = network::SharedURLLoaderFactory::Create( std::make_unique<network::WrapperPendingSharedURLLoaderFactory>( ElectronURLLoaderFactory::Create(protocol_handler->first, diff --git a/shell/browser/ui/inspectable_web_contents.h b/shell/browser/ui/inspectable_web_contents.h index fd7ef2f59c5ed..c5163d5d15e29 100644 --- a/shell/browser/ui/inspectable_web_contents.h +++ b/shell/browser/ui/inspectable_web_contents.h @@ -195,6 +195,9 @@ class InspectableWebContents const std::string& request) override {} void RegisterAidaClientEvent(DispatchCallback callback, const std::string& request) override {} + void DispatchHttpRequest( + DispatchCallback callback, + const DevToolsDispatchHttpRequestParams& params) override {} // content::DevToolsFrontendHostDelegate: void HandleMessageFromDevToolsFrontend(base::Value::Dict message); diff --git a/shell/browser/ui/inspectable_web_contents_view.cc b/shell/browser/ui/inspectable_web_contents_view.cc index 09155c1ced5e7..00fff4a08265c 100644 --- a/shell/browser/ui/inspectable_web_contents_view.cc +++ b/shell/browser/ui/inspectable_web_contents_view.cc @@ -132,6 +132,23 @@ void InspectableWebContentsView::ShowDevTools(bool activate) { } } +void InspectableWebContentsView::ActivateDevTools() { + if (!devtools_visible_) { + return; + } + if (devtools_window_) { + if (!devtools_window_->IsActive()) { + devtools_window_->Activate(); + } + return; + } + if (devtools_web_view_) { + if (!devtools_web_view_->HasFocus()) { + devtools_web_view_->RequestFocus(); + } + } +} + void InspectableWebContentsView::CloseDevTools() { if (!devtools_visible_) return; diff --git a/shell/browser/ui/inspectable_web_contents_view.h b/shell/browser/ui/inspectable_web_contents_view.h index 282d3bf805a97..ff2ee8636555f 100644 --- a/shell/browser/ui/inspectable_web_contents_view.h +++ b/shell/browser/ui/inspectable_web_contents_view.h @@ -10,7 +10,7 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/devtools/devtools_contents_resizing_strategy.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" #include "ui/views/view.h" class DevToolsContentsResizingStrategy; @@ -49,6 +49,7 @@ class InspectableWebContentsView : public views::View { void SetCornerRadii(const gfx::RoundedCornersF& corner_radii); void ShowDevTools(bool activate); + void ActivateDevTools(); void CloseDevTools(); bool IsDevToolsViewShowing(); bool IsDevToolsViewFocused(); diff --git a/shell/browser/ui/message_box_win.cc b/shell/browser/ui/message_box_win.cc index e8658938e584c..d683d6c43d077 100644 --- a/shell/browser/ui/message_box_win.cc +++ b/shell/browser/ui/message_box_win.cc @@ -19,8 +19,8 @@ #include "shell/browser/browser.h" #include "shell/browser/native_window_views.h" #include "shell/browser/ui/win/dialog_thread.h" -#include "ui/gfx/icon_util.h" #include "ui/gfx/image/image_skia.h" +#include "ui/gfx/win/icon_util.h" namespace electron { @@ -160,10 +160,22 @@ DialogResult ShowTaskDialogWstr(gfx::AcceleratedWidget parent, if (parent) { config.hwndParent = parent; + config.dwFlags |= TDF_POSITION_RELATIVE_TO_WINDOW; } - if (default_id > 0) - config.nDefaultButton = kIDStart + default_id; + if (default_id >= 0 && + base::checked_cast<size_t>(default_id) < buttons.size()) { + if (!no_link) { + auto common = GetCommonID(buttons[default_id]); + if (common.button != -1) { + config.nDefaultButton = common.id; + } else { + config.nDefaultButton = kIDStart + default_id; + } + } else { + config.nDefaultButton = kIDStart + default_id; + } + } // TaskDialogIndirect doesn't allow empty name, if we set empty title it // will show "electron.exe" in title. diff --git a/shell/browser/ui/tray_icon_linux.cc b/shell/browser/ui/tray_icon_linux.cc index 50b03937babdd..b7147c7bed270 100644 --- a/shell/browser/ui/tray_icon_linux.cc +++ b/shell/browser/ui/tray_icon_linux.cc @@ -6,7 +6,9 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h" +#include "shell/browser/browser.h" #include "shell/browser/ui/status_icon_gtk.h" +#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_rep.h" namespace electron { @@ -31,7 +33,7 @@ gfx::ImageSkia GetBestImageRep(const gfx::ImageSkia& image) { } // namespace TrayIconLinux::TrayIconLinux() - : status_icon_dbus_(new StatusIconLinuxDbus), + : status_icon_dbus_(new StatusIconLinuxDbus(Browser::Get()->GetName())), status_icon_type_(StatusIconType::kDbus) { status_icon_dbus_->SetDelegate(this); } diff --git a/shell/browser/ui/tray_icon_linux.h b/shell/browser/ui/tray_icon_linux.h index baff7a625a4da..d8cd0ef1e54e1 100644 --- a/shell/browser/ui/tray_icon_linux.h +++ b/shell/browser/ui/tray_icon_linux.h @@ -9,6 +9,7 @@ #include <string> #include "shell/browser/ui/tray_icon.h" +#include "ui/gfx/image/image_skia.h" #include "ui/linux/status_icon_linux.h" class StatusIconLinuxDbus; diff --git a/shell/browser/ui/tray_icon_win.cc b/shell/browser/ui/tray_icon_win.cc index 9153748f5ea60..bc4267bf21615 100644 --- a/shell/browser/ui/tray_icon_win.cc +++ b/shell/browser/ui/tray_icon_win.cc @@ -9,8 +9,8 @@ namespace electron { // static TrayIcon* TrayIcon::Create(std::optional<base::Uuid> guid) { - static NotifyIconHost host; - return host.CreateNotifyIcon(guid); + static NotifyIconHost* host = new NotifyIconHost(); + return host->CreateNotifyIcon(guid); } } // namespace electron diff --git a/shell/browser/ui/views/autofill_popup_view.cc b/shell/browser/ui/views/autofill_popup_view.cc index c80294774e74a..fe92fbc562b28 100644 --- a/shell/browser/ui/views/autofill_popup_view.cc +++ b/shell/browser/ui/views/autofill_popup_view.cc @@ -23,6 +23,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/text_utils.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/border.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/widget/widget.h" @@ -40,8 +41,10 @@ AutofillPopupView::AutofillPopupView(AutofillPopup* popup, CreateChildViews(); SetFocusBehavior(FocusBehavior::ALWAYS); set_drag_controller(this); - SetAccessibleRole(ax::mojom::Role::kMenu); - SetAccessibleName(u"Autofill Menu"); + + auto& view_a11y = GetViewAccessibility(); + view_a11y.SetRole(ax::mojom::Role::kMenu); + view_a11y.SetName(u"Autofill Menu"); } AutofillPopupView::~AutofillPopupView() { diff --git a/shell/browser/ui/views/autofill_popup_view.h b/shell/browser/ui/views/autofill_popup_view.h index 315b42d1cfb5d..e217c013db1ad 100644 --- a/shell/browser/ui/views/autofill_popup_view.h +++ b/shell/browser/ui/views/autofill_popup_view.h @@ -14,6 +14,7 @@ #include "shell/browser/osr/osr_view_proxy.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/drag_controller.h" #include "ui/views/focus/native_view_focus_manager.h" #include "ui/views/widget/widget_delegate.h" @@ -43,8 +44,10 @@ class AutofillPopupChildView : public views::View { explicit AutofillPopupChildView(const std::u16string& suggestion) : suggestion_(suggestion) { SetFocusBehavior(FocusBehavior::ALWAYS); - SetAccessibleRole(ax::mojom::Role::kMenuItem); - SetAccessibleName(suggestion); + + auto& view_a11y = GetViewAccessibility(); + view_a11y.SetRole(ax::mojom::Role::kMenuItem); + view_a11y.SetName(suggestion); } // disable copy diff --git a/shell/browser/ui/views/client_frame_view_linux.cc b/shell/browser/ui/views/client_frame_view_linux.cc index 316752492b4fd..7886c91f19a75 100644 --- a/shell/browser/ui/views/client_frame_view_linux.cc +++ b/shell/browser/ui/views/client_frame_view_linux.cc @@ -28,6 +28,7 @@ #include "ui/linux/nav_button_provider.h" #include "ui/native_theme/native_theme.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/style/typography.h" #include "ui/views/widget/widget.h" @@ -40,7 +41,6 @@ namespace { // These values should be the same as Chromium uses. constexpr int kResizeBorder = 10; -constexpr int kResizeInsideBoundsSize = 5; ui::NavButtonProvider::ButtonState ButtonStateToNavButtonProviderState( views::Button::ButtonState state) { @@ -86,7 +86,7 @@ ClientFrameViewLinux::ClientFrameViewLinux() for (auto& button : nav_buttons_) { auto image_button = std::make_unique<views::ImageButton>(); image_button->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); - image_button->SetAccessibleName( + image_button->GetViewAccessibility().SetName( l10n_util::GetStringUTF16(button.accessibility_id)); button.button = AddChildView(std::move(image_button)); } @@ -151,8 +151,19 @@ gfx::Insets ClientFrameViewLinux::RestoredMirroredFrameBorderInsets() const { gfx::Insets ClientFrameViewLinux::RestoredFrameBorderInsets() const { gfx::Insets insets = GetFrameProvider()->GetFrameThicknessDip(); - insets.SetToMax(GetInputInsets()); - return insets; + const gfx::Insets input = GetInputInsets(); + + auto expand_if_visible = [](int side_thickness, int min_band) { + return side_thickness > 0 ? std::max(side_thickness, min_band) : 0; + }; + + gfx::Insets merged; + merged.set_top(expand_if_visible(insets.top(), input.top())); + merged.set_left(expand_if_visible(insets.left(), input.left())); + merged.set_bottom(expand_if_visible(insets.bottom(), input.bottom())); + merged.set_right(expand_if_visible(insets.right(), input.right())); + + return merged; } gfx::Insets ClientFrameViewLinux::GetInputInsets() const { @@ -197,9 +208,7 @@ void ClientFrameViewLinux::OnWindowButtonOrderingChange() { } int ClientFrameViewLinux::ResizingBorderHitTest(const gfx::Point& point) { - return ResizingBorderHitTestImpl(point, - RestoredMirroredFrameBorderInsets() + - gfx::Insets(kResizeInsideBoundsSize)); + return ResizingBorderHitTestImpl(point, RestoredMirroredFrameBorderInsets()); } gfx::Rect ClientFrameViewLinux::GetBoundsForClientView() const { @@ -495,7 +504,7 @@ gfx::Size ClientFrameViewLinux::SizeWithDecorations(gfx::Size size) const { views::View* ClientFrameViewLinux::TargetForRect(views::View* root, const gfx::Rect& rect) { - return views::NonClientFrameView::TargetForRect(root, rect); + return views::FrameView::TargetForRect(root, rect); } int ClientFrameViewLinux::GetTranslucentTopAreaHeight() const { diff --git a/shell/browser/ui/views/client_frame_view_linux.h b/shell/browser/ui/views/client_frame_view_linux.h index 0d8f4050b9500..54cbc9a1c35e7 100644 --- a/shell/browser/ui/views/client_frame_view_linux.h +++ b/shell/browser/ui/views/client_frame_view_linux.h @@ -64,7 +64,7 @@ class ClientFrameViewLinux : public FramelessView, // Overridden from FramelessView: int ResizingBorderHitTest(const gfx::Point& point) override; - // Overridden from views::NonClientFrameView: + // Overridden from views::FrameView: gfx::Rect GetBoundsForClientView() const override; gfx::Rect GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const override; diff --git a/shell/browser/ui/views/electron_views_delegate.cc b/shell/browser/ui/views/electron_views_delegate.cc index eff63f089db7b..9417844e8aff5 100644 --- a/shell/browser/ui/views/electron_views_delegate.cc +++ b/shell/browser/ui/views/electron_views_delegate.cc @@ -8,6 +8,7 @@ #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/native_widget_aura.h" +#include "ui/views/window/default_frame_view.h" #if BUILDFLAG(IS_LINUX) #include "base/environment.h" @@ -60,9 +61,9 @@ gfx::ImageSkia* ViewsDelegate::GetDefaultWindowIcon() const { } #endif -std::unique_ptr<views::NonClientFrameView> -ViewsDelegate::CreateDefaultNonClientFrameView(views::Widget* widget) { - return nullptr; +std::unique_ptr<views::FrameView> ViewsDelegate::CreateDefaultFrameView( + views::Widget* widget) { + return std::make_unique<views::DefaultFrameView>(widget); } void ViewsDelegate::OnBeforeWidgetInit( diff --git a/shell/browser/ui/views/electron_views_delegate.h b/shell/browser/ui/views/electron_views_delegate.h index 62298e240de52..2b97b0906fffd 100644 --- a/shell/browser/ui/views/electron_views_delegate.h +++ b/shell/browser/ui/views/electron_views_delegate.h @@ -47,7 +47,7 @@ class ViewsDelegate : public views::ViewsDelegate { #elif BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS) gfx::ImageSkia* GetDefaultWindowIcon() const override; #endif - std::unique_ptr<views::NonClientFrameView> CreateDefaultNonClientFrameView( + std::unique_ptr<views::FrameView> CreateDefaultFrameView( views::Widget* widget) override; void AddRef() override {} void ReleaseRef() override {} diff --git a/shell/browser/ui/views/frameless_view.cc b/shell/browser/ui/views/frameless_view.cc index dcfed5ef695f0..420a825f27577 100644 --- a/shell/browser/ui/views/frameless_view.cc +++ b/shell/browser/ui/views/frameless_view.cc @@ -96,7 +96,7 @@ views::View* FramelessView::TargetForRect(views::View* root, if (NonClientHitTest(rect.origin()) != HTCLIENT) return this; - return NonClientFrameView::TargetForRect(root, rect); + return FrameView::TargetForRect(root, rect); } gfx::Size FramelessView::CalculatePreferredSize( diff --git a/shell/browser/ui/views/frameless_view.h b/shell/browser/ui/views/frameless_view.h index bea0ba58482a8..e391cb9bd7c2f 100644 --- a/shell/browser/ui/views/frameless_view.h +++ b/shell/browser/ui/views/frameless_view.h @@ -17,8 +17,8 @@ namespace electron { class NativeWindowViews; -class FramelessView : public views::NonClientFrameView { - METADATA_HEADER(FramelessView, views::NonClientFrameView) +class FramelessView : public views::FrameView { + METADATA_HEADER(FramelessView, views::FrameView) public: FramelessView(); @@ -46,7 +46,7 @@ class FramelessView : public views::NonClientFrameView { int ResizingBorderHitTestImpl(const gfx::Point& point, const gfx::Insets& resize_border); - // views::NonClientFrameView: + // views::FrameView: gfx::Rect GetBoundsForClientView() const override; gfx::Rect GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const override; diff --git a/shell/browser/ui/views/global_menu_bar_x11.h b/shell/browser/ui/views/global_menu_bar_x11.h index 0851822fc3f16..e086273dd6fe7 100644 --- a/shell/browser/ui/views/global_menu_bar_x11.h +++ b/shell/browser/ui/views/global_menu_bar_x11.h @@ -10,7 +10,7 @@ #include "base/memory/raw_ptr.h" #include "shell/browser/ui/electron_menu_model.h" #include "ui/base/glib/scoped_gsignal.h" -#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/native_ui_types.h" #include "ui/gfx/x/xproto.h" typedef struct _DbusmenuMenuitem DbusmenuMenuitem; diff --git a/shell/browser/ui/views/menu_bar.cc b/shell/browser/ui/views/menu_bar.cc index bde828d8d72ff..0f09312b6bc7c 100644 --- a/shell/browser/ui/views/menu_bar.cc +++ b/shell/browser/ui/views/menu_bar.cc @@ -10,7 +10,7 @@ #include "shell/browser/ui/views/submenu_button.h" #include "ui/base/mojom/menu_source_type.mojom.h" #include "ui/color/color_provider.h" -#include "ui/native_theme/common_theme.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/background.h" #include "ui/views/layout/box_layout.h" @@ -19,7 +19,7 @@ #endif #if BUILDFLAG(IS_WIN) -#include "ui/gfx/color_utils.h" +#include "shell/common/color_util.h" #endif namespace electron { @@ -43,9 +43,11 @@ MenuBar::MenuBar(NativeWindow* window, RootView* root_view) SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal)); window_->AddObserver(this); - SetAccessibleName(std::u16string(), + + auto& view_a11y = GetViewAccessibility(); + view_a11y.SetName(std::u16string(), ax::mojom::NameFrom::kAttributeExplicitlyEmpty); - SetAccessibleRole(ax::mojom::Role::kMenuBar); + view_a11y.SetRole(ax::mojom::Role::kMenuBar); } MenuBar::~MenuBar() { @@ -261,7 +263,7 @@ void MenuBar::UpdateViewColors() { #elif BUILDFLAG(IS_WIN) for (views::View* child : GetChildrenInZOrder()) { auto* button = static_cast<SubmenuButton*>(child); - button->SetUnderlineColor(color_utils::GetSysSkColor(COLOR_MENUTEXT)); + button->SetUnderlineColor(GetSysSkColor(COLOR_MENUTEXT)); } #endif } diff --git a/shell/browser/ui/views/opaque_frame_view.cc b/shell/browser/ui/views/opaque_frame_view.cc index 43ce172504911..8bc02ca34eb41 100644 --- a/shell/browser/ui/views/opaque_frame_view.cc +++ b/shell/browser/ui/views/opaque_frame_view.cc @@ -17,6 +17,7 @@ #include "ui/compositor/layer.h" #include "ui/gfx/font_list.h" #include "ui/linux/linux_ui.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/background.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -160,7 +161,7 @@ int OpaqueFrameView::NonClientHitTest(const gfx::Point& point) { } void OpaqueFrameView::ResetWindowControls() { - NonClientFrameView::ResetWindowControls(); + FrameView::ResetWindowControls(); if (restore_button_) restore_button_->SetState(views::Button::STATE_NORMAL); @@ -173,7 +174,7 @@ void OpaqueFrameView::ResetWindowControls() { views::View* OpaqueFrameView::TargetForRect(views::View* root, const gfx::Rect& rect) { - return views::NonClientFrameView::TargetForRect(root, rect); + return views::FrameView::TargetForRect(root, rect); } void OpaqueFrameView::Layout(PassKey) { @@ -305,7 +306,8 @@ views::Button* OpaqueFrameView::CreateButton( button->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); button->SetCallback(std::move(callback)); - button->SetAccessibleName(l10n_util::GetStringUTF16(accessibility_string_id)); + button->GetViewAccessibility().SetName( + l10n_util::GetStringUTF16(accessibility_string_id)); button->SetID(view_id); button->SetPaintToLayer(); diff --git a/shell/browser/ui/views/opaque_frame_view.h b/shell/browser/ui/views/opaque_frame_view.h index dae79d03f4931..94da7e876613f 100644 --- a/shell/browser/ui/views/opaque_frame_view.h +++ b/shell/browser/ui/views/opaque_frame_view.h @@ -40,7 +40,7 @@ class OpaqueFrameView : public FramelessView { int ResizingBorderHitTest(const gfx::Point& point) override; void InvalidateCaptionButtons() override; - // views::NonClientFrameView: + // views::FrameView: gfx::Rect GetBoundsForClientView() const override; gfx::Rect GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const override; diff --git a/shell/browser/ui/views/submenu_button.cc b/shell/browser/ui/views/submenu_button.cc index a07f2c2b0be7e..fdcdd3b1c8a88 100644 --- a/shell/browser/ui/views/submenu_button.cc +++ b/shell/browser/ui/views/submenu_button.cc @@ -9,6 +9,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/text_utils.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_host.h" @@ -26,7 +27,7 @@ SubmenuButton::SubmenuButton(PressedCallback callback, // Don't use native style border. SetBorder(CreateDefaultBorder()); #endif - SetAccessibleRole(ax::mojom::Role::kPopUpButton); + GetViewAccessibility().SetRole(ax::mojom::Role::kPopUpButton); if (GetUnderlinePosition(title, &accelerator_, &underline_start_, &underline_end_)) gfx::Canvas::SizeStringInt(GetText(), gfx::FontList(), &text_width_, diff --git a/shell/browser/ui/views/win_caption_button.cc b/shell/browser/ui/views/win_caption_button.cc index 63b69f42e7b77..c966eb7422a9e 100644 --- a/shell/browser/ui/views/win_caption_button.cc +++ b/shell/browser/ui/views/win_caption_button.cc @@ -11,6 +11,7 @@ #include "base/i18n/rtl.h" #include "base/numerics/safe_conversions.h" #include "base/win/windows_version.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/grit/theme_resources.h" #include "shell/browser/native_window_views.h" #include "shell/browser/ui/views/win_frame_view.h" @@ -21,6 +22,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/scoped_canvas.h" +#include "ui/views/accessibility/view_accessibility.h" namespace electron { @@ -35,7 +37,7 @@ WinCaptionButton::WinCaptionButton(PressedCallback callback, SetAnimateOnStateChange(true); // Not focusable by default, only for accessibility. SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); - SetAccessibleName(accessible_name); + GetViewAccessibility().SetName(accessible_name); } WinCaptionButton::~WinCaptionButton() = default; @@ -47,6 +49,13 @@ std::unique_ptr<WinIconPainter> WinCaptionButton::CreateIconPainter() { return std::make_unique<WinIconPainter>(); } +SkColor WinCaptionButton::GetBaseForegroundColor() const { + return GetColorProvider()->GetColor( + frame_view_->GetShouldPaintAsActive() + ? kColorCaptionButtonForegroundActive + : kColorCaptionButtonForegroundInactive); +} + gfx::Size WinCaptionButton::CalculatePreferredSize( const views::SizeBounds& available_size) const { // TODO(bsep): The sizes in this function are for 1x device scale and don't @@ -76,7 +85,7 @@ void WinCaptionButton::OnPaintBackground(gfx::Canvas* canvas) { pressed_alpha = 0x98; } else { // Match the native buttons. - base_color = frame_view_->GetReadableFeatureColor(bg_color); + base_color = GetBaseForegroundColor(); hovered_alpha = 0x1A; pressed_alpha = 0x33; diff --git a/shell/browser/ui/views/win_caption_button.h b/shell/browser/ui/views/win_caption_button.h index ff96851c842a1..4534f8710736d 100644 --- a/shell/browser/ui/views/win_caption_button.h +++ b/shell/browser/ui/views/win_caption_button.h @@ -49,6 +49,10 @@ class WinCaptionButton : public views::Button { private: std::unique_ptr<WinIconPainter> CreateIconPainter(); + + // The base color to use for the button symbols and background blending. Uses + // the more readable of black and white. + SkColor GetBaseForegroundColor() const; // Returns the amount we should visually reserve on the left (right in RTL) // for spacing between buttons. We do this instead of repositioning the // buttons to avoid the sliver of deadspace that would result. @@ -59,10 +63,6 @@ class WinCaptionButton : public views::Button { // smaller indices). int GetButtonDisplayOrderIndex() const; - // The base color to use for the button symbols and background blending. Uses - // the more readable of black and white. - SkColor GetBaseColor() const; - // Paints the minimize/maximize/restore/close icon for the button. void PaintSymbol(gfx::Canvas* canvas); diff --git a/shell/browser/ui/views/win_frame_view.cc b/shell/browser/ui/views/win_frame_view.cc index 88a18703a00a9..697243c4adde4 100644 --- a/shell/browser/ui/views/win_frame_view.cc +++ b/shell/browser/ui/views/win_frame_view.cc @@ -39,18 +39,6 @@ void WinFrameView::Init(NativeWindowViews* window, views::Widget* frame) { } } -SkColor WinFrameView::GetReadableFeatureColor(SkColor background_color) { - // color_utils::GetColorWithMaxContrast()/IsDark() aren't used here because - // they switch based on the Chrome light/dark endpoints, while we want to use - // the system native behavior below. - const auto windows_luma = [](SkColor c) { - return 0.25f * SkColorGetR(c) + 0.625f * SkColorGetG(c) + - 0.125f * SkColorGetB(c); - }; - return windows_luma(background_color) <= 128.0f ? SK_ColorWHITE - : SK_ColorBLACK; -} - void WinFrameView::InvalidateCaptionButtons() { if (!caption_button_container_) return; @@ -89,7 +77,7 @@ views::View* WinFrameView::TargetForRect(views::View* root, return this; } - return NonClientFrameView::TargetForRect(root, rect); + return FrameView::TargetForRect(root, rect); } int WinFrameView::NonClientHitTest(const gfx::Point& point) { @@ -170,7 +158,7 @@ void WinFrameView::Layout(PassKey) { if (window()->IsWindowControlsOverlayEnabled()) { LayoutWindowControlsOverlay(); } - LayoutSuperclass<NonClientFrameView>(this); + LayoutSuperclass<FrameView>(this); } int WinFrameView::FrameTopBorderThickness(bool restored) const { @@ -282,6 +270,10 @@ void WinFrameView::LayoutWindowControlsOverlay() { window()->NotifyLayoutWindowControlsOverlay(); } +bool WinFrameView::GetShouldPaintAsActive() { + return ShouldPaintAsActive(); +} + BEGIN_METADATA(WinFrameView) END_METADATA diff --git a/shell/browser/ui/views/win_frame_view.h b/shell/browser/ui/views/win_frame_view.h index 203b4055bddf9..c47550aef09e0 100644 --- a/shell/browser/ui/views/win_frame_view.h +++ b/shell/browser/ui/views/win_frame_view.h @@ -31,7 +31,7 @@ class WinFrameView : public FramelessView { SkColor GetReadableFeatureColor(SkColor background_color); - // views::NonClientFrameView: + // views::FrameView: gfx::Rect GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const override; int NonClientHitTest(const gfx::Point& point) override; @@ -46,6 +46,9 @@ class WinFrameView : public FramelessView { // the area above the top of the screen). int TitlebarMaximizedVisualHeight() const; + // Returns true if the frame should be painted as active. + bool GetShouldPaintAsActive(); + protected: // views::View: void Layout(PassKey) override; diff --git a/shell/browser/ui/views/win_icon_painter.cc b/shell/browser/ui/views/win_icon_painter.cc index 798e02d04b41a..7f102f75eda9d 100644 --- a/shell/browser/ui/views/win_icon_painter.cc +++ b/shell/browser/ui/views/win_icon_painter.cc @@ -7,6 +7,7 @@ #include "base/numerics/safe_conversions.h" #include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPathBuilder.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rrect_f.h" @@ -75,11 +76,12 @@ void WinIconPainter::PaintCloseIcon(gfx::Canvas* canvas, paint_flags.setAntiAlias(true); canvas->ClipRect(symbol_rect); - SkPath path; - path.moveTo(symbol_rect.x(), symbol_rect.y()); - path.lineTo(symbol_rect.right(), symbol_rect.bottom()); - path.moveTo(symbol_rect.right(), symbol_rect.y()); - path.lineTo(symbol_rect.x(), symbol_rect.bottom()); + const SkPath path = SkPathBuilder() + .moveTo(symbol_rect.x(), symbol_rect.y()) + .lineTo(symbol_rect.right(), symbol_rect.bottom()) + .moveTo(symbol_rect.right(), symbol_rect.y()) + .lineTo(symbol_rect.x(), symbol_rect.bottom()) + .detach(); canvas->DrawPath(path, flags); } diff --git a/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc b/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc index 40a3d6b66d23a..42039cd92f4d5 100644 --- a/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc +++ b/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc @@ -142,6 +142,7 @@ bool ElectronDesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) { if (prevent_default) { electron::api::WebContents::SetDisableDraggableRegions(true); views::DesktopWindowTreeHostWin::HandleMouseEvent(event); + electron::api::WebContents::SetDisableDraggableRegions(false); } return prevent_default; } diff --git a/shell/browser/ui/win/notify_icon.cc b/shell/browser/ui/win/notify_icon.cc index c4c9e66563ad5..2412417b6c92a 100644 --- a/shell/browser/ui/win/notify_icon.cc +++ b/shell/browser/ui/win/notify_icon.cc @@ -77,8 +77,7 @@ void NotifyIcon::HandleClickEvent(int modifiers, if (double_button_click) // double left click NotifyDoubleClicked(bounds, modifiers); else // single left click - NotifyClicked(bounds, - display::Screen::GetScreen()->GetCursorScreenPoint(), + NotifyClicked(bounds, display::Screen::Get()->GetCursorScreenPoint(), modifiers); return; } else if (middle_button_click) { // single middle click @@ -92,19 +91,19 @@ void NotifyIcon::HandleClickEvent(int modifiers, } void NotifyIcon::HandleMouseMoveEvent(int modifiers) { - gfx::Point cursorPos = display::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point cursorPos = display::Screen::Get()->GetCursorScreenPoint(); // Omit event fired when tray icon is created but cursor is outside of it. if (GetBounds().Contains(cursorPos)) NotifyMouseMoved(cursorPos, modifiers); } void NotifyIcon::HandleMouseEntered(int modifiers) { - gfx::Point cursor_pos = display::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point cursor_pos = display::Screen::Get()->GetCursorScreenPoint(); NotifyMouseEntered(cursor_pos, modifiers); } void NotifyIcon::HandleMouseExited(int modifiers) { - gfx::Point cursor_pos = display::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point cursor_pos = display::Screen::Get()->GetCursorScreenPoint(); NotifyMouseExited(cursor_pos, modifiers); } @@ -225,7 +224,7 @@ void NotifyIcon::PopUpContextMenu(const gfx::Point& pos, // Show menu at mouse's position by default. gfx::Rect rect(pos, gfx::Size()); if (pos.IsOrigin()) - rect.set_origin(display::Screen::GetScreen()->GetCursorScreenPoint()); + rect.set_origin(display::Screen::Get()->GetCursorScreenPoint()); if (menu_model) { menu_runner_ = std::make_unique<views::MenuRunner>( diff --git a/shell/browser/ui/win/notify_icon_host.cc b/shell/browser/ui/win/notify_icon_host.cc index 2895175e72925..c59d9f6b93713 100644 --- a/shell/browser/ui/win/notify_icon_host.cc +++ b/shell/browser/ui/win/notify_icon_host.cc @@ -120,8 +120,7 @@ class NotifyIconHost::MouseEnteredExitedDetector { } bool IsCursorOverIcon(raw_ptr<NotifyIcon> icon) { - gfx::Point cursor_pos = - display::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point cursor_pos = display::Screen::Get()->GetCursorScreenPoint(); return icon->GetBounds().Contains(cursor_pos); } diff --git a/shell/browser/ui/win/taskbar_host.cc b/shell/browser/ui/win/taskbar_host.cc index b0094736e670f..36b8fa8789852 100644 --- a/shell/browser/ui/win/taskbar_host.cc +++ b/shell/browser/ui/win/taskbar_host.cc @@ -18,7 +18,7 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkRRect.h" #include "ui/display/win/screen_win.h" -#include "ui/gfx/icon_util.h" +#include "ui/gfx/win/icon_util.h" namespace electron { diff --git a/shell/browser/ui/x/x_window_utils.cc b/shell/browser/ui/x/x_window_utils.cc index fd0c5ec3aa305..bc69f5fedb8e8 100644 --- a/shell/browser/ui/x/x_window_utils.cc +++ b/shell/browser/ui/x/x_window_utils.cc @@ -34,8 +34,7 @@ bool ShouldUseGlobalMenuBar() { if (env->HasVar("ELECTRON_FORCE_WINDOW_MENU_BAR")) return false; - dbus::Bus::Options options; - auto bus = base::MakeRefCounted<dbus::Bus>(options); + auto bus = base::MakeRefCounted<dbus::Bus>(dbus::Bus::Options{}); dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)); diff --git a/shell/browser/usb/electron_usb_delegate.cc b/shell/browser/usb/electron_usb_delegate.cc index 446b68fb4bfc2..916112e16d05d 100644 --- a/shell/browser/usb/electron_usb_delegate.cc +++ b/shell/browser/usb/electron_usb_delegate.cc @@ -9,6 +9,7 @@ #include "base/observer_list.h" #include "base/scoped_observation.h" +#include "content/public/browser/page.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "electron/buildflags/buildflags.h" diff --git a/shell/browser/web_contents_permission_helper.cc b/shell/browser/web_contents_permission_helper.cc index fcffbac319a40..dbe7253802ac8 100644 --- a/shell/browser/web_contents_permission_helper.cc +++ b/shell/browser/web_contents_permission_helper.cc @@ -195,8 +195,8 @@ void MediaAccessAllowed(const content::MediaStreamRequest& request, } void OnPermissionResponse(base::OnceCallback<void(bool)> callback, - blink::mojom::PermissionStatus status) { - if (status == blink::mojom::PermissionStatus::GRANTED) + content::PermissionResult result) { + if (result.status == blink::mojom::PermissionStatus::GRANTED) std::move(callback).Run(true); else std::move(callback).Run(false); diff --git a/shell/browser/web_contents_zoom_controller.cc b/shell/browser/web_contents_zoom_controller.cc index b4c237d68f7ac..41bf6d4db7e0c 100644 --- a/shell/browser/web_contents_zoom_controller.cc +++ b/shell/browser/web_contents_zoom_controller.cc @@ -179,7 +179,7 @@ void WebContentsZoomController::SetZoomMode(ZoomMode new_mode) { if (!url.is_empty()) { const std::string host = net::GetHostOrSpecFromURL(url); - const std::string scheme = url.scheme(); + const std::string scheme = url.GetScheme(); if (zoom_map->HasZoomLevel(scheme, host)) { // If there are other tabs with the same origin, then set this tab's @@ -257,7 +257,7 @@ void WebContentsZoomController::ResetZoomModeOnNavigationIfNeeded( zoom_level_ = zoom_map->GetDefaultZoomLevel(); double old_zoom_level = zoom_map->GetZoomLevel(web_contents()); double new_zoom_level = zoom_map->GetZoomLevelForHostAndScheme( - url.scheme(), net::GetHostOrSpecFromURL(url)); + url.GetScheme(), net::GetHostOrSpecFromURL(url)); event_data_ = std::make_unique<ZoomChangedEventData>( web_contents(), old_zoom_level, new_zoom_level, false, ZOOM_MODE_DEFAULT); @@ -346,7 +346,7 @@ void WebContentsZoomController::SetZoomFactorOnNavigationIfNeeded( // then it takes precedence. // pref store < kZoomFactor < setZoomLevel std::string host = net::GetHostOrSpecFromURL(url); - std::string scheme = url.scheme(); + std::string scheme = url.GetScheme(); double zoom_factor = default_zoom_factor(); double zoom_level = blink::ZoomFactorToZoomLevel(zoom_factor); if (host_zoom_map_->HasZoomLevel(scheme, host)) { diff --git a/shell/browser/web_contents_zoom_controller.h b/shell/browser/web_contents_zoom_controller.h index 94b7f7c67c8f8..40686061019bf 100644 --- a/shell/browser/web_contents_zoom_controller.h +++ b/shell/browser/web_contents_zoom_controller.h @@ -5,6 +5,7 @@ #ifndef ELECTRON_SHELL_BROWSER_WEB_CONTENTS_ZOOM_CONTROLLER_H_ #define ELECTRON_SHELL_BROWSER_WEB_CONTENTS_ZOOM_CONTROLLER_H_ +#include "base/callback_list.h" #include "base/memory/raw_ptr.h" #include "base/observer_list.h" #include "content/public/browser/host_zoom_map.h" diff --git a/shell/browser/win/dark_mode.cc b/shell/browser/win/dark_mode.cc index 444b832771d35..e78398d1d14b3 100644 --- a/shell/browser/win/dark_mode.cc +++ b/shell/browser/win/dark_mode.cc @@ -42,9 +42,11 @@ bool IsDarkModeSupported() { void SetDarkModeForWindow(HWND hWnd) { ui::NativeTheme* theme = ui::NativeTheme::GetInstanceForNativeUi(); - bool dark = - theme->ShouldUseDarkColors() && !theme->UserHasContrastPreference(); - + bool has_contrast_preference = + theme->preferred_contrast() == ui::NativeTheme::PreferredContrast::kMore; + bool prefers_dark = theme->preferred_color_scheme() == + ui::NativeTheme::PreferredColorScheme::kDark; + bool dark = prefers_dark && !has_contrast_preference; TrySetWindowTheme(hWnd, dark); } diff --git a/shell/browser/zoom_level_delegate.cc b/shell/browser/zoom_level_delegate.cc index d1e3a764922c3..c79435b22cee2 100644 --- a/shell/browser/zoom_level_delegate.cc +++ b/shell/browser/zoom_level_delegate.cc @@ -7,6 +7,7 @@ #include <utility> #include <vector> +#include "base/callback_list.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/strings/string_number_conversions.h" diff --git a/shell/browser/zoom_level_delegate.h b/shell/browser/zoom_level_delegate.h index 56146f78b2385..c241206bef96f 100644 --- a/shell/browser/zoom_level_delegate.h +++ b/shell/browser/zoom_level_delegate.h @@ -7,6 +7,7 @@ #include <string> +#include "base/callback_list.h" #include "base/memory/raw_ptr.h" #include "base/values.h" #include "content/public/browser/host_zoom_map.h" diff --git a/shell/common/api/electron_api_asar.cc b/shell/common/api/electron_api_asar.cc index 2e872759d0dcd..93229863e2b36 100644 --- a/shell/common/api/electron_api_asar.cc +++ b/shell/common/api/electron_api_asar.cc @@ -191,13 +191,15 @@ class Archive : public node::ObjectWrap { static void SplitPath(const v8::FunctionCallbackInfo<v8::Value>& args) { auto* isolate = args.GetIsolate(); + auto dict = gin_helper::Dictionary::CreateEmpty(isolate); + args.GetReturnValue().Set(dict.GetHandle()); + base::FilePath path; if (!gin::ConvertFromV8(isolate, args[0], &path)) { - args.GetReturnValue().Set(v8::False(isolate)); + dict.Set("isAsar", false); return; } - auto dict = gin_helper::Dictionary::CreateEmpty(isolate); base::FilePath asar_path, file_path; if (asar::GetAsarArchivePath(path, &asar_path, &file_path, true)) { dict.Set("isAsar", true); @@ -206,7 +208,6 @@ static void SplitPath(const v8::FunctionCallbackInfo<v8::Value>& args) { } else { dict.Set("isAsar", false); } - args.GetReturnValue().Set(dict.GetHandle()); } void Initialize(v8::Local<v8::Object> exports, diff --git a/shell/common/api/electron_api_clipboard.cc b/shell/common/api/electron_api_clipboard.cc index 17563f1e1d704..2f810d4250aeb 100644 --- a/shell/common/api/electron_api_clipboard.cc +++ b/shell/common/api/electron_api_clipboard.cc @@ -22,18 +22,21 @@ #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image.h" -namespace electron::api { +namespace { -ui::ClipboardBuffer Clipboard::GetClipboardBuffer(gin_helper::Arguments* args) { +[[nodiscard]] ui::ClipboardBuffer GetClipboardBuffer(gin::Arguments* args) { std::string type; - if (args->GetNext(&type) && type == "selection") - return ui::ClipboardBuffer::kSelection; - else - return ui::ClipboardBuffer::kCopyPaste; + return args->GetNext(&type) && type == "selection" + ? ui::ClipboardBuffer::kSelection + : ui::ClipboardBuffer::kCopyPaste; } +} // namespace + +namespace electron::api { + std::vector<std::u16string> Clipboard::AvailableFormats( - gin_helper::Arguments* args) { + gin::Arguments* const args) { std::vector<std::u16string> format_types; ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); clipboard->ReadAvailableTypes(GetClipboardBuffer(args), @@ -42,7 +45,7 @@ std::vector<std::u16string> Clipboard::AvailableFormats( } bool Clipboard::Has(const std::string& format_string, - gin_helper::Arguments* args) { + gin::Arguments* const args) { ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::ClipboardFormatType format = ui::ClipboardFormatType::CustomPlatformType(format_string); @@ -97,17 +100,17 @@ std::string Clipboard::Read(const std::string& format_string) { return data; } -v8::Local<v8::Value> Clipboard::ReadBuffer(const std::string& format_string, - gin_helper::Arguments* args) { +v8::Local<v8::Value> Clipboard::ReadBuffer(v8::Isolate* const isolate, + const std::string& format_string) { std::string data = Read(format_string); - return electron::Buffer::Copy(args->isolate(), data).ToLocalChecked(); + return electron::Buffer::Copy(isolate, data).ToLocalChecked(); } void Clipboard::WriteBuffer(const std::string& format, const v8::Local<v8::Value> buffer, - gin_helper::Arguments* args) { + gin::Arguments* const args) { if (!node::Buffer::HasInstance(buffer)) { - args->ThrowError("buffer must be a node Buffer"); + args->ThrowTypeError("buffer must be a node Buffer"); return; } @@ -124,7 +127,7 @@ void Clipboard::WriteBuffer(const std::string& format, } void Clipboard::Write(const gin_helper::Dictionary& data, - gin_helper::Arguments* args) { + gin::Arguments* const args) { ui::ScopedClipboardWriter writer(GetClipboardBuffer(args)); std::u16string text, html, bookmark; gfx::Image image; @@ -148,7 +151,7 @@ void Clipboard::Write(const gin_helper::Dictionary& data, writer.WriteImage(image.AsBitmap()); } -std::u16string Clipboard::ReadText(gin_helper::Arguments* args) { +std::u16string Clipboard::ReadText(gin::Arguments* const args) { std::u16string data; ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); auto type = GetClipboardBuffer(args); @@ -170,24 +173,24 @@ std::u16string Clipboard::ReadText(gin_helper::Arguments* args) { } void Clipboard::WriteText(const std::u16string& text, - gin_helper::Arguments* args) { + gin::Arguments* const args) { ui::ScopedClipboardWriter writer(GetClipboardBuffer(args)); writer.WriteText(text); } -std::u16string Clipboard::ReadRTF(gin_helper::Arguments* args) { +std::u16string Clipboard::ReadRTF(gin::Arguments* const args) { std::string data; ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); clipboard->ReadRTF(GetClipboardBuffer(args), /* data_dst = */ nullptr, &data); return base::UTF8ToUTF16(data); } -void Clipboard::WriteRTF(const std::string& text, gin_helper::Arguments* args) { +void Clipboard::WriteRTF(const std::string& text, gin::Arguments* const args) { ui::ScopedClipboardWriter writer(GetClipboardBuffer(args)); writer.WriteRTF(text); } -std::u16string Clipboard::ReadHTML(gin_helper::Arguments* args) { +std::u16string Clipboard::ReadHTML(gin::Arguments* const args) { std::u16string data; std::u16string html; std::string url; @@ -201,15 +204,15 @@ std::u16string Clipboard::ReadHTML(gin_helper::Arguments* args) { } void Clipboard::WriteHTML(const std::u16string& html, - gin_helper::Arguments* args) { + gin::Arguments* const args) { ui::ScopedClipboardWriter writer(GetClipboardBuffer(args)); writer.WriteHTML(html, std::string()); } -v8::Local<v8::Value> Clipboard::ReadBookmark(gin_helper::Arguments* args) { +v8::Local<v8::Value> Clipboard::ReadBookmark(v8::Isolate* const isolate) { std::u16string title; std::string url; - auto dict = gin_helper::Dictionary::CreateEmpty(args->isolate()); + auto dict = gin_helper::Dictionary::CreateEmpty(isolate); ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); clipboard->ReadBookmark(/* data_dst = */ nullptr, &title, &url); dict.Set("title", title); @@ -219,15 +222,15 @@ v8::Local<v8::Value> Clipboard::ReadBookmark(gin_helper::Arguments* args) { void Clipboard::WriteBookmark(const std::u16string& title, const std::string& url, - gin_helper::Arguments* args) { + gin::Arguments* const args) { ui::ScopedClipboardWriter writer(GetClipboardBuffer(args)); writer.WriteBookmark(title, url); } -gfx::Image Clipboard::ReadImage(gin_helper::Arguments* args) { +gfx::Image Clipboard::ReadImage(gin::Arguments* const args) { // The ReadPng uses thread pool which requires app ready. if (IsBrowserProcess() && !Browser::Get()->is_ready()) { - args->ThrowError( + gin_helper::ErrorThrower{args->isolate()}.ThrowError( "clipboard.readImage is available only after app ready in the main " "process"); return {}; @@ -256,7 +259,7 @@ gfx::Image Clipboard::ReadImage(gin_helper::Arguments* args) { } void Clipboard::WriteImage(const gfx::Image& image, - gin_helper::Arguments* args) { + gin::Arguments* const args) { ui::ScopedClipboardWriter writer(GetClipboardBuffer(args)); SkBitmap orig = image.AsBitmap(); SkBitmap bmp; @@ -274,7 +277,7 @@ std::u16string Clipboard::ReadFindText() { } #endif -void Clipboard::Clear(gin_helper::Arguments* args) { +void Clipboard::Clear(gin::Arguments* const args) { ui::Clipboard::GetForCurrentThread()->Clear(GetClipboardBuffer(args)); } diff --git a/shell/common/api/electron_api_clipboard.h b/shell/common/api/electron_api_clipboard.h index 74713c9a7baa8..d3c9c5a5ad032 100644 --- a/shell/common/api/electron_api_clipboard.h +++ b/shell/common/api/electron_api_clipboard.h @@ -16,8 +16,11 @@ namespace gfx { class Image; } // namespace gfx -namespace gin_helper { +namespace gin { class Arguments; +} // namespace gin + +namespace gin_helper { class Dictionary; } // namespace gin_helper @@ -29,44 +32,38 @@ class Clipboard { Clipboard(const Clipboard&) = delete; Clipboard& operator=(const Clipboard&) = delete; - static ui::ClipboardBuffer GetClipboardBuffer(gin_helper::Arguments* args); - static std::vector<std::u16string> AvailableFormats( - gin_helper::Arguments* args); - static bool Has(const std::string& format_string, - gin_helper::Arguments* args); - static void Clear(gin_helper::Arguments* args); + static std::vector<std::u16string> AvailableFormats(gin::Arguments* args); + static bool Has(const std::string& format_string, gin::Arguments* args); + static void Clear(gin::Arguments* args); static std::string Read(const std::string& format_string); - static void Write(const gin_helper::Dictionary& data, - gin_helper::Arguments* args); + static void Write(const gin_helper::Dictionary& data, gin::Arguments* args); - static std::u16string ReadText(gin_helper::Arguments* args); - static void WriteText(const std::u16string& text, - gin_helper::Arguments* args); + static std::u16string ReadText(gin::Arguments* args); + static void WriteText(const std::u16string& text, gin::Arguments* args); - static std::u16string ReadRTF(gin_helper::Arguments* args); - static void WriteRTF(const std::string& text, gin_helper::Arguments* args); + static std::u16string ReadRTF(gin::Arguments* args); + static void WriteRTF(const std::string& text, gin::Arguments* args); - static std::u16string ReadHTML(gin_helper::Arguments* args); - static void WriteHTML(const std::u16string& html, - gin_helper::Arguments* args); + static std::u16string ReadHTML(gin::Arguments* args); + static void WriteHTML(const std::u16string& html, gin::Arguments* args); - static v8::Local<v8::Value> ReadBookmark(gin_helper::Arguments* args); + static v8::Local<v8::Value> ReadBookmark(v8::Isolate* isolate); static void WriteBookmark(const std::u16string& title, const std::string& url, - gin_helper::Arguments* args); + gin::Arguments* args); - static gfx::Image ReadImage(gin_helper::Arguments* args); - static void WriteImage(const gfx::Image& image, gin_helper::Arguments* args); + static gfx::Image ReadImage(gin::Arguments* args); + static void WriteImage(const gfx::Image& image, gin::Arguments* args); static std::u16string ReadFindText(); static void WriteFindText(const std::u16string& text); - static v8::Local<v8::Value> ReadBuffer(const std::string& format_string, - gin_helper::Arguments* args); + static v8::Local<v8::Value> ReadBuffer(v8::Isolate* isolate, + const std::string& format_string); static void WriteBuffer(const std::string& format_string, const v8::Local<v8::Value> buffer, - gin_helper::Arguments* args); + gin::Arguments* args); static void WriteFilesForTesting(const std::vector<base::FilePath>& files); }; diff --git a/shell/common/api/electron_api_command_line.cc b/shell/common/api/electron_api_command_line.cc index 5225a43ec6361..98bbf6035118c 100644 --- a/shell/common/api/electron_api_command_line.cc +++ b/shell/common/api/electron_api_command_line.cc @@ -29,7 +29,7 @@ base::CommandLine::StringType GetSwitchValue(gin_helper::ErrorThrower thrower, } void AppendSwitch(const std::string& switch_string, - gin_helper::Arguments* args) { + gin::Arguments* const args) { auto switch_str = base::ToLowerASCII(switch_string); auto* command_line = base::CommandLine::ForCurrentProcess(); if (base::EndsWith(switch_string, "-path", diff --git a/shell/common/api/electron_api_native_image.cc b/shell/common/api/electron_api_native_image.cc index ced163c16abfc..14ab473c7c077 100644 --- a/shell/common/api/electron_api_native_image.cc +++ b/shell/common/api/electron_api_native_image.cc @@ -51,7 +51,7 @@ #if BUILDFLAG(IS_WIN) #include "base/win/scoped_gdi_object.h" #include "shell/common/asar/archive.h" -#include "ui/gfx/icon_util.h" +#include "ui/gfx/win/icon_util.h" #endif namespace electron::api { diff --git a/shell/common/api/electron_api_native_image_mac.mm b/shell/common/api/electron_api_native_image_mac.mm index f25a4e0b640dc..2075fdcdd6854 100644 --- a/shell/common/api/electron_api_native_image_mac.mm +++ b/shell/common/api/electron_api_native_image_mac.mm @@ -120,9 +120,18 @@ void ReceivedThumbnailResult(CGSize size, name.erase(pos, to_remove.length()); } - NSImage* image = [NSImage imageNamed:base::SysUTF8ToNSString(name)]; + NSImage* image = nil; + NSString* ns_name = base::SysUTF8ToNSString(name); + + // Treat non-Cocoa-prefixed names as SF Symbols first. + if (!base::StartsWith(name, "NS") && !base::StartsWith(name, "NX")) { + image = [NSImage imageWithSystemSymbolName:ns_name + accessibilityDescription:nil]; + } else { + image = [NSImage imageNamed:ns_name]; + } - if (!image.valid) { + if (!image || !image.valid) { return CreateEmpty(args->isolate()); } diff --git a/shell/common/api/electron_api_native_image_win.cc b/shell/common/api/electron_api_native_image_win.cc index 53f1fe7137433..d66f4209c64a0 100644 --- a/shell/common/api/electron_api_native_image_win.cc +++ b/shell/common/api/electron_api_native_image_win.cc @@ -14,8 +14,8 @@ #include "shell/common/gin_helper/promise.h" #include "shell/common/skia_util.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/icon_util.h" #include "ui/gfx/image/image_skia.h" +#include "ui/gfx/win/icon_util.h" namespace electron::api { diff --git a/shell/common/api/electron_api_shared_texture.cc b/shell/common/api/electron_api_shared_texture.cc new file mode 100644 index 0000000000000..f8b825bb10aab --- /dev/null +++ b/shell/common/api/electron_api_shared_texture.cc @@ -0,0 +1,810 @@ +// Copyright (c) 2025 Reito <reito@chromium.org> +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/common/api/electron_api_shared_texture.h" + +#include "base/base64.h" +#include "base/command_line.h" +#include "base/numerics/byte_conversions.h" +#include "components/viz/common/resources/shared_image_format_utils.h" +#include "content/browser/compositor/image_transport_factory.h" // nogncheck +#include "gpu/command_buffer/client/context_support.h" +#include "gpu/ipc/client/client_shared_image_interface.h" +#include "gpu/ipc/client/gpu_channel_host.h" +#include "gpu/ipc/common/exported_shared_image.mojom-shared.h" +#include "gpu/ipc/common/exported_shared_image_mojom_traits.h" +#include "media/base/format_utils.h" +#include "media/base/video_frame.h" +#include "media/mojo/mojom/video_frame_mojom_traits.h" +#include "shell/common/gin_converters/blink_converter.h" +#include "shell/common/gin_converters/callback_converter.h" +#include "shell/common/gin_converters/gfx_converter.h" +#include "shell/common/gin_helper/dictionary.h" +#include "shell/common/gin_helper/error_thrower.h" +#include "shell/common/node_includes.h" +#include "shell/common/node_util.h" +#include "third_party/blink/renderer/modules/webcodecs/video_frame.h" // nogncheck +#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" // nogncheck +#include "ui/compositor/compositor.h" + +#if BUILDFLAG(IS_LINUX) +#include "base/posix/eintr_wrapper.h" +#include "base/strings/string_number_conversions.h" +#endif + +namespace { + +bool IsBrowserProcess() { + static int is_browser_process = -1; + if (is_browser_process == -1) { + // Browser process does not specify a type. + is_browser_process = base::CommandLine::ForCurrentProcess() + ->GetSwitchValueASCII("type") + .empty(); + } + + return is_browser_process == 1; +} + +gpu::ContextSupport* GetContextSupport() { + if (IsBrowserProcess()) { + auto* factory = content::ImageTransportFactory::GetInstance(); + return factory->GetContextFactory() + ->SharedMainThreadRasterContextProvider() + ->ContextSupport(); + } else { + return blink::SharedGpuContext::ContextProviderWrapper() + ->ContextProvider() + .ContextSupport(); + } +} + +gpu::SharedImageInterface* GetSharedImageInterface() { + if (IsBrowserProcess()) { + auto* factory = content::ImageTransportFactory::GetInstance(); + return factory->GetContextFactory() + ->SharedMainThreadRasterContextProvider() + ->SharedImageInterface(); + } else { + return blink::SharedGpuContext::SharedImageInterfaceProvider() + ->SharedImageInterface(); + } +} + +std::string GetBase64StringFromSyncToken(gpu::SyncToken& sync_token) { + if (!sync_token.verified_flush()) { + auto* sii = GetSharedImageInterface(); + sii->VerifySyncToken(sync_token); + } + + auto sync_token_data = base::Base64Encode(UNSAFE_BUFFERS( + base::span(reinterpret_cast<uint8_t*>(sync_token.GetData()), + sizeof(gpu::SyncToken)))); + + return sync_token_data; +} + +gpu::SyncToken GetSyncTokenFromBase64String( + const std::string& sync_token_data) { + if (sync_token_data.empty()) { + LOG(ERROR) << "Sync token data is empty."; + return {}; + } + + auto sync_token_bytes = base::Base64Decode(sync_token_data); + if (!sync_token_bytes.has_value()) { + LOG(ERROR) << "Failed to decode sync token from base64 string."; + return {}; + } + + if (sync_token_bytes->size() != sizeof(gpu::SyncToken)) { + LOG(ERROR) << "Invalid sync token size: " << sync_token_bytes->size(); + return {}; + } + + base::span<const uint8_t> sync_token_span = UNSAFE_BUFFERS( + base::span(sync_token_bytes->data(), sync_token_bytes->size())); + auto* sync_token_source = + reinterpret_cast<const gpu::SyncToken*>(sync_token_span.data()); + gpu::SyncToken sync_token(sync_token_source->namespace_id(), + sync_token_source->command_buffer_id(), + sync_token_source->release_count()); + + if (sync_token_source->verified_flush()) { + sync_token.SetVerifyFlush(); + } + + return sync_token; +} + +std::string TransferVideoPixelFormatToString(media::VideoPixelFormat format) { + switch (format) { + case media::PIXEL_FORMAT_ARGB: + return "bgra"; + case media::PIXEL_FORMAT_ABGR: + return "rgba"; + case media::PIXEL_FORMAT_RGBAF16: + return "rgbaf16"; + default: + NOTREACHED(); + } +} + +struct ImportedSharedTexture + : base::RefCountedThreadSafe<ImportedSharedTexture> { + // Metadata + gfx::Size coded_size; + gfx::Rect visible_rect; + int64_t timestamp; + media::VideoPixelFormat pixel_format; + + // Holds a reference to prevent it from being destroyed. + scoped_refptr<gpu::ClientSharedImage> client_shared_image; + gpu::SyncToken frame_creation_sync_token; + base::Lock release_sync_token_lock_; + gpu::SyncToken release_sync_token GUARDED_BY(release_sync_token_lock_); + base::OnceClosure release_callback; + + // Texture id for printing warnings like GC check. + std::string id; + + void UpdateReleaseSyncToken(const gpu::SyncToken& token); + void SetupReleaseSyncTokenCallback(); + + // Transfer to other Chromium processes. + v8::Local<v8::Value> StartTransferSharedTexture(v8::Isolate* isolate); + + // Get the creation sync token for the shared image. This is called + // after |finishTransferSharedTexture| and users need to pass the + // sync token back to the source object, and call |setReleaseSyncToken| + // to prevent the resource being released before actual acquisition + // happens for the target object. + v8::Local<v8::Value> GetFrameCreationSyncToken(v8::Isolate* isolate); + + // Set a release sync token for this shared texture. This is set + // when |finishTransferSharedTexture| is called and prevent the source + // object release the underlying resource before the target object + // actually done acquiring the resource at gpu process. + // Note that this is optional to set, if not set, users can still use + // `release()` and use the callback to wait for the signal that source + // object is safe to do the further release. If set, users can call + // `release()` on the source object without worrying the target object + // didn't finish acquiring the resource at gpu process. + void SetReleaseSyncToken(v8::Isolate* isolate, v8::Local<v8::Value> options); + + // The cleanup happens at destructor. + private: + friend class base::RefCountedThreadSafe<ImportedSharedTexture>; + ~ImportedSharedTexture(); +}; + +// Wraps the structure so that it can be ref counted. +struct ImportedSharedTextureWrapper { + // Make the import shared texture wrapper ref counted, so that it can be + // held by multiple VideoFrames. + scoped_refptr<ImportedSharedTexture> ist; + + // Monitor garbage collection. + std::unique_ptr<v8::Persistent<v8::Value>> persistent_; + void ResetPersistent() const { persistent_->Reset(); } + v8::Persistent<v8::Value>* CreatePersistent(v8::Isolate* isolate, + v8::Local<v8::Value> value) { + persistent_ = std::make_unique<v8::Persistent<v8::Value>>(isolate, value); + return persistent_.get(); + } + + // Create VideoFrame from the shared image. + v8::Local<v8::Value> CreateVideoFrame(v8::Isolate* isolate); + + // Release the shared image. + bool IsReferenceReleased() const { return ist.get() == nullptr; } + void ReleaseReference(); +}; + +void ImportedSharedTextureWrapper::ReleaseReference() { + if (IsReferenceReleased()) { + LOG(ERROR) << "This imported shared texture is already released."; + return; + } + + // Drop the reference, if at lease one VideoFrame is still holding it, + // the final clean up will wait for them. + ist.reset(); +} + +// This function will be called when the VideoFrame is destructed. +void OnVideoFrameMailboxReleased( + const scoped_refptr<ImportedSharedTexture>& ist, + const gpu::SyncToken& sync_token) { + ist->UpdateReleaseSyncToken(sync_token); +} + +v8::Local<v8::Value> ImportedSharedTextureWrapper::CreateVideoFrame( + v8::Isolate* isolate) { + auto* current_script_state = blink::ScriptState::ForCurrentRealm(isolate); + auto* current_execution_context = + blink::ToExecutionContext(current_script_state); + + auto si = ist->client_shared_image; + auto cb = base::BindOnce(OnVideoFrameMailboxReleased, ist); + + scoped_refptr<media::VideoFrame> raw_frame = + media::VideoFrame::WrapSharedImage( + ist->pixel_format, si, ist->frame_creation_sync_token, std::move(cb), + ist->coded_size, ist->visible_rect, ist->coded_size, + base::Microseconds(ist->timestamp)); + + raw_frame->set_color_space(si->color_space()); + + blink::VideoFrame* frame = blink::MakeGarbageCollected<blink::VideoFrame>( + raw_frame, current_execution_context); + return blink::ToV8Traits<blink::VideoFrame>::ToV8(current_script_state, + frame); +} + +v8::Local<v8::Value> ImportedSharedTexture::StartTransferSharedTexture( + v8::Isolate* isolate) { + auto exported = client_shared_image->Export(); + + // Use mojo to serialize the exported shared image. + mojo::Message message(0, 0, MOJO_CREATE_MESSAGE_FLAG_UNLIMITED_SIZE, 0); + mojo::internal::MessageFragment< + gpu::mojom::internal::ExportedSharedImage_Data> + data(message); + data.Allocate(); + mojo::internal::Serializer<gpu::mojom::ExportedSharedImageDataView, + gpu::ExportedSharedImage>::Serialize(exported, + data); + + auto encoded = base::Base64Encode(UNSAFE_BUFFERS( + base::span(message.payload(), message.payload_num_bytes()))); + gin_helper::Dictionary root(isolate, v8::Object::New(isolate)); + root.SetReadOnly("transfer", encoded); + + auto sync_token = GetBase64StringFromSyncToken(frame_creation_sync_token); + root.SetReadOnly("syncToken", sync_token); + + root.SetReadOnly("pixelFormat", + TransferVideoPixelFormatToString(pixel_format)); + root.SetReadOnly("codedSize", coded_size); + root.SetReadOnly("visibleRect", visible_rect); + root.SetReadOnly("timestamp", timestamp); + + return gin::ConvertToV8(isolate, root); +} + +v8::Local<v8::Value> ImportedSharedTexture::GetFrameCreationSyncToken( + v8::Isolate* isolate) { + gin::Dictionary root(isolate, v8::Object::New(isolate)); + + auto sync_token = GetBase64StringFromSyncToken(frame_creation_sync_token); + root.Set("syncToken", sync_token); + + return gin::ConvertToV8(isolate, root); +} + +void ImportedSharedTexture::SetReleaseSyncToken(v8::Isolate* isolate, + v8::Local<v8::Value> options) { + std::string sync_token_data; + gin::Dictionary dict(isolate, options.As<v8::Object>()); + dict.Get("syncToken", &sync_token_data); + + auto sync_token = GetSyncTokenFromBase64String(sync_token_data); + UpdateReleaseSyncToken(sync_token); +} + +ImportedSharedTexture::~ImportedSharedTexture() { + // When nothing holds this, 1) all VideoFrames are destructed and the + // release_sync_token have been updated; 2) the user called `release()` + // explicitly. This is destructed and the final clean up is started. + SetupReleaseSyncTokenCallback(); + client_shared_image.reset(); +} + +void ImportedSharedTexture::UpdateReleaseSyncToken( + const gpu::SyncToken& token) { + base::AutoLock locker(release_sync_token_lock_); + + auto* sii = GetSharedImageInterface(); + if (release_sync_token.HasData()) { + // If we already have a release sync token, we need to wait for it + // to be signaled before we can set the new one. + sii->WaitSyncToken(release_sync_token); + } + + // Set the new release sync token to use at last. + release_sync_token = token; +} + +void ImportedSharedTexture::SetupReleaseSyncTokenCallback() { + base::AutoLock locker(release_sync_token_lock_); + + auto* sii = GetSharedImageInterface(); + if (!release_sync_token.HasData()) { + release_sync_token = sii->GenUnverifiedSyncToken(); + } + + client_shared_image->UpdateDestructionSyncToken(release_sync_token); + + if (release_callback) { + GetContextSupport()->SignalSyncToken(release_sync_token, + std::move(release_callback)); + } +} + +void PersistentCallbackPass1( + const v8::WeakCallbackInfo<ImportedSharedTextureWrapper>& data) { + auto* wrapper = data.GetParameter(); + // The |wrapper->ist| must be valid here, as we are a holder of it. + if (!wrapper->IsReferenceReleased()) { + // Emit a warning when the user didn't properly manually release the + // texture. + LOG(ERROR) << "The imported shared texture " << wrapper->ist->id + << " was garbage collected before calling `release()`. You have " + "to manually release the resource once you're done with it."; + + // Release it for user here. + wrapper->ReleaseReference(); + } + // We are responsible for resetting the persistent handle. + wrapper->ResetPersistent(); + // Finally, release the import monitor; + delete wrapper; +} + +void ImportedTextureGetVideoFrame( + const v8::FunctionCallbackInfo<v8::Value>& info) { + auto* isolate = info.GetIsolate(); + auto* wrapper = static_cast<ImportedSharedTextureWrapper*>( + info.Data().As<v8::External>()->Value()); + + if (wrapper->IsReferenceReleased()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "The shared texture has been released."); + return; + } + + if (IsBrowserProcess()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "The VideoFrame cannot be created at current process."); + return; + } + + auto ret = wrapper->CreateVideoFrame(isolate); + info.GetReturnValue().Set(ret); +} + +void ImportedTextureStartTransferSharedTexture( + const v8::FunctionCallbackInfo<v8::Value>& info) { + auto* isolate = info.GetIsolate(); + auto* wrapper = static_cast<ImportedSharedTextureWrapper*>( + info.Data().As<v8::External>()->Value()); + + if (wrapper->IsReferenceReleased()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "The shared texture has been released."); + return; + } + + auto ret = wrapper->ist->StartTransferSharedTexture(isolate); + info.GetReturnValue().Set(ret); +} + +void ImportedTextureRelease(const v8::FunctionCallbackInfo<v8::Value>& info) { + auto* wrapper = static_cast<ImportedSharedTextureWrapper*>( + info.Data().As<v8::External>()->Value()); + + auto cb = info[0]; + if (cb->IsFunction()) { + auto* isolate = info.GetIsolate(); + gin::ConvertFromV8(isolate, cb, &wrapper->ist->release_callback); + } + + // Release the shared texture, so that future frames can be generated. + wrapper->ReleaseReference(); + + // Release of the wrapper happens at GC persistent callback. + // Release of the |ist| happens when nothing holds a reference to it. +} + +void ImportedTextureGetFrameCreationSyncToken( + const v8::FunctionCallbackInfo<v8::Value>& info) { + auto* isolate = info.GetIsolate(); + auto* wrapper = static_cast<ImportedSharedTextureWrapper*>( + info.Data().As<v8::External>()->Value()); + + if (wrapper->IsReferenceReleased()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "The shared texture has been released."); + return; + } + + auto ret = wrapper->ist->GetFrameCreationSyncToken(isolate); + info.GetReturnValue().Set(ret); +} + +void ImportedTextureSetReleaseSyncToken( + const v8::FunctionCallbackInfo<v8::Value>& info) { + auto* isolate = info.GetIsolate(); + auto* wrapper = static_cast<ImportedSharedTextureWrapper*>( + info.Data().As<v8::External>()->Value()); + + if (wrapper->IsReferenceReleased()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "The shared texture has been released."); + return; + } + + if (info.Length() < 1 || !info[0]->IsObject()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "Expected an options object with a syncToken property."); + return; + } + + wrapper->ist->SetReleaseSyncToken(isolate, info[0].As<v8::Object>()); +} + +v8::Local<v8::Value> CreateImportedSharedTextureFromSharedImage( + v8::Isolate* isolate, + ImportedSharedTexture* imported) { + auto* wrapper = new ImportedSharedTextureWrapper(); + wrapper->ist = base::WrapRefCounted(imported); + + auto imported_wrapped = v8::External::New(isolate, wrapper); + gin::Dictionary root(isolate, v8::Object::New(isolate)); + + auto releaser = v8::Function::New(isolate->GetCurrentContext(), + ImportedTextureRelease, imported_wrapped) + .ToLocalChecked(); + + auto get_video_frame = + v8::Function::New(isolate->GetCurrentContext(), + ImportedTextureGetVideoFrame, imported_wrapped) + .ToLocalChecked(); + + auto start_transfer = + v8::Function::New(isolate->GetCurrentContext(), + ImportedTextureStartTransferSharedTexture, + imported_wrapped) + .ToLocalChecked(); + + auto get_frame_creation_sync_token = + v8::Function::New(isolate->GetCurrentContext(), + ImportedTextureGetFrameCreationSyncToken, + imported_wrapped) + .ToLocalChecked(); + + auto set_release_sync_token = + v8::Function::New(isolate->GetCurrentContext(), + ImportedTextureSetReleaseSyncToken, imported_wrapped) + .ToLocalChecked(); + + root.Set("release", releaser); + root.Set("getVideoFrame", get_video_frame); + root.Set("startTransferSharedTexture", start_transfer); + root.Set("getFrameCreationSyncToken", get_frame_creation_sync_token); + root.Set("setReleaseSyncToken", set_release_sync_token); + + auto root_local = gin::ConvertToV8(isolate, root); + auto* persistent = wrapper->CreatePersistent(isolate, root_local); + + persistent->SetWeak(wrapper, PersistentCallbackPass1, + v8::WeakCallbackType::kParameter); + + return root_local; +} + +struct ImportSharedTextureInfoPlane { + // The strides and offsets in bytes to be used when accessing the buffers + // via a memory mapping. One per plane per entry. Size in bytes of the + // plane is necessary to map the buffers. + uint32_t stride; + uint64_t offset; + uint64_t size; + + // File descriptor for the underlying memory object (usually dmabuf). + int fd = 0; +}; + +struct ImportSharedTextureInfo { + // Texture id for printing warnings like GC check. + std::string id; + + // The pixel format of the shared texture, RGBA or BGRA depends on platform. + media::VideoPixelFormat pixel_format; + + // The full dimensions of the video frame data. + gfx::Size coded_size; + + // A subsection of [0, 0, coded_size().width(), coded_size.height()]. + // In OSR case, it is expected to have the full area of the section. + gfx::Rect visible_rect; + + // The color space of the video frame. + gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); + + // The capture timestamp, microseconds since capture start + int64_t timestamp = 0; + +#if BUILDFLAG(IS_WIN) + // On Windows, it must be a NT HANDLE (CreateSharedHandle) to the shared + // texture, it can't be a deprecated non-NT HANDLE (GetSharedHandle). This + // must be a handle already duplicated for the current process and can be + // owned by this. + uintptr_t nt_handle = 0; +#elif BUILDFLAG(IS_APPLE) + // On macOS, it is an IOSurfaceRef, this must be a valid IOSurface at the + // current process. + uintptr_t io_surface = 0; +#elif BUILDFLAG(IS_LINUX) + // On Linux, to be implemented. + std::vector<ImportSharedTextureInfoPlane> planes; + uint64_t modifier = gfx::NativePixmapHandle::kNoModifier; + bool supports_zero_copy_webgpu_import = false; +#endif +}; + +} // namespace + +namespace gin { + +template <> +struct Converter<ImportSharedTextureInfo> { + static bool FromV8(v8::Isolate* isolate, + v8::Local<v8::Value> val, + ImportSharedTextureInfo* out) { + if (!val->IsObject()) + return false; + gin::Dictionary dict(isolate, val.As<v8::Object>()); + + std::string pixel_format_str; + if (dict.Get("pixelFormat", &pixel_format_str)) { + if (pixel_format_str == "bgra") + out->pixel_format = media::PIXEL_FORMAT_ARGB; + else if (pixel_format_str == "rgba") + out->pixel_format = media::PIXEL_FORMAT_ABGR; + else if (pixel_format_str == "rgbaf16") + out->pixel_format = media::PIXEL_FORMAT_RGBAF16; + else + return false; + } + + dict.Get("codedSize", &out->coded_size); + if (!dict.Get("visibleRect", &out->visible_rect)) { + out->visible_rect = gfx::Rect(out->coded_size); + } + dict.Get("colorSpace", &out->color_space); + dict.Get("timestamp", &out->timestamp); + dict.Get("id", &out->id); + + gin::Dictionary shared_texture(isolate, val.As<v8::Object>()); + if (!dict.Get("handle", &shared_texture)) { + return false; + } + +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) + auto GetNativeHandle = [&](const std::string& property_key, + uintptr_t* output) { + v8::Local<v8::Value> handle_buf; + if (shared_texture.Get(property_key, &handle_buf) && + node::Buffer::HasInstance(handle_buf)) { + char* data = node::Buffer::Data(handle_buf); + if (node::Buffer::Length(handle_buf) == sizeof(uintptr_t)) { + *output = *reinterpret_cast<uintptr_t*>(data); + } + } + }; +#endif + +#if BUILDFLAG(IS_WIN) + GetNativeHandle("ntHandle", &out->nt_handle); +#elif BUILDFLAG(IS_APPLE) + GetNativeHandle("ioSurface", &out->io_surface); +#elif BUILDFLAG(IS_LINUX) + v8::Local<v8::Object> native_pixmap; + if (shared_texture.Get("nativePixmap", &native_pixmap)) { + gin::Dictionary v8_native_pixmap(isolate, native_pixmap); + v8::Local<v8::Array> v8_planes; + if (v8_native_pixmap.Get("planes", &v8_planes)) { + out->planes.clear(); + for (uint32_t i = 0; i < v8_planes->Length(); ++i) { + v8::Local<v8::Value> v8_item = + v8_planes->Get(isolate->GetCurrentContext(), i).ToLocalChecked(); + gin::Dictionary v8_plane(isolate, v8_item.As<v8::Object>()); + ImportSharedTextureInfoPlane plane; + v8_plane.Get("stride", &plane.stride); + v8_plane.Get("offset", &plane.offset); + v8_plane.Get("size", &plane.size); + v8_plane.Get("fd", &plane.fd); + out->planes.push_back(plane); + } + } + std::string modifier_str; + if (v8_native_pixmap.Get("modifier", &modifier_str)) { + base::StringToUint64(modifier_str, &out->modifier); + } + v8_native_pixmap.Get("supportsZeroCopyWebGpuImport", + &out->supports_zero_copy_webgpu_import); + } +#endif + + return true; + } +}; + +} // namespace gin + +namespace electron::api::shared_texture { + +v8::Local<v8::Value> ImportSharedTexture(v8::Isolate* isolate, + v8::Local<v8::Value> options) { + ImportSharedTextureInfo shared_texture{}; + if (!gin::ConvertFromV8(isolate, options, &shared_texture)) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "Invalid shared texture info object"); + return v8::Null(isolate); + } + + gfx::GpuMemoryBufferHandle gmb_handle; +#if BUILDFLAG(IS_WIN) + if (shared_texture.nt_handle == 0) { + gin_helper::ErrorThrower(isolate).ThrowTypeError("Invalid ntHandle value"); + return v8::Null(isolate); + } + + auto handle = reinterpret_cast<HANDLE>(shared_texture.nt_handle); + + HANDLE dup_handle; + // Duplicate the handle to allow scoped handle close it. + if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), + &dup_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "Unable to duplicate handle."); + return v8::Null(isolate); + } + + auto dxgi_handle = gfx::DXGIHandle(base::win::ScopedHandle(dup_handle)); + gmb_handle = gfx::GpuMemoryBufferHandle(std::move(dxgi_handle)); +#elif BUILDFLAG(IS_APPLE) + if (shared_texture.io_surface == 0) { + gin_helper::ErrorThrower(isolate).ThrowTypeError("Invalid ioSurface value"); + return v8::Null(isolate); + } + + // Retain the io_surface reference to increase the reference count. + auto io_surface = reinterpret_cast<IOSurfaceRef>(shared_texture.io_surface); + auto io_surface_scoped = base::apple::ScopedCFTypeRef<IOSurfaceRef>( + io_surface, base::scoped_policy::RETAIN); + gmb_handle = gfx::GpuMemoryBufferHandle(std::move(io_surface_scoped)); +#elif BUILDFLAG(IS_LINUX) + gfx::NativePixmapHandle pixmap; + pixmap.modifier = shared_texture.modifier; + pixmap.supports_zero_copy_webgpu_import = + shared_texture.supports_zero_copy_webgpu_import; + + for (const auto& plane : shared_texture.planes) { + gfx::NativePixmapPlane plane_info; + plane_info.stride = plane.stride; + plane_info.offset = plane.offset; + plane_info.size = plane.size; + + // Duplicate fd, otherwise the process may already have ownership. + int checked_dup = HANDLE_EINTR(dup(plane.fd)); + plane_info.fd = base::ScopedFD(checked_dup); + + pixmap.planes.push_back(std::move(plane_info)); + } + + gmb_handle = gfx::GpuMemoryBufferHandle(std::move(pixmap)); +#endif + + gfx::Size coded_size = shared_texture.coded_size; + media::VideoPixelFormat pixel_format = shared_texture.pixel_format; + gfx::ColorSpace color_space = shared_texture.color_space; + + auto buffer_format = media::VideoPixelFormatToGfxBufferFormat(pixel_format); + if (!buffer_format.has_value()) { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "Invalid shared texture buffer format"); + return v8::Null(isolate); + } + + auto* sii = GetSharedImageInterface(); + gpu::SharedImageUsageSet shared_image_usage = +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) + gpu::SHARED_IMAGE_USAGE_GLES2_READ | gpu::SHARED_IMAGE_USAGE_GLES2_WRITE | + gpu::SHARED_IMAGE_USAGE_RASTER_READ | + gpu::SHARED_IMAGE_USAGE_DISPLAY_READ | + gpu::SHARED_IMAGE_USAGE_WEBGPU_READ | + gpu::SHARED_IMAGE_USAGE_WEBGPU_WRITE; +#else + gpu::SHARED_IMAGE_USAGE_GLES2_READ | gpu::SHARED_IMAGE_USAGE_GLES2_WRITE | + gpu::SHARED_IMAGE_USAGE_RASTER_READ | + gpu::SHARED_IMAGE_USAGE_DISPLAY_READ; +#endif + + auto si_format = viz::GetSharedImageFormat(buffer_format.value()); + auto si = + sii->CreateSharedImage({si_format, coded_size, color_space, + shared_image_usage, "SharedTextureVideoFrame"}, + std::move(gmb_handle)); + + ImportedSharedTexture* imported = new ImportedSharedTexture(); + imported->pixel_format = shared_texture.pixel_format; + imported->coded_size = shared_texture.coded_size; + imported->visible_rect = shared_texture.visible_rect; + imported->timestamp = shared_texture.timestamp; + imported->frame_creation_sync_token = si->creation_sync_token(); + imported->client_shared_image = std::move(si); + imported->id = shared_texture.id; + + return CreateImportedSharedTextureFromSharedImage(isolate, imported); +} + +v8::Local<v8::Value> FinishTransferSharedTexture(v8::Isolate* isolate, + v8::Local<v8::Value> options) { + ImportSharedTextureInfo partial{}; + gin::ConvertFromV8(isolate, options, &partial); + + std::string id; + std::string transfer; + std::string sync_token_data; + + gin::Dictionary dict(isolate, options.As<v8::Object>()); + dict.Get("id", &id); + dict.Get("transfer", &transfer); + dict.Get("syncToken", &sync_token_data); + + auto transfer_data = base::Base64Decode(transfer); + + // Use mojo to deserialize the exported shared image. + mojo::Message message(transfer_data.value(), {}); + mojo::internal::MessageFragment< + gpu::mojom::internal::ExportedSharedImage_Data> + data(message); + data.Claim(message.mutable_payload()); + + gpu::ExportedSharedImage exported; + mojo::internal::Serializer<gpu::mojom::ExportedSharedImageDataView, + gpu::ExportedSharedImage>::Deserialize(data.data(), + &exported, + &message); + + auto* sii = GetSharedImageInterface(); + auto si = sii->ImportSharedImage(std::move(exported)); + + auto source_st = GetSyncTokenFromBase64String(sync_token_data); + sii->WaitSyncToken(source_st); + + ImportedSharedTexture* imported = new ImportedSharedTexture(); + imported->pixel_format = partial.pixel_format; + imported->coded_size = partial.coded_size; + imported->visible_rect = partial.visible_rect; + imported->timestamp = partial.timestamp; + imported->frame_creation_sync_token = sii->GenUnverifiedSyncToken(); + imported->client_shared_image = std::move(si); + imported->id = id; + + return CreateImportedSharedTextureFromSharedImage(isolate, imported); +} + +} // namespace electron::api::shared_texture + +namespace { + +void Initialize(v8::Local<v8::Object> exports, + v8::Local<v8::Value> unused, + v8::Local<v8::Context> context, + void* priv) { + v8::Isolate* const isolate = v8::Isolate::GetCurrent(); + gin_helper::Dictionary dict(isolate, exports); + dict.SetMethod("importSharedTexture", + &electron::api::shared_texture::ImportSharedTexture); + dict.SetMethod("finishTransferSharedTexture", + &electron::api::shared_texture::FinishTransferSharedTexture); +} + +} // namespace + +NODE_LINKED_BINDING_CONTEXT_AWARE(electron_common_shared_texture, Initialize) diff --git a/shell/common/api/electron_api_shared_texture.h b/shell/common/api/electron_api_shared_texture.h new file mode 100644 index 0000000000000..2e74245c73d02 --- /dev/null +++ b/shell/common/api/electron_api_shared_texture.h @@ -0,0 +1,23 @@ +// Copyright (c) 2025 Reito <reito@chromium.org> +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_COMMON_API_ELECTRON_API_SHARED_TEXTURE_H_ +#define ELECTRON_SHELL_COMMON_API_ELECTRON_API_SHARED_TEXTURE_H_ + +#include <string> +#include <vector> + +#include "v8/include/v8-forward.h" + +namespace electron::api::shared_texture { + +v8::Local<v8::Value> ImportSharedTexture(v8::Isolate* isolate, + v8::Local<v8::Value> options); + +v8::Local<v8::Value> FinishTransferSharedTexture(v8::Isolate* isolate, + v8::Local<v8::Value> options); + +} // namespace electron::api::shared_texture + +#endif // ELECTRON_SHELL_COMMON_API_ELECTRON_API_SHARED_TEXTURE_H_ diff --git a/shell/common/api/electron_api_shell.cc b/shell/common/api/electron_api_shell.cc index 944e4a6b36035..fc9d014a14840 100644 --- a/shell/common/api/electron_api_shell.cc +++ b/shell/common/api/electron_api_shell.cc @@ -55,7 +55,8 @@ void OnOpenFinished(gin_helper::Promise<void> promise, promise.RejectWithErrorMessage(error); } -v8::Local<v8::Promise> OpenExternal(const GURL& url, gin::Arguments* args) { +v8::Local<v8::Promise> OpenExternal(const GURL& url, + gin::Arguments* const args) { gin_helper::Promise<void> promise(args->isolate()); v8::Local<v8::Promise> handle = promise.GetHandle(); @@ -108,7 +109,7 @@ v8::Local<v8::Promise> TrashItem(v8::Isolate* isolate, #if BUILDFLAG(IS_WIN) bool WriteShortcutLink(const base::FilePath& shortcut_path, - gin_helper::Arguments* args) { + gin::Arguments* const args) { base::win::ShortcutOperation operation = base::win::ShortcutOperation::kCreateAlways; args->GetNext(&operation); diff --git a/shell/common/api/electron_api_url_loader.cc b/shell/common/api/electron_api_url_loader.cc index 81084d9f1b7e8..7e7a7d04ef8e0 100644 --- a/shell/common/api/electron_api_url_loader.cc +++ b/shell/common/api/electron_api_url_loader.cc @@ -492,7 +492,7 @@ SimpleURLLoaderWrapper::GetURLLoaderFactoryForURL(const GURL& url) { // correctly intercept file:// scheme URLs. if (const bool bypass = request_options_ & kBypassCustomProtocolHandlers; !bypass) { - const std::string_view scheme = url.scheme_piece(); + const std::string_view scheme = url.scheme(); const auto* const protocol_registry = ProtocolRegistry::FromBrowserContext(browser_context_); diff --git a/shell/common/api/electron_api_url_loader.h b/shell/common/api/electron_api_url_loader.h index 405dccdbda3e2..2ff737ce75db7 100644 --- a/shell/common/api/electron_api_url_loader.h +++ b/shell/common/api/electron_api_url_loader.h @@ -125,6 +125,7 @@ class SimpleURLLoaderWrapper final int64_t recv_bytes, int64_t sent_bytes) override {} void OnWebSocketConnectedToPrivateNetwork( + const GURL& request_url, network::mojom::IPAddressSpace ip_address_space) override {} void Clone( mojo::PendingReceiver<network::mojom::URLLoaderNetworkServiceObserver> diff --git a/shell/common/api/electron_bindings.cc b/shell/common/api/electron_bindings.cc index 417334f331332..4ffe9f5fe7389 100644 --- a/shell/common/api/electron_bindings.cc +++ b/shell/common/api/electron_bindings.cc @@ -17,10 +17,13 @@ #include "electron/mas.h" #include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h" #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" +// #include +// "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h" #include "shell/browser/browser.h" #include "shell/common/application_info.h" #include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_helper/dictionary.h" +#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/locker.h" #include "shell/common/gin_helper/promise.h" #include "shell/common/heap_snapshot.h" @@ -163,11 +166,11 @@ v8::Local<v8::Value> ElectronBindings::GetCreationTime(v8::Isolate* isolate) { // static v8::Local<v8::Value> ElectronBindings::GetSystemMemoryInfo( - v8::Isolate* isolate, - gin_helper::Arguments* args) { + v8::Isolate* const isolate) { base::SystemMemoryInfo mem_info; if (!base::GetSystemMemoryInfo(&mem_info)) { - args->ThrowError("Unable to retrieve system memory information"); + gin_helper::ErrorThrower{isolate}.ThrowError( + "Unable to retrieve system memory information"); return v8::Undefined(isolate); } @@ -211,7 +214,7 @@ v8::Local<v8::Promise> ElectronBindings::GetProcessMemoryInfo( v8::Global<v8::Context> context(isolate, isolate->GetCurrentContext()); memory_instrumentation::MemoryInstrumentation::GetInstance() ->RequestGlobalDumpForPid( - base::GetCurrentProcId(), std::vector<std::string>(), + base::GetCurrentProcId(), {} /* allocator_dump_names */, base::BindOnce(&ElectronBindings::DidReceiveMemoryDump, std::move(context), std::move(promise), base::GetCurrentProcId())); @@ -235,7 +238,7 @@ void ElectronBindings::DidReceiveMemoryDump( v8::Global<v8::Context> context, gin_helper::Promise<gin_helper::Dictionary> promise, base::ProcessId target_pid, - bool success, + const memory_instrumentation::mojom::RequestOutcome outcome, std::unique_ptr<memory_instrumentation::GlobalMemoryDump> global_dump) { DCHECK(electron::IsBrowserProcess()); v8::Isolate* isolate = promise.isolate(); @@ -244,7 +247,7 @@ void ElectronBindings::DidReceiveMemoryDump( v8::Local<v8::Context>::New(isolate, context); v8::Context::Scope context_scope(local_context); - if (!success) { + if (outcome != memory_instrumentation::mojom::RequestOutcome::kSuccess) { promise.RejectWithErrorMessage("Failed to create memory dump"); return; } diff --git a/shell/common/api/electron_bindings.h b/shell/common/api/electron_bindings.h index 851ae358f62ef..a618a34e5e50e 100644 --- a/shell/common/api/electron_bindings.h +++ b/shell/common/api/electron_bindings.h @@ -10,6 +10,7 @@ #include "base/memory/scoped_refptr.h" #include "base/process/process_metrics.h" +#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom-forward.h" #include "shell/common/node_bindings.h" #include "uv.h" // NOLINT(build/include_directory) @@ -18,7 +19,6 @@ class FilePath; } namespace gin_helper { -class Arguments; class Dictionary; template <typename T> class Promise; @@ -60,15 +60,14 @@ class ElectronBindings { v8::Global<v8::Context> context, gin_helper::Promise<gin_helper::Dictionary> promise, base::ProcessId target_pid, - bool success, + memory_instrumentation::mojom::RequestOutcome outcome, std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump); private: static void Hang(); static v8::Local<v8::Value> GetHeapStatistics(v8::Isolate* isolate); static v8::Local<v8::Value> GetCreationTime(v8::Isolate* isolate); - static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate, - gin_helper::Arguments* args); + static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate); static v8::Local<v8::Promise> GetProcessMemoryInfo(v8::Isolate* isolate); static v8::Local<v8::Value> GetBlinkMemoryInfo(v8::Isolate* isolate); static v8::Local<v8::Value> GetCPUUsage(base::ProcessMetrics* metrics, diff --git a/shell/common/application_info_win.cc b/shell/common/application_info_win.cc index 5b0a28c9ab4b1..76eacffce17f8 100644 --- a/shell/common/application_info_win.cc +++ b/shell/common/application_info_win.cc @@ -13,6 +13,7 @@ #include <memory> #include "base/file_version_info.h" +#include "base/no_destructor.h" #include "base/strings/string_util.h" #include "base/strings/string_util_win.h" #include "base/strings/utf_string_conversions.h" @@ -20,13 +21,13 @@ namespace electron { -namespace { +const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1"; -std::wstring g_app_user_model_id; +std::wstring& GetAppUserModelId() { + static base::NoDestructor<std::wstring> g_app_user_model_id; + return *g_app_user_model_id; } -const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1"; - std::string GetApplicationName() { auto* module = GetModuleHandle(nullptr); std::unique_ptr<FileVersionInfo> info( @@ -42,15 +43,15 @@ std::string GetApplicationVersion() { } void SetAppUserModelID(const std::wstring& name) { - g_app_user_model_id = name; - SetCurrentProcessExplicitAppUserModelID(g_app_user_model_id.c_str()); + GetAppUserModelId() = name; + SetCurrentProcessExplicitAppUserModelID(GetAppUserModelId().c_str()); } PCWSTR GetRawAppUserModelID() { - if (g_app_user_model_id.empty()) { + if (GetAppUserModelId().empty()) { PWSTR current_app_id; if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) { - g_app_user_model_id = current_app_id; + GetAppUserModelId() = current_app_id; } else { std::string name = GetApplicationName(); std::wstring generated_app_id = base::ReplaceStringPlaceholders( @@ -60,7 +61,7 @@ PCWSTR GetRawAppUserModelID() { CoTaskMemFree(current_app_id); } - return g_app_user_model_id.c_str(); + return GetAppUserModelId().c_str(); } bool GetAppUserModelID(ScopedHString* app_id) { diff --git a/shell/common/asar/archive.cc b/shell/common/asar/archive.cc index 7951632806215..29c1a7e13704b 100644 --- a/shell/common/asar/archive.cc +++ b/shell/common/asar/archive.cc @@ -255,7 +255,8 @@ bool Archive::Init() { } #endif - std::optional<base::Value> value = base::JSONReader::Read(header); + std::optional<base::Value> value = + base::JSONReader::Read(header, base::JSON_PARSE_CHROMIUM_EXTENSIONS); if (!value || !value->is_dict()) { LOG(ERROR) << "Failed to parse header"; return false; diff --git a/shell/common/asar/archive_mac.mm b/shell/common/asar/archive_mac.mm index 455c5e03c2d08..bc6286e7eb851 100644 --- a/shell/common/asar/archive_mac.mm +++ b/shell/common/asar/archive_mac.mm @@ -17,6 +17,7 @@ #include "base/files/file_util.h" #include "base/strings/sys_string_conversions.h" #include "shell/common/asar/asar_util.h" +#include "shell/common/asar/integrity_digest.h" namespace asar { @@ -39,6 +40,9 @@ NSDictionary* integrity = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ElectronAsarIntegrity"]; + if (!IsIntegrityDictionaryValid(integrity)) + return std::nullopt; + // Integrity not provided if (!integrity) return std::nullopt; diff --git a/shell/common/asar/archive_win.cc b/shell/common/asar/archive_win.cc index ae3e73797bf4f..2360493832f81 100644 --- a/shell/common/asar/archive_win.cc +++ b/shell/common/asar/archive_win.cc @@ -71,7 +71,8 @@ auto LoadIntegrityConfig() { // Parse integrity config payload std::optional<base::Value> root = - base::JSONReader::Read(std::string_view{res_data, res_size}); + base::JSONReader::Read(std::string_view{res_data, res_size}, + base::JSON_PARSE_CHROMIUM_EXTENSIONS); if (!root.has_value()) { LOG(FATAL) << "Invalid integrity config: NOT a valid JSON."; diff --git a/shell/common/asar/integrity_digest.h b/shell/common/asar/integrity_digest.h new file mode 100644 index 0000000000000..9336baaba5f6f --- /dev/null +++ b/shell/common/asar/integrity_digest.h @@ -0,0 +1,15 @@ +// Copyright (c) 2025 Noah Gregory +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_COMMON_ASAR_INTEGRITY_DIGEST_H_ +#define ELECTRON_SHELL_COMMON_ASAR_INTEGRITY_DIGEST_H_ + +#include <Foundation/Foundation.h> +namespace asar { + +bool IsIntegrityDictionaryValid(NSDictionary* integrity_dict); + +} // namespace asar + +#endif // ELECTRON_SHELL_COMMON_ASAR_INTEGRITY_DIGEST_H_ diff --git a/shell/common/asar/integrity_digest.mm b/shell/common/asar/integrity_digest.mm new file mode 100644 index 0000000000000..7f64ae57e22fd --- /dev/null +++ b/shell/common/asar/integrity_digest.mm @@ -0,0 +1,74 @@ +// Copyright (c) 2025 Noah Gregory +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/common/asar/integrity_digest.h" + +#include <Foundation/Foundation.h> + +#include <array> +#include <cstdint> +#include <span> + +#include "base/strings/sys_string_conversions.h" +#include "crypto/hash.h" + +namespace asar { + +constexpr crypto::hash::HashKind kIntegrityDictionaryHashKind = + crypto::hash::HashKind::kSha256; + +constexpr size_t kIntegrityDictionaryDigestSize = + DigestSizeForHashKind(kIntegrityDictionaryHashKind); +constexpr char kIntegrityDictionaryDigestSentinel[] = + "AGbevlPCksUGKNL8TSn7wGmJEuJsXb2A"; + +struct IntegrityDictionaryDigestSlot { + uint8_t sentinel[sizeof(kIntegrityDictionaryDigestSentinel) - 1]; + uint8_t used; + uint8_t version; + uint8_t digest[kIntegrityDictionaryDigestSize]; +}; + +constexpr IntegrityDictionaryDigestSlot MakeDigestSlot( + const char (&sentinel)[33]) { + IntegrityDictionaryDigestSlot slot{}; + std::span<uint8_t, 32> slot_sentinel_span(slot.sentinel); + std::copy_n(sentinel, slot_sentinel_span.size(), slot_sentinel_span.begin()); + slot.used = false; // to be set at package-time + slot.version = 0; // to be set at package-time + return slot; +} + +__attribute__((section("__DATA_CONST,__asar_integrity"), used)) +const volatile IntegrityDictionaryDigestSlot kIntegrityDictionaryDigest = + MakeDigestSlot(kIntegrityDictionaryDigestSentinel); + +bool IsIntegrityDictionaryValid(NSDictionary* integrity) { + if (kIntegrityDictionaryDigest.used == false) + return true; // No digest to validate against, fail open + if (kIntegrityDictionaryDigest.version != 1) + return false; // Unknown version, fail closed + crypto::hash::Hasher integrity_hasher(kIntegrityDictionaryHashKind); + for (NSString *relative_path_key in + [[integrity allKeys] sortedArrayUsingComparator:^NSComparisonResult( + NSString* s1, NSString* s2) { + return [s1 compare:s2 options:NSLiteralSearch]; + }]) { + NSDictionary* file_integrity = [integrity objectForKey:relative_path_key]; + NSString* algorithm = [file_integrity objectForKey:@"algorithm"]; + NSString* hash = [file_integrity objectForKey:@"hash"]; + integrity_hasher.Update(base::SysNSStringToUTF8(relative_path_key)); + integrity_hasher.Update(base::SysNSStringToUTF8(algorithm)); + integrity_hasher.Update(base::SysNSStringToUTF8(hash)); + } + std::array<uint8_t, kIntegrityDictionaryDigestSize> digest; + integrity_hasher.Finish(digest); + if (!std::equal(digest.begin(), digest.end(), + kIntegrityDictionaryDigest.digest)) { + return false; + } + return true; +} + +} // namespace asar diff --git a/shell/common/callback_util.h b/shell/common/callback_util.h new file mode 100644 index 0000000000000..70f454cf58f3a --- /dev/null +++ b/shell/common/callback_util.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft GmbH. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_COMMON_CALLBACK_UTIL_H_ +#define ELECTRON_SHELL_COMMON_CALLBACK_UTIL_H_ + +#include <memory> +#include <utility> + +#include "base/functional/bind.h" +#include "base/functional/callback.h" + +namespace electron { + +namespace internal { +template <typename... Args> +class OnceCallbackHolder { + public: + explicit OnceCallbackHolder(base::OnceCallback<void(Args...)> cb) + : cb_(std::move(cb)) {} + + void Run(Args... args) { + if (cb_) + std::move(cb_).Run(std::forward<Args>(args)...); + } + + private: + base::OnceCallback<void(Args...)> cb_; +}; +} // namespace internal + +template <typename... Args> +base::RepeatingCallback<void(Args...)> AdaptCallbackForRepeating( + base::OnceCallback<void(Args...)> cb) { + using Holder = internal::OnceCallbackHolder<Args...>; + return base::BindRepeating(&Holder::Run, + std::make_unique<Holder>(std::move(cb))); +} + +} // namespace electron + +#endif // ELECTRON_SHELL_COMMON_CALLBACK_UTIL_H_ diff --git a/shell/common/color_util.cc b/shell/common/color_util.cc index 80c998b86b27d..33c0c40818b04 100644 --- a/shell/common/color_util.cc +++ b/shell/common/color_util.cc @@ -14,6 +14,7 @@ #include <dwmapi.h> #include "base/win/registry.h" +#include "skia/ext/skia_utils_win.h" #endif namespace { @@ -83,6 +84,10 @@ std::optional<DWORD> GetSystemAccentColor() { return accent_color; } + +SkColor GetSysSkColor(int which) { + return skia::COLORREFToSkColor(GetSysColor(which)); +} #endif } // namespace electron diff --git a/shell/common/color_util.h b/shell/common/color_util.h index 873ec67790255..2c28e1b189fd3 100644 --- a/shell/common/color_util.h +++ b/shell/common/color_util.h @@ -39,6 +39,7 @@ std::string ToRGBAHex(SkColor color, bool include_hash = true); #if BUILDFLAG(IS_WIN) std::optional<DWORD> GetSystemAccentColor(); +SkColor GetSysSkColor(int which); #endif } // namespace electron diff --git a/shell/common/electron_command_line.cc b/shell/common/electron_command_line.cc index 0f474e91ebe9a..45c26715fd18a 100644 --- a/shell/common/electron_command_line.cc +++ b/shell/common/electron_command_line.cc @@ -6,39 +6,43 @@ #include "base/command_line.h" #include "base/containers/to_vector.h" +#include "base/no_destructor.h" #include "base/strings/utf_string_conversions.h" namespace electron { // static -base::CommandLine::StringVector ElectronCommandLine::argv_; +base::CommandLine::StringVector& ElectronCommandLine::argv() { + static base::NoDestructor<base::CommandLine::StringVector> g_argv; + return *g_argv; +} // static void ElectronCommandLine::Init(int argc, base::CommandLine::CharType const* const* argv) { - DCHECK(argv_.empty()); + DCHECK(ElectronCommandLine::argv().empty()); // Safety: as is normal in command lines, argc and argv must correspond // to one another. Otherwise there will be out-of-bounds accesses. - argv_.assign(argv, UNSAFE_BUFFERS(argv + argc)); + ElectronCommandLine::argv().assign(argv, UNSAFE_BUFFERS(argv + argc)); } // static std::vector<std::string> ElectronCommandLine::AsUtf8() { - DCHECK(!argv_.empty()); + DCHECK(!argv().empty()); #if BUILDFLAG(IS_WIN) return base::ToVector( - argv_, [](const auto& wstr) { return base::WideToUTF8(wstr); }); + argv(), [](const auto& wstr) { return base::WideToUTF8(wstr); }); #else - return argv_; + return argv(); #endif } #if BUILDFLAG(IS_LINUX) // static void ElectronCommandLine::InitializeFromCommandLine() { - argv_ = base::CommandLine::ForCurrentProcess()->argv(); + argv() = base::CommandLine::ForCurrentProcess()->argv(); } #endif diff --git a/shell/common/electron_command_line.h b/shell/common/electron_command_line.h index f9e713c6c35b9..5595bd0e5a171 100644 --- a/shell/common/electron_command_line.h +++ b/shell/common/electron_command_line.h @@ -18,7 +18,7 @@ class ElectronCommandLine { ElectronCommandLine(const ElectronCommandLine&) = delete; ElectronCommandLine& operator=(const ElectronCommandLine&) = delete; - static const base::CommandLine::StringVector& argv() { return argv_; } + static base::CommandLine::StringVector& argv(); static std::vector<std::string> AsUtf8(); @@ -29,9 +29,6 @@ class ElectronCommandLine { // it is using zygote. static void InitializeFromCommandLine(); #endif - - private: - static base::CommandLine::StringVector argv_; }; } // namespace electron diff --git a/shell/common/electron_constants.h b/shell/common/electron_constants.h index 2ddf98d25acf4..813fc849702c9 100644 --- a/shell/common/electron_constants.h +++ b/shell/common/electron_constants.h @@ -21,6 +21,23 @@ inline constexpr std::string_view kDeviceVendorIdKey = "vendorId"; inline constexpr std::string_view kDeviceProductIdKey = "productId"; inline constexpr std::string_view kDeviceSerialNumberKey = "serialNumber"; +// Window state preference keys +inline constexpr std::string_view kLeft = "left"; +inline constexpr std::string_view kTop = "top"; +inline constexpr std::string_view kRight = "right"; +inline constexpr std::string_view kBottom = "bottom"; + +inline constexpr std::string_view kMaximized = "maximized"; +inline constexpr std::string_view kFullscreen = "fullscreen"; +inline constexpr std::string_view kKiosk = "kiosk"; + +inline constexpr std::string_view kWorkAreaLeft = "workAreaLeft"; +inline constexpr std::string_view kWorkAreaTop = "workAreaTop"; +inline constexpr std::string_view kWorkAreaRight = "workAreaRight"; +inline constexpr std::string_view kWorkAreaBottom = "workAreaBottom"; + +inline constexpr std::string_view kWindowStates = "windowStates"; + inline constexpr base::cstring_view kRunAsNode = "ELECTRON_RUN_AS_NODE"; // Per-profile UUID to distinguish global shortcut sessions for @@ -33,8 +50,6 @@ inline constexpr char kElectronGlobalShortcutsUuid[] = #if BUILDFLAG(ENABLE_PDF_VIEWER) inline constexpr std::string_view kPDFExtensionPluginName = "Chromium PDF Viewer"; -inline constexpr std::string_view kPDFInternalPluginName = - "Chromium PDF Plugin"; #endif // BUILDFLAG(ENABLE_PDF_VIEWER) } // namespace electron diff --git a/shell/common/extensions/api/_manifest_features.json b/shell/common/extensions/api/_manifest_features.json index 03ceb2df004dc..e854b22c39493 100644 --- a/shell/common/extensions/api/_manifest_features.json +++ b/shell/common/extensions/api/_manifest_features.json @@ -22,10 +22,6 @@ "extension_types": ["extension"], "platforms": ["win", "mac"] }, - "chrome_url_overrides": { - "channel": "stable", - "extension_types": ["extension", "legacy_packaged_app"] - }, "content_scripts": { "channel": "stable", "extension_types": ["extension", "legacy_packaged_app"] @@ -36,10 +32,6 @@ "extension", "legacy_packaged_app", "hosted_app" ] }, - "devtools_page": { - "channel": "stable", - "extension_types": ["extension", "legacy_packaged_app"] - }, "file_browser_handlers": { "channel": "stable", "extension_types": ["extension", "legacy_packaged_app"] diff --git a/shell/common/extensions/api/pdf_viewer_private.idl b/shell/common/extensions/api/pdf_viewer_private.idl index 0de5d9f6ce615..449f53ccfc47c 100644 --- a/shell/common/extensions/api/pdf_viewer_private.idl +++ b/shell/common/extensions/api/pdf_viewer_private.idl @@ -6,6 +6,15 @@ // functionality that the PDF Viewer needs from outside the PDF plugin. This API // is exclusively for the PDF Viewer. namespace pdfViewerPrivate { + // Must match `SaveRequestType` in `pdf/mojom/pdf.mojom` and + // `tools/typescript/definitions/pdf_viewer_private.d.ts`. + enum SaveRequestType { + ANNOTATION, + ORIGINAL, + EDITED, + SEARCHIFIED + }; + // Nearly identical to mimeHandlerPrivate.StreamInfo, but without a mime type // nor a response header field. Those fields are unused by the PDF viewer. dictionary StreamInfo { @@ -52,6 +61,13 @@ namespace pdfViewerPrivate { DOMString url, IsAllowedLocalFileAccessCallback callback); + // Sends a request to save the PDF to Google Drive if `saveRequestType` is + // set. Otherwise, if `saveRequestType` is not set, the default action is + // to cancel the existing upload. + static void saveToDrive( + optional SaveRequestType saveRequestType, + optional VoidCallback callback); + // Sets the current tab title to `title` for a full-page PDF. static void setPdfDocumentTitle( DOMString title, diff --git a/shell/common/extensions/electron_extensions_api_provider.cc b/shell/common/extensions/electron_extensions_api_provider.cc index 3d870af093228..2d310a69eb8f4 100644 --- a/shell/common/extensions/electron_extensions_api_provider.cc +++ b/shell/common/extensions/electron_extensions_api_provider.cc @@ -8,7 +8,6 @@ #include <string> #include "base/containers/span.h" -#include "chrome/common/extensions/chrome_manifest_url_handlers.h" #include "chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h" // nogncheck #include "electron/buildflags/buildflags.h" #include "electron/shell/common/extensions/api/generated_schemas.h" @@ -19,6 +18,7 @@ #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_handler.h" #include "extensions/common/manifest_handler_registry.h" +#include "extensions/common/manifest_handlers/chrome_url_overrides_handler.h" #include "extensions/common/manifest_handlers/permissions_parser.h" #include "extensions/common/manifest_url_handlers.h" #include "extensions/common/permissions/permissions_info.h" @@ -30,10 +30,6 @@ namespace extensions { namespace { constexpr APIPermissionInfo::InitInfo permissions_to_register[] = { - {mojom::APIPermissionID::kDevtools, "devtools", - APIPermissionInfo::kFlagImpliesFullURLAccess | - APIPermissionInfo::kFlagCannotBeOptional | - APIPermissionInfo::kFlagInternal}, {mojom::APIPermissionID::kResourcesPrivate, "resourcesPrivate", APIPermissionInfo::kFlagCannotBeOptional}, #if BUILDFLAG(ENABLE_PDF_VIEWER) @@ -104,8 +100,6 @@ void ElectronExtensionsAPIProvider::RegisterPermissions( void ElectronExtensionsAPIProvider::RegisterManifestHandlers() { extensions::ManifestHandlerRegistry* registry = extensions::ManifestHandlerRegistry::Get(); - registry->RegisterHandler( - std::make_unique<extensions::DevToolsPageHandler>()); registry->RegisterHandler( std::make_unique<extensions::MinimumChromeVersionChecker>()); } diff --git a/shell/common/gin_converters/base_converter.h b/shell/common/gin_converters/base_converter.h index 56c420d77d817..37aa2bd34ddfe 100644 --- a/shell/common/gin_converters/base_converter.h +++ b/shell/common/gin_converters/base_converter.h @@ -35,6 +35,8 @@ struct Converter<base::TerminationStatus> { case base::TERMINATION_STATUS_INTEGRITY_FAILURE: return gin::ConvertToV8(isolate, "integrity-failure"); #endif + case base::TERMINATION_STATUS_EVICTED_FOR_MEMORY: + return gin::ConvertToV8(isolate, "memory-eviction"); case base::TERMINATION_STATUS_MAX_ENUM: NOTREACHED(); } diff --git a/shell/common/gin_converters/callback_converter.h b/shell/common/gin_converters/callback_converter.h index ca2bc900c0d66..1fe807de6c78b 100644 --- a/shell/common/gin_converters/callback_converter.h +++ b/shell/common/gin_converters/callback_converter.h @@ -8,6 +8,7 @@ #include <utility> #include "base/functional/callback_helpers.h" +#include "shell/common/callback_util.h" #include "shell/common/gin_helper/callback.h" namespace gin { @@ -41,7 +42,7 @@ struct Converter<base::OnceCallback<Sig>> { static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, base::OnceCallback<Sig> in) { return gin::ConvertToV8(isolate, - base::AdaptCallbackForRepeating(std::move(in))); + electron::AdaptCallbackForRepeating(std::move(in))); } static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, diff --git a/shell/common/gin_converters/content_converter.cc b/shell/common/gin_converters/content_converter.cc index ee21095df3546..69c88e1427508 100644 --- a/shell/common/gin_converters/content_converter.cc +++ b/shell/common/gin_converters/content_converter.cc @@ -10,6 +10,7 @@ #include "base/containers/fixed_flat_map.h" #include "components/input/native_web_keyboard_event.h" #include "content/public/browser/context_menu_params.h" +#include "content/public/browser/permission_result.h" #include "content/public/browser/web_contents.h" #include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/web_contents_permission_helper.h" @@ -128,18 +129,22 @@ v8::Local<v8::Value> Converter<ContextMenuParamsWithRenderFrameHost>::ToV8( } // static -bool Converter<blink::mojom::PermissionStatus>::FromV8( +bool Converter<content::PermissionResult>::FromV8( v8::Isolate* isolate, v8::Local<v8::Value> val, - blink::mojom::PermissionStatus* out) { + content::PermissionResult* out) { bool result; if (!ConvertFromV8(isolate, val, &result)) return false; if (result) - *out = blink::mojom::PermissionStatus::GRANTED; + *out = + content::PermissionResult(blink::mojom::PermissionStatus::GRANTED, + content::PermissionStatusSource::UNSPECIFIED); else - *out = blink::mojom::PermissionStatus::DENIED; + *out = + content::PermissionResult(blink::mojom::PermissionStatus::DENIED, + content::PermissionStatusSource::UNSPECIFIED); return true; } diff --git a/shell/common/gin_converters/content_converter.h b/shell/common/gin_converters/content_converter.h index 2fa5f7f118df9..d9bab26dacba3 100644 --- a/shell/common/gin_converters/content_converter.h +++ b/shell/common/gin_converters/content_converter.h @@ -17,6 +17,7 @@ namespace content { struct ContextMenuParams; +struct PermissionResult; class RenderFrameHost; class WebContents; } // namespace content @@ -53,10 +54,10 @@ struct Converter<ui::mojom::MenuSourceType> { }; template <> -struct Converter<blink::mojom::PermissionStatus> { +struct Converter<content::PermissionResult> { static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, - blink::mojom::PermissionStatus* out); + content::PermissionResult* out); }; template <> diff --git a/shell/common/gin_converters/frame_converter.cc b/shell/common/gin_converters/frame_converter.cc index f02b44014a6a8..306daa2415139 100644 --- a/shell/common/gin_converters/frame_converter.cc +++ b/shell/common/gin_converters/frame_converter.cc @@ -12,12 +12,6 @@ namespace gin { -namespace { - -v8::Persistent<v8::ObjectTemplate> rfh_templ; - -} // namespace - // static v8::Local<v8::Value> Converter<content::FrameTreeNodeId>::ToV8( v8::Isolate* isolate, @@ -59,17 +53,11 @@ Converter<gin_helper::AccessorValue<content::RenderFrameHost*>>::ToV8( const int32_t process_id = rfh->GetProcess()->GetID().GetUnsafeValue(); const int routing_id = rfh->GetRoutingID(); - if (rfh_templ.IsEmpty()) { - v8::EscapableHandleScope inner(isolate); - v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate); - local->SetInternalFieldCount(2); - rfh_templ.Reset(isolate, inner.Escape(local)); - } + v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); + templ->SetInternalFieldCount(2); v8::Local<v8::Object> rfh_obj = - v8::Local<v8::ObjectTemplate>::New(isolate, rfh_templ) - ->NewInstance(isolate->GetCurrentContext()) - .ToLocalChecked(); + templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); rfh_obj->SetInternalField(0, v8::Number::New(isolate, process_id)); rfh_obj->SetInternalField(1, v8::Number::New(isolate, routing_id)); diff --git a/shell/common/gin_converters/gfx_converter.cc b/shell/common/gin_converters/gfx_converter.cc index 8984d20aa784c..19f3d49180d4f 100644 --- a/shell/common/gin_converters/gfx_converter.cc +++ b/shell/common/gin_converters/gfx_converter.cc @@ -16,6 +16,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/resize_utils.h" #include "ui/gfx/geometry/size.h" @@ -455,6 +456,12 @@ bool Converter<gfx::ColorSpace>::FromV8(v8::Isolate* isolate, // Get primaries if (dict.Get("primaries", &primaries_str)) { + if (primaries_str == "custom") { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "'custom' not supported."); + return false; + } + if (primaries_str == "bt709") primaries = gfx::ColorSpace::PrimaryID::BT709; else if (primaries_str == "bt470m") @@ -485,18 +492,18 @@ bool Converter<gfx::ColorSpace>::FromV8(v8::Isolate* isolate, primaries = gfx::ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN; else if (primaries_str == "ebu-3213-e") primaries = gfx::ColorSpace::PrimaryID::EBU_3213_E; - - if (primaries_str == "custom") { - gin_helper::ErrorThrower(isolate).ThrowTypeError( - "'custom' not supported."); - return false; - } else { + else primaries = gfx::ColorSpace::PrimaryID::INVALID; - } } // Get transfer if (dict.Get("transfer", &transfer_str)) { + if (transfer_str == "custom" || transfer_str == "custom-hdr") { + gin_helper::ErrorThrower(isolate).ThrowTypeError( + "'custom', 'custom-hdr' not supported."); + return false; + } + if (transfer_str == "bt709") transfer = gfx::ColorSpace::TransferID::BT709; else if (transfer_str == "bt709-apple") @@ -541,14 +548,8 @@ bool Converter<gfx::ColorSpace>::FromV8(v8::Isolate* isolate, transfer = gfx::ColorSpace::TransferID::LINEAR_HDR; else if (transfer_str == "scrgb-linear-80-nits") transfer = gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS; - - if (transfer_str == "custom" || transfer_str == "custom-hdr") { - gin_helper::ErrorThrower(isolate).ThrowTypeError( - "'custom', 'custom-hdr' not supported."); - return false; - } else { - primaries = gfx::ColorSpace::PrimaryID::INVALID; - } + else + transfer = gfx::ColorSpace::TransferID::INVALID; } // Get matrix diff --git a/shell/common/gin_converters/osr_converter.cc b/shell/common/gin_converters/osr_converter.cc index 55b94f855c424..82195f6a1ac79 100644 --- a/shell/common/gin_converters/osr_converter.cc +++ b/shell/common/gin_converters/osr_converter.cc @@ -16,7 +16,6 @@ #endif #include "shell/common/gin_converters/gfx_converter.h" #include "shell/common/gin_converters/optional_converter.h" -#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/node_includes.h" #include "shell/common/node_util.h" @@ -29,6 +28,8 @@ std::string OsrVideoPixelFormatToString(media::VideoPixelFormat format) { return "bgra"; case media::PIXEL_FORMAT_ABGR: return "rgba"; + case media::PIXEL_FORMAT_RGBAF16: + return "rgbaf16"; default: NOTREACHED(); } diff --git a/shell/common/gin_helper/arguments.cc b/shell/common/gin_helper/arguments.cc deleted file mode 100644 index 9047d26d6dec8..0000000000000 --- a/shell/common/gin_helper/arguments.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE.chromium file. - -#include <string_view> - -#include "shell/common/gin_helper/arguments.h" - -#include "v8/include/v8-exception.h" - -namespace gin_helper { - -void Arguments::ThrowError() const { - // Gin advances |next_| counter when conversion fails while we do not, so we - // have to manually advance the counter here to make gin report error with the - // correct index. - const_cast<Arguments*>(this)->Skip(); - gin::Arguments::ThrowError(); -} - -void Arguments::ThrowError(const std::string_view message) const { - isolate()->ThrowException( - v8::Exception::Error(gin::StringToV8(isolate(), message))); -} - -} // namespace gin_helper diff --git a/shell/common/gin_helper/arguments.h b/shell/common/gin_helper/arguments.h deleted file mode 100644 index eb79200972287..0000000000000 --- a/shell/common/gin_helper/arguments.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE.chromium file. - -#ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_ARGUMENTS_H_ -#define ELECTRON_SHELL_COMMON_GIN_HELPER_ARGUMENTS_H_ - -#include <string_view> - -#include "gin/arguments.h" - -namespace gin_helper { - -// Provides additional APIs to the gin::Arguments class. -class Arguments : public gin::Arguments { - public: - // Get the next argument, if conversion to T fails then state is unchanged. - // - // This is difference from gin::Arguments::GetNext which always advances the - // |next_| counter no matter whether the conversion succeeds. - template <typename T> - bool GetNext(T* out) { - v8::Local<v8::Value> val = PeekNext(); - if (val.IsEmpty()) - return false; - if (!gin::ConvertFromV8(isolate(), val, out)) - return false; - Skip(); - return true; - } - - // Gin always returns true when converting V8 value to boolean, we do not want - // this behavior when parsing parameters. - bool GetNext(bool* out) { - v8::Local<v8::Value> val = PeekNext(); - if (val.IsEmpty() || !val->IsBoolean()) - return false; - *out = val->BooleanValue(isolate()); - Skip(); - return true; - } - - // Throw error with custom error message. - void ThrowError() const; - void ThrowError(std::string_view message) const; - - private: - // MUST NOT ADD ANY DATA MEMBER. -}; - -} // namespace gin_helper - -#endif // ELECTRON_SHELL_COMMON_GIN_HELPER_ARGUMENTS_H_ diff --git a/shell/common/gin_helper/callback.cc b/shell/common/gin_helper/callback.cc index b5342ebcb7238..fb56f95a01bb2 100644 --- a/shell/common/gin_helper/callback.cc +++ b/shell/common/gin_helper/callback.cc @@ -28,15 +28,14 @@ struct TranslatorHolder { delete data.GetParameter(); } + static gin::DeprecatedWrapperInfo kWrapperInfo; + v8::Global<v8::External> handle; Translator translator; }; -// Cached JavaScript version of |CallTranslator|. -// v8::Persistent handles are bound to a specific v8::Isolate. Require -// initializing per-thread to avoid using the wrong isolate from service -// worker preload scripts. -thread_local v8::Persistent<v8::FunctionTemplate> g_call_translator; +gin::DeprecatedWrapperInfo TranslatorHolder::kWrapperInfo = { + gin::kEmbedderNativeGin}; void CallTranslator(v8::Local<v8::External> external, v8::Local<v8::Object> state, @@ -117,14 +116,17 @@ v8::Local<v8::Function> SafeV8Function::NewHandle(v8::Isolate* isolate) const { v8::Local<v8::Value> CreateFunctionFromTranslator(v8::Isolate* isolate, const Translator& translator, bool one_time) { + gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); + auto* wrapper_info = &TranslatorHolder::kWrapperInfo; + v8::Local<v8::FunctionTemplate> constructor = + data->DeprecatedGetFunctionTemplate(wrapper_info); // The FunctionTemplate is cached. - if (g_call_translator.IsEmpty()) - g_call_translator.Reset( - isolate, - CreateFunctionTemplate(isolate, base::BindRepeating(&CallTranslator))); + if (constructor.IsEmpty()) { + constructor = + CreateFunctionTemplate(isolate, base::BindRepeating(&CallTranslator)); + data->DeprecatedSetFunctionTemplate(wrapper_info, constructor); + } - v8::Local<v8::FunctionTemplate> call_translator = - v8::Local<v8::FunctionTemplate>::New(isolate, g_call_translator); auto* holder = new TranslatorHolder(isolate); holder->translator = translator; auto state = gin::Dictionary::CreateEmpty(isolate); @@ -132,7 +134,7 @@ v8::Local<v8::Value> CreateFunctionFromTranslator(v8::Isolate* isolate, state.Set("oneTime", true); auto context = isolate->GetCurrentContext(); return BindFunctionWith( - isolate, context, call_translator->GetFunction(context).ToLocalChecked(), + isolate, context, constructor->GetFunction(context).ToLocalChecked(), holder->handle.Get(isolate), gin::ConvertToV8(isolate, state)); } diff --git a/shell/common/gin_helper/constructible.h b/shell/common/gin_helper/constructible.h index dc07046269e1d..1f6db4bc8cb45 100644 --- a/shell/common/gin_helper/constructible.h +++ b/shell/common/gin_helper/constructible.h @@ -43,7 +43,7 @@ class Constructible { v8::Isolate* const isolate, v8::Local<v8::Context> context) { gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); - auto* wrapper_info = &T::kWrapperInfo; + auto* const wrapper_info = &T::kWrapperInfo; v8::Local<v8::FunctionTemplate> constructor = data->DeprecatedGetFunctionTemplate(wrapper_info); if (constructor.IsEmpty()) { @@ -67,7 +67,7 @@ class Constructible { static v8::Local<v8::Function> GetConstructor( v8::Isolate* const isolate, v8::Local<v8::Context> context, - gin::WrapperInfo* wrapper_info) { + const gin::WrapperInfo* const wrapper_info) { gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); v8::Local<v8::FunctionTemplate> constructor = data->GetFunctionTemplate(wrapper_info); diff --git a/shell/common/gin_helper/constructor.h b/shell/common/gin_helper/constructor.h index 7ae5e096c15b7..2e406a0dbb92f 100644 --- a/shell/common/gin_helper/constructor.h +++ b/shell/common/gin_helper/constructor.h @@ -40,7 +40,7 @@ class GinArgumentsToTuple { // Invoke a callback with arguments extracted from `args`. template <typename... Types> WrappableBase* InvokeFactory( - gin::Arguments* args, + gin::Arguments* const args, const base::RepeatingCallback<WrappableBase*(Types...)>& callback) { auto [ok, tup] = GinArgumentsToTuple<Types...>::GetArgs(args); if (!ok) @@ -52,10 +52,10 @@ WrappableBase* InvokeFactory( template <typename Sig> void InvokeNew(const base::RepeatingCallback<Sig>& factory, - v8::Isolate* isolate, - gin_helper::Arguments* args) { + v8::Isolate* const isolate, + gin::Arguments* const args) { if (!args->IsConstructCall()) { - args->ThrowError("Requires constructor call"); + args->ThrowTypeError("Requires constructor call"); return; } diff --git a/shell/common/gin_helper/destroyable.cc b/shell/common/gin_helper/destroyable.cc index 51758bf3e8d6d..63f9516f02857 100644 --- a/shell/common/gin_helper/destroyable.cc +++ b/shell/common/gin_helper/destroyable.cc @@ -30,8 +30,10 @@ void DestroyFunc(const v8::FunctionCallbackInfo<v8::Value>& info) { // TODO(zcbenz): gin_helper::Wrappable will be removed. delete static_cast<gin_helper::WrappableBase*>( - holder->GetAlignedPointerFromInternalField(0)); - holder->SetAlignedPointerInInternalField(0, nullptr); + holder->GetAlignedPointerFromInternalField( + 0, v8::kEmbedderDataTypeTagDefault)); + holder->SetAlignedPointerInInternalField(0, nullptr, + v8::kEmbedderDataTypeTagDefault); } void IsDestroyedFunc(const v8::FunctionCallbackInfo<v8::Value>& info) { @@ -46,7 +48,8 @@ bool Destroyable::IsDestroyed(v8::Local<v8::Object> object) { // An object is considered destroyed if it has no internal pointer or its // internal has been destroyed. return object->InternalFieldCount() == 0 || - object->GetAlignedPointerFromInternalField(0) == nullptr; + object->GetAlignedPointerFromInternalField( + 0, v8::kEmbedderDataTypeTagDefault) == nullptr; } // static diff --git a/shell/common/gin_helper/event_emitter_caller.cc b/shell/common/gin_helper/event_emitter_caller.cc index d21a3fb77a6fe..a64f36d6144b9 100644 --- a/shell/common/gin_helper/event_emitter_caller.cc +++ b/shell/common/gin_helper/event_emitter_caller.cc @@ -11,7 +11,7 @@ namespace gin_helper::internal { v8::Local<v8::Value> CallMethodWithArgs( v8::Isolate* isolate, v8::Local<v8::Object> obj, - const char* method, + const std::string_view method, const base::span<v8::Local<v8::Value>> args) { v8::EscapableHandleScope handle_scope{isolate}; @@ -27,8 +27,9 @@ v8::Local<v8::Value> CallMethodWithArgs( v8::MicrotasksScope::kRunMicrotasks); // node::MakeCallback will also run pending tasks in Node.js. - v8::MaybeLocal<v8::Value> ret = node::MakeCallback( - isolate, obj, method, args.size(), args.data(), {0, 0}); + v8::MaybeLocal<v8::Value> ret = + node::MakeCallback(isolate, obj, gin::StringToV8(isolate, method), + args.size(), args.data(), {0, 0}); // If the JS function throws an exception (doesn't return a value) the result // of MakeCallback will be empty and therefore ToLocal will be false, in this diff --git a/shell/common/gin_helper/event_emitter_caller.h b/shell/common/gin_helper/event_emitter_caller.h index 25c935d660cbf..5ac2f40363180 100644 --- a/shell/common/gin_helper/event_emitter_caller.h +++ b/shell/common/gin_helper/event_emitter_caller.h @@ -6,6 +6,7 @@ #define ELECTRON_SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_CALLER_H_ #include <array> +#include <string_view> #include <utility> #include "base/containers/span.h" @@ -20,17 +21,17 @@ namespace internal { v8::Local<v8::Value> CallMethodWithArgs(v8::Isolate* isolate, v8::Local<v8::Object> obj, - const char* method, + std::string_view method, base::span<v8::Local<v8::Value>> args); } // namespace internal // obj.emit(name, args...); // The caller is responsible of allocating a HandleScope. -template <typename StringType, typename... Args> +template <typename... Args> v8::Local<v8::Value> EmitEvent(v8::Isolate* isolate, v8::Local<v8::Object> obj, - const StringType& name, + const std::string_view name, Args&&... args) { v8::EscapableHandleScope scope{isolate}; std::array<v8::Local<v8::Value>, 1U + sizeof...(args)> converted_args = { @@ -45,7 +46,7 @@ v8::Local<v8::Value> EmitEvent(v8::Isolate* isolate, template <typename... Args> v8::Local<v8::Value> CustomEmit(v8::Isolate* isolate, v8::Local<v8::Object> object, - const char* custom_emit, + const std::string_view custom_emit, Args&&... args) { v8::EscapableHandleScope scope{isolate}; std::array<v8::Local<v8::Value>, sizeof...(args)> converted_args = { @@ -58,7 +59,7 @@ v8::Local<v8::Value> CustomEmit(v8::Isolate* isolate, template <typename T, typename... Args> v8::Local<v8::Value> CallMethod(v8::Isolate* isolate, gin_helper::DeprecatedWrappable<T>* object, - const char* method_name, + const std::string_view method_name, Args&&... args) { v8::EscapableHandleScope scope(isolate); v8::Local<v8::Object> v8_object; @@ -71,7 +72,7 @@ v8::Local<v8::Value> CallMethod(v8::Isolate* isolate, template <typename T, typename... Args> v8::Local<v8::Value> CallMethod(gin_helper::DeprecatedWrappable<T>* object, - const char* method_name, + const std::string_view method_name, Args&&... args) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); return CallMethod(isolate, object, method_name, std::forward<Args>(args)...); @@ -80,7 +81,7 @@ v8::Local<v8::Value> CallMethod(gin_helper::DeprecatedWrappable<T>* object, template <typename T, typename... Args> v8::Local<v8::Value> CallMethod(v8::Isolate* isolate, gin::Wrappable<T>* object, - const char* method_name, + const std::string_view method_name, Args&&... args) { v8::EscapableHandleScope scope(isolate); v8::Local<v8::Object> v8_object; @@ -93,7 +94,7 @@ v8::Local<v8::Value> CallMethod(v8::Isolate* isolate, template <typename T, typename... Args> v8::Local<v8::Value> CallMethod(gin::Wrappable<T>* object, - const char* method_name, + const std::string_view method_name, Args&&... args) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); return CallMethod(isolate, object, method_name, std::forward<Args>(args)...); diff --git a/shell/common/gin_helper/function_template.h b/shell/common/gin_helper/function_template.h index 43bace908b734..c9d82747ceea4 100644 --- a/shell/common/gin_helper/function_template.h +++ b/shell/common/gin_helper/function_template.h @@ -13,7 +13,6 @@ #include "base/memory/raw_ptr.h" #include "gin/arguments.h" #include "gin/per_isolate_data.h" -#include "shell/common/gin_helper/arguments.h" #include "shell/common/gin_helper/destroyable.h" #include "shell/common/gin_helper/error_thrower.h" #include "v8/include/v8-context.h" @@ -154,15 +153,6 @@ inline bool GetNextArgument(gin::Arguments* args, return true; } -// Electron-specific GetNextArgument that supports the gin_helper::Arguments. -inline bool GetNextArgument(gin::Arguments* args, - const InvokerOptions& invoker_options, - bool is_first, - gin_helper::Arguments** result) { - *result = static_cast<gin_helper::Arguments*>(args); - return true; -} - // For advanced use cases, we allow callers to request the unparsed Arguments // object and poke around in it directly. inline bool GetNextArgument(gin::Arguments* args, diff --git a/shell/common/gin_helper/trackable_object.h b/shell/common/gin_helper/trackable_object.h index bedd6352ab2f2..41e5406327f3b 100644 --- a/shell/common/gin_helper/trackable_object.h +++ b/shell/common/gin_helper/trackable_object.h @@ -61,7 +61,8 @@ class TrackableObject : public TrackableObjectBase, public EventEmitter<T> { v8::HandleScope scope(gin_helper::Wrappable<T>::isolate()); v8::Local<v8::Object> wrapper = gin_helper::Wrappable<T>::GetWrapper(); if (!wrapper.IsEmpty()) { - wrapper->SetAlignedPointerInInternalField(0, nullptr); + wrapper->SetAlignedPointerInInternalField( + 0, nullptr, v8::kEmbedderDataTypeTagDefault); gin_helper::WrappableBase::wrapper_.ClearWeak(); } } @@ -70,7 +71,8 @@ class TrackableObject : public TrackableObjectBase, public EventEmitter<T> { v8::HandleScope scope(gin_helper::Wrappable<T>::isolate()); v8::Local<v8::Object> wrapper = gin_helper::Wrappable<T>::GetWrapper(); return wrapper->InternalFieldCount() == 0 || - wrapper->GetAlignedPointerFromInternalField(0) == nullptr; + wrapper->GetAlignedPointerFromInternalField( + 0, v8::kEmbedderDataTypeTagDefault) == nullptr; } // Finds out the TrackableObject from its ID in weak map. diff --git a/shell/common/gin_helper/wrappable.cc b/shell/common/gin_helper/wrappable.cc index 94dbe2ffbe21e..a8a6f4ad0c1c0 100644 --- a/shell/common/gin_helper/wrappable.cc +++ b/shell/common/gin_helper/wrappable.cc @@ -22,7 +22,8 @@ bool IsValidWrappable(const v8::Local<v8::Value>& val, const gin::DeprecatedWrapperInfo* info = static_cast<gin::DeprecatedWrapperInfo*>( - port->GetAlignedPointerFromInternalField(gin::kWrapperInfoIndex)); + port->GetAlignedPointerFromInternalField( + gin::kWrapperInfoIndex, v8::kEmbedderDataTypeTagDefault)); if (info != wrapper_info) return false; @@ -36,7 +37,8 @@ WrappableBase::~WrappableBase() { return; v8::HandleScope scope(isolate()); - GetWrapper()->SetAlignedPointerInInternalField(0, nullptr); + GetWrapper()->SetAlignedPointerInInternalField( + 0, nullptr, v8::kEmbedderDataTypeTagDefault); wrapper_.ClearWeak(); wrapper_.Reset(); } @@ -48,7 +50,7 @@ v8::Local<v8::Object> WrappableBase::GetWrapper() const { return {}; } -void WrappableBase::InitWithArgs(gin::Arguments* args) { +void WrappableBase::InitWithArgs(const gin::Arguments* const args) { v8::Local<v8::Object> holder; args->GetHolder(&holder); InitWith(args->isolate(), holder); @@ -58,7 +60,8 @@ void WrappableBase::InitWith(v8::Isolate* isolate, v8::Local<v8::Object> wrapper) { CHECK(wrapper_.IsEmpty()); isolate_ = isolate; - wrapper->SetAlignedPointerInInternalField(0, this); + wrapper->SetAlignedPointerInInternalField(0, this, + v8::kEmbedderDataTypeTagDefault); wrapper_.Reset(isolate, wrapper); wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kInternalFields); @@ -158,9 +161,10 @@ v8::MaybeLocal<v8::Object> DeprecatedWrappableBase::GetWrapperImpl( return v8::MaybeLocal<v8::Object>(wrapper); } - int indices[] = {gin::kWrapperInfoIndex, gin::kEncodedValueIndex}; - void* values[] = {info, this}; - wrapper->SetAlignedPointerInInternalFields(2, indices, values); + wrapper->SetAlignedPointerInInternalField(gin::kWrapperInfoIndex, info, + v8::kEmbedderDataTypeTagDefault); + wrapper->SetAlignedPointerInInternalField(gin::kEncodedValueIndex, this, + v8::kEmbedderDataTypeTagDefault); wrapper_.Reset(isolate, wrapper); wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kInternalFields); @@ -180,7 +184,8 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val) { v8::Local<v8::Object> obj = val.As<v8::Object>(); if (obj->InternalFieldCount() != 1) return nullptr; - return obj->GetAlignedPointerFromInternalField(0); + return obj->GetAlignedPointerFromInternalField( + 0, v8::kEmbedderDataTypeTagDefault); } void* FromV8Impl(v8::Isolate* isolate, @@ -205,7 +210,8 @@ void* FromV8Impl(v8::Isolate* isolate, return nullptr; } - return obj->GetAlignedPointerFromInternalField(gin::kEncodedValueIndex); + return obj->GetAlignedPointerFromInternalField( + gin::kEncodedValueIndex, v8::kEmbedderDataTypeTagDefault); } } // namespace internal @@ -219,7 +225,8 @@ DeprecatedWrapperInfo* DeprecatedWrapperInfo::From( if (object->InternalFieldCount() != kNumberOfInternalFields) return NULL; DeprecatedWrapperInfo* info = static_cast<DeprecatedWrapperInfo*>( - object->GetAlignedPointerFromInternalField(kWrapperInfoIndex)); + object->GetAlignedPointerFromInternalField( + kWrapperInfoIndex, v8::kEmbedderDataTypeTagDefault)); return info->embedder == kEmbedderNativeGin ? info : NULL; } diff --git a/shell/common/gin_helper/wrappable_base.h b/shell/common/gin_helper/wrappable_base.h index 35a9de3f21d14..5d63a148ab606 100644 --- a/shell/common/gin_helper/wrappable_base.h +++ b/shell/common/gin_helper/wrappable_base.h @@ -51,7 +51,7 @@ class WrappableBase { virtual void InitWith(v8::Isolate* isolate, v8::Local<v8::Object> wrapper); // Helper to init with arguments. - void InitWithArgs(gin::Arguments* args); + void InitWithArgs(const gin::Arguments* args); v8::Global<v8::Object> wrapper_; // Weak diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 0f4ee0539285f..3b887fa6ab303 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -24,6 +24,7 @@ #include "base/trace_event/trace_event.h" #include "chrome/common/chrome_version.h" #include "content/public/common/content_paths.h" +#include "content/public/renderer/render_frame.h" #include "electron/buildflags/buildflags.h" #include "electron/electron_version.h" #include "electron/fuses.h" @@ -39,9 +40,13 @@ #include "shell/common/mac/main_application_bundle.h" #include "shell/common/node_includes.h" #include "shell/common/node_util.h" +#include "shell/common/options_switches.h" +#include "shell/common/platform_util.h" #include "shell/common/process_util.h" #include "shell/common/world_ids.h" +#include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/web/web_local_frame.h" +#include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h" // nogncheck #include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h" // nogncheck #include "third_party/electron_node/src/debug_utils.h" #include "third_party/electron_node/src/module_wrap.h" @@ -94,6 +99,7 @@ V(electron_common_environment) \ V(electron_common_features) \ V(electron_common_native_image) \ + V(electron_common_shared_texture) \ V(electron_common_shell) \ V(electron_common_v8_util) @@ -211,6 +217,61 @@ bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context, return node::AllowWasmCodeGenerationCallback(context, source); } +enum ESMHandlerPlatform { + kNone, + kNodeJS, + kBlink, +}; + +static ESMHandlerPlatform SelectESMHandlerPlatform( + v8::Local<v8::Context> context, + v8::Local<v8::Data> raw_host_defined_options) { + if (node::Environment::GetCurrent(context) == nullptr) { + if (electron::IsBrowserProcess() || electron::IsUtilityProcess()) + return ESMHandlerPlatform::kNone; + + return ESMHandlerPlatform::kBlink; + } + + if (!electron::IsRendererProcess()) + return ESMHandlerPlatform::kNodeJS; + + blink::WebLocalFrame* frame = blink::WebLocalFrame::FrameForContext(context); + + if (frame == nullptr) + return ESMHandlerPlatform::kBlink; + + auto prefs = content::RenderFrame::FromWebFrame(frame)->GetBlinkPreferences(); + + // If we're running with contextIsolation enabled in the renderer process, + // fall back to Blink's logic when the frame is not in the isolated world. + if (prefs.context_isolation) { + return frame->GetScriptContextWorldId(context) == + electron::WorldIDs::ISOLATED_WORLD_ID + ? ESMHandlerPlatform::kNodeJS + : ESMHandlerPlatform::kBlink; + } + + if (raw_host_defined_options.IsEmpty() || + !raw_host_defined_options->IsFixedArray()) { + return ESMHandlerPlatform::kBlink; + } + + // Since the routing is based on the `host_defined_options` length - + // make sure that Node's host defined options are different from Blink's. + static_assert( + static_cast<size_t>(node::loader::HostDefinedOptions::kLength) != + blink::ReferrerScriptInfo::HostDefinedOptionsIndex::kLength); + + // Use Node.js resolver only if host options were created by it. + auto options = v8::Local<v8::FixedArray>::Cast(raw_host_defined_options); + if (options->Length() == node::loader::HostDefinedOptions::kLength) { + return ESMHandlerPlatform::kNodeJS; + } + + return ESMHandlerPlatform::kBlink; +} + v8::MaybeLocal<v8::Promise> HostImportModuleWithPhaseDynamically( v8::Local<v8::Context> context, v8::Local<v8::Data> v8_host_defined_options, @@ -218,33 +279,20 @@ v8::MaybeLocal<v8::Promise> HostImportModuleWithPhaseDynamically( v8::Local<v8::String> v8_specifier, v8::ModuleImportPhase import_phase, v8::Local<v8::FixedArray> v8_import_attributes) { - if (node::Environment::GetCurrent(context) == nullptr) { - if (electron::IsBrowserProcess() || electron::IsUtilityProcess()) - return {}; - return blink::V8Initializer::HostImportModuleWithPhaseDynamically( - context, v8_host_defined_options, v8_referrer_resource_url, - v8_specifier, import_phase, v8_import_attributes); - } - - // If we're running with contextIsolation enabled in the renderer process, - // fall back to Blink's logic. - if (electron::IsRendererProcess()) { - blink::WebLocalFrame* frame = - blink::WebLocalFrame::FrameForContext(context); - if (!frame || frame->GetScriptContextWorldId(context) != - electron::WorldIDs::ISOLATED_WORLD_ID) { + switch (SelectESMHandlerPlatform(context, v8_host_defined_options)) { + case ESMHandlerPlatform::kBlink: return blink::V8Initializer::HostImportModuleWithPhaseDynamically( context, v8_host_defined_options, v8_referrer_resource_url, v8_specifier, import_phase, v8_import_attributes); - } + case ESMHandlerPlatform::kNodeJS: + CHECK(import_phase == v8::ModuleImportPhase::kEvaluation); + return node::loader::ImportModuleDynamicallyWithPhase( + context, v8_host_defined_options, v8_referrer_resource_url, + v8_specifier, import_phase, v8_import_attributes); + case ESMHandlerPlatform::kNone: + default: + return {}; } - - // TODO: Switch to node::loader::ImportModuleDynamicallyWithPhase - // once we land the Node.js version that has it in upstream. - CHECK(import_phase == v8::ModuleImportPhase::kEvaluation); - return node::loader::ImportModuleDynamically( - context, v8_host_defined_options, v8_referrer_resource_url, v8_specifier, - v8_import_attributes); } v8::MaybeLocal<v8::Promise> HostImportModuleDynamically( @@ -504,7 +552,7 @@ node::IsolateData* NodeBindings::isolate_data( } auto* isolate_data = static_cast<node::IsolateData*>( context->GetAlignedPointerFromEmbedderData( - kElectronContextEmbedderDataIndex)); + kElectronContextEmbedderDataIndex, v8::kEmbedderDataTypeTagDefault)); CHECK(isolate_data); CHECK(isolate_data->event_loop()); return isolate_data; @@ -625,6 +673,19 @@ void NodeBindings::Initialize(v8::Isolate* const isolate, if (!fuses::IsNodeOptionsEnabled()) process_flags |= node::ProcessInitializationFlags::kDisableNodeOptionsEnv; + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kNoStdioInit)) { + process_flags |= node::ProcessInitializationFlags::kNoStdioInitialization; + } else { +#if BUILDFLAG(IS_WIN) + if (!platform_util::IsNulDeviceEnabled()) { + LOG(FATAL) << "Unable to open nul device needed for initialization," + "aborting startup. As a workaround, try starting with --" + << switches::kNoStdioInit; + } +#endif + } + std::shared_ptr<node::InitializationResult> result = node::InitializeOncePerProcess( args, @@ -706,7 +767,8 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment( auto* isolate_data = node::CreateIsolateData(isolate, uv_loop_, platform); isolate_data->max_young_gen_size = max_young_generation_size; context->SetAlignedPointerInEmbedderData(kElectronContextEmbedderDataIndex, - static_cast<void*>(isolate_data)); + static_cast<void*>(isolate_data), + v8::kEmbedderDataTypeTagDefault); uint64_t env_flags = node::EnvironmentFlags::kDefaultFlags | node::EnvironmentFlags::kHideConsoleWindows | @@ -831,7 +893,8 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment( // Since we're about to free `isolate_data`, clear that entry v8::HandleScope handle_scope{isolate}; context.Get(isolate)->SetAlignedPointerInEmbedderData( - kElectronContextEmbedderDataIndex, nullptr); + kElectronContextEmbedderDataIndex, nullptr, + v8::kEmbedderDataTypeTagDefault); context.Reset(); node::FreeEnvironment(nenv); diff --git a/shell/common/node_bindings_mac.cc b/shell/common/node_bindings_mac.cc index 4afada977aee6..eaddf9be1f114 100644 --- a/shell/common/node_bindings_mac.cc +++ b/shell/common/node_bindings_mac.cc @@ -2,16 +2,10 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove FD_ZERO and convert code to safer -// constructs. -#pragma allow_unsafe_buffers -#endif - #include "shell/common/node_bindings_mac.h" #include <errno.h> -#include <sys/select.h> +#include <poll.h> #include <sys/sysctl.h> #include <sys/time.h> #include <sys/types.h> @@ -23,24 +17,18 @@ NodeBindingsMac::NodeBindingsMac(BrowserEnvironment browser_env) void NodeBindingsMac::PollEvents() { auto* const event_loop = uv_loop(); + // uv_backend_timeout returns milliseconds or -1 for infinite wait. + const int backend_fd = uv_backend_fd(event_loop); + const int timeout_ms = uv_backend_timeout(event_loop); // -1 => infinite - struct timeval tv; - int timeout = uv_backend_timeout(event_loop); - if (timeout != -1) { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - } - - fd_set readset; - int fd = uv_backend_fd(event_loop); - FD_ZERO(&readset); - FD_SET(fd, &readset); + struct pollfd pfd; + pfd.fd = backend_fd; + pfd.events = POLLIN; + pfd.revents = 0; - // Wait for new libuv events. int r; do { - r = select(fd + 1, &readset, nullptr, nullptr, - timeout == -1 ? nullptr : &tv); + r = poll(&pfd, 1, timeout_ms); } while (r == -1 && errno == EINTR); } diff --git a/shell/common/node_util.cc b/shell/common/node_util.cc index fb763208c3443..233cbeeb2d884 100644 --- a/shell/common/node_util.cc +++ b/shell/common/node_util.cc @@ -8,8 +8,11 @@ #include "base/containers/to_value_list.h" #include "base/json/json_writer.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/no_destructor.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" +#include "base/threading/thread_local.h" #include "base/values.h" #include "gin/converter.h" #include "shell/browser/javascript_environment.h" @@ -28,9 +31,15 @@ v8::MaybeLocal<v8::Value> CompileAndCall( v8::LocalVector<v8::Value>* arguments) { v8::TryCatch try_catch{isolate}; - thread_local node::builtins::BuiltinLoader builtin_loader; - v8::MaybeLocal<v8::Function> compiled = builtin_loader.LookupAndCompile( - context, id, parameters, node::Realm::GetCurrent(context)); + static base::NoDestructor< + base::ThreadLocalOwnedPointer<node::builtins::BuiltinLoader>> + builtin_loader; + if (!builtin_loader->Get()) { + builtin_loader->Set(base::WrapUnique(new node::builtins::BuiltinLoader)); + } + v8::MaybeLocal<v8::Function> compiled = + builtin_loader->Get()->LookupAndCompile(context, id, parameters, + node::Realm::GetCurrent(context)); if (compiled.IsEmpty()) { // TODO(samuelmaddock): how can we get the compilation error message? diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h index b07313f033ec1..0868f6c01c6df 100644 --- a/shell/common/options_switches.h +++ b/shell/common/options_switches.h @@ -107,6 +107,19 @@ inline constexpr std::string_view kFocusable = "focusable"; // The WebPreferences. inline constexpr std::string_view kWebPreferences = "webPreferences"; +// Window state persistence for BaseWindow +inline constexpr std::string_view kWindowStatePersistence = + "windowStatePersistence"; + +// Identifier for the window provided by the application +inline constexpr std::string_view kName = "name"; + +// Whether to save the window bounds +inline constexpr std::string_view kBounds = "bounds"; + +// Whether to save the window display mode +inline constexpr std::string_view kDisplayMode = "displayMode"; + // Add a vibrancy effect to the browser window inline constexpr std::string_view kVibrancyType = "vibrancy"; @@ -183,6 +196,9 @@ inline constexpr std::string_view kOffscreen = "offscreen"; inline constexpr std::string_view kUseSharedTexture = "useSharedTexture"; +inline constexpr std::string_view kSharedTexturePixelFormat = + "sharedTexturePixelFormat"; + inline constexpr std::string_view kNodeIntegrationInSubFrames = "nodeIntegrationInSubFrames"; @@ -219,6 +235,8 @@ inline constexpr std::string_view kSpellcheck = "spellcheck"; inline constexpr std::string_view kEnableDeprecatedPaste = "enableDeprecatedPaste"; +inline constexpr std::string_view kModal = "modal"; + } // namespace options // Following are actually command line switches, should be moved to other files. @@ -306,6 +324,10 @@ inline constexpr base::cstring_view kDisableNTLMv2 = "disable-ntlm-v2"; inline constexpr base::cstring_view kServiceWorkerPreload = "service-worker-preload"; +// If set, flag node::ProcessInitializationFlags::kNoStdioInitialization would +// be set for node initialization. +inline constexpr base::cstring_view kNoStdioInit = "no-stdio-init"; + } // namespace switches } // namespace electron diff --git a/shell/common/platform_util.h b/shell/common/platform_util.h index c20376e5c3139..ccca2f778b4c3 100644 --- a/shell/common/platform_util.h +++ b/shell/common/platform_util.h @@ -47,6 +47,9 @@ void Beep(); #if BUILDFLAG(IS_WIN) // SHGetFolderPath calls not covered by Chromium bool GetFolderPath(int key, base::FilePath* result); + +// Check if nul device can be used. +bool IsNulDeviceEnabled(); #endif #if BUILDFLAG(IS_MAC) diff --git a/shell/common/platform_util_linux.cc b/shell/common/platform_util_linux.cc index d0f6ca904b12f..b5cedcff0ad3f 100644 --- a/shell/common/platform_util_linux.cc +++ b/shell/common/platform_util_linux.cc @@ -15,7 +15,6 @@ #include "base/cancelable_callback.h" #include "base/containers/contains.h" -#include "base/containers/map_util.h" #include "base/environment.h" #include "base/files/file_util.h" #include "base/files/scoped_file.h" @@ -59,8 +58,6 @@ const char kFreedesktopPortalName[] = "org.freedesktop.portal.Desktop"; const char kFreedesktopPortalPath[] = "/org/freedesktop/portal/desktop"; const char kFreedesktopPortalOpenURI[] = "org.freedesktop.portal.OpenURI"; -const char kOriginalXdgCurrentDesktopEnvVar[] = "ORIGINAL_XDG_CURRENT_DESKTOP"; - const char kMethodOpenDirectory[] = "OpenDirectory"; class ShowItemHelper { @@ -279,12 +276,6 @@ bool XDGUtil(const std::vector<std::string>& argv, base::nix::CreateLaunchOptionsWithXdgActivation(base::BindOnce( [](base::RepeatingClosure quit_loop, base::LaunchOptions* options_out, base::LaunchOptions options) { - // Correct the XDG_CURRENT_DESKTOP environment variable before calling - // XDG, in case it was changed for compatibility. - if (const auto* orig = base::FindOrNull( - options.environment, kOriginalXdgCurrentDesktopEnvVar)) - options.environment.emplace(base::nix::kXdgCurrentDesktopEnvVar, - *orig); *options_out = std::move(options); std::move(quit_loop).Run(); }, diff --git a/shell/common/platform_util_mac.mm b/shell/common/platform_util_mac.mm index 001d17b3fff94..153334f7f1d24 100644 --- a/shell/common/platform_util_mac.mm +++ b/shell/common/platform_util_mac.mm @@ -148,6 +148,12 @@ void OpenExternal(const GURL& url, return; } + // Check this to prevent system dialog from popping up on macOS Tahoe. + if (![[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:ns_url]) { + std::move(callback).Run("No application found to open URL"); + return; + } + NSWorkspaceOpenConfiguration* configuration = [NSWorkspaceOpenConfiguration configuration]; configuration.activates = options.activate; diff --git a/shell/common/platform_util_win.cc b/shell/common/platform_util_win.cc index a4333d7f1b4ff..b20b66db9c69d 100644 --- a/shell/common/platform_util_win.cc +++ b/shell/common/platform_util_win.cc @@ -12,6 +12,8 @@ #include <comdef.h> #include <commdlg.h> #include <dwmapi.h> +#include <fcntl.h> +#include <io.h> #include <objbase.h> #include <shellapi.h> #include <shlobj.h> @@ -450,4 +452,15 @@ void Beep() { MessageBeep(MB_OK); } +bool IsNulDeviceEnabled() { + bool ret = true; + int fd = _open("nul", _O_RDWR); + if (fd < 0) { + ret = false; + } else { + _close(fd); + } + return ret; +} + } // namespace platform_util diff --git a/shell/common/plugin_info.h b/shell/common/plugin_info.h index 94b5f009e08e8..fddfca63c3a04 100644 --- a/shell/common/plugin_info.h +++ b/shell/common/plugin_info.h @@ -7,7 +7,7 @@ #include <vector> -#include "content/public/common/content_plugin_info.h" +#include "content/public/common/webplugininfo.h" #include "electron/buildflags/buildflags.h" namespace electron { diff --git a/shell/common/skia_util.cc b/shell/common/skia_util.cc index c8b7236794489..3e1031a3742c4 100644 --- a/shell/common/skia_util.cc +++ b/shell/common/skia_util.cc @@ -24,7 +24,7 @@ #include "ui/gfx/image/image_util.h" #if BUILDFLAG(IS_WIN) -#include "ui/gfx/icon_util.h" +#include "ui/gfx/win/icon_util.h" #endif namespace electron::util { diff --git a/shell/renderer/api/electron_api_context_bridge.cc b/shell/renderer/api/electron_api_context_bridge.cc index e12b5c992ff3a..343fa0e70b2ea 100644 --- a/shell/renderer/api/electron_api_context_bridge.cc +++ b/shell/renderer/api/electron_api_context_bridge.cc @@ -269,10 +269,11 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContextInner( v8::TryCatch try_catch(isolate); v8::Local<v8::Context> source_context = global_source_context.Get(isolate); - val = PassValueToOtherContext( - source_context, global_destination_context.Get(isolate), result, - source_context->Global(), false, - BridgeErrorTarget::kDestination); + val = + PassValueToOtherContext(isolate, source_context, isolate, + global_destination_context.Get(isolate), + result, source_context->Global(), false, + BridgeErrorTarget::kDestination); if (try_catch.HasCaught()) { if (try_catch.Message().IsEmpty()) { proxied_promise->RejectWithErrorMessage( @@ -316,10 +317,11 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContextInner( v8::TryCatch try_catch(isolate); v8::Local<v8::Context> source_context = global_source_context.Get(isolate); - val = PassValueToOtherContext( - source_context, global_destination_context.Get(isolate), result, - source_context->Global(), false, - BridgeErrorTarget::kDestination); + val = + PassValueToOtherContext(isolate, source_context, isolate, + global_destination_context.Get(isolate), + result, source_context->Global(), false, + BridgeErrorTarget::kDestination); if (try_catch.HasCaught()) { if (try_catch.Message().IsEmpty()) { proxied_promise->RejectWithErrorMessage( @@ -419,10 +421,10 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContextInner( // Custom logic to "clone" VideoFrame references blink::VideoFrame* video_frame = - blink::V8VideoFrame::ToWrappable(source_context->GetIsolate(), value); + blink::V8VideoFrame::ToWrappable(source_isolate, value); if (video_frame != nullptr) { - blink::ScriptState* script_state = blink::ScriptState::ForCurrentRealm( - destination_context->GetIsolate()); + blink::ScriptState* script_state = + blink::ScriptState::ForCurrentRealm(destination_isolate); return v8::MaybeLocal<v8::Value>( blink::ToV8Traits<blink::VideoFrame>::ToV8(script_state, video_frame)); @@ -467,7 +469,9 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContextInner( } v8::MaybeLocal<v8::Value> PassValueToOtherContext( + v8::Isolate* source_isolate, v8::Local<v8::Context> source_context, + v8::Isolate* destination_isolate, v8::Local<v8::Context> destination_context, v8::Local<v8::Value> value, v8::Local<v8::Value> parent_value, @@ -484,9 +488,9 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext( blink::ExecutionContext::From(source_context); DCHECK(source_execution_context); return PassValueToOtherContextInner( - source_context->GetIsolate(), source_context, source_execution_context, - destination_context->GetIsolate(), destination_context, value, - parent_value, object_cache, support_dynamic_properties, 0, error_target); + source_isolate, source_context, source_execution_context, + destination_isolate, destination_context, value, parent_value, + object_cache, support_dynamic_properties, 0, error_target); } void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) { @@ -529,7 +533,7 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) { for (auto value : original_args) { auto arg = PassValueToOtherContext( - calling_context, func_owning_context, value, + isolate, calling_context, isolate, func_owning_context, value, calling_context->Global(), support_dynamic_properties, BridgeErrorTarget::kSource, &object_cache); if (arg.IsEmpty()) @@ -597,7 +601,7 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) { { v8::TryCatch try_catch(isolate); ret = PassValueToOtherContext( - func_owning_context, calling_context, + isolate, func_owning_context, isolate, calling_context, maybe_return_value.ToLocalChecked(), func_owning_context->Global(), support_dynamic_properties, BridgeErrorTarget::kDestination); if (try_catch.HasCaught()) { @@ -732,25 +736,24 @@ namespace { void ExposeAPI(v8::Isolate* isolate, v8::Local<v8::Context> source_context, + v8::Isolate* target_isolate, v8::Local<v8::Context> target_context, const std::string& key, - v8::Local<v8::Value> api, - gin_helper::Arguments* args) { + v8::Local<v8::Value> api) { DCHECK(!target_context.IsEmpty()); v8::Context::Scope target_context_scope(target_context); - gin_helper::Dictionary global(target_context->GetIsolate(), - target_context->Global()); + gin_helper::Dictionary global(target_isolate, target_context->Global()); if (global.Has(key)) { - args->ThrowError( + gin_helper::ErrorThrower{isolate}.ThrowError( "Cannot bind an API on top of an existing property on the window " "object"); return; } v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext( - source_context, target_context, api, source_context->Global(), false, - BridgeErrorTarget::kSource); + isolate, source_context, target_isolate, target_context, api, + source_context->Global(), false, BridgeErrorTarget::kSource); if (maybe_proxy.IsEmpty()) return; auto proxy = maybe_proxy.ToLocalChecked(); @@ -773,7 +776,8 @@ void ExposeAPI(v8::Isolate* isolate, // world ID. For service workers, Electron only supports one isolated // context and the main worker context. Anything else is invalid. v8::MaybeLocal<v8::Context> GetTargetContext(v8::Isolate* isolate, - const int world_id) { + const int world_id, + v8::Isolate* target_isolate) { v8::Local<v8::Context> source_context = isolate->GetCurrentContext(); v8::MaybeLocal<v8::Context> maybe_target_context; @@ -795,8 +799,8 @@ v8::MaybeLocal<v8::Context> GetTargetContext(v8::Isolate* isolate, isolate, "Isolated worlds are not supported in preload realms."))); return maybe_target_context; } - maybe_target_context = - electron::preload_realm::GetInitiatorContext(source_context); + maybe_target_context = electron::preload_realm::GetInitiatorContext( + source_context, target_isolate); } else { NOTREACHED(); } @@ -808,18 +812,18 @@ v8::MaybeLocal<v8::Context> GetTargetContext(v8::Isolate* isolate, void ExposeAPIInWorld(v8::Isolate* isolate, const int world_id, const std::string& key, - v8::Local<v8::Value> api, - gin_helper::Arguments* args) { + v8::Local<v8::Value> api) { TRACE_EVENT2("electron", "ContextBridge::ExposeAPIInWorld", "key", key, "worldId", world_id); v8::Local<v8::Context> source_context = isolate->GetCurrentContext(); CHECK(!source_context.IsEmpty()); + v8::Isolate* target_isolate = isolate; v8::MaybeLocal<v8::Context> maybe_target_context = - GetTargetContext(isolate, world_id); - if (maybe_target_context.IsEmpty()) + GetTargetContext(isolate, world_id, target_isolate); + if (maybe_target_context.IsEmpty() || !target_isolate) return; v8::Local<v8::Context> target_context = maybe_target_context.ToLocalChecked(); - ExposeAPI(isolate, source_context, target_context, key, api, args); + ExposeAPI(isolate, source_context, target_isolate, target_context, key, api); } gin_helper::Dictionary TraceKeyPath(const gin_helper::Dictionary& start, @@ -844,8 +848,7 @@ void OverrideGlobalValueFromIsolatedWorld( auto* frame = render_frame->GetWebFrame(); CHECK(frame); v8::Local<v8::Context> main_context = frame->MainWorldScriptContext(); - gin_helper::Dictionary global(main_context->GetIsolate(), - main_context->Global()); + gin_helper::Dictionary global(isolate, main_context->Global()); const std::string final_key = key_path[key_path.size() - 1]; gin_helper::Dictionary target_object = TraceKeyPath(global, key_path); @@ -855,8 +858,9 @@ void OverrideGlobalValueFromIsolatedWorld( v8::Local<v8::Context> source_context = value->GetCreationContextChecked(isolate); v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext( - source_context, main_context, value, source_context->Global(), - support_dynamic_properties, BridgeErrorTarget::kSource); + isolate, source_context, isolate, main_context, value, + source_context->Global(), support_dynamic_properties, + BridgeErrorTarget::kSource); DCHECK(!maybe_proxy.IsEmpty()); auto proxy = maybe_proxy.ToLocalChecked(); @@ -868,8 +872,7 @@ bool OverrideGlobalPropertyFromIsolatedWorld( v8::Isolate* const isolate, const std::vector<std::string>& key_path, v8::Local<v8::Object> getter, - v8::Local<v8::Value> setter, - gin_helper::Arguments* args) { + v8::Local<v8::Value> setter) { if (key_path.empty()) return false; @@ -878,8 +881,7 @@ bool OverrideGlobalPropertyFromIsolatedWorld( auto* frame = render_frame->GetWebFrame(); CHECK(frame); v8::Local<v8::Context> main_context = frame->MainWorldScriptContext(); - gin_helper::Dictionary global(main_context->GetIsolate(), - main_context->Global()); + gin_helper::Dictionary global(isolate, main_context->Global()); const std::string final_key = key_path[key_path.size() - 1]; v8::Local<v8::Object> target_object = @@ -894,8 +896,8 @@ bool OverrideGlobalPropertyFromIsolatedWorld( v8::Local<v8::Context> source_context = getter->GetCreationContextChecked(isolate); v8::MaybeLocal<v8::Value> maybe_getter_proxy = PassValueToOtherContext( - source_context, main_context, getter, source_context->Global(), false, - BridgeErrorTarget::kSource); + isolate, source_context, isolate, main_context, getter, + source_context->Global(), false, BridgeErrorTarget::kSource); DCHECK(!maybe_getter_proxy.IsEmpty()); getter_proxy = maybe_getter_proxy.ToLocalChecked(); } @@ -903,39 +905,38 @@ bool OverrideGlobalPropertyFromIsolatedWorld( v8::Local<v8::Context> source_context = getter->GetCreationContextChecked(isolate); v8::MaybeLocal<v8::Value> maybe_setter_proxy = PassValueToOtherContext( - source_context, main_context, setter, source_context->Global(), false, - BridgeErrorTarget::kSource); + isolate, source_context, isolate, main_context, setter, + source_context->Global(), false, BridgeErrorTarget::kSource); DCHECK(!maybe_setter_proxy.IsEmpty()); setter_proxy = maybe_setter_proxy.ToLocalChecked(); } v8::PropertyDescriptor desc(getter_proxy, setter_proxy); bool success = IsTrue(target_object->DefineProperty( - main_context, gin::StringToV8(args->isolate(), final_key), desc)); + main_context, gin::StringToV8(isolate, final_key), desc)); DCHECK(success); return success; } } // Serialize script to be executed in the given world. -v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate, +v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* const isolate, const int world_id, - gin_helper::Arguments* args) { + gin::Arguments* const args) { // Get context of caller v8::Local<v8::Context> source_context = isolate->GetCurrentContext(); // Get execution script argument gin_helper::Dictionary exec_script; if (args->Length() >= 1 && !args->GetNext(&exec_script)) { - gin_helper::ErrorThrower(args->isolate()).ThrowError("Invalid script"); + args->ThrowTypeError("Invalid script"); return v8::Undefined(isolate); } // Get "func" from execution script v8::Local<v8::Function> func; if (!exec_script.Get("func", &func)) { - gin_helper::ErrorThrower(isolate).ThrowError( - "Function 'func' is required in script"); + args->ThrowTypeError("Function 'func' is required in script"); return v8::Undefined(isolate); } @@ -944,7 +945,7 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate, v8::Local<v8::Value> args_value; if (exec_script.Get("args", &args_value)) { if (!args_value->IsArray()) { - gin_helper::ErrorThrower(isolate).ThrowError("'args' must be an array"); + args->ThrowTypeError("'args' must be an array"); return v8::Undefined(isolate); } args_array = args_value.As<v8::Array>(); @@ -956,7 +957,7 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate, v8::Local<v8::String> serialized_function; if (!func->FunctionProtoToString(isolate->GetCurrentContext()) .ToLocal(&serialized_function)) { - gin_helper::ErrorThrower(isolate).ThrowError( + gin_helper::ErrorThrower{isolate}.ThrowError( "Failed to serialize function"); return v8::Undefined(isolate); } @@ -966,8 +967,9 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate, } // Get the target context + v8::Isolate* target_isolate = isolate; v8::MaybeLocal<v8::Context> maybe_target_context = - GetTargetContext(isolate, world_id); + GetTargetContext(isolate, world_id, target_isolate); v8::Local<v8::Context> target_context; if (!maybe_target_context.ToLocal(&target_context)) { isolate->ThrowException(v8::Exception::Error(gin::StringToV8( @@ -1053,9 +1055,9 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate, } auto proxied_arg = PassValueToOtherContext( - source_context, target_context, arg, source_context->Global(), - support_dynamic_properties, BridgeErrorTarget::kSource, - &object_cache); + isolate, source_context, target_isolate, target_context, arg, + source_context->Global(), support_dynamic_properties, + BridgeErrorTarget::kSource, &object_cache); if (proxied_arg.IsEmpty()) { gin_helper::ErrorThrower(isolate).ThrowError( absl::StrFormat("Failed to proxy argument at index %d", i)); @@ -1100,8 +1102,8 @@ v8::Local<v8::Value> ExecuteInWorld(v8::Isolate* isolate, v8::TryCatch try_catch(isolate); // Pass value from target context back to source context maybe_cloned_result = PassValueToOtherContext( - target_context, source_context, result, target_context->Global(), - false, BridgeErrorTarget::kSource); + target_isolate, target_context, isolate, source_context, result, + target_context->Global(), false, BridgeErrorTarget::kSource); if (try_catch.HasCaught()) { v8::String::Utf8Value utf8(isolate, try_catch.Exception()); error_message = *utf8 ? *utf8 : "Unknown error cloning result"; diff --git a/shell/renderer/api/electron_api_context_bridge.h b/shell/renderer/api/electron_api_context_bridge.h index f8498ae658ae4..d26243cf79159 100644 --- a/shell/renderer/api/electron_api_context_bridge.h +++ b/shell/renderer/api/electron_api_context_bridge.h @@ -31,7 +31,9 @@ enum class BridgeErrorTarget { }; v8::MaybeLocal<v8::Value> PassValueToOtherContext( + v8::Isolate* source_isolate, v8::Local<v8::Context> source_context, + v8::Isolate* destination_isolate, v8::Local<v8::Context> destination_context, v8::Local<v8::Value> value, /** diff --git a/shell/renderer/api/electron_api_ipc_renderer.cc b/shell/renderer/api/electron_api_ipc_renderer.cc index 61cade3c982c8..1bf1065ca8f45 100644 --- a/shell/renderer/api/electron_api_ipc_renderer.cc +++ b/shell/renderer/api/electron_api_ipc_renderer.cc @@ -221,10 +221,10 @@ class IPCRenderFrame : public IPCBase<IPCRenderFrame>, void OnDestruct() override { electron_ipc_remote_.reset(); } - void WillReleaseScriptContext(v8::Local<v8::Context> context, + void WillReleaseScriptContext(v8::Isolate* const isolate, + v8::Local<v8::Context> context, int32_t world_id) override { - if (weak_context_.IsEmpty() || - weak_context_.Get(context->GetIsolate()) == context) { + if (weak_context_.IsEmpty() || weak_context_.Get(isolate) == context) { OnDestruct(); } } diff --git a/shell/renderer/api/electron_api_web_frame.cc b/shell/renderer/api/electron_api_web_frame.cc index 44ff3b647d966..6ec272a600646 100644 --- a/shell/renderer/api/electron_api_web_frame.cc +++ b/shell/renderer/api/electron_api_web_frame.cc @@ -11,12 +11,14 @@ #include "base/containers/span.h" #include "base/memory/memory_pressure_listener.h" +#include "base/no_destructor.h" #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "components/spellcheck/renderer/spellcheck.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_visitor.h" +#include "gin/arguments.h" #include "gin/object_template_builder.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "shell/common/api/api.mojom.h" @@ -107,6 +109,13 @@ namespace api { namespace { +class SpellCheckerHolder; + +std::set<SpellCheckerHolder*>& GetSpellCheckerHolderInstances() { + static base::NoDestructor<std::set<SpellCheckerHolder*>> instances; + return *instances; +} + #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) bool SpellCheckWord(content::RenderFrame* render_frame, @@ -160,8 +169,8 @@ class ScriptExecutionCallback { v8::Local<v8::Context> source_context = result->GetCreationContextChecked(isolate); maybe_result = PassValueToOtherContext( - source_context, promise_.GetContext(), result, - source_context->Global(), false, BridgeErrorTarget::kSource); + isolate, source_context, promise_.isolate(), promise_.GetContext(), + result, source_context->Global(), false, BridgeErrorTarget::kSource); if (maybe_result.IsEmpty() || try_catch.HasCaught()) { success = false; } @@ -282,7 +291,7 @@ class SpellCheckerHolder final : private content::RenderFrameObserver { // Find existing holder for the |render_frame|. static SpellCheckerHolder* FromRenderFrame( content::RenderFrame* render_frame) { - for (auto* holder : instances_) { + for (auto* holder : GetSpellCheckerHolderInstances()) { if (holder->render_frame() == render_frame) return holder; } @@ -294,10 +303,10 @@ class SpellCheckerHolder final : private content::RenderFrameObserver { : content::RenderFrameObserver(render_frame), spell_check_client_(std::move(spell_check_client)) { DCHECK(!FromRenderFrame(render_frame)); - instances_.insert(this); + GetSpellCheckerHolderInstances().insert(this); } - ~SpellCheckerHolder() final { instances_.erase(this); } + ~SpellCheckerHolder() final { GetSpellCheckerHolderInstances().erase(this); } void UnsetAndDestroy() { FrameSetSpellChecker set_spell_checker(nullptr, render_frame()); @@ -319,7 +328,8 @@ class SpellCheckerHolder final : private content::RenderFrameObserver { delete this; } - void WillReleaseScriptContext(v8::Local<v8::Context> context, + void WillReleaseScriptContext(v8::Isolate* const isolate, + v8::Local<v8::Context> context, int world_id) final { // Unset spell checker when the script context is going to be released, as // the spell check implementation lives there. @@ -327,8 +337,6 @@ class SpellCheckerHolder final : private content::RenderFrameObserver { } private: - static std::set<SpellCheckerHolder*> instances_; - std::unique_ptr<SpellCheckClient> spell_check_client_; }; @@ -630,12 +638,11 @@ class WebFrameRenderer final return !context->GetContentSecurityPolicy()->ShouldCheckEval(); } - v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* gin_args, + // webFrame.executeJavaScript(code[, userGesture][, callback]) + v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* const args, const std::u16string& code) { - gin_helper::Arguments* args = static_cast<gin_helper::Arguments*>(gin_args); - - v8::Isolate* isolate = args->isolate(); - gin_helper::Promise<v8::Local<v8::Value>> promise(isolate); + v8::Isolate* const isolate = args->isolate(); + gin_helper::Promise<v8::Local<v8::Value>> promise{isolate}; v8::Local<v8::Promise> handle = promise.GetHandle(); content::RenderFrame* render_frame; @@ -648,10 +655,14 @@ class WebFrameRenderer final const blink::WebScriptSource source{blink::WebString::FromUTF16(code)}; bool has_user_gesture = false; - args->GetNext(&has_user_gesture); + if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsBoolean()) { + args->GetNext(&has_user_gesture); + } ScriptExecutionCallback::CompletionCallback completion_callback; - args->GetNext(&completion_callback); + if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsFunction()) { + args->GetNext(&completion_callback); + } auto* self = new ScriptExecutionCallback(std::move(promise), std::move(completion_callback)); @@ -672,14 +683,14 @@ class WebFrameRenderer final return handle; } + // executeJavaScriptInIsolatedWorld( + // worldId, scripts[, userGesture][, callback]) v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld( - gin::Arguments* gin_args, - int world_id, + gin::Arguments* const args, + const int world_id, const std::vector<gin_helper::Dictionary>& scripts) { - gin_helper::Arguments* args = static_cast<gin_helper::Arguments*>(gin_args); - - v8::Isolate* isolate = args->isolate(); - gin_helper::Promise<v8::Local<v8::Value>> promise(isolate); + v8::Isolate* const isolate = args->isolate(); + gin_helper::Promise<v8::Local<v8::Value>> promise{isolate}; v8::Local<v8::Promise> handle = promise.GetHandle(); content::RenderFrame* render_frame; @@ -691,24 +702,14 @@ class WebFrameRenderer final } bool has_user_gesture = false; - args->GetNext(&has_user_gesture); - - blink::mojom::EvaluationTiming script_execution_type = - blink::mojom::EvaluationTiming::kSynchronous; - blink::mojom::LoadEventBlockingOption load_blocking_option = - blink::mojom::LoadEventBlockingOption::kDoNotBlock; - std::string execution_type; - args->GetNext(&execution_type); - - if (execution_type == "asynchronous") { - script_execution_type = blink::mojom::EvaluationTiming::kAsynchronous; - } else if (execution_type == "asynchronousBlockingOnload") { - script_execution_type = blink::mojom::EvaluationTiming::kAsynchronous; - load_blocking_option = blink::mojom::LoadEventBlockingOption::kBlock; + if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsBoolean()) { + args->GetNext(&has_user_gesture); } ScriptExecutionCallback::CompletionCallback completion_callback; - args->GetNext(&completion_callback); + if (auto next = args->PeekNext(); !next.IsEmpty() && next->IsFunction()) { + args->GetNext(&completion_callback); + } std::vector<blink::WebScriptSource> sources; sources.reserve(scripts.size()); @@ -742,7 +743,9 @@ class WebFrameRenderer final world_id, base::span(sources), has_user_gesture ? blink::mojom::UserActivationOption::kActivate : blink::mojom::UserActivationOption::kDoNotActivate, - script_execution_type, load_blocking_option, base::NullCallback(), + blink::mojom::EvaluationTiming::kSynchronous, + blink::mojom::LoadEventBlockingOption::kDoNotBlock, + base::NullCallback(), base::BindOnce(&ScriptExecutionCallback::Completed, base::Unretained(self)), blink::BackForwardCacheAware::kPossiblyDisallow, @@ -808,7 +811,7 @@ class WebFrameRenderer final void ClearCache(v8::Isolate* isolate) { blink::WebCache::Clear(); base::MemoryPressureListener::NotifyMemoryPressure( - base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); + base::MEMORY_PRESSURE_LEVEL_CRITICAL); } v8::Local<v8::Value> FindFrameByToken(v8::Isolate* isolate, @@ -941,9 +944,6 @@ class WebFrameRenderer final gin::DeprecatedWrapperInfo WebFrameRenderer::kWrapperInfo = { gin::kEmbedderNativeGin}; -// static -std::set<SpellCheckerHolder*> SpellCheckerHolder::instances_; - } // namespace api } // namespace electron diff --git a/shell/renderer/electron_api_service_impl.cc b/shell/renderer/electron_api_service_impl.cc index e527061455ce6..19c9bce33a1f2 100644 --- a/shell/renderer/electron_api_service_impl.cc +++ b/shell/renderer/electron_api_service_impl.cc @@ -120,7 +120,7 @@ void ElectronApiServiceImpl::ReceivePostMessage( for (auto& port : message.ports) { ports.emplace_back( blink::WebMessagePortConverter::EntangleAndInjectMessagePortChannel( - context, std::move(port))); + isolate, context, std::move(port))); } std::vector<v8::Local<v8::Value>> args = {message_value}; diff --git a/shell/renderer/electron_ipc_native.cc b/shell/renderer/electron_ipc_native.cc index 36396ad2ff483..7fac851f9e2e7 100644 --- a/shell/renderer/electron_ipc_native.cc +++ b/shell/renderer/electron_ipc_native.cc @@ -4,6 +4,8 @@ #include "electron/shell/renderer/electron_ipc_native.h" +#include <optional> + #include "base/trace_event/trace_event.h" #include "shell/common/gin_converters/blink_converter.h" #include "shell/common/gin_converters/value_converter.h" @@ -45,10 +47,9 @@ void InvokeIpcCallback(v8::Isolate* const isolate, // Only set up the node::CallbackScope if there's a node environment. // Sandboxed renderers don't have a node environment. - std::unique_ptr<node::CallbackScope> callback_scope; - if (node::Environment::GetCurrent(context)) { - callback_scope = std::make_unique<node::CallbackScope>( - isolate, ipcNative, node::async_context{0, 0}); + std::optional<node::CallbackScope> callback_scope; + if (auto* env = node::Environment::GetCurrent(context)) { + callback_scope.emplace(env, ipcNative, node::async_context{0, 0}); } auto callback_key = gin::ConvertToV8(isolate, callback_name) diff --git a/shell/renderer/electron_render_frame_observer.cc b/shell/renderer/electron_render_frame_observer.cc index cfca2519482ec..a9d08b836f47d 100644 --- a/shell/renderer/electron_render_frame_observer.cc +++ b/shell/renderer/electron_render_frame_observer.cc @@ -7,7 +7,6 @@ #include "base/memory/ref_counted_memory.h" #include "base/trace_event/trace_event.h" #include "content/public/renderer/render_frame.h" -#include "ipc/ipc_message_macros.h" #include "net/base/net_module.h" #include "net/grit/net_resources.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -60,11 +59,6 @@ ElectronRenderFrameObserver::ElectronRenderFrameObserver( renderer_client_(renderer_client) { // Initialise resource for directory listing. net::NetModule::SetResourceProvider(NetResourceProvider); - - // In Chrome, app regions are only supported in the main frame. - // However, we need to support draggable regions on other - // local frames/windows, so extend support beyond the main frame. - render_frame_->GetWebView()->SetSupportsDraggableRegions(true); } void ElectronRenderFrameObserver::DidClearWindowObject() { @@ -148,11 +142,11 @@ void ElectronRenderFrameObserver::DidInstallConditionalFeatures( } void ElectronRenderFrameObserver::WillReleaseScriptContext( + v8::Isolate* const isolate, v8::Local<v8::Context> context, int world_id) { if (ShouldNotifyClient(world_id)) - renderer_client_->WillReleaseScriptContext(context->GetIsolate(), context, - render_frame_); + renderer_client_->WillReleaseScriptContext(isolate, context, render_frame_); } void ElectronRenderFrameObserver::OnDestruct() { diff --git a/shell/renderer/electron_render_frame_observer.h b/shell/renderer/electron_render_frame_observer.h index 5919cf6d0d862..54582eb68ccd1 100644 --- a/shell/renderer/electron_render_frame_observer.h +++ b/shell/renderer/electron_render_frame_observer.h @@ -8,7 +8,6 @@ #include <string> #include "content/public/renderer/render_frame_observer.h" -#include "ipc/ipc_platform_file.h" #include "third_party/blink/public/web/web_local_frame.h" namespace electron { @@ -31,7 +30,8 @@ class ElectronRenderFrameObserver : private content::RenderFrameObserver { void DidClearWindowObject() override; void DidInstallConditionalFeatures(v8::Local<v8::Context> context, int world_id) override; - void WillReleaseScriptContext(v8::Local<v8::Context> context, + void WillReleaseScriptContext(v8::Isolate* const isolate, + v8::Local<v8::Context> context, int world_id) override; void OnDestruct() override; void DidMeaningfulLayout(blink::WebMeaningfulLayout layout_type) override; @@ -39,8 +39,6 @@ class ElectronRenderFrameObserver : private content::RenderFrameObserver { [[nodiscard]] bool ShouldNotifyClient(int world_id) const; void CreateIsolatedWorldContext(); - void OnTakeHeapSnapshot(IPC::PlatformFileForTransit file_handle, - const std::string& channel); bool has_delayed_node_initialization_ = false; raw_ptr<content::RenderFrame> render_frame_; diff --git a/shell/renderer/electron_sandboxed_renderer_client.cc b/shell/renderer/electron_sandboxed_renderer_client.cc index 4243a128f2c89..f797b7f09226b 100644 --- a/shell/renderer/electron_sandboxed_renderer_client.cc +++ b/shell/renderer/electron_sandboxed_renderer_client.cc @@ -172,19 +172,18 @@ void ElectronSandboxedRendererClient::EmitProcessEvent( void ElectronSandboxedRendererClient::WillEvaluateServiceWorkerOnWorkerThread( blink::WebServiceWorkerContextProxy* context_proxy, + v8::Isolate* const v8_isolate, v8::Local<v8::Context> v8_context, int64_t service_worker_version_id, const GURL& service_worker_scope, const GURL& script_url, const blink::ServiceWorkerToken& service_worker_token) { RendererClientBase::WillEvaluateServiceWorkerOnWorkerThread( - context_proxy, v8_context, service_worker_version_id, + context_proxy, v8_isolate, v8_context, service_worker_version_id, service_worker_scope, script_url, service_worker_token); auto* command_line = base::CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kServiceWorkerPreload)) { - v8::Isolate* const v8_isolate = v8_context->GetIsolate(); - if (!service_worker_data) { service_worker_data = new ServiceWorkerData{ context_proxy, service_worker_version_id, v8_isolate, v8_context}; diff --git a/shell/renderer/electron_sandboxed_renderer_client.h b/shell/renderer/electron_sandboxed_renderer_client.h index 42e72ddd18527..45da50fdb5045 100644 --- a/shell/renderer/electron_sandboxed_renderer_client.h +++ b/shell/renderer/electron_sandboxed_renderer_client.h @@ -47,6 +47,7 @@ class ElectronSandboxedRendererClient : public RendererClientBase { void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override; void WillEvaluateServiceWorkerOnWorkerThread( blink::WebServiceWorkerContextProxy* context_proxy, + v8::Isolate* const isolate, v8::Local<v8::Context> v8_context, int64_t service_worker_version_id, const GURL& service_worker_scope, diff --git a/shell/renderer/electron_smooth_round_rect.cc b/shell/renderer/electron_smooth_round_rect.cc index 58bbc49152cc8..015f815756d09 100644 --- a/shell/renderer/electron_smooth_round_rect.cc +++ b/shell/renderer/electron_smooth_round_rect.cc @@ -7,6 +7,7 @@ #include <numbers> #include "base/check.h" #include "base/check_op.h" +#include "third_party/skia/include/core/SkPathBuilder.h" namespace electron { @@ -99,7 +100,7 @@ constexpr CurveGeometry::CurveGeometry(float radius, float smoothness) { ((edge_connecting_offset - arc_curve_offset) * EDGE_CURVE_POINT_RATIO); } -void DrawCorner(SkPath& path, +void DrawCorner(SkPathBuilder& path, float radius, float smoothness1, float smoothness2, @@ -148,8 +149,9 @@ void DrawCorner(SkPath& path, { SkPoint arc_connecting_point = corner + QuarterRotate(curve2.arc_connecting_vector, quarter_rotations); - path.arcTo(SkPoint::Make(radius, radius), 0.0f, SkPath::kSmall_ArcSize, - SkPathDirection::kCW, arc_connecting_point); + path.arcTo(SkPoint::Make(radius, radius), 0.0f, + SkPathBuilder::kSmall_ArcSize, SkPathDirection::kCW, + arc_connecting_point); } // Draw the second smoothing curve @@ -287,7 +289,7 @@ SkPath DrawSmoothRoundRect(float x, auto [left_top_smoothness, left_bottom_smoothness] = ConstrainSmoothness( height, smoothness, top_left_radius, bottom_left_radius); - SkPath path; + SkPathBuilder path; // Top left corner DrawCorner(path, top_left_radius, left_top_smoothness, top_left_smoothness, @@ -302,11 +304,11 @@ SkPath DrawSmoothRoundRect(float x, bottom_right_smoothness, SkPoint::Make(x + width, y + height), 2); // Bottom left corner - DrawCorner(path, bottom_left_radius, left_bottom_smoothness, - bottom_left_smoothness, SkPoint::Make(x, y + height), 3); + DrawCorner(path, bottom_left_radius, bottom_left_smoothness, + left_bottom_smoothness, SkPoint::Make(x, y + height), 3); path.close(); - return path; + return path.detach(); } } // namespace electron diff --git a/shell/renderer/preload_realm_context.cc b/shell/renderer/preload_realm_context.cc index 1912c9aabcc87..da11d25018cbd 100644 --- a/shell/renderer/preload_realm_context.cc +++ b/shell/renderer/preload_realm_context.cc @@ -59,9 +59,11 @@ class PreloadRealmLifetimeController RegisterDebugger(initiator_execution_context); initiator_context()->SetAlignedPointerInEmbedderData( - kElectronContextEmbedderDataIndex, static_cast<void*>(this)); + kElectronContextEmbedderDataIndex, static_cast<void*>(this), + v8::kEmbedderDataTypeTagDefault); realm_context()->SetAlignedPointerInEmbedderData( - kElectronContextEmbedderDataIndex, static_cast<void*>(this)); + kElectronContextEmbedderDataIndex, static_cast<void*>(this), + v8::kEmbedderDataTypeTagDefault); metrics_ = base::ProcessMetrics::CreateCurrentProcessMetrics(); RunInitScript(); @@ -74,7 +76,8 @@ class PreloadRealmLifetimeController } auto* controller = static_cast<PreloadRealmLifetimeController*>( context->GetAlignedPointerFromEmbedderData( - kElectronContextEmbedderDataIndex)); + kElectronContextEmbedderDataIndex, + v8::kEmbedderDataTypeTagDefault)); CHECK(controller); return controller; } @@ -98,6 +101,12 @@ class PreloadRealmLifetimeController : v8::MaybeLocal<v8::Context>(); } + v8::Isolate* GetInitiatorIsolate() { + return initiator_script_state_->ContextIsValid() + ? initiator_script_state_->GetIsolate() + : nullptr; + } + electron::ServiceWorkerData* service_worker_data() { return service_worker_data_; } @@ -106,7 +115,8 @@ class PreloadRealmLifetimeController void ContextDestroyed() override { v8::HandleScope handle_scope(realm_isolate()); realm_context()->SetAlignedPointerInEmbedderData( - kElectronContextEmbedderDataIndex, nullptr); + kElectronContextEmbedderDataIndex, nullptr, + v8::kEmbedderDataTypeTagDefault); // See ShadowRealmGlobalScope::ContextDestroyed shadow_realm_script_state_->DisposePerContextData(); @@ -199,16 +209,19 @@ class PreloadRealmLifetimeController } // namespace -v8::MaybeLocal<v8::Context> GetInitiatorContext( - v8::Local<v8::Context> context) { +v8::MaybeLocal<v8::Context> GetInitiatorContext(v8::Local<v8::Context> context, + v8::Isolate* target_isolate) { DCHECK(!context.IsEmpty()); + DCHECK(target_isolate); blink::ExecutionContext* execution_context = blink::ExecutionContext::From(context); if (!execution_context->IsShadowRealmGlobalScope()) return v8::MaybeLocal<v8::Context>(); auto* controller = PreloadRealmLifetimeController::From(context); - if (controller) + if (controller) { + target_isolate = controller->GetInitiatorIsolate(); return controller->GetInitiatorContext(); + } return v8::MaybeLocal<v8::Context>(); } diff --git a/shell/renderer/preload_realm_context.h b/shell/renderer/preload_realm_context.h index ec5f354722376..223a8fc838eac 100644 --- a/shell/renderer/preload_realm_context.h +++ b/shell/renderer/preload_realm_context.h @@ -14,7 +14,8 @@ class ServiceWorkerData; namespace electron::preload_realm { // Get initiator context given the preload context. -v8::MaybeLocal<v8::Context> GetInitiatorContext(v8::Local<v8::Context> context); +v8::MaybeLocal<v8::Context> GetInitiatorContext(v8::Local<v8::Context> context, + v8::Isolate* target_isolate); // Get the preload context given the initiator context. v8::MaybeLocal<v8::Context> GetPreloadRealmContext( diff --git a/shell/renderer/preload_utils.cc b/shell/renderer/preload_utils.cc index 298b018eabdaf..a7a3d55859085 100644 --- a/shell/renderer/preload_utils.cc +++ b/shell/renderer/preload_utils.cc @@ -6,7 +6,6 @@ #include "base/process/process.h" #include "base/strings/strcat.h" -#include "shell/common/gin_helper/arguments.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/node_includes.h" #include "v8/include/v8-context.h" @@ -34,20 +33,19 @@ v8::Local<v8::Object> GetBindingCache(v8::Isolate* isolate) { // adapted from node.cc v8::Local<v8::Value> GetBinding(v8::Isolate* isolate, - v8::Local<v8::String> key, - gin_helper::Arguments* margs) { + v8::Local<v8::String> key) { v8::Local<v8::Object> exports; - std::string binding_key = gin::V8ToString(isolate, key); + const std::string binding_key = gin::V8ToString(isolate, key); gin_helper::Dictionary cache(isolate, GetBindingCache(isolate)); if (cache.Get(binding_key, &exports)) { return exports; } - auto* mod = node::binding::get_linked_module(binding_key.c_str()); - + auto* const mod = node::binding::get_linked_module(binding_key.c_str()); if (!mod) { - margs->ThrowError(base::StrCat({"No such binding: ", binding_key})); + gin_helper::ErrorThrower{isolate}.ThrowError( + base::StrCat({"No such binding: ", binding_key})); return exports; } diff --git a/shell/renderer/preload_utils.h b/shell/renderer/preload_utils.h index 542e76a125ffd..b2931cf54a237 100644 --- a/shell/renderer/preload_utils.h +++ b/shell/renderer/preload_utils.h @@ -14,8 +14,7 @@ class Arguments; namespace electron::preload_utils { v8::Local<v8::Value> GetBinding(v8::Isolate* isolate, - v8::Local<v8::String> key, - gin_helper::Arguments* margs); + v8::Local<v8::String> key); v8::Local<v8::Value> CreatePreloadScript(v8::Isolate* isolate, v8::Local<v8::String> source); diff --git a/shell/renderer/renderer_client_base.cc b/shell/renderer/renderer_client_base.cc index 4d2548c6074aa..9b911450f8b9b 100644 --- a/shell/renderer/renderer_client_base.cc +++ b/shell/renderer/renderer_client_base.cc @@ -233,7 +233,7 @@ void RendererClientBase::RenderThreadStarted() { extensions::ExtensionsRendererClient::Set(extensions_renderer_client_.get()); extensions_renderer_client_->RenderThreadStarted(); - WTF::String extension_scheme(extensions::kExtensionScheme); + blink::String extension_scheme(extensions::kExtensionScheme); // Extension resources are HTTP-like and safe to expose to the fetch API. The // rules for the fetch API are consistent with XHR. blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI( @@ -270,7 +270,7 @@ void RendererClientBase::RenderThreadStarted() { ParseSchemesCLISwitch(command_line, switches::kBypassCSPSchemes); for (const std::string& scheme : csp_bypassing_schemes) blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy( - WTF::String::FromUTF8(scheme)); + blink::String::FromUTF8(scheme)); std::vector<std::string> code_cache_schemes_list = ParseSchemesCLISwitch(command_line, switches::kCodeCacheSchemes); @@ -489,6 +489,7 @@ void RendererClientBase::DidInitializeServiceWorkerContextOnWorkerThread( void RendererClientBase::WillEvaluateServiceWorkerOnWorkerThread( blink::WebServiceWorkerContextProxy* context_proxy, + v8::Isolate* const v8_isolate, v8::Local<v8::Context> v8_context, int64_t service_worker_version_id, const GURL& service_worker_scope, @@ -497,7 +498,7 @@ void RendererClientBase::WillEvaluateServiceWorkerOnWorkerThread( #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) extensions_renderer_client_->dispatcher() ->WillEvaluateServiceWorkerOnWorkerThread( - context_proxy, v8_context, service_worker_version_id, + context_proxy, v8_isolate, v8_context, service_worker_version_id, service_worker_scope, script_url, service_worker_token); #endif } @@ -591,8 +592,8 @@ void RendererClientBase::SetupMainWorldOverrides( v8::Local<v8::Value> guest_view_internal; if (global.GetHidden("guestViewInternal", &guest_view_internal)) { auto result = api::PassValueToOtherContext( - source_context, context, guest_view_internal, source_context->Global(), - false, api::BridgeErrorTarget::kSource); + isolate, source_context, isolate, context, guest_view_internal, + source_context->Global(), false, api::BridgeErrorTarget::kSource); if (!result.IsEmpty()) { isolated_api.Set("guestViewInternal", result.ToLocalChecked()); } diff --git a/shell/renderer/renderer_client_base.h b/shell/renderer/renderer_client_base.h index c14158eef53fd..e4571fa976569 100644 --- a/shell/renderer/renderer_client_base.h +++ b/shell/renderer/renderer_client_base.h @@ -124,6 +124,7 @@ class RendererClientBase : public content::ContentRendererClient const GURL& script_url) override; void WillEvaluateServiceWorkerOnWorkerThread( blink::WebServiceWorkerContextProxy* context_proxy, + v8::Isolate* const isolate, v8::Local<v8::Context> v8_context, int64_t service_worker_version_id, const GURL& service_worker_scope, diff --git a/shell/services/node/node_service.cc b/shell/services/node/node_service.cc index 11a4a34fc9285..ffb7f3c007b96 100644 --- a/shell/services/node/node_service.cc +++ b/shell/services/node/node_service.cc @@ -30,15 +30,19 @@ namespace electron { -mojo::Remote<node::mojom::NodeServiceClient> g_client_remote; +mojo::Remote<node::mojom::NodeServiceClient>& GetRemote() { + static base::NoDestructor<mojo::Remote<node::mojom::NodeServiceClient>> + instance; + return *instance; +} void V8FatalErrorCallback(const char* location, const char* message) { - if (g_client_remote.is_bound() && g_client_remote.is_connected()) { + if (GetRemote().is_bound() && GetRemote().is_connected()) { auto* isolate = v8::Isolate::TryGetCurrent(); std::ostringstream outstream; node::GetNodeReport(isolate, message, location, v8::Local<v8::Object>() /* error */, outstream); - g_client_remote->OnV8FatalError(location, outstream.str()); + GetRemote()->OnV8FatalError(location, outstream.str()); } #if !IS_MAS_BUILD() @@ -101,7 +105,7 @@ NodeService::~NodeService() { ParentPort::GetInstance()->Close(); js_env_->DestroyMicrotasksRunner(); node::Stop(node_env_.get(), node::StopFlags::kDoNotTerminateIsolate); - g_client_remote.reset(); + GetRemote().reset(); } } @@ -111,8 +115,8 @@ void NodeService::Initialize( if (NodeBindings::IsInitialized()) return; - g_client_remote.Bind(std::move(client_pending_remote)); - g_client_remote.reset_on_disconnect(); + GetRemote().Bind(std::move(client_pending_remote)); + GetRemote().reset_on_disconnect(); ParentPort::GetInstance()->Initialize(std::move(params->port)); @@ -155,7 +159,7 @@ void NodeService::Initialize( node_env_stopped_ = true; ParentPort::GetInstance()->Close(); js_env_->DestroyMicrotasksRunner(); - g_client_remote.reset(); + GetRemote().reset(); receiver_.ResetWithReason(exit_code, "process_exit_termination"); node::DefaultProcessExitHandler(env, exit_code); }); diff --git a/spec/api-app-spec.ts b/spec/api-app-spec.ts index 34983c484e9e6..81ab51f10e2ac 100644 --- a/spec/api-app-spec.ts +++ b/spec/api-app-spec.ts @@ -149,6 +149,12 @@ describe('app module', () => { }); }); + describe('app.isHardwareAccelerationEnabled()', () => { + it('should be a boolean', () => { + expect(app.isHardwareAccelerationEnabled()).to.be.a('boolean'); + }); + }); + describe('app.isPackaged', () => { it('should be false during tests', () => { expect(app.isPackaged).to.equal(false); @@ -1019,7 +1025,7 @@ describe('app module', () => { }); }); - ifdescribe(process.platform !== 'linux')('accessibilitySupportEnabled property', () => { + ifdescribe(process.platform !== 'linux')('accessibility support functionality', () => { it('is mutable', () => { const values = [false, true, false]; const setters: Array<(arg: boolean) => void> = [ @@ -1037,6 +1043,61 @@ describe('app module', () => { } } }); + + it('getAccessibilitySupportFeatures returns an array with accessibility properties', () => { + const values = [ + 'nativeAPIs', + 'webContents', + 'inlineTextBoxes', + 'extendedProperties', + 'screenReader', + 'html', + 'labelImages', + 'pdfPrinting' + ]; + + app.setAccessibilitySupportEnabled(false); + + const disabled = app.getAccessibilitySupportFeatures(); + expect(disabled).to.be.an('array'); + expect(disabled.includes('complete')).to.equal(false); + + app.setAccessibilitySupportEnabled(true); + const enabled = app.getAccessibilitySupportFeatures(); + expect(enabled).to.be.an('array').with.length.greaterThan(0); + + const boolEnabled = app.isAccessibilitySupportEnabled(); + if (boolEnabled) { + expect(enabled.some(f => values.includes(f))).to.equal(true); + } + }); + + it('setAccessibilitySupportFeatures can enable a subset of features', () => { + app.setAccessibilitySupportEnabled(false); + expect(app.isAccessibilitySupportEnabled()).to.equal(false); + expect(app.getAccessibilitySupportFeatures()).to.be.an('array').that.is.empty(); + + const subsetA = ['webContents', 'html']; + app.setAccessibilitySupportFeatures(subsetA); + const afterSubsetA = app.getAccessibilitySupportFeatures(); + expect(afterSubsetA).to.deep.equal(subsetA); + + const subsetB = [ + 'nativeAPIs', + 'webContents', + 'inlineTextBoxes', + 'extendedProperties' + ]; + app.setAccessibilitySupportFeatures(subsetB); + const afterSubsetB = app.getAccessibilitySupportFeatures(); + expect(afterSubsetB).to.deep.equal(subsetB); + }); + + it('throws when an unknown accessibility feature is requested', () => { + expect(() => { + app.setAccessibilitySupportFeatures(['unknownFeature']); + }).to.throw('Unknown accessibility feature: unknownFeature'); + }); }); ifdescribe(process.platform === 'win32')('setJumpList(categories)', () => { diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index 58529ac1f8379..614722db2ffc3 100755 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, net, protocol, screen, webContents, webFrameMain, session, WebContents, WebFrameMain } from 'electron/main'; +import { app, BrowserWindow, BaseWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, net, protocol, screen, webContents, webFrameMain, session, systemPreferences, WebContents, WebFrameMain, BrowserWindowConstructorOptions } from 'electron/main'; import { expect } from 'chai'; @@ -57,6 +57,8 @@ describe('BrowserWindow module', () => { }); describe('BrowserWindow constructor', () => { + afterEach(closeAllWindows); + it('allows passing void 0 as the webContents', async () => { expect(() => { const w = new BrowserWindow({ @@ -83,6 +85,38 @@ describe('BrowserWindow module', () => { w.destroy(); }).not.to.throw(); }); + + it('throws error when creating windows with duplicate names', () => { + const w1 = new BrowserWindow({ show: false, name: 'duplicate-name' }); + + expect(() => { + // eslint-disable-next-line no-new + new BrowserWindow({ show: false, name: 'duplicate-name' }); + }).to.throw("Window name 'duplicate-name' is already in use. Window names must be unique."); + + w1.destroy(); + }); + + it('prevents BaseWindow and BrowserWindow from using same name', () => { + const base = new BaseWindow({ show: false, name: 'shared-name' }); + + expect(() => { + // eslint-disable-next-line no-new + new BrowserWindow({ show: false, name: 'shared-name' }); + }).to.throw("Window name 'shared-name' is already in use. Window names must be unique."); + + base.destroy(); + }); + + it('allows reusing name after window is destroyed', () => { + const w1 = new BrowserWindow({ show: false, name: 'reusable-name' }); + w1.destroy(); + + expect(() => { + const w2 = new BrowserWindow({ show: false, name: 'reusable-name' }); + w2.destroy(); + }).not.to.throw(); + }); }); describe('garbage collection', () => { @@ -2562,7 +2596,23 @@ describe('BrowserWindow module', () => { expect(() => { // @ts-ignore this is wrong on purpose. w.setAccentColor([1, 2, 3]); - }).to.throw('Invalid accent color value - must be a string or boolean'); + }).to.throw('Invalid accent color value - must be null, hex string, or boolean'); + }); + + it('throws if called with an invalid parameter', () => { + const w = new BrowserWindow({ show: false }); + expect(() => { + // @ts-ignore this is wrong on purpose. + w.setAccentColor(new Date()); + }).to.throw('Invalid accent color value - must be null, hex string, or boolean'); + }); + + it('can be reset with null', () => { + const w = new BrowserWindow({ show: false }); + w.setAccentColor('#FF0000'); + expect(w.getAccentColor()).to.equal('#FF0000'); + w.setAccentColor(null); + expect(w.getAccentColor()).to.not.equal('#FF0000'); }); it('returns the accent color after setting it to a string', () => { @@ -2590,6 +2640,14 @@ describe('BrowserWindow module', () => { expect(accentColor).to.match(/^#[0-9A-F]{6}$/i); }); + it('matches the systemPreferences system color when true', () => { + const w = new BrowserWindow({ show: false }); + w.setAccentColor(true); + const accentColor = w.getAccentColor() as string; + const systemColor = systemPreferences.getAccentColor().slice(0, 6); + expect(accentColor).to.equal(`#${systemColor}`); + }); + it('returns the correct accent color after multiple changes', () => { const w = new BrowserWindow({ show: false }); @@ -5455,7 +5513,7 @@ describe('BrowserWindow module', () => { thickFrame: true, transparent: true }); - expect(w.isResizable()).to.be.true('resizable'); + expect(w.isResizable()).to.be.false('resizable'); w.maximize(); expect(w.isMaximized()).to.be.true('maximized'); const bounds = w.getBounds(); @@ -7070,4 +7128,1536 @@ describe('BrowserWindow module', () => { expect(startPos).to.not.deep.equal(endPos); }); }); + + ifdescribe(hasCapturableScreen())('windowStatePersistence', () => { + const getWindowStateFromDisk = (windowName: string, preferencesPath: string) => { + if (!fs.existsSync(preferencesPath)) { + throw new Error(`Preferences file does not exist at path: ${preferencesPath}. Window state was not saved to disk.`); + } + const prefsContent = fs.readFileSync(preferencesPath, 'utf8'); + const prefs = JSON.parse(prefsContent); + return prefs?.windowStates?.[windowName] || null; + }; + + // Helper to get preferences file modification time + const getPrefsModTime = (preferencesPath: string): Date => { + try { + return fs.statSync(preferencesPath).mtime; + } catch { + throw new Error(`Test requires preferences file to exist at path: ${preferencesPath}.`); + } + }; + + const waitForPrefsUpdate = async (initialModTime: Date, preferencesPath: string): Promise<void> => { + const startTime = Date.now(); + const timeoutMs = 20000; + while (true) { + const currentModTime = getPrefsModTime(preferencesPath); + + if (currentModTime > initialModTime) { + return; + } + + if (Date.now() - startTime > timeoutMs) { + throw new Error(`Window state was not flushed to disk within ${timeoutMs}ms`); + } + // Wait for 1 second before checking again + await setTimeout(1000); + } + }; + + const waitForPrefsFileCreation = async (preferencesPath: string) => { + while (!fs.existsSync(preferencesPath)) { + await setTimeout(1000); + } + }; + + const createAndSaveWindowState = async (preferencesPath: string, windowName: string, options?: BrowserWindowConstructorOptions) => { + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: { + displayMode: false + }, + show: false, + ...options + }); + if (!fs.existsSync(preferencesPath)) { + // File doesn't exist, wait for creation + await waitForPrefsFileCreation(preferencesPath); + } else { + // File exists, wait for update + const initialModTime = getPrefsModTime(preferencesPath); + await waitForPrefsUpdate(initialModTime, preferencesPath); + } + // Ensure window is destroyed because we can't create another window with the same name otherwise + w.destroy(); + }; + + describe('save window state', () => { + const fixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'window-state-save'); + const sharedUserDataPath = path.join(os.tmpdir(), 'electron-window-state-test'); + const sharedPreferencesPath = path.join(sharedUserDataPath, 'Local State'); + + // Clean up before each test + beforeEach(() => { + if (fs.existsSync(sharedUserDataPath)) { + fs.rmSync(sharedUserDataPath, { recursive: true, force: true }); + } + }); + + describe('state saving after window operations', () => { + it('should save window state with required properties', async () => { + const appPath = path.join(fixturesPath, 'schema-check'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-window-state-schema', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-window-state-schema" does not exist'); + expect(savedState).to.have.property('left'); + expect(savedState).to.have.property('top'); + expect(savedState).to.have.property('right'); + expect(savedState).to.have.property('bottom'); + expect(savedState).to.have.property('maximized'); + expect(savedState).to.have.property('fullscreen'); + expect(savedState).to.have.property('kiosk'); + expect(savedState).to.have.property('workAreaLeft'); + expect(savedState).to.have.property('workAreaTop'); + expect(savedState).to.have.property('workAreaRight'); + expect(savedState).to.have.property('workAreaBottom'); + }); + + it('should save window state after window is closed and app exit', async () => { + const appPath = path.join(fixturesPath, 'close-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-close-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-close-save" does not exist'); + expect(savedState.right - savedState.left).to.equal(400); + expect(savedState.bottom - savedState.top).to.equal(300); + expect(savedState.maximized).to.equal(false); + expect(savedState.fullscreen).to.equal(false); + expect(savedState.kiosk).to.equal(false); + }); + + it('should save window state after window is resized and app exit', async () => { + const appPath = path.join(fixturesPath, 'resize-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-resize-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-resize-save" does not exist'); + expect(savedState.right - savedState.left).to.equal(500); + expect(savedState.bottom - savedState.top).to.equal(400); + expect(savedState.maximized).to.equal(false); + expect(savedState.fullscreen).to.equal(false); + expect(savedState.kiosk).to.equal(false); + }); + + it('should save window state after window is moved and app exit', async () => { + const appPath = path.join(fixturesPath, 'move-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-move-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-move-save" does not exist'); + expect(savedState.left).to.equal(100); + expect(savedState.top).to.equal(150); + expect(savedState.maximized).to.equal(false); + expect(savedState.fullscreen).to.equal(false); + expect(savedState.kiosk).to.equal(false); + }); + + it('should save window state after window is fullscreened and app exit', async () => { + const appPath = path.join(fixturesPath, 'fullscreen-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-fullscreen-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-fullscreen-save" does not exist'); + expect(savedState.fullscreen).to.equal(true); + expect(savedState.maximized).to.equal(false); + expect(savedState.kiosk).to.equal(false); + }); + + it('should save window state after window is maximized and app exit', async () => { + const appPath = path.join(fixturesPath, 'maximize-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-maximize-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-maximize-save" does not exist'); + expect(savedState.maximized).to.equal(true); + expect(savedState.fullscreen).to.equal(false); + expect(savedState.kiosk).to.equal(false); + }); + + it('should save window state if in a minimized state and app exit', async () => { + const appPath = path.join(fixturesPath, 'minimize-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-minimize-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-minimize-save" does not exist'); + // Should save the bounds from before minimizing + expect(savedState.right - savedState.left).to.equal(400); + expect(savedState.bottom - savedState.top).to.equal(300); + expect(savedState.maximized).to.equal(false); + expect(savedState.fullscreen).to.equal(false); + expect(savedState.kiosk).to.equal(false); + }); + + it('should save window state after window is kiosked and app exit', async () => { + const appPath = path.join(fixturesPath, 'kiosk-save'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-kiosk-save', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-kiosk-save" does not exist'); + expect(savedState.kiosk).to.equal(true); + expect(savedState.fullscreen).to.equal(true); + expect(savedState.maximized).to.equal(false); + }); + }); + + describe('work area tests', () => { + it('should save valid work area bounds', async () => { + const appPath = path.join(fixturesPath, 'schema-check'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-window-state-schema', sharedPreferencesPath); + + expect(savedState).to.not.be.null('window state with window name "test-window-state-schema" does not exist'); + expect(savedState.workAreaLeft).to.be.a('number'); + expect(savedState.workAreaTop).to.be.a('number'); + expect(savedState.workAreaRight).to.be.a('number'); + expect(savedState.workAreaBottom).to.be.a('number'); + + expect(savedState.workAreaLeft).to.be.lessThan(savedState.workAreaRight); + expect(savedState.workAreaTop).to.be.lessThan(savedState.workAreaBottom); + }); + + it('should save work area bounds that contain the window bounds on primary display', async () => { + // Fixture will center the window on the primary display + const appPath = path.join(fixturesPath, 'work-area-primary'); + const appProcess = childProcess.spawn(process.execPath, [appPath]); + const [code] = await once(appProcess, 'exit'); + expect(code).to.equal(0); + + const savedState = getWindowStateFromDisk('test-work-area-primary', sharedPreferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-work-area-primary" does not exist'); + + expect(savedState.left).to.be.greaterThanOrEqual(savedState.workAreaLeft); + expect(savedState.top).to.be.greaterThanOrEqual(savedState.workAreaTop); + expect(savedState.right).to.be.lessThanOrEqual(savedState.workAreaRight); + expect(savedState.bottom).to.be.lessThanOrEqual(savedState.workAreaBottom); + }); + }); + + describe('asynchronous batching behavior', () => { + let w: BrowserWindow; + const windowName = 'test-batching-behavior'; + const preferencesPath = path.join(app.getPath('userData'), 'Local State'); + + beforeEach(async () => { + await setTimeout(2000); + BrowserWindow.clearPersistedState(windowName); + w = new BrowserWindow({ + show: false, + width: 400, + height: 300, + name: windowName, + windowStatePersistence: true + }); + }); + + afterEach(closeAllWindows); + + it('should not immediately save window state to disk when window is moved/resized', async () => { + // Wait for preferences file to be created if its the first time we're running the test + await waitForPrefsFileCreation(preferencesPath); + + const initialModTime = getPrefsModTime(preferencesPath); + + const moved = once(w, 'move'); + w.setPosition(150, 200); + await moved; + // Wait for any potential save to occur from the move operation + await setTimeout(1000); + + const resized = once(w, 'resize'); + w.setSize(500, 400); + await resized; + // Wait for any potential save to occur from the resize operation + await setTimeout(1000); + + const afterMoveModTime = getPrefsModTime(preferencesPath); + + expect(afterMoveModTime.getTime()).to.equal(initialModTime.getTime()); + }); + + it('should eventually flush window state to disk after batching period', async () => { + // Wait for preferences file to be created if its the first time we're running the test + await waitForPrefsFileCreation(preferencesPath); + + const initialModTime = getPrefsModTime(preferencesPath); + + const resized = once(w, 'resize'); + w.setSize(500, 400); + await resized; + + await waitForPrefsUpdate(initialModTime, preferencesPath); + + const savedState = getWindowStateFromDisk(windowName, preferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-batching-behavior" does not exist'); + expect(savedState.right - savedState.left).to.equal(500); + expect(savedState.bottom - savedState.top).to.equal(400); + }); + + it('should batch multiple window operations and save final state', async () => { + // Wait for preferences file to be created if its the first time we're running the test + await waitForPrefsFileCreation(preferencesPath); + + const initialModTime = getPrefsModTime(preferencesPath); + + const resize1 = once(w, 'resize'); + w.setSize(500, 400); + await resize1; + // Wait for any potential save to occur + await setTimeout(1000); + + const afterFirstResize = getPrefsModTime(preferencesPath); + + const resize2 = once(w, 'resize'); + w.setSize(600, 500); + await resize2; + // Wait for any potential save to occur + await setTimeout(1000); + + const afterSecondResize = getPrefsModTime(preferencesPath); + + const resize3 = once(w, 'resize'); + w.setSize(700, 600); + await resize3; + // Wait for any potential save to occur + await setTimeout(1000); + + const afterThirdResize = getPrefsModTime(preferencesPath); + + await waitForPrefsUpdate(initialModTime, preferencesPath); + + const savedState = getWindowStateFromDisk(windowName, preferencesPath); + expect(savedState).to.not.be.null('window state with window name "test-batching-behavior" does not exist'); + + [afterFirstResize, afterSecondResize, afterThirdResize].forEach(time => { + expect(time.getTime()).to.equal(initialModTime.getTime()); + }); + + expect(savedState.right - savedState.left).to.equal(700); + expect(savedState.bottom - savedState.top).to.equal(600); + }); + + it('should not save window bounds when main thread is busy', async () => { + // Wait for preferences file to be created if its the first time we're running the test + await waitForPrefsFileCreation(preferencesPath); + + const initialModTime = getPrefsModTime(preferencesPath); + + const moved = once(w, 'move'); + w.setPosition(100, 100); + await moved; + + const startTime = Date.now(); + + // Keep main thread busy for 25 seconds + while (Date.now() - startTime < 25000); + + const finalModTime = getPrefsModTime(preferencesPath); + + expect(finalModTime.getTime()).to.equal(initialModTime.getTime()); + }); + }); + }); + + describe('clear window state', () => { + const windowName = 'test-window-clear'; + const preferencesPath = path.join(app.getPath('userData'), 'Local State'); + + beforeEach(async () => { + // Timeout here plays nice with CI + await setTimeout(2000); + // Let's start with a clean slate everytime + BrowserWindow.clearPersistedState(windowName); + }); + + afterEach(closeAllWindows); + + it('should clear existing window state', async () => { + const initialModTime = getPrefsModTime(preferencesPath); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + w.destroy(); + + await waitForPrefsUpdate(initialModTime, preferencesPath); + + const stateBefore = getWindowStateFromDisk(windowName, preferencesPath); + expect(stateBefore).to.not.be.null('window state with window name "test-window-clear" should exist but does not'); + + BrowserWindow.clearPersistedState(windowName); + + await waitForPrefsUpdate(getPrefsModTime(preferencesPath), preferencesPath); + + const stateAfter = getWindowStateFromDisk(windowName, preferencesPath); + expect(stateAfter).to.be.null('window state with window name "test-window-clear" should be cleared'); + }); + + it('should clear existing window state from memory immediately', async () => { + const w = new BrowserWindow({ + height: 100, + width: 100, + name: windowName, + windowStatePersistence: true, + show: false + }); + + w.destroy(); + + const w1 = new BrowserWindow({ + height: 200, + width: 200, + name: windowName, + windowStatePersistence: true, + show: false + }); + + // This proves that the window state exists in memory + expect(w1.getBounds().width).to.equal(100); + expect(w1.getBounds().height).to.equal(100); + + w1.destroy(); + + BrowserWindow.clearPersistedState(windowName); + + const w2 = new BrowserWindow({ + height: 200, + width: 200, + name: windowName, + windowStatePersistence: true, + show: false + }); + // windowStatePersistence: true should override the constructor bounds if not cleared + // If the window has dimensions 200x200, it indicates that the state was indeed cleared + expect(w2.getBounds().width).to.equal(200); + expect(w2.getBounds().height).to.equal(200); + + w2.destroy(); + }); + + it('should not throw when clearing non-existent window state', () => { + expect(() => { + BrowserWindow.clearPersistedState('non-existent-window'); + }).to.not.throw(); + }); + + it('should not affect other window states when clearing specific window', async () => { + const windowName1 = 'test-window-1'; + const windowName2 = 'test-window-2'; + const initialModTime = getPrefsModTime(preferencesPath); + + const w1 = new BrowserWindow({ + name: windowName1, + windowStatePersistence: true, + show: false + }); + w1.destroy(); + + const w2 = new BrowserWindow({ + name: windowName2, + windowStatePersistence: true, + show: false + }); + w2.destroy(); + + await waitForPrefsUpdate(initialModTime, preferencesPath); + + expect(getWindowStateFromDisk(windowName1, preferencesPath)).to.not.be.null('window state with window name "test-window-1" should exist but does not'); + expect(getWindowStateFromDisk(windowName2, preferencesPath)).to.not.be.null('window state with window name "test-window-2" should exist but does not'); + + BrowserWindow.clearPersistedState(windowName1); + + await waitForPrefsUpdate(getPrefsModTime(preferencesPath), preferencesPath); + + // Verify if only window1 was cleared + expect(getWindowStateFromDisk(windowName1, preferencesPath)).to.be.null('window state with window name "test-window-1" should be cleared'); + expect(getWindowStateFromDisk(windowName2, preferencesPath)).to.not.be.null('window state with window name "test-window-2" should not be cleared'); + }); + }); + + describe('restore window state', () => { + const preferencesPath = path.join(app.getPath('userData'), 'Local State'); + const windowName = 'test-restore-window'; + + beforeEach(async () => { + // Timeout here plays nice with CI + await setTimeout(2000); + // Let's start with a clean slate everytime + BrowserWindow.clearPersistedState(windowName); + }); + + afterEach(closeAllWindows); + + describe('single monitor tests', () => { + // Window state restoration takes into account current work area bounds to readjust height/width + // height and width will be readjusted to kMinimumVisibleWidth*kMinimumVisibleHeight (100x100) + // if there is no capturable screen + it('should restore bounds when windowStatePersistence is true', async () => { + const workArea = screen.getPrimaryDisplay().workArea; + const bounds = { width: 100, height: 100, x: workArea.x, y: workArea.y }; + await createAndSaveWindowState(preferencesPath, windowName, bounds); + // Should override default constructor bounds + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + width: 500, + height: 400, + x: 200, + y: 250, + show: false + }); + + expectBoundsEqual(w.getBounds(), bounds); + + w.destroy(); + }); + + it('should use default window options when no saved state exists', async () => { + const defaultBounds = { width: 500, height: 400, x: 200, y: 250 }; + // BrowserWindow.clearPersistedState(windowName) is called in beforeEach + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + ...defaultBounds, + show: false + }); + // Should take the default bounds from the constructor as there is no saved state + expectBoundsEqual(w.getBounds(), defaultBounds); + expect(w.isFullScreen()).to.equal(false); + expect(w.isMaximized()).to.equal(false); + + w.destroy(); + }); + + it('should restore fullscreen state when windowStatePersistence is true', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { fullscreen: true }); + await setTimeout(2000); + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true + }); + + const enterFullScreen = once(w, 'enter-full-screen'); + if (!w.isFullScreen()) await enterFullScreen; + + expect(w.isFullScreen()).to.equal(true); + + w.destroy(); + }); + + it('should restore kiosk state when windowStatePersistence is true', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { kiosk: true }); + await setTimeout(2000); + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true + }); + + const enterFullScreen = once(w, 'enter-full-screen'); + if (!w.isFullScreen()) await enterFullScreen; + + expect(w.isFullScreen()).to.equal(true); + expect(w.isKiosk()).to.equal(true); + + w.destroy(); + }); + + it('should restore maximized state when windowStatePersistence is true', async () => { + const width = screen.getPrimaryDisplay().workArea.width; + const height = screen.getPrimaryDisplay().workArea.height; + await createAndSaveWindowState(preferencesPath, windowName, { width, height }); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const maximized = once(w, 'maximize'); + if (!w.isMaximized()) await maximized; + + expect(w.isMaximized()).to.equal(true); + + w.destroy(); + }); + + it('should not restore state when windowStatePersistence is false', async () => { + const bounds = { width: 400, height: 300, x: 100, y: 150 }; + await createAndSaveWindowState(preferencesPath, windowName, bounds); + + const defaultBounds = { width: 500, height: 400, x: 200, y: 250 }; + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: false, + ...defaultBounds, + show: false + }); + + expectBoundsEqual(w.getBounds(), defaultBounds); + + w.destroy(); + }); + + it('should restore bounds only when displayMode is disabled', async () => { + // We don't use the utility createAndSaveWindowState here because the default bounds + // passed through the constructor get affected by setting fullscreen: true alongside it. + // It particularly affects this test because we want to ensure initial bounds stay the same + // on restore. + const workArea = screen.getPrimaryDisplay().workArea; + const defaultBounds = { width: 100, height: 100, x: workArea.x, y: workArea.y }; + const initialWindow = new BrowserWindow({ + ...defaultBounds, + show: false, + name: windowName, + windowStatePersistence: true + }); + const enterFullScreen = once(initialWindow, 'enter-full-screen'); + initialWindow.setFullScreen(true); + if (!initialWindow.isFullScreen()) await enterFullScreen; + + initialWindow.destroy(); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: { + displayMode: false + }, + show: false + }); + // We expect the bounds to restore to the values same as before the fullscreen state was set + expectBoundsEqual(w.getBounds(), defaultBounds); + expect(w.isFullScreen()).to.equal(false); + + w.destroy(); + }); + + it('should restore display modes when bounds is disabled', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { fullscreen: true }); + await setTimeout(2000); + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: { + bounds: false + } + }); + + const enterFullScreen = once(w, 'enter-full-screen'); + if (!w.isFullScreen()) await enterFullScreen; + expect(w.isFullScreen()).to.equal(true); + + w.destroy(); + }); + + it('should respect fullscreenable property', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { fullscreen: true }); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + fullscreenable: false, + show: false + }); + // Wait for the window to potentially enter fullscreen + await setTimeout(2000); + + expect(w.isFullScreen()).to.equal(false); + expect(w.isFullScreenable()).to.equal(false); + + w.destroy(); + }); + + it('should respect minWidth and minHeight properly', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { width: 200, height: 200 }); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + minWidth: 400, + minHeight: 400, + show: false + }); + + const bounds = w.getBounds(); + expect(bounds.width).to.be.at.least(400); + expect(bounds.height).to.be.at.least(400); + }); + + it('should respect maxWidth and maxHeight properly', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { width: 800, height: 800 }); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + maxWidth: 400, + maxHeight: 400, + show: false + }); + + const bounds = w.getBounds(); + expect(bounds.width).to.be.at.most(400); + expect(bounds.height).to.be.at.most(400); + }); + + it('should restore correct state for each named window independently - multi window check', async () => { + const window1Name = 'test-window-1'; + const window2Name = 'test-window-2'; + + // Clear any existing state + BrowserWindow.clearPersistedState(window1Name); + BrowserWindow.clearPersistedState(window2Name); + + const workArea = screen.getPrimaryDisplay().workArea; + + const bounds1 = { width: 100, height: 100, x: workArea.x, y: workArea.y }; + const w1 = new BrowserWindow({ + name: window1Name, + windowStatePersistence: true, + ...bounds1, + show: false + }); + + w1.destroy(); + + const bounds2 = { width: 120, height: 100, x: workArea.x, y: workArea.y }; + const w2 = new BrowserWindow({ + name: window2Name, + windowStatePersistence: true, + ...bounds2, + show: false + }); + + w2.destroy(); + + if (!fs.existsSync(preferencesPath)) { + // File doesn't exist, wait for creation + await waitForPrefsFileCreation(preferencesPath); + } else { + // File exists, wait for update + const initialModTime = getPrefsModTime(preferencesPath); + await waitForPrefsUpdate(initialModTime, preferencesPath); + } + + const restored1 = new BrowserWindow({ + name: window1Name, + windowStatePersistence: true, + show: false + }); + + const restored2 = new BrowserWindow({ + name: window2Name, + windowStatePersistence: true, + show: false + }); + + expectBoundsEqual(restored1.getBounds(), bounds1); + expectBoundsEqual(restored2.getBounds(), bounds2); + + restored1.destroy(); + restored2.destroy(); + }); + + it('should adjust restored bounds if they overflow current work area entirely', async () => { + const workArea = screen.getPrimaryDisplay().workArea; + // Completely off-screen to the right + const offscreenBounds = { + width: 100, + height: 100, + x: workArea.x + workArea.width + 10, + y: workArea.y + workArea.height + 10 + }; + + await createAndSaveWindowState(preferencesPath, windowName, offscreenBounds); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const bounds = w.getBounds(); + + // Window should be moved to be entirely visible + expect(bounds.x + bounds.width).to.be.at.most(workArea.x + workArea.width); + expect(bounds.y + bounds.height).to.be.at.most(workArea.y + workArea.height); + expect(bounds.x).to.be.at.least(workArea.x); + expect(bounds.y).to.be.at.least(workArea.y); + expect(bounds.width).to.equal(100); + expect(bounds.height).to.equal(100); + + w.destroy(); + }); + + ifit(process.platform === 'darwin')('should adjust bounds if window overflows work area such that the window is entirely visible', async () => { + const workArea = screen.getPrimaryDisplay().workArea; + const overflowBounds = { + width: 100, + height: 100, + x: workArea.x + workArea.width - 20, + y: workArea.y + workArea.height - 20 + }; + + await createAndSaveWindowState(preferencesPath, windowName, overflowBounds); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const bounds = w.getBounds(); + + // On macOS, window should be adjusted to be entirely visible + expect(bounds.x + bounds.width).to.be.at.most(workArea.x + workArea.width); + expect(bounds.y + bounds.height).to.be.at.most(workArea.y + workArea.height); + expect(bounds.width).to.equal(100); + expect(bounds.height).to.equal(100); + + w.destroy(); + }); + + ifit(process.platform !== 'darwin')('should adjust bounds if window overflows work area such that the window has minimum visible height/width 100x100', async () => { + const workArea = screen.getPrimaryDisplay().workArea; + // Initialize with 50x50 of the window visible + const overflowBounds = { + width: 120, + height: 120, + x: workArea.x + workArea.width - 50, + y: workArea.y + workArea.height - 50 + }; + + await createAndSaveWindowState(preferencesPath, windowName, overflowBounds); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const bounds = w.getBounds(); + // Calculate the boundaries of the visible intersection rectangle + const leftMost = Math.max(bounds.x, workArea.x); + const rightMost = Math.min(bounds.x + bounds.width, workArea.x + workArea.width); + const topMost = Math.max(bounds.y, workArea.y); + const bottomMost = Math.min(bounds.y + bounds.height, workArea.y + workArea.height); + // On non-macOS platforms, at least 100x100 should be visible + const visibleWidth = rightMost - leftMost; + const visibleHeight = bottomMost - topMost; + + expect(visibleWidth).to.be.at.least(100); + expect(visibleHeight).to.be.at.least(100); + expect(bounds.width).to.equal(120); + expect(bounds.height).to.equal(120); + + w.destroy(); + }); + + it('should respect show:false when restoring display modes', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { fullscreen: true }); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const shown = once(w, 'show'); + const enterFullScreen = once(w, 'enter-full-screen'); + + await setTimeout(2000); + expect(w.isVisible()).to.equal(false); + + w.show(); + await shown; + expect(w.isVisible()).to.equal(true); + + // Fullscreen state should still be restored correctly + if (!w.isFullScreen()) await enterFullScreen; + expect(w.isFullScreen()).to.equal(true); + + w.destroy(); + }); + }); + + // FIXME(nilayarya): Figure out why these tests fail on macOS-x64 + // virtualDisplay.create() is creating double displays on macOS-x64 + const testMultiMonitor = + process.platform === 'darwin' && + process.arch === 'arm64' && + screen.getAllDisplays().length === 1; + + ifdescribe(testMultiMonitor)('multi-monitor tests', () => { + const virtualDisplay = require('@electron-ci/virtual-display'); + const primaryDisplay = screen.getPrimaryDisplay(); + + beforeEach(async () => { + virtualDisplay.forceCleanup(); + let attempts = 0; + while (screen.getAllDisplays().length > 1 && attempts++ < 20) await setTimeout(1000); + const displayCount = screen.getAllDisplays().length; + // We expect only the primary display to be present + expect(displayCount).to.equal(1, `Display cleanup failed: ${displayCount} displays remain`); + }); + + it('should restore window bounds correctly on a secondary display', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create a new virtual target display to the right of the primary display + const targetDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + // Verify the virtual display is created correctly + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + expect(targetDisplay.bounds.x).to.equal(targetDisplayX); + expect(targetDisplay.bounds.y).to.equal(targetDisplayY); + expect(targetDisplay.bounds.width).to.equal(1920); + expect(targetDisplay.bounds.height).to.equal(1080); + + // Bounds for the test window on the virtual target display + const boundsOnTargetDisplay = { + width: 400, + height: 300, + x: targetDisplay.workArea.x + 100, + y: targetDisplay.workArea.y + 100 + }; + + await createAndSaveWindowState(preferencesPath, windowName, boundsOnTargetDisplay); + + // Restore the window state by creating a new window with the same name + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const restoredBounds = w.getBounds(); + expectBoundsEqual(restoredBounds, boundsOnTargetDisplay); + + w.destroy(); + virtualDisplay.destroy(targetDisplayId); + }); + + it('should restore window to a visible location when saved display no longer exists', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create a new virtual target display to the right of the primary display + const targetDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + // Verify the virtual display is created correctly - single check for targetDisplay.bounds.x + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + expect(targetDisplay.bounds.x).to.equal(targetDisplayX); + + // Bounds for the test window on the virtual target display + const boundsOnTargetDisplay = { + width: 400, + height: 300, + x: targetDisplay.workArea.x + 100, + y: targetDisplay.workArea.y + 100 + }; + + // Save window state on the virtual display + await createAndSaveWindowState(preferencesPath, windowName, boundsOnTargetDisplay); + + virtualDisplay.destroy(targetDisplayId); + // Wait for the target virtual display to be destroyed + while (screen.getAllDisplays().length > 1) await setTimeout(1000); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const restoredBounds = w.getBounds(); + const primaryWorkArea = primaryDisplay.workArea; + + // Window should be fully visible on the primary display + expect(restoredBounds.x).to.be.at.least(primaryWorkArea.x); + expect(restoredBounds.y).to.be.at.least(primaryWorkArea.y); + expect(restoredBounds.x + restoredBounds.width).to.be.at.most(primaryWorkArea.x + primaryWorkArea.width); + expect(restoredBounds.y + restoredBounds.height).to.be.at.most(primaryWorkArea.y + primaryWorkArea.height); + + // Window should maintain its original size + expect(restoredBounds.width).to.equal(boundsOnTargetDisplay.width); + expect(restoredBounds.height).to.equal(boundsOnTargetDisplay.height); + + w.destroy(); + }); + + it('should fallback to nearest display when saved display no longer exists', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create first virtual display to the right of primary + const middleDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + + // Create second virtual display to the right of the first (rightmost) + const rightmostDisplayX = targetDisplayX + 1920; + const rightmostDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: rightmostDisplayX, + y: targetDisplayY + }); + + // Wait for the target displays to be created + while (screen.getAllDisplays().length !== 3) await setTimeout(1000); + + // Verify the virtual displays are created correctly - single check for origin x values + const middleDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + expect(middleDisplay.bounds.x).to.equal(targetDisplayX); + + const rightmostDisplay = screen.getDisplayNearestPoint({ x: rightmostDisplayX, y: targetDisplayY }); + expect(rightmostDisplay.bounds.x).to.equal(rightmostDisplayX); + + // Bounds for the test window on the rightmost display + const boundsOnRightmostDisplay = { + width: 400, + height: 300, + x: rightmostDisplay.workArea.x + 100, + y: rightmostDisplay.workArea.y + 100 + }; + + // Save window state on the rightmost display + await createAndSaveWindowState(preferencesPath, windowName, boundsOnRightmostDisplay); + + // Destroy the rightmost display (where window was saved) + virtualDisplay.destroy(rightmostDisplayId); + // Wait for the rightmost display to be destroyed + while (screen.getAllDisplays().length > 2) await setTimeout(1000); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const restoredBounds = w.getBounds(); + + // Window should be restored on the middle display (nearest remaining display) + expect(restoredBounds.x).to.be.at.least(middleDisplay.workArea.x); + expect(restoredBounds.y).to.be.at.least(middleDisplay.workArea.y); + expect(restoredBounds.x + restoredBounds.width).to.be.at.most(middleDisplay.workArea.x + middleDisplay.workArea.width); + expect(restoredBounds.y + restoredBounds.height).to.be.at.most(middleDisplay.workArea.y + middleDisplay.workArea.height); + + // Window should maintain its original size + expect(restoredBounds.width).to.equal(boundsOnRightmostDisplay.width); + expect(restoredBounds.height).to.equal(boundsOnRightmostDisplay.height); + + w.destroy(); + virtualDisplay.destroy(middleDisplayId); + }); + + it('should restore multiple named windows independently across displays', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create a first virtual display to the right of the primary display + const targetDisplayId1 = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + // Create a second virtual display to the right of the first + const targetDisplayId2 = virtualDisplay.create({ + width: 1600, + height: 900, + x: targetDisplayX + 1920, + y: targetDisplayY + }); + + // Wait for the target displays to be created + while (screen.getAllDisplays().length !== 3) await setTimeout(1000); + + // Verify the virtual displays are created correctly - single check for origin x values + const targetDisplay1 = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + expect(targetDisplay1.bounds.x).to.equal(targetDisplayX); + + const targetDisplay2 = screen.getDisplayNearestPoint({ x: targetDisplayX + 1920, y: targetDisplayY }); + expect(targetDisplay2.bounds.x).to.equal(targetDisplayX + 1920); + + // Window 1 on primary display + const window1Name = 'test-multi-window-1'; + const bounds1 = { + width: 300, + height: 200, + x: primaryDisplay.workArea.x + 50, + y: primaryDisplay.workArea.y + 50 + }; + + // Window 2 on second display (first virtual) + const window2Name = 'test-multi-window-2'; + const bounds2 = { + width: 400, + height: 300, + x: targetDisplay1.workArea.x + 100, + y: targetDisplay1.workArea.y + 100 + }; + + // Window 3 on third display (second virtual) + const window3Name = 'test-multi-window-3'; + const bounds3 = { + width: 350, + height: 250, + x: targetDisplay2.workArea.x + 150, + y: targetDisplay2.workArea.y + 150 + }; + + // Clear window state for all three windows from previous tests + BrowserWindow.clearPersistedState(window1Name); + BrowserWindow.clearPersistedState(window2Name); + BrowserWindow.clearPersistedState(window3Name); + + // Create and save state for all three windows + const w1 = new BrowserWindow({ + name: window1Name, + windowStatePersistence: true, + show: false, + ...bounds1 + }); + const w2 = new BrowserWindow({ + name: window2Name, + windowStatePersistence: true, + show: false, + ...bounds2 + }); + const w3 = new BrowserWindow({ + name: window3Name, + windowStatePersistence: true, + show: false, + ...bounds3 + }); + + w1.destroy(); + w2.destroy(); + w3.destroy(); + + await setTimeout(2000); + + // Restore all three windows + const restoredW1 = new BrowserWindow({ + name: window1Name, + windowStatePersistence: true, + show: false + }); + const restoredW2 = new BrowserWindow({ + name: window2Name, + windowStatePersistence: true, + show: false + }); + const restoredW3 = new BrowserWindow({ + name: window3Name, + windowStatePersistence: true, + show: false + }); + + // Check that each window restored to its correct display and position + expectBoundsEqual(restoredW1.getBounds(), bounds1); + expectBoundsEqual(restoredW2.getBounds(), bounds2); + expectBoundsEqual(restoredW3.getBounds(), bounds3); + + restoredW1.destroy(); + restoredW2.destroy(); + restoredW3.destroy(); + virtualDisplay.destroy(targetDisplayId1); + virtualDisplay.destroy(targetDisplayId2); + }); + + it('should restore fullscreen state on correct display', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create a new virtual target display to the right of the primary display + const targetDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + + // Wait for the target displays to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + expect(targetDisplay.bounds.x).to.equal(targetDisplayX); + + // Create window on target display and set fullscreen + const initialBounds = { + width: 400, + height: 300, + x: targetDisplay.workArea.x + 100, + y: targetDisplay.workArea.y + 100, + fullscreen: true + }; + + await createAndSaveWindowState(preferencesPath, windowName, initialBounds); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true + }); + + const enterFullScreen = once(w, 'enter-full-screen'); + if (!w.isFullScreen()) await enterFullScreen; + + expect(w.isFullScreen()).to.equal(true); + + // Check that fullscreen window is on the correct display + const fsBounds = w.getBounds(); + expect(fsBounds.x).to.be.at.least(targetDisplay.bounds.x); + expect(fsBounds.y).to.be.at.least(targetDisplay.bounds.y); + expect(fsBounds.x + fsBounds.width).to.be.at.most(targetDisplay.bounds.x + targetDisplay.bounds.width); + expect(fsBounds.y + fsBounds.height).to.be.at.most(targetDisplay.bounds.y + targetDisplay.bounds.height); + + w.destroy(); + virtualDisplay.destroy(targetDisplayId); + }); + + it('should restore maximized state on correct display', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create a new virtual target display to the right of the primary display + const targetDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + + // Wait for the target displays to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + expect(targetDisplay.bounds.x).to.equal(targetDisplayX); + + // Create window on target display and maximize it + const w1 = new BrowserWindow({ + name: windowName, + windowStatePersistence: { + displayMode: false + }, + x: targetDisplay.workArea.x, + y: targetDisplay.workArea.y + }); + + const maximized = once(w1, 'maximize'); + w1.maximize(); + if (!w1.isMaximized()) await maximized; + + w1.destroy(); + await setTimeout(2000); + + const w2 = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: true + }); + + const maximized_ = once(w2, 'maximize'); + if (!w2.isMaximized()) await maximized_; + + expect(w2.isMaximized()).to.equal(true); + // Check that maximized window is on the correct display + const maximizedBounds = w2.getBounds(); + expect(maximizedBounds.x).to.be.at.least(targetDisplay.bounds.x); + expect(maximizedBounds.y).to.be.at.least(targetDisplay.bounds.y); + expect(maximizedBounds.x + maximizedBounds.width).to.be.at.most(targetDisplay.bounds.x + targetDisplay.bounds.width); + expect(maximizedBounds.y + maximizedBounds.height).to.be.at.most(targetDisplay.bounds.y + targetDisplay.bounds.height); + + w2.destroy(); + virtualDisplay.destroy(targetDisplayId); + }); + + it('should restore kiosk state on correct display', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create a new virtual target display to the right of the primary display + const targetDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + + // Create window on target display and set kiosk: true + const initialBounds = { + width: 400, + height: 300, + x: targetDisplay.workArea.x + 100, + y: targetDisplay.workArea.y + 100, + kiosk: true + }; + + await createAndSaveWindowState(preferencesPath, windowName, initialBounds); + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true + }); + + const enterFullScreen = once(w, 'enter-full-screen'); + if (!w.isFullScreen()) await enterFullScreen; + + expect(w.isFullScreen()).to.equal(true); + expect(w.isKiosk()).to.equal(true); + + // Check that kiosk window is on the correct display + const kioskBounds = w.getBounds(); + expect(kioskBounds.x).to.be.at.least(targetDisplay.bounds.x); + expect(kioskBounds.y).to.be.at.least(targetDisplay.bounds.y); + expect(kioskBounds.x + kioskBounds.width).to.be.at.most(targetDisplay.bounds.x + targetDisplay.bounds.width); + expect(kioskBounds.y + kioskBounds.height).to.be.at.most(targetDisplay.bounds.y + targetDisplay.bounds.height); + + w.destroy(); + virtualDisplay.destroy(targetDisplayId); + }); + + it('should maintain same bounds when target display resolution increases', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + + // Create initial virtual display + const targetDisplayId = virtualDisplay.create({ + width: 1920, + height: 1080, + x: targetDisplayX, + y: targetDisplayY + }); + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + + // Create a new virtual display with double the resolution of the target display + const higherResDisplayId = virtualDisplay.create({ + width: targetDisplay.bounds.width * 2, + height: targetDisplay.bounds.height * 2, + x: targetDisplayX + targetDisplay.bounds.width, + y: targetDisplayY + }); + + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 3) await setTimeout(1000); + + // Bounds for the test window on the virtual target display + const initialBounds = { + width: 400, + height: 300, + x: targetDisplay.workArea.x + 100, + y: targetDisplay.workArea.y + 100 + }; + + await createAndSaveWindowState(preferencesPath, windowName, initialBounds); + + // Destroy the target display and wait for the higher resolution display to take its place + virtualDisplay.destroy(targetDisplayId); + while (screen.getAllDisplays().length > 2) await setTimeout(1000); + + // Restore window + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const restoredBounds = w.getBounds(); + + // Window should maintain same x, y, width, height as the display got bigger + expectBoundsEqual(restoredBounds, initialBounds); + + w.destroy(); + virtualDisplay.destroy(higherResDisplayId); + }); + + it('should reposition and resize window when target display resolution decreases', async () => { + const targetDisplayX = primaryDisplay.bounds.x + primaryDisplay.bounds.width; + const targetDisplayY = primaryDisplay.bounds.y; + // Create initial virtual display with high resolution + const targetDisplayId = virtualDisplay.create({ + width: 2560, + height: 1440, + x: targetDisplayX, + y: targetDisplayY + }); + + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 2) await setTimeout(1000); + + const targetDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplayY }); + + // Create a new virtual display with half the resolution of the target display shifted down + const lowerResDisplayId = virtualDisplay.create({ + width: targetDisplay.bounds.width / 2, + height: targetDisplay.bounds.height / 2, + x: targetDisplayX + targetDisplay.bounds.width, + y: targetDisplay.bounds.height / 2 + }); + + // Wait for the target display to be created + while (screen.getAllDisplays().length !== 3) await setTimeout(1000); + + // Bounds that would overflow on a smaller display + const initialBounds = { + x: targetDisplay.workArea.x, + y: targetDisplay.workArea.y, + width: targetDisplay.bounds.width, + height: targetDisplay.bounds.height + }; + + await createAndSaveWindowState(preferencesPath, windowName, initialBounds); + + // Destroy and and wait for the lower resolution display to take its place + virtualDisplay.destroy(targetDisplayId); + while (screen.getAllDisplays().length > 2) await setTimeout(1000); + + // We expect the display to be shifted down as we set y: targetDisplay.bounds.height / 2 earlier + const smallerDisplay = screen.getDisplayNearestPoint({ x: targetDisplayX, y: targetDisplay.bounds.height / 2 }); + + // Restore window + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + const restoredBounds = w.getBounds(); + + // Window should be repositioned to be entirely visible on smaller display + expect(restoredBounds.x).to.be.at.least(smallerDisplay.workArea.x); + expect(restoredBounds.y).to.be.at.least(smallerDisplay.workArea.y); + expect(restoredBounds.x + restoredBounds.width).to.be.at.most(smallerDisplay.workArea.x + smallerDisplay.workArea.width); + expect(restoredBounds.y + restoredBounds.height).to.be.at.most(smallerDisplay.workArea.y + smallerDisplay.workArea.height); + + w.destroy(); + virtualDisplay.destroy(lowerResDisplayId); + }); + }); + }); + describe('event emitters', () => { + const preferencesPath = path.join(app.getPath('userData'), 'Local State'); + const windowName = 'test-restore-window'; + + it('should emit restored-persisted-state when windowStatePersistence is enabled and state exists', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { width: 300, height: 200 }); + + const restoredPromise = new Promise<void>((resolve) => { + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + w.once('restored-persisted-state', () => { + resolve(); + w.destroy(); + }); + }); + + await restoredPromise; + }); + + it('should not emit restored-persisted-state when windowStatePersistence is disabled', async () => { + await createAndSaveWindowState(preferencesPath, windowName, { width: 300, height: 200 }); + + let eventEmitted = false; + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: false, + show: false + }); + + w.on('restored-persisted-state', () => { + eventEmitted = true; + }); + + // Wait for the event to be emitted for 5 seconds + await setTimeout(5000); + + expect(eventEmitted).to.equal(false); + w.destroy(); + }); + + it('should not emit restored-persisted-state when no window state exists on disk', async () => { + // Clear any existing state to ensure no state exists + BrowserWindow.clearPersistedState(windowName); + + let eventEmitted = false; + + const w = new BrowserWindow({ + name: windowName, + windowStatePersistence: true, + show: false + }); + + w.on('restored-persisted-state', () => { + eventEmitted = true; + }); + + // Wait for the event to be emitted for 5 seconds + await setTimeout(5000); + + expect(eventEmitted).to.equal(false); + w.destroy(); + }); + }); + }); }); diff --git a/spec/api-context-bridge-spec.ts b/spec/api-context-bridge-spec.ts index b7fa47104264a..e83244141828b 100644 --- a/spec/api-context-bridge-spec.ts +++ b/spec/api-context-bridge-spec.ts @@ -671,7 +671,7 @@ describe('contextBridge', () => { it('should release the global hold on methods sent across contexts', async () => { await makeBindingWindow(() => { const trackedValues: WeakRef<object>[] = []; - require('electron').ipcRenderer.on('get-gc-info', e => e.sender.send('gc-info', { trackedValues: trackedValues.filter(value => value.deref()).length })); + require('electron').ipcRenderer.on('get-gc-info', (e: any) => e.sender.send('gc-info', { trackedValues: trackedValues.filter(value => value.deref()).length })); contextBridge.exposeInMainWorld('example', { getFunction: () => () => 123, track: (value: object) => { trackedValues.push(new WeakRef(value)); } @@ -699,7 +699,7 @@ describe('contextBridge', () => { it('should not leak the global hold on methods sent across contexts when reloading a sandboxed renderer', async () => { await makeBindingWindow(() => { const trackedValues: WeakRef<object>[] = []; - require('electron').ipcRenderer.on('get-gc-info', e => e.sender.send('gc-info', { trackedValues: trackedValues.filter(value => value.deref()).length })); + require('electron').ipcRenderer.on('get-gc-info', (e: any) => e.sender.send('gc-info', { trackedValues: trackedValues.filter(value => value.deref()).length })); contextBridge.exposeInMainWorld('example', { getFunction: () => () => 123, track: (value: object) => { trackedValues.push(new WeakRef(value)); } diff --git a/spec/api-ipc-spec.ts b/spec/api-ipc-spec.ts index d1be06727ca95..062d99f51e113 100644 --- a/spec/api-ipc-spec.ts +++ b/spec/api-ipc-spec.ts @@ -243,7 +243,6 @@ describe('ipc module', () => { await w.webContents.executeJavaScript(`(${function () { try { const buffer = new ArrayBuffer(10); - // @ts-expect-error require('electron').ipcRenderer.postMessage('port', '', [buffer]); } catch (e) { require('electron').ipcRenderer.postMessage('port', { error: (e as Error).message }); @@ -323,7 +322,7 @@ describe('ipc module', () => { w.loadURL('about:blank'); await w.webContents.executeJavaScript(`(${function () { const { ipcRenderer } = require('electron'); - ipcRenderer.on('port', e => { + ipcRenderer.on('port', (e: any) => { const [port] = e.ports; port.start(); port.onclose = () => { @@ -480,8 +479,8 @@ describe('ipc module', () => { w.loadURL('about:blank'); await w.webContents.executeJavaScript(`(${function () { const { ipcRenderer } = require('electron'); - ipcRenderer.on('port', ev => { - const [port] = ev.ports; + ipcRenderer.on('port', (e: any) => { + const [port] = e.ports; port.onmessage = () => { ipcRenderer.send('done'); }; @@ -498,9 +497,9 @@ describe('ipc module', () => { w.loadURL('about:blank'); await w.webContents.executeJavaScript(`(${function () { const { ipcRenderer } = require('electron'); - ipcRenderer.on('port', e1 => { - e1.ports[0].onmessage = e2 => { - e2.ports[0].onmessage = e3 => { + ipcRenderer.on('port', (e1: any) => { + e1.ports[0].onmessage = (e2: any) => { + e2.ports[0].onmessage = (e3: any) => { ipcRenderer.send('done', e3.data); }; }; @@ -587,7 +586,7 @@ describe('ipc module', () => { w.loadURL('about:blank'); await w.webContents.executeJavaScript(`(${function () { const { ipcRenderer } = require('electron'); - ipcRenderer.on('foo', (_e, msg) => { + ipcRenderer.on('foo', (_e: Event, msg: string) => { ipcRenderer.send('bar', msg); }); }})()`); diff --git a/spec/api-native-image-spec.ts b/spec/api-native-image-spec.ts index 9d32af6d7cc50..3ad3e08be6586 100644 --- a/spec/api-native-image-spec.ts +++ b/spec/api-native-image-spec.ts @@ -348,6 +348,11 @@ describe('nativeImage module', () => { expect(image.isEmpty()).to.be.false(); }); + ifit(process.platform === 'darwin')('returns a valid named symbol on darwin', function () { + const image = nativeImage.createFromNamedImage('atom'); + expect(image.isEmpty()).to.be.false(); + }); + ifit(process.platform === 'darwin')('returns allows an HSL shift for a valid image on darwin', function () { const image = nativeImage.createFromNamedImage('NSActionTemplate', [0.5, 0.2, 0.8]); expect(image.isEmpty()).to.be.false(); diff --git a/spec/api-protocol-spec.ts b/spec/api-protocol-spec.ts index 415ed5fdafe45..4a2f8b10c9c4e 100644 --- a/spec/api-protocol-spec.ts +++ b/spec/api-protocol-spec.ts @@ -15,6 +15,7 @@ import * as webStream from 'node:stream/web'; import { setTimeout } from 'node:timers/promises'; import * as url from 'node:url'; +import { collectStreamBody, getResponse } from './lib/net-helpers'; import { listen, defer, ifit } from './lib/spec-helpers'; import { WebmGenerator } from './lib/video-helpers'; import { closeAllWindows, closeWindow } from './lib/window-helpers'; @@ -1578,6 +1579,22 @@ describe('protocol module', () => { expect(await net.fetch(url, { bypassCustomProtocolHandlers: true }).then(r => r.text())).to.equal('default'); }); + it('can bypass intercepted protocol handlers with net.request', async () => { + protocol.handle('http', () => new Response('custom')); + defer(() => { protocol.unhandle('http'); }); + const server = http.createServer((req, res) => { + res.end('default'); + }); + defer(() => server.close()); + const { url } = await listen(server); + // Make a request using net.request with bypassCustomProtocolHandlers: true + const request = net.request({ method: 'GET', url, bypassCustomProtocolHandlers: true }); + const response = await getResponse(request); + const body = await collectStreamBody(response); + expect(response.statusCode).to.equal(200); + expect(body).to.equal('default'); + }); + it('bypassing custom protocol handlers also bypasses new protocols', async () => { protocol.handle('app', () => new Response('custom')); defer(() => { protocol.unhandle('app'); }); diff --git a/spec/api-shared-texture-spec.ts b/spec/api-shared-texture-spec.ts new file mode 100644 index 0000000000000..a89edb50b272f --- /dev/null +++ b/spec/api-shared-texture-spec.ts @@ -0,0 +1,281 @@ +import { BaseWindow } from 'electron'; + +import { expect } from 'chai'; + +import { randomUUID } from 'node:crypto'; +import * as path from 'node:path'; + +import { closeWindow } from './lib/window-helpers'; + +const fixtures = path.resolve(__dirname, 'fixtures'); + +describe('sharedTexture module', () => { + const { + nativeImage + } = require('electron'); + + const debugSpec = false; + const dirPath = path.join(fixtures, 'api', 'shared-texture'); + const osrPath = path.join(dirPath, 'osr.html'); + const imagePath = path.join(dirPath, 'image.png'); + const targetImage = nativeImage.createFromPath(imagePath); + + describe('import shared texture produced by osr', () => { + const { + app, + BrowserWindow, + sharedTexture, + ipcMain + } = require('electron'); + + afterEach(async () => { + ipcMain.removeAllListeners(); + for (const w of BaseWindow.getAllWindows()) { + await closeWindow(w); + } + }); + + it('successfully imported and rendered with subtle api', (done) => { + type CapturedTextureHolder = { + importedSubtle: Electron.SharedTextureImportedSubtle, + texture: Electron.OffscreenSharedTexture + } + + const capturedTextures = new Map<string, CapturedTextureHolder>(); + const preloadPath = path.join(dirPath, 'subtle', 'preload.js'); + const htmlPath = path.join(dirPath, 'subtle', 'index.html'); + + const createWindow = () => { + const win = new BrowserWindow({ + width: 256, + height: 256, + show: debugSpec, + webPreferences: { + preload: preloadPath + } + }); + + const osr = new BrowserWindow({ + width: 128, + height: 128, + show: debugSpec, + webPreferences: { + offscreen: { + useSharedTexture: true + } + } + }); + + osr.webContents.setFrameRate(1); + osr.webContents.on('paint', (event: any) => { + // Step 1: Input source of shared texture handle. + const texture = event.texture; + + if (!texture) { + console.error('No texture, GPU may be unavailable, skipping.'); + done(); + return; + } + + // Step 2: Import as SharedTextureImported + console.log(texture.textureInfo); + const importedSubtle = sharedTexture.subtle.importSharedTexture(texture.textureInfo); + + // Step 3: Prepare for transfer to another process (win's renderer) + const transfer = importedSubtle.startTransferSharedTexture(); + + const id = randomUUID(); + capturedTextures.set(id, { importedSubtle, texture }); + + // Step 4: Send the shared texture to the renderer process (goto preload.js) + win.webContents.send('shared-texture', id, transfer); + }); + + ipcMain.on('shared-texture-done', (event: any, id: string) => { + // Step 12: Release the shared texture resources at main process + const data = capturedTextures.get(id); + if (data) { + capturedTextures.delete(id); + const { importedSubtle, texture } = data; + + // Step 13: Release the imported shared texture + importedSubtle.release(() => { + // Step 14: Release the shared texture once GPU is done + texture.release(); + }); + + // Step 15: Slightly timeout and capture the node screenshot + setTimeout(async () => { + // Step 16: Compare the captured image with the target image + const captured = await win.webContents.capturePage({ + x: 16, + y: 16, + width: 128, + height: 128 + }); + + // Step 17: Resize the target image to match the captured image size, in case dpr != 1 + const target = targetImage.resize({ ...captured.getSize() }); + + // Step 18: nativeImage have error comparing pixel data when color space is different, + // send to browser for comparison using canvas. + win.webContents.send('verify-captured-image', { + captured: captured.toDataURL(), + target: target.toDataURL() + }); + }, 300); + } + }); + + ipcMain.on('verify-captured-image-done', (event: any, result: { difference: number, total: number }) => { + // Step 22: Verify the result from renderer process + try { + // macOS may have tiny color difference after the whole rendering process, + // and the color may change slightly when resizing at device pixel ratio != 1. + // Limit error should not be different more than 1% of the whole image. + const ratio = result.difference / result.total; + console.log('image difference: ', ratio); + expect(ratio).to.be.lessThan(0.01); + done(); + } catch (e) { + done(e); + } + }); + + ipcMain.on('webgpu-unavailable', () => { + console.error('WebGPU is not available, skipping.'); + done(); + }); + + win.loadFile(htmlPath); + osr.loadFile(osrPath); + }; + + app.whenReady().then(() => { + createWindow(); + }); + }).timeout(debugSpec ? 100000 : 10000); + + const runSharedTextureManagedTest = (done: Mocha.Done, iframe: boolean) => { + const preloadPath = path.join(dirPath, 'managed', 'preload.js'); + const htmlPath = path.join(dirPath, 'managed', iframe ? 'frame.html' : 'index.html'); + + const createWindow = () => { + const win = new BrowserWindow({ + width: 256, + height: 256, + show: debugSpec, + webPreferences: { + preload: preloadPath, + nodeIntegrationInSubFrames: iframe + } + }); + + const osr = new BrowserWindow({ + width: 128, + height: 128, + show: debugSpec, + webPreferences: { + offscreen: { + useSharedTexture: true + } + } + }); + + osr.webContents.setFrameRate(1); + osr.webContents.on('paint', async (event: any) => { + const targetFrame = iframe ? win.webContents.mainFrame.frames[0] : win.webContents.mainFrame; + if (!targetFrame) { + done(new Error('Target frame not found')); + return; + } + + // Step 1: Input source of shared texture handle. + const texture = event.texture; + + if (!texture) { + console.error('No texture, GPU may be unavailable, skipping.'); + done(); + return; + } + + // Step 2: Import as SharedTextureImported + console.log(texture.textureInfo); + const imported = sharedTexture.importSharedTexture({ + textureInfo: texture.textureInfo, + allReferencesReleased: () => { + // Release the shared texture source once GPU is done. + // Will be called when all processes have finished using the shared texture. + texture.release(); + + // Slightly timeout and capture the node screenshot + setTimeout(async () => { + // Compare the captured image with the target image + const captured = await win.webContents.capturePage({ + x: 16, + y: 16, + width: 128, + height: 128 + }); + + // Resize the target image to match the captured image size, in case dpr != 1 + const target = targetImage.resize({ ...captured.getSize() }); + + // nativeImage have error comparing pixel data when color space is different, + // send to browser for comparison using canvas. + targetFrame.send('verify-captured-image', { + captured: captured.toDataURL(), + target: target.toDataURL() + }); + }, 300); + } + }); + + // Step 3: Transfer to another process (win's renderer) + await sharedTexture.sendSharedTexture({ + frame: iframe ? targetFrame : win.webContents.mainFrame, + importedSharedTexture: imported + }); + + // Step 4: Release the imported and wait for signal to release the source + imported.release(); + }); + + ipcMain.on('verify-captured-image-done', (event: any, result: { difference: number, total: number }) => { + // Verify the result from renderer process + try { + // macOS may have tiny color difference after the whole rendering process, + // and the color may change slightly when resizing at device pixel ratio != 1. + // Limit error should not be different more than 1% of the whole image. + const ratio = result.difference / result.total; + console.log('image difference: ', ratio); + expect(ratio).to.be.lessThan(0.01); + done(); + } catch (e) { + setTimeout(() => done(e), 1000000); + } + }); + + ipcMain.on('webgpu-unavailable', () => { + console.error('WebGPU is not available, skipping.'); + done(); + }); + + win.loadFile(htmlPath); + osr.loadFile(osrPath); + }; + + app.whenReady().then(() => { + createWindow(); + }); + }; + + it('successfully imported and rendered with managed api, without iframe', (done) => { + runSharedTextureManagedTest(done, false); + }).timeout(debugSpec ? 100000 : 10000); + + it('successfully imported and rendered with managed api, with iframe', (done) => { + runSharedTextureManagedTest(done, true); + }).timeout(debugSpec ? 100000 : 10000); + }); +}); diff --git a/spec/api-shell-spec.ts b/spec/api-shell-spec.ts index 643c780ed4ac1..eef14040b028d 100644 --- a/spec/api-shell-spec.ts +++ b/spec/api-shell-spec.ts @@ -82,6 +82,11 @@ describe('shell module', () => { ]); }); + ifit(process.platform === 'darwin')('throws when there is no application registered to open the URL', async () => { + const url = `unknownscheme-${Date.now()}://test`; + await expect(shell.openExternal(url)).to.eventually.be.rejectedWith(/No application found to open URL/); + }); + 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 } }); diff --git a/spec/api-system-preferences-spec.ts b/spec/api-system-preferences-spec.ts index 05de0b91e8565..5c10b433183a0 100644 --- a/spec/api-system-preferences-spec.ts +++ b/spec/api-system-preferences-spec.ts @@ -2,11 +2,17 @@ import { systemPreferences } from 'electron/main'; import { expect } from 'chai'; -import { ifdescribe } from './lib/spec-helpers'; +import { ifdescribe, ifit } from './lib/spec-helpers'; describe('systemPreferences module', () => { - ifdescribe(process.platform === 'win32')('systemPreferences.getAccentColor', () => { - it('should return a non-empty string', () => { + ifdescribe(['win32', 'linux'].includes(process.platform))('systemPreferences.getAccentColor', () => { + ifit(process.platform === 'linux')('should return a string', () => { + // Testing this properly (i.e. non-empty string) requires + // some tricky D-Bus mock setup. + const accentColor = systemPreferences.getAccentColor(); + expect(accentColor).to.be.a('string'); + }); + ifit(process.platform === 'win32')('should return a non-empty string', () => { const accentColor = systemPreferences.getAccentColor(); expect(accentColor).to.be.a('string').that.is.not.empty('accent color'); }); diff --git a/spec/api-view-spec.ts b/spec/api-view-spec.ts index 48c8ccae0c48f..fc39bccb29d6d 100644 --- a/spec/api-view-spec.ts +++ b/spec/api-view-spec.ts @@ -92,4 +92,46 @@ describe('View', () => { expect(v.getVisible()).to.be.false(); }); }); + + describe('view.getBounds|setBounds', () => { + it('defaults to 0,0,0,0', () => { + const v = new View(); + expect(v.getBounds()).to.deep.equal({ x: 0, y: 0, width: 0, height: 0 }); + }); + + it('can be set and retrieved', () => { + const v = new View(); + v.setBounds({ x: 10, y: 20, width: 300, height: 400 }); + expect(v.getBounds()).to.deep.equal({ x: 10, y: 20, width: 300, height: 400 }); + }); + + it('emits bounds-changed when bounds mutate', () => { + const v = new View(); + let called = 0; + v.once('bounds-changed', () => { called++; }); + v.setBounds({ x: 5, y: 6, width: 7, height: 8 }); + expect(called).to.equal(1); + }); + + it('allows zero-size bounds', () => { + const v = new View(); + v.setBounds({ x: 1, y: 2, width: 0, height: 0 }); + expect(v.getBounds()).to.deep.equal({ x: 1, y: 2, width: 0, height: 0 }); + }); + + it('allows negative coordinates', () => { + const v = new View(); + v.setBounds({ x: -10, y: -20, width: 100, height: 50 }); + expect(v.getBounds()).to.deep.equal({ x: -10, y: -20, width: 100, height: 50 }); + }); + + it('child bounds remain relative after parent moves', () => { + const parent = new View(); + const child = new View(); + parent.addChildView(child); + child.setBounds({ x: 10, y: 15, width: 25, height: 30 }); + parent.setBounds({ x: 50, y: 60, width: 500, height: 600 }); + expect(child.getBounds()).to.deep.equal({ x: 10, y: 15, width: 25, height: 30 }); + }); + }); }); diff --git a/spec/api-web-contents-spec.ts b/spec/api-web-contents-spec.ts index 9819327c979f7..50cf544736161 100644 --- a/spec/api-web-contents-spec.ts +++ b/spec/api-web-contents-spec.ts @@ -1,6 +1,6 @@ import { BrowserWindow, ipcMain, webContents, session, app, BrowserView, WebContents, BaseWindow, WebContentsView } from 'electron/main'; -import { expect } from 'chai'; +import { assert, expect } from 'chai'; import * as cp from 'node:child_process'; import { once } from 'node:events'; @@ -919,7 +919,7 @@ describe('webContents module', () => { return w.webContents.navigationHistory.restore({ index: 2, entries }); }); - expect(formValue).to.equal('Hi!'); + await waitUntil(() => formValue === 'Hi!'); }); it('should handle invalid base64 pageState', async () => { @@ -1013,6 +1013,41 @@ describe('webContents module', () => { await devToolsClosed; expect(() => { webContents.getFocusedWebContents(); }).to.not.throw(); }); + + it('Inspect activates detached devtools window', async () => { + const window = new BrowserWindow({ show: true }); + await window.loadURL('about:blank'); + const webContentsBeforeOpenedDevtools = webContents.getAllWebContents(); + + const windowWasBlurred = once(window, 'blur'); + window.webContents.openDevTools({ mode: 'detach' }); + await windowWasBlurred; + + let devToolsWebContents = null; + for (const newWebContents of webContents.getAllWebContents()) { + const oldWebContents = webContentsBeforeOpenedDevtools.find( + oldWebContents => { + return newWebContents.id === oldWebContents.id; + }); + if (oldWebContents !== null) { + devToolsWebContents = newWebContents; + break; + } + } + assert(devToolsWebContents !== null); + + const windowFocused = once(window, 'focus'); + window.focus(); + await windowFocused; + + expect(devToolsWebContents.isFocused()).to.be.false(); + const devToolsWebContentsFocused = once(devToolsWebContents, 'focus'); + window.webContents.inspectElement(100, 100); + await devToolsWebContentsFocused; + + expect(devToolsWebContents.isFocused()).to.be.true(); + expect(window.isFocused()).to.be.false(); + }); }); describe('setDevToolsWebContents() API', () => { diff --git a/spec/api-web-frame-main-spec.ts b/spec/api-web-frame-main-spec.ts index ccb109beec286..89397fcee840a 100644 --- a/spec/api-web-frame-main-spec.ts +++ b/spec/api-web-frame-main-spec.ts @@ -342,6 +342,8 @@ describe('webFrameMain module', () => { const crashEvent = once(w.webContents, 'render-process-gone'); w.webContents.forcefullyCrashRenderer(); await crashEvent; + // A short wait seems to be required to reproduce the crash. + await setTimeout(100); await w.webContents.loadURL(server.url); // Log just to keep mainFrame in scope. console.log('mainFrame.url', mainFrame.url); diff --git a/spec/api-web-request-spec.ts b/spec/api-web-request-spec.ts index b2792cf9a66d1..9000b2d2b1270 100644 --- a/spec/api-web-request-spec.ts +++ b/spec/api-web-request-spec.ts @@ -733,5 +733,80 @@ describe('webRequest module', () => { expect(reqHeaders['/websocket'].foo).to.equal('bar'); expect(reqHeaders['/'].foo).to.equal('bar'); }); + + it('authenticates a WebSocket via login event', async () => { + const authServer = http.createServer(); + const wssAuth = new WebSocket.Server({ noServer: true }); + const expected = 'Basic ' + Buffer.from('user:pass').toString('base64'); + + wssAuth.on('connection', ws => { + ws.send('Authenticated!'); + }); + + authServer.on('upgrade', (req, socket, head) => { + const auth = req.headers.authorization || ''; + if (auth !== expected) { + socket.write( + 'HTTP/1.1 401 Unauthorized\r\n' + + 'WWW-Authenticate: Basic realm="Test"\r\n' + + 'Content-Length: 0\r\n' + + '\r\n' + ); + socket.destroy(); + return; + } + + wssAuth.handleUpgrade(req, socket as Socket, head, ws => { + wssAuth.emit('connection', ws, req); + }); + }); + + const { port } = await listen(authServer); + const ses = session.fromPartition(`WebRequestWSAuth-${Date.now()}`); + + const contents = (webContents as typeof ElectronInternal.WebContents).create({ + session: ses, + sandbox: true + }); + + defer(() => { + contents.destroy(); + authServer.close(); + wssAuth.close(); + }); + + ses.webRequest.onBeforeRequest({ urls: ['ws://*/*'] }, (details, callback) => { + callback({}); + }); + + contents.on('login', (event, details: any, _: any, callback: (u: string, p: string) => void) => { + if (details?.url?.startsWith(`ws://localhost:${port}`)) { + event.preventDefault(); + callback('user', 'pass'); + } + }); + + await contents.loadFile(path.join(fixturesPath, 'blank.html')); + + const message = await contents.executeJavaScript(`new Promise((resolve, reject) => { + let attempts = 0; + function connect() { + attempts++; + const ws = new WebSocket('ws://localhost:${port}'); + ws.onmessage = e => resolve(e.data); + ws.onerror = () => { + if (attempts < 3) { + setTimeout(connect, 50); + } else { + reject(new Error('WebSocket auth failed')); + } + }; + } + connect(); + setTimeout(() => reject(new Error('timeout')), 5000); + });`); + + expect(message).to.equal('Authenticated!'); + }); }); }); diff --git a/spec/chromium-spec.ts b/spec/chromium-spec.ts index ec86015aa7077..b962dc363c72e 100644 --- a/spec/chromium-spec.ts +++ b/spec/chromium-spec.ts @@ -343,12 +343,12 @@ describe('web security', () => { }); } </script>`); - return await w.webContents.executeJavaScript('loadWasm()'); + return (await w.webContents.executeJavaScript('loadWasm()')).trim(); } it('wasm codegen is disallowed by default', async () => { const r = await loadWasm(''); - expect(r).to.equal('WebAssembly.instantiate(): Refused to compile or instantiate WebAssembly module because \'unsafe-eval\' is not an allowed source of script in the following Content Security Policy directive: "script-src \'self\' \'unsafe-inline\'"'); + expect(r).to.equal('WebAssembly.instantiate(): Compiling or instantiating WebAssembly module violates the following Content Security policy directive because \'unsafe-eval\' is not an allowed source of script in the following Content Security Policy directive:'); }); it('wasm codegen is allowed with "wasm-unsafe-eval" csp', async () => { @@ -381,7 +381,7 @@ describe('web security', () => { } </script>`); const [{ message }] = await once(w.webContents, 'console-message'); - expect(message).to.match(/Refused to evaluate a string/); + expect(message).to.match(/Evaluating a string as JavaScript violates/); }); it('does not prevent eval from running in an inline script when there is no csp', async () => { @@ -898,16 +898,84 @@ describe('chromium features', () => { expect(position).to.have.property('coords'); expect(position).to.have.property('timestamp'); }); + + ifdescribe(process.platform === 'darwin')('with --disable-geolocation', () => { + const testSwitchBehavior = (handlerAction: 'allow' | 'deny' | 'none') => async () => { + const rc = await startRemoteControlApp([ + '--disable-geolocation', + `--boot-eval=fixturesPath=${JSON.stringify(fixturesPath)}` + ]); + + const result = await rc.remotely(async (action: typeof handlerAction) => { + const { session, BrowserWindow } = require('electron'); + const path = require('node:path'); + + // Isolate each test's permissions to prevent permission state leaks between the test variations + const testSession = session.fromPartition(`geolocation-disable-${action}`); + + if (action !== 'none') { + // Make the PermissionRequestHandler behave according to action variable passed for this test + testSession.setPermissionRequestHandler((_wc: Electron.WebContents, permission: string, callback: (allow: boolean) => void) => { + if (permission === 'geolocation') { + if (action === 'allow') callback(true); + else if (action === 'deny') callback(false); + else callback(false); + } + }); + } + + const w = new BrowserWindow({ + show: false, + webPreferences: { + session: testSession, + nodeIntegration: true, + contextIsolation: false + } + }); + + await w.loadFile(path.join(fixturesPath, 'pages', 'blank.html')); + + const permissionState = await w.webContents.executeJavaScript(` + navigator.permissions.query({ name: 'geolocation' }) + .then(status => status.state) + .catch(() => 'error') + `); + + const geoResult = await w.webContents.executeJavaScript(` + new Promise(resolve => { + navigator.geolocation.getCurrentPosition( + () => resolve('allowed'), + err => resolve(err.code) + ); + }) + `); + + return { permissionState, geoResult }; + }, handlerAction); + + // Always expect status to be denied regardless of the decision made by a handler set via `session.setPermissionRequestHandler` + expect(result.permissionState).to.equal('denied', `Unexpected permission state for ${handlerAction} handler`); + + // 1 = PERMISSION_DENIED + expect(result.geoResult).to.equal(1, `Unexpected API result for ${handlerAction} handler`); + }; + + it('denies geolocation when permission request handler would allow', testSwitchBehavior('allow')); + it('denies geolocation when permission request handler would deny', testSwitchBehavior('deny')); + it('denies geolocation with no permission request handler', testSwitchBehavior('none')); + }); }); describe('File System API,', () => { - afterEach(closeAllWindows); + let w: BrowserWindow | null = null; + afterEach(() => { session.defaultSession.setPermissionRequestHandler(null); + closeAllWindows(); }); it('allows access by default to reading an OPFS file', async () => { - const w = new BrowserWindow({ + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, @@ -929,7 +997,7 @@ describe('chromium features', () => { }); it('fileHandle.queryPermission by default has permission to read and write to OPFS files', async () => { - const w = new BrowserWindow({ + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, @@ -951,7 +1019,8 @@ describe('chromium features', () => { }); it('fileHandle.requestPermission automatically grants permission to read and write to OPFS files', async () => { - const w = new BrowserWindow({ + w = new BrowserWindow({ + show: false, webPreferences: { nodeIntegration: true, partition: 'file-system-spec', @@ -971,8 +1040,8 @@ describe('chromium features', () => { expect(status).to.equal('granted'); }); - it('requests permission when trying to create a writable file handle', (done) => { - const writablePath = path.join(fixturesPath, 'file-system', 'test-writable.html'); + it('allows permission when trying to create a writable file handle', (done) => { + const writablePath = path.join(fixturesPath, 'file-system', 'test-perms.html'); const testFile = path.join(fixturesPath, 'file-system', 'test.txt'); const w = new BrowserWindow({ @@ -1000,9 +1069,9 @@ describe('chromium features', () => { ipcMain.once('did-create-file-handle', async () => { const result = await w.webContents.executeJavaScript(` - new Promise((resolve, reject) => { + new Promise(async (resolve, reject) => { try { - const writable = fileHandle.createWritable(); + const writable = await handle.createWritable(); resolve(true); } catch { resolve(false); @@ -1021,6 +1090,258 @@ describe('chromium features', () => { w.webContents.paste(); }); }); + + it('denies permission when trying to create a writable file handle', (done) => { + const writablePath = path.join(fixturesPath, 'file-system', 'test-perms.html'); + const testFile = path.join(fixturesPath, 'file-system', 'test.txt'); + + const w = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + sandbox: false + } + }); + + w.webContents.session.setPermissionRequestHandler((wc, permission, callback, details) => { + expect(permission).to.equal('fileSystem'); + + const { href } = url.pathToFileURL(writablePath); + expect(details).to.deep.equal({ + fileAccessType: 'writable', + isDirectory: false, + isMainFrame: true, + filePath: testFile, + requestingUrl: href + }); + + callback(false); + }); + + ipcMain.once('did-create-file-handle', async () => { + const result = await w.webContents.executeJavaScript(` + new Promise(async (resolve, reject) => { + try { + const writable = await handle.createWritable(); + resolve(true); + } catch { + resolve(false); + } + }) + `, true); + expect(result).to.be.false(); + done(); + }); + + w.loadFile(writablePath); + + w.webContents.once('did-finish-load', () => { + // @ts-expect-error Undocumented testing method. + clipboard._writeFilesForTesting([testFile]); + w.webContents.paste(); + }); + }); + + it('calls twice when trying to query a read/write file handle permissions', (done) => { + const writablePath = path.join(fixturesPath, 'file-system', 'test-perms.html'); + const testFile = path.join(fixturesPath, 'file-system', 'test.txt'); + + const w = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + sandbox: false + } + }); + + let calls = 0; + w.webContents.session.setPermissionCheckHandler((wc, permission, origin, details) => { + if (permission === 'fileSystem') { + const { fileAccessType, isDirectory, filePath } = details; + expect(['writable', 'readable']).to.contain(fileAccessType); + expect(isDirectory).to.be.false(); + expect(filePath).to.equal(testFile); + calls++; + return true; + } + + return false; + }); + + ipcMain.once('did-create-file-handle', async () => { + const permission = await w.webContents.executeJavaScript(` + new Promise(async (resolve, reject) => { + try { + const permission = await handle.queryPermission({ mode: 'readwrite' }); + resolve(permission); + } catch { + resolve('denied'); + } + }) + `, true); + expect(permission).to.equal('granted'); + expect(calls).to.equal(2); + done(); + }); + + w.loadFile(writablePath); + + w.webContents.once('did-finish-load', () => { + // @ts-expect-error Undocumented testing method. + clipboard._writeFilesForTesting([testFile]); + w.webContents.paste(); + }); + }); + + it('correctly denies permissions after creating a readable directory handle', (done) => { + const permPath = path.join(fixturesPath, 'file-system', 'test-perms.html'); + const testDir = path.join(fixturesPath, 'file-system'); + + const w = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + sandbox: false + } + }); + + w.webContents.session.setPermissionCheckHandler((wc, permission, origin, details) => { + expect(permission).to.equal('fileSystem'); + + const { fileAccessType, isDirectory, filePath } = details; + expect(fileAccessType).to.equal('readable'); + expect(isDirectory).to.be.true(); + expect(filePath).to.equal(testDir); + return false; + }); + + ipcMain.once('did-create-directory-handle', async () => { + const permission = await w.webContents.executeJavaScript(` + new Promise(async (resolve, reject) => { + try { + const permission = await handle.queryPermission({ mode: 'read' }); + resolve(permission); + } catch { + resolve('denied'); + } + }) + `, true); + expect(permission).to.equal('denied'); + done(); + }); + + w.loadFile(permPath); + + w.webContents.once('did-finish-load', () => { + // @ts-expect-error Undocumented testing method. + clipboard._writeFilesForTesting([testDir]); + w.webContents.paste(); + }); + }); + + it('correctly allows permissions after creating a readable directory handle', (done) => { + const permPath = path.join(fixturesPath, 'file-system', 'test-perms.html'); + const testDir = path.join(fixturesPath, 'file-system'); + + const w = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + sandbox: false + } + }); + + w.webContents.session.setPermissionCheckHandler((wc, permission, origin, details) => { + if (permission === 'fileSystem') { + const { fileAccessType, isDirectory, filePath } = details; + expect(fileAccessType).to.equal('readable'); + expect(isDirectory).to.be.true(); + expect(filePath).to.equal(testDir); + return true; + } + return false; + }); + + ipcMain.once('did-create-directory-handle', async () => { + const permission = await w.webContents.executeJavaScript(` + new Promise(async (resolve, reject) => { + try { + const permission = await handle.queryPermission({ mode: 'read' }); + resolve(permission); + } catch { + resolve('denied'); + } + }) + `, true); + expect(permission).to.equal('granted'); + done(); + }); + + w.loadFile(permPath); + + w.webContents.once('did-finish-load', () => { + // @ts-expect-error Undocumented testing method. + clipboard._writeFilesForTesting([testDir]); + w.webContents.paste(); + }); + }); + + it('allows in-session persistence of granted file permissions', (done) => { + const writablePath = path.join(fixturesPath, 'file-system', 'test-perms.html'); + const testFile = path.join(fixturesPath, 'file-system', 'persist.txt'); + + const w = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + sandbox: false + } + }); + + w.webContents.session.setPermissionRequestHandler((_wc, _permission, callback) => { + callback(true); + }); + + w.webContents.session.setPermissionCheckHandler((_wc, permission, _origin, details) => { + if (permission === 'fileSystem') { + const { fileAccessType, isDirectory, filePath } = details; + expect(fileAccessType).to.deep.equal('readable'); + expect(isDirectory).to.be.false(); + expect(filePath).to.equal(testFile); + return true; + } + return false; + }); + + let reload = true; + ipcMain.on('did-create-file-handle', async () => { + if (reload) { + w.webContents.reload(); + reload = false; + } else { + const permission = await w.webContents.executeJavaScript(` + new Promise(async (resolve, reject) => { + try { + const permission = await handle.queryPermission({ mode: 'read' }); + resolve(permission); + } catch { + resolve('denied'); + } + }) + `, true); + expect(permission).to.equal('granted'); + done(); + } + }); + + w.loadFile(writablePath); + + w.webContents.on('did-finish-load', () => { + // @ts-expect-error Undocumented testing method. + clipboard._writeFilesForTesting([testFile]); + w.webContents.paste(); + }); + }); }); describe('web workers', () => { @@ -1654,10 +1975,10 @@ describe('chromium features', () => { }); it('delivers messages that match the origin', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + const w = new BrowserWindow({ show: false }); w.loadFile(path.resolve(__dirname, 'fixtures', 'blank.html')); const data = await w.webContents.executeJavaScript(` - window.open(${JSON.stringify(serverURL)}, '', 'show=no,contextIsolation=no,nodeIntegration=yes'); + window.open(${JSON.stringify(serverURL)}, '', 'show=no'); new Promise(resolve => window.addEventListener('message', resolve, {once: true})).then(e => e.data) `); expect(data).to.equal('deliver'); diff --git a/spec/esm-spec.ts b/spec/esm-spec.ts index a09198ba7486e..b4221c0eda0a4 100644 --- a/spec/esm-spec.ts +++ b/spec/esm-spec.ts @@ -130,6 +130,17 @@ describe('esm', () => { } describe('nodeIntegration', () => { + let badFilePath = ''; + + beforeEach(async () => { + badFilePath = path.resolve(path.resolve(os.tmpdir(), 'bad-file.badjs')); + await fs.promises.writeFile(badFilePath, 'const foo = "bar";'); + }); + + afterEach(async () => { + await fs.promises.unlink(badFilePath); + }); + it('should support an esm entrypoint', async () => { const [webContents] = await loadWindowWithPreload('import { resolve } from "path"; window.resolvePath = resolve;', { nodeIntegration: true, @@ -189,6 +200,18 @@ describe('esm', () => { expect(error?.message).to.include('Failed to fetch dynamically imported module'); }); + it('should use Node.js ESM dynamic loader in the preload', async () => { + const [, preloadError] = await loadWindowWithPreload(`await import(${JSON.stringify((pathToFileURL(badFilePath)))})`, { + nodeIntegration: true, + sandbox: false, + contextIsolation: false + }); + + expect(preloadError).to.not.equal(null); + // This is a node.js specific error message + expect(preloadError!.toString()).to.include('Unknown file extension'); + }); + it('should use import.meta callback handling from Node.js for Node.js modules', async () => { const result = await runFixture(path.resolve(fixturePath, 'import-meta')); expect(result.code).to.equal(0); @@ -196,17 +219,6 @@ describe('esm', () => { }); describe('with context isolation', () => { - let badFilePath = ''; - - beforeEach(async () => { - badFilePath = path.resolve(path.resolve(os.tmpdir(), 'bad-file.badjs')); - await fs.promises.writeFile(badFilePath, 'const foo = "bar";'); - }); - - afterEach(async () => { - await fs.promises.unlink(badFilePath); - }); - it('should use Node.js ESM dynamic loader in the isolated context', async () => { const [, preloadError] = await loadWindowWithPreload(`await import(${JSON.stringify((pathToFileURL(badFilePath)))})`, { nodeIntegration: true, diff --git a/spec/fixtures/api/pdf-reader.mjs b/spec/fixtures/api/pdf-reader.mjs index 4b21b60102ecc..589e90042d3a7 100644 --- a/spec/fixtures/api/pdf-reader.mjs +++ b/spec/fixtures/api/pdf-reader.mjs @@ -1,7 +1,8 @@ -import * as pdfjs from 'pdfjs-dist'; +import { app } from 'electron'; async function getPDFDoc () { try { + const pdfjs = await import('pdfjs-dist'); const doc = await pdfjs.getDocument(process.argv[2]).promise; const page = await doc.getPage(1); const { items } = await page.getTextContent(); @@ -20,4 +21,4 @@ async function getPDFDoc () { } } -getPDFDoc(); +app.whenReady().then(() => getPDFDoc()); diff --git a/spec/fixtures/api/shared-texture/common.js b/spec/fixtures/api/shared-texture/common.js new file mode 100644 index 0000000000000..2674a18803974 --- /dev/null +++ b/spec/fixtures/api/shared-texture/common.js @@ -0,0 +1,168 @@ +window.verifyCapturedImage = (images, result) => { + const { captured, target } = images; + // Compare the captured image with the target image + const capturedImage = new Image(); + capturedImage.src = captured; + capturedImage.onload = () => { + const targetImage = new Image(); + targetImage.src = target; + targetImage.onload = () => { + const canvas = document.createElement('canvas'); + canvas.width = capturedImage.width; + canvas.height = capturedImage.height; + + const ctx = canvas.getContext('2d'); + ctx.drawImage(capturedImage, 0, 0); + const capturedData = ctx.getImageData(0, 0, canvas.width, canvas.height).data; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(targetImage, 0, 0); + const targetData = ctx.getImageData(0, 0, canvas.width, canvas.height).data; + + // Compare the pixel data + let difference = 0; + for (let i = 0; i < capturedData.length; i += 4) { + difference += Math.abs(capturedData[i] - targetData[i]); + difference += Math.abs(capturedData[i + 1] - targetData[i + 1]); + difference += Math.abs(capturedData[i + 2] - targetData[i + 2]); + difference += Math.abs(capturedData[i + 3] - targetData[i + 3]); + } + + // Send the result back to the main process + result({ difference, total: capturedData.length * 255 }); + canvas.remove(); + capturedImage.remove(); + targetImage.remove(); + }; + }; +}; + +window.initWebGpu = async () => { + // Init WebGPU + const canvas = document.createElement('canvas'); + canvas.width = 128; + canvas.height = 128; + canvas.style.width = '128px'; + canvas.style.height = '128px'; + canvas.style.position = 'absolute'; + canvas.style.top = '16px'; + canvas.style.left = '16px'; + + document.body.appendChild(canvas); + const context = canvas.getContext('webgpu'); + + // Configure WebGPU context + const adapter = await navigator.gpu.requestAdapter(); + const device = await adapter.requestDevice(); + const format = navigator.gpu.getPreferredCanvasFormat(); + context.configure({ device, format }); + + window.renderFrame = async (frame) => { + try { + // Create external texture + const externalTexture = device.importExternalTexture({ source: frame }); + + // Create bind group layout, correctly specifying the external texture type + const bindGroupLayout = device.createBindGroupLayout({ + entries: [ + { + binding: 0, + visibility: window.GPUShaderStage.FRAGMENT, + externalTexture: {} + }, + { + binding: 1, + visibility: window.GPUShaderStage.FRAGMENT, + sampler: {} + } + ] + }); + + // Create pipeline layout + const pipelineLayout = device.createPipelineLayout({ + bindGroupLayouts: [bindGroupLayout] + }); + + // Create render pipeline + const pipeline = device.createRenderPipeline({ + layout: pipelineLayout, + vertex: { + module: device.createShaderModule({ + code: ` + @vertex + fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> { + var pos = array<vec2<f32>, 6>( + vec2<f32>(-1.0, -1.0), + vec2<f32>(1.0, -1.0), + vec2<f32>(-1.0, 1.0), + vec2<f32>(-1.0, 1.0), + vec2<f32>(1.0, -1.0), + vec2<f32>(1.0, 1.0) + ); + return vec4<f32>(pos[VertexIndex], 0.0, 1.0); + } + ` + }), + entryPoint: 'main' + }, + fragment: { + module: device.createShaderModule({ + code: ` + @group(0) @binding(0) var extTex: texture_external; + @group(0) @binding(1) var mySampler: sampler; + + @fragment + fn main(@builtin(position) fragCoord: vec4<f32>) -> @location(0) vec4<f32> { + let texCoord = fragCoord.xy / vec2<f32>(${canvas.width}.0, ${canvas.height}.0); + return textureSampleBaseClampToEdge(extTex, mySampler, texCoord); + } + ` + }), + entryPoint: 'main', + targets: [{ format }] + }, + primitive: { topology: 'triangle-list' } + }); + + // Create bind group + const bindGroup = device.createBindGroup({ + layout: bindGroupLayout, + entries: [ + { + binding: 0, + resource: externalTexture + }, + { + binding: 1, + resource: device.createSampler() + } + ] + }); + + // Create command encoder and render pass + const commandEncoder = device.createCommandEncoder(); + const textureView = context.getCurrentTexture().createView(); + const renderPass = commandEncoder.beginRenderPass({ + colorAttachments: [ + { + view: textureView, + clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }, + loadOp: 'clear', + storeOp: 'store' + } + ] + }); + + // Set pipeline and bind group + renderPass.setPipeline(pipeline); + renderPass.setBindGroup(0, bindGroup); + renderPass.draw(6); // Draw a rectangle composed of two triangles + renderPass.end(); + + // Submit commands + device.queue.submit([commandEncoder.finish()]); + } catch (error) { + console.error('Rendering error:', error); + } + }; +}; diff --git a/spec/fixtures/api/shared-texture/image.png b/spec/fixtures/api/shared-texture/image.png new file mode 100644 index 0000000000000..3f2e16dd64ff9 Binary files /dev/null and b/spec/fixtures/api/shared-texture/image.png differ diff --git a/spec/fixtures/api/shared-texture/managed/frame.html b/spec/fixtures/api/shared-texture/managed/frame.html new file mode 100644 index 0000000000000..08da2e384f275 --- /dev/null +++ b/spec/fixtures/api/shared-texture/managed/frame.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> +</head> + +<body style="margin: 0;"> + <iframe src="index.html" style="width: 100%; height: 100%; border: none;"></iframe> +</body> + +</html> \ No newline at end of file diff --git a/spec/fixtures/api/shared-texture/managed/index.html b/spec/fixtures/api/shared-texture/managed/index.html new file mode 100644 index 0000000000000..db6184c5235d2 --- /dev/null +++ b/spec/fixtures/api/shared-texture/managed/index.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <title>Hello World! + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/api/shared-texture/managed/preload.js b/spec/fixtures/api/shared-texture/managed/preload.js new file mode 100644 index 0000000000000..c26070140d53b --- /dev/null +++ b/spec/fixtures/api/shared-texture/managed/preload.js @@ -0,0 +1,28 @@ +const { sharedTexture } = require('electron'); +const { ipcRenderer, contextBridge } = require('electron/renderer'); + +contextBridge.exposeInMainWorld('textures', { + onSharedTexture: (cb) => { + // Step 0: Register the receiver for transferred shared texture + sharedTexture.setSharedTextureReceiver(async (data) => { + // Step 5: Receive the imported shared texture + const { importedSharedTexture: imported } = data; + await cb(imported); + + // Release the imported shared texture since we're done. + // No need to use the callback here, as the util function automatically + // managed the lifetime via sync token. + imported.release(); + }); + }, + webGpuUnavailable: () => { + ipcRenderer.send('webgpu-unavailable'); + }, + verifyCapturedImage: (verify) => { + ipcRenderer.on('verify-captured-image', (e, images) => { + verify(images, (result) => { + ipcRenderer.send('verify-captured-image-done', result); + }); + }); + } +}); diff --git a/spec/fixtures/api/shared-texture/managed/renderer.js b/spec/fixtures/api/shared-texture/managed/renderer.js new file mode 100644 index 0000000000000..e1c3ac11ce84a --- /dev/null +++ b/spec/fixtures/api/shared-texture/managed/renderer.js @@ -0,0 +1,21 @@ +window.initWebGpu().catch((err) => { + console.error('Failed to initialize WebGPU:', err); + window.textures.webGpuUnavailable(); +}); + +window.textures.onSharedTexture(async (imported) => { + try { + // Step 6: Get VideoFrame from the imported texture + const frame = imported.getVideoFrame(); + + // Step 7: Render using WebGPU + await window.renderFrame(frame); + + // Step 8: Release the VideoFrame as we no longer need it + frame.close(); + } catch (error) { + console.error('Error getting VideoFrame:', error); + } +}); + +window.textures.verifyCapturedImage(window.verifyCapturedImage); diff --git a/spec/fixtures/api/shared-texture/osr.html b/spec/fixtures/api/shared-texture/osr.html new file mode 100644 index 0000000000000..1f69a2dc67a07 --- /dev/null +++ b/spec/fixtures/api/shared-texture/osr.html @@ -0,0 +1,13 @@ + + + +
+ + Hello World! +
+ + + + + + \ No newline at end of file diff --git a/spec/fixtures/api/shared-texture/subtle/index.html b/spec/fixtures/api/shared-texture/subtle/index.html new file mode 100644 index 0000000000000..db6184c5235d2 --- /dev/null +++ b/spec/fixtures/api/shared-texture/subtle/index.html @@ -0,0 +1,14 @@ + + + + + + Hello World! + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/api/shared-texture/subtle/preload.js b/spec/fixtures/api/shared-texture/subtle/preload.js new file mode 100644 index 0000000000000..d369b4e93ebdd --- /dev/null +++ b/spec/fixtures/api/shared-texture/subtle/preload.js @@ -0,0 +1,30 @@ +const { sharedTexture } = require('electron'); +const { ipcRenderer, contextBridge } = require('electron/renderer'); + +contextBridge.exposeInMainWorld('textures', { + onSharedTexture: (cb) => { + ipcRenderer.on('shared-texture', async (e, id, transfer) => { + // Step 5: Get the shared texture from the transfer + const importedSubtle = sharedTexture.subtle.finishTransferSharedTexture(transfer); + + // Step 6: Let the renderer render using WebGPU + await cb(id, importedSubtle); + + // Step 10: Release the shared texture with a callback + importedSubtle.release(() => { + // Step 11: When GPU command buffer is done, we can notify the main process to release + ipcRenderer.send('shared-texture-done', id); + }); + }); + }, + webGpuUnavailable: () => { + ipcRenderer.send('webgpu-unavailable'); + }, + verifyCapturedImage: (verify) => { + ipcRenderer.on('verify-captured-image', (e, images) => { + verify(images, (result) => { + ipcRenderer.send('verify-captured-image-done', result); + }); + }); + } +}); diff --git a/spec/fixtures/api/shared-texture/subtle/renderer.js b/spec/fixtures/api/shared-texture/subtle/renderer.js new file mode 100644 index 0000000000000..83ab96c640fea --- /dev/null +++ b/spec/fixtures/api/shared-texture/subtle/renderer.js @@ -0,0 +1,21 @@ +window.initWebGpu().catch((err) => { + console.error('Failed to initialize WebGPU:', err); + window.textures.webGpuUnavailable(); +}); + +window.textures.onSharedTexture(async (id, importedSubtle) => { + try { + // Step 7: Get VideoFrame from the imported texture + const frame = importedSubtle.getVideoFrame(); + + // Step 8: Render using WebGPU + await window.renderFrame(frame); + + // Step 9: Release the VideoFrame as we no longer need it + frame.close(); + } catch (error) { + console.error('Error getting VideoFrame:', error); + } +}); + +window.textures.verifyCapturedImage(window.verifyCapturedImage); diff --git a/spec/fixtures/api/window-state-save/close-save/index.js b/spec/fixtures/api/window-state-save/close-save/index.js new file mode 100644 index 0000000000000..6dcd5e935f1cf --- /dev/null +++ b/spec/fixtures/api/window-state-save/close-save/index.js @@ -0,0 +1,27 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-close-save', + windowStatePersistence: true, + show: false + }); + + w.on('close', () => { + app.quit(); + }); + + w.close(); + // Timeout of 10s to ensure app exits + setTimeout(() => { + app.quit(); + }, 10000); +}); diff --git a/spec/fixtures/api/window-state-save/fullscreen-save/index.js b/spec/fixtures/api/window-state-save/fullscreen-save/index.js new file mode 100644 index 0000000000000..bd2f2cbabb659 --- /dev/null +++ b/spec/fixtures/api/window-state-save/fullscreen-save/index.js @@ -0,0 +1,28 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-fullscreen-save', + windowStatePersistence: true + }); + + w.on('enter-full-screen', () => { + setTimeout(() => { + app.quit(); + }, 1000); + }); + + w.setFullScreen(true); + // Timeout of 10s to ensure app exits + setTimeout(() => { + app.quit(); + }, 10000); +}); diff --git a/spec/fixtures/api/window-state-save/kiosk-save/index.js b/spec/fixtures/api/window-state-save/kiosk-save/index.js new file mode 100644 index 0000000000000..29f3b5f1675b4 --- /dev/null +++ b/spec/fixtures/api/window-state-save/kiosk-save/index.js @@ -0,0 +1,28 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-kiosk-save', + windowStatePersistence: true + }); + + w.on('enter-full-screen', () => { + setTimeout(() => { + app.quit(); + }, 1000); + }); + + w.setKiosk(true); + // Timeout of 10s to ensure app exits + setTimeout(() => { + app.quit(); + }, 10000); +}); diff --git a/spec/fixtures/api/window-state-save/maximize-save/index.js b/spec/fixtures/api/window-state-save/maximize-save/index.js new file mode 100644 index 0000000000000..3e0dcd8915f52 --- /dev/null +++ b/spec/fixtures/api/window-state-save/maximize-save/index.js @@ -0,0 +1,28 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-maximize-save', + windowStatePersistence: true + }); + + w.on('maximize', () => { + setTimeout(() => { + app.quit(); + }, 1000); + }); + + w.maximize(); + // Timeout of 10s to ensure app exits + setTimeout(() => { + app.quit(); + }, 10000); +}); diff --git a/spec/fixtures/api/window-state-save/minimize-save/index.js b/spec/fixtures/api/window-state-save/minimize-save/index.js new file mode 100644 index 0000000000000..36c7018abb464 --- /dev/null +++ b/spec/fixtures/api/window-state-save/minimize-save/index.js @@ -0,0 +1,28 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-minimize-save', + windowStatePersistence: true + }); + + w.on('minimize', () => { + setTimeout(() => { + app.quit(); + }, 1000); + }); + + w.minimize(); + // Timeout of 10s to ensure app exits + setTimeout(() => { + app.quit(); + }, 10000); +}); diff --git a/spec/fixtures/api/window-state-save/move-save/index.js b/spec/fixtures/api/window-state-save/move-save/index.js new file mode 100644 index 0000000000000..56fb079b32741 --- /dev/null +++ b/spec/fixtures/api/window-state-save/move-save/index.js @@ -0,0 +1,23 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-move-save', + windowStatePersistence: true, + show: false + }); + + w.setPosition(100, 150); + + setTimeout(() => { + app.quit(); + }, 1000); +}); diff --git a/spec/fixtures/api/window-state-save/resize-save/index.js b/spec/fixtures/api/window-state-save/resize-save/index.js new file mode 100644 index 0000000000000..a25d399f657e7 --- /dev/null +++ b/spec/fixtures/api/window-state-save/resize-save/index.js @@ -0,0 +1,23 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(async () => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-resize-save', + windowStatePersistence: true, + show: false + }); + + w.setSize(500, 400); + + setTimeout(() => { + app.quit(); + }, 1000); +}); diff --git a/spec/fixtures/api/window-state-save/schema-check/index.js b/spec/fixtures/api/window-state-save/schema-check/index.js new file mode 100644 index 0000000000000..cad32f1e82636 --- /dev/null +++ b/spec/fixtures/api/window-state-save/schema-check/index.js @@ -0,0 +1,23 @@ +const { app, BrowserWindow } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(() => { + const w = new BrowserWindow({ + width: 400, + height: 300, + name: 'test-window-state-schema', + windowStatePersistence: true, + show: false + }); + + w.close(); + + setTimeout(() => { + app.quit(); + }, 1000); +}); diff --git a/spec/fixtures/api/window-state-save/work-area-primary/index.js b/spec/fixtures/api/window-state-save/work-area-primary/index.js new file mode 100644 index 0000000000000..4f7b0f86b7a6f --- /dev/null +++ b/spec/fixtures/api/window-state-save/work-area-primary/index.js @@ -0,0 +1,41 @@ +const { app, BrowserWindow, screen } = require('electron'); + +const os = require('node:os'); +const path = require('node:path'); + +const sharedUserData = path.join(os.tmpdir(), 'electron-window-state-test'); +app.setPath('userData', sharedUserData); + +app.whenReady().then(async () => { + const primaryDisplay = screen.getPrimaryDisplay(); + const workArea = primaryDisplay.workArea; + + const maxWidth = Math.max(200, Math.floor(workArea.width * 0.8)); + const maxHeight = Math.max(150, Math.floor(workArea.height * 0.8)); + const windowWidth = Math.min(400, maxWidth); + const windowHeight = Math.min(300, maxHeight); + + const w = new BrowserWindow({ + width: windowWidth, + height: windowHeight, + name: 'test-work-area-primary', + windowStatePersistence: true + }); + + // Center the window on the primary display to prevent overflow + const centerX = workArea.x + Math.floor((workArea.width - windowWidth) / 2); + const centerY = workArea.y + Math.floor((workArea.height - windowHeight) / 2); + + w.setPosition(centerX, centerY); + + w.on('close', () => { + app.quit(); + }); + + w.close(); + + // Timeout of 10s to ensure app exits + setTimeout(() => { + app.quit(); + }, 10000); +}); diff --git a/spec/fixtures/file-system/persist.txt b/spec/fixtures/file-system/persist.txt new file mode 100644 index 0000000000000..4750e51cc1a56 --- /dev/null +++ b/spec/fixtures/file-system/persist.txt @@ -0,0 +1 @@ +hello persist \ No newline at end of file diff --git a/spec/fixtures/file-system/test-writable.html b/spec/fixtures/file-system/test-perms.html similarity index 59% rename from spec/fixtures/file-system/test-writable.html rename to spec/fixtures/file-system/test-perms.html index 6d7012192b143..24a4787d257cc 100644 --- a/spec/fixtures/file-system/test-writable.html +++ b/spec/fixtures/file-system/test-perms.html @@ -10,13 +10,17 @@