From 4f6a94b56327cd74a11e3469004fe8c053a5fd4c Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Thu, 25 Aug 2022 12:29:15 -0700 Subject: [PATCH] devops: move to a new infra (#16845) --- .github/workflows/trigger_build_chromium.yml | 31 - .../trigger_build_chromium_tip_of_tree.yml | 31 - .../trigger_build_chromium_with_symbols.yml | 33 - .github/workflows/trigger_build_ffmpeg.yml | 24 - .github/workflows/trigger_build_firefox.yml | 24 - .../workflows/trigger_build_firefox_beta.yml | 24 - .github/workflows/trigger_build_webkit.yml | 24 - .github/workflows/trigger_build_winldd.yml | 24 - browser_patches/README.md | 194 -- browser_patches/build.sh | 39 - .../checkout_build_archive_upload.sh | 548 ---- .../chromium-tip-of-tree/BUILD_NUMBER | 1 - .../chromium-tip-of-tree/EXPECTED_BUILDS | 5 - .../chromium-tip-of-tree/UPSTREAM_CONFIG.sh | 3 - .../chromium-tip-of-tree/archive.sh | 9 - browser_patches/chromium-tip-of-tree/build.sh | 9 - browser_patches/chromium-tip-of-tree/clean.sh | 9 - .../roll_to_current_tip_of_tree.sh | 32 - browser_patches/chromium/.gitignore | 3 - browser_patches/chromium/BUILD_NUMBER | 1 - browser_patches/chromium/EXPECTED_BUILDS | 5 - .../chromium/EXPECTED_BUILDS_WITH_SYMBOLS | 5 - browser_patches/chromium/UPSTREAM_CONFIG.sh | 3 - browser_patches/chromium/archive.sh | 92 - browser_patches/chromium/build.sh | 130 - browser_patches/chromium/buildwin.bat | 2 - browser_patches/chromium/buildwingoma.bat | 2 - browser_patches/chromium/clean.sh | 15 - .../chromium/compute_files_to_archive.js | 26 - .../chromium/ensure_depot_tools.sh | 32 - browser_patches/chromium/goma.sh | 105 - .../chromium/roll_to_current_beta.sh | 32 - browser_patches/clean.sh | 39 - browser_patches/docker/cli.sh | 98 - .../docker/firefox-beta/debian-11.dockerfile | 54 - .../firefox-beta/ubuntu-18.04.dockerfile | 60 - .../ubuntu-20.04-arm64.dockerfile | 62 - .../firefox-beta/ubuntu-20.04.dockerfile | 54 - .../ubuntu-22.04-arm64.dockerfile | 62 - .../firefox-beta/ubuntu-22.04.dockerfile | 54 - .../docker/firefox/debian-11.dockerfile | 54 - .../docker/firefox/ubuntu-18.04.dockerfile | 60 - .../firefox/ubuntu-20.04-arm64.dockerfile | 62 - .../docker/firefox/ubuntu-20.04.dockerfile | 54 - .../firefox/ubuntu-22.04-arm64.dockerfile | 62 - .../docker/firefox/ubuntu-22.04.dockerfile | 54 - browser_patches/docker/pwuser_bashrc | 29 - .../docker/webkit/debian-11.dockerfile | 48 - .../docker/webkit/ubuntu-18.04.dockerfile | 67 - .../webkit/ubuntu-20.04-arm64.dockerfile | 56 - .../docker/webkit/ubuntu-20.04.dockerfile | 45 - .../webkit/ubuntu-22.04-arm64.dockerfile | 56 - .../docker/webkit/ubuntu-22.04.dockerfile | 45 - browser_patches/export.sh | 177 - browser_patches/ffmpeg/.gitignore | 2 - browser_patches/ffmpeg/BUILD_NUMBER | 1 - browser_patches/ffmpeg/CONFIG.sh | 53 - browser_patches/ffmpeg/EXPECTED_BUILDS | 6 - browser_patches/ffmpeg/README.md | 57 - browser_patches/ffmpeg/archive.sh | 34 - browser_patches/ffmpeg/build-linux.sh | 93 - browser_patches/ffmpeg/build-mac.sh | 106 - browser_patches/ffmpeg/build.sh | 78 - browser_patches/ffmpeg/clean.sh | 9 - .../ffmpeg/crosscompile-from-linux.sh | 147 - .../ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 | 502 --- browser_patches/firefox-beta/.gitignore | 1 - browser_patches/firefox-beta/BUILD_NUMBER | 2 - browser_patches/firefox-beta/EXPECTED_BUILDS | 9 - .../firefox-beta/UPSTREAM_CONFIG.sh | 3 - browser_patches/firefox-beta/archive.sh | 61 - browser_patches/firefox-beta/build.sh | 153 - browser_patches/firefox-beta/clean.sh | 20 - .../firefox-beta/install-preferences.js | 100 - .../firefox-beta/juggler/Helper.js | 135 - .../firefox-beta/juggler/NetworkObserver.js | 958 ------ .../firefox-beta/juggler/SimpleChannel.js | 180 - .../firefox-beta/juggler/TargetRegistry.js | 1065 ------ .../juggler/components/Juggler.js | 135 - .../juggler/components/components.conf | 18 - .../firefox-beta/juggler/components/moz.build | 6 - .../firefox-beta/juggler/content/FrameTree.js | 634 ---- .../firefox-beta/juggler/content/PageAgent.js | 894 ----- .../firefox-beta/juggler/content/Runtime.js | 596 ---- .../juggler/content/WorkerMain.js | 76 - .../juggler/content/hidden-scrollbars.css | 7 - .../firefox-beta/juggler/content/main.js | 155 - browser_patches/firefox-beta/juggler/jar.mn | 25 - .../firefox-beta/juggler/moz.build | 10 - .../firefox-beta/juggler/pipe/components.conf | 15 - .../firefox-beta/juggler/pipe/moz.build | 24 - .../juggler/pipe/nsIRemoteDebuggingPipe.idl | 20 - .../juggler/pipe/nsRemoteDebuggingPipe.cpp | 223 -- .../juggler/pipe/nsRemoteDebuggingPipe.h | 34 - .../juggler/protocol/BrowserHandler.js | 296 -- .../juggler/protocol/Dispatcher.js | 135 - .../juggler/protocol/PageHandler.js | 466 --- .../juggler/protocol/PrimitiveTypes.js | 147 - .../firefox-beta/juggler/protocol/Protocol.js | 993 ------ .../screencast/HeadlessWindowCapturer.cpp | 144 - .../screencast/HeadlessWindowCapturer.h | 64 - .../juggler/screencast/ScreencastEncoder.cpp | 382 --- .../juggler/screencast/ScreencastEncoder.h | 45 - .../juggler/screencast/WebMFileWriter.cpp | 50 - .../juggler/screencast/WebMFileWriter.h | 32 - .../juggler/screencast/components.conf | 15 - .../firefox-beta/juggler/screencast/moz.build | 49 - .../screencast/nsIScreencastService.idl | 31 - .../screencast/nsScreencastService.cpp | 378 --- .../juggler/screencast/nsScreencastService.h | 29 - .../firefox-beta/patches/bootstrap.diff | 2905 ----------------- .../preferences/00-playwright-prefs.js | 3 - .../firefox-beta/preferences/playwright.cfg | 291 -- browser_patches/firefox/BUILD_NUMBER | 2 - browser_patches/firefox/EXPECTED_BUILDS | 9 - browser_patches/firefox/archive.sh | 61 - browser_patches/firefox/build.sh | 153 - browser_patches/firefox/clean.sh | 20 - .../firefox/install-preferences.js | 100 - browser_patches/get_xcode_version.js | 30 - browser_patches/prepare_checkout.sh | 270 -- browser_patches/repack-juggler.mjs | 341 -- browser_patches/sanitize_and_compress_log.js | 81 - browser_patches/send_telegram_message.js | 78 - browser_patches/upload.sh | 82 - browser_patches/utils.sh | 85 - browser_patches/webkit/BUILD_NUMBER | 2 - browser_patches/webkit/EXPECTED_BUILDS | 12 - browser_patches/webkit/archive.sh | 145 - browser_patches/webkit/build.sh | 132 - browser_patches/webkit/buildwin.bat | 5 - browser_patches/webkit/clean.sh | 29 - browser_patches/webkit/concat_protocol.js | 7 - browser_patches/webkit/pw_run_debug.sh | 45 - browser_patches/webkit/upstream_status.md | 20 - 135 files changed, 17680 deletions(-) delete mode 100644 .github/workflows/trigger_build_chromium.yml delete mode 100644 .github/workflows/trigger_build_chromium_tip_of_tree.yml delete mode 100644 .github/workflows/trigger_build_chromium_with_symbols.yml delete mode 100644 .github/workflows/trigger_build_ffmpeg.yml delete mode 100644 .github/workflows/trigger_build_firefox.yml delete mode 100644 .github/workflows/trigger_build_firefox_beta.yml delete mode 100644 .github/workflows/trigger_build_webkit.yml delete mode 100644 .github/workflows/trigger_build_winldd.yml delete mode 100644 browser_patches/README.md delete mode 100755 browser_patches/build.sh delete mode 100755 browser_patches/checkout_build_archive_upload.sh delete mode 100644 browser_patches/chromium-tip-of-tree/BUILD_NUMBER delete mode 100644 browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS delete mode 100644 browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh delete mode 100755 browser_patches/chromium-tip-of-tree/archive.sh delete mode 100755 browser_patches/chromium-tip-of-tree/build.sh delete mode 100755 browser_patches/chromium-tip-of-tree/clean.sh delete mode 100755 browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh delete mode 100644 browser_patches/chromium/.gitignore delete mode 100644 browser_patches/chromium/BUILD_NUMBER delete mode 100644 browser_patches/chromium/EXPECTED_BUILDS delete mode 100644 browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS delete mode 100644 browser_patches/chromium/UPSTREAM_CONFIG.sh delete mode 100755 browser_patches/chromium/archive.sh delete mode 100755 browser_patches/chromium/build.sh delete mode 100644 browser_patches/chromium/buildwin.bat delete mode 100644 browser_patches/chromium/buildwingoma.bat delete mode 100755 browser_patches/chromium/clean.sh delete mode 100644 browser_patches/chromium/compute_files_to_archive.js delete mode 100644 browser_patches/chromium/ensure_depot_tools.sh delete mode 100755 browser_patches/chromium/goma.sh delete mode 100755 browser_patches/chromium/roll_to_current_beta.sh delete mode 100755 browser_patches/clean.sh delete mode 100755 browser_patches/docker/cli.sh delete mode 100644 browser_patches/docker/firefox-beta/debian-11.dockerfile delete mode 100644 browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile delete mode 100644 browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile delete mode 100644 browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile delete mode 100644 browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile delete mode 100644 browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile delete mode 100644 browser_patches/docker/firefox/debian-11.dockerfile delete mode 100644 browser_patches/docker/firefox/ubuntu-18.04.dockerfile delete mode 100644 browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile delete mode 100644 browser_patches/docker/firefox/ubuntu-20.04.dockerfile delete mode 100644 browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile delete mode 100644 browser_patches/docker/firefox/ubuntu-22.04.dockerfile delete mode 100644 browser_patches/docker/pwuser_bashrc delete mode 100644 browser_patches/docker/webkit/debian-11.dockerfile delete mode 100644 browser_patches/docker/webkit/ubuntu-18.04.dockerfile delete mode 100644 browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile delete mode 100644 browser_patches/docker/webkit/ubuntu-20.04.dockerfile delete mode 100644 browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile delete mode 100644 browser_patches/docker/webkit/ubuntu-22.04.dockerfile delete mode 100755 browser_patches/export.sh delete mode 100644 browser_patches/ffmpeg/.gitignore delete mode 100644 browser_patches/ffmpeg/BUILD_NUMBER delete mode 100644 browser_patches/ffmpeg/CONFIG.sh delete mode 100644 browser_patches/ffmpeg/EXPECTED_BUILDS delete mode 100644 browser_patches/ffmpeg/README.md delete mode 100755 browser_patches/ffmpeg/archive.sh delete mode 100644 browser_patches/ffmpeg/build-linux.sh delete mode 100755 browser_patches/ffmpeg/build-mac.sh delete mode 100755 browser_patches/ffmpeg/build.sh delete mode 100755 browser_patches/ffmpeg/clean.sh delete mode 100644 browser_patches/ffmpeg/crosscompile-from-linux.sh delete mode 100644 browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 delete mode 100644 browser_patches/firefox-beta/.gitignore delete mode 100644 browser_patches/firefox-beta/BUILD_NUMBER delete mode 100644 browser_patches/firefox-beta/EXPECTED_BUILDS delete mode 100644 browser_patches/firefox-beta/UPSTREAM_CONFIG.sh delete mode 100755 browser_patches/firefox-beta/archive.sh delete mode 100755 browser_patches/firefox-beta/build.sh delete mode 100755 browser_patches/firefox-beta/clean.sh delete mode 100644 browser_patches/firefox-beta/install-preferences.js delete mode 100644 browser_patches/firefox-beta/juggler/Helper.js delete mode 100644 browser_patches/firefox-beta/juggler/NetworkObserver.js delete mode 100644 browser_patches/firefox-beta/juggler/SimpleChannel.js delete mode 100644 browser_patches/firefox-beta/juggler/TargetRegistry.js delete mode 100644 browser_patches/firefox-beta/juggler/components/Juggler.js delete mode 100644 browser_patches/firefox-beta/juggler/components/components.conf delete mode 100644 browser_patches/firefox-beta/juggler/components/moz.build delete mode 100644 browser_patches/firefox-beta/juggler/content/FrameTree.js delete mode 100644 browser_patches/firefox-beta/juggler/content/PageAgent.js delete mode 100644 browser_patches/firefox-beta/juggler/content/Runtime.js delete mode 100644 browser_patches/firefox-beta/juggler/content/WorkerMain.js delete mode 100644 browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css delete mode 100644 browser_patches/firefox-beta/juggler/content/main.js delete mode 100644 browser_patches/firefox-beta/juggler/jar.mn delete mode 100644 browser_patches/firefox-beta/juggler/moz.build delete mode 100644 browser_patches/firefox-beta/juggler/pipe/components.conf delete mode 100644 browser_patches/firefox-beta/juggler/pipe/moz.build delete mode 100644 browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl delete mode 100644 browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp delete mode 100644 browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h delete mode 100644 browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js delete mode 100644 browser_patches/firefox-beta/juggler/protocol/Dispatcher.js delete mode 100644 browser_patches/firefox-beta/juggler/protocol/PageHandler.js delete mode 100644 browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js delete mode 100644 browser_patches/firefox-beta/juggler/protocol/Protocol.js delete mode 100644 browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp delete mode 100644 browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h delete mode 100644 browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp delete mode 100644 browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h delete mode 100644 browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp delete mode 100644 browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h delete mode 100644 browser_patches/firefox-beta/juggler/screencast/components.conf delete mode 100644 browser_patches/firefox-beta/juggler/screencast/moz.build delete mode 100644 browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl delete mode 100644 browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp delete mode 100644 browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h delete mode 100644 browser_patches/firefox-beta/patches/bootstrap.diff delete mode 100644 browser_patches/firefox-beta/preferences/00-playwright-prefs.js delete mode 100644 browser_patches/firefox-beta/preferences/playwright.cfg delete mode 100644 browser_patches/firefox/BUILD_NUMBER delete mode 100644 browser_patches/firefox/EXPECTED_BUILDS delete mode 100755 browser_patches/firefox/archive.sh delete mode 100755 browser_patches/firefox/build.sh delete mode 100755 browser_patches/firefox/clean.sh delete mode 100644 browser_patches/firefox/install-preferences.js delete mode 100755 browser_patches/get_xcode_version.js delete mode 100755 browser_patches/prepare_checkout.sh delete mode 100755 browser_patches/repack-juggler.mjs delete mode 100755 browser_patches/sanitize_and_compress_log.js delete mode 100644 browser_patches/send_telegram_message.js delete mode 100755 browser_patches/upload.sh delete mode 100644 browser_patches/utils.sh delete mode 100644 browser_patches/webkit/BUILD_NUMBER delete mode 100644 browser_patches/webkit/EXPECTED_BUILDS delete mode 100755 browser_patches/webkit/archive.sh delete mode 100755 browser_patches/webkit/build.sh delete mode 100644 browser_patches/webkit/buildwin.bat delete mode 100755 browser_patches/webkit/clean.sh delete mode 100644 browser_patches/webkit/concat_protocol.js delete mode 100755 browser_patches/webkit/pw_run_debug.sh delete mode 100644 browser_patches/webkit/upstream_status.md diff --git a/.github/workflows/trigger_build_chromium.yml b/.github/workflows/trigger_build_chromium.yml deleted file mode 100644 index e2b2314624..0000000000 --- a/.github/workflows/trigger_build_chromium.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: "Trigger: Chromium Builds" - -on: - workflow_dispatch: - inputs: - ref: - description: 'Playwright SHA / ref to build Chromium' - required: true - default: 'main' - push: - branches: - - main - - release-* - paths: - - browser_patches/chromium/BUILD_NUMBER - - .github/workflows/trigger_build_chromium.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"build_chromium\", \"client_payload\": {\"ref\": \"${GHREF}\"}}" \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} - GHREF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.sha }} diff --git a/.github/workflows/trigger_build_chromium_tip_of_tree.yml b/.github/workflows/trigger_build_chromium_tip_of_tree.yml deleted file mode 100644 index bdab67cb4d..0000000000 --- a/.github/workflows/trigger_build_chromium_tip_of_tree.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: "Trigger: Chromium Tip Of Tree Builds" - -on: - workflow_dispatch: - inputs: - ref: - description: 'Playwright SHA / ref to build Chromium Tip Of Tree' - required: true - default: 'main' - push: - branches: - - main - - release-* - paths: - - browser_patches/chromium-tip-of-tree/BUILD_NUMBER - - .github/workflows/trigger_build_chromium_tip_of_tree.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"build_chromium_tip_of_tree\", \"client_payload\": {\"ref\": \"${GHREF}\"}}" \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} - GHREF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.sha }} diff --git a/.github/workflows/trigger_build_chromium_with_symbols.yml b/.github/workflows/trigger_build_chromium_with_symbols.yml deleted file mode 100644 index 8fd161a5a7..0000000000 --- a/.github/workflows/trigger_build_chromium_with_symbols.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: "Trigger: Chromium with Symbols Builds" - - -on: - workflow_dispatch: - inputs: - ref: - description: 'Playwright SHA / ref to build Chromium With Symbols' - required: true - default: 'main' - release: - types: [published] - push: - branches: - - release-* - paths: - - browser_patches/chromium/BUILD_NUMBER - - .github/workflows/trigger_build_chromium_with_symbols.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"build_chromium_with_symbols\", \"client_payload\": {\"ref\": \"${GHREF}\"}}" \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} - GHREF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.sha }} diff --git a/.github/workflows/trigger_build_ffmpeg.yml b/.github/workflows/trigger_build_ffmpeg.yml deleted file mode 100644 index 6202c68a16..0000000000 --- a/.github/workflows/trigger_build_ffmpeg.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "FFMPEG Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/ffmpeg/BUILD_NUMBER - - .github/workflows/trigger_build_ffmpeg.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_ffmpeg"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_firefox.yml b/.github/workflows/trigger_build_firefox.yml deleted file mode 100644 index f0dc3b3daf..0000000000 --- a/.github/workflows/trigger_build_firefox.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "Firefox Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/firefox/BUILD_NUMBER - - .github/workflows/trigger_build_firefox.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_firefox"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_firefox_beta.yml b/.github/workflows/trigger_build_firefox_beta.yml deleted file mode 100644 index 762dd95e18..0000000000 --- a/.github/workflows/trigger_build_firefox_beta.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "Firefox Beta Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/firefox-beta/BUILD_NUMBER - - .github/workflows/trigger_build_firefox_beta.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_firefox_beta"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_webkit.yml b/.github/workflows/trigger_build_webkit.yml deleted file mode 100644 index 3dd79da40c..0000000000 --- a/.github/workflows/trigger_build_webkit.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "WebKit Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/webkit/BUILD_NUMBER - - .github/workflows/trigger_build_webkit.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_webkit"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_winldd.yml b/.github/workflows/trigger_build_winldd.yml deleted file mode 100644 index dfb2f4bfeb..0000000000 --- a/.github/workflows/trigger_build_winldd.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "WinLDD Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/winldd/BUILD_NUMBER - - .github/workflows/trigger_build_winldd.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_winldd"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/browser_patches/README.md b/browser_patches/README.md deleted file mode 100644 index e56d6eae3b..0000000000 --- a/browser_patches/README.md +++ /dev/null @@ -1,194 +0,0 @@ -- [Contributing Browser Patches](#Contributing-browser-patches) - * [1. Setting up local browser checkout](#1-setting-up-local-browser-checkout) - * [2. Developing a new change](#2-developing-a-new-change) - * [3. Exporting your change to playwright repo](#3-exporting-your-change-to-playwright-repo) - * [4. Rolling Playwright to the new browser build](#4-rolling-playwright-to-the-new-browser-build) -- [Cheatsheet](#cheatsheet) - * [Firefox](#firefox) - - [stack trace](#stack-trace) - - [logging](#logging) - * [WebKit](#webkit) - - [Debugging Windows](#degugging-windows) - - [Enable core dumps on Linux](#enable-core-dumps-on-linux) - -# Contributing Browser Patches - -Firefox and WebKit have additional patches atop to expose necessary capabilities. - -Ideally, all these changes should be upstreamed. -For the time being, it is possible to setup a browser checkout -and develop from there. - -[WebKit upstream status](webkit/upstream_status.md) - -## 1. Setting up local browser checkout - -From the `playwright` repo, run the following command: - -```bash -$ ./browser_patches/prepare_checkout.sh firefox -``` -(you can optionally pass "webkit" for a webkit checkout) - -This will create a firefox checkout at `$HOME/firefox` - -> **NOTE:** this command downloads GBs of data. - - -This command will: -- create a `browser_upstream` remote in the checkout -- create a `playwright-build` branch and apply all playwright-required patches to it. - -## 2. Developing a new change - -### Creating new branch - -You want to create a new branch off the `playwright-build` branch. - -Assuming that you're under `$HOME/firefox` checkout: - -```bash -$ git checkout -b my-new-feature playwright-build -$ # develop my feature on the my-new-feature branch .... -``` - -### Building - -Each browser has corresponding build script. `--full` options normally takes care of also installing required build dependencies on Linux. - -```bash -./browser_patches/firefox/build.sh --full -``` - -### Running tests with local browser build - -Playwright test suite may run against local browser build without bundling it. -```bash -# Run webkit tests with local webkit build -WKPATH=./browser_patches/webkit/pw_run.sh npm run wtest - -# Run firefox tests with local firefox build on macos -FFPATH=/tmp/repackaged-firefox/firefox/Nightly.app/Contents/MacOS/firefox npm run ftest - -# Run chromium tests with local chromium build on linux -CRPATH=~/chromium/src/out/Release/chrome npm run ctest -``` - -### Flakiness dashboard - -You can look at the [flakiness dashboard](http://flaky.aslushnikov.com/) to see recent history of any playwright test. - -## 3. Exporting your change to playwright repo - -Once you're happy with the work you did in the browser-land, you want to export it to the `playwright` repo. - -Assuming that you're in the root of the `playwright` repo and that your browser checkout has your feature branch checked out: - -```bash -$ ./browser_patches/export.sh firefox -``` - -This script will: -- create a new patch and put it to the `./browser_patches/firefox/patches/` -- update the `./browser_patches/firefox/UPSTREAM_CONFIG.sh` if necessary -- bump the `./browser_patches/firefox/BUILD_NUMBER` number. - -The script will assume Firefox checkout is located at `$HOME/firefox` - -Send a PR to the Playwright repo to be reviewed. - -## 4. Rolling Playwright to the new browser build - -Once the patch has been committed, the build bots will kick in, compile and upload a new browser version to all the platforms. Then you can roll the browser: - -```bash -$ node utils/roll_browser.js chromium 123456 -``` - -# Cheatsheet - -## See browser stdout/stderr - -Set the `DEBUG=pw:browser` environment variable to see it. - -## Firefox - -### Debug build - -When compiling set the `FF_DEBUG_BUILD=1` environment variable. - -#### Stack trace - -In `//mozglue/misc/StackWalk.cpp` add - -```c++ -#define MOZ_DEMANGLE_SYMBOLS 1 -``` - -In native code use - -```c++ -#include "mozilla/StackWalk.h" -// ... -MozWalkTheStack(stderr); -``` - -If the stack trace is still mangled `cat` it to `tools/rb/fix_linux_stack.py` - -#### Logging - -Upstream documentation: https://firefox-source-docs.mozilla.org/xpcom/logging.html - -```bash -MOZ_LOG=nsHttp:5 -``` - -Module name is a string passed to the `mozilla::LazyLogModule` of the corresponding component, e.g.: - -```c++ -LazyLogModule gHttpLog("nsHttp"); -``` - -Inside Juggler, you can use `dump('foo\n')`. - -## WebKit - -#### Logging - -Inside Objective-C you can use [NSLog](https://developer.apple.com/documentation/foundation/1395275-nslog). - -``` -NSLog(@"Foobar value: %@", value); -``` - -#### Debugging windows - -In `Source\WTF\wtf\win\DbgHelperWin.cpp` replace - -```#if !defined(NDEBUG)``` with ```#if 1``` - -Then regular `WTFReportBacktrace()` works. - -#### Debugging linux - -`WTFReportBacktrace()` has been broken since [r283707](https://github.com/WebKit/WebKit/commit/de4ba48c8f229bc45042b543a514f6d88b551a64), see [this comment](https://bugs.webkit.org/show_bug.cgi?id=181916#c96). Revert that change locally to make backtraces work again. Otherwise addr2line -f can still be used to map addresses to function names. - -#### Enable core dumps on Linux - -```bash -mkdir -p /tmp/coredumps -sudo bash -c 'echo "/tmp/coredumps/core-pid_%p.dump" > /proc/sys/kernel/core_pattern' -ulimit -c unlimited -``` - -Then to read stack traces run the following command: -```bash -# To find out crashing process name -file core-pid_29652.dump -# Point gdb to the local binary of the crashed process and the core file -gdb $HOME/.cache/ms-playwright/webkit-1292/minibrowser-gtk/WebKitWebProcess core-pid_29652 -# Inside gdb update .so library search path to the local one -set solib-search-path /home/yurys/.cache/ms-playwright/webkit-1292/minibrowser-gtk -# Finally print backtrace -bt -``` diff --git a/browser_patches/build.sh b/browser_patches/build.sh deleted file mode 100755 index 509307f9e0..0000000000 --- a/browser_patches/build.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: build.sh [firefox|webkit|firefox-beta]" - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './build.sh --help' for more information" - exit 1 -fi - -CMD="$1" -shift -if [[ ("$CMD" == "firefox") || ("$CMD" == "firefox/") || ("$CMD" == "ff") ]]; then - bash ./firefox/build.sh "$@" -elif [[ ("$CMD" == "firefox-beta") || ("$CMD" == "ff-beta") ]]; then - bash ./firefox-beta/build.sh "$@" -elif [[ ("$CMD" == "webkit") || ("$CMD" == "webkit/") || ("$CMD" == "wk") ]]; then - bash ./webkit/build.sh "$@" -elif [[ ("$CMD" == "chromium") || ("$CMD" == "chromium/") || ("$CMD" == "cr") ]]; then - bash ./chromium/build.sh "$@" -elif [[ ("$CMD" == "winldd") ]]; then - bash ./winldd/build.sh "$@" -elif [[ ("$CMD" == "ffmpeg") ]]; then - bash ./ffmpeg/build.sh "$@" -else - echo ERROR: unknown browser to build - "$CMD" - exit 1 -fi - diff --git a/browser_patches/checkout_build_archive_upload.sh b/browser_patches/checkout_build_archive_upload.sh deleted file mode 100755 index 3d6e6ce179..0000000000 --- a/browser_patches/checkout_build_archive_upload.sh +++ /dev/null @@ -1,548 +0,0 @@ -#!/bin/bash -set -e -set +x -set -o pipefail - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [firefox-linux|firefox-win64|webkit-gtk|webkit-wpe|webkit-gtk-wpe|webkit-win64|webkit-mac-10.15] [-f|--force]" - echo - echo "Prepares checkout under browser folder, applies patches, builds, archives, and uploads if build is missing." - echo "Script will bail out early if the build for the browser version is already present." - echo - echo "Pass -f to upload anyway." - echo - echo "NOTE: This script is safe to run in a cronjob - it aquires a lock so that it does not run twice." - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing build flavor!" - echo "try './$(basename "$0") --help' for more information" - exit 1 -fi - -CURRENT_ARCH="$(uname -m)" -CURRENT_HOST_OS="$(uname)" -CURRENT_HOST_OS_VERSION="" -if [[ "$CURRENT_HOST_OS" == "Darwin" ]]; then - CURRENT_HOST_OS_VERSION=$(sw_vers -productVersion | grep -o '^\d\+.\d\+') -elif [[ "$CURRENT_HOST_OS" == "Linux" ]]; then - CURRENT_HOST_OS="$(bash -c 'source /etc/os-release && echo $NAME')" - CURRENT_HOST_OS_VERSION="$(bash -c 'source /etc/os-release && echo $VERSION_ID')" -fi - -BROWSER_NAME="" -BROWSER_DISPLAY_NAME="" -EXTRA_BUILD_ARGS="" -EXTRA_ARCHIVE_ARGS="" -BUILD_FLAVOR="$1" -BUILD_BLOB_NAME="" -EXPECTED_HOST_OS="" -EXPECTED_HOST_OS_VERSION="" -EXPECTED_ARCH="x86_64" -BUILDS_LIST="EXPECTED_BUILDS" - -# =========================== -# WINLDD COMPILATION -# =========================== -if [[ "$BUILD_FLAVOR" == "winldd-win64" ]]; then - BROWSER_NAME="winldd" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="winldd-win64.zip" - - -# =========================== -# FFMPEG COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "ffmpeg-mac" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--mac --full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - BUILD_BLOB_NAME="ffmpeg-mac.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-mac-arm64" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--mac --full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="ffmpeg-mac-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-linux" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--linux" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="ffmpeg-linux.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-linux-arm64" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--cross-compile-linux-arm64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="ffmpeg-linux-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-cross-compile-win64" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--cross-compile-win64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="ffmpeg-win64.zip" - -# =========================== -# CHROMIUM COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "chromium-win64" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="chromium-win64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-mac" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-mac.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-mac-arm64" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-mac-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-linux" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="chromium-linux.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-linux-arm64" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="chromium-linux-arm64.zip" - -# =========================== -# CHROMIUM-TIP-OF-TREE COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-win64" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="chromium-tip-of-tree-win64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-mac" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-tip-of-tree-mac.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-mac-arm64" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-tip-of-tree-mac-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-linux" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="chromium-tip-of-tree-linux.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-linux-arm64" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="chromium-tip-of-tree-linux-arm64.zip" - -# =========================== -# CHROMIUM-WITH-SYMBOLS COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-win64" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--symbols --full --goma" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="chromium-with-symbols-win64.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-mac" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--symbols --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-with-symbols-mac.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-mac-arm64" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--arm64 --symbols --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-with-symbols-mac-arm64.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-linux" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--symbols --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="chromium-with-symbols-linux.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-linux-arm64" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols-arm64" - EXTRA_BUILD_ARGS="--arm64 --symbols --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="chromium-with-symbols-linux-arm64.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" - -# =========================== -# FIREFOX COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-18.04" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="firefox-ubuntu-18.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-20.04" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-ubuntu-20.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-20.04-arm64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-ubuntu-20.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-22.04" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-ubuntu-22.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-22.04-arm64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-ubuntu-22.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-debian-11" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Debian" - EXPECTED_HOST_OS_VERSION="11" - BUILD_BLOB_NAME="firefox-debian-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-mac-11" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="x86_64" - BUILD_BLOB_NAME="firefox-mac-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-mac-11-arm64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="firefox-mac-11-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-win64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="firefox-win64.zip" - # This is the architecture that is set by mozilla-build bash. - EXPECTED_ARCH="i686" - - -# =============================== -# FIREFOX-BETA COMPILATION -# =============================== -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-18.04" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-18.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-20.04" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-20.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-20.04-arm64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-20.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-22.04" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-22.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-22.04-arm64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-22.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-debian-11" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Debian" - EXPECTED_HOST_OS_VERSION="11" - BUILD_BLOB_NAME="firefox-beta-debian-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-mac-11" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="x86_64" - BUILD_BLOB_NAME="firefox-beta-mac-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-mac-11-arm64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="firefox-beta-mac-11-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-win64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="firefox-beta-win64.zip" - # This is the architecture that is set by mozilla-build bash. - EXPECTED_ARCH="i686" - -# =========================== -# WEBKIT COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "webkit-debian-11" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Debian" - EXPECTED_HOST_OS_VERSION="11" - BUILD_BLOB_NAME="webkit-debian-11.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-18.04" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="webkit-ubuntu-18.04.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-20.04" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="webkit-ubuntu-20.04.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-20.04-arm64" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - EXPECTED_ARCH="aarch64" - BUILD_BLOB_NAME="webkit-ubuntu-20.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-22.04" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="webkit-ubuntu-22.04.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-22.04-arm64" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - EXPECTED_ARCH="aarch64" - BUILD_BLOB_NAME="webkit-ubuntu-22.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-win64" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="webkit-win64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-10.15" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="10.15" - BUILD_BLOB_NAME="webkit-mac-10.15.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-12" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="webkit-mac-12.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-12-arm64" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="webkit-mac-12-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-11" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - BUILD_BLOB_NAME="webkit-mac-11.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-11-arm64" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="webkit-mac-11-arm64.zip" - - -# =========================== -# Unknown input -# =========================== -else - echo ERROR: unknown build flavor - "$BUILD_FLAVOR" - exit 1 -fi - -if [[ -z "$BROWSER_DISPLAY_NAME" ]]; then - BROWSER_DISPLAY_NAME="${BROWSER_NAME}" -fi - -if [[ "$CURRENT_ARCH" != "$EXPECTED_ARCH" ]]; then - echo "ERROR: cannot build $BUILD_FLAVOR" - echo " -- expected arch: $EXPECTED_ARCH" - echo " -- current arch: $CURRENT_ARCH" - exit 1 -fi - -if [[ "$CURRENT_HOST_OS" != $EXPECTED_HOST_OS* ]]; then - echo "ERROR: cannot build $BUILD_FLAVOR" - echo " -- expected OS: $EXPECTED_HOST_OS" - echo " -- current OS: $CURRENT_HOST_OS" - exit 1 -fi - -if [[ "$CURRENT_HOST_OS_VERSION" != "$EXPECTED_HOST_OS_VERSION" ]]; then - echo "ERROR: cannot build $BUILD_FLAVOR" - echo " -- expected OS Version: $EXPECTED_HOST_OS_VERSION" - echo " -- current OS Version: $CURRENT_HOST_OS_VERSION" - exit 1 -fi - -if [[ $(uname) == MINGW* || "$(uname)" == MSYS* ]]; then - ZIP_PATH="$PWD/archive-$BROWSER_NAME.zip" - LOG_PATH="$PWD/log-$BROWSER_NAME.zip" -else - ZIP_PATH="/tmp/archive-$BROWSER_NAME.zip" - LOG_PATH="/tmp/log-$BROWSER_NAME.zip" -fi - -if [[ -f "$ZIP_PATH" ]]; then - echo "Archive $ZIP_PATH already exists - remove and re-run the script." - exit 1 -fi -trap "rm -rf ${ZIP_PATH}; rm -rf ${LOG_PATH}; cd $(pwd -P);" INT TERM EXIT -cd "$(dirname "$0")" -BUILD_NUMBER=$(head -1 ./$BROWSER_NAME/BUILD_NUMBER) -BUILD_BLOB_PATH="${BROWSER_NAME}/${BUILD_NUMBER}/${BUILD_BLOB_NAME}" -LOG_BLOB_NAME="${BUILD_BLOB_NAME%.zip}.log.gz" -LOG_BLOB_PATH="${BROWSER_NAME}/${BUILD_NUMBER}/${LOG_BLOB_NAME}" - -# pull from upstream and check if a new build has to be uploaded. -if ! [[ ($2 == '-f') || ($2 == '--force') ]]; then - if ./upload.sh "${BUILD_BLOB_PATH}" --check; then - echo "Build is already uploaded - no changes." - exit 0 - fi -else - echo "Force-rebuilding the build." -fi - -function generate_and_upload_browser_build { - echo "-- preparing checkout" - if ! ./prepare_checkout.sh $BROWSER_NAME; then - return 20 - fi - - echo "-- cleaning" - if ! ./$BROWSER_NAME/clean.sh; then - return 21 - fi - - echo "-- building" - if ! ./$BROWSER_NAME/build.sh $EXTRA_BUILD_ARGS; then - return 22 - fi - - echo "-- archiving to $ZIP_PATH" - if ! ./$BROWSER_NAME/archive.sh "$ZIP_PATH" $EXTRA_ARCHIVE_ARGS; then - return 23 - fi - - echo "-- uploading" - if ! ./upload.sh "$BUILD_BLOB_PATH" "$ZIP_PATH"; then - return 24 - fi - return 0 -} - -function create_roll_into_playwright_pr { - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "roll_into_pw", "client_payload": {"browser": "'"$1"'", "revision": "'"$2"'"}}' \ - https://api.github.com/repos/microsoft/playwright/dispatches -} - -BUILD_ALIAS="$BUILD_FLAVOR r$BUILD_NUMBER" -node send_telegram_message.js "$BUILD_ALIAS -- started" - -if generate_and_upload_browser_build 2>&1 | ./sanitize_and_compress_log.js $LOG_PATH; then - # Report successful build. Note: MINGW might not have `du` command. - UPLOAD_SIZE="" - if command -v du >/dev/null && command -v awk >/dev/null; then - UPLOAD_SIZE="$(du -h "$ZIP_PATH" | awk '{print $1}') " - fi - node send_telegram_message.js "$BUILD_ALIAS -- ${UPLOAD_SIZE}uploaded" - - # Check if we uploaded the last build. - ( - for i in $(cat "${BROWSER_NAME}/${BUILDS_LIST}"); do - URL="https://playwright2.blob.core.windows.net/builds/${BROWSER_NAME}/${BUILD_NUMBER}/$i" - if ! [[ $(curl -s -L -I "$URL" | head -1 | cut -f2 -d' ') == 200 ]]; then - # Exit subshell - echo "Missing build at ${URL}" - exit - fi - done; - LAST_COMMIT_MESSAGE=$(git log --format=%s -n 1 HEAD -- "./${BROWSER_NAME}/BUILD_NUMBER") - node send_telegram_message.js "${BROWSER_DISPLAY_NAME} r${BUILD_NUMBER} COMPLETE! ✅ ${LAST_COMMIT_MESSAGE}" - if [[ "${BROWSER_DISPLAY_NAME}" != "chromium-with-symbols" ]]; then - create_roll_into_playwright_pr $BROWSER_NAME $BUILD_NUMBER - fi - ) -else - RESULT_CODE="$?" - if (( RESULT_CODE == 10 )); then - FAILED_STEP="./download_gtk_and_wpe_and_zip_together.sh" - elif (( RESULT_CODE == 11 )); then - FAILED_STEP="./upload.sh" - elif (( RESULT_CODE == 20 )); then - FAILED_STEP="./prepare_checkout.sh" - elif (( RESULT_CODE == 21 )); then - FAILED_STEP="./clean.sh" - elif (( RESULT_CODE == 22 )); then - FAILED_STEP="./build.sh" - elif (( RESULT_CODE == 23 )); then - FAILED_STEP="./archive.sh" - elif (( RESULT_CODE == 24 )); then - FAILED_STEP="./upload.sh" - else - FAILED_STEP="" - fi - # Upload logs only in case of failure and report failure. - ./upload.sh "${LOG_BLOB_PATH}" ${LOG_PATH} || true - node send_telegram_message.js "$BUILD_ALIAS -- ${FAILED_STEP} failed! ❌ ${LOG_BLOB_NAME} -- GitHub Action Logs" - exit 1 -fi - diff --git a/browser_patches/chromium-tip-of-tree/BUILD_NUMBER b/browser_patches/chromium-tip-of-tree/BUILD_NUMBER deleted file mode 100644 index 4fba33e90d..0000000000 --- a/browser_patches/chromium-tip-of-tree/BUILD_NUMBER +++ /dev/null @@ -1 +0,0 @@ -1037 diff --git a/browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS b/browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS deleted file mode 100644 index 2575021ad4..0000000000 --- a/browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS +++ /dev/null @@ -1,5 +0,0 @@ -chromium-tip-of-tree-mac.zip -chromium-tip-of-tree-mac-arm64.zip -chromium-tip-of-tree-linux.zip -chromium-tip-of-tree-linux-arm64.zip -chromium-tip-of-tree-win64.zip diff --git a/browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh b/browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh deleted file mode 100644 index b08f1afc4e..0000000000 --- a/browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh +++ /dev/null @@ -1,3 +0,0 @@ -# CURRENT_VERSION: 107.0.5260.0 -# BRANCH_BASE_POSITION: 1039004 -BRANCH_COMMIT="36307074a546485e40ad2295e546e3a681596689" diff --git a/browser_patches/chromium-tip-of-tree/archive.sh b/browser_patches/chromium-tip-of-tree/archive.sh deleted file mode 100755 index 3e260dfb0a..0000000000 --- a/browser_patches/chromium-tip-of-tree/archive.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -bash "../chromium/archive.sh" "$@" diff --git a/browser_patches/chromium-tip-of-tree/build.sh b/browser_patches/chromium-tip-of-tree/build.sh deleted file mode 100755 index efc6479c61..0000000000 --- a/browser_patches/chromium-tip-of-tree/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -bash "../chromium/build.sh" "$@" diff --git a/browser_patches/chromium-tip-of-tree/clean.sh b/browser_patches/chromium-tip-of-tree/clean.sh deleted file mode 100755 index 3ea4237e9c..0000000000 --- a/browser_patches/chromium-tip-of-tree/clean.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -bash "../chromium/clean.sh" "$@" diff --git a/browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh b/browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh deleted file mode 100755 index 4ddf20bf32..0000000000 --- a/browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -# 1. get current version -CURRENT_BETA_VERSION=$(curl https://omahaproxy.appspot.com/all | grep "win64,canary," | cut -d ',' -f 3) -VERSION_INFO_JSON=$(curl "https://omahaproxy.appspot.com/deps.json?version=$CURRENT_BETA_VERSION") - -NODE_SCRIPT=$(cat < "${SCRIPT_FOLDER}/UPSTREAM_CONFIG.sh" -BUILD_NUMBER=$(cat "${SCRIPT_FOLDER}/BUILD_NUMBER") -echo $(( $BUILD_NUMBER + 1 )) > "${SCRIPT_FOLDER}/BUILD_NUMBER" diff --git a/browser_patches/chromium/.gitignore b/browser_patches/chromium/.gitignore deleted file mode 100644 index 2658404cd7..0000000000 --- a/browser_patches/chromium/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/output -/depot_tools -/electron-build-tools diff --git a/browser_patches/chromium/BUILD_NUMBER b/browser_patches/chromium/BUILD_NUMBER deleted file mode 100644 index c7781419a3..0000000000 --- a/browser_patches/chromium/BUILD_NUMBER +++ /dev/null @@ -1 +0,0 @@ -1022 diff --git a/browser_patches/chromium/EXPECTED_BUILDS b/browser_patches/chromium/EXPECTED_BUILDS deleted file mode 100644 index aa0df7e2ef..0000000000 --- a/browser_patches/chromium/EXPECTED_BUILDS +++ /dev/null @@ -1,5 +0,0 @@ -chromium-mac.zip -chromium-mac-arm64.zip -chromium-linux.zip -chromium-linux-arm64.zip -chromium-win64.zip diff --git a/browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS b/browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS deleted file mode 100644 index 36a818ac6f..0000000000 --- a/browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS +++ /dev/null @@ -1,5 +0,0 @@ -chromium-with-symbols-mac.zip -chromium-with-symbols-mac-arm64.zip -chromium-with-symbols-linux.zip -chromium-with-symbols-linux-arm64.zip -chromium-with-symbols-win64.zip diff --git a/browser_patches/chromium/UPSTREAM_CONFIG.sh b/browser_patches/chromium/UPSTREAM_CONFIG.sh deleted file mode 100644 index f09f91b09c..0000000000 --- a/browser_patches/chromium/UPSTREAM_CONFIG.sh +++ /dev/null @@ -1,3 +0,0 @@ -# CURRENT_VERSION: 105.0.5195.52 -# BRANCH_BASE_POSITION: 1027018 -BRANCH_COMMIT="f6b3c2f7e67f9f47e936acbcb765fa557b670851" diff --git a/browser_patches/chromium/archive.sh b/browser_patches/chromium/archive.sh deleted file mode 100755 index c9de582580..0000000000 --- a/browser_patches/chromium/archive.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_PATH=$(pwd -P) -source "${SCRIPT_PATH}/../utils.sh" - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename "$0") [output-absolute-path]" - echo - echo "Generate distributable .zip archive from ./output folder that was previously downloaded." - echo - exit 0 -fi - -ZIP_PATH=$1 - -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname "$ZIP_PATH") ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" -fi -if [[ ! -d "${CR_CHECKOUT_PATH}/src" ]]; then - echo "ERROR: CR_CHECKOUT_PATH does not have src/ subfolder; is this a chromium checkout?" - exit 1 -fi - -CHROMIUM_FOLDER_NAME="" -CHROMIUM_FILES_TO_ARCHIVE=() - -if is_mac; then - CHROMIUM_FOLDER_NAME="chrome-mac" - IFS=$'\n' CHROMIUM_FILES_TO_ARCHIVE=($(node "${SCRIPT_PATH}/compute_files_to_archive.js" "${CR_CHECKOUT_PATH}/src/infra/archive_config/mac-archive-rel.json")) - unset IFS -elif is_linux; then - CHROMIUM_FOLDER_NAME="chrome-linux" - IFS=$'\n' CHROMIUM_FILES_TO_ARCHIVE=($(node "${SCRIPT_PATH}/compute_files_to_archive.js" "${CR_CHECKOUT_PATH}/src/infra/archive_config/linux-archive-rel.json")) - unset IFS -elif is_win; then - CHROMIUM_FOLDER_NAME="chrome-win" - IFS=$'\n\r' CHROMIUM_FILES_TO_ARCHIVE=($(node "${SCRIPT_PATH}/compute_files_to_archive.js" "${CR_CHECKOUT_PATH}/src/infra/archive_config/win-archive-rel.json")) - unset IFS -else - echo "ERROR: unsupported platform - $(uname)" - exit 1 -fi - -# Prepare resulting archive. -cd "$SCRIPT_PATH" -rm -rf output -mkdir -p "output/${CHROMIUM_FOLDER_NAME}" - -# On Mac, use 'ditto' to copy directories instead of 'cp'. -COPY_COMMAND="cp -R" -if is_mac; then - COPY_COMMAND="ditto" -fi - -for ((i = 0; i < ${#CHROMIUM_FILES_TO_ARCHIVE[@]}; i++)) do - file="${CHROMIUM_FILES_TO_ARCHIVE[$i]}" - mkdir -p "output/${CHROMIUM_FOLDER_NAME}/$(dirname "${file}")" - $COPY_COMMAND "${CR_CHECKOUT_PATH}/src/out/Default/${file}" "output/${CHROMIUM_FOLDER_NAME}/${file}" -done - -if is_win; then - $COPY_COMMAND "${CR_CHECKOUT_PATH}/src/out/Default/"*.manifest "output/${CHROMIUM_FOLDER_NAME}/" - mkdir -p "output/${CHROMIUM_FOLDER_NAME}/locales" - $COPY_COMMAND "${CR_CHECKOUT_PATH}/src/out/Default/locales/"*.pak "output/${CHROMIUM_FOLDER_NAME}/locales/" -fi - -cd output -zip --symlinks -r build.zip "${CHROMIUM_FOLDER_NAME}" - -cd "${SCRIPT_PATH}" -cp output/build.zip "$ZIP_PATH" diff --git a/browser_patches/chromium/build.sh b/browser_patches/chromium/build.sh deleted file mode 100755 index 521fb32e70..0000000000 --- a/browser_patches/chromium/build.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) -source "${SCRIPT_FOLDER}/../utils.sh" - -USAGE=$(cat< - - --arm64 cross-compile for arm64 - --symbols compile with symbols - --full install build dependencies - --goma use goma when compiling. Make sure to pre-start goma client beforehand with './goma.sh start'. - - On Linux & MacOS, it is possible to specify custom compilation targets: - - ./build.sh --goma blink_tests - -EOF -) - -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ $1 == "--help" || $1 == "-h" ]]; then - echo "$USAGE" - exit 0 -fi - -args=("$@") -IS_ARM64="" -IS_SYMBOLS_BUILD="" -IS_FULL="" -USE_GOMA="" -for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --arm64) IS_ARM64="1"; unset args[i]; ;; - --symbols) IS_SYMBOLS_BUILD="1"; unset args[i]; ;; - --full) IS_FULL="1"; unset args[i]; ;; - --goma) USE_GOMA="1"; unset args[i]; ;; - esac -done - -compile_chromium() { - if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" - fi - - if [[ ! -d "${CR_CHECKOUT_PATH}/src" ]]; then - echo "ERROR: CR_CHECKOUT_PATH does not have src/ subfolder; is this a chromium checkout?" - exit 1 - fi - - source "${SCRIPT_FOLDER}/ensure_depot_tools.sh" - - if is_mac; then - selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" chromium) - fi - - cd "${CR_CHECKOUT_PATH}/src" - - # Prepare build folder. - mkdir -p "./out/Default" - echo "is_debug = false" > ./out/Default/args.gn - echo "dcheck_always_on = false" >> ./out/Default/args.gn - if [[ -n "${IS_SYMBOLS_BUILD}" ]]; then - echo "symbol_level = 1" >> ./out/Default/args.gn - else - echo "symbol_level = 0" >> ./out/Default/args.gn - fi - - if [[ -n "${IS_ARM64}" ]]; then - echo 'target_cpu = "arm64"' >> ./out/Default/args.gn - fi - - if [[ ! -z "$USE_GOMA" ]]; then - "${SCRIPT_FOLDER}/goma.sh" args >> ./out/Default/args.gn - fi - echo 'enable_nacl = false' >> ./out/Default/args.gn - - echo "===== args.gn =====" - cat ./out/Default/args.gn - echo "===== ======= =====" - - if [[ -n "$IS_FULL" ]]; then - if is_linux; then - ./build/install-build-deps.sh - if [[ -n "$IS_ARM64" ]]; then - # Install sysroot image, see https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/linux/chromium_arm.md - ./build/linux/sysroot_scripts/install-sysroot.py --arch=arm64 - fi - fi - fi - - TARGETS="${args[@]}" - if is_win; then - if [[ -n "$TARGETS" ]]; then - echo "ERROR: cannot compile custom targets on windows yet." - echo "Requested to compile chromium targets - ${TARGETS}" - exit 1 - fi - if [[ -z "$USE_GOMA" ]]; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w "${SCRIPT_FOLDER}"/buildwin.bat)" - else - /c/Windows/System32/cmd.exe "/c $(cygpath -w "${SCRIPT_FOLDER}"/buildwingoma.bat)" - fi - else - if [[ -z "$TARGETS" ]]; then - if is_linux; then - TARGETS="chrome chrome_sandbox clear_key_cdm" - else - TARGETS="chrome" - fi - fi - echo - echo ">> Compiling Targets: $TARGETS" - echo - - gn gen out/Default - if [[ -z "$USE_GOMA" ]]; then - autoninja -C out/Default $TARGETS - else - ninja -j 200 -C out/Default $TARGETS - fi - fi -} - -compile_chromium "${args[@]}" diff --git a/browser_patches/chromium/buildwin.bat b/browser_patches/chromium/buildwin.bat deleted file mode 100644 index eec9a5c412..0000000000 --- a/browser_patches/chromium/buildwin.bat +++ /dev/null @@ -1,2 +0,0 @@ -CALL gn gen out/Default -CALL autoninja -C out/Default chrome eventlog_provider diff --git a/browser_patches/chromium/buildwingoma.bat b/browser_patches/chromium/buildwingoma.bat deleted file mode 100644 index d834c5516f..0000000000 --- a/browser_patches/chromium/buildwingoma.bat +++ /dev/null @@ -1,2 +0,0 @@ -CALL gn gen out/Default -CALL ninja -j 200 -C out/Default chrome eventlog_provider diff --git a/browser_patches/chromium/clean.sh b/browser_patches/chromium/clean.sh deleted file mode 100755 index e03c7df33b..0000000000 --- a/browser_patches/chromium/clean.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -rm -rf output -if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" -fi - -if [[ -d "${CR_CHECKOUT_PATH}/src" ]]; then - rm -rf "${CR_CHECKOUT_PATH}/src/out" -fi diff --git a/browser_patches/chromium/compute_files_to_archive.js b/browser_patches/chromium/compute_files_to_archive.js deleted file mode 100644 index 341837bc1c..0000000000 --- a/browser_patches/chromium/compute_files_to_archive.js +++ /dev/null @@ -1,26 +0,0 @@ -// This script is supposed to be run with a path to either of the following configs from chromium checkout: -// - infra/archive_config/mac-archive-rel.json -// - infra/archive_config/linux-archive-rel.json -// - infra/archive_config/win-archive-rel.json - -const fs = require('fs'); - -const configs = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')).archive_datas; -const config = configs.find(config => config.gcs_path.includes('chrome-linux.zip') || config.gcs_path.includes('chrome-win.zip') || config.gcs_path.includes('chrome-mac.zip')); - -const excludeList = new Set([ - // We do not need interactive tests in our archive. - 'interactive_ui_tests.exe', - // We no longer compile nacl with Chromium. - 'nacl_helper_bootstrap', - 'nacl_helper', - 'nacl_irt_x86_64.nexe', -]); - -const entries = [ - ...(config.files || []), - ...(config.dirs || []), -].filter(entry => !excludeList.has(entry)); - -for (const entry of entries) - console.log(entry); diff --git a/browser_patches/chromium/ensure_depot_tools.sh b/browser_patches/chromium/ensure_depot_tools.sh deleted file mode 100644 index c746fe5362..0000000000 --- a/browser_patches/chromium/ensure_depot_tools.sh +++ /dev/null @@ -1,32 +0,0 @@ -# Since this script modifies PATH, it cannot be run in a subshell -# and must be sourced. -# Make sure it is sourced. -sourced=0 -(return 0 2>/dev/null) && sourced=1 || sourced=0 - -if [[ $sourced == 0 ]]; then - echo 'ERROR: cannot run this script in a subshell' - echo 'This file modifies $PATH of the current shell, so it must be sourced instead' - echo 'Use `source ensure_depot_tool.sh` instead' - exit 1 -fi - -function ensure_depot_tools() { - # Install depot_tools if they are not in system, and modify $PATH - # to include depot_tools - if ! command -v autoninja >/dev/null; then - if [[ $(uname) == "MINGW"* || "$(uname)" == MSYS* ]]; then - # NOTE: as of Feb 8, 2021, windows requires manual and separate - # installation of depot_tools. - echo "ERROR: cannot automatically install depot_tools on windows. Please, install manually" - exit 1 - fi - local SCRIPT_PATH=$(cd "$(dirname "$BASH_SOURCE")"; pwd -P) - if [[ ! -d "${SCRIPT_PATH}/depot_tools" ]]; then - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git "${SCRIPT_PATH}/depot_tools" - fi - export PATH="${SCRIPT_PATH}/depot_tools:$PATH" - fi -} - -ensure_depot_tools diff --git a/browser_patches/chromium/goma.sh b/browser_patches/chromium/goma.sh deleted file mode 100755 index 8e2ff8649b..0000000000 --- a/browser_patches/chromium/goma.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) -source "${SCRIPT_FOLDER}/../utils.sh" - -ELECTRON_BUILD_TOOLS_REQUIRED_VERSION=2c24fb5c7c938a4e387f355ab64be449604ae5db -if [[ -d ./electron-build-tools ]]; then - cd ./electron-build-tools - # Make sure required commit is part of electron-build-tools. - if ! git merge-base --is-ancestor "${ELECTRON_BUILD_TOOLS_REQUIRED_VERSION}" HEAD; then - cd .. - rm -rf ./electron-build-tools - echo "Updating electron-build-tools" - else - cd .. - fi -fi - -if [[ ! -d ./electron-build-tools ]]; then - git clone --single-branch --branch main https://github.com/electron/build-tools/ electron-build-tools - cd electron-build-tools - npm install - mkdir -p third_party - ./src/e update-goma msftGoma - cd .. -fi - -if ! is_win; then - if command -v python >/dev/null; then - PYTHON=python - elif command -v python3 >/dev/null; then - PYTHON=python3 - else - echo "ERROR: no python or python3 found in PATH" - exit 1 - fi -fi - -cd electron-build-tools/third_party/goma - -export GOMA_START_COMPILER_PROXY=true - -function print_gn_args() { - PLAYWRIGHT_GOMA_PATH="${SCRIPT_FOLDER}/electron-build-tools/third_party/goma" - if is_win; then - PLAYWRIGHT_GOMA_PATH=$(cygpath -w "${PLAYWRIGHT_GOMA_PATH}") - fi - echo 'use_goma = true' - echo "goma_dir = \"${PLAYWRIGHT_GOMA_PATH}\"" -} - -if [[ $1 == "--help" ]]; then - echo "$(basename "$0") [login|start|stop|--help]" - exit 0 -elif [[ $1 == "args" ]]; then - print_gn_args -elif [[ $1 == "login" ]]; then - if is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w $(pwd)/goma_auth.bat) login" - else - $PYTHON ./goma_auth.py login - fi - echo - echo "Congratulation! Goma is logged in!" - echo "run '$(basename "$0") start' to launch goma client" -elif [[ $1 == "start" ]]; then - # We have to prefix ENV with `PLAYWRIGHT` since `GOMA_` env variables - # have special treatment by goma. - if [[ ! -z "$PLAYWRIGHT_GOMA_LOGIN_COOKIE" ]]; then - echo "$PLAYWRIGHT_GOMA_LOGIN_COOKIE" > "$HOME/.goma_oauth2_config" - fi - if [[ ! -f "$HOME/.goma_oauth2_config" ]]; then - echo "ERROR: goma is not logged in!" - echo "run '$(basename "$0") login'" - exit 1 - fi - if is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w $(pwd)/goma_ctl.bat) ensure_start" - else - $PYTHON ./goma_ctl.py ensure_start - fi - set +x - echo - echo "Congratulatons! Goma is running!" - echo - echo "Add the following gn args to use goma:" - echo - echo "===== args.gn =====" - print_gn_args - echo "===== ======= =====" -elif [[ $1 == "stop" ]]; then - if is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w $(pwd)/goma_ctl.bat) stop" - else - $PYTHON ./goma_ctl.py stop - fi -else - echo "ERROR: unknown command - $1" - echo "Use --help to list all available commands" - exit 1 -fi diff --git a/browser_patches/chromium/roll_to_current_beta.sh b/browser_patches/chromium/roll_to_current_beta.sh deleted file mode 100755 index 7b1c7d6e04..0000000000 --- a/browser_patches/chromium/roll_to_current_beta.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -# 1. get current version -CURRENT_BETA_VERSION=$(curl https://omahaproxy.appspot.com/all | grep "win64,beta" | cut -d ',' -f 3) -VERSION_INFO_JSON=$(curl "https://omahaproxy.appspot.com/deps.json?version=$CURRENT_BETA_VERSION") - -NODE_SCRIPT=$(cat < "${SCRIPT_FOLDER}/UPSTREAM_CONFIG.sh" -BUILD_NUMBER=$(cat "${SCRIPT_FOLDER}/BUILD_NUMBER") -echo $(( $BUILD_NUMBER + 1 )) > "${SCRIPT_FOLDER}/BUILD_NUMBER" diff --git a/browser_patches/clean.sh b/browser_patches/clean.sh deleted file mode 100755 index b6a2cfe1da..0000000000 --- a/browser_patches/clean.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: clean.sh [firefox|webkit|firefox-beta]" - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './clean.sh --help' for more information" - exit 1 -fi - -CMD="$1" -shift -if [[ ("$CMD" == "firefox") || ("$CMD" == "firefox/") || ("$CMD" == "ff") ]]; then - bash ./firefox/clean.sh "$@" -elif [[ ("$CMD" == "firefox-beta") || ("$CMD" == "ff-beta") ]]; then - bash ./firefox-beta/clean.sh "$@" -elif [[ ("$CMD" == "webkit") || ("$CMD" == "webkit/") || ("$CMD" == "wk") ]]; then - bash ./webkit/clean.sh "$@" -elif [[ ("$CMD" == "chromium") || ("$CMD" == "chromium/") || ("$CMD" == "cr") ]]; then - bash ./chromium/clean.sh "$@" -elif [[ ("$CMD" == "winldd") ]]; then - bash ./winldd/clean.sh "$@" -elif [[ ("$CMD" == "ffmpeg") ]]; then - bash ./ffmpeg/clean.sh "$@" -else - echo ERROR: unknown browser to build - "$CMD" - exit 1 -fi - diff --git a/browser_patches/docker/cli.sh b/browser_patches/docker/cli.sh deleted file mode 100755 index 1904ebad7e..0000000000 --- a/browser_patches/docker/cli.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# This script is designed to build Firefox & WebKit on various Linux -# distributions inside docker containers. -set -e -set +x -set -o pipefail - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [webkit-ubuntu-20.04|firefox-debian-11|...] [build|test|compile|enter|cleanup]" - echo - echo "Builds Webkit or Firefox browser inside given Linux distribution" - exit 0 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" - -export BUILD_FLAVOR="${1}" -export BROWSER_NAME="" - -DOCKERFILE="" - -if [[ "${BUILD_FLAVOR}" == "firefox-beta-"* ]]; then - DOCKERFILE="${SCRIPT_FOLDER}/firefox-beta/${BUILD_FLAVOR#firefox-beta-}.dockerfile" - BROWSER_NAME="firefox-beta" -elif [[ "${BUILD_FLAVOR}" == "firefox-"* ]]; then - DOCKERFILE="${SCRIPT_FOLDER}/firefox/${BUILD_FLAVOR#firefox-}.dockerfile" - BROWSER_NAME="firefox" -elif [[ "${BUILD_FLAVOR}" == "webkit-"* ]]; then - DOCKERFILE="${SCRIPT_FOLDER}/webkit/${BUILD_FLAVOR#webkit-}.dockerfile" - BROWSER_NAME="webkit" -else - echo "ERROR: unknown build flavor - ${BUILD_FLAVOR}" - exit 1 -fi - -if [[ "${BUILD_FLAVOR}" == *"-arm64" ]]; then - EXPECTED_ARCH="arm64" - DOCKER_PLATFORM="linux/arm64" -else - EXPECTED_ARCH="x86_64" - DOCKER_PLATFORM="linux/amd64" -fi - -if [[ $(arch) != "${EXPECTED_ARCH}" ]]; then - echo "ERROR: host architecture $(arch) does not match expected architecture - ${EXPECTED_ARCH}" - exit 1 -fi - -DOCKER_IMAGE_NAME="${BUILD_FLAVOR}" -DOCKER_CONTAINER_NAME="${BUILD_FLAVOR}" -DOCKER_ARGS=$(echo \ - --env CI \ - --env BUILD_FLAVOR \ - --env BROWSER_NAME \ - --env TELEGRAM_BOT_KEY \ - --env AZ_ACCOUNT_NAME \ - --env AZ_ACCOUNT_KEY \ - --env GITHUB_SERVER_URL \ - --env GITHUB_REPOSITORY \ - --env GITHUB_RUN_ID \ - --env GH_TOKEN \ - --env DEBIAN_FRONTEND=noninteractive \ - --env TZ="America/Los_Angeles" -) - -if [[ "$2" == "build" ]]; then - docker build \ - --build-arg ARG_BUILD_FLAVOR="${BUILD_FLAVOR}" \ - --build-arg ARG_BROWSER_NAME="${BROWSER_NAME}" \ - --no-cache \ - --platform "${DOCKER_PLATFORM}" \ - -t "${DOCKER_IMAGE_NAME}" \ - -f "${DOCKERFILE}" . -elif [[ "$2" == "test" ]]; then - docker run --rm ${DOCKER_ARGS} --init --name "${DOCKER_CONTAINER_NAME}" --platform "${DOCKER_PLATFORM}" -it "${DOCKER_IMAGE_NAME}" /bin/bash -c ' - CI=1 ./browser_patches/prepare_checkout.sh "${BROWSER_NAME}" - ./browser_patches/build.sh "${BROWSER_NAME}" --full - ./browser_patches/${BROWSER_NAME}/archive.sh $PWD/archive.zip - ' -elif [[ "$2" == "compile" ]]; then - docker run --rm ${DOCKER_ARGS} --init --name "${DOCKER_CONTAINER_NAME}" --platform "${DOCKER_PLATFORM}" -t "${DOCKER_IMAGE_NAME}" /bin/bash -c ' - ./browser_patches/checkout_build_archive_upload.sh "${BUILD_FLAVOR}" - ' -elif [[ "$2" == "enter" ]]; then - docker run --rm ${DOCKER_ARGS} --init --name "${DOCKER_CONTAINER_NAME}" --platform "${DOCKER_PLATFORM}" -it "${DOCKER_IMAGE_NAME}" /bin/bash -elif [[ "$2" == "cleanup" ]]; then - docker kill "${DOCKER_CONTAINER_NAME}" || true - # Wait for container to stop - docker wait "${DOCKER_CONTAINER_NAME}" || true - docker rmi "${DOCKER_IMAGE_NAME}" - docker system prune -f -else - echo "ERROR: unknown command - $2" - exit 1 -fi - diff --git a/browser_patches/docker/firefox-beta/debian-11.dockerfile b/browser_patches/docker/firefox-beta/debian-11.dockerfile deleted file mode 100644 index 714e0f3860..0000000000 --- a/browser_patches/docker/firefox-beta/debian-11.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 debian:11 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile deleted file mode 100644 index b329797466..0000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:18.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -# Firefox build on Ubuntu 18.04 requires Python3.8 to run its build scripts. -RUN apt-get install -y python3.8 python3.8-dev python3.8-distutils && \ - # Point python3 to python3.8 - update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2 && \ - curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \ - python3 get-pip.py && \ - rm get-pip.py - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile deleted file mode 100644 index 8528f52ac2..0000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 20.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile deleted file mode 100644 index d6dcbab630..0000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile deleted file mode 100644 index 768e956b09..0000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 22.04 aarch64 specific: default to clang-14. -RUN apt-get install -y clang-14 -ENV CC=/usr/bin/clang-14 -ENV CXX=/usr/bin/clang++-14 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile deleted file mode 100644 index 348ef04af3..0000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/debian-11.dockerfile b/browser_patches/docker/firefox/debian-11.dockerfile deleted file mode 100644 index 714e0f3860..0000000000 --- a/browser_patches/docker/firefox/debian-11.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 debian:11 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-18.04.dockerfile b/browser_patches/docker/firefox/ubuntu-18.04.dockerfile deleted file mode 100644 index b329797466..0000000000 --- a/browser_patches/docker/firefox/ubuntu-18.04.dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:18.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -# Firefox build on Ubuntu 18.04 requires Python3.8 to run its build scripts. -RUN apt-get install -y python3.8 python3.8-dev python3.8-distutils && \ - # Point python3 to python3.8 - update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2 && \ - curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \ - python3 get-pip.py && \ - rm get-pip.py - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile b/browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile deleted file mode 100644 index 8528f52ac2..0000000000 --- a/browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 20.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-20.04.dockerfile b/browser_patches/docker/firefox/ubuntu-20.04.dockerfile deleted file mode 100644 index d6dcbab630..0000000000 --- a/browser_patches/docker/firefox/ubuntu-20.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile b/browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile deleted file mode 100644 index 768e956b09..0000000000 --- a/browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 22.04 aarch64 specific: default to clang-14. -RUN apt-get install -y clang-14 -ENV CC=/usr/bin/clang-14 -ENV CXX=/usr/bin/clang++-14 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-22.04.dockerfile b/browser_patches/docker/firefox/ubuntu-22.04.dockerfile deleted file mode 100644 index 348ef04af3..0000000000 --- a/browser_patches/docker/firefox/ubuntu-22.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/pwuser_bashrc b/browser_patches/docker/pwuser_bashrc deleted file mode 100644 index ed78a6e053..0000000000 --- a/browser_patches/docker/pwuser_bashrc +++ /dev/null @@ -1,29 +0,0 @@ -source /etc/os-release -if [[ -z "${BUILD_FLAVOR}" ]]; then - BUILD_FLAVOR='' -fi -if [[ -z "${BROWSER_NAME}" ]]; then - BROWSER_NAME='' -fi - -echo "======================================================================" -echo "Welcome to the ${BUILD_FLAVOR} environment!" -echo "- distro: ${PRETTY_NAME}" -echo "- arch: $(arch)" - -if [[ -n "${CXX}" ]]; then - echo "- CXX: ${CXX}" -fi -if [[ -n "${CC}" ]]; then - echo "- CC: ${CC}" -fi - -echo -echo "NOTE: Playwright clone is shallow (has no git history); to unshallow, run:" -echo " git fetch --unshallow" -echo -echo "To get started, prepare your browser checkout:" -echo " CI=1 ./browser_patches/prepare_checkout.sh ${BROWSER_NAME}" -echo -echo "======================================================================" - diff --git a/browser_patches/docker/webkit/debian-11.dockerfile b/browser_patches/docker/webkit/debian-11.dockerfile deleted file mode 100644 index 34969d74d4..0000000000 --- a/browser_patches/docker/webkit/debian-11.dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM --platform=linux/amd64 debian:11 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -# Debian 11 specific: add contrib & non-free repositories. -RUN echo "deb http://ftp.us.debian.org/debian bullseye main contrib non-free" >> /etc/apt/sources.list.d/pwbuild.list - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-18.04.dockerfile b/browser_patches/docker/webkit/ubuntu-18.04.dockerfile deleted file mode 100644 index 8d03b4c919..0000000000 --- a/browser_patches/docker/webkit/ubuntu-18.04.dockerfile +++ /dev/null @@ -1,67 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:18.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 18.04 specific: update CMake. Default CMake on Ubuntu 18.04 is 3.10, whereas WebKit requires 3.12+. -RUN apt purge --auto-remove cmake && \ - apt-get install -y wget software-properties-common && \ - wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null && \ - apt-add-repository "deb https://apt.kitware.com/ubuntu/ bionic main" && \ - apt-get update && apt-get install -y cmake - -# Ubuntu 18.04 specific: default to gcc-9. -RUN add-apt-repository ppa:ubuntu-toolchain-r/test && \ - apt-get update && \ - apt-get install -y gcc-9 g++-9 -ENV CC=/usr/bin/gcc-9 -ENV CXX=/usr/bin/g++-9 - -# Install Python3 with distutils -RUN apt-get install -y python3.8 python3.8-dev python3.8-distutils && \ - # Point python3 to python3.8 - update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2 && \ - curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \ - python3 get-pip.py && \ - rm get-pip.py - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile b/browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile deleted file mode 100644 index 5b30404a56..0000000000 --- a/browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 20.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN apt-get install -y python3 \ - python3-dev \ - python3-pip \ - python3-distutils && \ - pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-20.04.dockerfile b/browser_patches/docker/webkit/ubuntu-20.04.dockerfile deleted file mode 100644 index 2609546265..0000000000 --- a/browser_patches/docker/webkit/ubuntu-20.04.dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile b/browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile deleted file mode 100644 index 30e86a1f3e..0000000000 --- a/browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 22.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN apt-get install -y python3 \ - python3-dev \ - python3-pip \ - python3-distutils && \ - pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-22.04.dockerfile b/browser_patches/docker/webkit/ubuntu-22.04.dockerfile deleted file mode 100644 index 928874b654..0000000000 --- a/browser_patches/docker/webkit/ubuntu-22.04.dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/export.sh b/browser_patches/export.sh deleted file mode 100755 index 01139737f0..0000000000 --- a/browser_patches/export.sh +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -REMOTE_BROWSER_UPSTREAM="browser_upstream" -BUILD_BRANCH="playwright-build" - -# COLORS -RED=$'\e[1;31m' -GRN=$'\e[1;32m' -YEL=$'\e[1;33m' -END=$'\e[0m' - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: export.sh [firefox|webkit] [custom_checkout_path]" - echo - echo "Exports patch from the current branch of the checkout to browser folder." - echo "The checkout has to be 'prepared', meaning that 'prepare_checkout.sh' should be" - echo "run against it first." - echo - echo "You can optionally specify custom_checkout_path if you have browser checkout somewhere else" - echo "and wish to export patches from it." - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './export.sh --help' for more information" - exit 1 -fi - -# FRIENDLY_CHECKOUT_PATH is used only for logging. -FRIENDLY_CHECKOUT_PATH=""; -BUILD_NUMBER_UPSTREAM_URL="" -CHECKOUT_PATH="" -EXPORT_PATH="" -EXTRA_FOLDER_PW_PATH="" -EXTRA_FOLDER_CHECKOUT_RELPATH="" -if [[ ("$1" == "firefox") || ("$1" == "firefox/") || ("$1" == "ff") ]]; then - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - EXTRA_FOLDER_PW_PATH="$PWD/firefox/juggler" - EXTRA_FOLDER_CHECKOUT_RELPATH="juggler" - EXPORT_PATH="$PWD/firefox" - BUILD_NUMBER_UPSTREAM_URL="https://raw.githubusercontent.com/microsoft/playwright/main/browser_patches/firefox/BUILD_NUMBER" - source "./firefox/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "firefox-beta") || ("$1" == "ff-beta") ]]; then - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - EXTRA_FOLDER_PW_PATH="$PWD/firefox-beta/juggler" - EXTRA_FOLDER_CHECKOUT_RELPATH="juggler" - EXPORT_PATH="$PWD/firefox-beta" - BUILD_NUMBER_UPSTREAM_URL="https://raw.githubusercontent.com/microsoft/playwright/main/browser_patches/firefox-beta/BUILD_NUMBER" - source "./firefox-beta/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "webkit") || ("$1" == "webkit/") || ("$1" == "wk") ]]; then - if [[ -z "${WK_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/webkit'; - CHECKOUT_PATH="$HOME/webkit" - else - echo "WARNING: using checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" - CHECKOUT_PATH="${WK_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - EXTRA_FOLDER_PW_PATH="$PWD/webkit/embedder/Playwright" - EXTRA_FOLDER_CHECKOUT_RELPATH="Tools/Playwright" - EXPORT_PATH="$PWD/webkit" - BUILD_NUMBER_UPSTREAM_URL="https://raw.githubusercontent.com/microsoft/playwright/main/browser_patches/webkit/BUILD_NUMBER" - source "./webkit/UPSTREAM_CONFIG.sh" -else - echo ERROR: unknown browser to export - "$1" - exit 1 -fi - -# we will use this just for beauty. -if [[ $# == 2 ]]; then - echo "WARNING: using custom checkout path $2" - CHECKOUT_PATH=$2 - FRIENDLY_CHECKOUT_PATH="" -fi - -# if there's no checkout folder - bail out. -if ! [[ -d $CHECKOUT_PATH ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH is missing - nothing to export." - exit 1; -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH exists - OK" -fi - -# if folder exists but not a git repository - bail out. -if ! [[ -d $CHECKOUT_PATH/.git ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH is not a git repository! Nothing to export." - exit 1 -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH is a git repo - OK" -fi - -# Switch to git repository. -cd "$CHECKOUT_PATH" - -# Setting up |$REMOTE_BROWSER_UPSTREAM| remote and fetch the $BASE_BRANCH -if git remote get-url $REMOTE_BROWSER_UPSTREAM >/dev/null; then - if ! [[ $(git config --get remote.$REMOTE_BROWSER_UPSTREAM.url || echo "") == "$REMOTE_URL" ]]; then - echo "ERROR: remote $REMOTE_BROWSER_UPSTREAM is not pointing to '$REMOTE_URL'! run 'prepare_checkout.sh' first" - exit 1 - fi -else - echo "ERROR: checkout does not have $REMOTE_BROWSER_UPSTREAM; run 'prepare_checkout.sh' first" - exit 1 -fi - -# Check if git repo is dirty. -if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH has dirty GIT state - aborting export." - exit 1 -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH is clean - OK" -fi - -PATCH_NAME=$(ls -1 "$EXPORT_PATH"/patches) -if [[ -z "$PATCH_NAME" ]]; then - PATCH_NAME="bootstrap.diff" - OLD_DIFF="" -else - OLD_DIFF=$(cat "$EXPORT_PATH"/patches/$PATCH_NAME) -fi - -CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -NEW_BASE_REVISION=$(git merge-base $REMOTE_BROWSER_UPSTREAM/"$BASE_BRANCH" "$CURRENT_BRANCH") -NEW_DIFF=$(git diff --diff-algorithm=myers --full-index "$NEW_BASE_REVISION" "$CURRENT_BRANCH" -- . ":!${EXTRA_FOLDER_CHECKOUT_RELPATH}") - -# Increment BUILD_NUMBER -BUILD_NUMBER=$(curl ${BUILD_NUMBER_UPSTREAM_URL} | head -1) -BUILD_NUMBER=$((BUILD_NUMBER+1)) - -echo "REMOTE_URL=\"$REMOTE_URL\" -BASE_BRANCH=\"$BASE_BRANCH\" -BASE_REVISION=\"$NEW_BASE_REVISION\"" > "$EXPORT_PATH"/UPSTREAM_CONFIG.sh -echo "$NEW_DIFF" > "$EXPORT_PATH"/patches/$PATCH_NAME -echo $BUILD_NUMBER > "$EXPORT_PATH"/BUILD_NUMBER -echo "Changed: $(git config user.email) $(date)" >> "$EXPORT_PATH"/BUILD_NUMBER - -echo "-- exporting standalone folder" -rm -rf "${EXTRA_FOLDER_PW_PATH}" -mkdir -p $(dirname "${EXTRA_FOLDER_PW_PATH}") -cp -r "${EXTRA_FOLDER_CHECKOUT_RELPATH}" "${EXTRA_FOLDER_PW_PATH}" - -NEW_BASE_REVISION_TEXT="$NEW_BASE_REVISION (not changed)" -if [[ "$NEW_BASE_REVISION" != "$BASE_REVISION" ]]; then - NEW_BASE_REVISION_TEXT="$YEL$NEW_BASE_REVISION (changed)$END" -fi - -echo "==============================================================" -echo " Repository: $FRIENDLY_CHECKOUT_PATH" -echo " Changes between branches: $REMOTE_BROWSER_UPSTREAM/$BASE_BRANCH..$CURRENT_BRANCH" -echo " BASE_REVISION: $NEW_BASE_REVISION_TEXT" -echo " BUILD_NUMBER: $YEL$BUILD_NUMBER (changed)$END" -echo "==============================================================" -echo diff --git a/browser_patches/ffmpeg/.gitignore b/browser_patches/ffmpeg/.gitignore deleted file mode 100644 index b97a986fa1..0000000000 --- a/browser_patches/ffmpeg/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -output/ diff --git a/browser_patches/ffmpeg/BUILD_NUMBER b/browser_patches/ffmpeg/BUILD_NUMBER deleted file mode 100644 index fb35a14c02..0000000000 --- a/browser_patches/ffmpeg/BUILD_NUMBER +++ /dev/null @@ -1 +0,0 @@ -1007 diff --git a/browser_patches/ffmpeg/CONFIG.sh b/browser_patches/ffmpeg/CONFIG.sh deleted file mode 100644 index 2cb8e6f836..0000000000 --- a/browser_patches/ffmpeg/CONFIG.sh +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ZLIB_VERSION="v1.2.11" -ZLIB_CONFIG="--static" - -LIBVPX_VERSION="v1.9.0" -LIBVPX_CONFIG="--enable-static \ - --disable-shared \ - --disable-docs \ - --disable-tools \ - --disable-unit-tests \ - --disable-examples" - -FFMPEG_VERSION="n4.3.1" -FFMPEG_CONFIG="--extra-version=playwright-build-$(cat ./BUILD_NUMBER | head -1) \ - --disable-debug \ - --disable-autodetect \ - --disable-everything \ - --enable-ffmpeg \ - --enable-protocol=pipe \ - --enable-protocol=file \ - --enable-parser=mjpeg \ - --enable-decoder=mjpeg \ - --enable-demuxer=image2pipe \ - --enable-filter=pad \ - --enable-filter=crop \ - --enable-filter=scale \ - --enable-muxer=webm \ - --enable-libvpx \ - --enable-static \ - --enable-encoder=libvpx_vp8 \ - --enable-decoder=libvpx_vp8 \ - --enable-demuxer=matroska \ - --enable-encoder=png \ - --enable-zlib \ - --enable-muxer=image2 \ - --disable-pthreads \ - --disable-iconv \ - --disable-w32threads \ - --disable-bzlib" - diff --git a/browser_patches/ffmpeg/EXPECTED_BUILDS b/browser_patches/ffmpeg/EXPECTED_BUILDS deleted file mode 100644 index ec5ce4f2e0..0000000000 --- a/browser_patches/ffmpeg/EXPECTED_BUILDS +++ /dev/null @@ -1,6 +0,0 @@ -ffmpeg-mac.zip -ffmpeg-mac-arm64.zip -ffmpeg-linux.zip -ffmpeg-linux-arm64.zip -ffmpeg-win64.zip - diff --git a/browser_patches/ffmpeg/README.md b/browser_patches/ffmpeg/README.md deleted file mode 100644 index 89ed18d6dc..0000000000 --- a/browser_patches/ffmpeg/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Playwright and FFMPEG - -Playwright requires FFMPEG to produce screncast and bundles FFMPEG binaries for Mac , Linux and Windows. - -## Configuration - -We compile `libvpx` and `ffmpeg` only. Their source versions and build -configurations are defined in [`//browser_patches/ffmpeg/CONFIG.sh`](./CONFIG.sh). - -## Building `ffmpeg-linux` - -Compilation scripts are based on: -- https://trac.ffmpeg.org/wiki/CompilationGuide/Generic - -Prerequisites: -- Mac or Linux -- Docker - -Building: - -``` -~/playwright$ ./browser_patches/ffmpeg/build.sh --linux -``` - -## Building `ffmpeg-mac` - -Compilation scripts are based on: -- https://trac.ffmpeg.org/wiki/CompilationGuide/Generic -- https://trac.ffmpeg.org/wiki/CompilationGuide/macOS - -Prerequisites: -- Mac -- xcode command line tools: `xcode-select --install` -- [homebrew](https://brew.sh/) - -Building: - -``` -~/playwright$ ./browser_patches/ffmpeg/build.sh --mac -``` - -## Building `ffmpeg-win*` - -Cross-compilation scripts are based on: -- https://trac.ffmpeg.org/wiki/CompilationGuide/Generic -- https://trac.ffmpeg.org/wiki/CompilationGuide/CrossCompilingForWindows - -Prerequisites: -- Mac or Linux -- [Docker](https://www.docker.com/) - -Building: - -``` -~/playwright$ ./browser_patches/ffmpeg/build.sh --cross-compile-win64 -``` - diff --git a/browser_patches/ffmpeg/archive.sh b/browser_patches/ffmpeg/archive.sh deleted file mode 100755 index ffdf2aba9e..0000000000 --- a/browser_patches/ffmpeg/archive.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -set -e -set +x - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename $0) [output-absolute-path]" - echo - echo "Generate distributable .zip archive from ./output folder that was previously built." - echo - exit 0 -fi - -ZIP_PATH=$1 -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname $ZIP_PATH) ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -cp output/ffmpeg.zip $ZIP_PATH diff --git a/browser_patches/ffmpeg/build-linux.sh b/browser_patches/ffmpeg/build-linux.sh deleted file mode 100644 index 5514a07e7c..0000000000 --- a/browser_patches/ffmpeg/build-linux.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -function die() { echo "$@"; exit 1; } - - -PREFIX="${HOME}/prefix" - - -if [[ "$(uname)" != "Linux" ]]; then - echo "ERROR: this script is designed to be run on Linux. Can't run on $(uname)" - exit 1 -fi - -output_path="$1" -if [[ -z "${output_path}" ]]; then - die "ERROR: output path is not specified" -elif [[ "${output_path}" != /* ]]; then - die "ERROR: output path ${output_path} is not absolute" -elif ! [[ -d $(dirname "${output_path}") ]]; then - die "ERROR: folder for output path ${output_path} does not exist." -fi - -function build_zlib { - cd "${HOME}" - git clone https://github.com/madler/zlib - cd zlib - git checkout "${ZLIB_VERSION}" - ./configure --prefix="${PREFIX}" ${ZLIB_CONFIG} - make && make install -} - -function build_libvpx { - cd "${HOME}" - git clone https://chromium.googlesource.com/webm/libvpx - cd libvpx - git checkout "${LIBVPX_VERSION}" - # Cross-compiling libvpx according to the docs: - # - https://chromium.googlesource.com/webm/libvpx/+/main/README - ./configure --prefix="${PREFIX}" ${LIBVPX_CONFIG} - make && make install -} - -function build_ffmpeg { - cd "${HOME}" - git clone git://source.ffmpeg.org/ffmpeg.git - cd ffmpeg - git checkout "${FFMPEG_VERSION}" - export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig" - # Prohibit pkg-config from using linux system installed libs. - export PKG_CONFIG_LIBDIR= - - ./configure --pkg-config=pkg-config \ - --pkg-config-flags="--static" \ - --extra-cflags="-I/${PREFIX}/include" \ - --extra-ldflags="-L/${PREFIX}/lib -static" \ - --prefix="${PREFIX}" \ - --bindir="${PWD}/bin" \ - ${FFMPEG_CONFIG} - make && make install -} - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -source ./CONFIG.sh - -apt-get update -apt-get install -y git make yasm pkg-config - -build_zlib -build_libvpx -build_ffmpeg - -# put resulting executable where we were asked to -cp "${HOME}/ffmpeg/bin/ffmpeg" "${output_path}" -strip "${output_path}" - diff --git a/browser_patches/ffmpeg/build-mac.sh b/browser_patches/ffmpeg/build-mac.sh deleted file mode 100755 index 91ac05f633..0000000000 --- a/browser_patches/ffmpeg/build-mac.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e - -function die() { echo "$@"; exit 1; } - -if [[ "$(uname)" != "Darwin" ]]; then - die "ERROR: this script is designed to be run on OSX. Can't run on $(uname)" -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" ffmpeg) - -source ./CONFIG.sh - -BUILDDIR="${PWD}/build" -PREFIX="${BUILDDIR}/osx_prefix" -OUTPUT_PATH="${PWD}/output/ffmpeg-mac" - -function build_zlib { - cd "${BUILDDIR}" - git clone https://github.com/madler/zlib - cd zlib - git checkout "${ZLIB_VERSION}" - ./configure --prefix="${PREFIX}" ${ZLIB_CONFIG} - make && make install -} - -function build_libvpx { - cd "${BUILDDIR}" - git clone https://chromium.googlesource.com/webm/libvpx - cd libvpx - git checkout "${LIBVPX_VERSION}" - # Compile libvpx according to the docs: - # - https://chromium.googlesource.com/webm/libvpx/+/main/README - ./configure --prefix="${PREFIX}" ${LIBVPX_CONFIG} - make && make install -} - -function build_ffmpeg { - cd "${BUILDDIR}" - git clone git://source.ffmpeg.org/ffmpeg.git - cd ffmpeg - git checkout "${FFMPEG_VERSION}" - export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig" - # Prohibit pkg-config from using system installed libs. - export PKG_CONFIG_LIBDIR= - - ./configure --pkg-config=pkg-config \ - --pkg-config-flags="--static" \ - --extra-cflags="-I/${PREFIX}/include" \ - --extra-ldflags="-L/${PREFIX}/lib" \ - --prefix="${PREFIX}" \ - --bindir="${PWD}/bin" \ - ${FFMPEG_CONFIG} - make && make install -} - -REQUIERED_BUILD_TOOLS=("git" "make" "yasm" "pkg-config") -missing_build_tools=() - -for dependency in ${REQUIERED_BUILD_TOOLS[@]}; do - if ! command -v "${dependency}" >/dev/null; then - missing_build_tools+=("${dependency}") - fi -done - -if [[ ${#missing_build_tools[@]} != 0 ]]; then - if [[ "$1" == "--full" ]]; then - brew install ${missing_build_tools[@]} - else - die "ERROR: missing dependencies! Please run: brew install ${missing_build_tools[@]}" - fi -fi - -# Cleanup -set -x -rm -rf "${BUILDDIR}" -mkdir -p "${BUILDDIR}" - -build_zlib -build_libvpx -build_ffmpeg - -# put resulting executable where we were asked to -mkdir -p $(dirname "${OUTPUT_PATH}") -cp "${BUILDDIR}/ffmpeg/bin/ffmpeg" "${OUTPUT_PATH}" -strip "${OUTPUT_PATH}" diff --git a/browser_patches/ffmpeg/build.sh b/browser_patches/ffmpeg/build.sh deleted file mode 100755 index 929f788234..0000000000 --- a/browser_patches/ffmpeg/build.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename $0) [--mac|--linux|--cross-compile-win64] [--full]" - echo - echo "Build ffmpeg for the given platform" - echo - exit 0 -fi - -if [[ -z "$1" ]]; then - echo "ERROR: expected build target. Run with --help for more info" - exit 1 -fi - -LICENSE_FILE="COPYING.LGPLv2.1" - -rm -rf ./output -mkdir -p output -cp ffmpeg-license/"${LICENSE_FILE}" output - -dockerflags=""; -# Use |-it| to run docker to support Ctrl-C if we run the script inside interactive terminal. -# Otherwise (e.g. cronjob) - do nothing. -if [[ -t 0 ]]; then - dockerflags="-it" -fi - -function ensure_docker_or_die() { - if ! command -v docker >/dev/null; then - echo "ERROR: docker is required for the script" - exit 1 - fi -} - -if [[ "$1" == "--mac" ]]; then - bash ./build-mac.sh $2 - cd output && zip ffmpeg.zip ffmpeg-mac "${LICENSE_FILE}" -elif [[ "$1" == "--linux" ]]; then - ensure_docker_or_die - - time docker run --init --rm -v"${PWD}":/host ${dockerflags} ubuntu:18.04 bash /host/build-linux.sh /host/output/ffmpeg-linux - cd output && zip ffmpeg.zip ffmpeg-linux "${LICENSE_FILE}" -elif [[ "$1" == --cross-compile-win64 ]]; then - ensure_docker_or_die - - time docker run --init --rm -v"${PWD}":/host ${dockerflags} ubuntu:18.04 bash /host/crosscompile-from-linux.sh --win64 /host/output/ffmpeg-win64.exe - cd output && zip ffmpeg.zip ffmpeg-win64.exe "${LICENSE_FILE}" -elif [[ "$1" == "--cross-compile-linux-arm64" ]]; then - ensure_docker_or_die - - time docker run --init --rm -v"${PWD}":/host ${dockerflags} ubuntu:18.04 bash /host/crosscompile-from-linux.sh --linux-arm64 /host/output/ffmpeg-linux - cd output && zip ffmpeg.zip ffmpeg-linux "${LICENSE_FILE}" -else - echo "ERROR: unsupported platform - $1" - exit 1 -fi - diff --git a/browser_patches/ffmpeg/clean.sh b/browser_patches/ffmpeg/clean.sh deleted file mode 100755 index db4d36c08e..0000000000 --- a/browser_patches/ffmpeg/clean.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -rm -rf output - diff --git a/browser_patches/ffmpeg/crosscompile-from-linux.sh b/browser_patches/ffmpeg/crosscompile-from-linux.sh deleted file mode 100644 index caa9484394..0000000000 --- a/browser_patches/ffmpeg/crosscompile-from-linux.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -function die() { echo "$@"; exit 1; } - - -PREFIX="${HOME}/prefix" -TOOLCHAIN_PREFIX_64="/usr/bin/x86_64-w64-mingw32-" -TOOLCHAIN_PREFIX_ARM64="/usr/bin/aarch64-linux-gnu-" - -arch="" -toolchain_prefix="" -binary="" - -if [[ "$(uname)" != "Linux" ]]; then - echo "ERROR: this script is designed to be run on Linux. Can't run on $(uname)" - exit 1 -fi - -if [[ "$1" == "--win64" ]]; then - arch="win64"; - toolchain_prefix="${TOOLCHAIN_PREFIX_64}" - binary="ffmpeg.exe" -elif [[ "$1" == "--linux-arm64" ]]; then - arch="linux-arm64"; - toolchain_prefix="${TOOLCHAIN_PREFIX_ARM64}" - binary="ffmpeg" -elif [[ -z "$1" ]]; then - die "ERROR: expect --win64 or --linux-arm64 as the first argument" -else - die "ERROR: unknown arch '$1' - expected --win64 or --linux-arm64" -fi - -output_path="$2" -if [[ -z "${output_path}" ]]; then - die "ERROR: output path is not specified" -elif [[ "${output_path}" != /* ]]; then - die "ERROR: output path ${output_path} is not absolute" -elif ! [[ -d $(dirname "${output_path}") ]]; then - die "ERROR: folder for output path ${output_path} does not exist." -fi - -function build_zlib { - cd "${HOME}" - git clone https://github.com/madler/zlib - cd zlib - git checkout "${ZLIB_VERSION}" - ./configure --prefix="${PREFIX}" ${ZLIB_CONFIG} - make \ - CC="${toolchain_prefix}gcc" \ - CXX="${toolchain_prefix}g++" \ - AR="${toolchain_prefix}ar" \ - PREFIX="$PREFIX" \ - RANLIB="${toolchain_prefix}ranlib" \ - LD="${toolchain_prefix}ld" \ - STRIP="${toolchain_prefix}strip" - make install -} - -function build_libvpx { - cd "${HOME}" - git clone https://chromium.googlesource.com/webm/libvpx - cd libvpx - git checkout "${LIBVPX_VERSION}" - # Cross-compiling libvpx according to the docs: - # - https://chromium.googlesource.com/webm/libvpx/+/main/README - local target="" - if [[ $arch == "win64" ]]; then - target="x86_64-win64-gcc"; - elif [[ $arch == "linux-arm64" ]]; then - target="arm64-linux-gcc"; - else - die "ERROR: unsupported arch to compile libvpx - $arch" - fi - CROSS="${toolchain_prefix}" ./configure --prefix="${PREFIX}" --target="${target}" ${LIBVPX_CONFIG} - CROSS="${toolchain_prefix}" make && make install -} - -function build_ffmpeg { - cd "${HOME}" - git clone git://source.ffmpeg.org/ffmpeg.git - cd ffmpeg - git checkout "${FFMPEG_VERSION}" - export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig" - # Prohibit pkg-config from using linux system installed libs. - export PKG_CONFIG_LIBDIR= - - local ffmpeg_arch="" - local ffmpeg_target_os="" - if [[ $arch == "win64" ]]; then - ffmpeg_arch="x86_64"; - ffmpeg_target_os="mingw32" - elif [[ $arch == "linux-arm64" ]]; then - ffmpeg_arch="arm64"; - ffmpeg_target_os="linux" - else - die "ERROR: unsupported arch to compile ffmpeg - $arch" - fi - ./configure --arch="${ffmpeg_arch}" \ - --target-os="${ffmpeg_target_os}" \ - --cross-prefix="${toolchain_prefix}" \ - --disable-doc \ - --pkg-config=pkg-config \ - --pkg-config-flags="--static" \ - --extra-cflags="-I/${PREFIX}/include" \ - --extra-ldflags="-L/${PREFIX}/lib -static" \ - --prefix="${PREFIX}" \ - --bindir="${PWD}/bin" \ - ${FFMPEG_CONFIG} - make && make install -} - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -source ./CONFIG.sh - -apt-get update -apt-get install -y git make yasm pkg-config -if [[ "${arch}" == "linux-arm64" ]]; then - apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -else - apt-get install -y mingw-w64 -fi - -build_zlib -build_libvpx -build_ffmpeg - -# put resulting executable where we were asked to -cp "${HOME}/ffmpeg/bin/${binary}" "${output_path}" -${toolchain_prefix}strip "${output_path}" diff --git a/browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 b/browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 deleted file mode 100644 index 58af0d3787..0000000000 --- a/browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/browser_patches/firefox-beta/.gitignore b/browser_patches/firefox-beta/.gitignore deleted file mode 100644 index 5e660dc18e..0000000000 --- a/browser_patches/firefox-beta/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/checkout diff --git a/browser_patches/firefox-beta/BUILD_NUMBER b/browser_patches/firefox-beta/BUILD_NUMBER deleted file mode 100644 index ec985803af..0000000000 --- a/browser_patches/firefox-beta/BUILD_NUMBER +++ /dev/null @@ -1,2 +0,0 @@ -1349 -Changed: lushnikov@chromium.org Thu 25 Aug 2022 08:30:01 AM PDT diff --git a/browser_patches/firefox-beta/EXPECTED_BUILDS b/browser_patches/firefox-beta/EXPECTED_BUILDS deleted file mode 100644 index 1ef87929ac..0000000000 --- a/browser_patches/firefox-beta/EXPECTED_BUILDS +++ /dev/null @@ -1,9 +0,0 @@ -firefox-beta-mac-11.zip -firefox-beta-mac-11-arm64.zip -firefox-beta-ubuntu-18.04.zip -firefox-beta-ubuntu-20.04.zip -firefox-beta-ubuntu-20.04-arm64.zip -firefox-beta-ubuntu-22.04.zip -firefox-beta-ubuntu-22.04-arm64.zip -firefox-beta-debian-11.zip -firefox-beta-win64.zip diff --git a/browser_patches/firefox-beta/UPSTREAM_CONFIG.sh b/browser_patches/firefox-beta/UPSTREAM_CONFIG.sh deleted file mode 100644 index cd18d7b449..0000000000 --- a/browser_patches/firefox-beta/UPSTREAM_CONFIG.sh +++ /dev/null @@ -1,3 +0,0 @@ -REMOTE_URL="https://github.com/mozilla/gecko-dev" -BASE_BRANCH="beta" -BASE_REVISION="ef2a450dd015d4e6e80469b21cab1dd1a52cfbac" diff --git a/browser_patches/firefox-beta/archive.sh b/browser_patches/firefox-beta/archive.sh deleted file mode 100755 index 99dd2c31cb..0000000000 --- a/browser_patches/firefox-beta/archive.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -e -set +x - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename "$0") [output-absolute-path]" - echo - echo "Generate distributable .zip archive from Firefox checkout folder that was previously built." - echo - exit 0 -fi - -ZIP_PATH=$1 -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname "$ZIP_PATH") ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FF_CHECKOUT_PATH="$HOME/firefox" -fi -OBJ_FOLDER="${FF_CHECKOUT_PATH}/obj-build-playwright" - -cd "${FF_CHECKOUT_PATH}" - -export MH_BRANCH=mozilla-beta -export MOZ_BUILD_DATE=$(date +%Y%m%d%H%M%S) -./mach package -node "${SCRIPT_FOLDER}/install-preferences.js" "${OBJ_FOLDER}/dist/firefox" - -if ! [[ -d "$OBJ_FOLDER/dist/firefox" ]]; then - echo "ERROR: cannot find $OBJ_FOLDER/dist/firefox folder in the firefox checkout. Did you build?" - exit 1; -fi - -if is_win; then - # Bundle vcruntime14_1.dll - see https://github.com/microsoft/playwright/issues/9974 - cd "$(printMSVCRedistDir)" - cp -t "${OBJ_FOLDER}/dist/firefox" vcruntime140_1.dll -fi - -# tar resulting directory and cleanup TMP. -cd "${OBJ_FOLDER}/dist" -zip -r "$ZIP_PATH" firefox diff --git a/browser_patches/firefox-beta/build.sh b/browser_patches/firefox-beta/build.sh deleted file mode 100755 index 860ceb68e8..0000000000 --- a/browser_patches/firefox-beta/build.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash -set -e -set +x - -RUST_VERSION="1.61.0" -CBINDGEN_VERSION="0.24.3" - -trap "cd $(pwd -P)" EXIT - -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -args=("$@") -IS_FULL="" -IS_JUGGLER="" -IS_DEBUG="" -for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --full) IS_FULL="1"; unset args[i]; ;; - --juggler) IS_JUGGLER="1"; unset args[i]; ;; - --debug) IS_DEBUG="1"; unset args[i]; ;; - esac -done - -if [[ -n "${IS_JUGGLER}" && -n "${IS_FULL}" ]]; then - echo "ERROR: either --full or --juggler is allowed" - exit 1 -fi - -echo "== BUILD CONFIGURATION ==" -if [[ -n "${IS_FULL}" ]]; then - echo "- build type: FULL" -elif [[ -n "${IS_JUGGLER}" ]]; then - echo "- build type: JUGGLER" -else - echo "- build type: INCREMENTAL" -fi - -if [[ -n "${IS_DEBUG}" ]]; then - echo "- debug: YES" -else - echo "- debug: NO" -fi - -echo "=========================" - -rm -rf .mozconfig - -if is_mac; then - selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" firefox) - echo "-- building on Mac" -elif is_linux; then - echo "-- building on Linux" -elif is_win; then - echo "ac_add_options --disable-update-agent" >> .mozconfig - echo "ac_add_options --disable-default-browser-agent" >> .mozconfig - echo "ac_add_options --disable-maintenance-service" >> .mozconfig - - echo "-- building win64 build on MINGW" - echo "ac_add_options --target=x86_64-pc-mingw32" >> .mozconfig - echo "ac_add_options --host=x86_64-pc-mingw32" >> .mozconfig - DLL_FILE=$("C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -find '**\Redist\MSVC\*\x64\**\vcruntime140.dll') - WIN32_REDIST_DIR=$(dirname "$DLL_FILE" | tail -n 1) - if ! [[ -d $WIN32_REDIST_DIR ]]; then - echo "ERROR: cannot find MS VS C++ redistributable $WIN32_REDIST_DIR" - exit 1; - fi -else - echo "ERROR: cannot upload on this platform!" 1>&2 - exit 1; -fi - -# There's no pre-built wasi sysroot on certain platforms. -echo "ac_add_options --without-wasm-sandboxed-libraries" >> .mozconfig - -OBJ_FOLDER="obj-build-playwright" -echo "mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/${OBJ_FOLDER}" >> .mozconfig -echo "ac_add_options --disable-crashreporter" >> .mozconfig -echo "ac_add_options --disable-backgroundtasks" >> .mozconfig - -if [[ -n "${IS_DEBUG}" ]]; then - echo "ac_add_options --enable-debug" >> .mozconfig - echo "ac_add_options --enable-debug-symbols" >> .mozconfig -else - echo "ac_add_options --enable-release" >> .mozconfig -fi - -if is_mac || is_win; then - # This options is only available on win and mac. - echo "ac_add_options --disable-update-agent" >> .mozconfig -fi - -if [[ -z "${IS_JUGGLER}" ]]; then - # TODO: rustup is not in the PATH on Windows - if command -v rustup >/dev/null; then - # We manage Rust version ourselves. - echo "-- Using rust v${RUST_VERSION}" - rustup install "${RUST_VERSION}" - rustup default "${RUST_VERSION}" - fi - # Firefox on Linux arm64 host does not ship - # cbindgen in their default toolchains - install manually. - if command -v cargo >/dev/null; then - echo "-- Using cbindgen v${CBINDGEN_VERSION}" - cargo install cbindgen --version "${CBINDGEN_VERSION}" - fi -fi - -if [[ -n "${IS_FULL}" ]]; then - # This is a slow but sure way to get all the necessary toolchains. - # However, it will not work if tree is dirty. - # Bail out if git repo is dirty. - if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: dirty GIT state - commit everything and re-run the script." - exit 1 - fi - - # 1. We have a --single-branch checkout, so we have to add a "master" branch and fetch it - git remote set-branches --add browser_upstream master - git fetch --depth 1 browser_upstream master - # 2. Checkout the master branch and run bootstrap from it. - git checkout browser_upstream/master - echo "ac_add_options --enable-bootstrap" >> .mozconfig - SHELL=/bin/sh ./mach --no-interactive bootstrap --application-choice=browser - git checkout - - rm -rf "${OBJ_FOLDER}" - - if [[ -n "${WIN32_REDIST_DIR}" ]]; then - # Having this option in .mozconfig kills incremental compilation. - echo "export WIN32_REDIST_DIR=\"$WIN32_REDIST_DIR\"" >> .mozconfig - fi -fi - -if [[ -n "${IS_JUGGLER}" ]]; then - ./mach build faster -else - ./mach build - if is_mac; then - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist - else - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist/bin - fi -fi - - diff --git a/browser_patches/firefox-beta/clean.sh b/browser_patches/firefox-beta/clean.sh deleted file mode 100755 index d94baf33a3..0000000000 --- a/browser_patches/firefox-beta/clean.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -OBJ_FOLDER="obj-build-playwright" -if [[ -d $OBJ_FOLDER ]]; then - rm -rf $OBJ_FOLDER -fi - -if [[ -f "mach" ]]; then - ./mach clobber || true -fi diff --git a/browser_patches/firefox-beta/install-preferences.js b/browser_patches/firefox-beta/install-preferences.js deleted file mode 100644 index f82f791d54..0000000000 --- a/browser_patches/firefox-beta/install-preferences.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright 2018 Google Inc. All rights reserved. - * Modifications copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const util = require('util'); - -const writeFileAsync = util.promisify(fs.writeFile.bind(fs)); -const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); - -// Install browser preferences after downloading and unpacking -// firefox instances. -// Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration -async function installFirefoxPreferences(distpath) { - let executablePath = ''; - if (os.platform() === 'linux') - executablePath = path.join(distpath, 'firefox'); - else if (os.platform() === 'darwin') - executablePath = path.join(distpath, (process.env.FF_DEBUG_BUILD ? 'NightlyDebug.app' : 'Nightly.app'), 'Contents', 'MacOS', 'firefox'); - else if (os.platform() === 'win32') - executablePath = path.join(distpath, 'firefox.exe'); - - const firefoxFolder = path.dirname(executablePath); - - let prefPath = ''; - let configPath = ''; - if (os.platform() === 'darwin') { - prefPath = path.join(firefoxFolder, '..', 'Resources', 'defaults', 'pref'); - configPath = path.join(firefoxFolder, '..', 'Resources'); - } else if (os.platform() === 'linux') { - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults')); - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences')); - prefPath = path.join(firefoxFolder, 'browser', 'defaults', 'preferences'); - configPath = firefoxFolder; - } else if (os.platform() === 'win32') { - prefPath = path.join(firefoxFolder, 'defaults', 'pref'); - configPath = firefoxFolder; - } else { - throw new Error('Unsupported platform: ' + os.platform()); - } - - await Promise.all([ - copyFile({ - from: path.join(__dirname, 'preferences', '00-playwright-prefs.js'), - to: path.join(prefPath, '00-playwright-prefs.js'), - }), - copyFile({ - from: path.join(__dirname, 'preferences', 'playwright.cfg'), - to: path.join(configPath, 'playwright.cfg'), - }), - ]); -} - -function copyFile({from, to}) { - const rd = fs.createReadStream(from); - const wr = fs.createWriteStream(to); - return new Promise(function(resolve, reject) { - rd.on('error', reject); - wr.on('error', reject); - wr.on('finish', resolve); - rd.pipe(wr); - }).catch(function(error) { - rd.destroy(); - wr.end(); - throw error; - }); -} - -module.exports = { installFirefoxPreferences }; - -if (require.main === module) { - if (process.argv.length !== 3) { - console.log('ERROR: expected a path to the directory with browser build'); - process.exit(1); - return; - } - - installFirefoxPreferences(process.argv[2]).catch(error => { - console.error('ERROR: failed to put preferences!'); - console.error(error); - process.exit(1); - }); -} diff --git a/browser_patches/firefox-beta/juggler/Helper.js b/browser_patches/firefox-beta/juggler/Helper.js deleted file mode 100644 index 70d8aef0d3..0000000000 --- a/browser_patches/firefox-beta/juggler/Helper.js +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -class Helper { - - addObserver(handler, topic) { - Services.obs.addObserver(handler, topic); - return () => Services.obs.removeObserver(handler, topic); - } - - addMessageListener(receiver, eventName, handler) { - receiver.addMessageListener(eventName, handler); - return () => receiver.removeMessageListener(eventName, handler); - } - - addEventListener(receiver, eventName, handler) { - receiver.addEventListener(eventName, handler); - return () => receiver.removeEventListener(eventName, handler); - } - - awaitEvent(receiver, eventName) { - return new Promise(resolve => { - receiver.addEventListener(eventName, function listener() { - receiver.removeEventListener(eventName, listener); - resolve(); - }); - }); - } - - on(receiver, eventName, handler) { - // The toolkit/modules/EventEmitter.jsm dispatches event name as a first argument. - // Fire event listeners without it for convenience. - const handlerWrapper = (_, ...args) => handler(...args); - receiver.on(eventName, handlerWrapper); - return () => receiver.off(eventName, handlerWrapper); - } - - addProgressListener(progress, listener, flags) { - progress.addProgressListener(listener, flags); - return () => progress.removeProgressListener(listener); - } - - removeListeners(listeners) { - for (const tearDown of listeners) - tearDown.call(null); - listeners.splice(0, listeners.length); - } - - generateId() { - const string = uuidGen.generateUUID().toString(); - return string.substring(1, string.length - 1); - } - - getLoadContext(channel) { - let loadContext = null; - try { - if (channel.notificationCallbacks) - loadContext = channel.notificationCallbacks.getInterface(Ci.nsILoadContext); - } catch (e) {} - try { - if (!loadContext && channel.loadGroup) - loadContext = channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext); - } catch (e) { } - return loadContext; - } - - getNetworkErrorStatusText(status) { - if (!status) - return null; - for (const key of Object.keys(Cr)) { - if (Cr[key] === status) - return key; - } - // Security module. The following is taken from - // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL - if ((status & 0xff0000) === 0x5a0000) { - // NSS_SEC errors (happen below the base value because of negative vals) - if ((status & 0xffff) < Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)) { - // The bases are actually negative, so in our positive numeric space, we - // need to subtract the base off our value. - const nssErr = Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff); - switch (nssErr) { - case 11: - return 'SEC_ERROR_EXPIRED_CERTIFICATE'; - case 12: - return 'SEC_ERROR_REVOKED_CERTIFICATE'; - case 13: - return 'SEC_ERROR_UNKNOWN_ISSUER'; - case 20: - return 'SEC_ERROR_UNTRUSTED_ISSUER'; - case 21: - return 'SEC_ERROR_UNTRUSTED_CERT'; - case 36: - return 'SEC_ERROR_CA_CERT_INVALID'; - case 90: - return 'SEC_ERROR_INADEQUATE_KEY_USAGE'; - case 176: - return 'SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED'; - default: - return 'SEC_ERROR_UNKNOWN'; - } - } - const sslErr = Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff); - switch (sslErr) { - case 3: - return 'SSL_ERROR_NO_CERTIFICATE'; - case 4: - return 'SSL_ERROR_BAD_CERTIFICATE'; - case 8: - return 'SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE'; - case 9: - return 'SSL_ERROR_UNSUPPORTED_VERSION'; - case 12: - return 'SSL_ERROR_BAD_CERT_DOMAIN'; - default: - return 'SSL_ERROR_UNKNOWN'; - } - } - return ''; - } - - browsingContextToFrameId(browsingContext) { - if (!browsingContext) - return undefined; - return 'frame-' + browsingContext.id; - } -} - -var EXPORTED_SYMBOLS = [ "Helper" ]; -this.Helper = Helper; - diff --git a/browser_patches/firefox-beta/juggler/NetworkObserver.js b/browser_patches/firefox-beta/juggler/NetworkObserver.js deleted file mode 100644 index f197959497..0000000000 --- a/browser_patches/firefox-beta/juggler/NetworkObserver.js +++ /dev/null @@ -1,958 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -const { ChannelEventSinkFactory } = ChromeUtils.import("chrome://remote/content/cdp/observers/ChannelEventSink.jsm"); - - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; -const Cm = Components.manager; -const CC = Components.Constructor; -const helper = new Helper(); - -const UINT32_MAX = Math.pow(2, 32)-1; - -const BinaryInputStream = CC('@mozilla.org/binaryinputstream;1', 'nsIBinaryInputStream', 'setInputStream'); -const BinaryOutputStream = CC('@mozilla.org/binaryoutputstream;1', 'nsIBinaryOutputStream', 'setOutputStream'); -const StorageStream = CC('@mozilla.org/storagestream;1', 'nsIStorageStream', 'init'); - -// Cap response storage with 100Mb per tracked tab. -const MAX_RESPONSE_STORAGE_SIZE = 100 * 1024 * 1024; - -const pageNetworkSymbol = Symbol('PageNetwork'); - -class PageNetwork { - static forPageTarget(target) { - let result = target[pageNetworkSymbol]; - if (!result) { - result = new PageNetwork(target); - target[pageNetworkSymbol] = result; - } - return result; - } - - constructor(target) { - EventEmitter.decorate(this); - this._target = target; - this._extraHTTPHeaders = null; - this._responseStorage = new ResponseStorage(MAX_RESPONSE_STORAGE_SIZE, MAX_RESPONSE_STORAGE_SIZE / 10); - this._requestInterceptionEnabled = false; - // This is requestId => NetworkRequest map, only contains requests that are - // awaiting interception action (abort, resume, fulfill) over the protocol. - this._interceptedRequests = new Map(); - } - - setExtraHTTPHeaders(headers) { - this._extraHTTPHeaders = headers; - } - - combinedExtraHTTPHeaders() { - return [ - ...(this._target.browserContext().extraHTTPHeaders || []), - ...(this._extraHTTPHeaders || []), - ]; - } - - enableRequestInterception() { - this._requestInterceptionEnabled = true; - } - - disableRequestInterception() { - this._requestInterceptionEnabled = false; - for (const intercepted of this._interceptedRequests.values()) - intercepted.resume(); - this._interceptedRequests.clear(); - } - - resumeInterceptedRequest(requestId, url, method, headers, postData) { - this._takeIntercepted(requestId).resume(url, method, headers, postData); - } - - fulfillInterceptedRequest(requestId, status, statusText, headers, base64body) { - this._takeIntercepted(requestId).fulfill(status, statusText, headers, base64body); - } - - abortInterceptedRequest(requestId, errorCode) { - this._takeIntercepted(requestId).abort(errorCode); - } - - getResponseBody(requestId) { - if (!this._responseStorage) - throw new Error('Responses are not tracked for the given browser'); - return this._responseStorage.getBase64EncodedResponse(requestId); - } - - _takeIntercepted(requestId) { - const intercepted = this._interceptedRequests.get(requestId); - if (!intercepted) - throw new Error(`Cannot find request "${requestId}"`); - this._interceptedRequests.delete(requestId); - return intercepted; - } -} - -class NetworkRequest { - constructor(networkObserver, httpChannel, redirectedFrom) { - this._networkObserver = networkObserver; - this.httpChannel = httpChannel; - - const loadInfo = this.httpChannel.loadInfo; - let browsingContext = loadInfo?.frameBrowsingContext || loadInfo?.browsingContext; - // TODO: Unfortunately, requests from web workers don't have frameBrowsingContext or - // browsingContext. - // - // We fail to attribute them to the original frames on the browser side, but we - // can use load context top frame to attribute them to the top frame at least. - if (!browsingContext) { - const loadContext = helper.getLoadContext(this.httpChannel); - browsingContext = loadContext?.topFrameElement?.browsingContext; - } - - this._frameId = helper.browsingContextToFrameId(browsingContext); - - this.requestId = httpChannel.channelId + ''; - this.navigationId = httpChannel.isMainDocumentChannel ? this.requestId : undefined; - - this._redirectedIndex = 0; - if (redirectedFrom) { - this.redirectedFromId = redirectedFrom.requestId; - this._redirectedIndex = redirectedFrom._redirectedIndex + 1; - this.requestId = this.requestId + '-redirect' + this._redirectedIndex; - this.navigationId = redirectedFrom.navigationId; - // Finish previous request now. Since we inherit the listener, we could in theory - // use onStopRequest, but that will only happen after the last redirect has finished. - redirectedFrom._sendOnRequestFinished(); - } - // In case of proxy auth, we get two requests with the same channel: - // - one is pre-auth - // - second is with auth header. - // - // In this case, we create this NetworkRequest object with a `redirectedFrom` - // object, and they both share the same httpChannel. - // - // Since we want to maintain _channelToRequest map without clashes, - // we must call `_sendOnRequestFinished` **before** we update it with a new object - // here. - if (this._networkObserver._channelToRequest.has(this.httpChannel)) - throw new Error(`Internal Error: invariant is broken for _channelToRequest map`); - this._networkObserver._channelToRequest.set(this.httpChannel, this); - - this._pageNetwork = redirectedFrom ? redirectedFrom._pageNetwork : networkObserver._findPageNetwork(httpChannel); - this._expectingInterception = false; - this._expectingResumedRequest = undefined; // { method, headers, postData } - this._sentOnResponse = false; - - if (this._pageNetwork) - appendExtraHTTPHeaders(httpChannel, this._pageNetwork.combinedExtraHTTPHeaders()); - - this._responseBodyChunks = []; - - httpChannel.QueryInterface(Ci.nsITraceableChannel); - this._originalListener = httpChannel.setNewListener(this); - if (redirectedFrom) { - // Listener is inherited for regular redirects, so we'd like to avoid - // calling into previous NetworkRequest. - this._originalListener = redirectedFrom._originalListener; - } - - this._previousCallbacks = httpChannel.notificationCallbacks; - httpChannel.notificationCallbacks = this; - - this.QueryInterface = ChromeUtils.generateQI([ - Ci.nsIAuthPrompt2, - Ci.nsIAuthPromptProvider, - Ci.nsIInterfaceRequestor, - Ci.nsINetworkInterceptController, - Ci.nsIStreamListener, - ]); - - if (this.redirectedFromId) { - // Redirects are not interceptable. - this._sendOnRequest(false); - } - } - - // Public interception API. - resume(url, method, headers, postData) { - this._expectingResumedRequest = { method, headers, postData }; - const newUri = url ? Services.io.newURI(url) : null; - this._interceptedChannel.resetInterceptionWithURI(newUri); - this._interceptedChannel = undefined; - } - - // Public interception API. - abort(errorCode) { - const error = errorMap[errorCode] || Cr.NS_ERROR_FAILURE; - this._interceptedChannel.cancelInterception(error); - this._interceptedChannel = undefined; - } - - // Public interception API. - fulfill(status, statusText, headers, base64body) { - this._interceptedChannel.synthesizeStatus(status, statusText); - for (const header of headers) { - this._interceptedChannel.synthesizeHeader(header.name, header.value); - if (header.name.toLowerCase() === 'set-cookie') { - Services.cookies.QueryInterface(Ci.nsICookieService); - Services.cookies.setCookieStringFromHttp(this.httpChannel.URI, header.value, this.httpChannel); - } - } - const synthesized = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); - synthesized.data = base64body ? atob(base64body) : ''; - this._interceptedChannel.startSynthesizedResponse(synthesized, null, null, '', false); - this._interceptedChannel.finishSynthesizedResponse(); - this._interceptedChannel = undefined; - } - - // Instrumentation called by NetworkObserver. - _onInternalRedirect(newChannel) { - // Intercepted requests produce "internal redirects" - this is both for our own - // interception and service workers. - // An internal redirect has the same channelId, inherits notificationCallbacks and - // listener, and should be used instead of an old channel. - this._networkObserver._channelToRequest.delete(this.httpChannel); - this.httpChannel = newChannel; - this._networkObserver._channelToRequest.set(this.httpChannel, this); - } - - // Instrumentation called by NetworkObserver. - _onInternalRedirectReady() { - // Resumed request is first internally redirected to a new request, - // and then the new request is ready to be updated. - if (!this._expectingResumedRequest) - return; - const { method, headers, postData } = this._expectingResumedRequest; - this._expectingResumedRequest = undefined; - - if (headers) { - for (const header of requestHeaders(this.httpChannel)) - this.httpChannel.setRequestHeader(header.name, '', false /* merge */); - for (const header of headers) - this.httpChannel.setRequestHeader(header.name, header.value, false /* merge */); - } else if (this._pageNetwork) { - appendExtraHTTPHeaders(this.httpChannel, this._pageNetwork.combinedExtraHTTPHeaders()); - } - if (method) - this.httpChannel.requestMethod = method; - if (postData !== undefined) - setPostData(this.httpChannel, postData, headers); - } - - // nsIInterfaceRequestor - getInterface(iid) { - if (iid.equals(Ci.nsIAuthPrompt2) || iid.equals(Ci.nsIAuthPromptProvider) || iid.equals(Ci.nsINetworkInterceptController)) - return this; - if (iid.equals(Ci.nsIAuthPrompt)) // Block nsIAuthPrompt - we want nsIAuthPrompt2 to be used instead. - throw Cr.NS_ERROR_NO_INTERFACE; - if (this._previousCallbacks) - return this._previousCallbacks.getInterface(iid); - throw Cr.NS_ERROR_NO_INTERFACE; - } - - // nsIAuthPromptProvider - getAuthPrompt(aPromptReason, iid) { - return this; - } - - // nsIAuthPrompt2 - asyncPromptAuth(aChannel, aCallback, aContext, level, authInfo) { - let canceled = false; - Promise.resolve().then(() => { - if (canceled) - return; - const hasAuth = this.promptAuth(aChannel, level, authInfo); - if (hasAuth) - aCallback.onAuthAvailable(aContext, authInfo); - else - aCallback.onAuthCancelled(aContext, true); - }); - return { - QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]), - cancel: () => { - aCallback.onAuthCancelled(aContext, false); - canceled = true; - } - }; - } - - // nsIAuthPrompt2 - promptAuth(aChannel, level, authInfo) { - if (authInfo.flags & Ci.nsIAuthInformation.PREVIOUS_FAILED) - return false; - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return false; - let credentials = null; - if (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) { - const proxy = this._networkObserver._targetRegistry.getProxyInfo(aChannel); - credentials = proxy ? {username: proxy.username, password: proxy.password} : null; - } else { - credentials = pageNetwork._target.browserContext().httpCredentials; - } - if (!credentials) - return false; - authInfo.username = credentials.username; - authInfo.password = credentials.password; - // This will produce a new request with respective auth header set. - // It will have the same id as ours. We expect it to arrive as new request and - // will treat it as our own redirect. - this._networkObserver._expectRedirect(this.httpChannel.channelId + '', this); - return true; - } - - // nsINetworkInterceptController - shouldPrepareForIntercept(aURI, channel) { - const interceptController = this._fallThroughInterceptController(); - if (interceptController && interceptController.shouldPrepareForIntercept(aURI, channel)) { - // We assume that interceptController is a service worker if there is one, - // and yield interception to it. We are not going to intercept ourselves, - // so we send onRequest now. - this._sendOnRequest(false); - return true; - } - - if (channel !== this.httpChannel) { - // Not our channel? Just in case this happens, don't do anything. - return false; - } - - // We do not want to intercept any redirects, because we are not able - // to intercept subresource redirects, and it's unreliable for main requests. - // We do not sendOnRequest here, because redirects do that in constructor. - if (this.redirectedFromId) - return false; - - const shouldIntercept = this._shouldIntercept(); - if (!shouldIntercept) { - // We are not intercepting - ready to issue onRequest. - this._sendOnRequest(false); - return false; - } - - this._expectingInterception = true; - return true; - } - - // nsINetworkInterceptController - channelIntercepted(intercepted) { - if (!this._expectingInterception) { - // We are not intercepting, fall-through. - const interceptController = this._fallThroughInterceptController(); - if (interceptController) - interceptController.channelIntercepted(intercepted); - return; - } - - this._expectingInterception = false; - this._interceptedChannel = intercepted.QueryInterface(Ci.nsIInterceptedChannel); - - const pageNetwork = this._pageNetwork; - if (!pageNetwork) { - // Just in case we disabled instrumentation while intercepting, resume and forget. - this.resume(); - return; - } - - const browserContext = pageNetwork._target.browserContext(); - if (browserContext.settings.onlineOverride === 'offline') { - // Implement offline. - this.abort(Cr.NS_ERROR_OFFLINE); - return; - } - - // Ok, so now we have intercepted the request, let's issue onRequest. - // If interception has been disabled while we were intercepting, resume and forget. - const interceptionEnabled = this._shouldIntercept(); - this._sendOnRequest(!!interceptionEnabled); - if (interceptionEnabled) - pageNetwork._interceptedRequests.set(this.requestId, this); - else - this.resume(); - } - - // nsIStreamListener - onDataAvailable(aRequest, aInputStream, aOffset, aCount) { - // Turns out webcompat shims might redirect to - // SimpleChannel, so we get requests from a different channel. - // See https://github.com/microsoft/playwright/issues/9418#issuecomment-944836244 - if (aRequest !== this.httpChannel) - return; - // For requests with internal redirect (e.g. intercepted by Service Worker), - // we do not get onResponse normally, but we do get nsIStreamListener notifications. - this._sendOnResponse(false); - - const iStream = new BinaryInputStream(aInputStream); - const sStream = new StorageStream(8192, aCount, null); - const oStream = new BinaryOutputStream(sStream.getOutputStream(0)); - - // Copy received data as they come. - const data = iStream.readBytes(aCount); - this._responseBodyChunks.push(data); - - oStream.writeBytes(data, aCount); - try { - this._originalListener.onDataAvailable(aRequest, sStream.newInputStream(0), aOffset, aCount); - } catch (e) { - // Be ready to original listener exceptions. - } - } - - // nsIStreamListener - onStartRequest(aRequest) { - // Turns out webcompat shims might redirect to - // SimpleChannel, so we get requests from a different channel. - // See https://github.com/microsoft/playwright/issues/9418#issuecomment-944836244 - if (aRequest !== this.httpChannel) - return; - try { - this._originalListener.onStartRequest(aRequest); - } catch (e) { - // Be ready to original listener exceptions. - } - } - - // nsIStreamListener - onStopRequest(aRequest, aStatusCode) { - // Turns out webcompat shims might redirect to - // SimpleChannel, so we get requests from a different channel. - // See https://github.com/microsoft/playwright/issues/9418#issuecomment-944836244 - if (aRequest !== this.httpChannel) - return; - try { - this._originalListener.onStopRequest(aRequest, aStatusCode); - } catch (e) { - // Be ready to original listener exceptions. - } - - if (aStatusCode === 0) { - // For requests with internal redirect (e.g. intercepted by Service Worker), - // we do not get onResponse normally, but we do get nsIRequestObserver notifications. - this._sendOnResponse(false); - const body = this._responseBodyChunks.join(''); - const pageNetwork = this._pageNetwork; - if (pageNetwork) - pageNetwork._responseStorage.addResponseBody(this, body); - this._sendOnRequestFinished(); - } else { - this._sendOnRequestFailed(aStatusCode); - } - - delete this._responseBodyChunks; - } - - _shouldIntercept() { - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return false; - if (pageNetwork._requestInterceptionEnabled) - return true; - const browserContext = pageNetwork._target.browserContext(); - if (browserContext.requestInterceptionEnabled) - return true; - if (browserContext.settings.onlineOverride === 'offline') - return true; - return false; - } - - _fallThroughInterceptController() { - if (!this._previousCallbacks || !(this._previousCallbacks instanceof Ci.nsINetworkInterceptController)) - return undefined; - return this._previousCallbacks.getInterface(Ci.nsINetworkInterceptController); - } - - _sendOnRequest(isIntercepted) { - // Note: we call _sendOnRequest either after we intercepted the request, - // or at the first moment we know that we are not going to intercept. - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return; - const loadInfo = this.httpChannel.loadInfo; - const causeType = loadInfo?.externalContentPolicyType || Ci.nsIContentPolicy.TYPE_OTHER; - const internalCauseType = loadInfo?.internalContentPolicyType || Ci.nsIContentPolicy.TYPE_OTHER; - pageNetwork.emit(PageNetwork.Events.Request, { - url: this.httpChannel.URI.spec, - frameId: this._frameId, - isIntercepted, - requestId: this.requestId, - redirectedFrom: this.redirectedFromId, - postData: readRequestPostData(this.httpChannel), - headers: requestHeaders(this.httpChannel), - method: this.httpChannel.requestMethod, - navigationId: this.navigationId, - cause: causeTypeToString(causeType), - internalCause: causeTypeToString(internalCauseType), - }, this._frameId); - } - - _sendOnResponse(fromCache, opt_statusCode, opt_statusText) { - if (this._sentOnResponse) { - // We can come here twice because of internal redirects, e.g. service workers. - return; - } - this._sentOnResponse = true; - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return; - - this.httpChannel.QueryInterface(Ci.nsIHttpChannelInternal); - this.httpChannel.QueryInterface(Ci.nsITimedChannel); - const timing = { - startTime: this.httpChannel.channelCreationTime, - domainLookupStart: this.httpChannel.domainLookupStartTime, - domainLookupEnd: this.httpChannel.domainLookupEndTime, - connectStart: this.httpChannel.connectStartTime, - secureConnectionStart: this.httpChannel.secureConnectionStartTime, - connectEnd: this.httpChannel.connectEndTime, - requestStart: this.httpChannel.requestStartTime, - responseStart: this.httpChannel.responseStartTime, - }; - - const { status, statusText, headers } = responseHead(this.httpChannel, opt_statusCode, opt_statusText); - let remoteIPAddress = undefined; - let remotePort = undefined; - try { - remoteIPAddress = this.httpChannel.remoteAddress; - remotePort = this.httpChannel.remotePort; - } catch (e) { - // remoteAddress is not defined for cached requests. - } - - const fromServiceWorker = this._networkObserver._channelIdsFulfilledByServiceWorker.has(this.requestId); - this._networkObserver._channelIdsFulfilledByServiceWorker.delete(this.requestId); - - pageNetwork.emit(PageNetwork.Events.Response, { - requestId: this.requestId, - securityDetails: getSecurityDetails(this.httpChannel), - fromCache, - headers, - remoteIPAddress, - remotePort, - status, - statusText, - timing, - fromServiceWorker, - }, this._frameId); - } - - _sendOnRequestFailed(error) { - const pageNetwork = this._pageNetwork; - if (pageNetwork) { - pageNetwork.emit(PageNetwork.Events.RequestFailed, { - requestId: this.requestId, - errorCode: helper.getNetworkErrorStatusText(error), - }, this._frameId); - } - this._networkObserver._channelToRequest.delete(this.httpChannel); - } - - _sendOnRequestFinished() { - const pageNetwork = this._pageNetwork; - if (pageNetwork) { - let protocolVersion = undefined; - try { - protocolVersion = this.httpChannel.protocolVersion; - } catch (e) { - // protocolVersion is unavailable in certain cases. - }; - pageNetwork.emit(PageNetwork.Events.RequestFinished, { - requestId: this.requestId, - responseEndTime: this.httpChannel.responseEndTime, - transferSize: this.httpChannel.transferSize, - encodedBodySize: this.httpChannel.encodedBodySize, - protocolVersion, - }, this._frameId); - } - this._networkObserver._channelToRequest.delete(this.httpChannel); - } -} - -class NetworkObserver { - static instance() { - return NetworkObserver._instance || null; - } - - constructor(targetRegistry) { - EventEmitter.decorate(this); - NetworkObserver._instance = this; - - this._targetRegistry = targetRegistry; - - this._channelToRequest = new Map(); // http channel -> network request - this._expectedRedirect = new Map(); // expected redirect channel id (string) -> network request - this._channelIdsFulfilledByServiceWorker = new Set(); // http channel ids that were fulfilled by service worker - - const protocolProxyService = Cc['@mozilla.org/network/protocol-proxy-service;1'].getService(); - this._channelProxyFilter = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIProtocolProxyChannelFilter]), - applyFilter: (channel, defaultProxyInfo, proxyFilter) => { - const proxy = this._targetRegistry.getProxyInfo(channel); - if (!proxy) { - proxyFilter.onProxyFilterResult(defaultProxyInfo); - return; - } - proxyFilter.onProxyFilterResult(protocolProxyService.newProxyInfo( - proxy.type, - proxy.host, - proxy.port, - '', /* aProxyAuthorizationHeader */ - '', /* aConnectionIsolationKey */ - Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST, /* aFlags */ - UINT32_MAX, /* aFailoverTimeout */ - null, /* failover proxy */ - )); - }, - }; - protocolProxyService.registerChannelFilter(this._channelProxyFilter, 0 /* position */); - - // Register self as ChannelEventSink to track redirects. - ChannelEventSinkFactory.getService().registerCollector({ - _onChannelRedirect: this._onRedirect.bind(this), - }); - - this._eventListeners = [ - helper.addObserver(this._onRequest.bind(this), 'http-on-modify-request'), - helper.addObserver(this._onResponse.bind(this, false /* fromCache */), 'http-on-examine-response'), - helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-cached-response'), - helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-merged-response'), - helper.addObserver(this._onServiceWorkerResponse.bind(this), 'service-worker-synthesized-response'), - ]; - } - - _expectRedirect(channelId, previous) { - this._expectedRedirect.set(channelId, previous); - } - - _onRedirect(oldChannel, newChannel, flags) { - if (!(oldChannel instanceof Ci.nsIHttpChannel) || !(newChannel instanceof Ci.nsIHttpChannel)) - return; - const oldHttpChannel = oldChannel.QueryInterface(Ci.nsIHttpChannel); - const newHttpChannel = newChannel.QueryInterface(Ci.nsIHttpChannel); - const request = this._channelToRequest.get(oldHttpChannel); - if (flags & Ci.nsIChannelEventSink.REDIRECT_INTERNAL) { - if (request) - request._onInternalRedirect(newHttpChannel); - } else if (flags & Ci.nsIChannelEventSink.REDIRECT_STS_UPGRADE) { - if (request) { - // This is an internal HSTS upgrade. The original http request is canceled, and a new - // equivalent https request is sent. We forge 307 redirect to follow Chromium here: - // https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_http_job.cc;l=211 - request._sendOnResponse(false, 307, 'Temporary Redirect'); - this._expectRedirect(newHttpChannel.channelId + '', request); - } - } else { - if (request) - this._expectRedirect(newHttpChannel.channelId + '', request); - } - } - - _findPageNetwork(httpChannel) { - let loadContext = helper.getLoadContext(httpChannel); - if (!loadContext) - return; - const target = this._targetRegistry.targetForBrowser(loadContext.topFrameElement); - if (!target) - return; - return PageNetwork.forPageTarget(target); - } - - _onRequest(channel, topic) { - if (!(channel instanceof Ci.nsIHttpChannel)) - return; - const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); - const channelId = httpChannel.channelId + ''; - const redirectedFrom = this._expectedRedirect.get(channelId); - if (redirectedFrom) { - this._expectedRedirect.delete(channelId); - new NetworkRequest(this, httpChannel, redirectedFrom); - } else { - const redirectedRequest = this._channelToRequest.get(httpChannel); - if (redirectedRequest) - redirectedRequest._onInternalRedirectReady(); - else - new NetworkRequest(this, httpChannel); - } - } - - _onResponse(fromCache, httpChannel, topic) { - const request = this._channelToRequest.get(httpChannel); - if (request) - request._sendOnResponse(fromCache); - } - - _onServiceWorkerResponse(channel, topic) { - if (!(channel instanceof Ci.nsIHttpChannel)) - return; - const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); - const channelId = httpChannel.channelId + ''; - this._channelIdsFulfilledByServiceWorker.add(channelId); - } - - dispose() { - this._activityDistributor.removeObserver(this); - ChannelEventSinkFactory.unregister(); - helper.removeListeners(this._eventListeners); - } -} - -const protocolVersionNames = { - [Ci.nsITransportSecurityInfo.TLS_VERSION_1]: 'TLS 1', - [Ci.nsITransportSecurityInfo.TLS_VERSION_1_1]: 'TLS 1.1', - [Ci.nsITransportSecurityInfo.TLS_VERSION_1_2]: 'TLS 1.2', - [Ci.nsITransportSecurityInfo.TLS_VERSION_1_3]: 'TLS 1.3', -}; - -function getSecurityDetails(httpChannel) { - const securityInfo = httpChannel.securityInfo; - if (!securityInfo) - return null; - securityInfo.QueryInterface(Ci.nsITransportSecurityInfo); - if (!securityInfo.serverCert) - return null; - return { - protocol: protocolVersionNames[securityInfo.protocolVersion] || '', - subjectName: securityInfo.serverCert.commonName, - issuer: securityInfo.serverCert.issuerCommonName, - // Convert to seconds. - validFrom: securityInfo.serverCert.validity.notBefore / 1000 / 1000, - validTo: securityInfo.serverCert.validity.notAfter / 1000 / 1000, - }; -} - -function readRequestPostData(httpChannel) { - if (!(httpChannel instanceof Ci.nsIUploadChannel)) - return undefined; - let iStream = httpChannel.uploadStream; - if (!iStream) - return undefined; - const isSeekableStream = iStream instanceof Ci.nsISeekableStream; - - // For some reason, we cannot rewind back big streams, - // so instead we should clone them. - const isCloneable = iStream instanceof Ci.nsICloneableInputStream; - if (isCloneable) - iStream = iStream.clone(); - - let prevOffset; - if (isSeekableStream) { - prevOffset = iStream.tell(); - iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); - } - - // Read data from the stream. - let result = undefined; - try { - const maxLen = iStream.available(); - // Cap at 10Mb. - if (maxLen <= 10 * 1024 * 1024) { - const buffer = NetUtil.readInputStreamToString(iStream, maxLen); - result = btoa(buffer); - } - } catch (err) { - } - - // Seek locks the file, so seek to the beginning only if necko hasn't - // read it yet, since necko doesn't seek to 0 before reading (at lest - // not till 459384 is fixed). - if (isSeekableStream && prevOffset == 0 && !isCloneable) - iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); - return result; -} - -function requestHeaders(httpChannel) { - const headers = []; - httpChannel.visitRequestHeaders({ - visitHeader: (name, value) => headers.push({name, value}), - }); - return headers; -} - -function causeTypeToString(causeType) { - for (let key in Ci.nsIContentPolicy) { - if (Ci.nsIContentPolicy[key] === causeType) - return key; - } - return 'TYPE_OTHER'; -} - -function appendExtraHTTPHeaders(httpChannel, headers) { - if (!headers) - return; - for (const header of headers) - httpChannel.setRequestHeader(header.name, header.value, false /* merge */); -} - -class ResponseStorage { - constructor(maxTotalSize, maxResponseSize) { - this._totalSize = 0; - this._maxResponseSize = maxResponseSize; - this._maxTotalSize = maxTotalSize; - this._responses = new Map(); - } - - addResponseBody(request, body) { - if (body.length > this._maxResponseSize) { - this._responses.set(request.requestId, { - evicted: true, - body: '', - }); - return; - } - let encodings = []; - if ((request.httpChannel instanceof Ci.nsIEncodedChannel) && request.httpChannel.contentEncodings && !request.httpChannel.applyConversion) { - const encodingHeader = request.httpChannel.getResponseHeader("Content-Encoding"); - encodings = encodingHeader.split(/\s*\t*,\s*\t*/); - } - this._responses.set(request.requestId, {body, encodings}); - this._totalSize += body.length; - if (this._totalSize > this._maxTotalSize) { - for (let [requestId, response] of this._responses) { - this._totalSize -= response.body.length; - response.body = ''; - response.evicted = true; - if (this._totalSize < this._maxTotalSize) - break; - } - } - } - - getBase64EncodedResponse(requestId) { - const response = this._responses.get(requestId); - if (!response) - throw new Error(`Request "${requestId}" is not found`); - if (response.evicted) - return {base64body: '', evicted: true}; - let result = response.body; - if (response.encodings && response.encodings.length) { - for (const encoding of response.encodings) - result = convertString(result, encoding, 'uncompressed'); - } - return {base64body: btoa(result)}; - } -} - -function responseHead(httpChannel, opt_statusCode, opt_statusText) { - const headers = []; - let status = opt_statusCode || 0; - let statusText = opt_statusText || ''; - try { - status = httpChannel.responseStatus; - statusText = httpChannel.responseStatusText; - httpChannel.visitResponseHeaders({ - visitHeader: (name, value) => headers.push({name, value}), - }); - } catch (e) { - // Response headers, status and/or statusText are not available - // when redirect did not actually hit the network. - } - return { status, statusText, headers }; -} - -function setPostData(httpChannel, postData, headers) { - if (!(httpChannel instanceof Ci.nsIUploadChannel2)) - return; - const synthesized = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); - const body = atob(postData); - synthesized.setData(body, body.length); - - const overriddenHeader = (lowerCaseName) => { - if (headers) { - for (const header of headers) { - if (header.name.toLowerCase() === lowerCaseName) { - return header.value; - } - } - } - return undefined; - } - // Clear content-length, so that upload stream resets it. - httpChannel.setRequestHeader('content-length', '', false /* merge */); - let contentType = overriddenHeader('content-type'); - if (contentType === undefined) { - try { - contentType = httpChannel.getRequestHeader('content-type'); - } catch (e) { - if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) - contentType = 'application/octet-stream'; - else - throw e; - } - } - httpChannel.explicitSetUploadStream(synthesized, contentType, -1, httpChannel.requestMethod, false); -} - -function convertString(s, source, dest) { - const is = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( - Ci.nsIStringInputStream - ); - is.setData(s, s.length); - const listener = Cc["@mozilla.org/network/stream-loader;1"].createInstance( - Ci.nsIStreamLoader - ); - let result = []; - listener.init({ - onStreamComplete: function onStreamComplete( - loader, - context, - status, - length, - data - ) { - const array = Array.from(data); - const kChunk = 100000; - for (let i = 0; i < length; i += kChunk) { - const len = Math.min(kChunk, length - i); - const chunk = String.fromCharCode.apply(this, array.slice(i, i + len)); - result.push(chunk); - } - }, - }); - const converter = Cc["@mozilla.org/streamConverters;1"].getService( - Ci.nsIStreamConverterService - ).asyncConvertData( - source, - dest, - listener, - null - ); - converter.onStartRequest(null, null); - converter.onDataAvailable(null, is, 0, s.length); - converter.onStopRequest(null, null, null); - return result.join(''); -} - -const errorMap = { - 'aborted': Cr.NS_ERROR_ABORT, - 'accessdenied': Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED, - 'addressunreachable': Cr.NS_ERROR_UNKNOWN_HOST, - 'blockedbyclient': Cr.NS_ERROR_FAILURE, - 'blockedbyresponse': Cr.NS_ERROR_FAILURE, - 'connectionaborted': Cr.NS_ERROR_NET_INTERRUPT, - 'connectionclosed': Cr.NS_ERROR_FAILURE, - 'connectionfailed': Cr.NS_ERROR_FAILURE, - 'connectionrefused': Cr.NS_ERROR_CONNECTION_REFUSED, - 'connectionreset': Cr.NS_ERROR_NET_RESET, - 'internetdisconnected': Cr.NS_ERROR_OFFLINE, - 'namenotresolved': Cr.NS_ERROR_UNKNOWN_HOST, - 'timedout': Cr.NS_ERROR_NET_TIMEOUT, - 'failed': Cr.NS_ERROR_FAILURE, -}; - -PageNetwork.Events = { - Request: Symbol('PageNetwork.Events.Request'), - Response: Symbol('PageNetwork.Events.Response'), - RequestFinished: Symbol('PageNetwork.Events.RequestFinished'), - RequestFailed: Symbol('PageNetwork.Events.RequestFailed'), -}; - -var EXPORTED_SYMBOLS = ['NetworkObserver', 'PageNetwork']; -this.NetworkObserver = NetworkObserver; -this.PageNetwork = PageNetwork; diff --git a/browser_patches/firefox-beta/juggler/SimpleChannel.js b/browser_patches/firefox-beta/juggler/SimpleChannel.js deleted file mode 100644 index 59b29532ab..0000000000 --- a/browser_patches/firefox-beta/juggler/SimpleChannel.js +++ /dev/null @@ -1,180 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -// Note: this file should be loadabale with eval() into worker environment. -// Avoid Components.*, ChromeUtils and global const variables. - -const SIMPLE_CHANNEL_MESSAGE_NAME = 'juggler:simplechannel'; - -class SimpleChannel { - static createForMessageManager(name, mm) { - const channel = new SimpleChannel(name); - - const messageListener = { - receiveMessage: message => channel._onMessage(message.data) - }; - mm.addMessageListener(SIMPLE_CHANNEL_MESSAGE_NAME, messageListener); - - channel.setTransport({ - sendMessage: obj => mm.sendAsyncMessage(SIMPLE_CHANNEL_MESSAGE_NAME, obj), - dispose: () => mm.removeMessageListener(SIMPLE_CHANNEL_MESSAGE_NAME, messageListener), - }); - - return channel; - } - - constructor(name) { - this._name = name; - this._messageId = 0; - this._connectorId = 0; - this._pendingMessages = new Map(); - this._handlers = new Map(); - this._bufferedIncomingMessages = []; - this._bufferedOutgoingMessages = []; - this.transport = { - sendMessage: null, - dispose: null, - }; - this._ready = false; - this._disposed = false; - } - - setTransport(transport) { - this.transport = transport; - // connection handshake: - // 1. There are two channel ends in different processes. - // 2. Both ends start in the `ready = false` state, meaning that they will - // not send any messages over transport. - // 3. Once channel end is created, it sends `READY` message to the other end. - // 4. Eventually, at least one of the ends receives `READY` message and responds with - // `READY_ACK`. We assume at least one of the ends will receive "READY" event from the other, since - // channel ends have a "parent-child" relation, i.e. one end is always created before the other one. - // 5. Once channel end receives either `READY` or `READY_ACK`, it transitions to `ready` state. - this.transport.sendMessage('READY'); - } - - _markAsReady() { - if (this._ready) - return; - this._ready = true; - for (const msg of this._bufferedOutgoingMessages) - this.transport.sendMessage(msg); - this._bufferedOutgoingMessages = []; - } - - dispose() { - if (this._disposed) - return; - this._disposed = true; - for (const {resolve, reject, methodName} of this._pendingMessages.values()) - reject(new Error(`Failed "${methodName}": ${this._name} is disposed.`)); - this._pendingMessages.clear(); - this._handlers.clear(); - this.transport.dispose(); - } - - _rejectCallbacksFromConnector(connectorId) { - for (const [messageId, callback] of this._pendingMessages) { - if (callback.connectorId === connectorId) { - callback.reject(new Error(`Failed "${callback.methodName}": connector for namespace "${callback.namespace}" in channel "${this._name}" is disposed.`)); - this._pendingMessages.delete(messageId); - } - } - } - - connect(namespace) { - const connectorId = ++this._connectorId; - return { - send: (...args) => this._send(namespace, connectorId, ...args), - emit: (...args) => void this._send(namespace, connectorId, ...args).catch(e => {}), - dispose: () => this._rejectCallbacksFromConnector(connectorId), - }; - } - - register(namespace, handler) { - if (this._handlers.has(namespace)) - throw new Error('ERROR: double-register for namespace ' + namespace); - this._handlers.set(namespace, handler); - // Try to re-deliver all pending messages. - const bufferedRequests = this._bufferedIncomingMessages; - this._bufferedIncomingMessages = []; - for (const data of bufferedRequests) { - this._onMessage(data); - } - return () => this.unregister(namespace); - } - - unregister(namespace) { - this._handlers.delete(namespace); - } - - /** - * @param {string} namespace - * @param {number} connectorId - * @param {string} methodName - * @param {...*} params - * @return {!Promise<*>} - */ - async _send(namespace, connectorId, methodName, ...params) { - if (this._disposed) - throw new Error(`ERROR: channel ${this._name} is already disposed! Cannot send "${methodName}" to "${namespace}"`); - const id = ++this._messageId; - const promise = new Promise((resolve, reject) => { - this._pendingMessages.set(id, {connectorId, resolve, reject, methodName, namespace}); - }); - const message = {requestId: id, methodName, params, namespace}; - if (this._ready) - this.transport.sendMessage(message); - else - this._bufferedOutgoingMessages.push(message); - return promise; - } - - async _onMessage(data) { - if (data === 'READY') { - this.transport.sendMessage('READY_ACK'); - this._markAsReady(); - return; - } - if (data === 'READY_ACK') { - this._markAsReady(); - return; - } - if (data.responseId) { - const {resolve, reject} = this._pendingMessages.get(data.responseId); - this._pendingMessages.delete(data.responseId); - if (data.error) - reject(new Error(data.error)); - else - resolve(data.result); - } else if (data.requestId) { - const namespace = data.namespace; - const handler = this._handlers.get(namespace); - if (!handler) { - this._bufferedIncomingMessages.push(data); - return; - } - const method = handler[data.methodName]; - if (!method) { - this.transport.sendMessage({responseId: data.requestId, error: `error in channel "${this._name}": No method "${data.methodName}" in namespace "${namespace}"`}); - return; - } - try { - const result = await method.call(handler, ...data.params); - this.transport.sendMessage({responseId: data.requestId, result}); - } catch (error) { - this.transport.sendMessage({responseId: data.requestId, error: `error in channel "${this._name}": exception while running method "${data.methodName}" in namespace "${namespace}": ${error.message} ${error.stack}`}); - return; - } - } else { - dump(` - ERROR: unknown message in channel "${this._name}": ${JSON.stringify(data)} - `); - } - } -} - -var EXPORTED_SYMBOLS = ['SimpleChannel']; -this.SimpleChannel = SimpleChannel; diff --git a/browser_patches/firefox-beta/juggler/TargetRegistry.js b/browser_patches/firefox-beta/juggler/TargetRegistry.js deleted file mode 100644 index b222ba98bb..0000000000 --- a/browser_patches/firefox-beta/juggler/TargetRegistry.js +++ /dev/null @@ -1,1065 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm"); -const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm"); -const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); -const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); - -const Cr = Components.results; - -const helper = new Helper(); - -const IDENTITY_NAME = 'JUGGLER '; -const HUNDRED_YEARS = 60 * 60 * 24 * 365 * 100; - -const ALL_PERMISSIONS = [ - 'geo', - 'desktop-notification', -]; - -class DownloadInterceptor { - constructor(registry) { - this._registry = registry - this._handlerToUuid = new Map(); - this._uuidToHandler = new Map(); - } - - // - // nsIDownloadInterceptor implementation. - // - interceptDownloadRequest(externalAppHandler, request, browsingContext, outFile) { - if (!(request instanceof Ci.nsIChannel)) - return false; - const channel = request.QueryInterface(Ci.nsIChannel); - let pageTarget = this._registry._browserBrowsingContextToTarget.get(channel.loadInfo.browsingContext.top); - if (!pageTarget) - return false; - - const browserContext = pageTarget.browserContext(); - const options = browserContext.downloadOptions; - if (!options) - return false; - - const uuid = helper.generateId(); - let file = null; - if (options.behavior === 'saveToDisk') { - file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - file.initWithPath(options.downloadsDir); - file.append(uuid); - - try { - file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); - } catch (e) { - dump(`interceptDownloadRequest failed to create file: ${e}\n`); - return false; - } - } - outFile.value = file; - this._handlerToUuid.set(externalAppHandler, uuid); - this._uuidToHandler.set(uuid, externalAppHandler); - const downloadInfo = { - uuid, - browserContextId: browserContext.browserContextId, - pageTargetId: pageTarget.id(), - url: request.name, - suggestedFileName: externalAppHandler.suggestedFileName, - }; - this._registry.emit(TargetRegistry.Events.DownloadCreated, downloadInfo); - return true; - } - - onDownloadComplete(externalAppHandler, canceled, errorName) { - const uuid = this._handlerToUuid.get(externalAppHandler); - if (!uuid) - return; - this._handlerToUuid.delete(externalAppHandler); - this._uuidToHandler.delete(uuid); - const downloadInfo = { - uuid, - error: errorName, - }; - if (canceled === 'NS_BINDING_ABORTED') { - downloadInfo.canceled = true; - } - this._registry.emit(TargetRegistry.Events.DownloadFinished, downloadInfo); - } - - async cancelDownload(uuid) { - const externalAppHandler = this._uuidToHandler.get(uuid); - if (!externalAppHandler) { - return; - } - await externalAppHandler.cancel(Cr.NS_BINDING_ABORTED); - } -} - -const screencastService = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); - -class TargetRegistry { - constructor() { - EventEmitter.decorate(this); - - this._browserContextIdToBrowserContext = new Map(); - this._userContextIdToBrowserContext = new Map(); - this._browserToTarget = new Map(); - this._browserBrowsingContextToTarget = new Map(); - - this._browserProxy = null; - - // Cleanup containers from previous runs (if any) - for (const identity of ContextualIdentityService.getPublicIdentities()) { - if (identity.name && identity.name.startsWith(IDENTITY_NAME)) { - ContextualIdentityService.remove(identity.userContextId); - ContextualIdentityService.closeContainerTabs(identity.userContextId); - } - } - - this._defaultContext = new BrowserContext(this, undefined, undefined); - - Services.obs.addObserver({ - observe: (subject, topic, data) => { - const browser = subject.ownerElement; - if (!browser) - return; - const target = this._browserToTarget.get(browser); - if (!target) - return; - target.emit(PageTarget.Events.Crashed); - target.dispose(); - } - }, 'oop-frameloader-crashed'); - - Services.mm.addMessageListener('juggler:content-ready', { - receiveMessage: message => { - const linkedBrowser = message.target; - const target = this._browserToTarget.get(linkedBrowser); - if (!target) - return; - - return { - initScripts: target.browserContext().initScripts, - bindings: target.browserContext().bindings, - settings: target.browserContext().settings, - }; - }, - }); - - const onTabOpenListener = (appWindow, window, event) => { - const tab = event.target; - const userContextId = tab.userContextId; - const browserContext = this._userContextIdToBrowserContext.get(userContextId); - const hasExplicitSize = appWindow && (appWindow.chromeFlags & Ci.nsIWebBrowserChrome.JUGGLER_WINDOW_EXPLICIT_SIZE) !== 0; - const openerContext = tab.linkedBrowser.browsingContext.opener; - let openerTarget; - if (openerContext) { - // Popups usually have opener context. Get top context for the case when opener is - // an iframe. - openerTarget = this._browserBrowsingContextToTarget.get(openerContext.top); - } else if (tab.openerTab) { - // Noopener popups from the same window have opener tab instead. - openerTarget = this._browserToTarget.get(tab.openerTab.linkedBrowser); - } - if (!browserContext) - throw new Error(`Internal error: cannot find context for userContextId=${userContextId}`); - const target = new PageTarget(this, window, tab, browserContext, openerTarget); - target.updateUserAgent(); - target.updatePlatform(); - target.updateJavaScriptDisabled(); - target.updateTouchOverride(); - target.updateColorSchemeOverride(); - target.updateReducedMotionOverride(); - target.updateForcedColorsOverride(); - if (!hasExplicitSize) - target.updateViewportSize(); - if (browserContext.videoRecordingOptions) - target._startVideoRecording(browserContext.videoRecordingOptions); - }; - - const onTabCloseListener = event => { - const tab = event.target; - const linkedBrowser = tab.linkedBrowser; - const target = this._browserToTarget.get(linkedBrowser); - if (target) - target.dispose(); - }; - - const domWindowTabListeners = new Map(); - - const onOpenWindow = async (appWindow) => { - - let domWindow; - if (appWindow instanceof Ci.nsIAppWindow) { - domWindow = appWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); - } else { - domWindow = appWindow; - appWindow = null; - } - if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) - return; - // In persistent mode, window might be opened long ago and might be - // already initialized. - // - // In this case, we want to keep this callback synchronous so that we will call - // `onTabOpenListener` synchronously and before the sync IPc message `juggler:content-ready`. - if (domWindow.document.readyState === 'uninitialized' || domWindow.document.readyState === 'loading') { - // For non-initialized windows, DOMContentLoaded initializes gBrowser - // and starts tab loading (see //browser/base/content/browser.js), so we - // are guaranteed to call `onTabOpenListener` before the sync IPC message - // `juggler:content-ready`. - await helper.awaitEvent(domWindow, 'DOMContentLoaded'); - } - - if (!domWindow.gBrowser) - return; - const tabContainer = domWindow.gBrowser.tabContainer; - domWindowTabListeners.set(domWindow, [ - helper.addEventListener(tabContainer, 'TabOpen', event => onTabOpenListener(appWindow, domWindow, event)), - helper.addEventListener(tabContainer, 'TabClose', onTabCloseListener), - ]); - for (const tab of domWindow.gBrowser.tabs) - onTabOpenListener(appWindow, domWindow, { target: tab }); - }; - - const onCloseWindow = window => { - const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); - if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) - return; - if (!domWindow.gBrowser) - return; - - const listeners = domWindowTabListeners.get(domWindow) || []; - domWindowTabListeners.delete(domWindow); - helper.removeListeners(listeners); - for (const tab of domWindow.gBrowser.tabs) - onTabCloseListener({ target: tab }); - }; - - const extHelperAppSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Ci.nsIExternalHelperAppService); - this._downloadInterceptor = new DownloadInterceptor(this); - extHelperAppSvc.setDownloadInterceptor(this._downloadInterceptor); - - Services.wm.addListener({ onOpenWindow, onCloseWindow }); - for (const win of Services.wm.getEnumerator(null)) - onOpenWindow(win); - } - - async cancelDownload(options) { - this._downloadInterceptor.cancelDownload(options.uuid); - } - - setBrowserProxy(proxy) { - this._browserProxy = proxy; - } - - getProxyInfo(channel) { - const originAttributes = channel.loadInfo && channel.loadInfo.originAttributes; - const browserContext = originAttributes ? this.browserContextForUserContextId(originAttributes.userContextId) : null; - // Prefer context proxy and fallback to browser-level proxy. - const proxyInfo = (browserContext && browserContext._proxy) || this._browserProxy; - if (!proxyInfo || proxyInfo.bypass.some(domainSuffix => channel.URI.host.endsWith(domainSuffix))) - return null; - return proxyInfo; - } - - defaultContext() { - return this._defaultContext; - } - - createBrowserContext(removeOnDetach) { - return new BrowserContext(this, helper.generateId(), removeOnDetach); - } - - browserContextForId(browserContextId) { - return this._browserContextIdToBrowserContext.get(browserContextId); - } - - browserContextForUserContextId(userContextId) { - return this._userContextIdToBrowserContext.get(userContextId); - } - - async newPage({browserContextId}) { - const browserContext = this.browserContextForId(browserContextId); - const features = "chrome,dialog=no,all"; - // See _callWithURIToLoad in browser.js for the structure of window.arguments - // window.arguments[1]: unused (bug 871161) - // [2]: referrerInfo (nsIReferrerInfo) - // [3]: postData (nsIInputStream) - // [4]: allowThirdPartyFixup (bool) - // [5]: userContextId (int) - // [6]: originPrincipal (nsIPrincipal) - // [7]: originStoragePrincipal (nsIPrincipal) - // [8]: triggeringPrincipal (nsIPrincipal) - // [9]: allowInheritPrincipal (bool) - // [10]: csp (nsIContentSecurityPolicy) - // [11]: nsOpenWindowInfo - const args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - const urlSupports = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - urlSupports.data = 'about:blank'; - args.appendElement(urlSupports); // 0 - args.appendElement(undefined); // 1 - args.appendElement(undefined); // 2 - args.appendElement(undefined); // 3 - args.appendElement(undefined); // 4 - const userContextIdSupports = Cc[ - "@mozilla.org/supports-PRUint32;1" - ].createInstance(Ci.nsISupportsPRUint32); - userContextIdSupports.data = browserContext.userContextId; - args.appendElement(userContextIdSupports); // 5 - args.appendElement(undefined); // 6 - args.appendElement(undefined); // 7 - args.appendElement(Services.scriptSecurityManager.getSystemPrincipal()); // 8 - - const window = Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, '_blank', features, args); - await waitForWindowReady(window); - if (window.gBrowser.browsers.length !== 1) - throw new Error(`Unexpected number of tabs in the new window: ${window.gBrowser.browsers.length}`); - const browser = window.gBrowser.browsers[0]; - let target = this._browserToTarget.get(browser); - while (!target) { - await helper.awaitEvent(this, TargetRegistry.Events.TargetCreated); - target = this._browserToTarget.get(browser); - } - browser.focus(); - if (browserContext.settings.timezoneId) { - if (await target.hasFailedToOverrideTimezone()) - throw new Error('Failed to override timezone'); - } - return target.id(); - } - - targets() { - return Array.from(this._browserToTarget.values()); - } - - targetForBrowser(browser) { - return this._browserToTarget.get(browser); - } -} - -class PageTarget { - constructor(registry, win, tab, browserContext, opener) { - EventEmitter.decorate(this); - - this._targetId = helper.generateId(); - this._registry = registry; - this._window = win; - this._gBrowser = win.gBrowser; - this._tab = tab; - this._linkedBrowser = tab.linkedBrowser; - this._browserContext = browserContext; - this._viewportSize = undefined; - this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; - this._url = 'about:blank'; - this._openerId = opener ? opener.id() : undefined; - this._channel = SimpleChannel.createForMessageManager(`browser::page[${this._targetId}]`, this._linkedBrowser.messageManager); - this._videoRecordingInfo = undefined; - this._screencastRecordingInfo = undefined; - this._dialogs = new Map(); - this.forcedColors = 'no-override'; - this._pageInitScripts = []; - - const navigationListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), - onLocationChange: (aWebProgress, aRequest, aLocation) => this._onNavigated(aLocation), - }; - this._eventListeners = [ - helper.addObserver(this._updateModalDialogs.bind(this), 'tabmodal-dialog-loaded'), - helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION), - helper.addEventListener(this._linkedBrowser, 'DOMModalDialogClosed', event => this._updateModalDialogs()), - ]; - - this._disposed = false; - browserContext.pages.add(this); - this._registry._browserToTarget.set(this._linkedBrowser, this); - this._registry._browserBrowsingContextToTarget.set(this._linkedBrowser.browsingContext, this); - - this._registry.emit(TargetRegistry.Events.TargetCreated, this); - } - - dialog(dialogId) { - return this._dialogs.get(dialogId); - } - - dialogs() { - return [...this._dialogs.values()]; - } - - async windowReady() { - await waitForWindowReady(this._window); - } - - linkedBrowser() { - return this._linkedBrowser; - } - - browserContext() { - return this._browserContext; - } - - updateTouchOverride() { - this._linkedBrowser.browsingContext.touchEventsOverride = this._browserContext.touchOverride ? 'enabled' : 'none'; - } - - updateUserAgent() { - this._linkedBrowser.browsingContext.customUserAgent = this._browserContext.defaultUserAgent; - } - - updatePlatform() { - this._linkedBrowser.browsingContext.customPlatform = this._browserContext.defaultPlatform; - } - - updateJavaScriptDisabled() { - this._linkedBrowser.browsingContext.allowJavascript = !this._browserContext.javaScriptDisabled; - } - - _updateModalDialogs() { - const prompts = new Set(this._linkedBrowser.tabModalPromptBox ? this._linkedBrowser.tabModalPromptBox.listPrompts() : []); - for (const dialog of this._dialogs.values()) { - if (!prompts.has(dialog.prompt())) { - this._dialogs.delete(dialog.id()); - this.emit(PageTarget.Events.DialogClosed, dialog); - } else { - prompts.delete(dialog.prompt()); - } - } - for (const prompt of prompts) { - const dialog = Dialog.createIfSupported(prompt); - if (!dialog) - continue; - this._dialogs.set(dialog.id(), dialog); - this.emit(PageTarget.Events.DialogOpened, dialog); - } - } - - async updateViewportSize() { - // Viewport size is defined by three arguments: - // 1. default size. Could be explicit if set as part of `window.open` call, e.g. - // `window.open(url, title, 'width=400,height=400')` - // 2. page viewport size - // 3. browserContext viewport size - // - // The "default size" (1) is only respected when the page is opened. - // Otherwise, explicitly set page viewport prevales over browser context - // default viewport. - const viewportSize = this._viewportSize || this._browserContext.defaultViewportSize; - const actualSize = await setViewportSizeForBrowser(viewportSize, this._linkedBrowser, this._window); - this._linkedBrowser.browsingContext.overrideDPPX = this._browserContext.deviceScaleFactor || this._initialDPPX; - await this._channel.connect('').send('awaitViewportDimensions', { - width: actualSize.width, - height: actualSize.height, - deviceSizeIsPageSize: !!this._browserContext.deviceScaleFactor, - }); - } - - setEmulatedMedia(mediumOverride) { - this._linkedBrowser.browsingContext.mediumOverride = mediumOverride || ''; - } - - setColorScheme(colorScheme) { - this.colorScheme = fromProtocolColorScheme(colorScheme); - this.updateColorSchemeOverride(); - } - - updateColorSchemeOverride() { - this._linkedBrowser.browsingContext.prefersColorSchemeOverride = this.colorScheme || this._browserContext.colorScheme || 'none'; - } - - setReducedMotion(reducedMotion) { - this.reducedMotion = fromProtocolReducedMotion(reducedMotion); - this.updateReducedMotionOverride(); - } - - updateReducedMotionOverride() { - this._linkedBrowser.browsingContext.prefersReducedMotionOverride = this.reducedMotion || this._browserContext.reducedMotion || 'none'; - } - - setForcedColors(forcedColors) { - this.forcedColors = fromProtocolForcedColors(forcedColors); - this.updateForcedColorsOverride(); - } - - updateForcedColorsOverride() { - this._linkedBrowser.browsingContext.forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override'; - } - - async setViewportSize(viewportSize) { - this._viewportSize = viewportSize; - await this.updateViewportSize(); - } - - close(runBeforeUnload = false) { - this._gBrowser.removeTab(this._tab, { - skipPermitUnload: !runBeforeUnload, - }); - } - - channel() { - return this._channel; - } - - id() { - return this._targetId; - } - - info() { - return { - targetId: this.id(), - type: 'page', - browserContextId: this._browserContext.browserContextId, - openerId: this._openerId, - }; - } - - _onNavigated(aLocation) { - this._url = aLocation.spec; - this._browserContext.grantPermissionsToOrigin(this._url); - } - - async ensurePermissions() { - await this._channel.connect('').send('ensurePermissions', {}).catch(e => void e); - } - - async setInitScripts(scripts) { - this._pageInitScripts = scripts; - await this.pushInitScripts(); - } - - async pushInitScripts() { - await this._channel.connect('').send('setInitScripts', [...this._browserContext.initScripts, ...this._pageInitScripts]).catch(e => void e); - } - - async addBinding(worldName, name, script) { - await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e); - } - - async applyContextSetting(name, value) { - await this._channel.connect('').send('applyContextSetting', { name, value }).catch(e => void e); - } - - async hasFailedToOverrideTimezone() { - return await this._channel.connect('').send('hasFailedToOverrideTimezone').catch(e => true); - } - - async _startVideoRecording({width, height, dir}) { - // On Mac the window may not yet be visible when TargetCreated and its - // NSWindow.windowNumber may be -1, so we wait until the window is known - // to be initialized and visible. - await this.windowReady(); - const file = OS.Path.join(dir, helper.generateId() + '.webm'); - if (width < 10 || width > 10000 || height < 10 || height > 10000) - throw new Error("Invalid size"); - - const docShell = this._gBrowser.ownerGlobal.docShell; - // Exclude address bar and navigation control from the video. - const rect = this.linkedBrowser().getBoundingClientRect(); - const devicePixelRatio = this._window.devicePixelRatio; - let sessionId; - const registry = this._registry; - const screencastClient = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), - screencastFrame(data, deviceWidth, deviceHeight) { - }, - screencastStopped() { - registry.emit(TargetRegistry.Events.ScreencastStopped, sessionId); - }, - }; - const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; - sessionId = screencastService.startVideoRecording(screencastClient, docShell, true, file, width, height, 0, viewport.width, viewport.height, devicePixelRatio * rect.top); - this._videoRecordingInfo = { sessionId, file }; - this.emit(PageTarget.Events.ScreencastStarted); - } - - _stopVideoRecording() { - if (!this._videoRecordingInfo) - throw new Error('No video recording in progress'); - const videoRecordingInfo = this._videoRecordingInfo; - this._videoRecordingInfo = undefined; - screencastService.stopVideoRecording(videoRecordingInfo.sessionId); - } - - videoRecordingInfo() { - return this._videoRecordingInfo; - } - - async startScreencast({ width, height, quality }) { - // On Mac the window may not yet be visible when TargetCreated and its - // NSWindow.windowNumber may be -1, so we wait until the window is known - // to be initialized and visible. - await this.windowReady(); - if (width < 10 || width > 10000 || height < 10 || height > 10000) - throw new Error("Invalid size"); - - const docShell = this._gBrowser.ownerGlobal.docShell; - // Exclude address bar and navigation control from the video. - const rect = this.linkedBrowser().getBoundingClientRect(); - const devicePixelRatio = this._window.devicePixelRatio; - - const self = this; - const screencastClient = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), - screencastFrame(data, deviceWidth, deviceHeight) { - if (self._screencastRecordingInfo) - self.emit(PageTarget.Events.ScreencastFrame, { data, deviceWidth, deviceHeight }); - }, - screencastStopped() { - }, - }; - const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; - const screencastId = screencastService.startVideoRecording(screencastClient, docShell, false, '', width, height, quality || 90, viewport.width, viewport.height, devicePixelRatio * rect.top); - this._screencastRecordingInfo = { screencastId }; - return { screencastId }; - } - - screencastFrameAck({ screencastId }) { - if (!this._screencastRecordingInfo || this._screencastRecordingInfo.screencastId !== screencastId) - return; - screencastService.screencastFrameAck(screencastId); - } - - stopScreencast() { - if (!this._screencastRecordingInfo) - throw new Error('No screencast in progress'); - const { screencastId } = this._screencastRecordingInfo; - this._screencastRecordingInfo = undefined; - screencastService.stopVideoRecording(screencastId); - } - - dispose() { - this._disposed = true; - if (this._videoRecordingInfo) - this._stopVideoRecording(); - if (this._screencastRecordingInfo) - this.stopScreencast(); - this._browserContext.pages.delete(this); - this._registry._browserToTarget.delete(this._linkedBrowser); - this._registry._browserBrowsingContextToTarget.delete(this._linkedBrowser.browsingContext); - try { - helper.removeListeners(this._eventListeners); - } catch (e) { - // In some cases, removing listeners from this._linkedBrowser fails - // because it is already half-destroyed. - if (e) - dump(e.message + '\n' + e.stack + '\n'); - } - this._registry.emit(TargetRegistry.Events.TargetDestroyed, this); - } -} - -PageTarget.Events = { - ScreencastStarted: Symbol('PageTarget.ScreencastStarted'), - ScreencastFrame: Symbol('PageTarget.ScreencastFrame'), - Crashed: Symbol('PageTarget.Crashed'), - DialogOpened: Symbol('PageTarget.DialogOpened'), - DialogClosed: Symbol('PageTarget.DialogClosed'), -}; - -function fromProtocolColorScheme(colorScheme) { - if (colorScheme === 'light' || colorScheme === 'dark') - return colorScheme; - if (colorScheme === null || colorScheme === 'no-preference') - return undefined; - throw new Error('Unknown color scheme: ' + colorScheme); -} - -function fromProtocolReducedMotion(reducedMotion) { - if (reducedMotion === 'reduce' || reducedMotion === 'no-preference') - return reducedMotion; - if (reducedMotion === null) - return undefined; - throw new Error('Unknown reduced motion: ' + reducedMotion); -} - -function fromProtocolForcedColors(forcedColors) { - if (forcedColors === 'active' || forcedColors === 'none') - return forcedColors; - if (forcedColors === null) - return undefined; - throw new Error('Unknown forced colors: ' + forcedColors); -} - -class BrowserContext { - constructor(registry, browserContextId, removeOnDetach) { - this._registry = registry; - this.browserContextId = browserContextId; - // Default context has userContextId === 0, but we pass undefined to many APIs just in case. - this.userContextId = 0; - if (browserContextId !== undefined) { - const identity = ContextualIdentityService.create(IDENTITY_NAME + browserContextId); - this.userContextId = identity.userContextId; - } - this._principals = []; - // Maps origins to the permission lists. - this._permissions = new Map(); - this._registry._browserContextIdToBrowserContext.set(this.browserContextId, this); - this._registry._userContextIdToBrowserContext.set(this.userContextId, this); - this._proxy = null; - this.removeOnDetach = removeOnDetach; - this.extraHTTPHeaders = undefined; - this.httpCredentials = undefined; - this.requestInterceptionEnabled = undefined; - this.ignoreHTTPSErrors = undefined; - this.downloadOptions = undefined; - this.defaultViewportSize = undefined; - this.deviceScaleFactor = undefined; - this.defaultUserAgent = null; - this.defaultPlatform = null; - this.javaScriptDisabled = false; - this.touchOverride = false; - this.colorScheme = 'none'; - this.forcedColors = 'no-override'; - this.reducedMotion = 'none'; - this.videoRecordingOptions = undefined; - this.initScripts = []; - this.bindings = []; - this.settings = {}; - this.pages = new Set(); - } - - setColorScheme(colorScheme) { - this.colorScheme = fromProtocolColorScheme(colorScheme); - for (const page of this.pages) - page.updateColorSchemeOverride(); - } - - setReducedMotion(reducedMotion) { - this.reducedMotion = fromProtocolReducedMotion(reducedMotion); - for (const page of this.pages) - page.updateReducedMotionOverride(); - } - - setForcedColors(forcedColors) { - this.forcedColors = fromProtocolForcedColors(forcedColors); - for (const page of this.pages) - page.updateForcedColorsOverride(); - } - - async destroy() { - if (this.userContextId !== 0) { - ContextualIdentityService.remove(this.userContextId); - for (const page of this.pages) - page.close(); - if (this.pages.size) { - await new Promise(f => { - const listener = helper.on(this._registry, TargetRegistry.Events.TargetDestroyed, () => { - if (!this.pages.size) { - helper.removeListeners([listener]); - f(); - } - }); - }); - } - } - this._registry._browserContextIdToBrowserContext.delete(this.browserContextId); - this._registry._userContextIdToBrowserContext.delete(this.userContextId); - } - - setProxy(proxy) { - // Clear AuthCache. - Services.obs.notifyObservers(null, "net:clear-active-logins"); - this._proxy = proxy; - } - - setIgnoreHTTPSErrors(ignoreHTTPSErrors) { - if (this.ignoreHTTPSErrors === ignoreHTTPSErrors) - return; - this.ignoreHTTPSErrors = ignoreHTTPSErrors; - const certOverrideService = Cc[ - "@mozilla.org/security/certoverride;1" - ].getService(Ci.nsICertOverrideService); - if (ignoreHTTPSErrors) { - Preferences.set("network.stricttransportsecurity.preloadlist", false); - Preferences.set("security.cert_pinning.enforcement_level", 0); - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(true, this.userContextId); - } else { - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(false, this.userContextId); - } - } - - setDefaultUserAgent(userAgent) { - this.defaultUserAgent = userAgent; - for (const page of this.pages) - page.updateUserAgent(); - } - - setDefaultPlatform(platform) { - this.defaultPlatform = platform; - for (const page of this.pages) - page.updatePlatform(); - } - - setJavaScriptDisabled(javaScriptDisabled) { - this.javaScriptDisabled = javaScriptDisabled; - for (const page of this.pages) - page.updateJavaScriptDisabled(); - } - - setTouchOverride(touchOverride) { - this.touchOverride = touchOverride; - for (const page of this.pages) - page.updateTouchOverride(); - } - - async setDefaultViewport(viewport) { - this.defaultViewportSize = viewport ? viewport.viewportSize : undefined; - this.deviceScaleFactor = viewport ? viewport.deviceScaleFactor : undefined; - await Promise.all(Array.from(this.pages).map(page => page.updateViewportSize())); - } - - async setInitScripts(scripts) { - this.initScripts = scripts; - await Promise.all(Array.from(this.pages).map(page => page.pushInitScripts())); - } - - async addBinding(worldName, name, script) { - this.bindings.push({ worldName, name, script }); - await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script))); - } - - async applySetting(name, value) { - this.settings[name] = value; - await Promise.all(Array.from(this.pages).map(page => page.applyContextSetting(name, value))); - } - - async grantPermissions(origin, permissions) { - this._permissions.set(origin, permissions); - const promises = []; - for (const page of this.pages) { - if (origin === '*' || page._url.startsWith(origin)) { - this.grantPermissionsToOrigin(page._url); - promises.push(page.ensurePermissions()); - } - } - await Promise.all(promises); - } - - resetPermissions() { - for (const principal of this._principals) { - for (const permission of ALL_PERMISSIONS) - Services.perms.removeFromPrincipal(principal, permission); - } - this._principals = []; - this._permissions.clear(); - } - - grantPermissionsToOrigin(url) { - let origin = Array.from(this._permissions.keys()).find(key => url.startsWith(key)); - if (!origin) - origin = '*'; - - const permissions = this._permissions.get(origin); - if (!permissions) - return; - - const attrs = { userContextId: this.userContextId || undefined }; - const principal = Services.scriptSecurityManager.createContentPrincipal(NetUtil.newURI(url), attrs); - this._principals.push(principal); - for (const permission of ALL_PERMISSIONS) { - const action = permissions.includes(permission) ? Ci.nsIPermissionManager.ALLOW_ACTION : Ci.nsIPermissionManager.DENY_ACTION; - Services.perms.addFromPrincipal(principal, permission, action, Ci.nsIPermissionManager.EXPIRE_NEVER, 0 /* expireTime */); - } - } - - setCookies(cookies) { - const protocolToSameSite = { - [undefined]: Ci.nsICookie.SAMESITE_NONE, - 'Lax': Ci.nsICookie.SAMESITE_LAX, - 'Strict': Ci.nsICookie.SAMESITE_STRICT, - }; - for (const cookie of cookies) { - const uri = cookie.url ? NetUtil.newURI(cookie.url) : null; - let domain = cookie.domain; - if (!domain) { - if (!uri) - throw new Error('At least one of the url and domain needs to be specified'); - domain = uri.host; - } - let path = cookie.path; - if (!path) - path = uri ? dirPath(uri.filePath) : '/'; - let secure = false; - if (cookie.secure !== undefined) - secure = cookie.secure; - else if (uri && uri.scheme === 'https') - secure = true; - Services.cookies.add( - domain, - path, - cookie.name, - cookie.value, - secure, - cookie.httpOnly || false, - cookie.expires === undefined || cookie.expires === -1 /* isSession */, - cookie.expires === undefined ? Date.now() + HUNDRED_YEARS : cookie.expires, - { userContextId: this.userContextId || undefined } /* originAttributes */, - protocolToSameSite[cookie.sameSite], - Ci.nsICookie.SCHEME_UNSET - ); - } - } - - clearCookies() { - Services.cookies.removeCookiesWithOriginAttributes(JSON.stringify({ userContextId: this.userContextId || undefined })); - } - - getCookies() { - const result = []; - const sameSiteToProtocol = { - [Ci.nsICookie.SAMESITE_NONE]: 'None', - [Ci.nsICookie.SAMESITE_LAX]: 'Lax', - [Ci.nsICookie.SAMESITE_STRICT]: 'Strict', - }; - for (let cookie of Services.cookies.cookies) { - if (cookie.originAttributes.userContextId !== this.userContextId) - continue; - if (cookie.host === 'addons.mozilla.org') - continue; - result.push({ - name: cookie.name, - value: cookie.value, - domain: cookie.host, - path: cookie.path, - expires: cookie.isSession ? -1 : cookie.expiry, - size: cookie.name.length + cookie.value.length, - httpOnly: cookie.isHttpOnly, - secure: cookie.isSecure, - session: cookie.isSession, - sameSite: sameSiteToProtocol[cookie.sameSite], - }); - } - return result; - } - - async setVideoRecordingOptions(options) { - this.videoRecordingOptions = options; - const promises = []; - for (const page of this.pages) { - if (options) - promises.push(page._startVideoRecording(options)); - else if (page._videoRecordingInfo) - promises.push(page._stopVideoRecording()); - } - await Promise.all(promises); - } -} - -class Dialog { - static createIfSupported(prompt) { - const type = prompt.args.promptType; - switch (type) { - case 'alert': - case 'alertCheck': - return new Dialog(prompt, 'alert'); - case 'prompt': - return new Dialog(prompt, 'prompt'); - case 'confirm': - case 'confirmCheck': - return new Dialog(prompt, 'confirm'); - case 'confirmEx': - return new Dialog(prompt, 'beforeunload'); - default: - return null; - }; - } - - constructor(prompt, type) { - this._id = helper.generateId(); - this._type = type; - this._prompt = prompt; - } - - id() { - return this._id; - } - - message() { - return this._prompt.ui.infoBody.textContent; - } - - type() { - return this._type; - } - - prompt() { - return this._prompt; - } - - dismiss() { - if (this._prompt.ui.button1) - this._prompt.ui.button1.click(); - else - this._prompt.ui.button0.click(); - } - - defaultValue() { - return this._prompt.ui.loginTextbox.value; - } - - accept(promptValue) { - if (typeof promptValue === 'string' && this._type === 'prompt') - this._prompt.ui.loginTextbox.value = promptValue; - this._prompt.ui.button0.click(); - } -} - - -function dirPath(path) { - return path.substring(0, path.lastIndexOf('/') + 1); -} - -async function waitForWindowReady(window) { - if (window.delayedStartupPromise) { - await window.delayedStartupPromise; - } else { - await new Promise((resolve => { - Services.obs.addObserver(function observer(aSubject, aTopic) { - if (window == aSubject) { - Services.obs.removeObserver(observer, aTopic); - resolve(); - } - }, "browser-delayed-startup-finished"); - })); - } - if (window.document.readyState !== 'complete') - await helper.awaitEvent(window, 'load'); -} - -async function setViewportSizeForBrowser(viewportSize, browser, window) { - await waitForWindowReady(window); - if (viewportSize) { - const {width, height} = viewportSize; - const rect = browser.getBoundingClientRect(); - window.resizeBy(width - rect.width, height - rect.height); - browser.style.setProperty('min-width', width + 'px'); - browser.style.setProperty('min-height', height + 'px'); - browser.style.setProperty('max-width', width + 'px'); - browser.style.setProperty('max-height', height + 'px'); - } else { - browser.style.removeProperty('min-width'); - browser.style.removeProperty('min-height'); - browser.style.removeProperty('max-width'); - browser.style.removeProperty('max-height'); - } - const rect = browser.getBoundingClientRect(); - return { width: rect.width, height: rect.height }; -} - -TargetRegistry.Events = { - TargetCreated: Symbol('TargetRegistry.Events.TargetCreated'), - TargetDestroyed: Symbol('TargetRegistry.Events.TargetDestroyed'), - DownloadCreated: Symbol('TargetRegistry.Events.DownloadCreated'), - DownloadFinished: Symbol('TargetRegistry.Events.DownloadFinished'), - ScreencastStopped: Symbol('TargetRegistry.ScreencastStopped'), -}; - -var EXPORTED_SYMBOLS = ['TargetRegistry', 'PageTarget']; -this.TargetRegistry = TargetRegistry; -this.PageTarget = PageTarget; diff --git a/browser_patches/firefox-beta/juggler/components/Juggler.js b/browser_patches/firefox-beta/juggler/components/Juggler.js deleted file mode 100644 index ed4242406f..0000000000 --- a/browser_patches/firefox-beta/juggler/components/Juggler.js +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var EXPORTED_SYMBOLS = ["Juggler", "JugglerFactory"]; - -const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -const {ComponentUtils} = ChromeUtils.import("resource://gre/modules/ComponentUtils.jsm"); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {Dispatcher} = ChromeUtils.import("chrome://juggler/content/protocol/Dispatcher.js"); -const {BrowserHandler} = ChromeUtils.import("chrome://juggler/content/protocol/BrowserHandler.js"); -const {NetworkObserver} = ChromeUtils.import("chrome://juggler/content/NetworkObserver.js"); -const {TargetRegistry} = ChromeUtils.import("chrome://juggler/content/TargetRegistry.js"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const helper = new Helper(); - -const Cc = Components.classes; -const Ci = Components.interfaces; - -const FRAME_SCRIPT = "chrome://juggler/content/content/main.js"; - -let browserStartupFinishedCallback; -let browserStartupFinishedPromise = new Promise(x => browserStartupFinishedCallback = x); - -class Juggler { - get classDescription() { return "Sample command-line handler"; } - get classID() { return Components.ID('{f7a74a33-e2ab-422d-b022-4fb213dd2639}'); } - get contractID() { return "@mozilla.org/remote/juggler;1" } - get QueryInterface() { - return ChromeUtils.generateQI([ Ci.nsICommandLineHandler, Ci.nsIObserver ]); - } - get helpInfo() { - return " --juggler Enable Juggler automation\n"; - } - - handle(cmdLine) { - // flag has to be consumed in nsICommandLineHandler:handle - // to avoid issues on macos. See Marionette.jsm::handle() for more details. - // TODO: remove after Bug 1724251 is fixed. - cmdLine.handleFlag("juggler-pipe", false); - } - - // This flow is taken from Remote agent and Marionette. - // See https://github.com/mozilla/gecko-dev/blob/0c1b4921830e6af8bc951da01d7772de2fe60a08/remote/components/RemoteAgent.jsm#L302 - async observe(subject, topic) { - switch (topic) { - case "profile-after-change": - Services.obs.addObserver(this, "command-line-startup"); - Services.obs.addObserver(this, "browser-idle-startup-tasks-finished"); - break; - case "command-line-startup": - Services.obs.removeObserver(this, topic); - const cmdLine = subject; - const jugglerPipeFlag = cmdLine.handleFlag('juggler-pipe', false); - if (!jugglerPipeFlag) - return; - - this._silent = cmdLine.findFlag('silent', false) >= 0; - if (this._silent) { - Services.startup.enterLastWindowClosingSurvivalArea(); - browserStartupFinishedCallback(); - } - Services.obs.addObserver(this, "final-ui-startup"); - break; - case "browser-idle-startup-tasks-finished": - browserStartupFinishedCallback(); - break; - // Used to wait until the initial application window has been opened. - case "final-ui-startup": - Services.obs.removeObserver(this, topic); - - const targetRegistry = new TargetRegistry(); - new NetworkObserver(targetRegistry); - - const loadFrameScript = () => { - Services.mm.loadFrameScript(FRAME_SCRIPT, true /* aAllowDelayedLoad */); - if (Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless) { - const styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); - const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); - const uri = ioService.newURI('chrome://juggler/content/content/hidden-scrollbars.css', null, null); - styleSheetService.loadAndRegisterSheet(uri, styleSheetService.AGENT_SHEET); - } - }; - - // Force create hidden window here, otherwise its creation later closes the web socket! - Services.appShell.hiddenDOMWindow; - - let pipeStopped = false; - let browserHandler; - const pipe = Cc['@mozilla.org/juggler/remotedebuggingpipe;1'].getService(Ci.nsIRemoteDebuggingPipe); - const connection = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIRemoteDebuggingPipeClient]), - receiveMessage(message) { - if (this.onmessage) - this.onmessage({ data: message }); - }, - disconnected() { - if (browserHandler) - browserHandler['Browser.close'](); - }, - send(message) { - if (pipeStopped) { - // We are missing the response to Browser.close, - // but everything works fine. Once we actually need it, - // we have to stop the pipe after the response is sent. - return; - } - pipe.sendMessage(message); - }, - }; - pipe.init(connection); - const dispatcher = new Dispatcher(connection); - browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, () => { - if (this._silent) - Services.startup.exitLastWindowClosingSurvivalArea(); - connection.onclose(); - pipe.stop(); - pipeStopped = true; - }, () => browserStartupFinishedPromise); - dispatcher.rootSession().setHandler(browserHandler); - loadFrameScript(); - dump(`\nJuggler listening to the pipe\n`); - break; - } - } - -} - -const jugglerInstance = new Juggler(); - -// This is used by the XPCOM codepath which expects a constructor -var JugglerFactory = function() { - return jugglerInstance; -}; - diff --git a/browser_patches/firefox-beta/juggler/components/components.conf b/browser_patches/firefox-beta/juggler/components/components.conf deleted file mode 100644 index e5bc6523b1..0000000000 --- a/browser_patches/firefox-beta/juggler/components/components.conf +++ /dev/null @@ -1,18 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Classes = [ - # Juggler - { - "cid": "{f7a74a33-e2ab-422d-b022-4fb213dd2639}", - "contract_ids": ["@mozilla.org/remote/juggler;1"], - "categories": { - "command-line-handler": "m-remote", - "profile-after-change": "Juggler", - }, - "jsm": "chrome://juggler/content/components/Juggler.js", - "constructor": "JugglerFactory", - }, -] - diff --git a/browser_patches/firefox-beta/juggler/components/moz.build b/browser_patches/firefox-beta/juggler/components/moz.build deleted file mode 100644 index bab81f83fc..0000000000 --- a/browser_patches/firefox-beta/juggler/components/moz.build +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPCOM_MANIFESTS += ["components.conf"] - diff --git a/browser_patches/firefox-beta/juggler/content/FrameTree.js b/browser_patches/firefox-beta/juggler/content/FrameTree.js deleted file mode 100644 index 61ff889e75..0000000000 --- a/browser_patches/firefox-beta/juggler/content/FrameTree.js +++ /dev/null @@ -1,634 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); -const {Runtime} = ChromeUtils.import('chrome://juggler/content/content/Runtime.js'); - -const helper = new Helper(); - -class FrameTree { - constructor(rootDocShell) { - EventEmitter.decorate(this); - - this._browsingContextGroup = rootDocShell.browsingContext.group; - if (!this._browsingContextGroup.__jugglerFrameTrees) - this._browsingContextGroup.__jugglerFrameTrees = new Set(); - this._browsingContextGroup.__jugglerFrameTrees.add(this); - this._isolatedWorlds = new Map(); - - this._webSocketEventService = Cc[ - "@mozilla.org/websocketevent/service;1" - ].getService(Ci.nsIWebSocketEventService); - - this._runtime = new Runtime(false /* isWorker */); - this._workers = new Map(); - this._docShellToFrame = new Map(); - this._frameIdToFrame = new Map(); - this._pageReady = false; - this._mainFrame = this._createFrame(rootDocShell); - const webProgress = rootDocShell.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebProgress); - this.QueryInterface = ChromeUtils.generateQI([ - Ci.nsIWebProgressListener, - Ci.nsIWebProgressListener2, - Ci.nsISupportsWeakReference, - ]); - - this._addedScrollbarsStylesheetSymbol = Symbol('_addedScrollbarsStylesheetSymbol'); - - this._wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].createInstance(Ci.nsIWorkerDebuggerManager); - this._wdmListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerManagerListener]), - onRegister: this._onWorkerCreated.bind(this), - onUnregister: this._onWorkerDestroyed.bind(this), - }; - this._wdm.addListener(this._wdmListener); - for (const workerDebugger of this._wdm.getWorkerDebuggerEnumerator()) - this._onWorkerCreated(workerDebugger); - - const flags = Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT | - Ci.nsIWebProgress.NOTIFY_LOCATION; - this._eventListeners = [ - helper.addObserver(this._onDOMWindowCreated.bind(this), 'content-document-global-created'), - helper.addObserver(this._onDOMWindowCreated.bind(this), 'juggler-dom-window-reused'), - helper.addObserver(subject => this._onDocShellCreated(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-create'), - helper.addObserver(subject => this._onDocShellDestroyed(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-destroy'), - helper.addProgressListener(webProgress, this, flags), - ]; - } - - workers() { - return [...this._workers.values()]; - } - - runtime() { - return this._runtime; - } - - setInitScripts(scripts) { - for (const world of this._isolatedWorlds.values()) - world._scriptsToEvaluateOnNewDocument = []; - - for (let { worldName, script } of scripts) { - worldName = worldName || ''; - const existing = this._isolatedWorlds.has(worldName); - const world = this._ensureWorld(worldName); - world._scriptsToEvaluateOnNewDocument.push(script); - // FIXME: 'should inherit http credentials from browser context' fails without this - if (worldName && !existing) { - for (const frame of this.frames()) - frame._createIsolatedContext(worldName); - } - } - } - - _ensureWorld(worldName) { - worldName = worldName || ''; - let world = this._isolatedWorlds.get(worldName); - if (!world) { - world = new IsolatedWorld(worldName); - this._isolatedWorlds.set(worldName, world); - } - return world; - } - - _frameForWorker(workerDebugger) { - if (workerDebugger.type !== Ci.nsIWorkerDebugger.TYPE_DEDICATED) - return null; - if (!workerDebugger.window) - return null; - const docShell = workerDebugger.window.docShell; - return this._docShellToFrame.get(docShell) || null; - } - - _onDOMWindowCreated(window) { - if (!window[this._addedScrollbarsStylesheetSymbol] && this.scrollbarsHidden) { - const styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); - const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); - const uri = ioService.newURI('chrome://juggler/content/content/hidden-scrollbars.css', null, null); - const sheet = styleSheetService.preloadSheet(uri, styleSheetService.AGENT_SHEET); - window.windowUtils.addSheet(sheet, styleSheetService.AGENT_SHEET); - window[this._addedScrollbarsStylesheetSymbol] = true; - } - const frame = this._docShellToFrame.get(window.docShell) || null; - if (!frame) - return; - frame._onGlobalObjectCleared(); - } - - setScrollbarsHidden(hidden) { - this.scrollbarsHidden = hidden; - } - - _onWorkerCreated(workerDebugger) { - // Note: we do not interoperate with firefox devtools. - if (workerDebugger.isInitialized) - return; - const frame = this._frameForWorker(workerDebugger); - if (!frame) - return; - const worker = new Worker(frame, workerDebugger); - this._workers.set(workerDebugger, worker); - this.emit(FrameTree.Events.WorkerCreated, worker); - } - - _onWorkerDestroyed(workerDebugger) { - const worker = this._workers.get(workerDebugger); - if (!worker) - return; - worker.dispose(); - this._workers.delete(workerDebugger); - this.emit(FrameTree.Events.WorkerDestroyed, worker); - } - - allFramesInBrowsingContextGroup(group) { - const frames = []; - for (const frameTree of (group.__jugglerFrameTrees || [])) - frames.push(...frameTree.frames()); - return frames; - } - - isPageReady() { - return this._pageReady; - } - - forcePageReady() { - if (this._pageReady) - return false; - this._pageReady = true; - this.emit(FrameTree.Events.PageReady); - return true; - } - - addBinding(worldName, name, script) { - worldName = worldName || ''; - const world = this._ensureWorld(worldName); - world._bindings.set(name, script); - for (const frame of this.frames()) - frame._addBinding(worldName, name, script); - } - - frameForDocShell(docShell) { - return this._docShellToFrame.get(docShell) || null; - } - - frame(frameId) { - return this._frameIdToFrame.get(frameId) || null; - } - - frames() { - let result = []; - collect(this._mainFrame); - return result; - - function collect(frame) { - result.push(frame); - for (const subframe of frame._children) - collect(subframe); - } - } - - mainFrame() { - return this._mainFrame; - } - - dispose() { - this._browsingContextGroup.__jugglerFrameTrees.delete(this); - this._wdm.removeListener(this._wdmListener); - this._runtime.dispose(); - helper.removeListeners(this._eventListeners); - } - - onStateChange(progress, request, flag, status) { - if (!(request instanceof Ci.nsIChannel)) - return; - const channel = request.QueryInterface(Ci.nsIChannel); - const docShell = progress.DOMWindow.docShell; - const frame = this._docShellToFrame.get(docShell); - if (!frame) { - dump(`ERROR: got a state changed event for un-tracked docshell!\n`); - return; - } - - if (!channel.isDocument) { - // Somehow, we can get worker requests here, - // while we are only interested in frame documents. - return; - } - - const isStart = flag & Ci.nsIWebProgressListener.STATE_START; - const isTransferring = flag & Ci.nsIWebProgressListener.STATE_TRANSFERRING; - const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP; - const isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT; - - if (isStart) { - // Starting a new navigation. - frame._pendingNavigationId = channelId(channel); - frame._pendingNavigationURL = channel.URI.spec; - this.emit(FrameTree.Events.NavigationStarted, frame); - } else if (isTransferring || (isStop && frame._pendingNavigationId && !status)) { - // Navigation is committed. - for (const subframe of frame._children) - this._detachFrame(subframe); - const navigationId = frame._pendingNavigationId; - frame._pendingNavigationId = null; - frame._pendingNavigationURL = null; - frame._lastCommittedNavigationId = navigationId; - frame._url = channel.URI.spec; - this.emit(FrameTree.Events.NavigationCommitted, frame); - if (frame === this._mainFrame) - this.forcePageReady(); - } else if (isStop && frame._pendingNavigationId && status) { - // Navigation is aborted. - const navigationId = frame._pendingNavigationId; - frame._pendingNavigationId = null; - frame._pendingNavigationURL = null; - // Always report download navigation as failure to match other browsers. - const errorText = helper.getNetworkErrorStatusText(status); - this.emit(FrameTree.Events.NavigationAborted, frame, navigationId, errorText); - if (frame === this._mainFrame && status !== Cr.NS_BINDING_ABORTED) - this.forcePageReady(); - } - - if (isStop && isDocument) - this.emit(FrameTree.Events.Load, frame); - } - - onLocationChange(progress, request, location, flags) { - const docShell = progress.DOMWindow.docShell; - const frame = this._docShellToFrame.get(docShell); - const sameDocumentNavigation = !!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT); - if (frame && sameDocumentNavigation) { - frame._url = location.spec; - this.emit(FrameTree.Events.SameDocumentNavigation, frame); - } - } - - _onDocShellCreated(docShell) { - // Bug 1142752: sometimes, the docshell appears to be immediately - // destroyed, bailout early to prevent random exceptions. - if (docShell.isBeingDestroyed()) - return; - // If this docShell doesn't belong to our frame tree - do nothing. - let root = docShell; - while (root.parent) - root = root.parent; - if (root === this._mainFrame._docShell) - this._createFrame(docShell); - } - - _createFrame(docShell) { - const parentFrame = this._docShellToFrame.get(docShell.parent) || null; - const frame = new Frame(this, this._runtime, docShell, parentFrame); - this._docShellToFrame.set(docShell, frame); - this._frameIdToFrame.set(frame.id(), frame); - this.emit(FrameTree.Events.FrameAttached, frame); - // Create execution context **after** reporting frame. - // This is our protocol contract. - if (frame.domWindow()) - frame._onGlobalObjectCleared(); - return frame; - } - - _onDocShellDestroyed(docShell) { - const frame = this._docShellToFrame.get(docShell); - if (frame) - this._detachFrame(frame); - } - - _detachFrame(frame) { - // Detach all children first - for (const subframe of frame._children) - this._detachFrame(subframe); - this._docShellToFrame.delete(frame._docShell); - this._frameIdToFrame.delete(frame.id()); - if (frame._parentFrame) - frame._parentFrame._children.delete(frame); - frame._parentFrame = null; - frame.dispose(); - this.emit(FrameTree.Events.FrameDetached, frame); - } -} - -FrameTree.Events = { - FrameAttached: 'frameattached', - FrameDetached: 'framedetached', - WorkerCreated: 'workercreated', - WorkerDestroyed: 'workerdestroyed', - WebSocketCreated: 'websocketcreated', - WebSocketOpened: 'websocketopened', - WebSocketClosed: 'websocketclosed', - WebSocketFrameReceived: 'websocketframereceived', - WebSocketFrameSent: 'websocketframesent', - NavigationStarted: 'navigationstarted', - NavigationCommitted: 'navigationcommitted', - NavigationAborted: 'navigationaborted', - SameDocumentNavigation: 'samedocumentnavigation', - PageReady: 'pageready', - Load: 'load', -}; - -class IsolatedWorld { - constructor(name) { - this._name = name; - this._scriptsToEvaluateOnNewDocument = []; - this._bindings = new Map(); - } -} - -class Frame { - constructor(frameTree, runtime, docShell, parentFrame) { - this._frameTree = frameTree; - this._runtime = runtime; - this._docShell = docShell; - this._children = new Set(); - this._frameId = helper.browsingContextToFrameId(this._docShell.browsingContext); - this._parentFrame = null; - this._url = ''; - if (docShell.domWindow && docShell.domWindow.location) - this._url = docShell.domWindow.location.href; - if (parentFrame) { - this._parentFrame = parentFrame; - parentFrame._children.add(this); - } - - this._lastCommittedNavigationId = null; - this._pendingNavigationId = null; - this._pendingNavigationURL = null; - - this._textInputProcessor = null; - - this._worldNameToContext = new Map(); - this._initialNavigationDone = false; - - this._webSocketListenerInnerWindowId = 0; - // WebSocketListener calls frameReceived event before webSocketOpened. - // To avoid this, serialize event reporting. - this._webSocketInfos = new Map(); - - const dispatchWebSocketFrameReceived = (webSocketSerialID, frame) => this._frameTree.emit(FrameTree.Events.WebSocketFrameReceived, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - opcode: frame.opCode, - data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload, - }); - this._webSocketListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketEventListener, ]), - - webSocketCreated: (webSocketSerialID, uri, protocols) => { - this._frameTree.emit(FrameTree.Events.WebSocketCreated, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - requestURL: uri, - }); - this._webSocketInfos.set(webSocketSerialID, { - opened: false, - pendingIncomingFrames: [], - }); - }, - - webSocketOpened: (webSocketSerialID, effectiveURI, protocols, extensions, httpChannelId) => { - this._frameTree.emit(FrameTree.Events.WebSocketOpened, { - frameId: this._frameId, - requestId: httpChannelId + '', - wsid: webSocketSerialID + '', - effectiveURL: effectiveURI, - }); - const info = this._webSocketInfos.get(webSocketSerialID); - info.opened = true; - for (const frame of info.pendingIncomingFrames) - dispatchWebSocketFrameReceived(webSocketSerialID, frame); - }, - - webSocketMessageAvailable: (webSocketSerialID, data, messageType) => { - // We don't use this event. - }, - - webSocketClosed: (webSocketSerialID, wasClean, code, reason) => { - this._webSocketInfos.delete(webSocketSerialID); - let error = ''; - if (!wasClean) { - const keys = Object.keys(Ci.nsIWebSocketChannel); - for (const key of keys) { - if (Ci.nsIWebSocketChannel[key] === code) - error = key; - } - } - this._frameTree.emit(FrameTree.Events.WebSocketClosed, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - error, - }); - }, - - frameReceived: (webSocketSerialID, frame) => { - // Report only text and binary frames. - if (frame.opCode !== 1 && frame.opCode !== 2) - return; - const info = this._webSocketInfos.get(webSocketSerialID); - if (info.opened) - dispatchWebSocketFrameReceived(webSocketSerialID, frame); - else - info.pendingIncomingFrames.push(frame); - }, - - frameSent: (webSocketSerialID, frame) => { - // Report only text and binary frames. - if (frame.opCode !== 1 && frame.opCode !== 2) - return; - this._frameTree.emit(FrameTree.Events.WebSocketFrameSent, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - opcode: frame.opCode, - data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload, - }); - }, - }; - } - - _createIsolatedContext(name) { - const principal = [this.domWindow()]; // extended principal - const sandbox = Cu.Sandbox(principal, { - sandboxPrototype: this.domWindow(), - wantComponents: false, - wantExportHelpers: false, - wantXrays: true, - }); - const world = this._runtime.createExecutionContext(this.domWindow(), sandbox, { - frameId: this.id(), - name, - }); - this._worldNameToContext.set(name, world); - return world; - } - - unsafeObject(objectId) { - for (const context of this._worldNameToContext.values()) { - const result = context.unsafeObject(objectId); - if (result) - return result.object; - } - throw new Error('Cannot find object with id = ' + objectId); - } - - dispose() { - for (const context of this._worldNameToContext.values()) - this._runtime.destroyExecutionContext(context); - this._worldNameToContext.clear(); - } - - _addBinding(worldName, name, script) { - let executionContext = this._worldNameToContext.get(worldName); - if (worldName && !executionContext) - executionContext = this._createIsolatedContext(worldName); - if (executionContext) - executionContext.addBinding(name, script); - } - - _onGlobalObjectCleared() { - const webSocketService = this._frameTree._webSocketEventService; - if (this._webSocketListenerInnerWindowId) - webSocketService.removeListener(this._webSocketListenerInnerWindowId, this._webSocketListener); - this._webSocketListenerInnerWindowId = this.domWindow().windowGlobalChild.innerWindowId; - webSocketService.addListener(this._webSocketListenerInnerWindowId, this._webSocketListener); - - for (const context of this._worldNameToContext.values()) - this._runtime.destroyExecutionContext(context); - this._worldNameToContext.clear(); - - this._worldNameToContext.set('', this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), { - frameId: this._frameId, - name: '', - })); - for (const [name, world] of this._frameTree._isolatedWorlds) { - if (name) - this._createIsolatedContext(name); - const executionContext = this._worldNameToContext.get(name); - // Add bindings before evaluating scripts. - for (const [name, script] of world._bindings) - executionContext.addBinding(name, script); - for (const script of world._scriptsToEvaluateOnNewDocument) - executionContext.evaluateScriptSafely(script); - } - } - - mainExecutionContext() { - return this._worldNameToContext.get(''); - } - - textInputProcessor() { - if (!this._textInputProcessor) { - this._textInputProcessor = Cc["@mozilla.org/text-input-processor;1"].createInstance(Ci.nsITextInputProcessor); - } - this._textInputProcessor.beginInputTransactionForTests(this._docShell.DOMWindow); - return this._textInputProcessor; - } - - pendingNavigationId() { - return this._pendingNavigationId; - } - - pendingNavigationURL() { - return this._pendingNavigationURL; - } - - lastCommittedNavigationId() { - return this._lastCommittedNavigationId; - } - - docShell() { - return this._docShell; - } - - domWindow() { - return this._docShell.domWindow; - } - - name() { - const frameElement = this._docShell.domWindow.frameElement; - let name = ''; - if (frameElement) - name = frameElement.getAttribute('name') || frameElement.getAttribute('id') || ''; - return name; - } - - parentFrame() { - return this._parentFrame; - } - - id() { - return this._frameId; - } - - url() { - return this._url; - } - -} - -class Worker { - constructor(frame, workerDebugger) { - this._frame = frame; - this._workerId = helper.generateId(); - this._workerDebugger = workerDebugger; - - workerDebugger.initialize('chrome://juggler/content/content/WorkerMain.js'); - - this._channel = new SimpleChannel(`content::worker[${this._workerId}]`); - this._channel.setTransport({ - sendMessage: obj => workerDebugger.postMessage(JSON.stringify(obj)), - dispose: () => {}, - }); - this._workerDebuggerListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerListener]), - onMessage: msg => void this._channel._onMessage(JSON.parse(msg)), - onClose: () => void this._channel.dispose(), - onError: (filename, lineno, message) => { - dump(`Error in worker: ${message} @${filename}:${lineno}\n`); - }, - }; - workerDebugger.addListener(this._workerDebuggerListener); - } - - channel() { - return this._channel; - } - - frame() { - return this._frame; - } - - id() { - return this._workerId; - } - - url() { - return this._workerDebugger.url; - } - - dispose() { - this._channel.dispose(); - this._workerDebugger.removeListener(this._workerDebuggerListener); - } -} - -function channelId(channel) { - if (channel instanceof Ci.nsIIdentChannel) { - const identChannel = channel.QueryInterface(Ci.nsIIdentChannel); - return String(identChannel.channelId); - } - return helper.generateId(); -} - - -var EXPORTED_SYMBOLS = ['FrameTree']; -this.FrameTree = FrameTree; - diff --git a/browser_patches/firefox-beta/juggler/content/PageAgent.js b/browser_patches/firefox-beta/juggler/content/PageAgent.js deleted file mode 100644 index 63a1807e4d..0000000000 --- a/browser_patches/firefox-beta/juggler/content/PageAgent.js +++ /dev/null @@ -1,894 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -const dragService = Cc["@mozilla.org/widget/dragservice;1"].getService( - Ci.nsIDragService -); -const obs = Cc["@mozilla.org/observer-service;1"].getService( - Ci.nsIObserverService -); - -const helper = new Helper(); - -class WorkerData { - constructor(pageAgent, browserChannel, worker) { - this._workerRuntime = worker.channel().connect('runtime'); - this._browserWorker = browserChannel.connect(worker.id()); - this._worker = worker; - const emit = name => { - return (...args) => this._browserWorker.emit(name, ...args); - }; - this._eventListeners = [ - worker.channel().register('runtime', { - runtimeConsole: emit('runtimeConsole'), - runtimeExecutionContextCreated: emit('runtimeExecutionContextCreated'), - runtimeExecutionContextDestroyed: emit('runtimeExecutionContextDestroyed'), - }), - browserChannel.register(worker.id(), { - evaluate: (options) => this._workerRuntime.send('evaluate', options), - callFunction: (options) => this._workerRuntime.send('callFunction', options), - getObjectProperties: (options) => this._workerRuntime.send('getObjectProperties', options), - disposeObject: (options) => this._workerRuntime.send('disposeObject', options), - }), - ]; - } - - dispose() { - this._workerRuntime.dispose(); - this._browserWorker.dispose(); - helper.removeListeners(this._eventListeners); - } -} - -class PageAgent { - constructor(messageManager, browserChannel, frameTree) { - this._messageManager = messageManager; - this._browserChannel = browserChannel; - this._browserPage = browserChannel.connect('page'); - this._frameTree = frameTree; - this._runtime = frameTree.runtime(); - - this._workerData = new Map(); - - const docShell = frameTree.mainFrame().docShell(); - this._docShell = docShell; - this._initialDPPX = docShell.contentViewer.overrideDPPX; - this._dragging = false; - - // Dispatch frameAttached events for all initial frames - for (const frame of this._frameTree.frames()) { - this._onFrameAttached(frame); - if (frame.url()) - this._onNavigationCommitted(frame); - if (frame.pendingNavigationId()) - this._onNavigationStarted(frame); - } - - // Report created workers. - for (const worker of this._frameTree.workers()) - this._onWorkerCreated(worker); - - // Report execution contexts. - for (const context of this._runtime.executionContexts()) - this._onExecutionContextCreated(context); - - if (this._frameTree.isPageReady()) { - this._browserPage.emit('pageReady', {}); - const mainFrame = this._frameTree.mainFrame(); - const domWindow = mainFrame.domWindow(); - const document = domWindow ? domWindow.document : null; - const readyState = document ? document.readyState : null; - // Sometimes we initialize later than the first about:blank page is opened. - // In this case, the page might've been loaded already, and we need to issue - // the `DOMContentLoaded` and `load` events. - if (mainFrame.url() === 'about:blank' && readyState === 'complete') - this._emitAllEvents(this._frameTree.mainFrame()); - } - - this._eventListeners = [ - helper.addObserver(this._linkClicked.bind(this, false), 'juggler-link-click'), - helper.addObserver(this._linkClicked.bind(this, true), 'juggler-link-click-sync'), - helper.addObserver(this._onWindowOpenInNewContext.bind(this), 'juggler-window-open-in-new-context'), - helper.addObserver(this._filePickerShown.bind(this), 'juggler-file-picker-shown'), - helper.addEventListener(this._messageManager, 'DOMContentLoaded', this._onDOMContentLoaded.bind(this)), - helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'), - helper.on(this._frameTree, 'load', this._onLoad.bind(this)), - helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)), - helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)), - helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)), - helper.on(this._frameTree, 'navigationcommitted', this._onNavigationCommitted.bind(this)), - helper.on(this._frameTree, 'navigationaborted', this._onNavigationAborted.bind(this)), - helper.on(this._frameTree, 'samedocumentnavigation', this._onSameDocumentNavigation.bind(this)), - helper.on(this._frameTree, 'pageready', () => this._browserPage.emit('pageReady', {})), - helper.on(this._frameTree, 'workercreated', this._onWorkerCreated.bind(this)), - helper.on(this._frameTree, 'workerdestroyed', this._onWorkerDestroyed.bind(this)), - helper.on(this._frameTree, 'websocketcreated', event => this._browserPage.emit('webSocketCreated', event)), - helper.on(this._frameTree, 'websocketopened', event => this._browserPage.emit('webSocketOpened', event)), - helper.on(this._frameTree, 'websocketframesent', event => this._browserPage.emit('webSocketFrameSent', event)), - helper.on(this._frameTree, 'websocketframereceived', event => this._browserPage.emit('webSocketFrameReceived', event)), - helper.on(this._frameTree, 'websocketclosed', event => this._browserPage.emit('webSocketClosed', event)), - helper.addObserver(this._onWindowOpen.bind(this), 'webNavigation-createdNavigationTarget-from-js'), - this._runtime.events.onErrorFromWorker((domWindow, message, stack) => { - const frame = this._frameTree.frameForDocShell(domWindow.docShell); - if (!frame) - return; - this._browserPage.emit('pageUncaughtError', { - frameId: frame.id(), - message, - stack, - }); - }), - this._runtime.events.onConsoleMessage(msg => this._browserPage.emit('runtimeConsole', msg)), - this._runtime.events.onRuntimeError(this._onRuntimeError.bind(this)), - this._runtime.events.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)), - this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)), - this._runtime.events.onBindingCalled(this._onBindingCalled.bind(this)), - browserChannel.register('page', { - addBinding: ({ worldName, name, script }) => this._frameTree.addBinding(worldName, name, script), - adoptNode: this._adoptNode.bind(this), - crash: this._crash.bind(this), - describeNode: this._describeNode.bind(this), - dispatchKeyEvent: this._dispatchKeyEvent.bind(this), - dispatchMouseEvent: this._dispatchMouseEvent.bind(this), - dispatchTouchEvent: this._dispatchTouchEvent.bind(this), - dispatchTapEvent: this._dispatchTapEvent.bind(this), - getContentQuads: this._getContentQuads.bind(this), - getFullAXTree: this._getFullAXTree.bind(this), - goBack: this._goBack.bind(this), - goForward: this._goForward.bind(this), - insertText: this._insertText.bind(this), - navigate: this._navigate.bind(this), - reload: this._reload.bind(this), - scrollIntoViewIfNeeded: this._scrollIntoViewIfNeeded.bind(this), - setCacheDisabled: this._setCacheDisabled.bind(this), - setFileInputFiles: this._setFileInputFiles.bind(this), - setInterceptFileChooserDialog: this._setInterceptFileChooserDialog.bind(this), - evaluate: this._runtime.evaluate.bind(this._runtime), - callFunction: this._runtime.callFunction.bind(this._runtime), - getObjectProperties: this._runtime.getObjectProperties.bind(this._runtime), - disposeObject: this._runtime.disposeObject.bind(this._runtime), - }), - ]; - } - - _setCacheDisabled({cacheDisabled}) { - const enable = Ci.nsIRequest.LOAD_NORMAL; - const disable = Ci.nsIRequest.LOAD_BYPASS_CACHE | - Ci.nsIRequest.INHIBIT_CACHING; - - const docShell = this._frameTree.mainFrame().docShell(); - docShell.defaultLoadFlags = cacheDisabled ? disable : enable; - } - - _emitAllEvents(frame) { - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'DOMContentLoaded', - }); - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load', - }); - } - - _onExecutionContextCreated(executionContext) { - this._browserPage.emit('runtimeExecutionContextCreated', { - executionContextId: executionContext.id(), - auxData: executionContext.auxData(), - }); - } - - _onExecutionContextDestroyed(executionContext) { - this._browserPage.emit('runtimeExecutionContextDestroyed', { - executionContextId: executionContext.id(), - }); - } - - _onWorkerCreated(worker) { - const workerData = new WorkerData(this, this._browserChannel, worker); - this._workerData.set(worker.id(), workerData); - this._browserPage.emit('pageWorkerCreated', { - workerId: worker.id(), - frameId: worker.frame().id(), - url: worker.url(), - }); - } - - _onWorkerDestroyed(worker) { - const workerData = this._workerData.get(worker.id()); - if (!workerData) - return; - this._workerData.delete(worker.id()); - workerData.dispose(); - this._browserPage.emit('pageWorkerDestroyed', { - workerId: worker.id(), - }); - } - - _onWindowOpen(subject) { - if (!(subject instanceof Ci.nsIPropertyBag2)) - return; - const props = subject.QueryInterface(Ci.nsIPropertyBag2); - const hasUrl = props.hasKey('url'); - const createdDocShell = props.getPropertyAsInterface('createdTabDocShell', Ci.nsIDocShell); - if (!hasUrl && createdDocShell === this._docShell && this._frameTree.forcePageReady()) - this._emitAllEvents(this._frameTree.mainFrame()); - } - - _setInterceptFileChooserDialog({enabled}) { - this._docShell.fileInputInterceptionEnabled = !!enabled; - } - - _linkClicked(sync, anchorElement) { - if (anchorElement.ownerGlobal.docShell !== this._docShell) - return; - this._browserPage.emit('pageLinkClicked', { phase: sync ? 'after' : 'before' }); - } - - _onWindowOpenInNewContext(docShell) { - // TODO: unify this with _onWindowOpen if possible. - const frame = this._frameTree.frameForDocShell(docShell); - if (!frame) - return; - this._browserPage.emit('pageWillOpenNewWindowAsynchronously'); - } - - _filePickerShown(inputElement) { - const frame = this._findFrameForNode(inputElement); - if (!frame) - return; - this._browserPage.emit('pageFileChooserOpened', { - executionContextId: frame.mainExecutionContext().id(), - element: frame.mainExecutionContext().rawValueToRemoteObject(inputElement) - }); - } - - _findFrameForNode(node) { - return this._frameTree.frames().find(frame => { - const doc = frame.domWindow().document; - return node === doc || node.ownerDocument === doc; - }); - } - - _onDOMContentLoaded(event) { - if (!event.target.ownerGlobal) - return; - const docShell = event.target.ownerGlobal.docShell; - const frame = this._frameTree.frameForDocShell(docShell); - if (!frame) - return; - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'DOMContentLoaded', - }); - } - - _onRuntimeError({ executionContext, message, stack }) { - this._browserPage.emit('pageUncaughtError', { - frameId: executionContext.auxData().frameId, - message: message.toString(), - stack: stack.toString(), - }); - } - - _onDocumentOpenLoad(document) { - const docShell = document.ownerGlobal.docShell; - const frame = this._frameTree.frameForDocShell(docShell); - if (!frame) - return; - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load' - }); - } - - _onLoad(frame) { - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load' - }); - } - - _onNavigationStarted(frame) { - this._browserPage.emit('pageNavigationStarted', { - frameId: frame.id(), - navigationId: frame.pendingNavigationId(), - url: frame.pendingNavigationURL(), - }); - } - - _onNavigationAborted(frame, navigationId, errorText) { - this._browserPage.emit('pageNavigationAborted', { - frameId: frame.id(), - navigationId, - errorText, - }); - if (!frame._initialNavigationDone && frame !== this._frameTree.mainFrame()) - this._emitAllEvents(frame); - frame._initialNavigationDone = true; - } - - _onSameDocumentNavigation(frame) { - this._browserPage.emit('pageSameDocumentNavigation', { - frameId: frame.id(), - url: frame.url(), - }); - } - - _onNavigationCommitted(frame) { - this._browserPage.emit('pageNavigationCommitted', { - frameId: frame.id(), - navigationId: frame.lastCommittedNavigationId() || undefined, - url: frame.url(), - name: frame.name(), - }); - frame._initialNavigationDone = true; - } - - _onFrameAttached(frame) { - this._browserPage.emit('pageFrameAttached', { - frameId: frame.id(), - parentFrameId: frame.parentFrame() ? frame.parentFrame().id() : undefined, - }); - } - - _onFrameDetached(frame) { - this._browserPage.emit('pageFrameDetached', { - frameId: frame.id(), - }); - } - - _onBindingCalled({executionContextId, name, payload}) { - this._browserPage.emit('pageBindingCalled', { - executionContextId, - name, - payload - }); - } - - dispose() { - for (const workerData of this._workerData.values()) - workerData.dispose(); - this._workerData.clear(); - helper.removeListeners(this._eventListeners); - } - - async _navigate({frameId, url, referer}) { - try { - const uri = NetUtil.newURI(url); - } catch (e) { - throw new Error(`Invalid url: "${url}"`); - } - let referrerURI = null; - let referrerInfo = null; - if (referer) { - try { - referrerURI = NetUtil.newURI(referer); - const ReferrerInfo = Components.Constructor( - '@mozilla.org/referrer-info;1', - 'nsIReferrerInfo', - 'init' - ); - referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, referrerURI); - } catch (e) { - throw new Error(`Invalid referer: "${referer}"`); - } - } - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell().QueryInterface(Ci.nsIWebNavigation); - docShell.loadURI(url, { - triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), - flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE, - referrerInfo, - postData: null, - headers: null, - }); - return {navigationId: frame.pendingNavigationId(), navigationURL: frame.pendingNavigationURL()}; - } - - async _reload({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell().QueryInterface(Ci.nsIWebNavigation); - docShell.reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); - } - - async _goBack({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell(); - if (!docShell.canGoBack) - return {success: false}; - docShell.goBack(); - return {success: true}; - } - - async _goForward({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell(); - if (!docShell.canGoForward) - return {success: false}; - docShell.goForward(); - return {success: true}; - } - - async _adoptNode({frameId, objectId, executionContextId}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - const context = this._runtime.findExecutionContext(executionContextId); - const fromPrincipal = unsafeObject.nodePrincipal; - const toFrame = this._frameTree.frame(context.auxData().frameId); - const toPrincipal = toFrame.domWindow().document.nodePrincipal; - if (!toPrincipal.subsumes(fromPrincipal)) - return { remoteObject: null }; - return { remoteObject: context.rawValueToRemoteObject(unsafeObject) }; - } - - async _setFileInputFiles({objectId, frameId, files}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - if (!unsafeObject) - throw new Error('Object is not input!'); - const nsFiles = await Promise.all(files.map(filePath => File.createFromFileName(filePath))); - unsafeObject.mozSetFileArray(nsFiles); - } - - _getContentQuads({objectId, frameId}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - if (!unsafeObject.getBoxQuads) - throw new Error('RemoteObject is not a node'); - const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document, recurseWhenNoFrame: true}).map(quad => { - return { - p1: {x: quad.p1.x, y: quad.p1.y}, - p2: {x: quad.p2.x, y: quad.p2.y}, - p3: {x: quad.p3.x, y: quad.p3.y}, - p4: {x: quad.p4.x, y: quad.p4.y}, - }; - }); - return {quads}; - } - - _describeNode({objectId, frameId}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - const browsingContextGroup = frame.docShell().browsingContext.group; - const frames = this._frameTree.allFramesInBrowsingContextGroup(browsingContextGroup); - let contentFrame; - let ownerFrame; - for (const frame of frames) { - if (unsafeObject.contentWindow && frame.docShell() === unsafeObject.contentWindow.docShell) - contentFrame = frame; - const document = frame.domWindow().document; - if (unsafeObject === document || unsafeObject.ownerDocument === document) - ownerFrame = frame; - } - return { - contentFrameId: contentFrame ? contentFrame.id() : undefined, - ownerFrameId: ownerFrame ? ownerFrame.id() : undefined, - }; - } - - async _scrollIntoViewIfNeeded({objectId, frameId, rect}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - if (!unsafeObject.isConnected) - throw new Error('Node is detached from document'); - if (!rect) - rect = { x: -1, y: -1, width: -1, height: -1}; - if (unsafeObject.scrollRectIntoViewIfNeeded) - unsafeObject.scrollRectIntoViewIfNeeded(rect.x, rect.y, rect.width, rect.height); - else - throw new Error('Node does not have a layout object'); - } - - _getNodeBoundingBox(unsafeObject) { - if (!unsafeObject.getBoxQuads) - throw new Error('RemoteObject is not a node'); - const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document}); - if (!quads.length) - return; - let x1 = Infinity; - let y1 = Infinity; - let x2 = -Infinity; - let y2 = -Infinity; - for (const quad of quads) { - const boundingBox = quad.getBounds(); - x1 = Math.min(boundingBox.x, x1); - y1 = Math.min(boundingBox.y, y1); - x2 = Math.max(boundingBox.x + boundingBox.width, x2); - y2 = Math.max(boundingBox.y + boundingBox.height, y2); - } - return {x: x1, y: y1, width: x2 - x1, height: y2 - y1}; - } - - async _dispatchKeyEvent({type, keyCode, code, key, repeat, location, text}) { - // key events don't fire if we are dragging. - if (this._dragging) { - if (type === 'keydown' && key === 'Escape') - this._cancelDragIfNeeded(); - return; - } - const frame = this._frameTree.mainFrame(); - const tip = frame.textInputProcessor(); - if (key === 'Meta' && Services.appinfo.OS !== 'Darwin') - key = 'OS'; - else if (key === 'OS' && Services.appinfo.OS === 'Darwin') - key = 'Meta'; - let keyEvent = new (frame.domWindow().KeyboardEvent)("", { - key, - code, - location, - repeat, - keyCode - }); - if (type === 'keydown') { - if (text && text !== key) { - tip.commitCompositionWith(text, keyEvent); - } else { - const flags = 0; - tip.keydown(keyEvent, flags); - } - } else if (type === 'keyup') { - if (text) - throw new Error(`keyup does not support text option`); - const flags = 0; - tip.keyup(keyEvent, flags); - } else { - throw new Error(`Unknown type ${type}`); - } - } - - async _dispatchTouchEvent({type, touchPoints, modifiers}) { - const frame = this._frameTree.mainFrame(); - const defaultPrevented = frame.domWindow().windowUtils.sendTouchEvent( - type.toLowerCase(), - touchPoints.map((point, id) => id), - touchPoints.map(point => point.x), - touchPoints.map(point => point.y), - touchPoints.map(point => point.radiusX === undefined ? 1.0 : point.radiusX), - touchPoints.map(point => point.radiusY === undefined ? 1.0 : point.radiusY), - touchPoints.map(point => point.rotationAngle === undefined ? 0.0 : point.rotationAngle), - touchPoints.map(point => point.force === undefined ? 1.0 : point.force), - touchPoints.length, - modifiers); - return {defaultPrevented}; - } - - async _dispatchTapEvent({x, y, modifiers}) { - // Force a layout at the point in question, because touch events - // do not seem to trigger one like mouse events. - this._frameTree.mainFrame().domWindow().windowUtils.elementFromPoint( - x, - y, - false /* aIgnoreRootScrollFrame */, - true /* aFlushLayout */); - - const {defaultPrevented: startPrevented} = await this._dispatchTouchEvent({ - type: 'touchstart', - modifiers, - touchPoints: [{x, y}] - }); - const {defaultPrevented: endPrevented} = await this._dispatchTouchEvent({ - type: 'touchend', - modifiers, - touchPoints: [{x, y}] - }); - if (startPrevented || endPrevented) - return; - - const frame = this._frameTree.mainFrame(); - frame.domWindow().windowUtils.sendMouseEvent( - 'mousemove', - x, - y, - 0 /*button*/, - 0 /*clickCount*/, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - 0 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - - frame.domWindow().windowUtils.sendMouseEvent( - 'mousedown', - x, - y, - 0 /*button*/, - 1 /*clickCount*/, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - 1 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - - frame.domWindow().windowUtils.sendMouseEvent( - 'mouseup', - x, - y, - 0 /*button*/, - 1 /*clickCount*/, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - 0 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - } - - _startDragSessionIfNeeded() { - const sess = dragService.getCurrentSession(); - if (sess) return; - dragService.startDragSessionForTests( - Ci.nsIDragService.DRAGDROP_ACTION_MOVE | - Ci.nsIDragService.DRAGDROP_ACTION_COPY | - Ci.nsIDragService.DRAGDROP_ACTION_LINK - ); - } - - _simulateDragEvent(type, x, y, modifiers) { - const window = this._frameTree.mainFrame().domWindow(); - const element = window.windowUtils.elementFromPoint(x, y, false, false); - const event = window.document.createEvent('DragEvent'); - - event.initDragEvent( - type, - true /* bubble */, - true /* cancelable */, - window, - 0 /* clickCount */, - window.mozInnerScreenX + x, - window.mozInnerScreenY + y, - x, - y, - modifiers & 2 /* ctrlkey */, - modifiers & 1 /* altKey */, - modifiers & 4 /* shiftKey */, - modifiers & 8 /* metaKey */, - 0 /* button */, // firefox always has the button as 0 on drops, regardless of which was pressed - null /* relatedTarget */, - null, - ); - if (type !== 'drop' || dragService.dragAction) - window.windowUtils.dispatchDOMEventViaPresShellForTesting(element, event); - if (type === 'drop') - this._cancelDragIfNeeded(); - } - - _cancelDragIfNeeded() { - this._dragging = false; - const sess = dragService.getCurrentSession(); - if (sess) - dragService.endDragSession(true); - } - - async _dispatchMouseEvent({type, x, y, button, clickCount, modifiers, buttons}) { - this._startDragSessionIfNeeded(); - const trapDrag = subject => { - this._dragging = true; - } - - // Don't send mouse events if there is an active drag - if (!this._dragging) { - const frame = this._frameTree.mainFrame(); - - obs.addObserver(trapDrag, 'on-datatransfer-available'); - frame.domWindow().windowUtils.sendMouseEvent( - type, - x, - y, - button, - clickCount, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - undefined /*inputSource*/, - true /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - buttons); - obs.removeObserver(trapDrag, 'on-datatransfer-available'); - - if (type === 'mousedown' && button === 2) { - frame.domWindow().windowUtils.sendMouseEvent( - 'contextmenu', - x, - y, - button, - clickCount, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - undefined /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - undefined /*isWidgetEventSynthesized*/, - buttons); - } - } - - // update drag state - if (this._dragging) { - if (type === 'mousemove') - this._simulateDragEvent('dragover', x, y, modifiers); - else if (type === 'mouseup') // firefox will do drops when any mouse button is released - this._simulateDragEvent('drop', x, y, modifiers); - } else { - this._cancelDragIfNeeded(); - } - } - - async _insertText({text}) { - const frame = this._frameTree.mainFrame(); - frame.textInputProcessor().commitCompositionWith(text); - } - - async _crash() { - dump(`Crashing intentionally\n`); - // This is to intentionally crash the frame. - // We crash by using js-ctypes and dereferencing - // a bad pointer. The crash should happen immediately - // upon loading this frame script. - const { ctypes } = ChromeUtils.import('resource://gre/modules/ctypes.jsm'); - ChromeUtils.privateNoteIntentionalCrash(); - const zero = new ctypes.intptr_t(8); - const badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t)); - badptr.contents; - } - - async _getFullAXTree({objectId}) { - let unsafeObject = null; - if (objectId) { - unsafeObject = this._frameTree.mainFrame().unsafeObject(objectId); - if (!unsafeObject) - throw new Error(`No object found for id "${objectId}"`); - } - - const service = Cc["@mozilla.org/accessibilityService;1"] - .getService(Ci.nsIAccessibilityService); - const document = this._frameTree.mainFrame().domWindow().document; - const docAcc = service.getAccessibleFor(document); - - while (docAcc.document.isUpdatePendingForJugglerAccessibility) - await new Promise(x => this._frameTree.mainFrame().domWindow().requestAnimationFrame(x)); - - async function waitForQuiet() { - let state = {}; - docAcc.getState(state, {}); - if ((state.value & Ci.nsIAccessibleStates.STATE_BUSY) == 0) - return; - let resolve, reject; - const promise = new Promise((x, y) => {resolve = x, reject = y}); - let eventObserver = { - observe(subject, topic) { - if (topic !== "accessible-event") { - return; - } - - // If event type does not match expected type, skip the event. - let event = subject.QueryInterface(Ci.nsIAccessibleEvent); - if (event.eventType !== Ci.nsIAccessibleEvent.EVENT_STATE_CHANGE) { - return; - } - - // If event's accessible does not match expected accessible, - // skip the event. - if (event.accessible !== docAcc) { - return; - } - - Services.obs.removeObserver(this, "accessible-event"); - resolve(); - }, - }; - Services.obs.addObserver(eventObserver, "accessible-event"); - return promise; - } - function buildNode(accElement) { - let a = {}, b = {}; - accElement.getState(a, b); - const tree = { - role: service.getStringRole(accElement.role), - name: accElement.name || '', - }; - if (unsafeObject && unsafeObject === accElement.DOMNode) - tree.foundObject = true; - for (const userStringProperty of [ - 'value', - 'description' - ]) { - tree[userStringProperty] = accElement[userStringProperty] || undefined; - } - - const states = {}; - for (const name of service.getStringStates(a.value, b.value)) - states[name] = true; - for (const name of ['selected', - 'focused', - 'pressed', - 'focusable', - 'required', - 'invalid', - 'modal', - 'editable', - 'busy', - 'checked', - 'multiselectable']) { - if (states[name]) - tree[name] = true; - } - - if (states['multi line']) - tree['multiline'] = true; - if (states['editable'] && states['readonly']) - tree['readonly'] = true; - if (states['checked']) - tree['checked'] = true; - if (states['mixed']) - tree['checked'] = 'mixed'; - if (states['expanded']) - tree['expanded'] = true; - else if (states['collapsed']) - tree['expanded'] = false; - if (!states['enabled']) - tree['disabled'] = true; - - const attributes = {}; - if (accElement.attributes) { - for (const { key, value } of accElement.attributes.enumerate()) { - attributes[key] = value; - } - } - for (const numericalProperty of ['level']) { - if (numericalProperty in attributes) - tree[numericalProperty] = parseFloat(attributes[numericalProperty]); - } - for (const stringProperty of ['tag', 'roledescription', 'valuetext', 'orientation', 'autocomplete', 'keyshortcuts', 'haspopup']) { - if (stringProperty in attributes) - tree[stringProperty] = attributes[stringProperty]; - } - const children = []; - - for (let child = accElement.firstChild; child; child = child.nextSibling) { - children.push(buildNode(child)); - } - if (children.length) - tree.children = children; - return tree; - } - await waitForQuiet(); - return { - tree: buildNode(docAcc) - }; - } -} - -var EXPORTED_SYMBOLS = ['PageAgent']; -this.PageAgent = PageAgent; - diff --git a/browser_patches/firefox-beta/juggler/content/Runtime.js b/browser_patches/firefox-beta/juggler/content/Runtime.js deleted file mode 100644 index 20c046a1db..0000000000 --- a/browser_patches/firefox-beta/juggler/content/Runtime.js +++ /dev/null @@ -1,596 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -// Note: this file should be loadabale with eval() into worker environment. -// Avoid Components.*, ChromeUtils and global const variables. - -if (!this.Debugger) { - // Worker has a Debugger defined already. - const {addDebuggerToGlobal} = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm", {}); - addDebuggerToGlobal(Components.utils.getGlobalForObject(this)); -} - -let lastId = 0; -function generateId() { - return 'id-' + (++lastId); -} - -const consoleLevelToProtocolType = { - 'dir': 'dir', - 'log': 'log', - 'debug': 'debug', - 'info': 'info', - 'error': 'error', - 'warn': 'warning', - 'dirxml': 'dirxml', - 'table': 'table', - 'trace': 'trace', - 'clear': 'clear', - 'group': 'startGroup', - 'groupCollapsed': 'startGroupCollapsed', - 'groupEnd': 'endGroup', - 'assert': 'assert', - 'profile': 'profile', - 'profileEnd': 'profileEnd', - 'count': 'count', - 'countReset': 'countReset', - 'time': null, - 'timeLog': 'timeLog', - 'timeEnd': 'timeEnd', - 'timeStamp': 'timeStamp', -}; - -const disallowedMessageCategories = new Set([ - 'XPConnect JavaScript', - 'component javascript', - 'chrome javascript', - 'chrome registration', - 'XBL', - 'XBL Prototype Handler', - 'XBL Content Sink', - 'xbl javascript', -]); - -class Runtime { - constructor(isWorker = false) { - this._debugger = new Debugger(); - this._pendingPromises = new Map(); - this._executionContexts = new Map(); - this._windowToExecutionContext = new Map(); - this._eventListeners = []; - if (isWorker) { - this._registerWorkerConsoleHandler(); - } else { - const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); - this._registerConsoleServiceListener(Services); - this._registerConsoleAPIListener(Services); - } - // We can't use event listener here to be compatible with Worker Global Context. - // Use plain callbacks instead. - this.events = { - onConsoleMessage: createEvent(), - onRuntimeError: createEvent(), - onErrorFromWorker: createEvent(), - onExecutionContextCreated: createEvent(), - onExecutionContextDestroyed: createEvent(), - onBindingCalled: createEvent(), - }; - } - - executionContexts() { - return [...this._executionContexts.values()]; - } - - async evaluate({executionContextId, expression, returnByValue}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - const exceptionDetails = {}; - let result = await executionContext.evaluateScript(expression, exceptionDetails); - if (!result) - return {exceptionDetails}; - if (returnByValue) - result = executionContext.ensureSerializedToValue(result); - return {result}; - } - - async callFunction({executionContextId, functionDeclaration, args, returnByValue}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - const exceptionDetails = {}; - let result = await executionContext.evaluateFunction(functionDeclaration, args, exceptionDetails); - if (!result) - return {exceptionDetails}; - if (returnByValue) - result = executionContext.ensureSerializedToValue(result); - return {result}; - } - - async getObjectProperties({executionContextId, objectId}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - return {properties: executionContext.getObjectProperties(objectId)}; - } - - async disposeObject({executionContextId, objectId}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - return executionContext.disposeObject(objectId); - } - - _registerConsoleServiceListener(Services) { - const Ci = Components.interfaces; - const consoleServiceListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIConsoleListener]), - - observe: message => { - if (!(message instanceof Ci.nsIScriptError) || !message.outerWindowID || - !message.category || disallowedMessageCategories.has(message.category)) { - return; - } - const errorWindow = Services.wm.getOuterWindowWithId(message.outerWindowID); - if (message.category === 'Web Worker' && message.logLevel === Ci.nsIConsoleMessage.error) { - emitEvent(this.events.onErrorFromWorker, errorWindow, message.message, '' + message.stack); - return; - } - const executionContext = this._windowToExecutionContext.get(errorWindow); - if (!executionContext) { - return; - } - const typeNames = { - [Ci.nsIConsoleMessage.debug]: 'debug', - [Ci.nsIConsoleMessage.info]: 'info', - [Ci.nsIConsoleMessage.warn]: 'warn', - [Ci.nsIConsoleMessage.error]: 'error', - }; - if (!message.hasException) { - emitEvent(this.events.onConsoleMessage, { - args: [{ - value: message.message, - }], - type: typeNames[message.logLevel], - executionContextId: executionContext.id(), - location: { - lineNumber: message.lineNumber, - columnNumber: message.columnNumber, - url: message.sourceName, - }, - }); - } else { - emitEvent(this.events.onRuntimeError, { - executionContext, - message: message.errorMessage, - stack: message.stack.toString(), - }); - } - }, - }; - Services.console.registerListener(consoleServiceListener); - this._eventListeners.push(() => Services.console.unregisterListener(consoleServiceListener)); - } - - _registerConsoleAPIListener(Services) { - const Ci = Components.interfaces; - const Cc = Components.classes; - const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage); - const onMessage = ({ wrappedJSObject }) => { - const executionContext = Array.from(this._executionContexts.values()).find(context => { - // There is no easy way to determine isolated world context and we normally don't write - // objects to console from utility worlds so we always return main world context here. - if (context._isIsolatedWorldContext()) - return false; - const domWindow = context._domWindow; - return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID; - }); - if (!executionContext) - return; - this._onConsoleMessage(executionContext, wrappedJSObject); - } - ConsoleAPIStorage.addLogEventListener( - onMessage, - Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal) - ); - this._eventListeners.push(() => ConsoleAPIStorage.removeLogEventListener(onMessage)); - } - - _registerWorkerConsoleHandler() { - setConsoleEventHandler(message => { - const executionContext = Array.from(this._executionContexts.values())[0]; - this._onConsoleMessage(executionContext, message); - }); - this._eventListeners.push(() => setConsoleEventHandler(null)); - } - - _onConsoleMessage(executionContext, message) { - const type = consoleLevelToProtocolType[message.level]; - if (!type) - return; - const args = message.arguments.map(arg => executionContext.rawValueToRemoteObject(arg)); - emitEvent(this.events.onConsoleMessage, { - args, - type, - executionContextId: executionContext.id(), - location: { - lineNumber: message.lineNumber - 1, - columnNumber: message.columnNumber - 1, - url: message.filename, - }, - }); - } - - dispose() { - for (const tearDown of this._eventListeners) - tearDown.call(null); - this._eventListeners = []; - } - - async _awaitPromise(executionContext, obj, exceptionDetails = {}) { - if (obj.promiseState === 'fulfilled') - return {success: true, obj: obj.promiseValue}; - if (obj.promiseState === 'rejected') { - const debuggee = executionContext._debuggee; - exceptionDetails.text = debuggee.executeInGlobalWithBindings('e.message', {e: obj.promiseReason}).return; - exceptionDetails.stack = debuggee.executeInGlobalWithBindings('e.stack', {e: obj.promiseReason}).return; - return {success: false, obj: null}; - } - let resolve, reject; - const promise = new Promise((a, b) => { - resolve = a; - reject = b; - }); - this._pendingPromises.set(obj.promiseID, {resolve, reject, executionContext, exceptionDetails}); - if (this._pendingPromises.size === 1) - this._debugger.onPromiseSettled = this._onPromiseSettled.bind(this); - return await promise; - } - - _onPromiseSettled(obj) { - const pendingPromise = this._pendingPromises.get(obj.promiseID); - if (!pendingPromise) - return; - this._pendingPromises.delete(obj.promiseID); - if (!this._pendingPromises.size) - this._debugger.onPromiseSettled = undefined; - - if (obj.promiseState === 'fulfilled') { - pendingPromise.resolve({success: true, obj: obj.promiseValue}); - return; - }; - const debuggee = pendingPromise.executionContext._debuggee; - pendingPromise.exceptionDetails.text = debuggee.executeInGlobalWithBindings('e.message', {e: obj.promiseReason}).return; - pendingPromise.exceptionDetails.stack = debuggee.executeInGlobalWithBindings('e.stack', {e: obj.promiseReason}).return; - pendingPromise.resolve({success: false, obj: null}); - } - - createExecutionContext(domWindow, contextGlobal, auxData) { - // Note: domWindow is null for workers. - const context = new ExecutionContext(this, domWindow, contextGlobal, auxData); - this._executionContexts.set(context._id, context); - if (domWindow) - this._windowToExecutionContext.set(domWindow, context); - emitEvent(this.events.onExecutionContextCreated, context); - return context; - } - - findExecutionContext(executionContextId) { - const executionContext = this._executionContexts.get(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - return executionContext; - } - - destroyExecutionContext(destroyedContext) { - for (const [promiseID, {reject, executionContext}] of this._pendingPromises) { - if (executionContext === destroyedContext) { - reject(new Error('Execution context was destroyed!')); - this._pendingPromises.delete(promiseID); - } - } - if (!this._pendingPromises.size) - this._debugger.onPromiseSettled = undefined; - this._debugger.removeDebuggee(destroyedContext._contextGlobal); - this._executionContexts.delete(destroyedContext._id); - if (destroyedContext._domWindow) - this._windowToExecutionContext.delete(destroyedContext._domWindow); - emitEvent(this.events.onExecutionContextDestroyed, destroyedContext); - } -} - -class ExecutionContext { - constructor(runtime, domWindow, contextGlobal, auxData) { - this._runtime = runtime; - this._domWindow = domWindow; - this._contextGlobal = contextGlobal; - this._debuggee = runtime._debugger.addDebuggee(contextGlobal); - this._remoteObjects = new Map(); - this._id = generateId(); - this._auxData = auxData; - this._jsonStringifyObject = this._debuggee.executeInGlobal(`((stringify, object) => { - const oldToJSON = Date.prototype.toJSON; - Date.prototype.toJSON = undefined; - const oldArrayToJSON = Array.prototype.toJSON; - const oldArrayHadToJSON = Array.prototype.hasOwnProperty('toJSON'); - if (oldArrayHadToJSON) - Array.prototype.toJSON = undefined; - - let hasSymbol = false; - const result = stringify(object, (key, value) => { - if (typeof value === 'symbol') - hasSymbol = true; - return value; - }); - - Date.prototype.toJSON = oldToJSON; - if (oldArrayHadToJSON) - Array.prototype.toJSON = oldArrayToJSON; - - return hasSymbol ? undefined : result; - }).bind(null, JSON.stringify.bind(JSON))`).return; - } - - id() { - return this._id; - } - - auxData() { - return this._auxData; - } - - _isIsolatedWorldContext() { - return !!this._auxData.name; - } - - async evaluateScript(script, exceptionDetails = {}) { - const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null; - if (this._domWindow && this._domWindow.document) - this._domWindow.document.notifyUserGestureActivation(); - - let {success, obj} = this._getResult(this._debuggee.executeInGlobal(script), exceptionDetails); - userInputHelper && userInputHelper.destruct(); - if (!success) - return null; - if (obj && obj.isPromise) { - const awaitResult = await this._runtime._awaitPromise(this, obj, exceptionDetails); - if (!awaitResult.success) - return null; - obj = awaitResult.obj; - } - return this._createRemoteObject(obj); - } - - evaluateScriptSafely(script) { - try { - this._debuggee.executeInGlobal(script); - } catch (e) { - dump(`ERROR: ${e.message}\n${e.stack}\n`); - } - } - - async evaluateFunction(functionText, args, exceptionDetails = {}) { - const funEvaluation = this._getResult(this._debuggee.executeInGlobal('(' + functionText + ')'), exceptionDetails); - if (!funEvaluation.success) - return null; - if (!funEvaluation.obj.callable) - throw new Error('functionText does not evaluate to a function!'); - args = args.map(arg => { - if (arg.objectId) { - if (!this._remoteObjects.has(arg.objectId)) - throw new Error('Cannot find object with id = ' + arg.objectId); - return this._remoteObjects.get(arg.objectId); - } - switch (arg.unserializableValue) { - case 'Infinity': return Infinity; - case '-Infinity': return -Infinity; - case '-0': return -0; - case 'NaN': return NaN; - default: return this._toDebugger(arg.value); - } - }); - const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null; - if (this._domWindow && this._domWindow.document) - this._domWindow.document.notifyUserGestureActivation(); - let {success, obj} = this._getResult(funEvaluation.obj.apply(null, args), exceptionDetails); - userInputHelper && userInputHelper.destruct(); - if (!success) - return null; - if (obj && obj.isPromise) { - const awaitResult = await this._runtime._awaitPromise(this, obj, exceptionDetails); - if (!awaitResult.success) - return null; - obj = awaitResult.obj; - } - return this._createRemoteObject(obj); - } - - addBinding(name, script) { - Cu.exportFunction((...args) => { - emitEvent(this._runtime.events.onBindingCalled, { - executionContextId: this._id, - name, - payload: args[0], - }); - }, this._contextGlobal, { - defineAs: name, - }); - this.evaluateScriptSafely(script); - } - - unsafeObject(objectId) { - if (!this._remoteObjects.has(objectId)) - return; - return { object: this._remoteObjects.get(objectId).unsafeDereference() }; - } - - rawValueToRemoteObject(rawValue) { - const debuggerObj = this._debuggee.makeDebuggeeValue(rawValue); - return this._createRemoteObject(debuggerObj); - } - - _instanceOf(debuggerObj, rawObj, className) { - if (this._domWindow) - return rawObj instanceof this._domWindow[className]; - return this._debuggee.executeInGlobalWithBindings('o instanceof this[className]', {o: debuggerObj, className: this._debuggee.makeDebuggeeValue(className)}).return; - } - - _createRemoteObject(debuggerObj) { - if (debuggerObj instanceof Debugger.Object) { - const objectId = generateId(); - this._remoteObjects.set(objectId, debuggerObj); - const rawObj = debuggerObj.unsafeDereference(); - const type = typeof rawObj; - let subtype = undefined; - if (debuggerObj.isProxy) - subtype = 'proxy'; - else if (Array.isArray(rawObj)) - subtype = 'array'; - else if (Object.is(rawObj, null)) - subtype = 'null'; - else if (this._instanceOf(debuggerObj, rawObj, 'Node')) - subtype = 'node'; - else if (this._instanceOf(debuggerObj, rawObj, 'RegExp')) - subtype = 'regexp'; - else if (this._instanceOf(debuggerObj, rawObj, 'Date')) - subtype = 'date'; - else if (this._instanceOf(debuggerObj, rawObj, 'Map')) - subtype = 'map'; - else if (this._instanceOf(debuggerObj, rawObj, 'Set')) - subtype = 'set'; - else if (this._instanceOf(debuggerObj, rawObj, 'WeakMap')) - subtype = 'weakmap'; - else if (this._instanceOf(debuggerObj, rawObj, 'WeakSet')) - subtype = 'weakset'; - else if (this._instanceOf(debuggerObj, rawObj, 'Error')) - subtype = 'error'; - else if (this._instanceOf(debuggerObj, rawObj, 'Promise')) - subtype = 'promise'; - else if ((this._instanceOf(debuggerObj, rawObj, 'Int8Array')) || (this._instanceOf(debuggerObj, rawObj, 'Uint8Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Uint8ClampedArray')) || (this._instanceOf(debuggerObj, rawObj, 'Int16Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Uint16Array')) || (this._instanceOf(debuggerObj, rawObj, 'Int32Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Uint32Array')) || (this._instanceOf(debuggerObj, rawObj, 'Float32Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Float64Array'))) { - subtype = 'typedarray'; - } - return {objectId, type, subtype}; - } - if (typeof debuggerObj === 'symbol') { - const objectId = generateId(); - this._remoteObjects.set(objectId, debuggerObj); - return {objectId, type: 'symbol'}; - } - - let unserializableValue = undefined; - if (Object.is(debuggerObj, NaN)) - unserializableValue = 'NaN'; - else if (Object.is(debuggerObj, -0)) - unserializableValue = '-0'; - else if (Object.is(debuggerObj, Infinity)) - unserializableValue = 'Infinity'; - else if (Object.is(debuggerObj, -Infinity)) - unserializableValue = '-Infinity'; - return unserializableValue ? {unserializableValue} : {value: debuggerObj}; - } - - ensureSerializedToValue(protocolObject) { - if (!protocolObject.objectId) - return protocolObject; - const obj = this._remoteObjects.get(protocolObject.objectId); - this._remoteObjects.delete(protocolObject.objectId); - return {value: this._serialize(obj)}; - } - - _toDebugger(obj) { - if (typeof obj !== 'object') - return obj; - if (obj === null) - return obj; - const properties = {}; - for (let [key, value] of Object.entries(obj)) { - properties[key] = { - configurable: true, - writable: true, - enumerable: true, - value: this._toDebugger(value), - }; - } - const baseObject = Array.isArray(obj) ? '([])' : '({})'; - const debuggerObj = this._debuggee.executeInGlobal(baseObject).return; - debuggerObj.defineProperties(properties); - return debuggerObj; - } - - _serialize(obj) { - const result = this._debuggee.executeInGlobalWithBindings('stringify(e)', {e: obj, stringify: this._jsonStringifyObject}); - if (result.throw) - throw new Error('Object is not serializable'); - return result.return === undefined ? undefined : JSON.parse(result.return); - } - - disposeObject(objectId) { - this._remoteObjects.delete(objectId); - } - - getObjectProperties(objectId) { - if (!this._remoteObjects.has(objectId)) - throw new Error('Cannot find object with id = ' + arg.objectId); - const result = []; - for (let obj = this._remoteObjects.get(objectId); obj; obj = obj.proto) { - for (const propertyName of obj.getOwnPropertyNames()) { - const descriptor = obj.getOwnPropertyDescriptor(propertyName); - if (!descriptor.enumerable) - continue; - result.push({ - name: propertyName, - value: this._createRemoteObject(descriptor.value), - }); - } - } - return result; - } - - _getResult(completionValue, exceptionDetails = {}) { - if (!completionValue) { - exceptionDetails.text = 'Evaluation terminated!'; - exceptionDetails.stack = ''; - return {success: false, obj: null}; - } - if (completionValue.throw) { - if (this._debuggee.executeInGlobalWithBindings('e instanceof Error', {e: completionValue.throw}).return) { - exceptionDetails.text = this._debuggee.executeInGlobalWithBindings('e.message', {e: completionValue.throw}).return; - exceptionDetails.stack = this._debuggee.executeInGlobalWithBindings('e.stack', {e: completionValue.throw}).return; - } else { - exceptionDetails.value = this._serialize(completionValue.throw); - } - return {success: false, obj: null}; - } - return {success: true, obj: completionValue.return}; - } -} - -const listenersSymbol = Symbol('listeners'); - -function createEvent() { - const listeners = new Set(); - const subscribeFunction = listener => { - listeners.add(listener); - return () => listeners.delete(listener); - } - subscribeFunction[listenersSymbol] = listeners; - return subscribeFunction; -} - -function emitEvent(event, ...args) { - let listeners = event[listenersSymbol]; - if (!listeners || !listeners.size) - return; - listeners = new Set(listeners); - for (const listener of listeners) - listener.call(null, ...args); -} - -var EXPORTED_SYMBOLS = ['Runtime']; -this.Runtime = Runtime; diff --git a/browser_patches/firefox-beta/juggler/content/WorkerMain.js b/browser_patches/firefox-beta/juggler/content/WorkerMain.js deleted file mode 100644 index 3d0c1168cb..0000000000 --- a/browser_patches/firefox-beta/juggler/content/WorkerMain.js +++ /dev/null @@ -1,76 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -loadSubScript('chrome://juggler/content/content/Runtime.js'); -loadSubScript('chrome://juggler/content/SimpleChannel.js'); - -const channel = new SimpleChannel('worker::worker'); -const eventListener = event => channel._onMessage(JSON.parse(event.data)); -this.addEventListener('message', eventListener); -channel.setTransport({ - sendMessage: msg => postMessage(JSON.stringify(msg)), - dispose: () => this.removeEventListener('message', eventListener), -}); - -const runtime = new Runtime(true /* isWorker */); - -(() => { - // Create execution context in the runtime only when the script - // source was actually evaluated in it. - const dbg = new Debugger(global); - if (dbg.findScripts({global}).length) { - runtime.createExecutionContext(null /* domWindow */, global, {}); - } else { - dbg.onNewScript = function(s) { - dbg.onNewScript = undefined; - dbg.removeAllDebuggees(); - runtime.createExecutionContext(null /* domWindow */, global, {}); - }; - } -})(); - -class RuntimeAgent { - constructor(runtime, channel) { - this._runtime = runtime; - this._browserRuntime = channel.connect('runtime'); - - for (const context of this._runtime.executionContexts()) - this._onExecutionContextCreated(context); - - this._eventListeners = [ - this._runtime.events.onConsoleMessage(msg => this._browserRuntime.emit('runtimeConsole', msg)), - this._runtime.events.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)), - this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)), - channel.register('runtime', { - evaluate: this._runtime.evaluate.bind(this._runtime), - callFunction: this._runtime.callFunction.bind(this._runtime), - getObjectProperties: this._runtime.getObjectProperties.bind(this._runtime), - disposeObject: this._runtime.disposeObject.bind(this._runtime), - }), - ]; - } - - _onExecutionContextCreated(executionContext) { - this._browserRuntime.emit('runtimeExecutionContextCreated', { - executionContextId: executionContext.id(), - auxData: executionContext.auxData(), - }); - } - - _onExecutionContextDestroyed(executionContext) { - this._browserRuntime.emit('runtimeExecutionContextDestroyed', { - executionContextId: executionContext.id(), - }); - } - - dispose() { - for (const disposer of this._eventListeners) - disposer(); - this._eventListeners = []; - } -} - -new RuntimeAgent(runtime, channel); - diff --git a/browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css b/browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css deleted file mode 100644 index 26fc0db768..0000000000 --- a/browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -* { - scrollbar-width: none !important; -} diff --git a/browser_patches/firefox-beta/juggler/content/main.js b/browser_patches/firefox-beta/juggler/content/main.js deleted file mode 100644 index d471ab9553..0000000000 --- a/browser_patches/firefox-beta/juggler/content/main.js +++ /dev/null @@ -1,155 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js'); -const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {PageAgent} = ChromeUtils.import('chrome://juggler/content/content/PageAgent.js'); - -let frameTree; -const helper = new Helper(); -const messageManager = this; - -let pageAgent; - -let failedToOverrideTimezone = false; - -const applySetting = { - geolocation: (geolocation) => { - if (geolocation) { - docShell.setGeolocationOverride({ - coords: { - latitude: geolocation.latitude, - longitude: geolocation.longitude, - accuracy: geolocation.accuracy, - altitude: NaN, - altitudeAccuracy: NaN, - heading: NaN, - speed: NaN, - }, - address: null, - timestamp: Date.now() - }); - } else { - docShell.setGeolocationOverride(null); - } - }, - - onlineOverride: (onlineOverride) => { - if (!onlineOverride) { - docShell.onlineOverride = Ci.nsIDocShell.ONLINE_OVERRIDE_NONE; - return; - } - docShell.onlineOverride = onlineOverride === 'online' ? - Ci.nsIDocShell.ONLINE_OVERRIDE_ONLINE : Ci.nsIDocShell.ONLINE_OVERRIDE_OFFLINE; - }, - - bypassCSP: (bypassCSP) => { - docShell.bypassCSPEnabled = bypassCSP; - }, - - timezoneId: (timezoneId) => { - failedToOverrideTimezone = !docShell.overrideTimezone(timezoneId); - }, - - locale: (locale) => { - docShell.languageOverride = locale; - }, - - scrollbarsHidden: (hidden) => { - frameTree.setScrollbarsHidden(hidden); - }, - - colorScheme: (colorScheme) => { - frameTree.setColorScheme(colorScheme); - }, - - reducedMotion: (reducedMotion) => { - frameTree.setReducedMotion(reducedMotion); - }, - - forcedColors: (forcedColors) => { - frameTree.setForcedColors(forcedColors); - }, -}; - -const channel = SimpleChannel.createForMessageManager('content::page', messageManager); - -function initialize() { - const response = sendSyncMessage('juggler:content-ready')[0]; - // If we didn't get a response, then we don't want to do anything - // as a part of this frame script. - if (!response) - return; - const { - initScripts = [], - bindings = [], - settings = {} - } = response || {}; - // Enforce focused state for all top level documents. - docShell.overrideHasFocus = true; - docShell.forceActiveState = true; - frameTree = new FrameTree(docShell); - for (const [name, value] of Object.entries(settings)) { - if (value !== undefined) - applySetting[name](value); - } - for (const { worldName, name, script } of bindings) - frameTree.addBinding(worldName, name, script); - frameTree.setInitScripts(initScripts); - - pageAgent = new PageAgent(messageManager, channel, frameTree); - - channel.register('', { - setInitScripts(scripts) { - frameTree.setInitScripts(scripts); - }, - - addBinding({worldName, name, script}) { - frameTree.addBinding(worldName, name, script); - }, - - applyContextSetting({name, value}) { - applySetting[name](value); - }, - - ensurePermissions() { - // noop, just a rountrip. - }, - - hasFailedToOverrideTimezone() { - return failedToOverrideTimezone; - }, - - async awaitViewportDimensions({width, height, deviceSizeIsPageSize}) { - docShell.deviceSizeIsPageSize = deviceSizeIsPageSize; - const win = docShell.domWindow; - if (win.innerWidth === width && win.innerHeight === height) - return; - await new Promise(resolve => { - const listener = helper.addEventListener(win, 'resize', () => { - if (win.innerWidth === width && win.innerHeight === height) { - helper.removeListeners([listener]); - resolve(); - } - }); - }); - }, - - dispose() { - }, - }); - - const gListeners = [ - helper.addEventListener(messageManager, 'unload', msg => { - helper.removeListeners(gListeners); - pageAgent.dispose(); - frameTree.dispose(); - channel.dispose(); - }), - ]; -} - -initialize(); diff --git a/browser_patches/firefox-beta/juggler/jar.mn b/browser_patches/firefox-beta/juggler/jar.mn deleted file mode 100644 index 8b3d3922c1..0000000000 --- a/browser_patches/firefox-beta/juggler/jar.mn +++ /dev/null @@ -1,25 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -juggler.jar: -% content juggler %content/ - - content/components/Juggler.js (components/Juggler.js) - - content/Helper.js (Helper.js) - content/NetworkObserver.js (NetworkObserver.js) - content/TargetRegistry.js (TargetRegistry.js) - content/SimpleChannel.js (SimpleChannel.js) - content/protocol/PrimitiveTypes.js (protocol/PrimitiveTypes.js) - content/protocol/Protocol.js (protocol/Protocol.js) - content/protocol/Dispatcher.js (protocol/Dispatcher.js) - content/protocol/PageHandler.js (protocol/PageHandler.js) - content/protocol/BrowserHandler.js (protocol/BrowserHandler.js) - content/content/main.js (content/main.js) - content/content/FrameTree.js (content/FrameTree.js) - content/content/PageAgent.js (content/PageAgent.js) - content/content/Runtime.js (content/Runtime.js) - content/content/WorkerMain.js (content/WorkerMain.js) - content/content/hidden-scrollbars.css (content/hidden-scrollbars.css) - diff --git a/browser_patches/firefox-beta/juggler/moz.build b/browser_patches/firefox-beta/juggler/moz.build deleted file mode 100644 index 905c20cc31..0000000000 --- a/browser_patches/firefox-beta/juggler/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ["components", "screencast", "pipe"] - -JAR_MANIFESTS += ["jar.mn"] -with Files("**"): - BUG_COMPONENT = ("Testing", "Juggler") - diff --git a/browser_patches/firefox-beta/juggler/pipe/components.conf b/browser_patches/firefox-beta/juggler/pipe/components.conf deleted file mode 100644 index db13a00ba7..0000000000 --- a/browser_patches/firefox-beta/juggler/pipe/components.conf +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Classes = [ - { - 'cid': '{d69ecefe-3df7-4d11-9dc7-f604edb96da2}', - 'contract_ids': ['@mozilla.org/juggler/remotedebuggingpipe;1'], - 'type': 'nsIRemoteDebuggingPipe', - 'constructor': 'mozilla::nsRemoteDebuggingPipe::GetSingleton', - 'headers': ['/juggler/pipe/nsRemoteDebuggingPipe.h'], - }, -] diff --git a/browser_patches/firefox-beta/juggler/pipe/moz.build b/browser_patches/firefox-beta/juggler/pipe/moz.build deleted file mode 100644 index b56c697881..0000000000 --- a/browser_patches/firefox-beta/juggler/pipe/moz.build +++ /dev/null @@ -1,24 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPIDL_SOURCES += [ - 'nsIRemoteDebuggingPipe.idl', -] - -XPIDL_MODULE = 'jugglerpipe' - -SOURCES += [ - 'nsRemoteDebuggingPipe.cpp', -] - -XPCOM_MANIFESTS += [ - 'components.conf', -] - -LOCAL_INCLUDES += [ -] - -FINAL_LIBRARY = 'xul' diff --git a/browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl b/browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl deleted file mode 100644 index ac91b63615..0000000000 --- a/browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl +++ /dev/null @@ -1,20 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(7910c231-971a-4653-abdc-a8599a986c4c)] -interface nsIRemoteDebuggingPipeClient : nsISupports -{ - void receiveMessage(in AString message); - void disconnected(); -}; - -[scriptable, uuid(b7bfb66b-fd46-4aa2-b4ad-396177186d94)] -interface nsIRemoteDebuggingPipe : nsISupports -{ - void init(in nsIRemoteDebuggingPipeClient client); - void sendMessage(in AString message); - void stop(); -}; diff --git a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp b/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp deleted file mode 100644 index abcb0a758f..0000000000 --- a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsRemoteDebuggingPipe.h" - -#include -#if defined(_WIN32) -#include -#include -#else -#include -#include -#include -#endif - -#include "mozilla/StaticPtr.h" -#include "nsISupportsPrimitives.h" -#include "nsThreadUtils.h" - -namespace mozilla { - -NS_IMPL_ISUPPORTS(nsRemoteDebuggingPipe, nsIRemoteDebuggingPipe) - -namespace { - -StaticRefPtr gPipe; - -const size_t kWritePacketSize = 1 << 16; - -#if defined(_WIN32) -HANDLE readHandle; -HANDLE writeHandle; -#else -const int readFD = 3; -const int writeFD = 4; -#endif - -size_t ReadBytes(void* buffer, size_t size, bool exact_size) -{ - size_t bytesRead = 0; - while (bytesRead < size) { -#if defined(_WIN32) - DWORD sizeRead = 0; - bool hadError = !ReadFile(readHandle, static_cast(buffer) + bytesRead, - size - bytesRead, &sizeRead, nullptr); -#else - int sizeRead = read(readFD, static_cast(buffer) + bytesRead, - size - bytesRead); - if (sizeRead < 0 && errno == EINTR) - continue; - bool hadError = sizeRead <= 0; -#endif - if (hadError) { - return 0; - } - bytesRead += sizeRead; - if (!exact_size) - break; - } - return bytesRead; -} - -void WriteBytes(const char* bytes, size_t size) -{ - size_t totalWritten = 0; - while (totalWritten < size) { - size_t length = size - totalWritten; - if (length > kWritePacketSize) - length = kWritePacketSize; -#if defined(_WIN32) - DWORD bytesWritten = 0; - bool hadError = !WriteFile(writeHandle, bytes + totalWritten, static_cast(length), &bytesWritten, nullptr); -#else - int bytesWritten = write(writeFD, bytes + totalWritten, length); - if (bytesWritten < 0 && errno == EINTR) - continue; - bool hadError = bytesWritten <= 0; -#endif - if (hadError) - return; - totalWritten += bytesWritten; - } -} - -} // namespace - -// static -already_AddRefed nsRemoteDebuggingPipe::GetSingleton() { - if (!gPipe) { - gPipe = new nsRemoteDebuggingPipe(); - } - return do_AddRef(gPipe); -} - -nsRemoteDebuggingPipe::nsRemoteDebuggingPipe() = default; - -nsRemoteDebuggingPipe::~nsRemoteDebuggingPipe() = default; - -nsresult nsRemoteDebuggingPipe::Init(nsIRemoteDebuggingPipeClient* aClient) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (mClient) { - return NS_ERROR_FAILURE; - } - mClient = aClient; - - MOZ_ALWAYS_SUCCEEDS(NS_NewNamedThread("Pipe Reader", getter_AddRefs(mReaderThread))); - MOZ_ALWAYS_SUCCEEDS(NS_NewNamedThread("Pipe Writer", getter_AddRefs(mWriterThread))); - -#if defined(_WIN32) - CHAR pipeReadStr[20]; - CHAR pipeWriteStr[20]; - GetEnvironmentVariableA("PW_PIPE_READ", pipeReadStr, 20); - GetEnvironmentVariableA("PW_PIPE_WRITE", pipeWriteStr, 20); - readHandle = reinterpret_cast(atoi(pipeReadStr)); - writeHandle = reinterpret_cast(atoi(pipeWriteStr)); -#endif - - MOZ_ALWAYS_SUCCEEDS(mReaderThread->Dispatch(NewRunnableMethod( - "nsRemoteDebuggingPipe::ReaderLoop", - this, &nsRemoteDebuggingPipe::ReaderLoop), nsIThread::DISPATCH_NORMAL)); - return NS_OK; -} - -nsresult nsRemoteDebuggingPipe::Stop() { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (!mClient) { - return NS_ERROR_FAILURE; - } - m_terminated = true; - mClient = nullptr; - // Cancel pending synchronous read. -#if defined(_WIN32) - CancelIoEx(readHandle, nullptr); - CloseHandle(readHandle); - CloseHandle(writeHandle); -#else - shutdown(readFD, SHUT_RDWR); - shutdown(writeFD, SHUT_RDWR); -#endif - mReaderThread->Shutdown(); - mReaderThread = nullptr; - mWriterThread->Shutdown(); - mWriterThread = nullptr; - return NS_OK; -} - -void nsRemoteDebuggingPipe::ReaderLoop() { - const size_t bufSize = 256 * 1024; - std::vector buffer; - buffer.resize(bufSize); - std::vector line; - while (!m_terminated) { - size_t size = ReadBytes(buffer.data(), bufSize, false); - if (!size) { - nsCOMPtr runnable = NewRunnableMethod<>( - "nsRemoteDebuggingPipe::Disconnected", - this, &nsRemoteDebuggingPipe::Disconnected); - NS_DispatchToMainThread(runnable.forget()); - break; - } - size_t start = 0; - size_t end = line.size(); - line.insert(line.end(), buffer.begin(), buffer.begin() + size); - while (true) { - for (; end < line.size(); ++end) { - if (line[end] == '\0') { - break; - } - } - if (end == line.size()) { - break; - } - if (end > start) { - nsCString message; - message.Append(line.data() + start, end - start); - nsCOMPtr runnable = NewRunnableMethod( - "nsRemoteDebuggingPipe::ReceiveMessage", - this, &nsRemoteDebuggingPipe::ReceiveMessage, std::move(message)); - NS_DispatchToMainThread(runnable.forget()); - } - ++end; - start = end; - } - if (start != 0 && start < line.size()) { - memmove(line.data(), line.data() + start, line.size() - start); - } - line.resize(line.size() - start); - } -} - -void nsRemoteDebuggingPipe::ReceiveMessage(const nsCString& aMessage) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (mClient) { - NS_ConvertUTF8toUTF16 utf16(aMessage); - mClient->ReceiveMessage(utf16); - } -} - -void nsRemoteDebuggingPipe::Disconnected() { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (mClient) - mClient->Disconnected(); -} - -nsresult nsRemoteDebuggingPipe::SendMessage(const nsAString& aMessage) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (!mClient) { - return NS_ERROR_FAILURE; - } - NS_ConvertUTF16toUTF8 utf8(aMessage); - nsCOMPtr runnable = NS_NewRunnableFunction( - "nsRemoteDebuggingPipe::SendMessage", - [message = std::move(utf8)] { - const nsCString& flat = PromiseFlatCString(message); - WriteBytes(flat.Data(), flat.Length()); - WriteBytes("\0", 1); - }); - MOZ_ALWAYS_SUCCEEDS(mWriterThread->Dispatch(runnable.forget(), nsIThread::DISPATCH_NORMAL)); - return NS_OK; -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h b/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h deleted file mode 100644 index be4cb2675e..0000000000 --- a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include "nsCOMPtr.h" -#include "nsIRemoteDebuggingPipe.h" -#include "nsThread.h" - -namespace mozilla { - -class nsRemoteDebuggingPipe final : public nsIRemoteDebuggingPipe { - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIREMOTEDEBUGGINGPIPE - - static already_AddRefed GetSingleton(); - nsRemoteDebuggingPipe(); - - private: - void ReaderLoop(); - void ReceiveMessage(const nsCString& aMessage); - void Disconnected(); - ~nsRemoteDebuggingPipe(); - - RefPtr mClient; - nsCOMPtr mReaderThread; - nsCOMPtr mWriterThread; - std::atomic m_terminated { false }; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js b/browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js deleted file mode 100644 index 623f9cc331..0000000000 --- a/browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js +++ /dev/null @@ -1,296 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm"); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {TargetRegistry} = ChromeUtils.import("chrome://juggler/content/TargetRegistry.js"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {PageHandler} = ChromeUtils.import("chrome://juggler/content/protocol/PageHandler.js"); -const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); - -const helper = new Helper(); - -class BrowserHandler { - constructor(session, dispatcher, targetRegistry, onclose, onstart) { - this._session = session; - this._dispatcher = dispatcher; - this._targetRegistry = targetRegistry; - this._enabled = false; - this._attachToDefaultContext = false; - this._eventListeners = []; - this._createdBrowserContextIds = new Set(); - this._attachedSessions = new Map(); - this._onclose = onclose; - this._onstart = onstart; - } - - async ['Browser.enable']({attachToDefaultContext}) { - if (this._enabled) - return; - await this._onstart(); - this._enabled = true; - this._attachToDefaultContext = attachToDefaultContext; - - this._eventListeners = [ - helper.on(this._targetRegistry, TargetRegistry.Events.TargetCreated, this._onTargetCreated.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.TargetDestroyed, this._onTargetDestroyed.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.DownloadCreated, this._onDownloadCreated.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.DownloadFinished, this._onDownloadFinished.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.ScreencastStopped, sessionId => { - this._session.emitEvent('Browser.videoRecordingFinished', {screencastId: '' + sessionId}); - }) - ]; - - for (const target of this._targetRegistry.targets()) - this._onTargetCreated(target); - } - - async ['Browser.createBrowserContext']({removeOnDetach}) { - if (!this._enabled) - throw new Error('Browser domain is not enabled'); - const browserContext = this._targetRegistry.createBrowserContext(removeOnDetach); - this._createdBrowserContextIds.add(browserContext.browserContextId); - return {browserContextId: browserContext.browserContextId}; - } - - async ['Browser.removeBrowserContext']({browserContextId}) { - if (!this._enabled) - throw new Error('Browser domain is not enabled'); - await this._targetRegistry.browserContextForId(browserContextId).destroy(); - this._createdBrowserContextIds.delete(browserContextId); - } - - dispose() { - helper.removeListeners(this._eventListeners); - for (const [target, session] of this._attachedSessions) - this._dispatcher.destroySession(session); - this._attachedSessions.clear(); - for (const browserContextId of this._createdBrowserContextIds) { - const browserContext = this._targetRegistry.browserContextForId(browserContextId); - if (browserContext.removeOnDetach) - browserContext.destroy(); - } - this._createdBrowserContextIds.clear(); - } - - _shouldAttachToTarget(target) { - if (this._createdBrowserContextIds.has(target._browserContext.browserContextId)) - return true; - return this._attachToDefaultContext && target._browserContext === this._targetRegistry.defaultContext(); - } - - _onTargetCreated(target) { - if (!this._shouldAttachToTarget(target)) - return; - const channel = target.channel(); - const session = this._dispatcher.createSession(); - this._attachedSessions.set(target, session); - this._session.emitEvent('Browser.attachedToTarget', { - sessionId: session.sessionId(), - targetInfo: target.info() - }); - session.setHandler(new PageHandler(target, session, channel)); - } - - _onTargetDestroyed(target) { - const session = this._attachedSessions.get(target); - if (!session) - return; - this._attachedSessions.delete(target); - this._dispatcher.destroySession(session); - this._session.emitEvent('Browser.detachedFromTarget', { - sessionId: session.sessionId(), - targetId: target.id(), - }); - } - - _onDownloadCreated(downloadInfo) { - this._session.emitEvent('Browser.downloadCreated', downloadInfo); - } - - _onDownloadFinished(downloadInfo) { - this._session.emitEvent('Browser.downloadFinished', downloadInfo); - } - - async ['Browser.cancelDownload']({uuid}) { - await this._targetRegistry.cancelDownload({uuid}); - } - - async ['Browser.newPage']({browserContextId}) { - const targetId = await this._targetRegistry.newPage({browserContextId}); - return {targetId}; - } - - async ['Browser.close']() { - let browserWindow = Services.wm.getMostRecentWindow( - "navigator:browser" - ); - if (browserWindow && browserWindow.gBrowserInit) { - // idleTasksFinishedPromise does not resolve when the window - // is closed early enough, so we race against window closure. - await Promise.race([ - browserWindow.gBrowserInit.idleTasksFinishedPromise, - waitForWindowClosed(browserWindow), - ]); - } - this._onclose(); - Services.startup.quit(Ci.nsIAppStartup.eForceQuit); - } - - async ['Browser.grantPermissions']({browserContextId, origin, permissions}) { - await this._targetRegistry.browserContextForId(browserContextId).grantPermissions(origin, permissions); - } - - async ['Browser.resetPermissions']({browserContextId}) { - this._targetRegistry.browserContextForId(browserContextId).resetPermissions(); - } - - ['Browser.setExtraHTTPHeaders']({browserContextId, headers}) { - this._targetRegistry.browserContextForId(browserContextId).extraHTTPHeaders = headers; - } - - ['Browser.setHTTPCredentials']({browserContextId, credentials}) { - this._targetRegistry.browserContextForId(browserContextId).httpCredentials = nullToUndefined(credentials); - } - - async ['Browser.setBrowserProxy']({type, host, port, bypass, username, password}) { - this._targetRegistry.setBrowserProxy({ type, host, port, bypass, username, password}); - } - - async ['Browser.setContextProxy']({browserContextId, type, host, port, bypass, username, password}) { - const browserContext = this._targetRegistry.browserContextForId(browserContextId); - browserContext.setProxy({ type, host, port, bypass, username, password }); - } - - ['Browser.setRequestInterception']({browserContextId, enabled}) { - this._targetRegistry.browserContextForId(browserContextId).requestInterceptionEnabled = enabled; - } - - ['Browser.setIgnoreHTTPSErrors']({browserContextId, ignoreHTTPSErrors}) { - this._targetRegistry.browserContextForId(browserContextId).setIgnoreHTTPSErrors(nullToUndefined(ignoreHTTPSErrors)); - } - - ['Browser.setDownloadOptions']({browserContextId, downloadOptions}) { - this._targetRegistry.browserContextForId(browserContextId).downloadOptions = nullToUndefined(downloadOptions); - } - - async ['Browser.setGeolocationOverride']({browserContextId, geolocation}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('geolocation', nullToUndefined(geolocation)); - } - - async ['Browser.setOnlineOverride']({browserContextId, override}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('onlineOverride', nullToUndefined(override)); - } - - async ['Browser.setColorScheme']({browserContextId, colorScheme}) { - await this._targetRegistry.browserContextForId(browserContextId).setColorScheme(nullToUndefined(colorScheme)); - } - - async ['Browser.setReducedMotion']({browserContextId, reducedMotion}) { - await this._targetRegistry.browserContextForId(browserContextId).setReducedMotion(nullToUndefined(reducedMotion)); - } - - async ['Browser.setForcedColors']({browserContextId, forcedColors}) { - await this._targetRegistry.browserContextForId(browserContextId).setForcedColors(nullToUndefined(forcedColors)); - } - - async ['Browser.setVideoRecordingOptions']({browserContextId, options}) { - await this._targetRegistry.browserContextForId(browserContextId).setVideoRecordingOptions(options); - } - - async ['Browser.setUserAgentOverride']({browserContextId, userAgent}) { - await this._targetRegistry.browserContextForId(browserContextId).setDefaultUserAgent(userAgent); - } - - async ['Browser.setPlatformOverride']({browserContextId, platform}) { - await this._targetRegistry.browserContextForId(browserContextId).setDefaultPlatform(platform); - } - - async ['Browser.setBypassCSP']({browserContextId, bypassCSP}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('bypassCSP', nullToUndefined(bypassCSP)); - } - - async ['Browser.setJavaScriptDisabled']({browserContextId, javaScriptDisabled}) { - await this._targetRegistry.browserContextForId(browserContextId).setJavaScriptDisabled(javaScriptDisabled); - } - - async ['Browser.setLocaleOverride']({browserContextId, locale}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('locale', nullToUndefined(locale)); - } - - async ['Browser.setTimezoneOverride']({browserContextId, timezoneId}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('timezoneId', nullToUndefined(timezoneId)); - } - - async ['Browser.setTouchOverride']({browserContextId, hasTouch}) { - await this._targetRegistry.browserContextForId(browserContextId).setTouchOverride(nullToUndefined(hasTouch)); - } - - async ['Browser.setDefaultViewport']({browserContextId, viewport}) { - await this._targetRegistry.browserContextForId(browserContextId).setDefaultViewport(nullToUndefined(viewport)); - } - - async ['Browser.setScrollbarsHidden']({browserContextId, hidden}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('scrollbarsHidden', nullToUndefined(hidden)); - } - - async ['Browser.setInitScripts']({browserContextId, scripts}) { - await this._targetRegistry.browserContextForId(browserContextId).setInitScripts(scripts); - } - - async ['Browser.addBinding']({browserContextId, worldName, name, script}) { - await this._targetRegistry.browserContextForId(browserContextId).addBinding(worldName, name, script); - } - - ['Browser.setCookies']({browserContextId, cookies}) { - this._targetRegistry.browserContextForId(browserContextId).setCookies(cookies); - } - - ['Browser.clearCookies']({browserContextId}) { - this._targetRegistry.browserContextForId(browserContextId).clearCookies(); - } - - ['Browser.getCookies']({browserContextId}) { - const cookies = this._targetRegistry.browserContextForId(browserContextId).getCookies(); - return {cookies}; - } - - async ['Browser.getInfo']() { - const version = AppConstants.MOZ_APP_VERSION_DISPLAY; - const userAgent = Components.classes["@mozilla.org/network/protocol;1?name=http"] - .getService(Components.interfaces.nsIHttpProtocolHandler) - .userAgent; - return {version: 'Firefox/' + version, userAgent}; - } -} - -async function waitForWindowClosed(browserWindow) { - if (browserWindow.closed) - return; - await new Promise((resolve => { - const listener = { - onCloseWindow: window => { - let domWindow; - if (window instanceof Ci.nsIAppWindow) - domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); - else - domWindow = window; - if (domWindow === browserWindow) { - Services.wm.removeListener(listener); - resolve(); - } - }, - }; - Services.wm.addListener(listener); - })); -} - -function nullToUndefined(value) { - return value === null ? undefined : value; -} - -var EXPORTED_SYMBOLS = ['BrowserHandler']; -this.BrowserHandler = BrowserHandler; diff --git a/browser_patches/firefox-beta/juggler/protocol/Dispatcher.js b/browser_patches/firefox-beta/juggler/protocol/Dispatcher.js deleted file mode 100644 index af72f307ac..0000000000 --- a/browser_patches/firefox-beta/juggler/protocol/Dispatcher.js +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {protocol, checkScheme} = ChromeUtils.import("chrome://juggler/content/protocol/Protocol.js"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); - -const helper = new Helper(); - -class Dispatcher { - /** - * @param {Connection} connection - */ - constructor(connection) { - this._connection = connection; - this._connection.onmessage = this._dispatch.bind(this); - this._connection.onclose = this._dispose.bind(this); - this._sessions = new Map(); - this._rootSession = new ProtocolSession(this, undefined); - } - - rootSession() { - return this._rootSession; - } - - createSession() { - const session = new ProtocolSession(this, helper.generateId()); - this._sessions.set(session.sessionId(), session); - return session; - } - - destroySession(session) { - this._sessions.delete(session.sessionId()); - session._dispose(); - } - - _dispose() { - this._connection.onmessage = null; - this._connection.onclose = null; - this._rootSession._dispose(); - this._rootSession = null; - this._sessions.clear(); - } - - async _dispatch(event) { - const data = JSON.parse(event.data); - const id = data.id; - const sessionId = data.sessionId; - delete data.sessionId; - try { - const session = sessionId ? this._sessions.get(sessionId) : this._rootSession; - if (!session) - throw new Error(`ERROR: cannot find session with id "${sessionId}"`); - const method = data.method; - const params = data.params || {}; - if (!id) - throw new Error(`ERROR: every message must have an 'id' parameter`); - if (!method) - throw new Error(`ERROR: every message must have a 'method' parameter`); - - const [domain, methodName] = method.split('.'); - const descriptor = protocol.domains[domain] ? protocol.domains[domain].methods[methodName] : null; - if (!descriptor) - throw new Error(`ERROR: method '${method}' is not supported`); - let details = {}; - if (!checkScheme(descriptor.params || {}, params, details)) - throw new Error(`ERROR: failed to call method '${method}' with parameters ${JSON.stringify(params, null, 2)}\n${details.error}`); - - const result = await session.dispatch(method, params); - - details = {}; - if ((descriptor.returns || result) && !checkScheme(descriptor.returns, result, details)) - throw new Error(`ERROR: failed to dispatch method '${method}' result ${JSON.stringify(result, null, 2)}\n${details.error}`); - - this._connection.send(JSON.stringify({id, sessionId, result})); - } catch (e) { - this._connection.send(JSON.stringify({id, sessionId, error: { - message: e.message, - data: e.stack - }})); - } - } - - _emitEvent(sessionId, eventName, params) { - const [domain, eName] = eventName.split('.'); - const scheme = protocol.domains[domain] ? protocol.domains[domain].events[eName] : null; - if (!scheme) - throw new Error(`ERROR: event '${eventName}' is not supported`); - const details = {}; - if (!checkScheme(scheme, params || {}, details)) - throw new Error(`ERROR: failed to emit event '${eventName}' ${JSON.stringify(params, null, 2)}\n${details.error}`); - this._connection.send(JSON.stringify({method: eventName, params, sessionId})); - } -} - -class ProtocolSession { - constructor(dispatcher, sessionId) { - this._sessionId = sessionId; - this._dispatcher = dispatcher; - this._handler = null; - } - - sessionId() { - return this._sessionId; - } - - setHandler(handler) { - this._handler = handler; - } - - _dispose() { - if (this._handler) - this._handler.dispose(); - this._handler = null; - this._dispatcher = null; - } - - emitEvent(eventName, params) { - if (!this._dispatcher) - throw new Error(`Session has been disposed.`); - this._dispatcher._emitEvent(this._sessionId, eventName, params); - } - - async dispatch(method, params) { - if (!this._handler) - throw new Error(`Session does not have a handler!`); - if (!this._handler[method]) - throw new Error(`Handler for does not implement method "${method}"`); - return await this._handler[method](params); - } -} - -this.EXPORTED_SYMBOLS = ['Dispatcher']; -this.Dispatcher = Dispatcher; - diff --git a/browser_patches/firefox-beta/juggler/protocol/PageHandler.js b/browser_patches/firefox-beta/juggler/protocol/PageHandler.js deleted file mode 100644 index 415f395aaf..0000000000 --- a/browser_patches/firefox-beta/juggler/protocol/PageHandler.js +++ /dev/null @@ -1,466 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {NetworkObserver, PageNetwork} = ChromeUtils.import('chrome://juggler/content/NetworkObserver.js'); -const {PageTarget} = ChromeUtils.import('chrome://juggler/content/TargetRegistry.js'); -const {setTimeout} = ChromeUtils.import('resource://gre/modules/Timer.jsm'); - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; -const helper = new Helper(); - -function hashConsoleMessage(params) { - return params.location.lineNumber + ':' + params.location.columnNumber + ':' + params.location.url; -} - -class WorkerHandler { - constructor(session, contentChannel, workerId) { - this._session = session; - this._contentWorker = contentChannel.connect(workerId); - this._workerConsoleMessages = new Set(); - this._workerId = workerId; - - const emitWrappedProtocolEvent = eventName => { - return params => { - this._session.emitEvent('Page.dispatchMessageFromWorker', { - workerId, - message: JSON.stringify({method: eventName, params}), - }); - } - } - - this._eventListeners = [ - contentChannel.register(workerId, { - runtimeConsole: (params) => { - this._workerConsoleMessages.add(hashConsoleMessage(params)); - emitWrappedProtocolEvent('Runtime.console')(params); - }, - runtimeExecutionContextCreated: emitWrappedProtocolEvent('Runtime.executionContextCreated'), - runtimeExecutionContextDestroyed: emitWrappedProtocolEvent('Runtime.executionContextDestroyed'), - }), - ]; - } - - async sendMessage(message) { - const [domain, method] = message.method.split('.'); - if (domain !== 'Runtime') - throw new Error('ERROR: can only dispatch to Runtime domain inside worker'); - const result = await this._contentWorker.send(method, message.params); - this._session.emitEvent('Page.dispatchMessageFromWorker', { - workerId: this._workerId, - message: JSON.stringify({result, id: message.id}), - }); - } - - dispose() { - this._contentWorker.dispose(); - helper.removeListeners(this._eventListeners); - } -} - -class PageHandler { - constructor(target, session, contentChannel) { - this._session = session; - this._contentChannel = contentChannel; - this._contentPage = contentChannel.connect('page'); - this._workers = new Map(); - - this._pageTarget = target; - this._pageNetwork = PageNetwork.forPageTarget(target); - - const emitProtocolEvent = eventName => { - return (...args) => this._session.emitEvent(eventName, ...args); - } - - this._reportedFrameIds = new Set(); - this._networkEventsForUnreportedFrameIds = new Map(); - - // `Page.ready` protocol event is emitted whenever page has completed initialization, e.g. - // finished all the transient navigations to the `about:blank`. - // - // We'd like to avoid reporting meaningful events before the `Page.ready` since they are likely - // to be ignored by the protocol clients. - this._isPageReady = false; - - if (this._pageTarget.videoRecordingInfo()) - this._onVideoRecordingStarted(); - - this._eventListeners = [ - helper.on(this._pageTarget, PageTarget.Events.DialogOpened, this._onDialogOpened.bind(this)), - helper.on(this._pageTarget, PageTarget.Events.DialogClosed, this._onDialogClosed.bind(this)), - helper.on(this._pageTarget, PageTarget.Events.Crashed, () => { - this._session.emitEvent('Page.crashed', {}); - }), - helper.on(this._pageTarget, PageTarget.Events.ScreencastStarted, this._onVideoRecordingStarted.bind(this)), - helper.on(this._pageTarget, PageTarget.Events.ScreencastFrame, this._onScreencastFrame.bind(this)), - helper.on(this._pageNetwork, PageNetwork.Events.Request, this._handleNetworkEvent.bind(this, 'Network.requestWillBeSent')), - helper.on(this._pageNetwork, PageNetwork.Events.Response, this._handleNetworkEvent.bind(this, 'Network.responseReceived')), - helper.on(this._pageNetwork, PageNetwork.Events.RequestFinished, this._handleNetworkEvent.bind(this, 'Network.requestFinished')), - helper.on(this._pageNetwork, PageNetwork.Events.RequestFailed, this._handleNetworkEvent.bind(this, 'Network.requestFailed')), - contentChannel.register('page', { - pageBindingCalled: emitProtocolEvent('Page.bindingCalled'), - pageDispatchMessageFromWorker: emitProtocolEvent('Page.dispatchMessageFromWorker'), - pageEventFired: emitProtocolEvent('Page.eventFired'), - pageFileChooserOpened: emitProtocolEvent('Page.fileChooserOpened'), - pageFrameAttached: this._onFrameAttached.bind(this), - pageFrameDetached: emitProtocolEvent('Page.frameDetached'), - pageLinkClicked: emitProtocolEvent('Page.linkClicked'), - pageWillOpenNewWindowAsynchronously: emitProtocolEvent('Page.willOpenNewWindowAsynchronously'), - pageNavigationAborted: emitProtocolEvent('Page.navigationAborted'), - pageNavigationCommitted: emitProtocolEvent('Page.navigationCommitted'), - pageNavigationStarted: emitProtocolEvent('Page.navigationStarted'), - pageReady: this._onPageReady.bind(this), - pageSameDocumentNavigation: emitProtocolEvent('Page.sameDocumentNavigation'), - pageUncaughtError: emitProtocolEvent('Page.uncaughtError'), - pageWorkerCreated: this._onWorkerCreated.bind(this), - pageWorkerDestroyed: this._onWorkerDestroyed.bind(this), - runtimeConsole: params => { - const consoleMessageHash = hashConsoleMessage(params); - for (const worker of this._workers.values()) { - if (worker._workerConsoleMessages.has(consoleMessageHash)) { - worker._workerConsoleMessages.delete(consoleMessageHash); - return; - } - } - emitProtocolEvent('Runtime.console')(params); - }, - runtimeExecutionContextCreated: emitProtocolEvent('Runtime.executionContextCreated'), - runtimeExecutionContextDestroyed: emitProtocolEvent('Runtime.executionContextDestroyed'), - - webSocketCreated: emitProtocolEvent('Page.webSocketCreated'), - webSocketOpened: emitProtocolEvent('Page.webSocketOpened'), - webSocketClosed: emitProtocolEvent('Page.webSocketClosed'), - webSocketFrameReceived: emitProtocolEvent('Page.webSocketFrameReceived'), - webSocketFrameSent: emitProtocolEvent('Page.webSocketFrameSent'), - }), - ]; - } - - async dispose() { - this._contentPage.dispose(); - helper.removeListeners(this._eventListeners); - } - - _onVideoRecordingStarted() { - const info = this._pageTarget.videoRecordingInfo(); - this._session.emitEvent('Page.videoRecordingStarted', { screencastId: info.sessionId, file: info.file }); - } - - _onScreencastFrame(params) { - this._session.emitEvent('Page.screencastFrame', params); - } - - _onPageReady(event) { - this._isPageReady = true; - this._session.emitEvent('Page.ready'); - for (const dialog of this._pageTarget.dialogs()) - this._onDialogOpened(dialog); - } - - _onDialogOpened(dialog) { - if (!this._isPageReady) - return; - this._session.emitEvent('Page.dialogOpened', { - dialogId: dialog.id(), - type: dialog.type(), - message: dialog.message(), - defaultValue: dialog.defaultValue(), - }); - } - - _onDialogClosed(dialog) { - if (!this._isPageReady) - return; - this._session.emitEvent('Page.dialogClosed', { dialogId: dialog.id(), }); - } - - _onWorkerCreated({workerId, frameId, url}) { - const worker = new WorkerHandler(this._session, this._contentChannel, workerId); - this._workers.set(workerId, worker); - this._session.emitEvent('Page.workerCreated', {workerId, frameId, url}); - } - - _onWorkerDestroyed({workerId}) { - const worker = this._workers.get(workerId); - if (!worker) - return; - this._workers.delete(workerId); - worker.dispose(); - this._session.emitEvent('Page.workerDestroyed', {workerId}); - } - - _handleNetworkEvent(protocolEventName, eventDetails, frameId) { - if (!this._reportedFrameIds.has(frameId)) { - let events = this._networkEventsForUnreportedFrameIds.get(frameId); - if (!events) { - events = []; - this._networkEventsForUnreportedFrameIds.set(frameId, events); - } - events.push({eventName: protocolEventName, eventDetails}); - } else { - this._session.emitEvent(protocolEventName, eventDetails); - } - } - - _onFrameAttached({frameId, parentFrameId}) { - this._session.emitEvent('Page.frameAttached', {frameId, parentFrameId}); - this._reportedFrameIds.add(frameId); - const events = this._networkEventsForUnreportedFrameIds.get(frameId) || []; - this._networkEventsForUnreportedFrameIds.delete(frameId); - for (const {eventName, eventDetails} of events) - this._session.emitEvent(eventName, eventDetails); - } - - async ['Page.close']({runBeforeUnload}) { - // Postpone target close to deliver response in session. - Services.tm.dispatchToMainThread(() => { - this._pageTarget.close(runBeforeUnload); - }); - } - - async ['Page.setViewportSize']({viewportSize}) { - await this._pageTarget.setViewportSize(viewportSize === null ? undefined : viewportSize); - } - - async ['Runtime.evaluate'](options) { - return await this._contentPage.send('evaluate', options); - } - - async ['Runtime.callFunction'](options) { - return await this._contentPage.send('callFunction', options); - } - - async ['Runtime.getObjectProperties'](options) { - return await this._contentPage.send('getObjectProperties', options); - } - - async ['Runtime.disposeObject'](options) { - return await this._contentPage.send('disposeObject', options); - } - - async ['Network.getResponseBody']({requestId}) { - return this._pageNetwork.getResponseBody(requestId); - } - - async ['Network.setExtraHTTPHeaders']({headers}) { - this._pageNetwork.setExtraHTTPHeaders(headers); - } - - async ['Network.setRequestInterception']({enabled}) { - if (enabled) - this._pageNetwork.enableRequestInterception(); - else - this._pageNetwork.disableRequestInterception(); - } - - async ['Network.resumeInterceptedRequest']({requestId, url, method, headers, postData}) { - this._pageNetwork.resumeInterceptedRequest(requestId, url, method, headers, postData); - } - - async ['Network.abortInterceptedRequest']({requestId, errorCode}) { - this._pageNetwork.abortInterceptedRequest(requestId, errorCode); - } - - async ['Network.fulfillInterceptedRequest']({requestId, status, statusText, headers, base64body}) { - this._pageNetwork.fulfillInterceptedRequest(requestId, status, statusText, headers, base64body); - } - - async ['Accessibility.getFullAXTree'](params) { - return await this._contentPage.send('getFullAXTree', params); - } - - async ['Page.setFileInputFiles'](options) { - return await this._contentPage.send('setFileInputFiles', options); - } - - async ['Page.setEmulatedMedia']({colorScheme, type, reducedMotion, forcedColors}) { - this._pageTarget.setColorScheme(colorScheme || null); - this._pageTarget.setReducedMotion(reducedMotion || null); - this._pageTarget.setForcedColors(forcedColors || null); - this._pageTarget.setEmulatedMedia(type); - } - - async ['Page.bringToFront'](options) { - this._pageTarget._window.focus(); - } - - async ['Page.setCacheDisabled'](options) { - return await this._contentPage.send('setCacheDisabled', options); - } - - async ['Page.addBinding'](options) { - return await this._contentPage.send('addBinding', options); - } - - async ['Page.adoptNode'](options) { - return await this._contentPage.send('adoptNode', options); - } - - async ['Page.screenshot']({ mimeType, clip, omitDeviceScaleFactor }) { - const rect = new DOMRect(clip.x, clip.y, clip.width, clip.height); - - const browsingContext = this._pageTarget.linkedBrowser().browsingContext; - // `win.devicePixelRatio` returns a non-overriden value to priveleged code. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1761032 - // See https://phabricator.services.mozilla.com/D141323 - const devicePixelRatio = browsingContext.overrideDPPX || this._pageTarget._window.devicePixelRatio; - const scale = omitDeviceScaleFactor ? 1 : devicePixelRatio; - const canvasWidth = rect.width * scale; - const canvasHeight = rect.height * scale; - - const MAX_CANVAS_DIMENSIONS = 32767; - const MAX_CANVAS_AREA = 472907776; - if (canvasWidth > MAX_CANVAS_DIMENSIONS || canvasHeight > MAX_CANVAS_DIMENSIONS) - throw new Error('Cannot take screenshot larger than ' + MAX_CANVAS_DIMENSIONS); - if (canvasWidth * canvasHeight > MAX_CANVAS_AREA) - throw new Error('Cannot take screenshot with more than ' + MAX_CANVAS_AREA + ' pixels'); - - let snapshot; - while (!snapshot) { - try { - //TODO(fission): browsingContext will change in case of cross-group navigation. - snapshot = await browsingContext.currentWindowGlobal.drawSnapshot( - rect, - scale, - "rgb(255,255,255)" - ); - } catch (e) { - // The currentWindowGlobal.drawSnapshot might throw - // NS_ERROR_LOSS_OF_SIGNIFICANT_DATA if called during navigation. - // wait a little and re-try. - await new Promise(x => setTimeout(x, 50)); - } - } - - const win = browsingContext.topChromeWindow.ownerGlobal; - const canvas = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas'); - canvas.width = canvasWidth; - canvas.height = canvasHeight; - let ctx = canvas.getContext('2d'); - ctx.drawImage(snapshot, 0, 0); - snapshot.close(); - const dataURL = canvas.toDataURL(mimeType); - return { data: dataURL.substring(dataURL.indexOf(',') + 1) }; - } - - async ['Page.getContentQuads'](options) { - return await this._contentPage.send('getContentQuads', options); - } - - async ['Page.navigate'](options) { - return await this._contentPage.send('navigate', options); - } - - async ['Page.goBack'](options) { - return await this._contentPage.send('goBack', options); - } - - async ['Page.goForward'](options) { - return await this._contentPage.send('goForward', options); - } - - async ['Page.reload'](options) { - return await this._contentPage.send('reload', options); - } - - async ['Page.describeNode'](options) { - return await this._contentPage.send('describeNode', options); - } - - async ['Page.scrollIntoViewIfNeeded'](options) { - return await this._contentPage.send('scrollIntoViewIfNeeded', options); - } - - async ['Page.setInitScripts']({ scripts }) { - return await this._pageTarget.setInitScripts(scripts); - } - - async ['Page.dispatchKeyEvent'](options) { - return await this._contentPage.send('dispatchKeyEvent', options); - } - - async ['Page.dispatchTouchEvent'](options) { - return await this._contentPage.send('dispatchTouchEvent', options); - } - - async ['Page.dispatchTapEvent'](options) { - return await this._contentPage.send('dispatchTapEvent', options); - } - - async ['Page.dispatchMouseEvent'](options) { - return await this._contentPage.send('dispatchMouseEvent', options); - } - - async ['Page.dispatchWheelEvent']({x, y, button, deltaX, deltaY, deltaZ, modifiers }) { - const boundingBox = this._pageTarget._linkedBrowser.getBoundingClientRect(); - x += boundingBox.left; - y += boundingBox.top; - const deltaMode = 0; // WheelEvent.DOM_DELTA_PIXEL - const lineOrPageDeltaX = deltaX > 0 ? Math.floor(deltaX) : Math.ceil(deltaX); - const lineOrPageDeltaY = deltaY > 0 ? Math.floor(deltaY) : Math.ceil(deltaY); - - const win = this._pageTarget._window; - win.windowUtils.sendWheelEvent( - x, - y, - deltaX, - deltaY, - deltaZ, - deltaMode, - modifiers, - lineOrPageDeltaX, - lineOrPageDeltaY, - 0 /* options */); - } - - async ['Page.insertText'](options) { - return await this._contentPage.send('insertText', options); - } - - async ['Page.crash'](options) { - return await this._contentPage.send('crash', options); - } - - async ['Page.handleDialog']({dialogId, accept, promptText}) { - const dialog = this._pageTarget.dialog(dialogId); - if (!dialog) - throw new Error('Failed to find dialog with id = ' + dialogId); - if (accept) - dialog.accept(promptText); - else - dialog.dismiss(); - } - - async ['Page.setInterceptFileChooserDialog'](options) { - return await this._contentPage.send('setInterceptFileChooserDialog', options); - } - - async ['Page.startScreencast'](options) { - return await this._pageTarget.startScreencast(options); - } - - async ['Page.screencastFrameAck'](options) { - await this._pageTarget.screencastFrameAck(options); - } - - async ['Page.stopScreencast'](options) { - await this._pageTarget.stopScreencast(options); - } - - async ['Page.sendMessageToWorker']({workerId, message}) { - const worker = this._workers.get(workerId); - if (!worker) - throw new Error('ERROR: cannot find worker with id ' + workerId); - return await worker.sendMessage(JSON.parse(message)); - } -} - -var EXPORTED_SYMBOLS = ['PageHandler']; -this.PageHandler = PageHandler; diff --git a/browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js b/browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js deleted file mode 100644 index 5799038f19..0000000000 --- a/browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js +++ /dev/null @@ -1,147 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const t = {}; - -t.String = function(x, details = {}, path = ['']) { - if (typeof x === 'string' || typeof x === 'String') - return true; - details.error = `Expected "${path.join('.')}" to be |string|; found |${typeof x}| \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Number = function(x, details = {}, path = ['']) { - if (typeof x === 'number') - return true; - details.error = `Expected "${path.join('.')}" to be |number|; found |${typeof x}| \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Boolean = function(x, details = {}, path = ['']) { - if (typeof x === 'boolean') - return true; - details.error = `Expected "${path.join('.')}" to be |boolean|; found |${typeof x}| \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Null = function(x, details = {}, path = ['']) { - if (Object.is(x, null)) - return true; - details.error = `Expected "${path.join('.')}" to be \`null\`; found \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Undefined = function(x, details = {}, path = ['']) { - if (Object.is(x, undefined)) - return true; - details.error = `Expected "${path.join('.')}" to be \`undefined\`; found \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Any = x => true, - -t.Enum = function(values) { - return function(x, details = {}, path = ['']) { - if (values.indexOf(x) !== -1) - return true; - details.error = `Expected "${path.join('.')}" to be one of [${values.join(', ')}]; found \`${JSON.stringify(x)}\` (${typeof x}) instead.`; - return false; - } -} - -t.Nullable = function(scheme) { - return function(x, details = {}, path = ['']) { - if (Object.is(x, null)) - return true; - return checkScheme(scheme, x, details, path); - } -} - -t.Optional = function(scheme) { - return function(x, details = {}, path = ['']) { - if (Object.is(x, undefined)) - return true; - return checkScheme(scheme, x, details, path); - } -} - -t.Array = function(scheme) { - return function(x, details = {}, path = ['']) { - if (!Array.isArray(x)) { - details.error = `Expected "${path.join('.')}" to be an array; found \`${JSON.stringify(x)}\` (${typeof x}) instead.`; - return false; - } - const lastPathElement = path[path.length - 1]; - for (let i = 0; i < x.length; ++i) { - path[path.length - 1] = lastPathElement + `[${i}]`; - if (!checkScheme(scheme, x[i], details, path)) - return false; - } - path[path.length - 1] = lastPathElement; - return true; - } -} - -t.Recursive = function(types, schemeName) { - return function(x, details = {}, path = ['']) { - const scheme = types[schemeName]; - return checkScheme(scheme, x, details, path); - } -} - -function beauty(path, obj) { - if (path.length === 1) - return `object ${JSON.stringify(obj, null, 2)}`; - return `property "${path.join('.')}" - ${JSON.stringify(obj, null, 2)}`; -} - -function checkScheme(scheme, x, details = {}, path = ['']) { - if (!scheme) - throw new Error(`ILLDEFINED SCHEME: ${path.join('.')}`); - if (typeof scheme === 'object') { - if (!x) { - details.error = `Object "${path.join('.')}" is undefined, but has some scheme`; - return false; - } - for (const [propertyName, aScheme] of Object.entries(scheme)) { - path.push(propertyName); - const result = checkScheme(aScheme, x[propertyName], details, path); - path.pop(); - if (!result) - return false; - } - for (const propertyName of Object.keys(x)) { - if (!scheme[propertyName]) { - path.push(propertyName); - details.error = `Found ${beauty(path, x[propertyName])} which is not described in this scheme`; - return false; - } - } - return true; - } - return scheme(x, details, path); -} - -/* - -function test(scheme, obj) { - const details = {}; - if (!checkScheme(scheme, obj, details)) { - dump(`FAILED: ${JSON.stringify(obj)} - details.error: ${details.error} - `); - } else { - dump(`SUCCESS: ${JSON.stringify(obj)} -`); - } -} - -test(t.Array(t.String), ['a', 'b', 2, 'c']); -test(t.Either(t.String, t.Number), {}); - -*/ - -this.t = t; -this.checkScheme = checkScheme; -this.EXPORTED_SYMBOLS = ['t', 'checkScheme']; diff --git a/browser_patches/firefox-beta/juggler/protocol/Protocol.js b/browser_patches/firefox-beta/juggler/protocol/Protocol.js deleted file mode 100644 index be0f15af0d..0000000000 --- a/browser_patches/firefox-beta/juggler/protocol/Protocol.js +++ /dev/null @@ -1,993 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js'); - -// Protocol-specific types. -const browserTypes = {}; - -browserTypes.TargetInfo = { - type: t.Enum(['page']), - targetId: t.String, - browserContextId: t.Optional(t.String), - // PageId of parent tab, if any. - openerId: t.Optional(t.String), -}; - -browserTypes.CookieOptions = { - name: t.String, - value: t.String, - url: t.Optional(t.String), - domain: t.Optional(t.String), - path: t.Optional(t.String), - secure: t.Optional(t.Boolean), - httpOnly: t.Optional(t.Boolean), - sameSite: t.Optional(t.Enum(['Strict', 'Lax', 'None'])), - expires: t.Optional(t.Number), -}; - -browserTypes.Cookie = { - name: t.String, - domain: t.String, - path: t.String, - value: t.String, - expires: t.Number, - size: t.Number, - httpOnly: t.Boolean, - secure: t.Boolean, - session: t.Boolean, - sameSite: t.Enum(['Strict', 'Lax', 'None']), -}; - -browserTypes.Geolocation = { - latitude: t.Number, - longitude: t.Number, - accuracy: t.Optional(t.Number), -}; - -browserTypes.DownloadOptions = { - behavior: t.Optional(t.Enum(['saveToDisk', 'cancel'])), - downloadsDir: t.Optional(t.String), -}; - -const pageTypes = {}; -pageTypes.DOMPoint = { - x: t.Number, - y: t.Number, -}; - -pageTypes.Rect = { - x: t.Number, - y: t.Number, - width: t.Number, - height: t.Number, -}; - -pageTypes.Size = { - width: t.Number, - height: t.Number, -}; - -pageTypes.Viewport = { - viewportSize: pageTypes.Size, - deviceScaleFactor: t.Optional(t.Number), -}; - -pageTypes.DOMQuad = { - p1: pageTypes.DOMPoint, - p2: pageTypes.DOMPoint, - p3: pageTypes.DOMPoint, - p4: pageTypes.DOMPoint, -}; - -pageTypes.TouchPoint = { - x: t.Number, - y: t.Number, - radiusX: t.Optional(t.Number), - radiusY: t.Optional(t.Number), - rotationAngle: t.Optional(t.Number), - force: t.Optional(t.Number), -}; - -pageTypes.Clip = { - x: t.Number, - y: t.Number, - width: t.Number, - height: t.Number, -}; - -pageTypes.InitScript = { - script: t.String, - worldName: t.Optional(t.String), -}; - -const runtimeTypes = {}; -runtimeTypes.RemoteObject = { - type: t.Optional(t.Enum(['object', 'function', 'undefined', 'string', 'number', 'boolean', 'symbol', 'bigint'])), - subtype: t.Optional(t.Enum(['array', 'null', 'node', 'regexp', 'date', 'map', 'set', 'weakmap', 'weakset', 'error', 'proxy', 'promise', 'typedarray'])), - objectId: t.Optional(t.String), - unserializableValue: t.Optional(t.Enum(['Infinity', '-Infinity', '-0', 'NaN'])), - value: t.Any -}; - -runtimeTypes.ObjectProperty = { - name: t.String, - value: runtimeTypes.RemoteObject, -}; - -runtimeTypes.ScriptLocation = { - columnNumber: t.Number, - lineNumber: t.Number, - url: t.String, -}; - -runtimeTypes.ExceptionDetails = { - text: t.Optional(t.String), - stack: t.Optional(t.String), - value: t.Optional(t.Any), -}; - -runtimeTypes.CallFunctionArgument = { - objectId: t.Optional(t.String), - unserializableValue: t.Optional(t.Enum(['Infinity', '-Infinity', '-0', 'NaN'])), - value: t.Any, -}; - -runtimeTypes.AuxData = { - frameId: t.Optional(t.String), - name: t.Optional(t.String), -}; - -const axTypes = {}; -axTypes.AXTree = { - role: t.String, - name: t.String, - children: t.Optional(t.Array(t.Recursive(axTypes, 'AXTree'))), - - selected: t.Optional(t.Boolean), - focused: t.Optional(t.Boolean), - pressed: t.Optional(t.Boolean), - focusable: t.Optional(t.Boolean), - haspopup: t.Optional(t.String), - required: t.Optional(t.Boolean), - invalid: t.Optional(t.Boolean), - modal: t.Optional(t.Boolean), - editable: t.Optional(t.Boolean), - busy: t.Optional(t.Boolean), - multiline: t.Optional(t.Boolean), - readonly: t.Optional(t.Boolean), - checked: t.Optional(t.Enum(['mixed', true])), - expanded: t.Optional(t.Boolean), - disabled: t.Optional(t.Boolean), - multiselectable: t.Optional(t.Boolean), - - value: t.Optional(t.String), - description: t.Optional(t.String), - - roledescription: t.Optional(t.String), - valuetext: t.Optional(t.String), - orientation: t.Optional(t.String), - autocomplete: t.Optional(t.String), - keyshortcuts: t.Optional(t.String), - - level: t.Optional(t.Number), - - tag: t.Optional(t.String), - - foundObject: t.Optional(t.Boolean), -} - -const networkTypes = {}; - -networkTypes.HTTPHeader = { - name: t.String, - value: t.String, -}; - -networkTypes.HTTPCredentials = { - username: t.String, - password: t.String, -}; - -networkTypes.SecurityDetails = { - protocol: t.String, - subjectName: t.String, - issuer: t.String, - validFrom: t.Number, - validTo: t.Number, -}; - -networkTypes.ResourceTiming = { - startTime: t.Number, - domainLookupStart: t.Number, - domainLookupEnd: t.Number, - connectStart: t.Number, - secureConnectionStart: t.Number, - connectEnd: t.Number, - requestStart: t.Number, - responseStart: t.Number, -}; - -const Browser = { - targets: ['browser'], - - types: browserTypes, - - events: { - 'attachedToTarget': { - sessionId: t.String, - targetInfo: browserTypes.TargetInfo, - }, - 'detachedFromTarget': { - sessionId: t.String, - targetId: t.String, - }, - 'downloadCreated': { - uuid: t.String, - browserContextId: t.Optional(t.String), - pageTargetId: t.String, - url: t.String, - suggestedFileName: t.String, - }, - 'downloadFinished': { - uuid: t.String, - canceled: t.Optional(t.Boolean), - error: t.Optional(t.String), - }, - 'videoRecordingFinished': { - screencastId: t.String, - }, - }, - - methods: { - 'enable': { - params: { - attachToDefaultContext: t.Boolean, - }, - }, - 'createBrowserContext': { - params: { - removeOnDetach: t.Optional(t.Boolean), - }, - returns: { - browserContextId: t.String, - }, - }, - 'removeBrowserContext': { - params: { - browserContextId: t.String, - }, - }, - 'newPage': { - params: { - browserContextId: t.Optional(t.String), - }, - returns: { - targetId: t.String, - } - }, - 'close': {}, - 'getInfo': { - returns: { - userAgent: t.String, - version: t.String, - }, - }, - 'setExtraHTTPHeaders': { - params: { - browserContextId: t.Optional(t.String), - headers: t.Array(networkTypes.HTTPHeader), - }, - }, - 'setBrowserProxy': { - params: { - type: t.Enum(['http', 'https', 'socks', 'socks4']), - bypass: t.Array(t.String), - host: t.String, - port: t.Number, - username: t.Optional(t.String), - password: t.Optional(t.String), - }, - }, - 'setContextProxy': { - params: { - browserContextId: t.Optional(t.String), - type: t.Enum(['http', 'https', 'socks', 'socks4']), - bypass: t.Array(t.String), - host: t.String, - port: t.Number, - username: t.Optional(t.String), - password: t.Optional(t.String), - }, - }, - 'setHTTPCredentials': { - params: { - browserContextId: t.Optional(t.String), - credentials: t.Nullable(networkTypes.HTTPCredentials), - }, - }, - 'setRequestInterception': { - params: { - browserContextId: t.Optional(t.String), - enabled: t.Boolean, - }, - }, - 'setGeolocationOverride': { - params: { - browserContextId: t.Optional(t.String), - geolocation: t.Nullable(browserTypes.Geolocation), - } - }, - 'setUserAgentOverride': { - params: { - browserContextId: t.Optional(t.String), - userAgent: t.Nullable(t.String), - } - }, - 'setPlatformOverride': { - params: { - browserContextId: t.Optional(t.String), - platform: t.Nullable(t.String), - } - }, - 'setBypassCSP': { - params: { - browserContextId: t.Optional(t.String), - bypassCSP: t.Nullable(t.Boolean), - } - }, - 'setIgnoreHTTPSErrors': { - params: { - browserContextId: t.Optional(t.String), - ignoreHTTPSErrors: t.Nullable(t.Boolean), - } - }, - 'setJavaScriptDisabled': { - params: { - browserContextId: t.Optional(t.String), - javaScriptDisabled: t.Boolean, - } - }, - 'setLocaleOverride': { - params: { - browserContextId: t.Optional(t.String), - locale: t.Nullable(t.String), - } - }, - 'setTimezoneOverride': { - params: { - browserContextId: t.Optional(t.String), - timezoneId: t.Nullable(t.String), - } - }, - 'setDownloadOptions': { - params: { - browserContextId: t.Optional(t.String), - downloadOptions: t.Nullable(browserTypes.DownloadOptions), - } - }, - 'setTouchOverride': { - params: { - browserContextId: t.Optional(t.String), - hasTouch: t.Nullable(t.Boolean), - } - }, - 'setDefaultViewport': { - params: { - browserContextId: t.Optional(t.String), - viewport: t.Nullable(pageTypes.Viewport), - } - }, - 'setScrollbarsHidden': { - params: { - browserContextId: t.Optional(t.String), - hidden: t.Boolean, - } - }, - 'setInitScripts': { - params: { - browserContextId: t.Optional(t.String), - scripts: t.Array(pageTypes.InitScript), - } - }, - 'addBinding': { - params: { - browserContextId: t.Optional(t.String), - worldName: t.Optional(t.String), - name: t.String, - script: t.String, - }, - }, - 'grantPermissions': { - params: { - origin: t.String, - browserContextId: t.Optional(t.String), - permissions: t.Array(t.String), - }, - }, - 'resetPermissions': { - params: { - browserContextId: t.Optional(t.String), - } - }, - 'setCookies': { - params: { - browserContextId: t.Optional(t.String), - cookies: t.Array(browserTypes.CookieOptions), - } - }, - 'clearCookies': { - params: { - browserContextId: t.Optional(t.String), - } - }, - 'getCookies': { - params: { - browserContextId: t.Optional(t.String) - }, - returns: { - cookies: t.Array(browserTypes.Cookie), - }, - }, - 'setOnlineOverride': { - params: { - browserContextId: t.Optional(t.String), - override: t.Nullable(t.Enum(['online', 'offline'])), - } - }, - 'setColorScheme': { - params: { - browserContextId: t.Optional(t.String), - colorScheme: t.Nullable(t.Enum(['dark', 'light', 'no-preference'])), - }, - }, - 'setReducedMotion': { - params: { - browserContextId: t.Optional(t.String), - reducedMotion: t.Nullable(t.Enum(['reduce', 'no-preference'])), - }, - }, - 'setForcedColors': { - params: { - browserContextId: t.Optional(t.String), - forcedColors: t.Nullable(t.Enum(['active', 'none'])), - }, - }, - 'setVideoRecordingOptions': { - params: { - browserContextId: t.Optional(t.String), - options: t.Optional({ - dir: t.String, - width: t.Number, - height: t.Number, - }), - }, - }, - 'cancelDownload': { - params: { - uuid: t.Optional(t.String), - } - } - }, -}; - -const Network = { - targets: ['page'], - types: networkTypes, - events: { - 'requestWillBeSent': { - // frameId may be absent for redirected requests. - frameId: t.Optional(t.String), - requestId: t.String, - // RequestID of redirected request. - redirectedFrom: t.Optional(t.String), - postData: t.Optional(t.String), - headers: t.Array(networkTypes.HTTPHeader), - isIntercepted: t.Boolean, - url: t.String, - method: t.String, - navigationId: t.Optional(t.String), - cause: t.String, - internalCause: t.String, - }, - 'responseReceived': { - securityDetails: t.Nullable(networkTypes.SecurityDetails), - requestId: t.String, - fromCache: t.Boolean, - remoteIPAddress: t.Optional(t.String), - remotePort: t.Optional(t.Number), - status: t.Number, - statusText: t.String, - headers: t.Array(networkTypes.HTTPHeader), - timing: networkTypes.ResourceTiming, - fromServiceWorker: t.Boolean, - }, - 'requestFinished': { - requestId: t.String, - responseEndTime: t.Number, - transferSize: t.Number, - encodedBodySize: t.Number, - protocolVersion: t.Optional(t.String), - }, - 'requestFailed': { - requestId: t.String, - errorCode: t.String, - }, - }, - methods: { - 'setRequestInterception': { - params: { - enabled: t.Boolean, - }, - }, - 'setExtraHTTPHeaders': { - params: { - headers: t.Array(networkTypes.HTTPHeader), - }, - }, - 'abortInterceptedRequest': { - params: { - requestId: t.String, - errorCode: t.String, - }, - }, - 'resumeInterceptedRequest': { - params: { - requestId: t.String, - url: t.Optional(t.String), - method: t.Optional(t.String), - headers: t.Optional(t.Array(networkTypes.HTTPHeader)), - postData: t.Optional(t.String), - }, - }, - 'fulfillInterceptedRequest': { - params: { - requestId: t.String, - status: t.Number, - statusText: t.String, - headers: t.Array(networkTypes.HTTPHeader), - base64body: t.Optional(t.String), // base64-encoded - }, - }, - 'getResponseBody': { - params: { - requestId: t.String, - }, - returns: { - base64body: t.String, - evicted: t.Optional(t.Boolean), - }, - }, - }, -}; - -const Runtime = { - targets: ['page'], - types: runtimeTypes, - events: { - 'executionContextCreated': { - executionContextId: t.String, - auxData: runtimeTypes.AuxData, - }, - 'executionContextDestroyed': { - executionContextId: t.String, - }, - 'console': { - executionContextId: t.String, - args: t.Array(runtimeTypes.RemoteObject), - type: t.String, - location: runtimeTypes.ScriptLocation, - }, - }, - methods: { - 'evaluate': { - params: { - // Pass frameId here. - executionContextId: t.String, - expression: t.String, - returnByValue: t.Optional(t.Boolean), - }, - - returns: { - result: t.Optional(runtimeTypes.RemoteObject), - exceptionDetails: t.Optional(runtimeTypes.ExceptionDetails), - } - }, - 'callFunction': { - params: { - // Pass frameId here. - executionContextId: t.String, - functionDeclaration: t.String, - returnByValue: t.Optional(t.Boolean), - args: t.Array(runtimeTypes.CallFunctionArgument), - }, - - returns: { - result: t.Optional(runtimeTypes.RemoteObject), - exceptionDetails: t.Optional(runtimeTypes.ExceptionDetails), - } - }, - 'disposeObject': { - params: { - executionContextId: t.String, - objectId: t.String, - }, - }, - - 'getObjectProperties': { - params: { - executionContextId: t.String, - objectId: t.String, - }, - - returns: { - properties: t.Array(runtimeTypes.ObjectProperty), - } - }, - }, -}; - -const Page = { - targets: ['page'], - - types: pageTypes, - events: { - 'ready': { - }, - 'crashed': { - }, - 'eventFired': { - frameId: t.String, - name: t.Enum(['load', 'DOMContentLoaded']), - }, - 'uncaughtError': { - frameId: t.String, - message: t.String, - stack: t.String, - }, - 'frameAttached': { - frameId: t.String, - parentFrameId: t.Optional(t.String), - }, - 'frameDetached': { - frameId: t.String, - }, - 'navigationStarted': { - frameId: t.String, - navigationId: t.String, - url: t.String, - }, - 'navigationCommitted': { - frameId: t.String, - // |navigationId| can only be null in response to enable. - navigationId: t.Optional(t.String), - url: t.String, - // frame.id or frame.name - name: t.String, - }, - 'navigationAborted': { - frameId: t.String, - navigationId: t.String, - errorText: t.String, - }, - 'sameDocumentNavigation': { - frameId: t.String, - url: t.String, - }, - 'dialogOpened': { - dialogId: t.String, - type: t.Enum(['prompt', 'alert', 'confirm', 'beforeunload']), - message: t.String, - defaultValue: t.Optional(t.String), - }, - 'dialogClosed': { - dialogId: t.String, - }, - 'bindingCalled': { - executionContextId: t.String, - name: t.String, - payload: t.Any, - }, - 'linkClicked': { - phase: t.Enum(['before', 'after']), - }, - 'willOpenNewWindowAsynchronously': {}, - 'fileChooserOpened': { - executionContextId: t.String, - element: runtimeTypes.RemoteObject - }, - 'workerCreated': { - workerId: t.String, - frameId: t.String, - url: t.String, - }, - 'workerDestroyed': { - workerId: t.String, - }, - 'dispatchMessageFromWorker': { - workerId: t.String, - message: t.String, - }, - 'videoRecordingStarted': { - screencastId: t.String, - file: t.String, - }, - 'webSocketCreated': { - frameId: t.String, - wsid: t.String, - requestURL: t.String, - }, - 'webSocketOpened': { - frameId: t.String, - requestId: t.String, - wsid: t.String, - effectiveURL: t.String, - }, - 'webSocketClosed': { - frameId: t.String, - wsid: t.String, - error: t.String, - }, - 'webSocketFrameSent': { - frameId: t.String, - wsid: t.String, - opcode: t.Number, - data: t.String, - }, - 'webSocketFrameReceived': { - frameId: t.String, - wsid: t.String, - opcode: t.Number, - data: t.String, - }, - 'screencastFrame': { - data: t.String, - deviceWidth: t.Number, - deviceHeight: t.Number, - }, - }, - - methods: { - 'close': { - params: { - runBeforeUnload: t.Optional(t.Boolean), - }, - }, - 'setFileInputFiles': { - params: { - frameId: t.String, - objectId: t.String, - files: t.Array(t.String), - }, - }, - 'addBinding': { - params: { - worldName: t.Optional(t.String), - name: t.String, - script: t.String, - }, - }, - 'setViewportSize': { - params: { - viewportSize: t.Nullable(pageTypes.Size), - }, - }, - 'bringToFront': { - params: { - }, - }, - 'setEmulatedMedia': { - params: { - type: t.Optional(t.Enum(['screen', 'print', ''])), - colorScheme: t.Optional(t.Enum(['dark', 'light', 'no-preference'])), - reducedMotion: t.Optional(t.Enum(['reduce', 'no-preference'])), - forcedColors: t.Optional(t.Enum(['active', 'none'])), - }, - }, - 'setCacheDisabled': { - params: { - cacheDisabled: t.Boolean, - }, - }, - 'describeNode': { - params: { - frameId: t.String, - objectId: t.String, - }, - returns: { - contentFrameId: t.Optional(t.String), - ownerFrameId: t.Optional(t.String), - }, - }, - 'scrollIntoViewIfNeeded': { - params: { - frameId: t.String, - objectId: t.String, - rect: t.Optional(pageTypes.Rect), - }, - }, - 'setInitScripts': { - params: { - scripts: t.Array(pageTypes.InitScript) - } - }, - 'navigate': { - params: { - frameId: t.String, - url: t.String, - referer: t.Optional(t.String), - }, - returns: { - navigationId: t.Nullable(t.String), - navigationURL: t.Nullable(t.String), - } - }, - 'goBack': { - params: { - frameId: t.String, - }, - returns: { - success: t.Boolean, - }, - }, - 'goForward': { - params: { - frameId: t.String, - }, - returns: { - success: t.Boolean, - }, - }, - 'reload': { - params: { - frameId: t.String, - }, - }, - 'adoptNode': { - params: { - frameId: t.String, - objectId: t.String, - executionContextId: t.String, - }, - returns: { - remoteObject: t.Nullable(runtimeTypes.RemoteObject), - }, - }, - 'screenshot': { - params: { - mimeType: t.Enum(['image/png', 'image/jpeg']), - clip: pageTypes.Clip, - omitDeviceScaleFactor: t.Optional(t.Boolean), - }, - returns: { - data: t.String, - } - }, - 'getContentQuads': { - params: { - frameId: t.String, - objectId: t.String, - }, - returns: { - quads: t.Array(pageTypes.DOMQuad), - }, - }, - 'dispatchKeyEvent': { - params: { - type: t.String, - key: t.String, - keyCode: t.Number, - location: t.Number, - code: t.String, - repeat: t.Boolean, - text: t.Optional(t.String), - } - }, - 'dispatchTouchEvent': { - params: { - type: t.Enum(['touchStart', 'touchEnd', 'touchMove', 'touchCancel']), - touchPoints: t.Array(pageTypes.TouchPoint), - modifiers: t.Number, - }, - returns: { - defaultPrevented: t.Boolean, - } - }, - 'dispatchTapEvent': { - params: { - x: t.Number, - y: t.Number, - modifiers: t.Number, - } - }, - 'dispatchMouseEvent': { - params: { - type: t.String, - button: t.Number, - x: t.Number, - y: t.Number, - modifiers: t.Number, - clickCount: t.Optional(t.Number), - buttons: t.Number, - } - }, - 'dispatchWheelEvent': { - params: { - x: t.Number, - y: t.Number, - deltaX: t.Number, - deltaY: t.Number, - deltaZ: t.Number, - modifiers: t.Number, - } - }, - 'insertText': { - params: { - text: t.String, - } - }, - 'crash': { - params: {} - }, - 'handleDialog': { - params: { - dialogId: t.String, - accept: t.Boolean, - promptText: t.Optional(t.String), - }, - }, - 'setInterceptFileChooserDialog': { - params: { - enabled: t.Boolean, - }, - }, - 'sendMessageToWorker': { - params: { - frameId: t.String, - workerId: t.String, - message: t.String, - }, - }, - 'startScreencast': { - params: { - width: t.Number, - height: t.Number, - quality: t.Number, - }, - returns: { - screencastId: t.String, - }, - }, - 'screencastFrameAck': { - params: { - screencastId: t.String, - }, - }, - 'stopScreencast': { - }, - }, -}; - - -const Accessibility = { - targets: ['page'], - types: axTypes, - events: {}, - methods: { - 'getFullAXTree': { - params: { - objectId: t.Optional(t.String), - }, - returns: { - tree: axTypes.AXTree - }, - } - } -} - -this.protocol = { - domains: {Browser, Page, Runtime, Network, Accessibility}, -}; -this.checkScheme = checkScheme; -this.EXPORTED_SYMBOLS = ['protocol', 'checkScheme']; diff --git a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp b/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp deleted file mode 100644 index 88d1791dde..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "HeadlessWindowCapturer.h" - -#include "api/video/i420_buffer.h" -#include "HeadlessWidget.h" -#include "libyuv.h" -#include "mozilla/EndianUtils.h" -#include "mozilla/gfx/DataSurfaceHelpers.h" -#include "rtc_base/ref_counted_object.h" -#include "rtc_base/time_utils.h" -#include "api/scoped_refptr.h" - -using namespace mozilla::widget; -using namespace webrtc; - -namespace mozilla { - -rtc::scoped_refptr HeadlessWindowCapturer::Create(HeadlessWidget* headlessWindow) { - return new rtc::RefCountedObject(headlessWindow); -} - -HeadlessWindowCapturer::HeadlessWindowCapturer(mozilla::widget::HeadlessWidget* window) - : mWindow(window) { -} -HeadlessWindowCapturer::~HeadlessWindowCapturer() { - StopCapture(); -} - - -void HeadlessWindowCapturer::RegisterCaptureDataCallback(rtc::VideoSinkInterface* dataCallback) { - rtc::CritScope lock2(&_callBackCs); - _dataCallBacks.insert(dataCallback); -} -void HeadlessWindowCapturer::DeRegisterCaptureDataCallback(rtc::VideoSinkInterface* dataCallback) { - rtc::CritScope lock2(&_callBackCs); - auto it = _dataCallBacks.find(dataCallback); - if (it != _dataCallBacks.end()) { - _dataCallBacks.erase(it); - } -} - -void HeadlessWindowCapturer::RegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) { - rtc::CritScope lock2(&_callBackCs); - _rawFrameCallbacks.insert(rawFrameCallback); -} - -void HeadlessWindowCapturer::DeRegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) { - rtc::CritScope lock2(&_callBackCs); - auto it = _rawFrameCallbacks.find(rawFrameCallback); - if (it != _rawFrameCallbacks.end()) { - _rawFrameCallbacks.erase(it); - } -} - -void HeadlessWindowCapturer::NotifyFrameCaptured(const webrtc::VideoFrame& frame) { - rtc::CritScope lock2(&_callBackCs); - for (auto dataCallBack : _dataCallBacks) - dataCallBack->OnFrame(frame); -} - -int32_t HeadlessWindowCapturer::StopCaptureIfAllClientsClose() { - if (_dataCallBacks.empty()) { - return StopCapture(); - } else { - return 0; - } -} - -int32_t HeadlessWindowCapturer::StartCapture(const webrtc::VideoCaptureCapability& capability) { - mWindow->SetSnapshotListener([this] (RefPtr&& dataSurface){ - if (!NS_IsInCompositorThread()) { - fprintf(stderr, "SnapshotListener is called not on the Compositor thread!\n"); - return; - } - - if (dataSurface->GetFormat() != gfx::SurfaceFormat::B8G8R8A8) { - fprintf(stderr, "Unexpected snapshot surface format: %hhd\n", dataSurface->GetFormat()); - return; - } - - webrtc::VideoCaptureCapability frameInfo; - frameInfo.width = dataSurface->GetSize().width; - frameInfo.height = dataSurface->GetSize().height; -#if MOZ_LITTLE_ENDIAN() - frameInfo.videoType = VideoType::kARGB; -#else - frameInfo.videoType = VideoType::kBGRA; -#endif - - { - rtc::CritScope lock2(&_callBackCs); - for (auto rawFrameCallback : _rawFrameCallbacks) { - rawFrameCallback->OnRawFrame(dataSurface->GetData(), dataSurface->Stride(), frameInfo); - } - if (!_dataCallBacks.size()) - return; - } - - int width = dataSurface->GetSize().width; - int height = dataSurface->GetSize().height; - rtc::scoped_refptr buffer = I420Buffer::Create(width, height); - - gfx::DataSourceSurface::ScopedMap map(dataSurface.get(), gfx::DataSourceSurface::MapType::READ); - if (!map.IsMapped()) { - fprintf(stderr, "Failed to map snapshot bytes!\n"); - return; - } - -#if MOZ_LITTLE_ENDIAN() - const int conversionResult = libyuv::ARGBToI420( -#else - const int conversionResult = libyuv::BGRAToI420( -#endif - map.GetData(), map.GetStride(), - buffer->MutableDataY(), buffer->StrideY(), - buffer->MutableDataU(), buffer->StrideU(), - buffer->MutableDataV(), buffer->StrideV(), - width, height); - if (conversionResult != 0) { - fprintf(stderr, "Failed to convert capture frame to I420: %d\n", conversionResult); - return; - } - - VideoFrame captureFrame(buffer, 0, rtc::TimeMillis(), kVideoRotation_0); - NotifyFrameCaptured(captureFrame); - }); - return 0; -} - -int32_t HeadlessWindowCapturer::StopCapture() { - if (!CaptureStarted()) - return 0; - mWindow->SetSnapshotListener(nullptr); - return 0; -} - -bool HeadlessWindowCapturer::CaptureStarted() { - return true; -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h b/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h deleted file mode 100644 index 9f67565c04..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h +++ /dev/null @@ -1,64 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include "api/video/video_frame.h" -#include "api/video/video_sink_interface.h" -#include "modules/video_capture/video_capture.h" -#include "rtc_base/deprecated/recursive_critical_section.h" -#include "video_engine/desktop_capture_impl.h" - -class nsIWidget; - -namespace mozilla { - -namespace widget { -class HeadlessWidget; -} - -class HeadlessWindowCapturer : public webrtc::VideoCaptureModuleEx { - public: - static rtc::scoped_refptr Create(mozilla::widget::HeadlessWidget*); - - void RegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; - int32_t StopCaptureIfAllClientsClose() override; - - void RegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) override; - void DeRegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(webrtc::VideoRotation) override { return -1; } - bool SetApplyRotation(bool) override { return false; } - bool GetApplyRotation() override { return true; } - - const char* CurrentDeviceName() const override { return "Headless window"; } - - // Platform dependent - int32_t StartCapture(const webrtc::VideoCaptureCapability& capability) override; - bool FocusOnSelectedSource() override { return false; } - int32_t StopCapture() override; - bool CaptureStarted() override; - int32_t CaptureSettings(webrtc::VideoCaptureCapability& settings) override { - return -1; - } - - protected: - HeadlessWindowCapturer(mozilla::widget::HeadlessWidget*); - ~HeadlessWindowCapturer() override; - - private: - void NotifyFrameCaptured(const webrtc::VideoFrame& frame); - - RefPtr mWindow; - rtc::RecursiveCriticalSection _callBackCs; - std::set*> _dataCallBacks; - std::set _rawFrameCallbacks; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp b/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp deleted file mode 100644 index 5891953392..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2010, The WebM Project authors. All rights reserved. - * Copyright (c) 2013 The Chromium Authors. All rights reserved. - * Copyright (C) 2020 Microsoft Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ScreencastEncoder.h" - -#include -#include -#include -#include -#include -#include "nsIThread.h" -#include "nsThreadUtils.h" -#include "WebMFileWriter.h" -#include "api/video/video_frame.h" - -namespace mozilla { - -namespace { - -struct VpxCodecDeleter { - void operator()(vpx_codec_ctx_t* codec) { - if (codec) { - vpx_codec_err_t ret = vpx_codec_destroy(codec); - if (ret != VPX_CODEC_OK) - fprintf(stderr, "Failed to destroy codec: %s\n", vpx_codec_error(codec)); - } - } -}; - -using ScopedVpxCodec = std::unique_ptr; - -// Number of timebase unints per one frame. -constexpr int timeScale = 1000; - -// Defines the dimension of a macro block. This is used to compute the active -// map for the encoder. -const int kMacroBlockSize = 16; - -void createImage(unsigned int width, unsigned int height, - std::unique_ptr& out_image, - std::unique_ptr& out_image_buffer, - int& out_buffer_size) { - std::unique_ptr image(new vpx_image_t()); - memset(image.get(), 0, sizeof(vpx_image_t)); - - // libvpx seems to require both to be assigned. - image->d_w = width; - image->w = width; - image->d_h = height; - image->h = height; - - // I420 - image->fmt = VPX_IMG_FMT_YV12; - image->x_chroma_shift = 1; - image->y_chroma_shift = 1; - - // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad - // the Y, U and V planes' strides to multiples of 16 bytes. - const int y_stride = ((image->w - 1) & ~15) + 16; - const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; - const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; - - // libvpx accesses the source image in macro blocks, and will over-read - // if the image is not padded out to the next macroblock: crbug.com/119633. - // Pad the Y, U and V planes' height out to compensate. - // Assuming macroblocks are 16x16, aligning the planes' strides above also - // macroblock aligned them. - static_assert(kMacroBlockSize == 16, "macroblock_size_not_16"); - const int y_rows = ((image->h - 1) & ~(kMacroBlockSize-1)) + kMacroBlockSize; - const int uv_rows = y_rows >> image->y_chroma_shift; - - // Allocate a YUV buffer large enough for the aligned data & padding. - out_buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows; - std::unique_ptr image_buffer(new uint8_t[out_buffer_size]); - - // Reset image value to 128 so we just need to fill in the y plane. - memset(image_buffer.get(), 128, out_buffer_size); - - // Fill in the information for |image_|. - unsigned char* uchar_buffer = - reinterpret_cast(image_buffer.get()); - image->planes[0] = uchar_buffer; - image->planes[1] = image->planes[0] + y_stride * y_rows; - image->planes[2] = image->planes[1] + uv_stride * uv_rows; - image->stride[0] = y_stride; - image->stride[1] = uv_stride; - image->stride[2] = uv_stride; - - out_image = std::move(image); - out_image_buffer = std::move(image_buffer); -} - -} // namespace - -class ScreencastEncoder::VPXFrame { -public: - VPXFrame(rtc::scoped_refptr&& buffer, const gfx::IntMargin& margin) - : m_frameBuffer(std::move(buffer)) - , m_margin(margin) - { } - - void setDuration(TimeDuration duration) { m_duration = duration; } - TimeDuration duration() const { return m_duration; } - - void convertToVpxImage(vpx_image_t* image) - { - if (m_frameBuffer->type() != webrtc::VideoFrameBuffer::Type::kI420) { - fprintf(stderr, "convertToVpxImage unexpected frame buffer type: %d\n", m_frameBuffer->type()); - return; - } - - auto src = m_frameBuffer->GetI420(); - const int y_stride = image->stride[VPX_PLANE_Y]; - MOZ_ASSERT(image->stride[VPX_PLANE_U] == image->stride[VPX_PLANE_V]); - const int uv_stride = image->stride[1]; - uint8_t* y_data = image->planes[VPX_PLANE_Y]; - uint8_t* u_data = image->planes[VPX_PLANE_U]; - uint8_t* v_data = image->planes[VPX_PLANE_V]; - - double src_width = src->width() - m_margin.LeftRight(); - double src_height = src->height() - m_margin.top; - // YUV offsets must be even. - int yuvTopOffset = m_margin.top & 1 ? m_margin.top + 1 : m_margin.top; - int yuvLeftOffset = m_margin.left & 1 ? m_margin.left + 1 : m_margin.left; - - if (src_width > image->w || src_height > image->h) { - double scale = std::min(image->w / src_width, image->h / src_height); - double dst_width = src_width * scale; - if (dst_width > image->w) { - src_width *= image->w / dst_width; - dst_width = image->w; - } - double dst_height = src_height * scale; - if (dst_height > image->h) { - src_height *= image->h / dst_height; - dst_height = image->h; - } - libyuv::I420Scale(src->DataY() + yuvTopOffset * src->StrideY() + yuvLeftOffset, src->StrideY(), - src->DataU() + (yuvTopOffset * src->StrideU() + yuvLeftOffset) / 2, src->StrideU(), - src->DataV() + (yuvTopOffset * src->StrideV() + yuvLeftOffset) / 2, src->StrideV(), - src_width, src_height, - y_data, y_stride, - u_data, uv_stride, - v_data, uv_stride, - dst_width, dst_height, - libyuv::kFilterBilinear); - } else { - int width = std::min(image->w, src_width); - int height = std::min(image->h, src_height); - - libyuv::I420Copy(src->DataY() + yuvTopOffset * src->StrideY() + yuvLeftOffset, src->StrideY(), - src->DataU() + (yuvTopOffset * src->StrideU() + yuvLeftOffset) / 2, src->StrideU(), - src->DataV() + (yuvTopOffset * src->StrideV() + yuvLeftOffset) / 2, src->StrideV(), - y_data, y_stride, - u_data, uv_stride, - v_data, uv_stride, - width, height); - } - } - -private: - rtc::scoped_refptr m_frameBuffer; - gfx::IntMargin m_margin; - TimeDuration m_duration; -}; - - -class ScreencastEncoder::VPXCodec { -public: - VPXCodec(ScopedVpxCodec codec, vpx_codec_enc_cfg_t cfg, FILE* file) - : m_codec(std::move(codec)) - , m_cfg(cfg) - , m_file(file) - , m_writer(new WebMFileWriter(file, &m_cfg)) - { - nsresult rv = NS_NewNamedThread("Screencast enc", getter_AddRefs(m_encoderQueue)); - if (rv != NS_OK) { - fprintf(stderr, "ScreencastEncoder::VPXCodec failed to spawn thread %d\n", rv); - return; - } - - createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer, m_imageBufferSize); - } - - ~VPXCodec() { - m_encoderQueue->Shutdown(); - m_encoderQueue = nullptr; - } - - void encodeFrameAsync(std::unique_ptr&& frame) - { - m_encoderQueue->Dispatch(NS_NewRunnableFunction("VPXCodec::encodeFrameAsync", [this, frame = std::move(frame)] { - memset(m_imageBuffer.get(), 128, m_imageBufferSize); - frame->convertToVpxImage(m_image.get()); - - double frameCount = frame->duration().ToSeconds() * fps; - // For long duration repeat frame at 1 fps to ensure last frame duration is short enough. - // TODO: figure out why simply passing duration doesn't work well. - for (;frameCount > 1.5; frameCount -= 1) { - encodeFrame(m_image.get(), timeScale); - } - encodeFrame(m_image.get(), std::max(1, frameCount * timeScale)); - })); - } - - void finishAsync(std::function&& callback) - { - m_encoderQueue->Dispatch(NS_NewRunnableFunction("VPXCodec::finishAsync", [this, callback = std::move(callback)] { - finish(); - callback(); - })); - } - -private: - bool encodeFrame(vpx_image_t *img, int duration) - { - vpx_codec_iter_t iter = nullptr; - const vpx_codec_cx_pkt_t *pkt = nullptr; - int flags = 0; - const vpx_codec_err_t res = vpx_codec_encode(m_codec.get(), img, m_pts, duration, flags, VPX_DL_REALTIME); - if (res != VPX_CODEC_OK) { - fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(m_codec.get())); - return false; - } - - bool gotPkts = false; - while ((pkt = vpx_codec_get_cx_data(m_codec.get(), &iter)) != nullptr) { - gotPkts = true; - - if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { - m_writer->writeFrame(pkt); - ++m_frameCount; - // fprintf(stderr, " #%03d %spts=%" PRId64 " sz=%zd\n", m_frameCount, (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0 ? "[K] " : "", pkt->data.frame.pts, pkt->data.frame.sz); - m_pts += pkt->data.frame.duration; - } - } - - return gotPkts; - } - - void finish() - { - // Flush encoder. - while (encodeFrame(nullptr, 1)) - ++m_frameCount; - - m_writer->finish(); - fclose(m_file); - // fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount); - } - - RefPtr m_encoderQueue; - ScopedVpxCodec m_codec; - vpx_codec_enc_cfg_t m_cfg; - FILE* m_file { nullptr }; - std::unique_ptr m_writer; - int m_frameCount { 0 }; - int64_t m_pts { 0 }; - std::unique_ptr m_imageBuffer; - int m_imageBufferSize { 0 }; - std::unique_ptr m_image; -}; - -ScreencastEncoder::ScreencastEncoder(std::unique_ptr vpxCodec, const gfx::IntMargin& margin) - : m_vpxCodec(std::move(vpxCodec)) - , m_margin(margin) -{ -} - -ScreencastEncoder::~ScreencastEncoder() -{ -} - -std::unique_ptr ScreencastEncoder::create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin) -{ - vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx(); - if (!codec_interface) { - errorString = "Codec not found."; - return nullptr; - } - - if (width <= 0 || height <= 0 || (width % 2) != 0 || (height % 2) != 0) { - errorString.AppendPrintf("Invalid frame size: %dx%d", width, height); - return nullptr; - } - - vpx_codec_enc_cfg_t cfg; - memset(&cfg, 0, sizeof(cfg)); - vpx_codec_err_t error = vpx_codec_enc_config_default(codec_interface, &cfg, 0); - if (error) { - errorString.AppendPrintf("Failed to get default codec config: %s", vpx_codec_err_to_string(error)); - return nullptr; - } - - cfg.g_w = width; - cfg.g_h = height; - cfg.g_timebase.num = 1; - cfg.g_timebase.den = fps * timeScale; - cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; - - ScopedVpxCodec codec(new vpx_codec_ctx_t); - if (vpx_codec_enc_init(codec.get(), codec_interface, &cfg, 0)) { - errorString.AppendPrintf("Failed to initialize encoder: %s", vpx_codec_error(codec.get())); - return nullptr; - } - - FILE* file = fopen(filePath.get(), "wb"); - if (!file) { - errorString.AppendPrintf("Failed to open file '%s' for writing: %s", filePath.get(), strerror(errno)); - return nullptr; - } - - std::unique_ptr vpxCodec(new VPXCodec(std::move(codec), cfg, file)); - // fprintf(stderr, "ScreencastEncoder initialized with: %s\n", vpx_codec_iface_name(codec_interface)); - return std::make_unique(std::move(vpxCodec), margin); -} - -void ScreencastEncoder::flushLastFrame() -{ - TimeStamp now = TimeStamp::Now(); - if (m_lastFrameTimestamp) { - // If previous frame encoding failed for some rason leave the timestampt intact. - if (!m_lastFrame) - return; - - m_lastFrame->setDuration(now - m_lastFrameTimestamp); - m_vpxCodec->encodeFrameAsync(std::move(m_lastFrame)); - } - m_lastFrameTimestamp = now; -} - -void ScreencastEncoder::encodeFrame(const webrtc::VideoFrame& videoFrame) -{ - // fprintf(stderr, "ScreencastEncoder::encodeFrame\n"); - flushLastFrame(); - - m_lastFrame = std::make_unique(videoFrame.video_frame_buffer(), m_margin); -} - -void ScreencastEncoder::finish(std::function&& callback) -{ - if (!m_vpxCodec) { - callback(); - return; - } - - flushLastFrame(); - m_vpxCodec->finishAsync([callback = std::move(callback)] () mutable { - NS_DispatchToMainThread(NS_NewRunnableFunction("ScreencastEncoder::finish callback", std::move(callback))); - }); -} - - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h b/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h deleted file mode 100644 index 883ad01011..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h +++ /dev/null @@ -1,45 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include "mozilla/gfx/Rect.h" -#include "mozilla/Maybe.h" -#include "mozilla/TimeStamp.h" -#include "nsISupportsImpl.h" -#include "nsStringFwd.h" - -namespace webrtc { -class VideoFrame; -} - -namespace mozilla { - -class ScreencastEncoder { -public: - static constexpr int fps = 25; - - static std::unique_ptr create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin); - - class VPXCodec; - ScreencastEncoder(std::unique_ptr, const gfx::IntMargin& margin); - ~ScreencastEncoder(); - - void encodeFrame(const webrtc::VideoFrame& videoFrame); - - void finish(std::function&& callback); - -private: - void flushLastFrame(); - - std::unique_ptr m_vpxCodec; - gfx::IntMargin m_margin; - TimeStamp m_lastFrameTimestamp; - class VPXFrame; - std::unique_ptr m_lastFrame; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp b/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp deleted file mode 100644 index f720b300f2..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2014 The WebM project authors. All Rights Reserved. - */ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WebMFileWriter.h" - -#include -#include "mkvmuxer/mkvmuxerutil.h" - -namespace mozilla { - -WebMFileWriter::WebMFileWriter(FILE* file, vpx_codec_enc_cfg_t* cfg) - : m_cfg(cfg) - , m_writer(new mkvmuxer::MkvWriter(file)) - , m_segment(new mkvmuxer::Segment()) { - m_segment->Init(m_writer.get()); - m_segment->set_mode(mkvmuxer::Segment::kFile); - m_segment->OutputCues(true); - - mkvmuxer::SegmentInfo* info = m_segment->GetSegmentInfo(); - std::string version = "Playwright " + std::string(vpx_codec_version_str()); - info->set_writing_app(version.c_str()); - - // Add vp8 track. - m_videoTrackId = m_segment->AddVideoTrack( - static_cast(m_cfg->g_w), static_cast(m_cfg->g_h), 0); - if (!m_videoTrackId) { - fprintf(stderr, "Failed to add video track\n"); - } -} - -WebMFileWriter::~WebMFileWriter() {} - -void WebMFileWriter::writeFrame(const vpx_codec_cx_pkt_t* pkt) { - int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * m_cfg->g_timebase.num / - m_cfg->g_timebase.den; - m_segment->AddFrame(static_cast(pkt->data.frame.buf), - pkt->data.frame.sz, m_videoTrackId, pts_ns, - pkt->data.frame.flags & VPX_FRAME_IS_KEY); -} - -void WebMFileWriter::finish() { - m_segment->Finalize(); -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h b/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h deleted file mode 100644 index 4a7fd06e6c..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h +++ /dev/null @@ -1,32 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include -#include "vpx/vpx_encoder.h" - -#include "mkvmuxer/mkvmuxer.h" -#include "mkvmuxer/mkvwriter.h" - -namespace mozilla { - -class WebMFileWriter { -public: - WebMFileWriter(FILE*, vpx_codec_enc_cfg_t* cfg); - ~WebMFileWriter(); - - void writeFrame(const vpx_codec_cx_pkt_t* pkt); - void finish(); - -private: - vpx_codec_enc_cfg_t* m_cfg = nullptr; - std::unique_ptr m_writer; - std::unique_ptr m_segment; - uint64_t m_videoTrackId = 0; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/components.conf b/browser_patches/firefox-beta/juggler/screencast/components.conf deleted file mode 100644 index 6298739122..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/components.conf +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Classes = [ - { - 'cid': '{d8c4d9e0-9462-445e-9e43-68d3872ad1de}', - 'contract_ids': ['@mozilla.org/juggler/screencast;1'], - 'type': 'nsIScreencastService', - 'constructor': 'mozilla::nsScreencastService::GetSingleton', - 'headers': ['/juggler/screencast/nsScreencastService.h'], - }, -] diff --git a/browser_patches/firefox-beta/juggler/screencast/moz.build b/browser_patches/firefox-beta/juggler/screencast/moz.build deleted file mode 100644 index e21b177c39..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/moz.build +++ /dev/null @@ -1,49 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPIDL_SOURCES += [ - 'nsIScreencastService.idl', -] - -XPIDL_MODULE = 'jugglerscreencast' - -SOURCES += [ - 'HeadlessWindowCapturer.cpp', - 'nsScreencastService.cpp', - 'ScreencastEncoder.cpp', -] - -XPCOM_MANIFESTS += [ - 'components.conf', -] - -LOCAL_INCLUDES += [ - '/dom/media/systemservices', - '/media/libyuv/libyuv/include', - '/third_party/libwebrtc', - '/third_party/libwebrtc/third_party/abseil-cpp', -] - -LOCAL_INCLUDES += [ - '/widget', - '/widget/headless', -] - -LOCAL_INCLUDES += [ - '/third_party/aom/third_party/libwebm', -] - -SOURCES += [ - '/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc', - '/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc', - '/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc', - 'WebMFileWriter.cpp', -] - -include('/dom/media/webrtc/third_party_build/webrtc.mozbuild') -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' diff --git a/browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl b/browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl deleted file mode 100644 index 16c94371ba..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl +++ /dev/null @@ -1,31 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIDocShell; - -[scriptable, uuid(0b5d32c4-aeeb-11eb-8529-0242ac130003)] -interface nsIScreencastServiceClient : nsISupports -{ - void screencastFrame(in AString frame, in uint32_t deviceWidth, in uint32_t deviceHeight); - - void screencastStopped(); -}; - -/** - * Service for recording window video. - */ -[scriptable, uuid(d8c4d9e0-9462-445e-9e43-68d3872ad1de)] -interface nsIScreencastService : nsISupports -{ - AString startVideoRecording(in nsIScreencastServiceClient client, in nsIDocShell docShell, in boolean isVideo, in ACString fileName, in uint32_t width, in uint32_t height, in uint32_t quality, in uint32_t viewportWidth, in uint32_t viewportHeight, in uint32_t offset_top); - - /** - * Will emit 'juggler-screencast-stopped' when the video file is saved. - */ - void stopVideoRecording(in AString sessionId); - - void screencastFrameAck(in AString sessionId); -}; diff --git a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp b/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp deleted file mode 100644 index 20a766dc37..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsScreencastService.h" - -#include "ScreencastEncoder.h" -#include "HeadlessWidget.h" -#include "HeadlessWindowCapturer.h" -#include "mozilla/Base64.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/PresShell.h" -#include "mozilla/StaticPtr.h" -#include "nsIDocShell.h" -#include "nsIObserverService.h" -#include "nsIRandomGenerator.h" -#include "nsISupportsPrimitives.h" -#include "nsThreadManager.h" -#include "nsView.h" -#include "nsViewManager.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/desktop_frame.h" -#include "modules/video_capture/video_capture.h" -#include "mozilla/widget/PlatformWidgetTypes.h" -#include "video_engine/desktop_capture_impl.h" -extern "C" { -#include "jpeglib.h" -} -#include - -using namespace mozilla::widget; - -namespace mozilla { - -NS_IMPL_ISUPPORTS(nsScreencastService, nsIScreencastService) - -namespace { - -const int kMaxFramesInFlight = 1; - -StaticRefPtr gScreencastService; - -rtc::scoped_refptr CreateWindowCapturer(nsIWidget* widget) { - if (gfxPlatform::IsHeadless()) { - HeadlessWidget* headlessWidget = static_cast(widget); - return HeadlessWindowCapturer::Create(headlessWidget); - } - uintptr_t rawWindowId = reinterpret_cast(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID)); - if (!rawWindowId) { - fprintf(stderr, "Failed to get native window id\n"); - return nullptr; - } - nsCString windowId; - windowId.AppendPrintf("%" PRIuPTR, rawWindowId); - bool captureCursor = false; - static int moduleId = 0; - return webrtc::DesktopCaptureImpl::Create(++moduleId, windowId.get(), CaptureDeviceType::Window, captureCursor); -} - -nsresult generateUid(nsString& uid) { - nsresult rv = NS_OK; - nsCOMPtr rg = do_GetService("@mozilla.org/security/random-generator;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - uint8_t* buffer; - const int kLen = 16; - rv = rg->GenerateRandomBytes(kLen, &buffer); - NS_ENSURE_SUCCESS(rv, rv); - - for (int i = 0; i < kLen; i++) { - uid.AppendPrintf("%02x", buffer[i]); - } - free(buffer); - return rv; -} -} - -class nsScreencastService::Session : public rtc::VideoSinkInterface, - public webrtc::RawFrameCallback { - Session( - nsIScreencastServiceClient* client, - rtc::scoped_refptr&& capturer, - std::unique_ptr encoder, - int width, int height, - int viewportWidth, int viewportHeight, - gfx::IntMargin margin, - uint32_t jpegQuality) - : mClient(client) - , mCaptureModule(std::move(capturer)) - , mEncoder(std::move(encoder)) - , mJpegQuality(jpegQuality) - , mWidth(width) - , mHeight(height) - , mViewportWidth(viewportWidth) - , mViewportHeight(viewportHeight) - , mMargin(margin) { - } - ~Session() override = default; - - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Session) - static RefPtr Create( - nsIScreencastServiceClient* client, - rtc::scoped_refptr&& capturer, - std::unique_ptr encoder, - int width, int height, - int viewportWidth, int viewportHeight, - gfx::IntMargin margin, - uint32_t jpegQuality) { - return do_AddRef(new Session(client, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, jpegQuality)); - } - - bool Start() { - webrtc::VideoCaptureCapability capability; - // The size is ignored in fact. - capability.width = 1280; - capability.height = 960; - capability.maxFPS = ScreencastEncoder::fps; - capability.videoType = webrtc::VideoType::kI420; - int error = mCaptureModule->StartCapture(capability); - if (error) { - fprintf(stderr, "StartCapture error %d\n", error); - return false; - } - - if (mEncoder) - mCaptureModule->RegisterCaptureDataCallback(this); - else - mCaptureModule->RegisterRawFrameCallback(this); - return true; - } - - void Stop() { - if (mStopped) { - fprintf(stderr, "Screencast session has already been stopped\n"); - return; - } - mStopped = true; - if (mEncoder) - mCaptureModule->DeRegisterCaptureDataCallback(this); - else - mCaptureModule->DeRegisterRawFrameCallback(this); - int error = mCaptureModule->StopCapture(); - if (error) { - fprintf(stderr, "StopCapture error %d\n", error); - } - if (mEncoder) { - mEncoder->finish([this, protect = RefPtr{this}] { - NS_DispatchToMainThread(NS_NewRunnableFunction( - "NotifyScreencastStopped", [this, protect = std::move(protect)]() -> void { - mClient->ScreencastStopped(); - })); - }); - } else { - mClient->ScreencastStopped(); - } - } - - void ScreencastFrameAck() { - if (mFramesInFlight.load() == 0) { - fprintf(stderr, "ScreencastFrameAck is called while there are no inflight frames\n"); - return; - } - mFramesInFlight.fetch_sub(1); - } - - // These callbacks end up running on the VideoCapture thread. - void OnFrame(const webrtc::VideoFrame& videoFrame) override { - if (!mEncoder) - return; - mEncoder->encodeFrame(videoFrame); - } - - // These callbacks end up running on the VideoCapture thread. - void OnRawFrame(uint8_t* videoFrame, size_t videoFrameStride, const webrtc::VideoCaptureCapability& frameInfo) override { - int pageWidth = frameInfo.width - mMargin.LeftRight(); - int pageHeight = frameInfo.height - mMargin.TopBottom(); - // Frame size is 1x1 when browser window is minimized. - if (pageWidth <= 1 || pageHeight <= 1) - return; - // Headed Firefox brings sizes in sync slowly. - if (mViewportWidth && pageWidth > mViewportWidth) - pageWidth = mViewportWidth; - if (mViewportHeight && pageHeight > mViewportHeight) - pageHeight = mViewportHeight; - - if (mFramesInFlight.load() >= kMaxFramesInFlight) - return; - - int screenshotWidth = pageWidth; - int screenshotHeight = pageHeight; - int screenshotTopMargin = mMargin.TopBottom(); - std::unique_ptr canvas; - uint8_t* canvasPtr = videoFrame; - int canvasStride = videoFrameStride; - - if (mWidth < pageWidth || mHeight < pageHeight) { - double scale = std::min(1., std::min((double)mWidth / pageWidth, (double)mHeight / pageHeight)); - int canvasWidth = frameInfo.width * scale; - int canvasHeight = frameInfo.height * scale; - canvasStride = canvasWidth * 4; - - screenshotWidth *= scale; - screenshotHeight *= scale; - screenshotTopMargin *= scale; - - canvas.reset(new uint8_t[canvasWidth * canvasHeight * 4]); - canvasPtr = canvas.get(); - libyuv::ARGBScale(videoFrame, - videoFrameStride, - frameInfo.width, - frameInfo.height, - canvasPtr, - canvasStride, - canvasWidth, - canvasHeight, - libyuv::kFilterBilinear); - } - - jpeg_compress_struct info; - jpeg_error_mgr error; - info.err = jpeg_std_error(&error); - jpeg_create_compress(&info); - - unsigned char* bufferPtr = nullptr; - unsigned long bufferSize; - jpeg_mem_dest(&info, &bufferPtr, &bufferSize); - - info.image_width = screenshotWidth; - info.image_height = screenshotHeight; - -#if MOZ_LITTLE_ENDIAN() - if (frameInfo.videoType == webrtc::VideoType::kARGB) - info.in_color_space = JCS_EXT_BGRA; - if (frameInfo.videoType == webrtc::VideoType::kBGRA) - info.in_color_space = JCS_EXT_ARGB; -#else - if (frameInfo.videoType == webrtc::VideoType::kARGB) - info.in_color_space = JCS_EXT_ARGB; - if (frameInfo.videoType == webrtc::VideoType::kBGRA) - info.in_color_space = JCS_EXT_BGRA; -#endif - - // # of color components in input image - info.input_components = 4; - - jpeg_set_defaults(&info); - jpeg_set_quality(&info, mJpegQuality, true); - - jpeg_start_compress(&info, true); - while (info.next_scanline < info.image_height) { - JSAMPROW row = canvasPtr + (screenshotTopMargin + info.next_scanline) * canvasStride; - if (jpeg_write_scanlines(&info, &row, 1) != 1) { - fprintf(stderr, "JPEG library failed to encode line\n"); - break; - } - } - - jpeg_finish_compress(&info); - jpeg_destroy_compress(&info); - - nsCString base64; - nsresult rv = mozilla::Base64Encode(reinterpret_cast(bufferPtr), bufferSize, base64); - free(bufferPtr); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - mFramesInFlight.fetch_add(1); - NS_DispatchToMainThread(NS_NewRunnableFunction( - "NotifyScreencastFrame", [this, protect = RefPtr{this}, base64, pageWidth, pageHeight]() -> void { - if (mStopped) - return; - NS_ConvertUTF8toUTF16 utf16(base64); - mClient->ScreencastFrame(utf16, pageWidth, pageHeight); - })); - } - - private: - RefPtr mClient; - rtc::scoped_refptr mCaptureModule; - std::unique_ptr mEncoder; - uint32_t mJpegQuality; - bool mStopped = false; - std::atomic mFramesInFlight = 0; - int mWidth; - int mHeight; - int mViewportWidth; - int mViewportHeight; - gfx::IntMargin mMargin; -}; - - -// static -already_AddRefed nsScreencastService::GetSingleton() { - if (gScreencastService) { - return do_AddRef(gScreencastService); - } - - gScreencastService = new nsScreencastService(); - // ClearOnShutdown(&gScreencastService); - return do_AddRef(gScreencastService); -} - -nsScreencastService::nsScreencastService() = default; - -nsScreencastService::~nsScreencastService() { -} - -nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aClient, nsIDocShell* aDocShell, bool isVideo, const nsACString& aVideoFileName, uint32_t width, uint32_t height, uint32_t quality, uint32_t viewportWidth, uint32_t viewportHeight, uint32_t offsetTop, nsAString& sessionId) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Screencast service must be started on the Main thread."); - - PresShell* presShell = aDocShell->GetPresShell(); - if (!presShell) - return NS_ERROR_UNEXPECTED; - nsViewManager* viewManager = presShell->GetViewManager(); - if (!viewManager) - return NS_ERROR_UNEXPECTED; - nsView* view = viewManager->GetRootView(); - if (!view) - return NS_ERROR_UNEXPECTED; - nsIWidget* widget = view->GetWidget(); - - rtc::scoped_refptr capturer = CreateWindowCapturer(widget); - if (!capturer) - return NS_ERROR_FAILURE; - - gfx::IntMargin margin; - auto bounds = widget->GetScreenBounds().ToUnknownRect(); - auto clientBounds = widget->GetClientBounds().ToUnknownRect(); - // Crop the image to exclude frame (if any). - margin = bounds - clientBounds; - // Crop the image to exclude controls. - margin.top += offsetTop; - - nsCString error; - std::unique_ptr encoder; - if (isVideo) { - encoder = ScreencastEncoder::create(error, PromiseFlatCString(aVideoFileName), width, height, margin); - if (!encoder) { - fprintf(stderr, "Failed to create ScreencastEncoder: %s\n", error.get()); - return NS_ERROR_FAILURE; - } - } - - nsString uid; - nsresult rv = generateUid(uid); - NS_ENSURE_SUCCESS(rv, rv); - sessionId = uid; - - auto session = Session::Create(aClient, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, isVideo ? 0 : quality); - if (!session->Start()) - return NS_ERROR_FAILURE; - mIdToSession.emplace(sessionId, std::move(session)); - return NS_OK; -} - -nsresult nsScreencastService::StopVideoRecording(const nsAString& aSessionId) { - nsString sessionId(aSessionId); - auto it = mIdToSession.find(sessionId); - if (it == mIdToSession.end()) - return NS_ERROR_INVALID_ARG; - it->second->Stop(); - mIdToSession.erase(it); - return NS_OK; -} - -nsresult nsScreencastService::ScreencastFrameAck(const nsAString& aSessionId) { - nsString sessionId(aSessionId); - auto it = mIdToSession.find(sessionId); - if (it == mIdToSession.end()) - return NS_ERROR_INVALID_ARG; - it->second->ScreencastFrameAck(); - return NS_OK; -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h b/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h deleted file mode 100644 index 419603e0e6..0000000000 --- a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h +++ /dev/null @@ -1,29 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include "nsIScreencastService.h" - -namespace mozilla { - -class nsScreencastService final : public nsIScreencastService { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSISCREENCASTSERVICE - - static already_AddRefed GetSingleton(); - - nsScreencastService(); - - private: - ~nsScreencastService(); - - class Session; - std::map> mIdToSession; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/patches/bootstrap.diff b/browser_patches/firefox-beta/patches/bootstrap.diff deleted file mode 100644 index aec94354e6..0000000000 --- a/browser_patches/firefox-beta/patches/bootstrap.diff +++ /dev/null @@ -1,2905 +0,0 @@ -diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h -index afb6230bb613ecde4a5e3271478a682d0396dc3b..a3a7d9786f9d18bad6afc292264b9dbc62c14cf2 100644 ---- a/accessible/base/NotificationController.h -+++ b/accessible/base/NotificationController.h -@@ -276,6 +276,8 @@ class NotificationController final : public EventQueue, - } - #endif - -+ bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); } -+ - protected: - virtual ~NotificationController(); - -diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index a91df31c96afda66f478a5a38eaa4352039c2a0b..ee777c1746284027fb3aa2f1686f8082af9d89ee 100644 ---- a/accessible/interfaces/nsIAccessibleDocument.idl -+++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -72,4 +72,9 @@ interface nsIAccessibleDocument : nsISupports - * Return the child document accessible at the given index. - */ - nsIAccessibleDocument getChildDocumentAt(in unsigned long index); -+ -+ /** -+ * Return whether it is updating. -+ */ -+ readonly attribute boolean isUpdatePendingForJugglerAccessibility; - }; -diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 1ddd5c8372c2742a8dc4e7a8156c084aaf2442fc..7e3aa30c20d8b2fcae5c12d293ca7772ecd28657 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.cpp -+++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -143,6 +143,15 @@ xpcAccessibleDocument::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) { - return NS_OK; - } - -+ -+NS_IMETHODIMP -+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) { -+ NS_ENSURE_ARG_POINTER(updating); -+ *updating = Intl()->Controller()->IsUpdatePendingForJugglerAccessibility(); -+ return NS_OK; -+} -+ -+ - //////////////////////////////////////////////////////////////////////////////// - // xpcAccessibleDocument - -diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 416a1c5497c97ed80cc0f37d72545e36f7e36b4c..b81983cf7153378260a21f6af225e3493f8f30dc 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.h -+++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, - nsIAccessibleDocument** aDocument) final; - NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) final; - -+ NS_IMETHOD GetIsUpdatePendingForJugglerAccessibility(bool* aUpdating) final; -+ - /** - * Return XPCOM wrapper for the internal accessible. - */ -diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp -index 326ed6a0838e50e5ce2bd4439df109c62070facb..19769fbb8d6da365f7f041f8f08fb06d41eb6a8c 100644 ---- a/browser/app/winlauncher/LauncherProcessWin.cpp -+++ b/browser/app/winlauncher/LauncherProcessWin.cpp -@@ -23,6 +23,7 @@ - #include "mozilla/WinHeaderOnlyUtils.h" - #include "nsWindowsHelpers.h" - -+#include - #include - #include - -@@ -412,8 +413,19 @@ Maybe LauncherMain(int& argc, wchar_t* argv[], - HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), - ::GetStdHandle(STD_OUTPUT_HANDLE), - ::GetStdHandle(STD_ERROR_HANDLE)}; -- - attrs.AddInheritableHandles(stdHandles); -+ // Playwright pipe installation. -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, L"juggler-pipe", -+ static_cast(nullptr), -+ mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; -+ if (hasJugglerPipe) { -+ intptr_t stdio3 = _get_osfhandle(3); -+ intptr_t stdio4 = _get_osfhandle(4); -+ HANDLE pipeHandles[] = {reinterpret_cast(stdio3), -+ reinterpret_cast(stdio4)}; -+ attrs.AddInheritableHandles(pipeHandles); -+ } - - DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; - -diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn -index b59fe4b1854fec7cb329139f9c6773498fb9de51..29973af04902848808e850b40bf85e5f694d349a 100644 ---- a/browser/installer/allowed-dupes.mn -+++ b/browser/installer/allowed-dupes.mn -@@ -71,6 +71,12 @@ browser/features/webcompat@mozilla.org/shims/empty-shim.txt - removed-files - #endif - -+# Juggler/marionette files -+chrome/juggler/content/content/floating-scrollbars.css -+browser/chrome/devtools/skin/floating-scrollbars-responsive-design.css -+chrome/juggler/content/server/stream-utils.js -+chrome/marionette/content/stream-utils.js -+ - #ifdef MOZ_EME_WIN32_ARTIFACT - gmp-clearkey/0.1/manifest.json - i686/gmp-clearkey/0.1/manifest.json -diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 9229a0bd0e041815331aaf2973afda22c007423d..3ce0e453d4124d110e11877f5bbade776d11cfd4 100644 ---- a/browser/installer/package-manifest.in -+++ b/browser/installer/package-manifest.in -@@ -196,6 +196,9 @@ - @RESPATH@/chrome/remote.manifest - #endif - -+@RESPATH@/chrome/juggler@JAREXT@ -+@RESPATH@/chrome/juggler.manifest -+ - ; [Extensions] - @RESPATH@/components/extensions-toolkit.manifest - @RESPATH@/browser/components/extensions-browser.manifest -diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c2835307f88 100644 ---- a/devtools/server/socket/websocket-server.js -+++ b/devtools/server/socket/websocket-server.js -@@ -133,13 +133,12 @@ function writeHttpResponse(output, response) { - * Process the WebSocket handshake headers and return the key to be sent in - * Sec-WebSocket-Accept response header. - */ --function processRequest({ requestLine, headers }) { -+function processRequest({ requestLine, headers }, expectedPath) { - const [method, path] = requestLine.split(" "); - if (method !== "GET") { - throw new Error("The handshake request must use GET method"); - } -- -- if (path !== "/") { -+ if (path !== expectedPath) { - throw new Error("The handshake request has unknown path"); - } - -@@ -189,13 +188,13 @@ function computeKey(key) { - /** - * Perform the server part of a WebSocket opening handshake on an incoming connection. - */ --const serverHandshake = async function(input, output) { -+const serverHandshake = async function(input, output, expectedPath) { - // Read the request - const request = await readHttpRequest(input); - - try { - // Check and extract info from the request -- const { acceptKey } = processRequest(request); -+ const { acceptKey } = processRequest(request, expectedPath); - - // Send response headers - await writeHttpResponse(output, [ -@@ -217,8 +216,8 @@ const serverHandshake = async function(input, output) { - * Performs the WebSocket handshake and waits for the WebSocket to open. - * Returns Promise with a WebSocket ready to send and receive messages. - */ --const accept = async function(transport, input, output) { -- await serverHandshake(input, output); -+const accept = async function(transport, input, output, expectedPath) { -+ await serverHandshake(input, output, expectedPath || "/"); - - const transportProvider = { - setListener(upgradeListener) { -diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp -index 05c2ad8035b2e5312da485ef2028f9482a1f7bdb..0fcb5421bae4bcb9566aa32b57ed966570cdd45c 100644 ---- a/docshell/base/BrowsingContext.cpp -+++ b/docshell/base/BrowsingContext.cpp -@@ -111,6 +111,20 @@ struct ParamTraits - mozilla::dom::PrefersColorSchemeOverride::None, - mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {}; - -+template <> -+struct ParamTraits -+ : public ContiguousEnumSerializer< -+ mozilla::dom::PrefersReducedMotionOverride, -+ mozilla::dom::PrefersReducedMotionOverride::None, -+ mozilla::dom::PrefersReducedMotionOverride::EndGuard_> {}; -+ -+template <> -+struct ParamTraits -+ : public ContiguousEnumSerializer< -+ mozilla::dom::ForcedColorsOverride, -+ mozilla::dom::ForcedColorsOverride::None, -+ mozilla::dom::ForcedColorsOverride::EndGuard_> {}; -+ - template <> - struct ParamTraits - : public ContiguousEnumSerializer< -@@ -2819,6 +2833,40 @@ void BrowsingContext::DidSet(FieldIndex, - PresContextAffectingFieldChanged(); - } - -+void BrowsingContext::DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (PrefersReducedMotionOverride() == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (nsIDocShell* shell = aContext->GetDocShell()) { -+ if (nsPresContext* pc = shell->GetPresContext()) { -+ pc->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ } -+ }); -+} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ dom::ForcedColorsOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (ForcedColorsOverride() == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (nsIDocShell* shell = aContext->GetDocShell()) { -+ if (nsPresContext* pc = shell->GetPresContext()) { -+ pc->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ } -+ }); -+} -+ - void BrowsingContext::DidSet(FieldIndex, - nsString&& aOldValue) { - MOZ_ASSERT(IsTop()); -diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index 6ad869bdd10efa9c87485d4a82e90fa3a0ad50e1..df3b05b581b450ba38056411f7b2befffe6e5f74 100644 ---- a/docshell/base/BrowsingContext.h -+++ b/docshell/base/BrowsingContext.h -@@ -176,10 +176,10 @@ enum class ExplicitActiveStatus : uint8_t { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ - /* ScreenOrientation-related APIs */ \ - FIELD(CurrentOrientationAngle, float) \ -- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ -+ FIELD(CurrentOrientationType, dom::OrientationType) \ - FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ - FIELD(UserAgentOverride, nsString) \ -- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ -+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ - FIELD(EmbedderElementType, Maybe) \ - FIELD(MessageManagerGroup, nsString) \ - FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -217,6 +217,10 @@ enum class ExplicitActiveStatus : uint8_t { - * embedder element. */ \ - FIELD(EmbedderColorScheme, dom::PrefersColorSchemeOverride) \ - FIELD(DisplayMode, dom::DisplayMode) \ -+ /* playwright addition */ \ -+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ /* playwright addition */ \ -+ FIELD(ForcedColorsOverride, dom::ForcedColorsOverride) \ - /* The number of entries added to the session history because of this \ - * browsing context. */ \ - FIELD(HistoryEntryCount, uint32_t) \ -@@ -902,6 +906,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetPrefersColorSchemeOverride(); - } - -+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { -+ return GetPrefersReducedMotionOverride(); -+ } -+ -+ dom::ForcedColorsOverride ForcedColorsOverride() const { -+ return GetForcedColorsOverride(); -+ } -+ - bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1059,6 +1071,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - - void PresContextAffectingFieldChanged(); - -+ bool CanSet(FieldIndex, -+ dom::PrefersReducedMotionOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue); -+ -+ -+ bool CanSet(FieldIndex, -+ dom::ForcedColorsOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::ForcedColorsOverride aOldValue); -+ - void DidSet(FieldIndex, nsString&& aOldValue); - - bool CanSet(FieldIndex, bool, ContentParent*) { -diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index 4341056f5c66d988d208bbc7aceccb7146311e2f..296ae7b5552ac1cdcaa7fef5e2e1ea8b8d13f221 100644 ---- a/docshell/base/nsDocShell.cpp -+++ b/docshell/base/nsDocShell.cpp -@@ -15,6 +15,12 @@ - # include // for getpid() - #endif - -+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU -+# include "unicode/locid.h" -+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */ -+ -+#include "js/LocaleSensitive.h" -+ - #include "mozilla/ArrayUtils.h" - #include "mozilla/Attributes.h" - #include "mozilla/AutoRestore.h" -@@ -65,6 +71,7 @@ - #include "mozilla/dom/ContentFrameMessageManager.h" - #include "mozilla/dom/DocGroup.h" - #include "mozilla/dom/Element.h" -+#include "mozilla/dom/Geolocation.h" - #include "mozilla/dom/HTMLAnchorElement.h" - #include "mozilla/dom/HTMLIFrameElement.h" - #include "mozilla/dom/PerformanceNavigation.h" -@@ -90,6 +97,7 @@ - #include "mozilla/dom/JSWindowActorChild.h" - #include "mozilla/dom/DocumentBinding.h" - #include "mozilla/ipc/ProtocolUtils.h" -+#include "mozilla/dom/WorkerCommon.h" - #include "mozilla/net/DocumentChannel.h" - #include "mozilla/net/DocumentChannelChild.h" - #include "mozilla/net/ParentChannelWrapper.h" -@@ -114,6 +122,7 @@ - #include "nsIDocShellTreeOwner.h" - #include "mozilla/dom/Document.h" - #include "nsHTMLDocument.h" -+#include "mozilla/dom/Element.h" - #include "nsIDocumentLoaderFactory.h" - #include "nsIDOMWindow.h" - #include "nsIEditingSession.h" -@@ -208,6 +217,7 @@ - #include "nsFocusManager.h" - #include "nsGlobalWindow.h" - #include "nsJSEnvironment.h" -+#include "nsJSUtils.h" - #include "nsNetCID.h" - #include "nsNetUtil.h" - #include "nsObjectLoadingContent.h" -@@ -371,6 +381,13 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, - mAllowDNSPrefetch(true), - mAllowWindowControl(true), - mCSSErrorReportingEnabled(false), -+ mFileInputInterceptionEnabled(false), -+ mOverrideHasFocus(false), -+ mBypassCSPEnabled(false), -+ mForceActiveState(false), -+ mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE), -+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), -+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), - mAllowAuth(mItemType == typeContent), - mAllowKeywordFixup(false), - mDisableMetaRefreshWhenInactive(false), -@@ -3255,6 +3272,221 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { - return NS_OK; - } - -+// =============== Juggler Begin ======================= -+ -+nsDocShell* nsDocShell::GetRootDocShell() { -+ nsCOMPtr rootAsItem; -+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); -+ nsCOMPtr rootShell = do_QueryInterface(rootAsItem); -+ return nsDocShell::Cast(rootShell); -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetBypassCSPEnabled(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mBypassCSPEnabled; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetBypassCSPEnabled(bool aEnabled) { -+ mBypassCSPEnabled = aEnabled; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetForceActiveState(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mForceActiveState; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetForceActiveState(bool aEnabled) { -+ mForceActiveState = aEnabled; -+ ActivenessMaybeChanged(); -+ return NS_OK; -+} -+ -+bool nsDocShell::IsBypassCSPEnabled() { -+ return GetRootDocShell()->mBypassCSPEnabled; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetOverrideHasFocus(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mOverrideHasFocus; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetOverrideHasFocus(bool aEnabled) { -+ mOverrideHasFocus = aEnabled; -+ return NS_OK; -+} -+ -+bool nsDocShell::ShouldOverrideHasFocus() const { -+ return mOverrideHasFocus; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetLanguageOverride(nsAString& aLanguageOverride) { -+ aLanguageOverride = GetRootDocShell()->mLanguageOverride; -+ return NS_OK; -+} -+ -+ -+static void SetIcuLocale(const nsAString& aLanguageOverride) { -+ icu::Locale locale(NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); -+ if (icu::Locale::getDefault() == locale) -+ return; -+ UErrorCode error_code = U_ZERO_ERROR; -+ const char* lang = locale.getLanguage(); -+ if (lang != nullptr && *lang != '\0') { -+ icu::Locale::setDefault(locale, error_code); -+ } else { -+ fprintf(stderr, "SetIcuLocale Failed to set the ICU default locale to %s\n", NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); -+ } -+ -+ AutoJSAPI jsapi; -+ jsapi.Init(); -+ JSContext* cx = jsapi.cx(); -+ JS_ResetDefaultLocale(JS_GetRuntime(cx)); -+ -+ ResetDefaultLocaleInAllWorkers(); -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) { -+ mLanguageOverride = aLanguageOverride; -+ SetIcuLocale(aLanguageOverride); -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride, -+ bool* aSuccess) { -+ NS_ENSURE_ARG(aSuccess); -+ NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride); -+ *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get()); -+ -+ // Set TZ which affects localtime_s(). -+ auto setTimeZoneEnv = [](const char* value) { -+#if defined(_WIN32) -+ return _putenv_s("TZ", value) == 0; -+#else -+ return setenv("TZ", value, true) == 0; -+#endif /* _WIN32 */ -+ }; -+ if (*aSuccess) { -+ *aSuccess = setTimeZoneEnv(timeZoneId.get()); -+ if (!*aSuccess) { -+ fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get()); -+ } -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetFileInputInterceptionEnabled(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = GetRootDocShell()->mFileInputInterceptionEnabled; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetFileInputInterceptionEnabled(bool aEnabled) { -+ mFileInputInterceptionEnabled = aEnabled; -+ return NS_OK; -+} -+ -+bool nsDocShell::IsFileInputInterceptionEnabled() { -+ return GetRootDocShell()->mFileInputInterceptionEnabled; -+} -+ -+void nsDocShell::FilePickerShown(mozilla::dom::Element* element) { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ observerService->NotifyObservers( -+ ToSupports(element), "juggler-file-picker-shown", nullptr); -+} -+ -+RefPtr nsDocShell::GetGeolocationServiceOverride() { -+ return GetRootDocShell()->mGeolocationServiceOverride; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) { -+ if (aGeolocationOverride) { -+ if (!mGeolocationServiceOverride) { -+ mGeolocationServiceOverride = new nsGeolocationService(); -+ mGeolocationServiceOverride->Init(); -+ } -+ mGeolocationServiceOverride->Update(aGeolocationOverride); -+ } else { -+ mGeolocationServiceOverride = nullptr; -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetOnlineOverride(OnlineOverride* aOnlineOverride) { -+ *aOnlineOverride = GetRootDocShell()->mOnlineOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetOnlineOverride(OnlineOverride aOnlineOverride) { -+ // We don't have a way to verify this coming from Javascript, so this check is -+ // still needed. -+ if (!(aOnlineOverride == ONLINE_OVERRIDE_NONE || -+ aOnlineOverride == ONLINE_OVERRIDE_ONLINE || -+ aOnlineOverride == ONLINE_OVERRIDE_OFFLINE)) { -+ return NS_ERROR_INVALID_ARG; -+ } -+ -+ mOnlineOverride = aOnlineOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { -+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { -+ mReducedMotionOverride = aReducedMotionOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) { -+ *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) { -+ mForcedColorsOverride = aForcedColorsOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+// =============== Juggler End ======================= -+ - NS_IMETHODIMP - nsDocShell::GetIsNavigating(bool* aOut) { - *aOut = mIsNavigating; -@@ -4886,7 +5118,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { - } - - void nsDocShell::ActivenessMaybeChanged() { -- const bool isActive = mBrowsingContext->IsActive(); -+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); - if (RefPtr presShell = GetPresShell()) { - presShell->ActivenessMaybeChanged(); - } -@@ -8624,6 +8856,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { - true, // aForceNoOpener - getter_AddRefs(newBC)); - MOZ_ASSERT(!newBC); -+ if (rv == NS_OK) { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); -+ } -+ } - return rv; - } - -@@ -12781,6 +13019,9 @@ class OnLinkClickEvent : public Runnable { - mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, - mTriggeringPrincipal); - } -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); -+ - return NS_OK; - } - -@@ -12860,6 +13101,8 @@ nsresult nsDocShell::OnLinkClick( - nsCOMPtr ev = - new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied, - aIsTrusted, aTriggeringPrincipal); -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); - return Dispatch(TaskCategory::UI, ev.forget()); - } - -diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 293bfeee6e0779d15dd6ef60fc06f9969f70f003..55d431c2a69384cae1d74d90ca36272f473ff8db 100644 ---- a/docshell/base/nsDocShell.h -+++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ - #include "mozilla/UniquePtr.h" - #include "mozilla/WeakPtr.h" - #include "mozilla/dom/BrowsingContext.h" -+#include "mozilla/dom/Element.h" - #include "mozilla/dom/WindowProxyHolder.h" - #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -77,6 +78,7 @@ class nsCommandManager; - class nsDocShellEditorData; - class nsDOMNavigationTiming; - class nsDSURIContentListener; -+class nsGeolocationService; - class nsGlobalWindowOuter; - - class FramingChecker; -@@ -409,6 +411,15 @@ class nsDocShell final : public nsDocLoader, - void SetWillChangeProcess() { mWillChangeProcess = true; } - bool WillChangeProcess() { return mWillChangeProcess; } - -+ bool IsFileInputInterceptionEnabled(); -+ void FilePickerShown(mozilla::dom::Element* element); -+ -+ bool ShouldOverrideHasFocus() const; -+ -+ bool IsBypassCSPEnabled(); -+ -+ RefPtr GetGeolocationServiceOverride(); -+ - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateContentViewerForActor( -@@ -1028,6 +1039,8 @@ class nsDocShell final : public nsDocLoader, - - bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; } - -+ nsDocShell* GetRootDocShell(); -+ - // Handles retrieval of subframe session history for nsDocShell::LoadURI. If a - // load is requested in a subframe of the current DocShell, the subframe - // loadType may need to reflect the loadType of the parent document, or in -@@ -1313,6 +1326,16 @@ class nsDocShell final : public nsDocLoader, - bool mAllowDNSPrefetch : 1; - bool mAllowWindowControl : 1; - bool mCSSErrorReportingEnabled : 1; -+ bool mFileInputInterceptionEnabled: 1; -+ bool mOverrideHasFocus : 1; -+ bool mBypassCSPEnabled : 1; -+ bool mForceActiveState : 1; -+ nsString mLanguageOverride; -+ RefPtr mGeolocationServiceOverride; -+ OnlineOverride mOnlineOverride; -+ ReducedMotionOverride mReducedMotionOverride; -+ ForcedColorsOverride mForcedColorsOverride; -+ - bool mAllowAuth : 1; - bool mAllowKeywordFixup : 1; - bool mDisableMetaRefreshWhenInactive : 1; -diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799ad244494 100644 ---- a/docshell/base/nsIDocShell.idl -+++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; - interface nsIChannel; - interface nsIContentViewer; - interface nsIContentSecurityPolicy; -+interface nsIDOMGeoPosition; - interface nsIEditor; - interface nsIEditingSession; - interface nsIInputStream; -@@ -803,6 +804,41 @@ interface nsIDocShell : nsIDocShellTreeItem - */ - void synchronizeLayoutHistoryState(); - -+ attribute boolean fileInputInterceptionEnabled; -+ -+ attribute boolean overrideHasFocus; -+ -+ attribute boolean bypassCSPEnabled; -+ -+ attribute boolean forceActiveState; -+ -+ attribute AString languageOverride; -+ -+ boolean overrideTimezone(in AString timezoneId); -+ -+ cenum OnlineOverride: 8 { -+ ONLINE_OVERRIDE_NONE = 0, -+ ONLINE_OVERRIDE_ONLINE = 1, -+ ONLINE_OVERRIDE_OFFLINE = 2, -+ }; -+ [infallible] attribute nsIDocShell_OnlineOverride onlineOverride; -+ -+ cenum ReducedMotionOverride : 8 { -+ REDUCED_MOTION_OVERRIDE_REDUCE, -+ REDUCED_MOTION_OVERRIDE_NO_PREFERENCE, -+ REDUCED_MOTION_OVERRIDE_NONE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ReducedMotionOverride reducedMotionOverride; -+ -+ cenum ForcedColorsOverride : 8 { -+ FORCED_COLORS_OVERRIDE_ACTIVE, -+ FORCED_COLORS_OVERRIDE_NONE, -+ FORCED_COLORS_OVERRIDE_NO_OVERRIDE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ForcedColorsOverride forcedColorsOverride; -+ -+ void setGeolocationOverride(in nsIDOMGeoPosition position); -+ - /** - * This attempts to save any applicable layout history state (like - * scroll position) in the nsISHEntry. This is normally done -diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp -index 2d744434a271f5bd7636b9ae344cbcb6666739e2..d2b4c2ce06ff61247cb64e64b9b30db268d520c4 100644 ---- a/dom/base/Document.cpp -+++ b/dom/base/Document.cpp -@@ -3649,6 +3649,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { - } - - void Document::ApplySettingsFromCSP(bool aSpeculative) { -+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) -+ return; -+ - nsresult rv = NS_OK; - if (!aSpeculative) { - // 1) apply settings from regular CSP -@@ -3706,6 +3709,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { - MOZ_ASSERT(!mScriptGlobalObject, - "CSP must be initialized before mScriptGlobalObject is set!"); - -+ nsCOMPtr shell(mDocumentContainer); -+ if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) { -+ return NS_OK; -+ } -+ - // If this is a data document - no need to set CSP. - if (mLoadedAsData) { - return NS_OK; -@@ -4517,6 +4525,10 @@ bool Document::HasFocus(ErrorResult& rv) const { - return false; - } - -+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - if (!fm->IsInActiveWindow(bc)) { - return false; - } -@@ -17888,6 +17900,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { - return LookAndFeel::PreferredColorSchemeForContent(); - } - -+bool Document::PrefersReducedMotion() const { -+ auto* docShell = static_cast(GetDocShell()); -+ nsIDocShell::ReducedMotionOverride reducedMotion; -+ if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK && -+ reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) { -+ switch (reducedMotion) { -+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE: -+ return true; -+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE: -+ return false; -+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE: -+ break; -+ }; -+ } -+ -+ if (auto* bc = GetBrowsingContext()) { -+ switch (bc->Top()->PrefersReducedMotionOverride()) { -+ case dom::PrefersReducedMotionOverride::Reduce: -+ return true; -+ case dom::PrefersReducedMotionOverride::No_preference: -+ return false; -+ case dom::PrefersReducedMotionOverride::None: -+ case dom::PrefersReducedMotionOverride::EndGuard_: -+ break; -+ } -+ } -+ -+ if (nsContentUtils::ShouldResistFingerprinting(this)) { -+ return false; -+ } -+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+} -+ -+bool Document::ForcedColors() const { -+ auto* docShell = static_cast(GetDocShell()); -+ nsIDocShell::ForcedColorsOverride forcedColors; -+ if (docShell && docShell->GetForcedColorsOverride(&forcedColors) == NS_OK) { -+ switch (forcedColors) { -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_ACTIVE: -+ return true; -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NONE: -+ return false; -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NO_OVERRIDE: -+ break; -+ }; -+ } -+ -+ if (auto* bc = GetBrowsingContext()) { -+ switch (bc->Top()->ForcedColorsOverride()) { -+ case dom::ForcedColorsOverride::Active: -+ return true; -+ case dom::ForcedColorsOverride::None: -+ return false; -+ case dom::ForcedColorsOverride::No_override: -+ case dom::ForcedColorsOverride::EndGuard_: -+ break; -+ } -+ } -+ -+ if (mIsBeingUsedAsImage) { -+ return false; -+ } -+ return !PreferenceSheet::PrefsFor(*this).mUseDocumentColors; -+} -+ - bool Document::HasRecentlyStartedForegroundLoads() { - if (!sLoadingForegroundTopLevelContentDocument) { - return false; -diff --git a/dom/base/Document.h b/dom/base/Document.h -index 41a5ece69fc8474b572956c37e0b4748dc6c5370..206550a448e0c73f0fb46e542722545e49992db3 100644 ---- a/dom/base/Document.h -+++ b/dom/base/Document.h -@@ -4024,6 +4024,9 @@ class Document : public nsINode, - // color-scheme meta tag. - ColorScheme DefaultColorScheme() const; - -+ bool PrefersReducedMotion() const; -+ bool ForcedColors() const; -+ - static bool HasRecentlyStartedForegroundLoads(); - - static bool AutomaticStorageAccessPermissionCanBeGranted( -diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 92081a09b4925e0b687608abd8ad51d02ff2f5cf..b010190d8af0cd1765d91b5bbd7e46e360a6c30f 100644 ---- a/dom/base/Navigator.cpp -+++ b/dom/base/Navigator.cpp -@@ -325,14 +325,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const { - * for more detail. - */ - /* static */ --void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { -+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages) { - MOZ_ASSERT(NS_IsMainThread()); - - aLanguages.Clear(); - - // E.g. "de-de, en-us,en". - nsAutoString acceptLang; -- Preferences::GetLocalizedString("intl.accept_languages", acceptLang); -+ if (aLanguageOverride && aLanguageOverride->Length()) -+ acceptLang = *aLanguageOverride; -+ else -+ Preferences::GetLocalizedString("intl.accept_languages", acceptLang); -+ - - // Split values on commas. - for (nsDependentSubstring lang : -@@ -384,7 +388,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { - } - - void Navigator::GetLanguages(nsTArray& aLanguages) { -- GetAcceptLanguages(aLanguages); -+ if (mWindow && mWindow->GetDocShell()) { -+ nsString languageOverride; -+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); -+ GetAcceptLanguages(&languageOverride, aLanguages); -+ } else { -+ GetAcceptLanguages(nullptr, aLanguages); -+ } - - // The returned value is cached by the binding code. The window listens to the - // accept languages change and will clear the cache when needed. It has to -@@ -563,7 +573,13 @@ bool Navigator::CookieEnabled() { - return granted; - } - --bool Navigator::OnLine() { return !NS_IsOffline(); } -+bool Navigator::OnLine() { -+ nsDocShell* docShell = static_cast(GetDocShell()); -+ nsIDocShell::OnlineOverride onlineOverride; -+ if (!docShell || docShell->GetOnlineOverride(&onlineOverride) != NS_OK || onlineOverride == nsIDocShell::ONLINE_OVERRIDE_NONE) -+ return !NS_IsOffline(); -+ return onlineOverride == nsIDocShell::ONLINE_OVERRIDE_ONLINE; -+} - - void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType, - ErrorResult& aRv) const { -diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index cb821086b1ac884ba96ef8874211bff16106b206..3b93388637f9ec7493735e9beb6f02a78e14c6b3 100644 ---- a/dom/base/Navigator.h -+++ b/dom/base/Navigator.h -@@ -215,7 +215,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { - - StorageManager* Storage(); - -- static void GetAcceptLanguages(nsTArray& aLanguages); -+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); - - dom::MediaCapabilities* MediaCapabilities(); - dom::MediaSession* MediaSession(); -diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index bed527b613ca169fef7d19870a16fe634b57ff25..bca538a001c7c7a1d334b8af2e4f795c0f3d171d 100644 ---- a/dom/base/nsContentUtils.cpp -+++ b/dom/base/nsContentUtils.cpp -@@ -8509,7 +8509,8 @@ nsresult nsContentUtils::SendMouseEvent( - bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, - PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized) { -+ bool aIsWidgetEventSynthesized, -+ bool convertToPointer) { - nsPoint offset; - nsCOMPtr widget = GetWidget(aPresShell, &offset); - if (!widget) return NS_ERROR_FAILURE; -@@ -8568,6 +8569,7 @@ nsresult nsContentUtils::SendMouseEvent( - event.mTime = PR_IntervalNow(); - event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; - event.mExitFrom = exitFrom; -+ event.convertToPointer = convertToPointer; - - nsPresContext* presContext = aPresShell->GetPresContext(); - if (!presContext) return NS_ERROR_FAILURE; -diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h -index a4446404bd7fa503f9320521d66d60695375b8d5..7b23679ce7affb80b23d0eaf1879548c0d41c519 100644 ---- a/dom/base/nsContentUtils.h -+++ b/dom/base/nsContentUtils.h -@@ -2957,7 +2957,8 @@ class nsContentUtils { - int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, - mozilla::PreventDefaultResult* aPreventDefault, -- bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized); -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true); - - static void FirePageShowEventForFrameLoaderSwap( - nsIDocShellTreeItem* aItem, -diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index 8cee829af918aa0c44049f794746816f73fb7b50..daad61c3fbd526aa941c8c0be28892d7ec00521d 100644 ---- a/dom/base/nsDOMWindowUtils.cpp -+++ b/dom/base/nsDOMWindowUtils.cpp -@@ -683,7 +683,7 @@ nsDOMWindowUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, - bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -- int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, uint8_t aOptionalArgCount, - bool* aPreventDefault) { - return SendMouseEventCommon( - aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -@@ -691,7 +691,7 @@ nsDOMWindowUtils::SendMouseEvent( - aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false, - aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, - aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, -- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, !aDisablePointerEvent); - } - - NS_IMETHODIMP -@@ -718,13 +718,13 @@ nsDOMWindowUtils::SendMouseEventCommon( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized, int32_t aButtons) { -+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer) { - RefPtr presShell = GetPresShell(); - PreventDefaultResult preventDefaultResult; - nsresult rv = nsContentUtils::SendMouseEvent( - presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers, - aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow, -- &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); -+ &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer); - - if (aPreventDefault) { - *aPreventDefault = preventDefaultResult != PreventDefaultResult::No; -diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 30e0fafa77857c33e9871259a6ac0cebac965df8..3d8810abcfac1c220529b4e6163b0159475723ff 100644 ---- a/dom/base/nsDOMWindowUtils.h -+++ b/dom/base/nsDOMWindowUtils.h -@@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils, - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized, int32_t aButtons); -+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true); - - MOZ_CAN_RUN_SCRIPT - nsresult SendTouchEventCommon( -diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 25c06cd90d552345da4fffbcdb4dfaab02377c97..cc81b234da508405daba42735430dd3f065d2b0c 100644 ---- a/dom/base/nsFocusManager.cpp -+++ b/dom/base/nsFocusManager.cpp -@@ -1610,6 +1610,10 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags, - (GetActiveBrowsingContext() == newRootBrowsingContext); - } - -+ // In Playwright, we want to send focus events even if the element -+ // isn't actually in the active window. -+ isElementInActiveWindow = true; -+ - // Exit fullscreen if a website focuses another window - if (StaticPrefs::full_screen_api_exit_on_windowRaise() && - !isElementInActiveWindow && (aFlags & FLAG_RAISE) && -@@ -2934,7 +2938,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, - } - } - -- if (sTestMode) { -+ // In Playwright, we still want to execte the embedder functions -+ // to actually show / focus windows. -+ if (false && sTestMode) { - // In test mode, emulate raising the window. WindowRaised takes - // care of lowering the present active window. This happens in - // a separate runnable to avoid touching multiple windows in -diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp -index 6b95fcd529cb796741a26c3af2d78d97f8b9fdb8..02010c7e0a5c5cfe9e7fc37d1cd57afcfe12f8d9 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2489,7 +2489,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, - &nsGlobalWindowInner::FireOnNewGlobalObject)); - } - -- if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) { -+ if (newInnerWindow && mDoc) { - // We should probably notify. However if this is the, arguably bad, - // situation when we're creating a temporary non-chrome-about-blank - // document in a chrome docshell, don't notify just yet. Instead wait -@@ -2508,10 +2508,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, - }(); - - if (!isContentAboutBlankInChromeDocshell) { -- newInnerWindow->mHasNotifiedGlobalCreated = true; -- nsContentUtils::AddScriptRunner(NewRunnableMethod( -- "nsGlobalWindowOuter::DispatchDOMWindowCreated", this, -- &nsGlobalWindowOuter::DispatchDOMWindowCreated)); -+ if (!newInnerWindow->mHasNotifiedGlobalCreated) { -+ newInnerWindow->mHasNotifiedGlobalCreated = true; -+ nsContentUtils::AddScriptRunner(NewRunnableMethod( -+ "nsGlobalWindowOuter::DispatchDOMWindowCreated", this, -+ &nsGlobalWindowOuter::DispatchDOMWindowCreated)); -+ } else if (!reUseInnerWindow) { -+ nsContentUtils::AddScriptRunner(NewRunnableMethod( -+ "nsGlobalWindowOuter::JugglerDispatchDOMWindowReused", this, -+ &nsGlobalWindowOuter::JugglerDispatchDOMWindowReused)); -+ } - } - } - -@@ -2632,6 +2638,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { - } - } - -+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && mDoc) { -+ nsIPrincipal* principal = mDoc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) { -+ observerService->NotifyObservers(static_cast(this), -+ "juggler-dom-window-reused", -+ nullptr); -+ } -+ } -+} -+ - void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } - - void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -@@ -3770,6 +3789,14 @@ Maybe nsGlobalWindowOuter::GetRDMDeviceSize( - } - } - } -+ if (topInProcessContentDoc) { -+ nsIDocShell* docShell = topInProcessContentDoc->GetDocShell(); -+ if (docShell && docShell->GetDeviceSizeIsPageSize()) { -+ nsPresContext* presContext = docShell->GetPresContext(); -+ if (presContext) -+ return Some(CSSPixel::FromAppUnitsRounded(presContext->GetVisibleArea().Size())); -+ } -+ } - return Nothing(); - } - -diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index e8285b0fb892040737ad9de2fa60b192b0a8d37f..fa9d0b219dcfa787ce1629809fbe83578f084b26 100644 ---- a/dom/base/nsGlobalWindowOuter.h -+++ b/dom/base/nsGlobalWindowOuter.h -@@ -333,6 +333,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, - - // Outer windows only. - void DispatchDOMWindowCreated(); -+ void JugglerDispatchDOMWindowReused(); - - // Outer windows only. - virtual void EnsureSizeAndPositionUpToDate() override; -diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp -index 1088bfc489a067f95bfb84a822a787bdf9463e54..54c4687ff71ec1b82912d9139f061ef5c7d4a426 100644 ---- a/dom/base/nsINode.cpp -+++ b/dom/base/nsINode.cpp -@@ -1324,6 +1324,62 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, - mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); - } - -+static nsIFrame* GetFirstFrame(nsINode* aNode) { -+ if (!aNode->IsContent()) -+ return nullptr; -+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); -+ if (!frame) { -+ FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = child->GetPrimaryFrame(FlushType::Frames); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ -+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv) { -+ aRv = NS_ERROR_UNEXPECTED; -+ nsCOMPtr document = OwnerDoc(); -+ if (!document) { -+ return aRv.ThrowNotFoundError("Node is detached from document"); -+ } -+ PresShell* presShell = document->GetPresShell(); -+ if (!presShell) { -+ return aRv.ThrowNotFoundError("Node is detached from document"); -+ } -+ nsIFrame* primaryFrame = GetFirstFrame(this); -+ if (!primaryFrame) { -+ return aRv.ThrowNotFoundError("Node does not have a layout object"); -+ } -+ aRv = NS_OK; -+ nsRect rect; -+ if (x == -1 && y == -1 && w == -1 && h == -1) { -+ rect = primaryFrame->GetRectRelativeToSelf(); -+ } else { -+ rect = nsRect(nsPresContext::CSSPixelsToAppUnits(x), -+ nsPresContext::CSSPixelsToAppUnits(y), -+ nsPresContext::CSSPixelsToAppUnits(w), -+ nsPresContext::CSSPixelsToAppUnits(h)); -+ } -+ presShell->ScrollFrameRectIntoView( -+ primaryFrame, rect, -+ nsMargin(), -+ ScrollAxis(kScrollToCenter, WhenToScroll::Always), -+ ScrollAxis(kScrollToCenter, WhenToScroll::Always), -+ ScrollFlags::ScrollOverflowHidden); -+ // If a _visual_ scroll update is pending, cancel it; otherwise, it will -+ // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break). -+ if (presShell->GetPendingVisualScrollUpdate()) { -+ presShell->AcknowledgePendingVisualScrollUpdate(); -+ presShell->ClearPendingVisualScrollUpdate(); -+ } -+} -+ - already_AddRefed nsINode::ConvertQuadFromNode( - DOMQuad& aQuad, const GeometryNode& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h -index 0c7c5867c4a1f2543b774a1f3371c4ce0807f33f..ae35e4a023297f2f0b9d59eb9a0fa8e5aa649202 100644 ---- a/dom/base/nsINode.h -+++ b/dom/base/nsINode.h -@@ -2130,6 +2130,10 @@ class nsINode : public mozilla::dom::EventTarget { - nsTArray>& aResult, - ErrorResult& aRv); - -+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv); -+ - already_AddRefed ConvertQuadFromNode( - DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index 1da84501bf3ce25b932ec3693f247cdb1a4fdf21..2305a1730e18ba7293a41772b9b7495b5aa66210 100644 ---- a/dom/base/nsJSUtils.cpp -+++ b/dom/base/nsJSUtils.cpp -@@ -169,6 +169,11 @@ bool nsJSUtils::GetScopeChainForElement( - return true; - } - -+/* static */ -+bool nsJSUtils::SetTimeZoneOverride(const char* timezoneId) { -+ return JS::SetTimeZoneOverride(timezoneId); -+} -+ - /* static */ - void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } - -diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h -index 85a21e459305f556933f4dc0fa7441d8f9ed95a9..d7cb86479ba2ed06542307349d6d86dfd026d55d 100644 ---- a/dom/base/nsJSUtils.h -+++ b/dom/base/nsJSUtils.h -@@ -78,6 +78,7 @@ class nsJSUtils { - JSContext* aCx, mozilla::dom::Element* aElement, - JS::MutableHandleVector aScopeChain); - -+ static bool SetTimeZoneOverride(const char* timezoneId); - static void ResetTimeZone(); - - static bool DumpEnabled(); -diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl -index 414e8367d19057d3249f07f6590fc84534406bf3..5872741f2e22d500cd3b939e66e730aaac5ad717 100644 ---- a/dom/chrome-webidl/BrowsingContext.webidl -+++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -52,6 +52,24 @@ enum PrefersColorSchemeOverride { - "dark", - }; - -+/** -+ * CSS prefers-reduced-motion values. -+ */ -+enum PrefersReducedMotionOverride { -+ "none", -+ "reduce", -+ "no-preference", -+}; -+ -+/** -+ * CSS forced-colors values. -+ */ -+enum ForcedColorsOverride { -+ "none", -+ "active", -+ "no-override", /* This clears the override. */ -+}; -+ - /** - * Allowed overrides of platform/pref default behaviour for touch events. - */ -@@ -186,6 +204,12 @@ interface BrowsingContext { - // Color-scheme simulation, for DevTools. - [SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride; - -+ // Reduced-Motion simulation, for DevTools. -+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Forced-Colors simulation, for DevTools. -+ [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; -+ - /** - * A unique identifier for the browser element that is hosting this - * BrowsingContext tree. Every BrowsingContext in the element's tree will -diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351599950e1 100644 ---- a/dom/geolocation/Geolocation.cpp -+++ b/dom/geolocation/Geolocation.cpp -@@ -23,6 +23,7 @@ - #include "nsComponentManagerUtils.h" - #include "nsContentPermissionHelper.h" - #include "nsContentUtils.h" -+#include "nsDocShell.h" - #include "nsGlobalWindow.h" - #include "mozilla/dom/Document.h" - #include "nsINamed.h" -@@ -260,10 +261,8 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- RefPtr gs = -- nsGeolocationService::GetGeolocationService(); -- -- bool canUseCache = false; -+ nsGeolocationService* gs = mLocator->GetGeolocationService(); -+ bool canUseCache = gs != nsGeolocationService::sService.get(); - CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); - if (lastPosition.position) { - EpochTimeStamp cachedPositionTime_ms; -@@ -436,8 +435,7 @@ void nsGeolocationRequest::Shutdown() { - // If there are no other high accuracy requests, the geolocation service will - // notify the provider to switch to the default accuracy. - if (mOptions && mOptions->mEnableHighAccuracy) { -- RefPtr gs = -- nsGeolocationService::GetGeolocationService(); -+ nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr; - if (gs) { - gs->UpdateAccuracy(); - } -@@ -727,8 +725,14 @@ void nsGeolocationService::StopDevice() { - StaticRefPtr nsGeolocationService::sService; - - already_AddRefed --nsGeolocationService::GetGeolocationService() { -+nsGeolocationService::GetGeolocationService(nsDocShell* docShell) { - RefPtr result; -+ if (docShell) { -+ result = docShell->GetGeolocationServiceOverride(); -+ if (result) -+ return result.forget(); -+ } -+ - if (nsGeolocationService::sService) { - result = nsGeolocationService::sService; - -@@ -820,7 +824,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { - // If no aContentDom was passed into us, we are being used - // by chrome/c++ and have no mOwner, no mPrincipal, and no need - // to prompt. -- mService = nsGeolocationService::GetGeolocationService(); -+ nsCOMPtr doc = aContentDom ? aContentDom->GetDoc() : nullptr; -+ mService = nsGeolocationService::GetGeolocationService( -+ doc ? static_cast(doc->GetDocShell()) : nullptr); - if (mService) { - mService->AddLocator(this); - } -diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 5c0d2f96a22c6928d6aee5a226032c0944ae7a54..5a7bb1f6cea1946eea143dca4e2f1e19746a04a4 100644 ---- a/dom/geolocation/Geolocation.h -+++ b/dom/geolocation/Geolocation.h -@@ -31,6 +31,7 @@ - - #include "nsIGeolocationProvider.h" - #include "mozilla/Attributes.h" -+#include "nsDocShell.h" - - class nsGeolocationService; - class nsGeolocationRequest; -@@ -48,13 +49,14 @@ struct CachedPositionAndAccuracy { - bool isHighAccuracy; - }; - -+ - /** - * Singleton that manages the geolocation provider - */ - class nsGeolocationService final : public nsIGeolocationUpdate, - public nsIObserver { - public: -- static already_AddRefed GetGeolocationService(); -+ static already_AddRefed GetGeolocationService(nsDocShell* docShell = nullptr); - static mozilla::StaticRefPtr sService; - - NS_DECL_THREADSAFE_ISUPPORTS -@@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache { - // null. - static already_AddRefed NonWindowSingleton(); - -+ nsGeolocationService* GetGeolocationService() { return mService; }; -+ - private: - ~Geolocation(); - -diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index cdd330a8efdfd6c3fb54780fabb0d00505e831c9..87df1c6dad398e4914b71e30df0940aa0b1bab71 100644 ---- a/dom/html/HTMLInputElement.cpp -+++ b/dom/html/HTMLInputElement.cpp -@@ -53,6 +53,7 @@ - #include "nsMappedAttributes.h" - #include "nsIFormControl.h" - #include "mozilla/dom/Document.h" -+#include "nsDocShell.h" - #include "nsIFormControlFrame.h" - #include "nsITextControlFrame.h" - #include "nsIFrame.h" -@@ -746,6 +747,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { - return NS_ERROR_FAILURE; - } - -+ nsDocShell* docShell = static_cast(win->GetDocShell()); -+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { -+ docShell->FilePickerShown(this); -+ return NS_OK; -+ } -+ - if (IsPopupBlocked(doc)) { - return NS_OK; - } -diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 51e3288c4cc8f40309a7c75d36c236f6f21fdfb7..844d362d956884feb41181fe40504de497ada14b 100644 ---- a/dom/interfaces/base/nsIDOMWindowUtils.idl -+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -372,7 +372,8 @@ interface nsIDOMWindowUtils : nsISupports { - [optional] in boolean aIsDOMEventSynthesized, - [optional] in boolean aIsWidgetEventSynthesized, - [optional] in long aButtons, -- [optional] in unsigned long aIdentifier); -+ [optional] in unsigned long aIdentifier, -+ [optional] in boolean aDisablePointerEvent); - - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index 9d4e8fbbfe8d45cc6245c7659423004ad1ceedeb..f955c7bace3cedfe0469e59a5e8c5824158c4d50 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -123,10 +123,11 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, - return 0; - } - --VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id, -+VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t id, - const char* uniqueId, -- const CaptureDeviceType type) { -- return new rtc::RefCountedObject(id, uniqueId, type); -+ const CaptureDeviceType type, -+ bool captureCursor) { -+ return new rtc::RefCountedObject(id, uniqueId, type, captureCursor); - } - - int32_t WindowDeviceInfoImpl::Init() { -@@ -358,9 +359,13 @@ int32_t DesktopCaptureImpl::Init() { - DesktopCapturer::SourceId sourceId = atoi(_deviceUniqueId.c_str()); - pWindowCapturer->SelectSource(sourceId); - -- desktop_capturer_cursor_composer_ = -- std::unique_ptr( -- new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); -+ if (capture_cursor_) { -+ desktop_capturer_cursor_composer_ = -+ std::unique_ptr( -+ new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); -+ } else { -+ desktop_capturer_cursor_composer_ = std::move(pWindowCapturer); -+ } - } else if (_deviceType == CaptureDeviceType::Browser) { - // XXX We don't capture cursors, so avoid the extra indirection layer. We - // could also pass null for the pMouseCursorMonitor. -@@ -377,13 +382,15 @@ int32_t DesktopCaptureImpl::Init() { - } - - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type) -+ const CaptureDeviceType type, -+ bool captureCursor) - : _id(id), - _deviceUniqueId(uniqueId), - _deviceType(type), - _requestedCapability(), - _rotateFrame(kVideoRotation_0), - last_capture_time_ms_(rtc::TimeMillis()), -+ capture_cursor_(captureCursor), - time_event_(EventWrapper::Create()), - #if defined(_WIN32) - capturer_thread_( -@@ -428,6 +435,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } - } - -+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&_apiCs); -+ _rawFrameCallbacks.insert(rawFrameCallback); -+} -+ -+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&_apiCs); -+ auto it = _rawFrameCallbacks.find(rawFrameCallback); -+ if (it != _rawFrameCallbacks.end()) { -+ _rawFrameCallbacks.erase(it); -+ } -+} -+ - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - if (_dataCallBacks.empty()) { - return StopCapture(); -@@ -636,6 +656,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result result, - frameInfo.height = frame->size().height(); - frameInfo.videoType = VideoType::kARGB; - -+ size_t videoFrameStride = -+ frameInfo.width * DesktopFrame::kBytesPerPixel; -+ { -+ rtc::CritScope cs(&_apiCs); -+ for (auto rawFrameCallback : _rawFrameCallbacks) { -+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); -+ } -+ } -+ - size_t videoFrameLength = - frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - IncomingFrame(videoFrame, videoFrameLength, -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index b725849dab1d1f898ab988e57a35c27e3eb44700..e2e13b0a0926475fe673fecf5e3c497569d158b3 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.h -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -46,6 +46,21 @@ namespace webrtc { - - class VideoCaptureEncodeInterface; - -+class RawFrameCallback { -+ public: -+ virtual ~RawFrameCallback() {} -+ -+ virtual void OnRawFrame(uint8_t* videoFrame, size_t videoFrameLength, const VideoCaptureCapability& frameInfo) = 0; -+}; -+ -+class VideoCaptureModuleEx : public VideoCaptureModule { -+ public: -+ virtual ~VideoCaptureModuleEx() {} -+ -+ virtual void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; -+ virtual void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; -+}; -+ - // simulate deviceInfo interface for video engine, bridge screen/application and - // real screen/application device info - -@@ -158,12 +173,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { - // As with video, DesktopCaptureImpl is a proxy for screen sharing - // and follows the video pipeline design - class DesktopCaptureImpl : public DesktopCapturer::Callback, -- public VideoCaptureModule { -+ public VideoCaptureModuleEx { - public: - /* Create a screen capture modules object - */ -- static VideoCaptureModule* Create(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type); -+ static VideoCaptureModuleEx* Create(const int32_t id, const char* uniqueId, -+ const CaptureDeviceType type, -+ bool captureCursor = true); - static VideoCaptureModule::DeviceInfo* CreateDeviceInfo( - const int32_t id, const CaptureDeviceType type); - -@@ -173,6 +189,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; - int32_t StopCaptureIfAllClientsClose() override; -+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; -+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(VideoRotation rotation) override; - bool SetApplyRotation(bool enable) override; -@@ -193,7 +211,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - - protected: - DesktopCaptureImpl(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type); -+ const CaptureDeviceType type, bool captureCursor); - virtual ~DesktopCaptureImpl(); - int32_t DeliverCapturedFrame(webrtc::VideoFrame& captureFrame); - -@@ -215,6 +233,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - rtc::RecursiveCriticalSection _apiCs; - - std::set*> _dataCallBacks; -+ std::set _rawFrameCallbacks; - - int64_t _incomingFrameTimesNanos - [kFrameRateCountHistorySize]; // timestamp for local captured frames -@@ -237,6 +256,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void ProcessIter(); - - private: -+ bool capture_cursor_ = true; - // This is created on the main thread and accessed on both the main thread - // and the capturer thread. It is created prior to the capturer thread - // starting and is destroyed after it is stopped. -diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index 8c8a5810fd56512cf37635da1f43757719f06113..d2bc58fcd3b05f989f948839d574d00d0409873c 100644 ---- a/dom/script/ScriptSettings.cpp -+++ b/dom/script/ScriptSettings.cpp -@@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { - MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal()); - } - -+static nsIGlobalObject* UnwrapSandboxGlobal(nsIGlobalObject* global) { -+ if (!global) -+ return global; -+ JSObject* globalObject = global->GetGlobalJSObject(); -+ if (!globalObject) -+ return global; -+ JSContext* cx = nsContentUtils::GetCurrentJSContext(); -+ if (!cx) -+ return global; -+ JS::Rooted proto(cx); -+ JS::RootedObject rootedGlobal(cx, globalObject); -+ if (!JS_GetPrototype(cx, rootedGlobal, &proto)) -+ return global; -+ if (!proto || !xpc::IsSandboxPrototypeProxy(proto)) -+ return global; -+ // If this is a sandbox associated with a DOMWindow via a -+ // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey -+ // and JetPack content scripts. -+ proto = js::CheckedUnwrapDynamic(proto, cx, /* stopAtWindowProxy = */ false); -+ if (!proto) -+ return global; -+ return xpc::WindowGlobalOrNull(proto); -+} -+ - // If the entry or incumbent global ends up being something that the subject - // principal doesn't subsume, we don't want to use it. This never happens on - // the web, but can happen with asymmetric privilege relationships (i.e. -@@ -177,7 +201,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) { - NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal()); - if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller() - ->SubsumesConsideringDomain(globalPrin)) { -- return GetCurrentGlobal(); -+ return UnwrapSandboxGlobal(GetCurrentGlobal()); - } - - return aGlobalOrNull; -diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp -index e78ba8eece8dc173a0755c2bbd4031fc9c83ce21..9cc998760258dc5224d71ce20bdd440a600c480e 100644 ---- a/dom/security/nsCSPUtils.cpp -+++ b/dom/security/nsCSPUtils.cpp -@@ -127,6 +127,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, - return; - } - -+ if (aDoc.GetDocShell() && -+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsAutoString policyStr( - nsContentUtils::TrimWhitespace( - aPolicyStr)); -diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index 2f71b284ee5f7e11f117c447834b48355784448c..ddcc545da1efec5784273b032efa00ad8b89fec0 100644 ---- a/dom/webidl/GeometryUtils.webidl -+++ b/dom/webidl/GeometryUtils.webidl -@@ -16,6 +16,8 @@ dictionary BoxQuadOptions { - GeometryNode relativeTo; - [ChromeOnly] - boolean createFramesForSuppressedWhitespace = true; -+ [ChromeOnly] -+ boolean recurseWhenNoFrame = false; - }; - - dictionary ConvertCoordinateOptions { -@@ -27,6 +29,9 @@ interface mixin GeometryUtils { - [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] - sequence getBoxQuads(optional BoxQuadOptions options = {}); - -+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ void scrollRectIntoViewIfNeeded(long x, long y, long w, long h); -+ - /* getBoxQuadsFromWindowOrigin is similar to getBoxQuads, but the - * returned quads are further translated relative to the window - * origin -- which is not the layout origin. Further translation -diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp -index 2f9beef0bde229a2f414f46d3ec2b10eac5c4f1c..2aa8c6b75b7791e29b6f579718a2d6e250dc4236 100644 ---- a/dom/workers/RuntimeService.cpp -+++ b/dom/workers/RuntimeService.cpp -@@ -981,7 +981,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { - AssertIsOnMainThread(); - - nsTArray languages; -- Navigator::GetAcceptLanguages(languages); -+ Navigator::GetAcceptLanguages(nullptr, languages); - - RuntimeService* runtime = RuntimeService::GetService(); - if (runtime) { -@@ -1183,8 +1183,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { - } - - // The navigator overridden properties should have already been read. -- -- Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages); -+ Navigator::GetAcceptLanguages(nullptr, mNavigatorProperties.mLanguages); - mNavigatorPropertiesLoaded = true; - } - -@@ -1782,6 +1781,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( - } - } - -+void RuntimeService::ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ BroadcastAllWorkers([](auto& worker) { -+ worker.ResetDefaultLocale(); -+ }); -+} -+ - template - void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { - AssertIsOnMainThread(); -@@ -2197,6 +2203,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( - } - } - -+void ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ RuntimeService* runtime = RuntimeService::GetService(); -+ if (runtime) { -+ runtime->ResetDefaultLocaleInAllWorkers(); -+ } -+} -+ - WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ASSERT(aCx); -diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h -index d1a44a19e865fb76cf2b7bfe5e1fbd9c64ec0465..1a44fee6508ea0ef3f48700b83b1185565778cc8 100644 ---- a/dom/workers/RuntimeService.h -+++ b/dom/workers/RuntimeService.h -@@ -110,6 +110,8 @@ class RuntimeService final : public nsIObserver { - void PropagateStorageAccessPermissionGranted( - const nsPIDOMWindowInner& aWindow); - -+ void ResetDefaultLocaleInAllWorkers(); -+ - const NavigatorProperties& GetNavigatorProperties() const { - return mNavigatorProperties; - } -diff --git a/dom/workers/WorkerCommon.h b/dom/workers/WorkerCommon.h -index d10dabb5c5ff8e17851edf2bd2efc08e74584d8e..53c4070c5fde43b27fb8fbfdcf4c23d8af57fba3 100644 ---- a/dom/workers/WorkerCommon.h -+++ b/dom/workers/WorkerCommon.h -@@ -44,6 +44,8 @@ void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow); - void PropagateStorageAccessPermissionGrantedToWorkers( - const nsPIDOMWindowInner& aWindow); - -+void ResetDefaultLocaleInAllWorkers(); -+ - // All of these are implemented in WorkerScope.cpp - - bool IsWorkerGlobal(JSObject* global); -diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp -index 3c53d24cbf31d01909cbf680eb0b485320607d59..8546618453d78ea507b9feeea362577c0dbd0153 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -699,6 +699,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { - } - }; - -+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { -+ public: -+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) -+ : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {} -+ -+ virtual bool WorkerRun(JSContext* aCx, -+ WorkerPrivate* aWorkerPrivate) override { -+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); -+ return true; -+ } -+}; -+ - class UpdateLanguagesRunnable final : public WorkerRunnable { - nsTArray mLanguages; - -@@ -1951,6 +1963,16 @@ void WorkerPrivate::UpdateContextOptions( - } - } - -+void WorkerPrivate::ResetDefaultLocale() { -+ AssertIsOnParentThread(); -+ -+ RefPtr runnable = -+ new ResetDefaultLocaleRunnable(this); -+ if (!runnable->Dispatch()) { -+ NS_WARNING("Failed to reset default locale in worker!"); -+ } -+} -+ - void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { - AssertIsOnParentThread(); - -@@ -5123,6 +5145,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( - } - } - -+void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) { -+ JS_ResetDefaultLocale(JS_GetRuntime(aCx)); -+ auto data = mWorkerThreadAccessible.Access(); -+ -+ for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) { -+ data->mChildWorkers[index]->ResetDefaultLocale(); -+ } -+} -+ - void WorkerPrivate::UpdateLanguagesInternal( - const nsTArray& aLanguages) { - WorkerGlobalScope* globalScope = GlobalScope(); -diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index ae304f38e867c494f279179ac10a1c91b88c5f4e..841b93d297478b28787e134af82e88e1c8eeb5d4 100644 ---- a/dom/workers/WorkerPrivate.h -+++ b/dom/workers/WorkerPrivate.h -@@ -330,6 +330,8 @@ class WorkerPrivate final - void UpdateContextOptionsInternal(JSContext* aCx, - const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocaleInternal(JSContext* aCx); -+ - void UpdateLanguagesInternal(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -966,6 +968,8 @@ class WorkerPrivate final - - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocale(); -+ - void UpdateLanguages(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); -diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp -index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc440d9ace 100644 ---- a/intl/components/src/TimeZone.cpp -+++ b/intl/components/src/TimeZone.cpp -@@ -16,6 +16,7 @@ - - namespace mozilla::intl { - -+ - /* static */ - Result, ICUError> TimeZone::TryCreate( - Maybe> aTimeZoneOverride) { -@@ -239,6 +240,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { - } - #endif - -+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { -+ // Validate timezone id. -+ mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( -+ icu::UnicodeString(timeZoneId, -1, US_INV))); -+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); -+} -+ - Result TimeZone::SetDefaultTimeZone( - Span aTimeZone) { - #if MOZ_INTL_USE_ICU_CPP_TIMEZONE -diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc6894733168 100644 ---- a/intl/components/src/TimeZone.h -+++ b/intl/components/src/TimeZone.h -@@ -154,6 +154,8 @@ class TimeZone final { - return FillBufferWithICUCall(aBuffer, ucal_getHostTimeZone); - } - -+ static bool IsValidTimeZoneId(const char* timeZoneId); -+ - /** - * Set the default time zone. - */ -diff --git a/js/public/Date.h b/js/public/Date.h -index bb69d58dc96ed7f0b37f73e26abdd0bdfeaaf556..8436d439f72287176a2fe6a1a837d3db73409e67 100644 ---- a/js/public/Date.h -+++ b/js/public/Date.h -@@ -53,6 +53,8 @@ namespace JS { - */ - extern JS_PUBLIC_API void ResetTimeZone(); - -+extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId); -+ - class ClippedTime; - inline ClippedTime TimeClip(double time); - -diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp -index 1c00fed8e0dc84b12c9b1c169d841e27402579a1..ad25cb5f8a0572c9c8622f85551b79dd2ffea819 100644 ---- a/js/src/debugger/Object.cpp -+++ b/js/src/debugger/Object.cpp -@@ -2373,7 +2373,11 @@ Maybe DebuggerObject::call(JSContext* cx, - invokeArgs[i].set(args2[i]); - } - -+ // Disable CSP for the scope of the call. -+ const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx); -+ JS_SetSecurityCallbacks(cx, nullptr); - ok = js::Call(cx, calleev, thisv, invokeArgs, &result); -+ JS_SetSecurityCallbacks(cx, securityCallbacks); - } - } - -diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp -index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8eac31718cc 100644 ---- a/js/src/vm/DateTime.cpp -+++ b/js/src/vm/DateTime.cpp -@@ -178,6 +178,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { - } - } - -+void js::DateTimeInfo::internalSetTimeZoneOverride(std::string timeZone) { -+ timeZoneOverride_ = std::move(timeZone); -+ internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); -+} -+ - void js::DateTimeInfo::updateTimeZone() { - MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid); - -@@ -502,10 +507,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { - js::DateTimeInfo::resetTimeZone(mode); - } - -+void js::SetTimeZoneOverrideInternal(std::string timeZone) { -+ auto guard = js::DateTimeInfo::instance->lock(); -+ guard->internalSetTimeZoneOverride(timeZone); -+} -+ - JS_PUBLIC_API void JS::ResetTimeZone() { - js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); - } - -+JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) { -+ if (!mozilla::intl::TimeZone::IsValidTimeZoneId(timeZoneId)) { -+ fprintf(stderr, "Invalid timezone id: %s\n", timeZoneId); -+ return false; -+ } -+ js::SetTimeZoneOverrideInternal(std::string(timeZoneId)); -+ return true; -+} -+ - #if JS_HAS_INTL_API - # if defined(XP_WIN) - static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) { -@@ -727,9 +746,17 @@ void js::ResyncICUDefaultTimeZone() { - - void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - #if JS_HAS_INTL_API -+ if (!timeZoneOverride_.empty()) { -+ mozilla::Span tzid = mozilla::Span(timeZoneOverride_.data(), timeZoneOverride_.length()); -+ auto result = mozilla::intl::TimeZone::SetDefaultTimeZone(tzid); -+ if (result.isErr()) { -+ fprintf(stderr, "ERROR: failed to setup default time zone\n"); -+ } -+ return; -+ } -+ - if (const char* tzenv = std::getenv("TZ")) { - std::string_view tz(tzenv); -- - mozilla::Span tzid; - - # if defined(XP_WIN) -diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 3ce936fe3a4a83f9161eddc9e5289322d6a363e3..6b1c34244d8b2f2102ec423e2d96812fb5d41a9d 100644 ---- a/js/src/vm/DateTime.h -+++ b/js/src/vm/DateTime.h -@@ -63,6 +63,8 @@ enum class ResetTimeZoneMode : bool { - */ - extern void ResetTimeZoneInternal(ResetTimeZoneMode mode); - -+extern void SetTimeZoneOverrideInternal(std::string timeZone); -+ - /** - * ICU's default time zone, used for various date/time formatting operations - * that include the local time in the representation, is allowed to go stale -@@ -202,6 +204,7 @@ class DateTimeInfo { - // and js::ResyncICUDefaultTimeZone(). - friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); - friend void js::ResyncICUDefaultTimeZone(); -+ friend void js::SetTimeZoneOverrideInternal(std::string); - - static void resetTimeZone(ResetTimeZoneMode mode) { - auto guard = instance->lock(); -@@ -293,6 +296,8 @@ class DateTimeInfo { - JS::UniqueChars locale_; - JS::UniqueTwoByteChars standardName_; - JS::UniqueTwoByteChars daylightSavingsName_; -+ -+ std::string timeZoneOverride_; - #else - // Restrict the data-time range to the minimum required time_t range as - // specified in POSIX. Most operating systems support 64-bit time_t -@@ -308,6 +313,8 @@ class DateTimeInfo { - - void internalResetTimeZone(ResetTimeZoneMode mode); - -+ void internalSetTimeZoneOverride(std::string timeZone); -+ - void updateTimeZone(); - - void internalResyncICUDefaultTimeZone(); -diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index dac899f7558b26d6848da8b98ed8a93555c8751a..2a07d67fa1c2840b25085566e84dc3b2d9b789cf 100644 ---- a/layout/base/GeometryUtils.cpp -+++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ - #include "nsContentUtils.h" - #include "nsCSSFrameConstructor.h" - #include "nsLayoutUtils.h" -+#include "ChildIterator.h" - - using namespace mozilla; - using namespace mozilla::dom; -@@ -261,11 +262,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, - return false; - } - -+static nsIFrame* GetFrameForNode(nsINode* aNode, -+ bool aCreateFramesForSuppressedWhitespace, -+ bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aCreateFramesForSuppressedWhitespace); -+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { -+ dom::FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNode(child, aCreateFramesForSuppressedWhitespace, aRecurseWhenNoFrame); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ - void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray >& aResult, CallerType aCallerType, - ErrorResult& aRv) { - nsIFrame* frame = -- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); -+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -@@ -280,7 +297,7 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - // when that happens and re-check it. - if (!weakFrame.IsAlive()) { - frame = -- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); -+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 2b98de7670625e5f3e5312271c4cecc6fb71e0f4..b4100d6f5ec2586ff20ffa24a792d5c6c731ef4d 100644 ---- a/layout/base/PresShell.cpp -+++ b/layout/base/PresShell.cpp -@@ -10900,7 +10900,9 @@ auto PresShell::ComputeActiveness() const -> Activeness { - if (!browserChild->IsVisible()) { - MOZ_LOG(gLog, LogLevel::Debug, - (" > BrowserChild %p is not visible", browserChild)); -- return {false, inActiveTab}; -+ bool isActive; -+ root->GetDocShell()->GetForceActiveState(&isActive); -+ return {isActive, inActiveTab}; - } - - // If the browser is visible but just due to be preserving layers -diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index f055aacef5278e767beb3ee5588533961e148804..e1939bc19edc43f9127883cdd3dca981662baeec 100644 ---- a/layout/style/GeckoBindings.h -+++ b/layout/style/GeckoBindings.h -@@ -575,6 +575,7 @@ void Gecko_MediaFeatures_GetDeviceSize(const mozilla::dom::Document*, - - float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); -+bool Gecko_MediaFeatures_ForcedColors(const mozilla::dom::Document*); - mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( - const mozilla::dom::Document*); - mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( -diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index a9d3f075f3587fc1e55544b010864cd0e4b67107..d9ce4a1a7d9e2cd27e20f0ef36132e6599b0bb66 100644 ---- a/layout/style/nsMediaFeatures.cpp -+++ b/layout/style/nsMediaFeatures.cpp -@@ -264,10 +264,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { - } - - bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (nsContentUtils::ShouldResistFingerprinting(aDocument)) { -- return false; -- } -- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+ return aDocument->PrefersReducedMotion(); -+} -+ -+bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) { -+ return aDocument->ForcedColors(); - } - - StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( -diff --git a/media/libjpeg/jconfig.h b/media/libjpeg/jconfig.h -index f2723e654098ff27542e1eb16a536c11ad0af617..b0b480551ff7d895dfdeb5a9800874858929c8ba 100644 ---- a/media/libjpeg/jconfig.h -+++ b/media/libjpeg/jconfig.h -@@ -17,6 +17,7 @@ - /* #undef D_ARITH_CODING_SUPPORTED */ - - /* Support in-memory source/destination managers */ -+#define MEM_SRCDST_SUPPORTED 1 - /* #undef MEM_SRCDST_SUPPORTED */ - - /* Use accelerated SIMD routines. */ -diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js -index d609cbd2d139630d2c1dd85a82e946828aa14acc..0592eb6ca3312170ef2e86233aa4a2d12297ef55 100644 ---- a/modules/libpref/init/all.js -+++ b/modules/libpref/init/all.js -@@ -4357,7 +4357,9 @@ pref("devtools.experiment.f12.shortcut_disabled", false); - // doesn't provide a way to lock the pref - pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); - #else --pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false, locked); -+// Playwright: DO NOT make preference locked so that we can overwrite it -+// later in our playwright.cfg file. -+pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); - #endif - - // Whether to start the private browsing mode at application startup -diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index e869cd28d396aa87c522241d3e63d435ee8dbae6..2d307f089209721d88d231b03e8628890b8228ea 100644 ---- a/netwerk/base/nsINetworkInterceptController.idl -+++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -59,6 +59,7 @@ interface nsIInterceptedChannel : nsISupports - * results in the resulting client not being controlled. - */ - void resetInterception(in boolean bypass); -+ void resetInterceptionWithURI(in nsIURI aURI); - - /** - * Set the status and reason for the forthcoming synthesized response. -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index 23495ec9ffa1c6a237005e0cd160e27185717fab..086163719d3c720ba92cf04478f486ddaeeb965f 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.cpp -+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -662,6 +662,14 @@ void InterceptedHttpChannel::DoAsyncAbort(nsresult aStatus) { - Unused << AsyncAbort(aStatus); - } - -+NS_IMETHODIMP -+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { -+ if (aURI) { -+ mURI = aURI; -+ } -+ return ResetInterception(true); -+} -+ - NS_IMETHODIMP - InterceptedHttpChannel::ResetInterception(bool aBypass) { - if (mCanceled) { -diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index 55c7dbe1ae90d64e5aa993424cc1c5659833582f..a451248676b9b7cdd773a74948eb3b4d442a2b18 100644 ---- a/parser/html/nsHtml5TreeOpExecutor.cpp -+++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1363,6 +1363,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( - void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - -+ if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsresult rv = NS_OK; - nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); - if (!preloadCsp) { -diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 153722c33b9db6475aa5134ad5b665051ac68658..74324d95f7088c65c3d52ab2a7c40e89901d9512 100644 ---- a/security/manager/ssl/nsCertOverrideService.cpp -+++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -572,7 +572,12 @@ nsCertOverrideService::HasMatchingOverride( - bool disableAllSecurityCheck = false; - { - MutexAutoLock lock(mMutex); -- disableAllSecurityCheck = mDisableAllSecurityCheck; -+ if (aOriginAttributes.mUserContextId) { -+ disableAllSecurityCheck = mUserContextIdsWithDisabledSecurityChecks.has( -+ aOriginAttributes.mUserContextId); -+ } else { -+ disableAllSecurityCheck = mDisableAllSecurityCheck; -+ } - } - if (disableAllSecurityCheck) { - nsCertOverride::OverrideBits all = nsCertOverride::OverrideBits::Untrusted | -@@ -789,14 +794,24 @@ static bool IsDebugger() { - - NS_IMETHODIMP - nsCertOverrideService:: -- SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) { -- if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { -+ SetDisableAllSecurityChecksAndLetAttackersInterceptMyData( -+ bool aDisable, uint32_t aUserContextId) { -+ if (false /* juggler hacks */ && !(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { - return NS_ERROR_NOT_AVAILABLE; - } - - { - MutexAutoLock lock(mMutex); -- mDisableAllSecurityCheck = aDisable; -+ if (aUserContextId) { -+ if (aDisable) { -+ mozilla::Unused << mUserContextIdsWithDisabledSecurityChecks.put(aUserContextId); -+ } else { -+ mUserContextIdsWithDisabledSecurityChecks.remove(aUserContextId); -+ } -+ return NS_OK; -+ } else { -+ mDisableAllSecurityCheck = aDisable; -+ } - } - - nsCOMPtr nss(do_GetService(PSM_COMPONENT_CONTRACTID)); -diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h -index e22af55d6e94ceba502fabc775500228481e040c..8bbe25701332d6238afe9a31e6b3b83984debbab 100644 ---- a/security/manager/ssl/nsCertOverrideService.h -+++ b/security/manager/ssl/nsCertOverrideService.h -@@ -134,6 +134,7 @@ class nsCertOverrideService final : public nsICertOverrideService, - - mozilla::Mutex mMutex; - bool mDisableAllSecurityCheck MOZ_GUARDED_BY(mMutex); -+ mozilla::HashSet mUserContextIdsWithDisabledSecurityChecks MOZ_GUARDED_BY(mMutex); - nsCOMPtr mSettingsFile MOZ_GUARDED_BY(mMutex); - nsTHashtable mSettingsTable MOZ_GUARDED_BY(mMutex); - -diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl -index 3862fe6830874c036592fd217cab7ad5f4cd3e27..3166b37db0e52f7f2972d2bcb7a72ed819805794 100644 ---- a/security/manager/ssl/nsICertOverrideService.idl -+++ b/security/manager/ssl/nsICertOverrideService.idl -@@ -201,7 +201,9 @@ interface nsICertOverrideService : nsISupports { - * @param aDisable If true, disable all security check and make - * hasMatchingOverride always return true. - */ -- void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(in boolean aDisable); -+ void setDisableAllSecurityChecksAndLetAttackersInterceptMyData( -+ in boolean aDisable, -+ [optional] in uint32_t aUserContextId); - - readonly attribute boolean securityCheckDisabled; - }; -diff --git a/services/settings/Utils.jsm b/services/settings/Utils.jsm -index a8b0c67ce19d801d2f032d1b59110871a9859787..9d8d689bc4c4fb6aa00ff6c551cbab0dcda7d85d 100644 ---- a/services/settings/Utils.jsm -+++ b/services/settings/Utils.jsm -@@ -102,7 +102,7 @@ function _isUndefined(value) { - - var Utils = { - get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs -index 65faf3003964dec306c8d2f58cc2b921b54f8cb9..dd2a4b40d3a45240edca8b0f731e2aa2a5c12bdb 100644 ---- a/servo/components/style/gecko/media_features.rs -+++ b/servo/components/style/gecko/media_features.rs -@@ -224,10 +224,15 @@ pub enum ForcedColors { - - /// https://drafts.csswg.org/mediaqueries-5/#forced-colors - fn eval_forced_colors(context: &Context, query_value: Option) -> bool { -- let forced = !context.device().use_document_colors(); -+ let prefers_forced_colors = -+ unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) }; -+ let query_value = match query_value { -+ Some(v) => v, -+ None => return prefers_forced_colors, -+ }; - match query_value { -- Some(query_value) => forced == (query_value == ForcedColors::Active), -- None => forced, -+ ForcedColors::Active => prefers_forced_colors, -+ ForcedColors::None => !prefers_forced_colors, - } - } - -diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 4f7337926efbb086a2be97cdbcb3dca39e27c786..f2005cb726ff153d6b1011d6af0479dbf1af02a5 100644 ---- a/toolkit/components/browser/nsIWebBrowserChrome.idl -+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -70,6 +70,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 0x00200000; - -+ // Whether this window has "width" or "height" defined in features -+ const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000; -+ - // Prevents new window animations on MacOS and Windows. Currently - // ignored for Linux. - const unsigned long CHROME_SUPPRESS_ANIMATION = 0x01000000; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -index 4a152c642f5f763f953158ccb4ea59c7c32b66d7..21e4636abb017201e2e242069071f642501139f3 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -@@ -116,6 +116,12 @@ EnterprisePoliciesManager.prototype = { - Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); - } - -+ // Playwright: Disable enterprise policies -+ if (true) { -+ this.status = Ci.nsIEnterprisePolicies.INACTIVE; -+ return; -+ } -+ - let provider = this._chooseProvider(); - - if (provider.failed) { -diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index a76e612bc7149155305468307bebf0e69679897d..ba3c5dc0af69a34fcfbf04a3dbc506ef45833107 100644 ---- a/toolkit/components/startup/nsAppStartup.cpp -+++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -370,7 +370,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { - nsCOMPtr windowEnumerator; - nsCOMPtr mediator( - do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); -- if (mediator) { -+ if (ferocity != eForceQuit && mediator) { - mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator)); - if (windowEnumerator) { - bool more; -diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -index 3e9672fdfe9ddab8acd0f8b18772aece92bb3b64..83454a9c27c96d72597445653beaa014c38728cd 100644 ---- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -@@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress, - } - - NS_IMETHODIMP --nsBrowserStatusFilter::OnProgressChange(nsIWebProgress* aWebProgress, -- nsIRequest* aRequest, -+nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress, -+ nsIRequest *aRequest, - int32_t aCurSelfProgress, - int32_t aMaxSelfProgress, - int32_t aCurTotalProgress, -diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -index 3983d580cd11a8241481876aaf8a924f4f083ad0..0dd75bab6249a4db25dea3cabefd4f8e3744caad 100644 ---- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp -+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1815,7 +1815,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( - - // Open a minimal popup. - *aIsPopupRequested = true; -- return nsIWebBrowserChrome::CHROME_MINIMAL_POPUP; -+ uint32_t chromeFlags = 0; -+ if (aFeatures.Exists("width") || aFeatures.Exists("height")) { -+ chromeFlags |= nsIWebBrowserChrome::JUGGLER_WINDOW_EXPLICIT_SIZE; -+ } -+ return chromeFlags | nsIWebBrowserChrome::CHROME_MINIMAL_POPUP; - } - - /** -diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm -index f499fb84ce2cfd06d7e63b82294d72467339ef8c..c539b9075a6b5443f6d075b5836d9ebd931a3bd9 100644 ---- a/toolkit/mozapps/update/UpdateService.jsm -+++ b/toolkit/mozapps/update/UpdateService.jsm -@@ -3607,6 +3607,8 @@ UpdateService.prototype = { - }, - - get disabledForTesting() { -+ /* for playwright */ -+ return true; - return ( - (Cu.isInAutomation || - lazy.Marionette.running || -diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index 1241f1b0f94e0965b517898167ca1b52cfb48dc5..39c14eb7c548b81d564bd2a4ed15c70a920e173c 100644 ---- a/toolkit/toolkit.mozbuild -+++ b/toolkit/toolkit.mozbuild -@@ -154,6 +154,7 @@ if CONFIG['ENABLE_WEBDRIVER']: - '/remote', - '/testing/firefox-ui', - '/testing/marionette', -+ '/juggler', - '/toolkit/components/telemetry/tests/marionette', - ] - -diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp -index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..f993e78e02563cada8c131be3d4658bc8f7532b6 100644 ---- a/toolkit/xre/nsWindowsWMain.cpp -+++ b/toolkit/xre/nsWindowsWMain.cpp -@@ -14,9 +14,11 @@ - #endif - - #include "mozilla/Char16.h" -+#include "mozilla/CmdLineAndEnvUtils.h" - #include "nsUTF8Utils.h" - #include "nsWindowsHelpers.h" - -+#include - #include - #include - -@@ -130,6 +132,20 @@ int wmain(int argc, WCHAR** argv) { - - SanitizeEnvironmentVariables(); - SetDllDirectoryW(L""); -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, L"juggler-pipe", -+ static_cast(nullptr), -+ mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; -+ if (hasJugglerPipe && !mozilla::EnvHasValue("PW_PIPE_READ")) { -+ intptr_t stdio3 = _get_osfhandle(3); -+ intptr_t stdio4 = _get_osfhandle(4); -+ CHAR stdio3str[20]; -+ CHAR stdio4str[20]; -+ itoa(stdio3, stdio3str, 10); -+ itoa(stdio4, stdio4str, 10); -+ SetEnvironmentVariableA("PW_PIPE_READ", stdio3str); -+ SetEnvironmentVariableA("PW_PIPE_WRITE", stdio4str); -+ } - - // Only run this code if LauncherProcessWin.h was included beforehand, thus - // signalling that the hosting process should support launcher mode. -diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp -index 9ca3975c99c8bff3829bce1cf49d1235910c3ab8..6606eb02fba53ea8bd401d07460b85b068abd2bd 100644 ---- a/uriloader/base/nsDocLoader.cpp -+++ b/uriloader/base/nsDocLoader.cpp -@@ -827,6 +827,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, - ("DocLoader:%p: Firing load event for document.open\n", - this)); - -+ nsCOMPtr os = mozilla::services::GetObserverService(); -+ if (os) { -+ nsIPrincipal* principal = doc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) -+ os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr); -+ } -+ - // This is a very cut-down version of - // nsDocumentViewer::LoadComplete that doesn't do various things - // that are not relevant here because this wasn't an actual -diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp -index 9abeebcb9e137186b62c7eff02ac8ca2848f5f20..3855b6ed82d8a87f5798525152bcf42c124bcc9f 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.cpp -+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -113,6 +113,7 @@ - - #include "mozilla/Components.h" - #include "mozilla/ClearOnShutdown.h" -+#include "mozilla/ErrorNames.h" - #include "mozilla/Preferences.h" - #include "mozilla/ipc/URIUtils.h" - -@@ -838,6 +839,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( - return NS_OK; - } - -+NS_IMETHODIMP nsExternalHelperAppService::SetDownloadInterceptor( -+ nsIDownloadInterceptor* interceptor) { -+ mInterceptor = interceptor; -+ return NS_OK; -+} -+ - nsresult nsExternalHelperAppService::GetFileTokenForPath( - const char16_t* aPlatformAppPath, nsIFile** aFile) { - nsDependentString platformAppPath(aPlatformAppPath); -@@ -1448,7 +1455,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { - // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1); - -+ return CreateSaverForTempFile(); -+} -+ -+nsresult nsExternalAppHandler::CreateSaverForTempFile() { - MOZ_ASSERT(!mSaver, "Output file initialization called more than once!"); -+ nsresult rv; - mSaver = - do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); -@@ -1639,7 +1651,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - return NS_OK; - } - -- rv = SetUpTempFile(aChannel); -+ bool isIntercepted = false; -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCOMPtr fileToUse; -+ rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted); -+ if (!NS_SUCCEEDED(rv)) { -+ LOG((" failed to call nsIDowloadInterceptor.interceptDownloadRequest")); -+ return rv; -+ } -+ if (isIntercepted) { -+ LOG((" request interceped by nsIDowloadInterceptor")); -+ if (fileToUse) { -+ mTempFile = fileToUse; -+ rv = mTempFile->GetLeafName(mTempLeafName); -+ NS_ENSURE_SUCCESS(rv, rv); -+ } else { -+ Cancel(NS_BINDING_ABORTED); -+ return NS_OK; -+ } -+ } -+ } -+ -+ // Temp file is the final destination when download is intercepted. In that -+ // case we only need to create saver (and not create transfer later). Not creating -+ // mTransfer also cuts off all downloads handling logic in the js compoenents and -+ // browser UI. -+ if (isIntercepted) -+ rv = CreateSaverForTempFile(); -+ else -+ rv = SetUpTempFile(aChannel); - if (NS_FAILED(rv)) { - nsresult transferError = rv; - -@@ -1693,6 +1734,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - - bool alwaysAsk = true; - mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); -+ if (isIntercepted) { -+ return NS_OK; -+ } - if (alwaysAsk) { - // But we *don't* ask if this mimeInfo didn't come from - // our user configuration datastore and the user has said -@@ -2259,6 +2303,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, - NotifyTransfer(aStatus); - } - -+ if (!mCanceled) { -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCString noError; -+ nsresult rv = interceptor->OnDownloadComplete(this, noError); -+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete"); -+ Unused << rv; -+ } -+ } -+ - return NS_OK; - } - -@@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { - } - } - -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCString errorName; -+ GetErrorName(aReason, errorName); -+ nsresult rv = interceptor->OnDownloadComplete(this, errorName); -+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel"); -+ Unused << rv; -+ } -+ - // Break our reference cycle with the helper app dialog (set up in - // OnStartRequest) - mDialog = nullptr; -diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h -index 2a1d67ffe2650d0d5f3e00bcb7f23deee8e76d0f..9e9731bc18de04fef382d0951a03793d83d14e14 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.h -+++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -244,6 +244,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, - mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, - nsIInterfaceRequestor* aWindowContext, - nsIStreamListener** aStreamListener); -+ -+ nsCOMPtr mInterceptor; - }; - - /** -@@ -446,6 +448,9 @@ class nsExternalAppHandler final : public nsIStreamListener, - * Upon successful return, both mTempFile and mSaver will be valid. - */ - nsresult SetUpTempFile(nsIChannel* aChannel); -+ -+ nsresult CreateSaverForTempFile(); -+ - /** - * When we download a helper app, we are going to retarget all load - * notifications into our own docloader and load group instead of -diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl -index 307e6196a89df52d0bccc3ebd1359f58e32de75d..c3692d0f76178ac3aeb1c77a0e973bfa22359346 100644 ---- a/uriloader/exthandler/nsIExternalHelperAppService.idl -+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,6 +6,8 @@ - - #include "nsICancelable.idl" - -+webidl BrowsingContext; -+interface nsIHelperAppLauncher; - interface nsIURI; - interface nsIRequest; - interface nsIStreamListener; -@@ -15,6 +17,17 @@ interface nsIWebProgressListener2; - interface nsIInterfaceRequestor; - webidl BrowsingContext; - -+/** -+ * Interceptor interface used by Juggler. -+ */ -+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] -+interface nsIDownloadInterceptor : nsISupports -+{ -+ bool interceptDownloadRequest(in nsIHelperAppLauncher aHandler, in nsIRequest aRequest, in BrowsingContext aBrowsingContext, out nsIFile file); -+ -+ void onDownloadComplete(in nsIHelperAppLauncher aHandler, in ACString aErrorName); -+}; -+ - /** - * The external helper app service is used for finding and launching - * platform specific external applications for a given mime content type. -@@ -76,6 +89,7 @@ interface nsIExternalHelperAppService : nsISupports - boolean applyDecodingForExtension(in AUTF8String aExtension, - in ACString aEncodingType); - -+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); - }; - - /** -diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp -index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9896abd1c 100644 ---- a/widget/InProcessCompositorWidget.cpp -+++ b/widget/InProcessCompositorWidget.cpp -@@ -4,7 +4,10 @@ - - #include "InProcessCompositorWidget.h" - -+#include "HeadlessCompositorWidget.h" -+#include "HeadlessWidget.h" - #include "mozilla/VsyncDispatcher.h" -+#include "mozilla/widget/PlatformWidgetTypes.h" - #include "nsBaseWidget.h" - - namespace mozilla { -@@ -23,6 +26,12 @@ RefPtr CompositorWidget::CreateLocal( - // do it after the static_cast. - nsBaseWidget* widget = static_cast(aWidget); - MOZ_RELEASE_ASSERT(widget); -+ if (aInitData.type() == -+ CompositorWidgetInitData::THeadlessCompositorWidgetInitData) { -+ return new HeadlessCompositorWidget( -+ aInitData.get_HeadlessCompositorWidgetInitData(), aOptions, -+ static_cast(aWidget)); -+ } - return new InProcessCompositorWidget(aOptions, widget); - } - #endif -diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644 ---- a/widget/cocoa/NativeKeyBindings.mm -+++ b/widget/cocoa/NativeKeyBindings.mm -@@ -492,6 +492,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowLeft: - if (aEvent.IsAlt()) { -+ if (aEvent.IsMeta() || aEvent.IsControl()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ !aEvent.IsShift() -+ ? ToObjcSelectorPtr(@selector(moveWordLeft:)) -+ : ToObjcSelectorPtr(@selector(moveWordLeftAndModifySelection:)), -+ aCommands); - break; - } - if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -512,6 +519,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowRight: - if (aEvent.IsAlt()) { -+ if (aEvent.IsMeta() || aEvent.IsControl()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ !aEvent.IsShift() -+ ? ToObjcSelectorPtr(@selector(moveWordRight:)) -+ : ToObjcSelectorPtr(@selector(moveWordRightAndModifySelection:)), -+ aCommands); - break; - } - if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -532,6 +546,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowUp: - if (aEvent.IsControl()) { -+ if (aEvent.IsMeta() || aEvent.IsAlt()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ ToObjcSelectorPtr(@selector(scrollPageUp:)), aCommands); - break; - } - if (aEvent.IsMeta()) { -@@ -541,7 +559,7 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - instance->AppendEditCommandsForSelector( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) -- : ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)), -+ : ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -564,6 +582,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowDown: - if (aEvent.IsControl()) { -+ if (aEvent.IsMeta() || aEvent.IsAlt()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ ToObjcSelectorPtr(@selector(scrollPageDown:)), aCommands); - break; - } - if (aEvent.IsMeta()) { -diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6dfcbc2ab 100644 ---- a/widget/headless/HeadlessCompositorWidget.cpp -+++ b/widget/headless/HeadlessCompositorWidget.cpp -@@ -3,6 +3,7 @@ - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -+#include "mozilla/layers/CompositorThread.h" - #include "mozilla/widget/PlatformWidgetTypes.h" - #include "HeadlessCompositorWidget.h" - #include "VsyncDispatcher.h" -@@ -13,10 +14,32 @@ namespace widget { - HeadlessCompositorWidget::HeadlessCompositorWidget( - const HeadlessCompositorWidgetInitData& aInitData, - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) -- : CompositorWidget(aOptions), mWidget(aWindow) { -+ : CompositorWidget(aOptions), mWidget(aWindow), mMon("snapshotListener") { - mClientSize = aInitData.InitialClientSize(); - } - -+void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) { -+ MOZ_ASSERT(NS_IsMainThread()); -+ -+ ReentrantMonitorAutoEnter lock(mMon); -+ mSnapshotListener = std::move(listener); -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::PeriodicSnapshot", this, -+ &HeadlessCompositorWidget::PeriodicSnapshot -+ )); -+} -+ -+already_AddRefed HeadlessCompositorWidget::StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion, -+ layers::BufferMode* aBufferMode) { -+ if (!mDrawTarget) -+ return nullptr; -+ -+ *aBufferMode = layers::BufferMode::BUFFER_NONE; -+ RefPtr result = mDrawTarget; -+ return result.forget(); -+} -+ - void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -29,6 +52,59 @@ nsIWidget* HeadlessCompositorWidget::RealWidget() { return mWidget; } - void HeadlessCompositorWidget::NotifyClientSizeChanged( - const LayoutDeviceIntSize& aClientSize) { - mClientSize = aClientSize; -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::UpdateDrawTarget", this, -+ &HeadlessCompositorWidget::UpdateDrawTarget, -+ aClientSize)); -+} -+ -+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { -+ MOZ_ASSERT(NS_IsInCompositorThread()); -+ if (aClientSize.IsEmpty()) { -+ mDrawTarget = nullptr; -+ return; -+ } -+ -+ RefPtr old = std::move(mDrawTarget); -+ gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; -+ gfx::IntSize size = aClientSize.ToUnknownSize(); -+ mDrawTarget = mozilla::gfx::Factory::CreateDrawTarget( -+ mozilla::gfx::BackendType::SKIA, size, format); -+ if (old) { -+ RefPtr snapshot = old->Snapshot(); -+ if (snapshot) -+ mDrawTarget->CopySurface(snapshot.get(), old->GetRect(), gfx::IntPoint(0, 0)); -+ } -+} -+ -+void HeadlessCompositorWidget::PeriodicSnapshot() { -+ ReentrantMonitorAutoEnter lock(mMon); -+ if (!mSnapshotListener) -+ return; -+ -+ TakeSnapshot(); -+ NS_DelayedDispatchToCurrentThread(NewRunnableMethod( -+ "HeadlessCompositorWidget::PeriodicSnapshot", this, -+ &HeadlessCompositorWidget::PeriodicSnapshot), 40); -+} -+ -+void HeadlessCompositorWidget::TakeSnapshot() { -+ if (!mDrawTarget) -+ return; -+ -+ RefPtr snapshot = mDrawTarget->Snapshot(); -+ if (!snapshot) { -+ fprintf(stderr, "Failed to get snapshot of draw target\n"); -+ return; -+ } -+ -+ RefPtr dataSurface = snapshot->GetDataSurface(); -+ if (!dataSurface) { -+ fprintf(stderr, "Failed to get data surface from snapshot\n"); -+ return; -+ } -+ -+ mSnapshotListener(std::move(dataSurface)); - } - - LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() { -diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h -index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e65c24835 100644 ---- a/widget/headless/HeadlessCompositorWidget.h -+++ b/widget/headless/HeadlessCompositorWidget.h -@@ -6,6 +6,7 @@ - #ifndef widget_headless_HeadlessCompositorWidget_h - #define widget_headless_HeadlessCompositorWidget_h - -+#include "mozilla/ReentrantMonitor.h" - #include "mozilla/widget/CompositorWidget.h" - - #include "HeadlessWidget.h" -@@ -23,8 +24,12 @@ class HeadlessCompositorWidget final : public CompositorWidget, - HeadlessWidget* aWindow); - - void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); -+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); - - // CompositorWidget Overrides -+ already_AddRefed StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion, -+ layers::BufferMode* aBufferMode) override; - - uintptr_t GetWidgetKey() override; - -@@ -42,9 +47,17 @@ class HeadlessCompositorWidget final : public CompositorWidget, - } - - private: -+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); -+ void PeriodicSnapshot(); -+ void TakeSnapshot(); -+ - HeadlessWidget* mWidget; -+ mozilla::ReentrantMonitor mMon; - - LayoutDeviceIntSize mClientSize; -+ -+ HeadlessWidget::SnapshotListener mSnapshotListener; -+ RefPtr mDrawTarget; - }; - - } // namespace widget -diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index c1fbcccc93d9a6876aa82893cdf9c09b72087751..7a8073e3b746aec3a894957e87975189c06782d3 100644 ---- a/widget/headless/HeadlessWidget.cpp -+++ b/widget/headless/HeadlessWidget.cpp -@@ -109,6 +109,8 @@ void HeadlessWidget::Destroy() { - } - } - -+ SetSnapshotListener(nullptr); -+ - nsBaseWidget::OnDestroy(); - - nsBaseWidget::Destroy(); -@@ -564,5 +566,15 @@ nsresult HeadlessWidget::SynthesizeNativeTouchPadPinch( - DispatchPinchGestureInput(inputToDispatch); - return NS_OK; - } -+ -+void HeadlessWidget::SetSnapshotListener(SnapshotListener&& listener) { -+ if (!mCompositorWidget) { -+ if (listener) -+ fprintf(stderr, "Trying to set SnapshotListener without compositor widget\n"); -+ return; -+ } -+ mCompositorWidget->SetSnapshotListener(std::move(listener)); -+} -+ - } // namespace widget - } // namespace mozilla -diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h -index 2b80eea70e58dd53c34edd9c5fa4415c42bcd632..72ecda7d8ddc7a9f87a954b547f8411e67ef1570 100644 ---- a/widget/headless/HeadlessWidget.h -+++ b/widget/headless/HeadlessWidget.h -@@ -135,6 +135,9 @@ class HeadlessWidget : public nsBaseWidget { - TouchpadGesturePhase aEventPhase, float aScale, - LayoutDeviceIntPoint aPoint, int32_t aModifierFlags) override; - -+ using SnapshotListener = std::function&&)>; -+ void SetSnapshotListener(SnapshotListener&& listener); -+ - private: - ~HeadlessWidget(); - bool mEnabled; -diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 2456c2c2b58b27cd595880b547ed20fb687a1835..e967c089b2331c7cd36d34e511543fbc84320b7d 100644 ---- a/xpcom/reflect/xptinfo/xptinfo.h -+++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -514,7 +514,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size"); - #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) - # define PARAM_BUFFER_COUNT 18 - #else --# define PARAM_BUFFER_COUNT 14 -+# define PARAM_BUFFER_COUNT 15 - #endif - - /** diff --git a/browser_patches/firefox-beta/preferences/00-playwright-prefs.js b/browser_patches/firefox-beta/preferences/00-playwright-prefs.js deleted file mode 100644 index 1895d2d1b7..0000000000 --- a/browser_patches/firefox-beta/preferences/00-playwright-prefs.js +++ /dev/null @@ -1,3 +0,0 @@ -// Any comment. You must start the file with a single-line comment! -pref("general.config.filename", "playwright.cfg"); -pref("general.config.obscure_value", 0); diff --git a/browser_patches/firefox-beta/preferences/playwright.cfg b/browser_patches/firefox-beta/preferences/playwright.cfg deleted file mode 100644 index f58a6d10d4..0000000000 --- a/browser_patches/firefox-beta/preferences/playwright.cfg +++ /dev/null @@ -1,291 +0,0 @@ -// Any comment. You must start the file with a comment! - -// ================================================================= -// THESE ARE THE PROPERTIES THAT MUST BE ENABLED FOR JUGGLER TO WORK -// ================================================================= - -pref("datareporting.policy.dataSubmissionEnabled", false); -pref("datareporting.policy.dataSubmissionPolicyAccepted", false); -pref("datareporting.policy.dataSubmissionPolicyBypassNotification", true); - -// @see https://github.com/microsoft/playwright/issues/4297 -pref("browser.tabs.remote.useCrossOriginEmbedderPolicy", false); -pref("browser.tabs.remote.useCrossOriginOpenerPolicy", false); - -pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false); - -pref("pdfjs.disabled", true); - -// Disable all kinds of cross-process navigations until we are ready. -pref("fission.autostart", false); -pref("fission.webContentIsolationStrategy", 0); -pref("fission.bfcacheInParent", false); -// Avoid about:blank loading cross-process until we are ready. -pref("browser.tabs.remote.systemTriggeredAboutBlankAnywhere", true); - -// ================================================================= -// ================================================================= - -// @see https://github.com/microsoft/playwright/issues/8178 -pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true); - -// Use light theme by default. -pref("ui.systemUsesDarkTheme", 0); - -// Only allow the old modal dialogs. This should be removed when there is -// support for the new modal UI (see Bug 1686743). -pref("prompts.contentPromptSubDialog", false); - -// Increase max number of child web processes so that new pages -// get a new process by default and we have a process isolation -// between pages from different contexts. If this becomes a performance -// issue we can povide custom '@mozilla.org/ipc/processselector;1' -// -pref("dom.ipc.processCount", 60000); - -// Never reuse processes as they may keep previously overridden values -// (locale, timezone etc.). -pref("dom.ipc.processPrelaunch.enabled", false); - -// Do not use system colors - they are affected by themes. -pref("ui.use_standins_for_native_colors", true); - -// Isolate permissions by user context. -pref("permissions.isolateBy.userContext", true); - -pref("dom.push.serverURL", ""); -// This setting breaks settings loading. -pref("services.settings.server", ""); -pref("browser.safebrowsing.provider.mozilla.updateURL", ""); -pref("browser.library.activity-stream.enabled", false); -pref("browser.search.geoSpecificDefaults", false); -pref("browser.search.geoSpecificDefaults.url", ""); -pref("captivedetect.canonicalURL", ""); -pref("network.captive-portal-service.enabled", false); -pref("network.connectivity-service.enabled", false); -pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", ""); - -// Make sure Shield doesn't hit the network. -pref("app.normandy.api_url", ""); -pref("app.normandy.enabled", false); - -// Disable updater -pref("app.update.enabled", false); -// Disable Firefox old build background check -pref("app.update.checkInstallTime", false); -// Disable automatically upgrading Firefox -pref("app.update.disabledForTesting", true); - -// make absolutely sure it is really off -pref("app.update.auto", false); -pref("app.update.mode", 0); -pref("app.update.service.enabled", false); -// Dislabe newtabpage -pref("browser.startup.homepage", "about:blank"); -pref("browser.startup.page", 0); -pref("browser.newtabpage.enabled", false); -// Do not redirect user when a milstone upgrade of Firefox is detected -pref("browser.startup.homepage_override.mstone", "ignore"); - -pref("browser.tabs.remote.separateFileUriProcess", false); -pref("security.sandbox.content.level", 2); - -// Disable topstories -pref("browser.newtabpage.activity-stream.feeds.section.topstories", false); -// DevTools JSONViewer sometimes fails to load dependencies with its require.js. -// This doesn't affect Puppeteer operations, but spams console with a lot of -// unpleasant errors. -// (bug 1424372) -pref("devtools.jsonview.enabled", false); - -// Increase the APZ content response timeout in tests to 1 minute. -// This is to accommodate the fact that test environments tends to be -// slower than production environments (with the b2g emulator being -// the slowest of them all), resulting in the production timeout value -// sometimes being exceeded and causing false-positive test failures. -// -// (bug 1176798, bug 1177018, bug 1210465) -pref("apz.content_response_timeout", 60000); - -// Allow creating files in content process - required for -// |Page.setFileInputFiles| protocol method. -pref("dom.file.createInChild", true); - -// Indicate that the download panel has been shown once so that -// whichever download test runs first doesn't show the popup -// inconsistently. -pref("browser.download.panel.shown", true); -// Background thumbnails in particular cause grief, and disabling -// thumbnails in general cannot hurt -pref("browser.pagethumbnails.capturing_disabled", true); -// Disable safebrowsing components. -pref("browser.safebrowsing.blockedURIs.enabled", false); -pref("browser.safebrowsing.downloads.enabled", false); -pref("browser.safebrowsing.passwords.enabled", false); -pref("browser.safebrowsing.malware.enabled", false); -pref("browser.safebrowsing.phishing.enabled", false); -// Disable updates to search engines. -pref("browser.search.update", false); -// Do not restore the last open set of tabs if the browser has crashed -pref("browser.sessionstore.resume_from_crash", false); -// Don't check for the default web browser during startup. -pref("browser.shell.checkDefaultBrowser", false); - -// Disable browser animations (tabs, fullscreen, sliding alerts) -pref("toolkit.cosmeticAnimations.enabled", false); - -// Close the window when the last tab gets closed -pref("browser.tabs.closeWindowWithLastTab", true); - -// Do not allow background tabs to be zombified on Android, otherwise for -// tests that open additional tabs, the test harness tab itself might get -// unloaded -pref("browser.tabs.disableBackgroundZombification", false); - -// Do not warn when closing all open tabs -pref("browser.tabs.warnOnClose", false); - -// Do not warn when closing all other open tabs -pref("browser.tabs.warnOnCloseOtherTabs", false); - -// Do not warn when multiple tabs will be opened -pref("browser.tabs.warnOnOpen", false); - -// Disable first run splash page on Windows 10 -pref("browser.usedOnWindows10.introURL", ""); - -// Disable the UI tour. -// -// Should be set in profile. -pref("browser.uitour.enabled", false); - -// Turn off search suggestions in the location bar so as not to trigger -// network connections. -pref("browser.urlbar.suggest.searches", false); - -// Do not warn on quitting Firefox -pref("browser.warnOnQuit", false); - -// Do not show datareporting policy notifications which can -// interfere with tests -pref("datareporting.healthreport.documentServerURI", ""); -pref("datareporting.healthreport.about.reportUrl", ""); -pref("datareporting.healthreport.logging.consoleEnabled", false); -pref("datareporting.healthreport.service.enabled", false); -pref("datareporting.healthreport.service.firstRun", false); -pref("datareporting.healthreport.uploadEnabled", false); - -// Automatically unload beforeunload alerts -pref("dom.disable_beforeunload", false); - -// Disable popup-blocker -pref("dom.disable_open_during_load", false); - -// Disable the ProcessHangMonitor -pref("dom.ipc.reportProcessHangs", false); -pref("hangmonitor.timeout", 0); - -// Disable slow script dialogues -pref("dom.max_chrome_script_run_time", 0); -pref("dom.max_script_run_time", 0); - -// Only load extensions from the application and user profile -// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION -pref("extensions.autoDisableScopes", 0); -pref("extensions.enabledScopes", 5); - -// Disable metadata caching for installed add-ons by default -pref("extensions.getAddons.cache.enabled", false); - -// Disable installing any distribution extensions or add-ons. -pref("extensions.installDistroAddons", false); - -// Turn off extension updates so they do not bother tests -pref("extensions.update.enabled", false); -pref("extensions.update.notifyUser", false); - -// Make sure opening about:addons will not hit the network -pref("extensions.webservice.discoverURL", ""); - -pref("extensions.screenshots.disabled", true); -pref("extensions.screenshots.upload-disabled", true); - -// Allow the application to have focus even it runs in the background -pref("focusmanager.testmode", true); - -// Disable useragent updates -pref("general.useragent.updates.enabled", false); - -// No ICC color correction. -// See https://developer.mozilla.org/en/docs/Mozilla/Firefox/Releases/3.5/ICC_color_correction_in_Firefox. -pref("gfx.color_management.mode", 0); -pref("gfx.color_management.rendering_intent", 3); - -// Always use network provider for geolocation tests so we bypass the -// macOS dialog raised by the corelocation provider -pref("geo.provider.testing", true); - -// Do not scan Wifi -pref("geo.wifi.scan", false); - -// Show chrome errors and warnings in the error console -pref("javascript.options.showInConsole", true); - -// Disable download and usage of OpenH264: and Widevine plugins -pref("media.gmp-manager.updateEnabled", false); - -// Do not prompt with long usernames or passwords in URLs -pref("network.http.phishy-userpass-length", 255); - -// Do not prompt for temporary redirects -pref("network.http.prompt-temp-redirect", false); - -// Disable speculative connections so they are not reported as leaking -// when they are hanging around -pref("network.http.speculative-parallel-limit", 0); - -// Do not automatically switch between offline and online -pref("network.manage-offline-status", false); - -// Make sure SNTP requests do not hit the network -pref("network.sntp.pools", ""); - -// Disable Flash -pref("plugin.state.flash", 0); - -pref("privacy.trackingprotection.enabled", false); - -pref("security.certerrors.mitm.priming.enabled", false); - -// Local documents have access to all other local documents, -// including directory listings -pref("security.fileuri.strict_origin_policy", false); - -// Tests do not wait for the notification button security delay -pref("security.notification_enable_delay", 0); - -// Do not automatically fill sign-in forms with known usernames and -// passwords -pref("signon.autofillForms", false); - -// Disable password capture, so that tests that include forms are not -// influenced by the presence of the persistent doorhanger notification -pref("signon.rememberSignons", false); - -// Disable first-run welcome page -pref("startup.homepage_welcome_url", "about:blank"); -pref("startup.homepage_welcome_url.additional", ""); - -// Prevent starting into safe mode after application crashes -pref("toolkit.startup.max_resumed_crashes", -1); -lockPref("toolkit.crashreporter.enabled", false); - -pref("toolkit.telemetry.enabled", false); -pref("toolkit.telemetry.server", ""); - -// Disable downloading the list of blocked extensions. -pref("extensions.blocklist.enabled", false); - -// Force Firefox Devtools to open in a separate window. -pref("devtools.toolbox.host", "window"); - diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER deleted file mode 100644 index ab77a54ced..0000000000 --- a/browser_patches/firefox/BUILD_NUMBER +++ /dev/null @@ -1,2 +0,0 @@ -1347 -Changed: lushnikov@chromium.org Tue 23 Aug 2022 03:05:32 PM PDT diff --git a/browser_patches/firefox/EXPECTED_BUILDS b/browser_patches/firefox/EXPECTED_BUILDS deleted file mode 100644 index d2bf4c2ace..0000000000 --- a/browser_patches/firefox/EXPECTED_BUILDS +++ /dev/null @@ -1,9 +0,0 @@ -firefox-mac-11.zip -firefox-mac-11-arm64.zip -firefox-ubuntu-18.04.zip -firefox-ubuntu-20.04.zip -firefox-ubuntu-20.04-arm64.zip -firefox-ubuntu-22.04.zip -firefox-ubuntu-22.04-arm64.zip -firefox-debian-11.zip -firefox-win64.zip diff --git a/browser_patches/firefox/archive.sh b/browser_patches/firefox/archive.sh deleted file mode 100755 index 1c34d8fb06..0000000000 --- a/browser_patches/firefox/archive.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -e -set +x - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename "$0") [output-absolute-path]" - echo - echo "Generate distributable .zip archive from Firefox checkout folder that was previously built." - echo - exit 0 -fi - -ZIP_PATH=$1 -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname "$ZIP_PATH") ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FF_CHECKOUT_PATH="$HOME/firefox" -fi -OBJ_FOLDER="${FF_CHECKOUT_PATH}/obj-build-playwright" - -cd "${FF_CHECKOUT_PATH}" - -export MH_BRANCH=mozilla-release -export MOZ_BUILD_DATE=$(date +%Y%m%d%H%M%S) -./mach package -node "${SCRIPT_FOLDER}/install-preferences.js" "${OBJ_FOLDER}/dist/firefox" - -if ! [[ -d "$OBJ_FOLDER/dist/firefox" ]]; then - echo "ERROR: cannot find $OBJ_FOLDER/dist/firefox folder in the firefox checkout. Did you build?" - exit 1; -fi - -if is_win; then - # Bundle vcruntime14_1.dll - see https://github.com/microsoft/playwright/issues/9974 - cd "$(printMSVCRedistDir)" - cp -t "${OBJ_FOLDER}/dist/firefox" vcruntime140_1.dll -fi - -# tar resulting directory and cleanup TMP. -cd "${OBJ_FOLDER}/dist" -zip -r "$ZIP_PATH" firefox diff --git a/browser_patches/firefox/build.sh b/browser_patches/firefox/build.sh deleted file mode 100755 index 860ceb68e8..0000000000 --- a/browser_patches/firefox/build.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash -set -e -set +x - -RUST_VERSION="1.61.0" -CBINDGEN_VERSION="0.24.3" - -trap "cd $(pwd -P)" EXIT - -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -args=("$@") -IS_FULL="" -IS_JUGGLER="" -IS_DEBUG="" -for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --full) IS_FULL="1"; unset args[i]; ;; - --juggler) IS_JUGGLER="1"; unset args[i]; ;; - --debug) IS_DEBUG="1"; unset args[i]; ;; - esac -done - -if [[ -n "${IS_JUGGLER}" && -n "${IS_FULL}" ]]; then - echo "ERROR: either --full or --juggler is allowed" - exit 1 -fi - -echo "== BUILD CONFIGURATION ==" -if [[ -n "${IS_FULL}" ]]; then - echo "- build type: FULL" -elif [[ -n "${IS_JUGGLER}" ]]; then - echo "- build type: JUGGLER" -else - echo "- build type: INCREMENTAL" -fi - -if [[ -n "${IS_DEBUG}" ]]; then - echo "- debug: YES" -else - echo "- debug: NO" -fi - -echo "=========================" - -rm -rf .mozconfig - -if is_mac; then - selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" firefox) - echo "-- building on Mac" -elif is_linux; then - echo "-- building on Linux" -elif is_win; then - echo "ac_add_options --disable-update-agent" >> .mozconfig - echo "ac_add_options --disable-default-browser-agent" >> .mozconfig - echo "ac_add_options --disable-maintenance-service" >> .mozconfig - - echo "-- building win64 build on MINGW" - echo "ac_add_options --target=x86_64-pc-mingw32" >> .mozconfig - echo "ac_add_options --host=x86_64-pc-mingw32" >> .mozconfig - DLL_FILE=$("C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -find '**\Redist\MSVC\*\x64\**\vcruntime140.dll') - WIN32_REDIST_DIR=$(dirname "$DLL_FILE" | tail -n 1) - if ! [[ -d $WIN32_REDIST_DIR ]]; then - echo "ERROR: cannot find MS VS C++ redistributable $WIN32_REDIST_DIR" - exit 1; - fi -else - echo "ERROR: cannot upload on this platform!" 1>&2 - exit 1; -fi - -# There's no pre-built wasi sysroot on certain platforms. -echo "ac_add_options --without-wasm-sandboxed-libraries" >> .mozconfig - -OBJ_FOLDER="obj-build-playwright" -echo "mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/${OBJ_FOLDER}" >> .mozconfig -echo "ac_add_options --disable-crashreporter" >> .mozconfig -echo "ac_add_options --disable-backgroundtasks" >> .mozconfig - -if [[ -n "${IS_DEBUG}" ]]; then - echo "ac_add_options --enable-debug" >> .mozconfig - echo "ac_add_options --enable-debug-symbols" >> .mozconfig -else - echo "ac_add_options --enable-release" >> .mozconfig -fi - -if is_mac || is_win; then - # This options is only available on win and mac. - echo "ac_add_options --disable-update-agent" >> .mozconfig -fi - -if [[ -z "${IS_JUGGLER}" ]]; then - # TODO: rustup is not in the PATH on Windows - if command -v rustup >/dev/null; then - # We manage Rust version ourselves. - echo "-- Using rust v${RUST_VERSION}" - rustup install "${RUST_VERSION}" - rustup default "${RUST_VERSION}" - fi - # Firefox on Linux arm64 host does not ship - # cbindgen in their default toolchains - install manually. - if command -v cargo >/dev/null; then - echo "-- Using cbindgen v${CBINDGEN_VERSION}" - cargo install cbindgen --version "${CBINDGEN_VERSION}" - fi -fi - -if [[ -n "${IS_FULL}" ]]; then - # This is a slow but sure way to get all the necessary toolchains. - # However, it will not work if tree is dirty. - # Bail out if git repo is dirty. - if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: dirty GIT state - commit everything and re-run the script." - exit 1 - fi - - # 1. We have a --single-branch checkout, so we have to add a "master" branch and fetch it - git remote set-branches --add browser_upstream master - git fetch --depth 1 browser_upstream master - # 2. Checkout the master branch and run bootstrap from it. - git checkout browser_upstream/master - echo "ac_add_options --enable-bootstrap" >> .mozconfig - SHELL=/bin/sh ./mach --no-interactive bootstrap --application-choice=browser - git checkout - - rm -rf "${OBJ_FOLDER}" - - if [[ -n "${WIN32_REDIST_DIR}" ]]; then - # Having this option in .mozconfig kills incremental compilation. - echo "export WIN32_REDIST_DIR=\"$WIN32_REDIST_DIR\"" >> .mozconfig - fi -fi - -if [[ -n "${IS_JUGGLER}" ]]; then - ./mach build faster -else - ./mach build - if is_mac; then - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist - else - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist/bin - fi -fi - - diff --git a/browser_patches/firefox/clean.sh b/browser_patches/firefox/clean.sh deleted file mode 100755 index d94baf33a3..0000000000 --- a/browser_patches/firefox/clean.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -OBJ_FOLDER="obj-build-playwright" -if [[ -d $OBJ_FOLDER ]]; then - rm -rf $OBJ_FOLDER -fi - -if [[ -f "mach" ]]; then - ./mach clobber || true -fi diff --git a/browser_patches/firefox/install-preferences.js b/browser_patches/firefox/install-preferences.js deleted file mode 100644 index f82f791d54..0000000000 --- a/browser_patches/firefox/install-preferences.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright 2018 Google Inc. All rights reserved. - * Modifications copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const util = require('util'); - -const writeFileAsync = util.promisify(fs.writeFile.bind(fs)); -const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); - -// Install browser preferences after downloading and unpacking -// firefox instances. -// Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration -async function installFirefoxPreferences(distpath) { - let executablePath = ''; - if (os.platform() === 'linux') - executablePath = path.join(distpath, 'firefox'); - else if (os.platform() === 'darwin') - executablePath = path.join(distpath, (process.env.FF_DEBUG_BUILD ? 'NightlyDebug.app' : 'Nightly.app'), 'Contents', 'MacOS', 'firefox'); - else if (os.platform() === 'win32') - executablePath = path.join(distpath, 'firefox.exe'); - - const firefoxFolder = path.dirname(executablePath); - - let prefPath = ''; - let configPath = ''; - if (os.platform() === 'darwin') { - prefPath = path.join(firefoxFolder, '..', 'Resources', 'defaults', 'pref'); - configPath = path.join(firefoxFolder, '..', 'Resources'); - } else if (os.platform() === 'linux') { - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults')); - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences')); - prefPath = path.join(firefoxFolder, 'browser', 'defaults', 'preferences'); - configPath = firefoxFolder; - } else if (os.platform() === 'win32') { - prefPath = path.join(firefoxFolder, 'defaults', 'pref'); - configPath = firefoxFolder; - } else { - throw new Error('Unsupported platform: ' + os.platform()); - } - - await Promise.all([ - copyFile({ - from: path.join(__dirname, 'preferences', '00-playwright-prefs.js'), - to: path.join(prefPath, '00-playwright-prefs.js'), - }), - copyFile({ - from: path.join(__dirname, 'preferences', 'playwright.cfg'), - to: path.join(configPath, 'playwright.cfg'), - }), - ]); -} - -function copyFile({from, to}) { - const rd = fs.createReadStream(from); - const wr = fs.createWriteStream(to); - return new Promise(function(resolve, reject) { - rd.on('error', reject); - wr.on('error', reject); - wr.on('finish', resolve); - rd.pipe(wr); - }).catch(function(error) { - rd.destroy(); - wr.end(); - throw error; - }); -} - -module.exports = { installFirefoxPreferences }; - -if (require.main === module) { - if (process.argv.length !== 3) { - console.log('ERROR: expected a path to the directory with browser build'); - process.exit(1); - return; - } - - installFirefoxPreferences(process.argv[2]).catch(error => { - console.error('ERROR: failed to put preferences!'); - console.error(error); - process.exit(1); - }); -} diff --git a/browser_patches/get_xcode_version.js b/browser_patches/get_xcode_version.js deleted file mode 100755 index 29e2d55a2b..0000000000 --- a/browser_patches/get_xcode_version.js +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env node - -const child_process = require('child_process'); - -const XCODE_VERSIONS = { - "macos-10.15": { - webkit: '11.7', - }, - "macos-11": { - webkit: '12.5', // WebKit strongly requires xcode 12.5 and not higher on MacOS 11 - firefox: '13.2', // As of Oct 2021 building Firefox requires XCode 13 - ffmpeg: '13.2', - }, - "macos-12": { - webkit: '13.2', // WebKit requires xcode 13.2 to work on MacOS 12.2. - firefox: '13.2', // As of Oct 2021 building Firefox requires XCode 13 - chromium: '13.3', // As of Apr 2022 Chromium requires Xcode13.3 - ffmpeg: '13.2', - }, -}; - -const [major, minor, patch] = child_process.execSync(`sw_vers -productVersion`).toString().trim().split('.'); -const browserName = process.argv[2]; -const macosVersion = major === '10' ? `macos-${major}.${minor}` : `macos-${major}`; -const versions = XCODE_VERSIONS[macosVersion]; -if (!versions || !versions[browserName.toLowerCase()]) - throw new Error(`Compilation of ${browserName} is not supported on ${macosVersion}`); - -console.log(versions[browserName.toLowerCase()]); - diff --git a/browser_patches/prepare_checkout.sh b/browser_patches/prepare_checkout.sh deleted file mode 100755 index 2ec4a2d8a9..0000000000 --- a/browser_patches/prepare_checkout.sh +++ /dev/null @@ -1,270 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_PATH=$(pwd -P) - -source "${SCRIPT_PATH}/utils.sh" - -REMOTE_BROWSER_UPSTREAM="browser_upstream" -BUILD_BRANCH="playwright-build" - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [firefox|firefox-beta|webkit] [custom_checkout_path]" - echo - echo "Prepares browser checkout. The checkout is a GIT repository that:" - echo "- has a '$REMOTE_BROWSER_UPSTREAM' remote pointing to a REMOTE_URL from UPSTREAM_CONFIG.sh" - echo "- has a '$BUILD_BRANCH' branch that is BASE_REVISION with all the patches applied." - echo - echo "You can optionally specify custom_checkout_path if you want to use some other browser checkout" - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './$(basename "$0") --help' for more information" - exit 1 -fi - -function maybe_cmd { - if is_win; then - local args="$@" - /c/Windows/System32/cmd.exe "/c $args" - else - $@ - fi -} - -function prepare_chromium_checkout { - cd "${SCRIPT_PATH}" - - if [[ $1 == "chromium" ]]; then - source "${SCRIPT_PATH}/chromium/UPSTREAM_CONFIG.sh" - elif [[ "$1" == "chromium-tot" ]]; then - source "${SCRIPT_PATH}/chromium-tip-of-tree/UPSTREAM_CONFIG.sh" - else - echo "ERROR: unknown type of checkout to prepare - $1" - exit 1 - fi - source "${SCRIPT_PATH}/chromium/ensure_depot_tools.sh" - - if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" - fi - - # Update Chromium checkout. - # - # This is based on https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md#get-the-code - if [[ ! -d "${CR_CHECKOUT_PATH}" ]]; then - rm -rf "${CR_CHECKOUT_PATH}" - mkdir -p "${CR_CHECKOUT_PATH}" - cd "${CR_CHECKOUT_PATH}" - maybe_cmd fetch --nohooks chromium - cd src - if is_linux; then - ./build/install-build-deps.sh - fi - maybe_cmd gclient runhooks - fi - if [[ ! -d "${CR_CHECKOUT_PATH}/src" ]]; then - echo "ERROR: CR_CHECKOUT_PATH does not have src/ subfolder; is this a chromium checkout?" - exit 1 - fi - - cd "${CR_CHECKOUT_PATH}/src" - maybe_cmd gclient sync --with_branch_heads - git fetch origin - git checkout "${BRANCH_COMMIT}" - maybe_cmd gclient sync -D --with_branch_heads -} - -# FRIENDLY_CHECKOUT_PATH is used only for logging. -FRIENDLY_CHECKOUT_PATH=""; -CHECKOUT_PATH="" -PATCHES_PATH="" -BUILD_NUMBER="" -WEBKIT_EXTRA_FOLDER_PATH="" -FIREFOX_EXTRA_FOLDER_PATH="" -if [[ ("$1" == "chromium") || ("$1" == "chromium/") || ("$1" == "cr") ]]; then - prepare_chromium_checkout chromium - exit 0 -elif [[ ("$1" == "chromium-tip-of-tree") || ("$1" == "chromium-tot") || ("$1" == "cr-tot") ]]; then - prepare_chromium_checkout chromium-tot - exit 0 -elif [[ ("$1" == "ffmpeg") || ("$1" == "ffmpeg/") ]]; then - echo "FYI: ffmpeg checkout is not supported. Use '//browser_patches/ffmpeg/build.sh' instead" - exit 0 -elif [[ ("$1" == "winldd") || ("$1" == "winldd/") ]]; then - echo "FYI: winldd source code is available right away" - exit 0 -elif [[ ("$1" == "firefox") || ("$1" == "firefox/") || ("$1" == "ff") ]]; then - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - PATCHES_PATH="$PWD/firefox/patches" - FIREFOX_EXTRA_FOLDER_PATH="$PWD/firefox/juggler" - BUILD_NUMBER=$(head -1 "$PWD/firefox/BUILD_NUMBER") - source "./firefox/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "firefox-beta") || ("$1" == "ff-beta") ]]; then - # NOTE: firefox-beta re-uses firefox checkout. - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - PATCHES_PATH="$PWD/firefox-beta/patches" - FIREFOX_EXTRA_FOLDER_PATH="$PWD/firefox-beta/juggler" - BUILD_NUMBER=$(head -1 "$PWD/firefox-beta/BUILD_NUMBER") - source "./firefox-beta/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "webkit") || ("$1" == "webkit/") || ("$1" == "wk") ]]; then - if [[ -z "${WK_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/webkit'; - CHECKOUT_PATH="$HOME/webkit" - else - echo "WARNING: using checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" - CHECKOUT_PATH="${WK_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - PATCHES_PATH="$PWD/webkit/patches" - WEBKIT_EXTRA_FOLDER_PATH="$PWD/webkit/embedder/Playwright" - BUILD_NUMBER=$(head -1 "$PWD/webkit/BUILD_NUMBER") - source "./webkit/UPSTREAM_CONFIG.sh" -else - echo ERROR: unknown browser - "$1" - exit 1 -fi - -# if there's no checkout folder - checkout one. -if ! [[ -d $CHECKOUT_PATH ]]; then - echo "-- $FRIENDLY_CHECKOUT_PATH is missing - checking out.." - if [[ -n "$CI" ]]; then - # In CI environment, we re-checkout constantly, so we do a shallow checkout to save time. - git clone --single-branch --depth 1 --branch "$BASE_BRANCH" "$REMOTE_URL" "$CHECKOUT_PATH" - else - # In non-CI environment, do a full checkout. This takes time, - # but liberates from the `git fetch --unshallow`. - git clone --single-branch --branch "$BASE_BRANCH" "$REMOTE_URL" "$CHECKOUT_PATH" - fi -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH folder - OK" -fi - -# if folder exists but not a git repository - bail out. -if ! [[ -d $CHECKOUT_PATH/.git ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH is not a git repository! Remove it and re-run the script." - exit 1 -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH is a git repo - OK" -fi - -# ============== SETTING UP GIT REPOSITORY ============== -cd "$CHECKOUT_PATH" - -# Bail out if git repo is dirty. -if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH has dirty GIT state - commit everything and re-run the script." - exit 1 -fi - -# Setting up |$REMOTE_BROWSER_UPSTREAM| remote and fetch the $BASE_BRANCH -if git remote get-url $REMOTE_BROWSER_UPSTREAM >/dev/null; then - echo "-- setting |$REMOTE_BROWSER_UPSTREAM| remote url to $REMOTE_URL" - git remote set-url $REMOTE_BROWSER_UPSTREAM "$REMOTE_URL" -else - echo "-- adding |$REMOTE_BROWSER_UPSTREAM| remote to $REMOTE_URL" - git remote rename origin $REMOTE_BROWSER_UPSTREAM -fi - -# Since we do a single-branch checkout by default, we might need to add a new remote base branch. -if ! git show-branch "remotes/$REMOTE_BROWSER_UPSTREAM/${BASE_BRANCH}" 2>&1 >/dev/null; then - git remote set-branches --add "$REMOTE_BROWSER_UPSTREAM" "${BASE_BRANCH}" -fi - -# if our remote branch does not contains "BASE_REVISION" - then fetch more stuff. -if [[ -z $(git branch -r --contains "${BASE_REVISION}" --list "${REMOTE_BROWSER_UPSTREAM}/${BASE_BRANCH}") ]]; then - # Detach git head so that we can fetch into branch. - git checkout --detach >/dev/null 2>/dev/null - - if [[ -z "$CI" ]]; then - # On non-CI, fetch everything. - git fetch "$REMOTE_BROWSER_UPSTREAM" "$BASE_BRANCH" - else - # On CI, fetch from REMOTE_BROWSER_UPSTREAM more and more commits - # until we find $BASE_REVISION. - # This technique allows us start with a shallow clone. - - # Fetch 128 commits first, and then double the amount every iteration. - FETCH_DEPTH=128 - SUCCESS="no" - while (( FETCH_DEPTH <= 8192 )); do - echo "Fetching ${FETCH_DEPTH} commits to find base revision..." - git fetch --depth "${FETCH_DEPTH}" "$REMOTE_BROWSER_UPSTREAM" "$BASE_BRANCH" - FETCH_DEPTH=$(( FETCH_DEPTH * 2 )); - if git cat-file -e "$BASE_REVISION"^{commit} >/dev/null; then - SUCCESS="yes" - break; - fi - done - if [[ "${SUCCESS}" == "no" ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH/ does not include the BASE_REVISION (@$BASE_REVISION). Wrong revision number?" - exit 1 - fi - fi -fi - -echo "-- checking $FRIENDLY_CHECKOUT_PATH repo has BASE_REVISION (@$BASE_REVISION) commit - OK" - -# Check out the $BASE_REVISION -git checkout "$BASE_REVISION" - -# Create a playwright-build branch and apply all the patches to it. -if git show-ref --verify --quiet refs/heads/playwright-build; then - git branch -D playwright-build -fi -git checkout -b playwright-build -echo "-- applying patches" -git apply --index --whitespace=nowarn "$PATCHES_PATH"/* - -if [[ ! -z "${WEBKIT_EXTRA_FOLDER_PATH}" ]]; then - echo "-- adding WebKit embedders" - EMBEDDER_DIR="$PWD/Tools/Playwright" - # git status does not show empty directories, check it separately. - # XCode 13 and WebKit build on MacOS 12 now create empty folder here: - # ./Tools/Playwright/Playwright.xcodeproj/project.xcworkspace/xcshareddata/swiftpm - # As an easy work-around, let's remove it. - if [[ -d $EMBEDDER_DIR ]]; then - rm -rf "$EMBEDDER_DIR" - fi - cp -r "${WEBKIT_EXTRA_FOLDER_PATH}" "$EMBEDDER_DIR" - git add "$EMBEDDER_DIR" -elif [[ ! -z "${FIREFOX_EXTRA_FOLDER_PATH}" ]]; then - echo "-- adding juggler" - EMBEDDER_DIR="$PWD/juggler" - # git status does not show empty directories, check it separately. - # Remove for good if its empty but exists. - if [[ -d $EMBEDDER_DIR ]]; then - rm -rf "$EMBEDDER_DIR" - fi - cp -r "${FIREFOX_EXTRA_FOLDER_PATH}" "$EMBEDDER_DIR" - git add "$EMBEDDER_DIR" -fi - -git commit -a --author="playwright-devops " -m "chore($1): bootstrap build #$BUILD_NUMBER" - -echo -echo -echo "DONE. Browser is ready to be built." diff --git a/browser_patches/repack-juggler.mjs b/browser_patches/repack-juggler.mjs deleted file mode 100755 index 9c21b5dd9e..0000000000 --- a/browser_patches/repack-juggler.mjs +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as path from 'path'; -import * as URL from 'url'; -import * as fs from 'fs'; -import * as http from 'http'; -import * as https from 'https'; -import * as os from 'os'; -import * as util from 'util'; -import * as child_process from 'child_process'; -import AdmZip from 'adm-zip'; - -const existsAsync = path => new Promise(resolve => fs.stat(path, err => resolve(!err))); - -const __filename = URL.fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -if (process.argv[2] === '--help' || process.argv[2] === '-h') { - console.log(`usage: ${path.basename(process.argv[1])} [firefox|ff|firefox-beta|ff-beta] [build number] [build platform]`); - console.log(``); - console.log(`Repackages Firefox with tip-of-tree Juggler implementation`); - process.exit(1); -} - -let browserName = ''; -if (process.argv[2] === 'firefox' || process.argv[2] === 'ff') { - browserName = 'firefox'; -} else if (process.argv[2] === 'firefox-beta' || process.argv[2] === 'ff-beta') { - browserName = 'firefox-beta'; -} else { - console.error('ERROR: unknown firefox to repackage - either "firefox", "ff", "firefox-beta" or "ff-beta" is allowed as first argument'); - process.exit(1); -} - -// Path to jar.mn in the juggler -const JARMN_PATH = path.join(__dirname, browserName, 'juggler', 'jar.mn'); -// Workdir for Firefox repackaging -const BUILD_DIRECTORY = os.platform() === 'win32' ? path.join(__dirname, '__repackaged_firefox__') : `/tmp/repackaged-firefox`; -// Information about currently downloaded build -const BUILD_INFO_PATH = path.join(BUILD_DIRECTORY, 'build-info.json'); -// Backup OMNI.JA - the original one before repackaging. -const OMNI_BACKUP_PATH = path.join(BUILD_DIRECTORY, 'omni.ja.backup'); -// Workdir to extract omni.ja -const OMNI_EXTRACT_DIR = path.join(BUILD_DIRECTORY, 'omni'); -// Path inside omni.ja to juggler -const OMNI_JUGGLER_DIR = path.join(OMNI_EXTRACT_DIR, 'chrome', 'juggler'); - -const EXECUTABLE_PATHS = { - 'ubuntu18.04': ['firefox', 'firefox'], - 'ubuntu20.04': ['firefox', 'firefox'], - 'mac10.14': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'mac10.15': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'mac11': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'mac11-arm64': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'win64': ['firefox', 'firefox.exe'], -}; - -const DOWNLOAD_URLS = { - 'firefox': { - 'ubuntu18.04': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-ubuntu-18.04.zip', - 'ubuntu20.04': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-ubuntu-20.04.zip', - 'mac10.14': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11.zip', - 'mac10.15': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11.zip', - 'mac11': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11.zip', - 'mac11-arm64': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11-arm64.zip', - 'win64': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-win64.zip', - }, - 'firefox-beta': { - 'ubuntu18.04': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-ubuntu-18.04.zip', - 'ubuntu20.04': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip', - 'mac10.14': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11.zip', - 'mac10.15': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11.zip', - 'mac11': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11.zip', - 'mac11-arm64': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip', - 'win64': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-win64.zip', - }, -}; - -async function ensureFirefoxBuild(browserName, buildNumber, buildPlatform) { - if (!buildNumber) - buildNumber = (await fs.promises.readFile(path.join(__dirname, browserName, 'BUILD_NUMBER'), 'utf8')).split('\n').shift(); - if (!buildPlatform) - buildPlatform = getHostPlatform(); - const currentBuildInfo = await fs.promises.readFile(BUILD_INFO_PATH).then(text => JSON.parse(text)).catch(e => ({ buildPlatform: '', buildNumber: '', browserName: '' })); - - if (currentBuildInfo.buildPlatform === buildPlatform && currentBuildInfo.buildNumber === buildNumber && currentBuildInfo.browserName === browserName) - return currentBuildInfo; - await fs.promises.rm(BUILD_DIRECTORY, { recursive: true }).catch(e => {}); - await fs.promises.mkdir(BUILD_DIRECTORY); - const buildZipPath = path.join(BUILD_DIRECTORY, 'firefox.zip'); - - const urlTemplate = DOWNLOAD_URLS[browserName][buildPlatform]; - if (!urlTemplate) - throw new Error(`ERROR: repack-juggler does not support ${buildPlatform}`); - const url = util.format(urlTemplate, buildNumber); - console.log(`Downloading ${browserName} r${buildNumber} for ${buildPlatform} - it might take a few minutes`); - let downloadedPercentage = 0; - await downloadFile(url, buildZipPath, (downloaded, total) => { - const percentage = Math.round(downloaded / total * 10) * 10; - if (percentage === downloadedPercentage) - return; - downloadedPercentage = percentage; - console.log(`Downloaded: ${downloadedPercentage}%`); - }); - - const zip = new AdmZip(buildZipPath); - zip.extractAllTo(BUILD_DIRECTORY, false /* overwrite */, true /* keepOriginalPermission */); - - const buildInfo = { buildNumber, buildPlatform, browserName }; - await fs.promises.writeFile(BUILD_INFO_PATH, JSON.stringify(buildInfo), 'utf8'); - return buildInfo; -} - -async function listFiles(aPath, files = []) { - const stat = await fs.promises.lstat(aPath); - if (stat.isDirectory()) { - const entries = await fs.promises.readdir(aPath); - await Promise.all(entries.map(entry => listFiles(path.join(aPath, entry), files))); - } else { - files.push(aPath); - } - return files; -} - -async function repackageJuggler(browserName, buildInfo) { - const { buildNumber, buildPlatform } = buildInfo; - - // Find all omni.ja files in the Firefox build. - const omniPaths = (await listFiles(BUILD_DIRECTORY)).filter(filePath => filePath.endsWith('omni.ja')); - - // Iterate over all omni.ja files and find one that has juggler inside. - const omniWithJugglerPath = await (async () => { - for (const omniPath of omniPaths) { - const zip = new AdmZip(omniPath); - for (const zipEntry of zip.getEntries()) { - if (zipEntry.toString().includes('chrome/juggler')) - return omniPath; - } - } - return null; - })(); - - if (!omniWithJugglerPath) { - console.error('ERROR: did not find omni.ja file with baked in Juggler!'); - process.exit(1); - } else { - if (!(await existsAsync(OMNI_BACKUP_PATH))) - await fs.promises.copyFile(omniWithJugglerPath, OMNI_BACKUP_PATH); - } - - // Let's repackage omni folder! - await fs.promises.rm(OMNI_EXTRACT_DIR, { recursive: true }).catch(e => {}); - await fs.promises.mkdir(OMNI_EXTRACT_DIR); - - { - // Unzip omni - const zip = new AdmZip(OMNI_BACKUP_PATH); - zip.extractAllTo(OMNI_EXTRACT_DIR, false /* overwrite */, true /* keepOriginalPermission */); - } - - // Remove current juggler directory - await fs.promises.rm(OMNI_JUGGLER_DIR, { recursive: true }); - // Repopulate with tip-of-tree juggler files - const jarmn = await fs.promises.readFile(JARMN_PATH, 'utf8'); - const jarLines = jarmn.split('\n').map(line => line.trim()).filter(line => line.startsWith('content/') && line.endsWith(')')); - for (const line of jarLines) { - const tokens = line.split(/\s+/); - const toPath = path.join(OMNI_JUGGLER_DIR, tokens[0]); - const fromPath = path.join(__dirname, browserName, 'juggler', tokens[1].slice(1, -1)); - await fs.promises.mkdir(path.dirname(toPath), { recursive: true }); - await fs.promises.copyFile(fromPath, toPath); - } - - await fs.promises.unlink(omniWithJugglerPath); - { - const zip = new AdmZip(); - zip.addLocalFolder(OMNI_EXTRACT_DIR); - zip.writeZip(omniWithJugglerPath); - } - - const module = await import(URL.pathToFileURL(path.join(__dirname, browserName, 'install-preferences.js'))); - await module.default.installFirefoxPreferences(path.join(BUILD_DIRECTORY, 'firefox')); - - // Output executable path to be used in test. - console.log(` - browser: ${browserName} - buildNumber: ${buildNumber} - buildPlatform: ${buildPlatform} - executablePath: ${path.join(BUILD_DIRECTORY, ...EXECUTABLE_PATHS[buildPlatform])} - `); -} - - -function httpRequest(url, method, response) { - const options = URL.parse(url); - options.method = method; - - const requestCallback = res => { - if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) - httpRequest(res.headers.location, method, response); - else - response(res); - }; - const request = options.protocol === 'https:' ? - https.request(options, requestCallback) : - http.request(options, requestCallback); - request.end(); - return request; -} - -function downloadFile(url, destinationPath, progressCallback) { - let downloadedBytes = 0; - let totalBytes = 0; - - let fulfill, reject; - const promise = new Promise((x, y) => { fulfill = x; reject = y; }); - - const request = httpRequest(url, 'GET', response => { - if (response.statusCode !== 200) { - const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`); - // consume response data to free up memory - response.resume(); - reject(error); - return; - } - const file = fs.createWriteStream(destinationPath); - file.on('finish', () => fulfill()); - file.on('error', error => reject(error)); - response.pipe(file); - totalBytes = parseInt(response.headers['content-length'], 10); - if (progressCallback) - response.on('data', onData); - }); - request.on('error', error => reject(error)); - return promise; - - function onData(chunk) { - downloadedBytes += chunk.length; - progressCallback(downloadedBytes, totalBytes); - } -} - -function getUbuntuVersionSync() { - if (os.platform() !== 'linux') - return ''; - try { - let osReleaseText; - if (fs.existsSync('/etc/upstream-release/lsb-release')) - osReleaseText = fs.readFileSync('/etc/upstream-release/lsb-release', 'utf8'); - else - osReleaseText = fs.readFileSync('/etc/os-release', 'utf8'); - if (!osReleaseText) - return ''; - return getUbuntuVersionInternal(osReleaseText); - } catch (e) { - return ''; - } -} - -function getUbuntuVersionInternal(osReleaseText) { - const fields = new Map(); - for (const line of osReleaseText.split('\n')) { - const tokens = line.split('='); - const name = tokens.shift(); - let value = tokens.join('=').trim(); - if (value.startsWith('"') && value.endsWith('"')) - value = value.substring(1, value.length - 1); - if (!name) - continue; - fields.set(name.toLowerCase(), value); - } - // For Linux mint - if (fields.get('distrib_id') && fields.get('distrib_id').toLowerCase() === 'ubuntu') - return fields.get('distrib_release') || ''; - if (!fields.get('name') || fields.get('name').toLowerCase() !== 'ubuntu') - return ''; - return fields.get('version_id') || ''; -} - -function getHostPlatform() { - const platform = os.platform(); - if (platform === 'darwin') { - const [major, minor] = child_process.execSync('sw_vers -productVersion', { - stdio: ['ignore', 'pipe', 'ignore'] - }).toString('utf8').trim().split('.').map(x => parseInt(x, 10)); - let arm64 = false; - // BigSur is the first version that might run on Apple Silicon. - if (major >= 11) { - arm64 = child_process.execSync('/usr/sbin/sysctl -in hw.optional.arm64', { - stdio: ['ignore', 'pipe', 'ignore'] - }).toString().trim() === '1'; - } - const LAST_STABLE_MAC_MAJOR_VERSION = 11; - // All new MacOS releases increase major version. - let macVersion = `${major}`; - if (major === 10) { - // Pre-BigSur MacOS was increasing minor version every release. - macVersion = `${major}.${minor}`; - } else if (major > LAST_STABLE_MAC_MAJOR_VERSION) { - // Best-effort support for MacOS beta versions. - macVersion = LAST_STABLE_MAC_MAJOR_VERSION + ''; - } - const archSuffix = arm64 ? '-arm64' : ''; - return `mac${macVersion}${archSuffix}`; - } - if (platform === 'linux') { - const ubuntuVersion = getUbuntuVersionSync(); - if (parseInt(ubuntuVersion, 10) <= 19) - return 'ubuntu18.04'; - return 'ubuntu20.04'; - } - if (platform === 'win32') - return 'win64'; - return platform; -} - -async function main() { - const buildInfo = await ensureFirefoxBuild(browserName, process.argv[3], process.argv[4]).catch(e => { - console.log(e.message); - process.exit(1); - }); - await repackageJuggler(browserName, buildInfo); -} - -await main(); - diff --git a/browser_patches/sanitize_and_compress_log.js b/browser_patches/sanitize_and_compress_log.js deleted file mode 100755 index aa9f469a9a..0000000000 --- a/browser_patches/sanitize_and_compress_log.js +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const fs = require('fs'); -const zlib = require('zlib'); -const readline = require('readline'); - -if (process.argv.length < 3) { - console.log('ERROR: output file path has to be specified!'); - process.exit(1); -} -const OUTPUT_PATH = process.argv[2]; - -// These env variable values should be removed from logs no matter what. -const BLOCKLIST_ENV_KEYS = new Set([ - 'AZ_ACCOUNT_NAME', - 'AZ_ACCOUNT_KEY', - 'TELEGRAM_BOT_KEY', -]); - -// These env variable values can stay in logs - they are harmless. -const ALLOWLIST_ENV_KEYS = new Set([ - 'SHELL', - 'TERM', - 'USER', - 'PWD', - 'EDITOR', - 'LANG', - 'HOME', - 'LOGNAME', - 'COLORTERM', - 'TMPDIR', -]); - -const sanitizeEnv = Object.entries(process.env).filter(([key, value]) => { - if (BLOCKLIST_ENV_KEYS.has(key)) - return true; - if (ALLOWLIST_ENV_KEYS.has(key)) - return false; - // Sanitize all env variables that have `KEY` or `ACCOUNT` as a name. - if (key.toUpperCase().includes('KEY') || key.toUpperCase().includes('ACCOUNT')) - return true; - // We shouldn't try sanitizing env values that are too short. - if (value.trim().length < 7) - return false; - return true; -}); - -const rl = readline.createInterface({ - input: process.stdin, - crlfDelay: Infinity, -}); - -const gzip = zlib.createGzip(); -gzip.pipe(fs.createWriteStream(OUTPUT_PATH)); - -rl.on('line', line => { - for (const [key, value] of sanitizeEnv) - line = line.split(value).join(`<${key}>`); - console.log(line); - gzip.write(line + '\n'); -}); - -rl.on('close', () => { - gzip.end(); -}); - diff --git a/browser_patches/send_telegram_message.js b/browser_patches/send_telegram_message.js deleted file mode 100644 index c7f3ad7862..0000000000 --- a/browser_patches/send_telegram_message.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// @ts-check -const https = require('https'); - -const TELEGRAM_CHAT_ID = "-1001225613794"; - -(async () => { - const { TELEGRAM_BOT_KEY } = process.env; - if (!TELEGRAM_BOT_KEY) { - console.log('environment variable \'TELEGRAM_BOT_KEY\' is not set'); - return; - } - - const text = process.argv[2]; - if (!text) { - console.log('Text not set!'); - console.log('Usage: node send_telegram_message.js '); - return; - } - - await sendTelegramMessage(TELEGRAM_BOT_KEY, text); - console.log('Telegram message sent successfully!'); -})().catch(error => { - console.error(`Failed to send Telegram message. Error: ${error}`); -}) - -/** - * @param {string} apiKey - * @param {string} text - */ -async function sendTelegramMessage(apiKey, text) { - await new Promise((resolve, reject) => { - const request = https.request({ - hostname: 'api.telegram.org', - path: `/bot${apiKey}/sendMessage`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - }, res => { - let body = ''; - res.on('data', chunk => body += chunk.toString()); - res.on('end', () => { - if (res.statusCode !== 200) - reject(new Error(`Telegram API returned status code ${res.statusCode}. Body: ${body}`)); - else - resolve(JSON.parse(body)); - }); - res.on('error', err => { - reject(err); - }); - }); - request.on('error',reject); - request.write(JSON.stringify({ - disable_web_page_preview: true, - chat_id: TELEGRAM_CHAT_ID, - parse_mode: 'html', - text, - disable_notification: false, - })); - request.end(); - }); -} diff --git a/browser_patches/upload.sh b/browser_patches/upload.sh deleted file mode 100755 index 70c813e939..0000000000 --- a/browser_patches/upload.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -source "./utils.sh" - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [BLOB-PATH] [--check|ZIP-PATH]" - echo - echo "Upload ZIP-PATH to BLOB-PATH in 'builds' container." - echo - echo "--check pass |--check| as a second parameter instead of a zip-path to check for" - echo " existence of BLOB-PATH" - echo - echo "NOTE: \$AZ_ACCOUNT_KEY (azure account name) and \$AZ_ACCOUNT_NAME (azure account name)" - echo "env variables are required to upload builds to CDN." - exit 0 -fi - -if [[ (-z $AZ_ACCOUNT_KEY) || (-z $AZ_ACCOUNT_NAME) ]]; then - echo "ERROR: Either \$AZ_ACCOUNT_KEY or \$AZ_ACCOUNT_NAME environment variable is missing." - echo " 'Azure Account Name' and 'Azure Account Key' secrets that are required" - echo " to upload builds ot Azure CDN." - exit 1 -fi - -if [[ $# < 2 ]]; then - echo "not enought arguments!" - echo "try '$(basename "$0") --help' for more information" - exit 1 -fi - -BLOB_PATH="$1" -ZIP_PATH="$2" - -if [[ ("$2" == '--check') ]]; then - EXISTS=$(az storage blob exists -c builds --account-key "$AZ_ACCOUNT_KEY" --account-name "$AZ_ACCOUNT_NAME" -n "$BLOB_PATH" --query "exists") - if [[ $EXISTS == "true" ]]; then - exit 0 - else - exit 1 - fi -fi - -GENERATE_MD5_HASH=$(cat <&2 - exit 1; - fi -} - - -createZipForLinux() { - # create a TMP directory to copy all necessary files - local tmpdir=$(mktemp -d -p "$(pwd)/WebKitBuild" -t webkit-deploy-XXXXXXXXXX) - mkdir -p "$tmpdir" - - # copy runner - cp -t "$tmpdir" "$SCRIPTS_DIR"/pw_run.sh - # copy protocol - node "$SCRIPTS_DIR"/concat_protocol.js > "$tmpdir"/protocol.json - - # Generate and unpack MiniBrowser bundles for each port - for port in gtk wpe; do - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/${port^^} \ - Tools/Scripts/generate-bundle \ - --bundle=MiniBrowser --release \ - --platform=${port} --destination="${tmpdir}" - - unzip "${tmpdir}"/MiniBrowser_${port}_release.zip -d "${tmpdir}"/minibrowser-${port} - rm -f "${tmpdir}"/MiniBrowser_${port}_release.zip - done - - # Bundle libstdc++ version that comes from gcc-9. gcc-9 is not default on Ubuntu 18.04 - if is_linux ubuntu 18.04; then - cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 "${tmpdir}/minibrowser-wpe/lib/libstdc++.so.6" - cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 "${tmpdir}/minibrowser-gtk/lib/libstdc++.so.6" - fi - - cd "$tmpdir" - - # zip resulting directory and cleanup TMP. - zip --symlinks -r "$ZIP_PATH" ./ - cd - - rm -rf "$tmpdir" -} - -createZipForWindows() { - # create a TMP directory to copy all necessary files - local tmpdir="/tmp/webkit-deploy-$(date +%s)" - mkdir -p "$tmpdir" - - cp -t "$tmpdir" ./WebKitLibraries/win/bin64/*.dll - cd WebKitBuild/Release/bin64 - cp -r -t "$tmpdir" WebKit.resources - cp -t "$tmpdir" JavaScriptCore.dll PlaywrightLib.dll WTF.dll WebKit2.dll libEGL.dll libGLESv2.dll - cp -t "$tmpdir" Playwright.exe WebKitNetworkProcess.exe WebKitWebProcess.exe - cd - - cd "$(printMSVCRedistDir)" - cp -t "$tmpdir" msvcp140.dll vcruntime140.dll vcruntime140_1.dll msvcp140_2.dll - cd - - - # copy protocol - node "$SCRIPTS_DIR"/concat_protocol.js > "$tmpdir"/protocol.json - # tar resulting directory and cleanup TMP. - cd "$tmpdir" - zip -r "$ZIP_PATH" ./ - cd - - rm -rf "$tmpdir" -} - -createZipForMac() { - # create a TMP directory to copy all necessary files - local tmpdir=$(mktemp -d) - - # copy all relevant files - ditto {./WebKitBuild/Release,"$tmpdir"}/com.apple.WebKit.GPU.xpc - ditto {./WebKitBuild/Release,"$tmpdir"}/com.apple.WebKit.Networking.xpc - ditto {./WebKitBuild/Release,"$tmpdir"}/com.apple.WebKit.WebContent.xpc - ditto {./WebKitBuild/Release,"$tmpdir"}/JavaScriptCore.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/libANGLE-shared.dylib - ditto {./WebKitBuild/Release,"$tmpdir"}/libwebrtc.dylib - ditto {./WebKitBuild/Release,"$tmpdir"}/Playwright.app - ditto {./WebKitBuild/Release,"$tmpdir"}/WebCore.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/WebInspectorUI.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/WebKit.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/WebKitLegacy.framework - ditto {"$SCRIPTS_DIR","$tmpdir"}/pw_run.sh - # copy protocol - node "$SCRIPTS_DIR"/concat_protocol.js > "$tmpdir"/protocol.json - - # Remove all broken symlinks. @see https://github.com/microsoft/playwright/issues/5472 - find "${tmpdir}" -type l ! -exec test -e {} \; -print | xargs rm - - # zip resulting directory and cleanup TMP. - ditto -c -k "$tmpdir" "$ZIP_PATH" - rm -rf "$tmpdir" -} - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPTS_DIR="$(pwd -P)" -source "${SCRIPTS_DIR}/../utils.sh" - -main "$@" diff --git a/browser_patches/webkit/build.sh b/browser_patches/webkit/build.sh deleted file mode 100755 index 209c86d832..0000000000 --- a/browser_patches/webkit/build.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -build_gtk() { - if [[ ! -d "./WebKitBuild/GTK/DependenciesGTK" ]]; then - yes | WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/GTK \ - DEBIAN_FRONTEND=noninteractive \ - ./Tools/Scripts/update-webkitgtk-libs - fi - local CMAKE_ARGS=( - --cmakeargs=-DENABLE_INTROSPECTION=OFF - --cmakeargs=-DUSE_GSTREAMER_WEBRTC=FALSE - ) - if is_linux ubuntu 18.04; then - CMAKE_ARGS+=("--cmakeargs=-DUSE_SYSTEM_MALLOC=ON") - fi - if [[ -n "${EXPORT_COMPILE_COMMANDS}" ]]; then - CMAKE_ARGS+=("--cmakeargs=-DCMAKE_EXPORT_COMPILE_COMMANDS=1") - fi - WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/GTK \ - ./Tools/Scripts/build-webkit --gtk --release "${CMAKE_ARGS}" --touch-events --orientation-events --no-bubblewrap-sandbox "${CMAKE_ARGS[@]}" MiniBrowser -} - -build_wpe() { - if [[ ! -d "./WebKitBuild/WPE/DependenciesWPE" ]]; then - yes | WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/WPE \ - DEBIAN_FRONTEND=noninteractive \ - ./Tools/Scripts/update-webkitwpe-libs - fi - local CMAKE_ARGS=( - --cmakeargs=-DENABLE_COG=OFF - --cmakeargs=-DENABLE_INTROSPECTION=OFF - --cmakeargs=-DENABLE_WEBXR=OFF - --cmakeargs=-DUSE_GSTREAMER_WEBRTC=FALSE - ) - if is_linux ubuntu 18.04; then - CMAKE_ARGS+=("--cmakeargs=-DUSE_SYSTEM_MALLOC=ON") - fi - if [[ -n "${EXPORT_COMPILE_COMMANDS}" ]]; then - CMAKE_ARGS+=("--cmakeargs=-DCMAKE_EXPORT_COMPILE_COMMANDS=1") - fi - - WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/WPE \ - ./Tools/Scripts/build-webkit --wpe --release "${CMAKE_ARGS}" --touch-events --orientation-events --no-bubblewrap-sandbox "${CMAKE_ARGS[@]}" MiniBrowser -} - -ensure_linux_deps() { - - yes | DEBIAN_FRONTEND=noninteractive ./Tools/gtk/install-dependencies - yes | DEBIAN_FRONTEND=noninteractive ./Tools/wpe/install-dependencies - # Install JHBuild deps. - yes | DEBIAN_FRONTEND=noninteractive WEBKIT_JHBUILD=1 WEBKIT_JHBUILD_MODULESET=minimal WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/WPE ./Tools/Scripts/update-webkitwpe-libs - yes | DEBIAN_FRONTEND=noninteractive WEBKIT_JHBUILD=1 WEBKIT_JHBUILD_MODULESET=minimal WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/GTK ./Tools/Scripts/update-webkitgtk-libs -} - -if [[ ! -z "${WK_CHECKOUT_PATH}" ]]; then - cd "${WK_CHECKOUT_PATH}" - echo "WARNING: checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" -else - cd "$HOME/webkit" -fi - -if is_mac; then - selectXcodeVersionOrDie $(node "$SCRIPT_FOLDER/../get_xcode_version.js" webkit) - ./Tools/Scripts/build-webkit --release --touch-events --orientation-events -elif is_linux; then - args=("$@") - IS_FULL="" - BUILD_GTK="" - BUILD_WPE="" - for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --full) IS_FULL="1"; unset args[i]; ;; - --gtk) BUILD_GTK="1"; unset args[i]; ;; - --wpe) BUILD_WPE="1"; unset args[i]; ;; - esac - done - - # if neither gtk nor wpe is requested then build both. - if [[ -z "${BUILD_GTK}" && -z "${BUILD_WPE}" ]]; then - BUILD_GTK="1" - BUILD_WPE="1" - fi - - echo "== BUILD CONFIGURATION ==" - if [[ -n "${IS_FULL}" ]]; then - echo "- install dependencies: YES" - else - echo "- install dependencies: NO" - fi - if [[ -n "${BUILD_GTK}" ]]; then - echo "- build GTK: YES" - else - echo "- build GTK: NO" - fi - if [[ -n "${BUILD_WPE}" ]]; then - echo "- build WPE: YES" - else - echo "- build WPE: NO" - fi - - if [[ -n "${IS_FULL}" ]]; then - ensure_linux_deps - fi - - if [[ -n "${BUILD_WPE}" ]]; then - build_wpe - fi - - if [[ -n "${BUILD_GTK}" ]]; then - build_gtk - fi -elif is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w "${SCRIPT_FOLDER}"/buildwin.bat)" -else - echo "ERROR: cannot upload on this platform!" 1>&2 - exit 1; -fi diff --git a/browser_patches/webkit/buildwin.bat b/browser_patches/webkit/buildwin.bat deleted file mode 100644 index d3e8dec042..0000000000 --- a/browser_patches/webkit/buildwin.bat +++ /dev/null @@ -1,5 +0,0 @@ -set PATH=%WEBKIT_BUILD_PATH% -set WEBKIT_LIBRARIES=%CD%\WebKitLibraries\win -set WEBKIT_OUTPUTDIR=%CD%\WebKitBuild -perl %CD%\Tools\Scripts\build-webkit --wincairo --release --no-ninja --touch-events --orientation-events --dark-mode-css --generate-project-only --cmakeargs="-DLIBVPX_PACKAGE_PATH=C:\vcpkg\packages\libvpx_x64-windows" -%DEVENV% %CD%\WebKitBuild\Release\WebKit.sln /build "Release|x64" diff --git a/browser_patches/webkit/clean.sh b/browser_patches/webkit/clean.sh deleted file mode 100755 index fabc11297a..0000000000 --- a/browser_patches/webkit/clean.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -source "../utils.sh" - -if [[ ! -z "${WK_CHECKOUT_PATH}" ]]; then - cd "${WK_CHECKOUT_PATH}" - echo "WARNING: checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" -else - cd "$HOME/webkit" -fi - -if is_mac; then - rm -rf ./WebKitBuild -else - if [[ -d ./WebKitBuild ]]; then - rm -rf ./WebKitBuild/Release - fi - if [[ -d ./WebKitBuild/GTK ]]; then - rm -rf ./WebKitBuild/GTK/Release - fi - if [[ -d ./WebKitBuild/WPE ]]; then - rm -rf ./WebKitBuild/WPE/Release - fi -fi diff --git a/browser_patches/webkit/concat_protocol.js b/browser_patches/webkit/concat_protocol.js deleted file mode 100644 index 3e28fb6bb0..0000000000 --- a/browser_patches/webkit/concat_protocol.js +++ /dev/null @@ -1,7 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const checkoutPath = process.env.WK_CHECKOUT_PATH || path.join(process.env.HOME, 'webkit'); -const protocolDir = path.join(checkoutPath, './Source/JavaScriptCore/inspector/protocol'); -const files = fs.readdirSync(protocolDir).filter(f => f.endsWith('.json')).map(f => path.join(protocolDir, f)); -const json = files.map(file => JSON.parse(fs.readFileSync(file))); -console.log(JSON.stringify(json)); diff --git a/browser_patches/webkit/pw_run_debug.sh b/browser_patches/webkit/pw_run_debug.sh deleted file mode 100755 index 0e41b28a8e..0000000000 --- a/browser_patches/webkit/pw_run_debug.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -function runOSX() { - # if script is run as-is - if [ -d $SCRIPT_PATH/checkout/WebKitBuild/Debug/MiniBrowser.app ]; then - DYLIB_PATH="$SCRIPT_PATH/checkout/WebKitBuild/Debug" - elif [ -d $SCRIPT_PATH/MiniBrowser.app ]; then - DYLIB_PATH="$SCRIPT_PATH" - elif [ -d $SCRIPT_PATH/WebKitBuild/Debug/MiniBrowser.app ]; then - DYLIB_PATH="$SCRIPT_PATH/WebKitBuild/Debug" - else - echo "Cannot find a MiniBrowser.app in neither location" 1>&2 - exit 1 - fi - MINIBROWSER="$DYLIB_PATH/MiniBrowser.app/Contents/MacOS/MiniBrowser" - DYLD_FRAMEWORK_PATH=$DYLIB_PATH DYLD_LIBRARY_PATH=$DYLIB_PATH $MINIBROWSER "$@" -} - -function runLinux() { - # if script is run as-is - if [ -d $SCRIPT_PATH/checkout/WebKitBuild/GTK ]; then - LD_PATH="$SCRIPT_PATH/checkout/WebKitBuild/GTK/DependenciesGTK/Root/lib:$SCRIPT_PATH/checkout/WebKitBuild/GTK/Debug/bin" - MINIBROWSER="$SCRIPT_PATH/checkout/WebKitBuild/GTK/Debug/bin/MiniBrowser" - elif [ -f $SCRIPT_PATH/MiniBrowser ]; then - LD_PATH="$SCRIPT_PATH" - MINIBROWSER="$SCRIPT_PATH/MiniBrowser" - elif [ -d $SCRIPT_PATH/WebKitBuild/GTK ]; then - LD_PATH="$SCRIPT_PATH/WebKitBuild/GTK/DependenciesGTK/Root/lib:$SCRIPT_PATH/WebKitBuild/GTK/Debug/bin" - MINIBROWSER="$SCRIPT_PATH/WebKitBuild/GTK/Debug/bin/MiniBrowser" - else - echo "Cannot find a MiniBrowser.app in neither location" 1>&2 - exit 1 - fi - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LD_PATH $MINIBROWSER "$@" -} - -SCRIPT_PATH="$(cd "$(dirname "$0")" ; pwd -P)" -if [ "$(uname)" == "Darwin" ]; then - runOSX "$@" -elif [ "$(uname)" == "Linux" ]; then - runLinux "$@" -else - echo "ERROR: cannot run on this platform!" 1>&2 - exit 1; -fi diff --git a/browser_patches/webkit/upstream_status.md b/browser_patches/webkit/upstream_status.md deleted file mode 100644 index 6c16dc531c..0000000000 --- a/browser_patches/webkit/upstream_status.md +++ /dev/null @@ -1,20 +0,0 @@ -### WebKit patches under review - -- [203870](https://bugs.webkit.org/show_bug.cgi?id=203870) Web Inspector: introduce browser inspector - -### WebKit patches landed - -- [207446](https://bugs.webkit.org/show_bug.cgi?id=207446) Web Inspector: request interception -- [212528](https://bugs.webkit.org/show_bug.cgi?id=212528) [Win] Allow compiling with the TOUCH_EVENTS enabled -- [208964](https://bugs.webkit.org/show_bug.cgi?id=208964) [Curl] sort out MS vs Seconds confusion in Cookies -- [207529](https://bugs.webkit.org/show_bug.cgi?id=207529) [WPE][WebDriver] MiniBrowser should react to close session commands -- [207450](https://bugs.webkit.org/show_bug.cgi?id=207450) [Curl] Implement NetworkStorageSession::get/set/deleteCookie -- [207448](https://bugs.webkit.org/show_bug.cgi?id=207448) Web Inspector: encode binary web socket frames using base64 -- [207404](https://bugs.webkit.org/show_bug.cgi?id=207420) [Geoclue] Avoid usage of provider in callbacks after it has been destroyed -- [207404](https://bugs.webkit.org/show_bug.cgi?id=207404) Ephemeral session data leaks between processes -- [207449](https://bugs.webkit.org/show_bug.cgi?id=207449) [WK2][Soup] Implement NetworkStorageSession::getAllCookies -- [201922](https://bugs.webkit.org/show_bug.cgi?id=201922) WebStorageNamespaceProvider / StorageNamespaceImpl no longer need SessionIDs -- [200272](https://bugs.webkit.org/show_bug.cgi?id=200272) Web Inspector: Debugger: support emulateUserGesture parameter in Debugger.evaluateOnCallFrame -- [200223](https://bugs.webkit.org/show_bug.cgi?id=200223) [GTK] Compilation errors when GL is disabled -- [196280](https://bugs.webkit.org/show_bug.cgi?id=196280) Web Inspector: Crash when interacting with Template Content in Console -- [137131](https://bugs.webkit.org/show_bug.cgi?id=137131) Web Inspector: tests under LayoutTests/inspector/debugger are flaky